refactor():重构编辑系统,不再需要添加额外的脚本作为可编辑的入口了

This commit is contained in:
2025-10-21 16:40:41 +08:00
parent 1ce3d1a0d8
commit 93b83b3af3
37 changed files with 186 additions and 199 deletions

View File

@@ -0,0 +1,116 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Script.Gameplay.Interface;
using Script.Gameplay.Connect;
namespace Script.Gameplay.Edit
{
public class ButtonInteractController : MonoBehaviour, IInteractable, IEditableComponent, IConnectable, ISignalSender
{
#region Interactable
public bool Interactable = true;
[SerializeField] private float signalDuration = 1.0f; // 信号持续时间(秒)
public string GetInteractPrompt()
{
return "按F按下按钮";
}
public void Interact(GameObject interactor)
{
if (!Interactable) return;
StartCoroutine(SendSignalCoroutine());
Debug.Log("Button pressed");
}
public void OnGazeEnter(GameObject editor)
{
// 可选:高亮按钮等
}
public void OnGazeExit(GameObject editor)
{
// 可选:取消高亮
}
private IEnumerator SendSignalCoroutine()
{
SendSignal(true);
Interactable = false;
// 按钮压下的动画或效果可以在这里添加
yield return new WaitForSeconds(signalDuration);
SendSignal(false);
Interactable = true;
// 按钮弹起的动画或效果可以在这里添加
}
#endregion
#region EditableComponent
[SerializeField] private bool isActive = true;
public bool IsEditableActive
{
get => isActive;
set
{
isActive = value;
Interactable = isActive;
}
}
public string ComponentName { get; set; } = "Button";
public LockLevel LockLevel => LockLevel.Red;
#endregion
#region Connectable
public void OnGazeEnter()
{
}
public void OnGazeExit()
{
}
public Vector3 GetPosition()
{
return transform.position;
}
public GameObject GetGameObject()
{
return gameObject;
}
public string GetConnectableName()
{
return gameObject.name;
}
public List<ConnectionLine> ConnectionLines { get; set; } = new List<ConnectionLine>();
public void SignalActive(bool active, GameObject sender)
{
// 按钮通常不接收信号,因此这里可以留空
}
public void SendSignal(bool active)
{
if (ConnectionLines != null)
{
foreach (var line in ConnectionLines)
{
line.SignalActive(active, this.gameObject);
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7f5359facd804a0cb94d416c9c54a167
timeCreated: 1760923022

View File

@@ -0,0 +1,45 @@
using UnityEngine;
using Script.Gameplay.Interface;
namespace Script.Gameplay.Edit
{
[RequireComponent(typeof(Collider))]
public class ColliderEditableController : MonoBehaviour, IEditableComponent
{
[SerializeField] private bool isActive = true;
public bool IsEditableActive
{
get => isActive;
set
{
isActive = value;
// 具体被编辑的逻辑:开启或关闭碰撞体
if (_collider != null)
_collider.enabled = isActive;
}
}
public string ComponentName { get; set; } = "Collider";
public LockLevel LockLevel { get; } = LockLevel.Red;
private Collider _collider;
private void Awake()
{
_collider = GetComponent<Collider>();
// 应用序列化的初始状态
_collider.enabled = isActive;
}
#if UNITY_EDITOR
private void OnValidate()
{
// 在编辑器中即时生效
_collider = _collider == null ? GetComponent<Collider>() : _collider;
if (_collider != null)
_collider.enabled = isActive;
}
#endif
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2791e039b8344f45ad6dc86f5188d82d
timeCreated: 1760758233

View File

@@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using Script.Gameplay.Player;
using UnityEngine;
using Script.Gameplay.Interface;
using Script.Gameplay.Connect;
namespace Script.Gameplay.Edit
{
public class DoorInteractController : MonoBehaviour, IInteractable, IEditableComponent, IConnectable
{
#region Interactable
public bool Interactable = true;
private bool isOpened = false;
public string GetInteractPrompt()
{
return "按F进行交互";
}
public void Interact(GameObject interactor)
{
if (!Interactable) return;
if (isOpened)
{
CloseDoor();
isOpened = false;
}
else
{
OpenDoor();
isOpened = true;
}
}
public void OnGazeEnter(GameObject editor)
{
//
}
public void OnGazeExit(GameObject editor)
{
//
}
private void OpenDoor()
{
// 逆时针旋转90度
transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles + new Vector3(0, -90, 0));
// Debug.Log("Open door");
}
private void CloseDoor()
{
// 顺时针旋转90度
transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles + new Vector3(0, 90, 0));
// Debug.Log("Close door");
}
#endregion
#region EditableComponent
private bool isActive = true;
public bool IsEditableActive
{
get => isActive;
set
{
isActive = value;
//具体被编辑的逻辑
Interactable = isActive;
}
}
public string ComponentName { get; set; } = "DoorSwitch";
public LockLevel LockLevel => LockLevel.Red;
#endregion
#region Connectable
public void OnGazeEnter()
{
}
public void OnGazeExit()
{
}
public Vector3 GetPosition()
{
return transform.position;
}
public GameObject GetGameObject()
{
return gameObject;
}
public string GetConnectableName()
{
return gameObject.name;
}
public List<ConnectionLine> ConnectionLines { get; set; } = new List<ConnectionLine>();
public void SignalActive(bool active, GameObject sender)
{
Interact(sender);
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3bdc5380046d4cacb0dd579877f320eb
timeCreated: 1760693181

View File

@@ -0,0 +1,23 @@
using Core;
using UnityEngine;
using System.Collections.Generic;
using Script.Gameplay.Interface;
namespace Script.Gameplay.Edit
{
public class EditableManager : MonoSingleton<EditableManager>
{
public static List<IEditableComponent> GetEditableComponents(GameObject target)
{
var components = new List<IEditableComponent>();
foreach (var mb in target.GetComponentsInChildren<MonoBehaviour>(true))
{
if (mb is IEditableComponent editableComponent)
{
components.Add(editableComponent);
}
}
return components;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9704373d6ec1409bb4e26e4b16324c40
timeCreated: 1761035435

View File

@@ -0,0 +1,77 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Script.Gameplay.Connect;
using Script.Gameplay.Interface;
namespace Script.Gameplay.Edit
{
public class EmitterController : MonoBehaviour, IEditableComponent, IConnectable
{
[Header("发射器设置")]
[SerializeField] private GameObject prefabToEmit;
[SerializeField] private Transform emitPoint;
[SerializeField] private Vector3 emitDirection = Vector3.forward;
[SerializeField] private float emitForce = 10f;
[SerializeField] private float emitInterval = 1f;
[Header("生成对象销毁时间")]
[SerializeField] private float destroyDelay = 5f; // 生成对象多少秒后销毁
private Coroutine emitCoroutine;
// 不可交互
// 可编辑
public bool IsEditableActive { get; set; } = true;
public string ComponentName { get; set; } = "Emitter";
public LockLevel LockLevel => LockLevel.Red;
// 可连线
public List<ConnectionLine> ConnectionLines { get; set; } = new List<ConnectionLine>();
public void OnGazeEnter() { }
public void OnGazeExit() { }
public Vector3 GetPosition() => transform.position;
public GameObject GetGameObject() => gameObject;
public string GetConnectableName() => gameObject.name;
// 接收信号
public void SignalActive(bool active, GameObject sender)
{
if(!IsEditableActive) return;
if (active)
{
if (emitCoroutine == null)
emitCoroutine = StartCoroutine(EmitRoutine());
}
else
{
if (emitCoroutine != null)
{
StopCoroutine(emitCoroutine);
emitCoroutine = null;
}
}
}
private IEnumerator EmitRoutine()
{
while (true)
{
Emit();
yield return new WaitForSeconds(emitInterval);
}
}
private void Emit()
{
if (prefabToEmit == null || emitPoint == null) return;
var obj = Instantiate(prefabToEmit, emitPoint.position, emitPoint.rotation);
var rb = obj.GetComponent<Rigidbody>();
if (rb != null)
{
rb.AddForce(emitPoint.TransformDirection(emitDirection.normalized) * emitForce, ForceMode.Impulse);
}
// 添加销毁逻辑
Destroy(obj, destroyDelay);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1a5a563132c84e50b983b557eb3da442
timeCreated: 1761028056

View File

@@ -0,0 +1,30 @@
using UnityEngine;
using Script.Gameplay.Interface;
namespace Script.Gameplay.Edit
{
public abstract class InteractableBaseController : MonoBehaviour, IInteractable
{
public bool Interactable = true;
public string GetInteractPrompt()
{
return "按F进行交互";
}
public virtual void Interact(GameObject interactor)
{
if (!Interactable) return;
Debug.Log($"{gameObject.name} 被 {interactor.name} 交互了!");
}
public void OnGazeEnter(GameObject editor)
{
// 修改鼠标指针或高亮显示物体等
}
public void OnGazeExit(GameObject editor)
{
// 恢复鼠标指针或取消高亮显示物体等
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f5781ad9dd2842a584b8ef333ae75e60
timeCreated: 1760693365

View File

@@ -0,0 +1,97 @@
using System.Collections.Generic;
using UnityEngine;
using Script.Gameplay.Interface;
using Script.Gameplay.Connect;
namespace Script.Gameplay.Edit
{
public class LeverInteractController : MonoBehaviour, IInteractable, IEditableComponent, IConnectable, ISignalSender
{
#region Interactable
public bool Interactable = true;
private bool isPulled = false;
public string GetInteractPrompt()
{
return "按F拉动拉杆";
}
public void Interact(GameObject interactor)
{
if (!Interactable) return;
isPulled = !isPulled;
SendSignal(isPulled);
// 可选:拉杆动画
Debug.Log(isPulled ? "Lever pulled down" : "Lever reset");
}
public void OnGazeEnter(GameObject editor)
{
// 可选:高亮拉杆
}
public void OnGazeExit(GameObject editor)
{
// 可选:取消高亮
}
#endregion
#region EditableComponent
[SerializeField] private bool isActive = true;
public bool IsEditableActive
{
get => isActive;
set
{
isActive = value;
Interactable = isActive;
}
}
public string ComponentName { get; set; } = "Lever";
public LockLevel LockLevel => LockLevel.Red;
#endregion
#region Connectable
public void OnGazeEnter()
{
}
public void OnGazeExit()
{
}
public Vector3 GetPosition() => transform.position;
public GameObject GetGameObject()
{
return gameObject;
}
public string GetConnectableName() => gameObject.name;
public List<ConnectionLine> ConnectionLines { get; set; }= new List<ConnectionLine>();
public void SignalActive(bool active, GameObject sender)
{
//
}
public void SendSignal(bool active)
{
if (ConnectionLines != null)
{
foreach (var line in ConnectionLines)
{
line.SignalActive(active, this.gameObject);
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6b9b9a895b0d40edb9a6d7213afbb256
timeCreated: 1760925436

View File

@@ -0,0 +1,76 @@
using System.Collections.Generic;
using UnityEngine;
using Script.Gameplay.Connect;
namespace Script.Gameplay.Edit
{
// 号码枚举类型
public enum NumberType
{
Zero,
One,
Two,
Three,
Four,
Five,
// Six,
// Seven,
// Eight,
// Nine
}
// 号码槽
public class NumberSlotController : MonoBehaviour, IConnectable, ISignalSender
{
[Header("号码槽设置")]
[SerializeField] private NumberType currentNumber = NumberType.Zero;
[SerializeField] private NumberType correctNumber = NumberType.One;
public List<ConnectionLine> ConnectionLines { get; set; } = new List<ConnectionLine>();
// 不可编辑,不可交互
// 可连接,可发信号
public void OnGazeEnter() { }
public void OnGazeExit() { }
public Vector3 GetPosition() => transform.position;
public GameObject GetGameObject() => gameObject;
public string GetConnectableName() => gameObject.name;
// 接收信号
public void SignalActive(bool active, GameObject sender)
{
if (active)
{
SwitchToNextNumber();
}
}
// 切换到下一个号码
private void SwitchToNextNumber()
{
currentNumber = (NumberType)(((int)currentNumber + 1) % System.Enum.GetValues(typeof(NumberType)).Length);
CheckNumberAndSendSignal();
}
// 检查号码并发信号
private void CheckNumberAndSendSignal()
{
bool isCorrect = currentNumber == correctNumber;
SendSignal(isCorrect);
}
// 发出信号
public void SendSignal(bool active)
{
if (ConnectionLines != null)
{
foreach (var line in ConnectionLines)
{
line.SignalActive(active, this.gameObject);
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 301178d89b6b43e0844e3d39aa579442
timeCreated: 1760961220

View File

@@ -0,0 +1,88 @@
using System.Collections.Generic;
using UnityEngine;
using Script.Gameplay.Interface;
using Script.Gameplay.Connect;
namespace Script.Gameplay.Edit
{
public class PressurePlateController : MonoBehaviour, IEditableComponent, IConnectable, ISignalSender
{
[SerializeField] private bool isActive = true;
[SerializeField] private LayerMask detectLayer = ~0; // 检测所有层可在Inspector中指定
[SerializeField] private Vector3 plateSize = new Vector3(1, 0.2f, 1);
[SerializeField] private Vector3 plateOffset = Vector3.up * 0.1f;
private bool lastState = false;
private void FixedUpdate()
{
if (!isActive) return;
bool hasObject = Physics.CheckBox(transform.position + plateOffset, plateSize * 0.5f, Quaternion.identity,
detectLayer);
if (hasObject != lastState)
{
SendSignal(hasObject);
lastState = hasObject;
}
}
#region EditableComponent
public bool IsEditableActive
{
get => isActive;
set => isActive = value;
}
public string ComponentName { get; set; } = "PressurePlate";
public LockLevel LockLevel => LockLevel.Red;
#endregion
#region Connectable
public void OnGazeEnter()
{
}
public void OnGazeExit()
{
}
public Vector3 GetPosition() => transform.position;
public GameObject GetGameObject()
{
return gameObject;
}
public string GetConnectableName() => gameObject.name;
public List<ConnectionLine> ConnectionLines { get; set; } = new List<ConnectionLine>();
public void SignalActive(bool active, GameObject sender)
{
//
}
public void SendSignal(bool active)
{
if (ConnectionLines != null)
{
foreach (var line in ConnectionLines)
{
line.SignalActive(active, this.gameObject);
}
}
}
#endregion
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireCube(transform.position + plateOffset, plateSize);
}
#endif
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2557c7d42f7a4d8896712ab2ae980b6f
timeCreated: 1760924285

View File

@@ -0,0 +1,43 @@
using UnityEngine;
using Script.Gameplay.Interface;
namespace Script.Gameplay.Edit
{
[RequireComponent(typeof(Rigidbody))]
public class RigidbodyEditableController : MonoBehaviour, IEditableComponent
{
[SerializeField] private bool isActive = true;
public bool IsEditableActive
{
get => isActive;
set
{
isActive = value;
//具体被编辑的逻辑
_rigidbody.isKinematic = !isActive;
}
}
public string ComponentName { get; set; } = "Rigidbody";
public LockLevel LockLevel { get; } = LockLevel.Red;
private Rigidbody _rigidbody;
private void Awake()
{
_rigidbody = GetComponent<Rigidbody>();
//应用序列化的初始状态
_rigidbody.isKinematic = !isActive;
}
#if UNITY_EDITOR
private void OnValidate()
{
//在编辑器中即时生效
_rigidbody = _rigidbody == null ? GetComponent<Rigidbody>() : _rigidbody;
if (_rigidbody != null)
_rigidbody.isKinematic = !isActive;
}
#endif
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 06015834a0da4561ba47d104b73171a4
timeCreated: 1760757148