using System.Collections.Generic; using Script.Gameplay.Connect; using Script.Gameplay.Global; using Script.Gameplay.Interface; using UnityEngine; using UnityEngine.Experimental.GlobalIllumination; namespace Script.Gameplay.Facility { public class BaseFacilityController : MonoBehaviour, IInteractable, IEditableComponent, IConnectable, ISignalSender, ISignalReceiver, IGaze { [SerializeField] protected bool isEnableInteract = true; [SerializeField] protected bool isEnableEdit = true; [SerializeField] protected bool isEnableConnect = true; [SerializeField] protected bool isOpenInEditor = true; [SerializeField] protected int needSignalCount = 1; [SerializeField] protected int currentSignalCount = 0; [SerializeField] protected string componentName; [SerializeField] protected bool isEnableSendSignal = false; public virtual bool IsEnableInteract { get => isEnableInteract; set => isEnableInteract = value; } public virtual bool IsEnableEdit { get => isEnableEdit; set => isEnableEdit = value; } public virtual bool IsOpenInEditor { get => isOpenInEditor; set { isOpenInEditor = value; IsEnableInteract = value; IsEnableConnect = value; } } public virtual bool IsEnableConnect { get => isEnableConnect; set => isEnableConnect = value; } public virtual int NeedSignalCount { get => needSignalCount; set => needSignalCount = value; } public virtual int CurrentNeedSignalCount { get => currentSignalCount; set => currentSignalCount = value; } public string ComponentName { get { // 如果没有自定义名称,则使用组件名称 return string.IsNullOrEmpty(componentName) ? GetType().Name : componentName; } set => componentName = value; } public List ConnectionLines { get; set; } = new List(); public string GetConnectableName() { return gameObject.name; } public GameObject GetGameObject() { return gameObject; } public virtual string GetInteractPrompt() { return $"Interact with {componentName}"; } public Vector3 GetPosition() { return transform.position; } public virtual void Interact(GameObject interactor) { // Implement interaction logic here } public virtual void OnGazeEnter(GameObject go) { // Handle gaze enter } public virtual void OnGazeExit(GameObject go) { // Handle gaze exit } public virtual void OnSignalReceived(bool active, GameObject sender) { if (isEnableSendSignal) { SendSignal(active, sender); } if (active) { CurrentNeedSignalCount++; } else { CurrentNeedSignalCount = Mathf.Max(0, CurrentNeedSignalCount - 1); } if (CurrentNeedSignalCount < NeedSignalCount) { return; } // Implement signal received logic here } public bool IsEnableSendSignal { get => isEnableSendSignal; set => isEnableSendSignal = value; } /// /// /// /// 发送true or false /// 让此物体触发发送的来源者 public virtual void SendSignal(bool active, GameObject sender) { if (!IsEnableSendSignal) return; if (ConnectionLines != null) { // 利用DFS检测是否存在连接环 if (DfsCheckConnectionRing(this.gameObject)) { StartCoroutine(GameManager.Instance.ReStartGame()); return; } foreach (var line in ConnectionLines) { // 排除掉为sender的连接线 if (line.gameObject == sender) { continue; } line.OnSignalReceived(active, this.gameObject); } } } public static bool DfsCheckConnectionRing(GameObject root) { if (root == null) return false; var rootConnect = root.GetComponent(); if (rootConnect == null) return false; var visited = new HashSet(); // 内部递归 DFS,parent 用于避免把返回到父节点误判为环 bool Dfs(GameObject current, GameObject parent) { if (current == null) return false; visited.Add(current); var conn = current.GetComponent(); if (conn == null) return false; foreach (var line in conn.ConnectionLines) { if (line == null) continue; GameObject a = line.PointA?.GetGameObject(); GameObject b = line.PointB?.GetGameObject(); GameObject neighbor = null; if (a == current) neighbor = b; else if (b == current) neighbor = a; else continue; // 如果这条线并未连接到 current,跳过 if (neighbor == null) continue; // 如果邻居是父节点,跳过(因为这是无向边回到父) if (neighbor == parent) continue; // 已访问到其他非父节点,说明存在环 if (visited.Contains(neighbor)) { return true; } if (Dfs(neighbor, current)) { return true; } } return false; } return Dfs(root, null); } } }