1
This commit is contained in:
218
Assets/BITKit/Unity/Scripts/Sensor/TriggerSensor.cs
Normal file
218
Assets/BITKit/Unity/Scripts/Sensor/TriggerSensor.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
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<GameObject> ignores = new();
|
||||
|
||||
[SerializeField] private Optional<LayerMask> detectedLayer;
|
||||
[SerializeField] private bool allowStatic;
|
||||
[SerializeField] private bool useRigidbody;
|
||||
[SerializeField] private bool immediately = false;
|
||||
|
||||
[Header(Constant.Header.Events)] public UnityEvent<Collider> onDetected = new();
|
||||
public UnityEvent<Collider> onLost = new();
|
||||
|
||||
[Header(Constant.Header.InternalVariables)]
|
||||
// ReSharper disable once FieldCanBeMadeReadOnly.Local
|
||||
private List<Collider> detected = new();
|
||||
public HashSet<int> Ignores { get; } = new();
|
||||
|
||||
private readonly Queue<Collider> triggerEnterQueue = new();
|
||||
private readonly Queue<Collider> 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<Transform> Get()
|
||||
{
|
||||
if(BITAppForUnity.IsPlaying is false)return ArraySegment<Transform>.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<Collider>.Get();
|
||||
foreach (var VARIABLE in detected)
|
||||
{
|
||||
try
|
||||
{
|
||||
list.Add(VARIABLE);
|
||||
}
|
||||
catch (MissingReferenceException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
detected.Clear();
|
||||
detected.AddRange(list);
|
||||
ListPool<Collider>.Release(list);
|
||||
diagnosisNextFrame = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(Sensor),true)]
|
||||
public class SensorInspector:BITInspector<Sensor>
|
||||
{
|
||||
private VisualElement detectedContainer;
|
||||
public override VisualElement CreateInspectorGUI()
|
||||
{
|
||||
FillDefaultInspector();
|
||||
|
||||
detectedContainer = root.Create<VisualElement>();
|
||||
|
||||
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<TriggerSensor>
|
||||
{
|
||||
private VisualElement detectedContainer;
|
||||
public override VisualElement CreateInspectorGUI()
|
||||
{
|
||||
FillDefaultInspector();
|
||||
|
||||
detectedContainer = root.Create<VisualElement>();
|
||||
|
||||
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
|
||||
}
|
Reference in New Issue
Block a user