using System; using System.Collections.Generic; using System.Linq; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.Events; using UnityEngine.Pool; using UnityEngine.UIElements; #if UNITY_EDITOR using UnityEditor; using UnityEditor.UIElements; #endif namespace BITKit.Sensors { public class TriggerSensor : MonoBehaviour, ISensor { [Header(Constant.Header.Settings)] [SerializeField] private List ignores = new(); [SerializeField] private Optional detectedLayer; [SerializeField] private bool allowStatic; [SerializeField] private bool useRigidbody; [SerializeField] private bool immediately = false; [Header(Constant.Header.Events)] public UnityEvent onDetected = new(); public UnityEvent onLost = new(); [Header(Constant.Header.InternalVariables)] // ReSharper disable once FieldCanBeMadeReadOnly.Local private List detected = new(); public HashSet Ignores { get; } = new(); private readonly Queue triggerEnterQueue = new(); private readonly Queue triggerExitQueue = new(); private bool diagnosisNextFrame; private void OnTriggerEnter(Collider _collider) { triggerEnterQueue.Enqueue(_collider); if (immediately) Rebuild(); } private void OnTriggerExit(Collider _collider) { triggerExitQueue.Enqueue(_collider); if (immediately) Rebuild(); } private void OnCollisionEnter(Collision collision) { var _collider = collision.collider; if (!IsValid(_collider)) return; detected.Add(_collider); onDetected.Invoke(_collider); } private void OnCollisionStay(Collision collision) { var _collider = collision.collider; if (detected.TryRemove(_collider)) { onLost.Invoke(_collider); } } public int Id => _id is 0 ? _id = GetInstanceID() : _id; private int _id; public IEnumerable Get() { if(BITAppForUnity.IsPlaying is false)return ArraySegment.Empty; try { return detected.Select(x => x.transform).ToArray(); } catch (MissingReferenceException) { detected = detected.Where(x => x).ToList(); } return detected.Select(x => x.transform).ToArray(); } //public bool IsValid(Collider _collider) => ignores.Contains(_collider.gameObject) is false; public bool IsValid(Collider _collider) { if(allowStatic is false && _collider.gameObject.isStatic) return false; var attachedRigidbody = _collider.attachedRigidbody; var detectedObject = _collider switch { var x when attachedRigidbody is not null && useRigidbody => attachedRigidbody.gameObject, _ => _collider.gameObject, }; if (ignores.Contains(detectedObject)) return false; return !detectedLayer.Allow || detectedLayer.Value.Includes(_collider.gameObject.layer); } public float GetDistance() { throw new NotImplementedException(); } public UniTask Execute(float delta = 0)=> UniTask.CompletedTask; private void Update() { if (immediately is false) { Rebuild(); } } private void Rebuild() { while (triggerEnterQueue.TryDequeue(out var _collider)) { if (IsValid(_collider) is false) return; if (detected.Contains(_collider))continue; onDetected.Invoke(_collider); detected.Add(_collider); } while (triggerExitQueue.TryDequeue(out var _collider)) { if (IsValid(_collider) is false) return; onLost.Invoke(_collider); detected.Remove(_collider); } try { diagnosisNextFrame = detected.Any(x =>x is not null &&x.enabled is false); } catch (MissingReferenceException) { diagnosisNextFrame = true; } if (diagnosisNextFrame) { var list = ListPool.Get(); foreach (var VARIABLE in detected) { try { list.Add(VARIABLE); } catch (MissingReferenceException) { } } detected.Clear(); detected.AddRange(list); ListPool.Release(list); diagnosisNextFrame = false; } } } #if UNITY_EDITOR [CustomEditor(typeof(Sensor),true)] public class SensorInspector:BITInspector { private VisualElement detectedContainer; public override VisualElement CreateInspectorGUI() { FillDefaultInspector(); detectedContainer = root.Create(); return root; } protected override void OnUpdate() { if (!agent || detectedContainer is null) return; if (BITAppForUnity.IsPlaying is false) return; detectedContainer.Clear(); foreach (var x in agent.Get()) { ObjectField objectField = new() { objectType = x.GetType(), value = x, }; objectField.SetEnabled(false); objectField.style.opacity = 1; detectedContainer.Add(objectField); } } } [CustomEditor(typeof(TriggerSensor),true)] public class TriggerSensorInspector:BITInspector { private VisualElement detectedContainer; public override VisualElement CreateInspectorGUI() { FillDefaultInspector(); detectedContainer = root.Create(); return root; } protected override void OnUpdate() { if (detectedContainer is null) return; detectedContainer.Clear(); foreach (var x in agent.Get()) { ObjectField objectField = new() { objectType = x.GetType(), value = x, }; objectField.SetEnabled(false); detectedContainer.Add(objectField); } } } #endif }