AOEEntityAI.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. using FL.Battle.Actions;
  2. using FL.Battle.Skills;
  3. using System;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using XGame.Database;
  7. using XGame.Framework;
  8. using XGame.Framework.Components;
  9. using XGame.Framework.Time;
  10. namespace FL.Battle.Components.AI
  11. {
  12. public interface IAOEEntityAIContext
  13. {
  14. long UID { get; }
  15. long MasterId { get; }
  16. int TableId { get; }
  17. ITargetSelector Selector { get; }
  18. ITimeModule Time { get; }
  19. Vector3 Position { get; }
  20. Transform Tr { get; }
  21. MoveComponent Move { get; }
  22. VfxComponent Vfx { get; }
  23. }
  24. /// <summary>
  25. /// AI组件和具体的EntityView绑定,其他Component最好不要尝试获取AI组件
  26. /// 虫群特效半径为1,配置宽高需要X2,该特效不适合缩放,预制按照目标尺寸重复摆放基础特效
  27. /// </summary>
  28. public class AOEEntityAI : Component<IAOEEntityAIContext>
  29. {
  30. private EEntityType _targetType;
  31. private ITimer _aoeTimer;
  32. private ITimer _stopTimer;
  33. private SkillTable _skill;
  34. private SkillVfxsTable _skillVfxs;
  35. private List<ITarget> _targets = new List<ITarget>();
  36. private HashSet<long> _selectedTargetIds = new();
  37. private Dictionary<long, int> _targetHitTimesMap = new();
  38. protected override void OnDispose()
  39. {
  40. _selectedTargetIds.Clear();
  41. _targetHitTimesMap.Clear();
  42. _targets.Clear();
  43. _aoeTimer?.Cancel();
  44. _aoeTimer = null;
  45. _stopTimer?.Cancel();
  46. _stopTimer = null;
  47. _skill = null;
  48. _skillVfxs = null;
  49. }
  50. public void Start(Vector3 targetPosition, EEntityType targetType)
  51. {
  52. _skill = SkillTableRepo.Get(Context.TableId);
  53. _skillVfxs = SkillVfxsTableRepo.Get(Context.TableId);
  54. _targetType = targetType;
  55. //Context.ParticleTr.localScale = new Vector3(_skill.Ranges[1] * 0.5f, _skill.Ranges[2] * 0.5f, 1);
  56. // 飞到目标位置
  57. if (_skill.SkillVfxType == (int)ESkillVfxType.AOE)
  58. {
  59. var moveArgs = new MoveArgs()
  60. {
  61. target = targetPosition,
  62. speed = _skillVfxs.SkillVfxSpeed,
  63. timeScale = 1,
  64. onComplete = StopAOE
  65. };
  66. if (Enum.TryParse<DG.Tweening.Ease>(_skillVfxs.SkillVfxMoveEase, true, out var ease))
  67. {
  68. moveArgs.ease = ease;
  69. }
  70. //Context.Tr.forward = (targetPosition - Context.Position).normalized;
  71. Context.Move.MoveTo(moveArgs);
  72. }
  73. else
  74. { //TODO 判断是否需要左右镜像
  75. Context.Tr.localScale = new Vector3(-1, 1, 1);
  76. _stopTimer = Context.Time.AddDelayTimer(_skillVfxs.SkillVfxTime, StopAOE);
  77. }
  78. _aoeTimer = Context.Time.AddDelayLooperTimer(_skill.DamageArgs[1], _skill.DamageArgs[2], OnAOE, _skill.DamageArgs[0]);
  79. }
  80. private void OnAOE(int obj)
  81. {
  82. // 是否重复选中,0:false
  83. var isSelectOnce = _skill.DamageArgs[3] == 0;
  84. // 受击次数,-1:不限,1:1次
  85. var hitLimit = _skill.DamageArgs[4];
  86. bool IsFilt(ITarget a)
  87. {
  88. if (isSelectOnce)
  89. return _selectedTargetIds.Contains(a.Entity.EntityId);
  90. return false;
  91. }
  92. bool isHaveTargets;
  93. if (_skill.Ranges[0] == 1)
  94. { // 矩形
  95. var size = new Vector2(_skill.Ranges[1], _skill.Ranges[2]);
  96. Vector2 position = Context.Position;
  97. position -= (size * 0.5f);
  98. var rect = new Rect(position, size);
  99. isHaveTargets = Context.Selector.FindTargets(rect, _targetType, ETargetFindType.InRangeAlive, IsFilt, ref _targets);
  100. }
  101. else
  102. {
  103. var finder = new FinderInfo()
  104. {
  105. uid = Context.UID,
  106. position = Context.Position,
  107. radius = _skill.Ranges[1]
  108. };
  109. isHaveTargets = Context.Selector.FindTargets(finder, _targetType, ETargetFindType.InRangeAlive, IsFilt, ref _targets);
  110. }
  111. if (isHaveTargets)
  112. {
  113. // 计算受击伤害
  114. foreach (var target in _targets)
  115. {
  116. var targetId = target.Entity.EntityId;
  117. var hitTimes = 0;
  118. var damage = _skill.Damage;
  119. if (hitLimit < 0 || _targetHitTimesMap.TryGetValue(targetId, out hitTimes) == false || hitTimes < hitLimit)
  120. { // 没有有受击次数限制 或 受击次数未达到上限
  121. PlayHitVfx(target.Position);
  122. if (_skill.Ranges[0] == 2 && _skill.Ranges.Length == 5)
  123. { // 圆形,有半径递减
  124. var distance = Vector3.Distance(target.Position, Context.Position);
  125. if (distance > _skill.Ranges[3])
  126. {
  127. // 向上取整
  128. damage = Mathf.CeilToInt((1 - _skill.Ranges[4]) * damage);
  129. }
  130. }
  131. }
  132. else
  133. { // 本次受击不造成伤害,但是还是要判断触发buff等
  134. damage = 0;
  135. }
  136. //if (_skill.SkillVfxType == (int)ESkillVfxType.AOETarget)
  137. //{
  138. // Log.Debug($"Skill AOE Id:{_skill.Id} target:{targetId} damage:{damage}");
  139. //}
  140. target.Calculation.Damage(-damage, Context.MasterId, _skill);
  141. if (hitLimit > 0)
  142. { // 记录目标受击次数
  143. _targetHitTimesMap[targetId] = ++hitTimes;
  144. }
  145. if (isSelectOnce)
  146. _selectedTargetIds.Add(targetId);
  147. }
  148. _targets.Clear();
  149. }
  150. //if (_skill.SkillVfxType == (int)ESkillVfxType.AOENoMove)
  151. //{
  152. // StopAOE();
  153. //}
  154. }
  155. /// <summary>
  156. /// 受击特效
  157. /// </summary>
  158. /// <param name="targetPosition"></param>
  159. private void PlayHitVfx(Vector3 targetPosition)
  160. {
  161. if (string.IsNullOrEmpty(_skillVfxs.HitVfx))
  162. return;
  163. var actPosition = ObjectPool.Acquire<PositionAction>();
  164. actPosition.position = targetPosition;
  165. var hitArgs = ObjectPool.Acquire<VfxArgs>();
  166. hitArgs.vfxName = _skillVfxs.HitVfx;
  167. hitArgs.duration = _skillVfxs.HitVfxTime;
  168. hitArgs.followType = EVfxFollowType.World;
  169. hitArgs.action = actPosition;
  170. Context.Vfx.Play(hitArgs);
  171. }
  172. private void StopAOE()
  173. {
  174. _aoeTimer?.Cancel();
  175. _aoeTimer = null;
  176. _stopTimer?.Cancel();
  177. _stopTimer = null;
  178. EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveSimpleEntity, Context.UID);
  179. }
  180. }
  181. }