using System; using System.Collections.Generic; using System.Linq; using System.Threading; using Cysharp.Threading.Tasks; #if UNITY_EDITOR using UnityEditor; using UnityEditor.UIElements; #endif using UnityEngine; using UnityEngine.Accessibility; using UnityEngine.Profiling; using UnityEngine.UIElements; // ReSharper disable PossibleMultipleEnumeration namespace BITKit.Sensors { /// /// 智能目标传感器,根据条件,智能选择目标 /// public class SmartTargetSensor :MonoBehaviour,ISensor,IAction { /// /// 自动更新 /// [Header(Constant.Header.Settings)] [SerializeField] private bool autoUpdate; [SerializeField] private Optional ignoreTags; [SerializeField] private Optional optionalRetargetInterval; /// /// 主传感器 /// [Header(nameof(Sensor))] [SerializeField,SerializeReference,SubclassSelector] private ISensor sensor; [Header(Constant.Header.Debug)] [SerializeReference, ReadOnly] private int updateCount; public IEnumerable Get() =>CurrentTarget is not null ? new[] { CurrentTarget }:Enumerable.Empty(); bool ISensor.AutoUpdate => autoUpdate; public bool IsValid(Collider _collider) { if (!_collider) return false; if (ignoreTags.Allow) { if (_collider.TryGetComponent(out var iTags)) { var tags = iTags.GetTags(); foreach (var x in ignoreTags.Value) { if (tags.Contains(x)) { return false; } } } } return true; } public float GetDistance() => sensor.GetDistance(); public Transform CurrentTarget { get; private set; } private IEnumerable detected = ArraySegment.Empty; private Vector3 _currentPosition; private int Id; private CancellationTokenSource timeoutCancellationTokenSource=new(); private void OnEnable() { SensorQueue.Register(Id=GetInstanceID(),this); } private void OnDisable() { SensorQueue.UnRegister(Id); } public async UniTask Execute() { updateCount++; timeoutCancellationTokenSource?.Cancel(); timeoutCancellationTokenSource = new CancellationTokenSource(); await sensor.Execute(); Profiler.BeginSample("Release Detected Buffer"); var newDetected = sensor.Get(); Profiler.EndSample(); // ReSharper disable once PossibleMultipleEnumeration if (newDetected.Contains(CurrentTarget)) { if (optionalRetargetInterval.Allow && optionalRetargetInterval.Value.AllowUpdate) { } else { return; } } Profiler.BeginSample("Filter Detected"); // // ReSharper disable once PossibleMultipleEnumeration // CurrentTarget = newDetected // .Where(_transform => IsValid(_transform.GetComponent())) // .OrderBy(_transform => Vector3.Distance(currentPosition, _transform.position)) // .FirstOrDefault(); foreach (var x in newDetected.OrderBy(KeySelector)) { if(IsValid(x.GetComponent()) is false)continue; CurrentTarget = x; break; } Profiler.EndSample(); } private float KeySelector(Transform x) { return Vector3.Distance(_currentPosition, x.position); } void IAction.Execute() { Execute().Forget(); } #if UNITY_EDITOR private void OnDrawGizmosSelected() { try { if (!CurrentTarget) return; Gizmos.DrawLine(transform.position,CurrentTarget.position); } catch (UnassignedReferenceException) { } } #endif } #if UNITY_EDITOR [CustomEditor(typeof(SmartTargetSensor))] public class SmartTargetSensorInspector:BITInspector { private ObjectField _objectField; public override VisualElement CreateInspectorGUI() { FillDefaultInspector(); CreateSubTitle("Editor Debug Field"); _objectField = root.Create(); _objectField.objectType = typeof(Transform); _objectField.SetEnabled(false); return root; } protected override void OnUpdate() { if (_objectField is not null) { _objectField.value = agent.CurrentTarget; } } } #endif }