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.UIElements; namespace BITKit.Sensors { /// /// 智能目标传感器,根据条件,智能选择目标 /// public class SmartTargetSensor :MonoBehaviour,ISensor,IAction { /// /// 自动更新 /// [Header(Constant.Header.Settings)] [SerializeField] private bool autoUpdate; /// /// 目标有效性验证 /// [Header(Constant.Header.Providers)] [SerializeField,SerializeReference,SubclassSelector] private IValidityProvider validityProvider; /// /// 主传感器 /// [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) =>validityProvider?.IsValid(_collider) ?? true; public float GetDistance() => sensor.GetDistance(); public Transform CurrentTarget { get; private set; } private readonly List detected = new(); public async UniTask Execute() { await sensor.Execute(); var _detected = sensor.Get().ToList(); if (_detected.Contains(CurrentTarget)) { if (detected.Count is 1 && detected[0] == CurrentTarget) { } else { detected.Clear(); detected.Add(CurrentTarget); } return; } CurrentTarget = _detected .Where(_transform => IsValid(_transform.GetComponent())) .OrderBy(_transform => Vector3.Distance(transform.position, _transform.position)) .FirstOrDefault(); } private void Update() { if(autoUpdate)Execute().Forget(); } void IAction.Execute() { Execute().Forget(); } #if UNITY_EDITOR private void OnDrawGizmosSelected() { if (CurrentTarget is null) return; Gizmos.DrawLine(sensorTransform.position,CurrentTarget.position); } #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 }