using System; using System.Collections.Generic; using UnityEngine; using XGame; namespace FL.Battle { public interface ITargetHandle { IEntity Entity { get; } Vector3 Position { get; } /// /// 是否可选中 /// bool IsCanSelected { get; } float Radius { get; } float AtkRange { get; } void SelectTarget(ITargetHandle target, int skillId); } public struct FindTargetArgs { public int entityId; public EEntityType entityType; /// /// 范围 /// public float range; /// /// 为零表示普通攻击 /// public int skillId; } /// /// 目标选择组件 /// public class TargetSelector { private Dictionary> _typeToHandlesMap; private Dictionary _idToHandlesMap; private Dictionary _waitingMap; private List _tempLst = new List(); public void Register(ITargetHandle handle) { if (_typeToHandlesMap == null) { _typeToHandlesMap = new Dictionary>(); _idToHandlesMap = new Dictionary(); } var type = handle.Entity.EntityType; if (!_typeToHandlesMap.TryGetValue(type, out var handles)) { handles = new HashSet(); _typeToHandlesMap.Add(type, handles); } handles.Add(handle); _idToHandlesMap.Add(handle.Entity.EntityId, handle); } public void Unregister(ITargetHandle handle) { if (_typeToHandlesMap == null) return; foreach(var handles in _typeToHandlesMap.Values) { if (handles.Contains(handle)) { handles.Remove(handle); break; } } _idToHandlesMap.Remove(handle.Entity.EntityId); _waitingMap?.Remove(handle); } public void Start(FindTargetArgs args) { if (_idToHandlesMap == null || _idToHandlesMap.TryGetValue(args.entityId, out var handle) == false) { return; } if (_waitingMap == null) { _waitingMap = new Dictionary(); } _waitingMap[handle] = args; } public void Selects() { var count = _waitingMap?.Count ?? 0; if (count == 0) return; _tempLst.AddRange(_waitingMap.Keys); for(var i = 0; i < count; i++) { var director = _tempLst[i]; if (!director.IsCanSelected) continue; if (!_waitingMap.TryGetValue(director, out var args)) { continue; } if (!TryGetTargets(args.entityType, out var targets)) { Log.Debug($"没有可选目标 Entity:{director.Entity.TableId} Relation:{director.Entity.EntityType} Target:{args.entityType}"); continue; } ITargetHandle preTarget = null; var distanceMin = float.MaxValue; foreach (var target in targets) { if (!target.IsCanSelected) continue; if (IsInRange(director, target, args.range, out var distance)) { if (preTarget == null || distanceMin > distance) { preTarget = target; distanceMin = distance; } } } if (preTarget != null) { try { director.SelectTarget(preTarget, args.skillId); _waitingMap.Remove(director); } catch (Exception ex) { Log.Exception(ex); } } } _tempLst.Clear(); } private bool TryGetTargets(EEntityType entityType, out HashSet targets) { if (_typeToHandlesMap != null && _typeToHandlesMap.TryGetValue(entityType, out targets)) { return true; } targets = null; return false; } private bool IsInRange(ITargetHandle director, ITargetHandle target, float range, out float distance) { distance = Vector3.Distance(target.Position, director.Position); distance -= (director.Radius + target.Radius); // 去掉双方的半径 return true;// range >= distance; } public void Clear() { _typeToHandlesMap?.Clear(); _idToHandlesMap?.Clear(); _waitingMap?.Clear(); _tempLst?.Clear(); } } }