using System; using System.Collections.Generic; using System.Linq; using Cysharp.Threading.Tasks; #if UNITY_EDITOR using UnityEditor; using UnityEditor.UIElements; #endif using UnityEngine; using UnityEngine.Profiling; using UnityEngine.UIElements; 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; #if UNITY_EDITOR [Header(Constant.Header.Debug)] [SerializeField] private Transform sensorTransform; #endif public IEnumerable Get() =>CurrentTarget is not null ? new[] { CurrentTarget }:Enumerable.Empty(); public bool IsValid(Collider _collider) { 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; public async UniTask Execute() { var currentPosition = transform.position; 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(); Profiler.EndSample(); } private void Update() { if(autoUpdate && SensorGlobalSettings.Enabled)Execute().Forget(); } void IAction.Execute() { Execute().Forget(); } #if UNITY_EDITOR private void OnDrawGizmosSelected() { try { if (CurrentTarget is null || sensorTransform is null) return; Gizmos.DrawLine(sensorTransform.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 }