TargetSelector.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using XGame;
  5. namespace FL.Battle
  6. {
  7. public interface ITargetHandle
  8. {
  9. IEntity Entity { get; }
  10. Vector3 Position { get; }
  11. /// <summary>
  12. /// 是否可选中
  13. /// </summary>
  14. bool IsCanSelected { get; }
  15. float Radius { get; }
  16. float AtkRange { get; }
  17. void SelectTarget(ITargetHandle target, int skillId);
  18. }
  19. public struct FindTargetArgs
  20. {
  21. public int entityId;
  22. public EEntityType entityType;
  23. /// <summary>
  24. /// 范围
  25. /// </summary>
  26. public float range;
  27. /// <summary>
  28. /// 为零表示普通攻击
  29. /// </summary>
  30. public int skillId;
  31. }
  32. /// <summary>
  33. /// 目标选择组件
  34. /// </summary>
  35. public class TargetSelector
  36. {
  37. private Dictionary<EEntityType, HashSet<ITargetHandle>> _typeToHandlesMap;
  38. private Dictionary<int, ITargetHandle> _idToHandlesMap;
  39. private Dictionary<ITargetHandle, FindTargetArgs> _waitingMap;
  40. private List<ITargetHandle> _tempLst = new List<ITargetHandle>();
  41. public void Register(ITargetHandle handle)
  42. {
  43. if (_typeToHandlesMap == null)
  44. {
  45. _typeToHandlesMap = new Dictionary<EEntityType, HashSet<ITargetHandle>>();
  46. _idToHandlesMap = new Dictionary<int, ITargetHandle>();
  47. }
  48. var type = handle.Entity.EntityType;
  49. if (!_typeToHandlesMap.TryGetValue(type, out var handles))
  50. {
  51. handles = new HashSet<ITargetHandle>();
  52. _typeToHandlesMap.Add(type, handles);
  53. }
  54. handles.Add(handle);
  55. _idToHandlesMap.Add(handle.Entity.EntityId, handle);
  56. }
  57. public void Unregister(ITargetHandle handle)
  58. {
  59. if (_typeToHandlesMap == null) return;
  60. foreach(var handles in _typeToHandlesMap.Values)
  61. {
  62. if (handles.Contains(handle))
  63. {
  64. handles.Remove(handle);
  65. break;
  66. }
  67. }
  68. _idToHandlesMap.Remove(handle.Entity.EntityId);
  69. _waitingMap?.Remove(handle);
  70. }
  71. public void Start(FindTargetArgs args)
  72. {
  73. if (_idToHandlesMap == null || _idToHandlesMap.TryGetValue(args.entityId, out var handle) == false)
  74. {
  75. return;
  76. }
  77. if (_waitingMap == null)
  78. {
  79. _waitingMap = new Dictionary<ITargetHandle, FindTargetArgs>();
  80. }
  81. _waitingMap[handle] = args;
  82. }
  83. public void Selects()
  84. {
  85. var count = _waitingMap?.Count ?? 0;
  86. if (count == 0)
  87. return;
  88. _tempLst.AddRange(_waitingMap.Keys);
  89. for(var i = 0; i < count; i++)
  90. {
  91. var director = _tempLst[i];
  92. if (!director.IsCanSelected)
  93. continue;
  94. if (!_waitingMap.TryGetValue(director, out var args))
  95. {
  96. continue;
  97. }
  98. if (!TryGetTargets(args.entityType, out var targets))
  99. {
  100. Log.Debug($"没有可选目标 Entity:{director.Entity.TableId} Relation:{director.Entity.EntityType} Target:{args.entityType}");
  101. continue;
  102. }
  103. ITargetHandle preTarget = null;
  104. var distanceMin = float.MaxValue;
  105. foreach (var target in targets)
  106. {
  107. if (!target.IsCanSelected)
  108. continue;
  109. if (IsInRange(director, target, args.range, out var distance))
  110. {
  111. if (preTarget == null || distanceMin > distance)
  112. {
  113. preTarget = target;
  114. distanceMin = distance;
  115. }
  116. }
  117. }
  118. if (preTarget != null)
  119. {
  120. try
  121. {
  122. director.SelectTarget(preTarget, args.skillId);
  123. _waitingMap.Remove(director);
  124. }
  125. catch (Exception ex)
  126. {
  127. Log.Exception(ex);
  128. }
  129. }
  130. }
  131. _tempLst.Clear();
  132. }
  133. private bool TryGetTargets(EEntityType entityType, out HashSet<ITargetHandle> targets)
  134. {
  135. if (_typeToHandlesMap != null && _typeToHandlesMap.TryGetValue(entityType, out targets))
  136. {
  137. return true;
  138. }
  139. targets = null;
  140. return false;
  141. }
  142. private bool IsInRange(ITargetHandle director, ITargetHandle target, float range, out float distance)
  143. {
  144. distance = Vector3.Distance(target.Position, director.Position);
  145. distance -= (director.Radius + target.Radius); // 去掉双方的半径
  146. return true;// range >= distance;
  147. }
  148. public void Clear()
  149. {
  150. _typeToHandlesMap?.Clear();
  151. _idToHandlesMap?.Clear();
  152. _waitingMap?.Clear();
  153. _tempLst?.Clear();
  154. }
  155. }
  156. }