SimpleSkillActor.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. using FL.Battle.Actions;
  2. using FL.Battle.Components;
  3. using System;
  4. using UnityEngine;
  5. using XGame.Database;
  6. using XGame.Framework;
  7. using XGame.Framework.Interfaces;
  8. using XGame.Framework.Time;
  9. namespace FL.Battle.Skills
  10. {
  11. /// <summary>
  12. /// 简单的技能表现
  13. /// </summary>
  14. internal class SimpleSkillActor : ISkillActor, IReference
  15. {
  16. public ISkillContext Context { get; set; }
  17. private ITimer _skillTimer; //技能施法时间
  18. private ITimer _bulletTimer;
  19. private ITimer _noAniTimer; // 没有动作时受击特效的定时器
  20. private SkillTable _skill;
  21. private SkillVfxsTable _skillVfxs;
  22. void ISkillActor.Play(int skillId, ITarget target, Action<int, int> onCompleted)
  23. {
  24. _skill = SkillTableRepo.Get(skillId);
  25. _skillVfxs = SkillVfxsTableRepo.Get(skillId);
  26. var owner = Context.Entity;
  27. //if (/*_skill.BuffTie.Length == 0*/ (ESkillVfxType)_skill.SkillVfxType is ESkillVfxType.AOE or ESkillVfxType.Trap)
  28. //{
  29. // onCompleted(skillId, _skill.RestTime);
  30. // return;
  31. //}
  32. PlayCastVfx(target);
  33. var isHaveBullet = PlayBullets(target);
  34. PlaySkillAnimation(target, isHaveBullet);
  35. //TODO 最少900毫秒
  36. var duration = _skill.EndureTime;
  37. //var startTime = Time.realtimeSinceStartup;
  38. _skillTimer = Context.Time.AddDelayTimer(duration, () =>
  39. {
  40. //Log.Debug($"SimpleSkillActor Completed. Entity:{Context.Entity.EntityId} Name:{Context.Entity.Attr.Name} SkillId:{_skill.Id} Frame:{Time.frameCount} duration:{duration} start:{startTime} used:{Time.realtimeSinceStartup - startTime}");
  41. var skillCD = _skill.RestTime;
  42. onCompleted.SafeInvoke(skillId, skillCD);
  43. });
  44. }
  45. public void Stop()
  46. {
  47. _skill = null;
  48. _skillVfxs = null;
  49. _skillTimer?.Cancel();
  50. _skillTimer = null;
  51. _bulletTimer?.Cancel();
  52. _bulletTimer = null;
  53. _noAniTimer?.Cancel();
  54. _noAniTimer = null;
  55. }
  56. /// <summary>
  57. /// 播放施法特效
  58. /// </summary>
  59. /// <param name="target"></param>
  60. private void PlayCastVfx(ITarget target)
  61. {
  62. if (!string.IsNullOrEmpty(_skillVfxs.CastVfx))
  63. {
  64. VfxArgs vfxArgs = ObjectPool.Acquire<VfxArgs>();
  65. vfxArgs.vfxName = _skillVfxs.CastVfx;
  66. vfxArgs.duration = _skillVfxs.CastVfxTime;
  67. vfxArgs.followType = EVfxFollowType.CastPoint; //(EVfxFollowType)_skillVfxs.VfxFollowType;
  68. if (_skill.Id == 200705)
  69. { // TODO
  70. var actFoword = ObjectPool.Acquire<ForwordAction>();
  71. actFoword.forword = (target.Position - Context.Position).normalized;
  72. vfxArgs.action = actFoword;
  73. }
  74. //vfxArgs.onFinish = OnSkillVfxFinish;
  75. Context.Vfx.Play(vfxArgs);
  76. }
  77. }
  78. /// <summary>
  79. /// 播放施法动作
  80. /// </summary>
  81. /// <param name="target"></param>
  82. /// <param name="isHaveBullet">是否有子弹,没子弹才需要播放受击特效</param>
  83. private void PlaySkillAnimation(ITarget target, bool isHaveBullet)
  84. {
  85. var actionName = _skillVfxs.AniName;
  86. if (actionName == EAnimationName.skill && Context.Entity.EntityType != EEntityType.Partner)
  87. { //TODO 现在只有随从有施法动作
  88. actionName = EAnimationName.attack;
  89. }
  90. //if (skill.Id == 200707)
  91. //{
  92. // actionName = EAnimationName.skill2;
  93. //}
  94. var skillVfxTyp = (ESkillVfxType)_skill.SkillVfxType;
  95. void onTrigger()
  96. {
  97. _noAniTimer = null;
  98. if (skillVfxTyp is ESkillVfxType.Trap or ESkillVfxType.AOE or ESkillVfxType.AOENoMove or ESkillVfxType.AOETarget)
  99. { //播放召唤兽特效
  100. SummonBeat(target);
  101. }
  102. else
  103. { // target不为空,播放受击特效
  104. PlayHitVfx(target);
  105. }
  106. }
  107. if (actionName >= EAnimationName.attack)
  108. { // 有攻击动作
  109. var skillId = _skillVfxs.Id;
  110. var entityName = Context.Entity.Attr.Name;
  111. var actArgs = new AnimationPlayArgs()
  112. {
  113. aniName = actionName,
  114. //onCompleted = () =>
  115. //{
  116. // Assert.IsNotNull(Context, $"技能动作回调,Context不能为空. skillId:{skillId} entityName:{entityName}");
  117. // Context.Animator.Play(EAnimationName.idle/* + UnityEngine.Random.Range(0, 100) % 2*/);
  118. //}
  119. };
  120. if (!isHaveBullet)
  121. { // 没有子弹,300毫秒后召唤或者播放受击特效
  122. actArgs.triggerFrame = _skillVfxs.SkillVfxDelay;
  123. actArgs.onTrigger = onTrigger;
  124. }
  125. Context.Animator.Play(actArgs);
  126. }
  127. else if (!isHaveBullet)
  128. { // 没有子弹,300毫秒后召唤或者播放受击特效
  129. _noAniTimer = Context.Time.AddDelayTimer(_skillVfxs.SkillVfxDelay, onTrigger);
  130. }
  131. }
  132. /// <summary>
  133. /// 播放子弹
  134. /// </summary>
  135. /// <param name="target"></param>
  136. /// <returns></returns>
  137. private bool PlayBullets(ITarget target)
  138. {
  139. var bulletCount = _skill.SkillVfxType / 100 == 1 ? _skillVfxs.SkillVfxCount : 0;
  140. if (bulletCount > 0)
  141. { // 有子弹,设置子弹的定时器
  142. var targetId = target?.Entity.EntityId ?? 0;
  143. var to = target?.Position ?? Vector3.zero;
  144. var randomIdx = -1;
  145. if (_skill.SkillVfxType == (int)ESkillVfxType.BulletMortar)
  146. { // 随机一个索引确保有一个目标坐标在敌人位置
  147. randomIdx = UnityEngine.Random.Range(0, 1000) % bulletCount;
  148. }
  149. _bulletTimer = Context.Time.AddDelayLooperTimer(_skillVfxs.SkillVfxDelay, _skillVfxs.SkillVfxInterval > 0 ? _skillVfxs.SkillVfxInterval : 500, (times) =>
  150. {
  151. //XGame.Log.Debug($"Skill bullet loop Id:{skillId} Count:{bulletCount} Times:{times}");
  152. if (times == bulletCount)
  153. _bulletTimer = null;
  154. var bulletArgs = new GenBulletDto()
  155. {
  156. masterId = Context.Entity.EntityId,
  157. masterType = Context.Entity.EntityType,
  158. targetId = targetId,
  159. tableId = _skill.Id,
  160. from = Context.Position,
  161. to = to,
  162. };
  163. if (randomIdx != -1)
  164. {
  165. bulletArgs.to = Context.Selector.RandomPosition(Context.Entity.EntityType == EEntityType.Monster ? EEntityType.Player : EEntityType.Monster, times - 1 == randomIdx);
  166. }
  167. EventSingle.Instance.Notify(EventDefine.GameMainMapGenBullet, bulletArgs);
  168. }, bulletCount);
  169. return true;
  170. }
  171. return false;
  172. }
  173. /// <summary>
  174. /// 召唤技能
  175. /// </summary>
  176. private void SummonBeat(ITarget target)
  177. {
  178. var dto = new GenSummonsDto()
  179. {
  180. masterId = Context.Entity.EntityId,
  181. masterType = Context.Entity.EntityType,
  182. tableId = _skill.Id,
  183. from = Context.Position,
  184. count = _skillVfxs.SkillVfxCount
  185. };
  186. if (target != null)
  187. {
  188. dto.targetId = target.Entity.EntityId;
  189. dto.targetType = target.Entity.EntityType;
  190. dto.from = target.Position;
  191. }
  192. else
  193. { //TODO 根据技能配置确定目标类型
  194. dto.targetType = dto.masterType == EEntityType.Monster ? EEntityType.Player : EEntityType.Monster;
  195. }
  196. EventSingle.Instance.Notify(EventDefine.GameMainMapGenCommons, dto);
  197. }
  198. /// <summary>
  199. /// 受击特效
  200. /// </summary>
  201. /// <param name="target"></param>
  202. private void PlayHitVfx(ITarget target)
  203. {
  204. var to = target?.Position ?? Vector3.zero;
  205. var hitVfx = _skillVfxs.HitVfx;
  206. if (!string.IsNullOrEmpty(hitVfx))
  207. {
  208. var actPosition = ObjectPool.Acquire<PositionAction>();
  209. actPosition.position = to;
  210. var hitArgs = ObjectPool.Acquire<VfxArgs>();
  211. hitArgs.vfxName = _skillVfxs.HitVfx;
  212. hitArgs.duration = _skillVfxs.HitVfxTime; //hitEffect == "effect_sk_hit_13521" ? 3000 : 2000;
  213. hitArgs.followType = EVfxFollowType.World;
  214. hitArgs.action = actPosition;
  215. Context.Vfx.Play(hitArgs);
  216. }
  217. Assert.IsNotNull(target, $"PlayHitVfx target null. skill:{_skill.Id}");
  218. if (!target.IsDead)
  219. {
  220. target.Calculation.Damage(-_skill.Damage, Context.Entity.EntityId, _skill);
  221. }
  222. }
  223. void IReference.Clear()
  224. {
  225. Stop();
  226. Context = null;
  227. }
  228. }
  229. }