hch
2025-07-29 97e922d74b3b016f63cb436fb82f8139718b9deb
Main/System/Battle/Skill/SkillBase.cs
@@ -1,26 +1,244 @@
using System.Collections.Generic;
using UnityEngine;
using System;
using DG.Tweening;
using Spine;
public class SkillBase
{
   protected H0604_tagUseSkillAttack tagUseSkillAttack;
   protected SkillConfig skillConfig;
   protected bool isFinished = false;
   public SkillBase(SkillConfig _skillCfg)
   protected BattleField battleField = null; // 战场
   protected RectTransform targetNode = null; // 目标节点
   protected BattleObject caster = null; // 施法者
   protected bool startCounting = false;
   protected bool pauseState = false;
   protected int curFrame = 0;
   protected List<GameNetPackBasic> packList;
   protected SkillBase otherSkill;
   public SkillBase(BattleObject _caster, SkillConfig _skillCfg, H0604_tagUseSkillAttack vNetData, List<GameNetPackBasic> _packList, BattleField _battleField = null)
   {
      caster = _caster;
      skillConfig = _skillCfg;
   }
      tagUseSkillAttack = vNetData;
      battleField = _battleField;
      packList = _packList;
   }
   public virtual void Run()
   {
      if (startCounting)
      {
         curFrame++;
      }
   }
   protected virtual void OnActiveSkillFrame()
   {
   }
   protected virtual void OnStartSkillFrame()
   {
   }
   protected virtual void OnEndSkillFrame()
   {
      
   }
   public virtual void Cast(BattleObject _caster, BattleField battleField, List<Dictionary<int, List<int>>> damageList)
   public void Pause()
   {
      Debug.LogError("SkillBase Cast should be overridden by derived class");
      pauseState = startCounting;
      startCounting = false;
   }
   public void Resume()
   {
      startCounting = pauseState;
   }
   // 0·移动到距离目标n码,的距离释放(可配置,9999即原地释放,负数则是移动到人物背面,人物要转身)
   // 1·移动到距离阵容位置n码的距离(如2号位,5号位)释放(即战场中央此类)
   public virtual void Cast()
   {
      //   高亮所有本次技能相关的目标
      HighLightAllTargets();
      //   距离配成负数要转身 TurnBack
      switch (skillConfig.castMode)
      {
         case SkillCastMode.Self:
            PlayCastAnimation(() => DoSkillLogic(OnSkillFinished));
            break;
         case SkillCastMode.Enemy:
            MoveToTarget(caster.GetEnemyCamp(), skillConfig.CastIndexNum, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
            break;
         case SkillCastMode.Target:
            // 目标是敌方主目标
            BattleObject mainTarget = battleField.battleObjMgr.GetBattleObject((int)tagUseSkillAttack.AttackID);
            if (mainTarget == null)
            {
               Debug.LogError("目标为空 mainTarget == null AttackID : " + tagUseSkillAttack.AttackID);
               OnSkillFinished();
               return;
            }
            MoveToTarget(mainTarget.Camp, mainTarget.teamHero.positionNum, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
            break;
         case SkillCastMode.Allies:
            MoveToTarget(caster.Camp, skillConfig.CastIndexNum, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
            break;
         // case SkillCastMode.DashCast:
         //    DashToTarget(() => BackToOrigin(OnSkillFinished));
         //    break;
         default:
            Debug.LogError("暂时不支持其他的方式释放 有需求请联系策划");
            break;
      }
   }
   //   冲刺的技能 动作 跟移动 是同时进行的 移动到目标的一瞬间就要进行技能逻辑
   // protected void DashToTarget(Action _onComplete)
   // {
   //    TrackEntry entry = PlayCastAnimation();
   //    BattleObject mainTarget = battleField.battleObjMgr.GetBattleObject((int)tagUseSkillAttack.AttackID);
   //    if (mainTarget == null)
   //    {
   //       Debug.LogError("目标为空 mainTarget == null AttackID : " + tagUseSkillAttack.AttackID);
   //       _onComplete?.Invoke();
   //       return;
   //    }
   //    //   做一个微微的提前
   //    MoveToTarget(mainTarget.Camp, mainTarget.teamHero.positionNum, entry.AnimationEnd - 0.05f, () => DoSkillLogic(_onComplete));
   // }
   //   这里其实是技能后摇结束的地方
   protected virtual void DoSkillLogic(Action _onComplete = null)
   {
   }
   protected TrackEntry PlayCastAnimation(Action onComplete = null)
   {
      // 播放施法动作
      return caster.motionBase.PlaySkillAnimation(skillConfig, onComplete,
            OnStartSkillFrame,//攻击前摇结束
            OnActiveSkillFrame);//攻击中摇结束
   }
   public void MoveToTarget(BattleCamp camp, int index, float duration = 0.2f, Action _onComplete = null)
   {
      // GetTargetNode();
      targetNode = battleField.GetTeamNode(camp, index);
      Vector2 offset = new Vector2(skillConfig.CastDistance, 0);
      RectTransform selfRect = caster.heroGo.transform as RectTransform;
      RectTransform targetRect = targetNode;
      var tweener = BattleUtility.MoveToTarget(selfRect, targetRect, offset, duration, _onComplete);
      battleField.battleTweenMgr.OnPlayTween(tweener);
   }
   public void TurnBack(Action _onComplete)
   {
      if (skillConfig.CastDistance < 0)
      {
         //   转身
         caster.heroGo.transform.localScale = new Vector3(-1, 1, 1);
      }
      _onComplete?.Invoke();
   }
   public void BackToOrigin(Action _onComplete = null)
   {
      RectTransform selfRect = caster.heroGo.transform as RectTransform;
      Vector2 targetAnchoredPos = Vector2.zero;
      var tween = selfRect.DOAnchorPos(targetAnchoredPos, 0.2f)
         .SetEase(Ease.Linear)
         .OnComplete(() =>
         {
            //   转成正确方向
            caster.heroGo.transform.localScale = Vector3.one;
            _onComplete?.Invoke();
         });
      battleField.battleTweenMgr.OnPlayTween(tween);
   }
   protected void HighLightAllTargets()
   {
      // 高亮所有目标
      HashSet<BattleObject> highlightList = new HashSet<BattleObject>(battleField.battleObjMgr.GetBattleObjList(tagUseSkillAttack));
      highlightList.Add(caster);
      //   把这些BO全高亮 或者说把除了这些的都放在遮罩后面
      //   YYL TODO
   }
   //   命中目标后的回调 正常是以各技能的方式来处理的
   protected virtual void OnHitTargets(int _hitIndex, List<H0604_tagUseSkillAttack.tagSkillHurtObj> hitList)
   {
      for (int i = 0; i < hitList.Count; i++)
      {
         H0604_tagUseSkillAttack.tagSkillHurtObj hurt = hitList[i];
         BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
         if (target == null)
         {
            Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
            continue;
         }
         // 伤害结算
         int[] damageDivide = skillConfig.DamageDivide[_hitIndex];
         List<long> damageList = new List<long>();
         long totalDamage = GeneralDefine.GetFactValue(hurt.HurtHP, hurt.HurtHPEx);
         for (int j = 0; j < damageDivide.Length; j++)
         {
            long damage = totalDamage * damageDivide[j] / 10000;
            damageList.Add(damage);
         }
         OnHitEachTarget(target, damageList, ref hurt);
      }
   }
   protected virtual void OnHitEachTarget(BattleObject target, List<long> damageList, ref H0604_tagUseSkillAttack.tagSkillHurtObj hurt)
   {
      target.Hurt(damageList, hurt.AttackType);
            //   击中目标的时候,不管近战远程 都确认一下是否有爆炸特效 然后播放
      if (skillConfig.ExplosionEffectId > 0)
      {
         // 播放爆炸特效
         target.battleField.battleEffectMgr.PlayEffect(
            target.ObjID,
            skillConfig.ExplosionEffectId,
            target.heroGo.transform
         );
      }
   }
   public virtual bool IsFinished()
@@ -33,20 +251,8 @@
      isFinished = true;
   }
#if UNITY_EDITOR
   public virtual List<BattleObject> GetTargetList(BattleObject _caster, BattleField battleField)
   public void OnSkillFinished()
   {
      SkillTargetType targetType = SkillTargetType.Enemy;
      SkillTargetRangeType rangeType = SkillTargetRangeType.LowestHP;
      List<BattleObject> affectList = battleField.battleObjMgr.GetTargetList(_caster, targetType, rangeType);
      return affectList;
      isFinished = true;
   }
   public virtual List<Dictionary<int, List<int>>> GetDamageList(BattleObject _caster, BattleField battleField)
   {
      Debug.LogError("SkillBase GetDamageList should be overridden by derived class");
      return null;
   }
#endif
}