using System.Collections.Generic; using UnityEngine; using System; using DG.Tweening; using Spine; using System.Linq; using PlasticGui.WorkspaceWindow.BranchExplorer; public class SkillBase { const float moveTime = 0.5f; protected SkillEffect skillEffect; protected HB427_tagSCUseSkill tagUseSkillAttack; protected SkillConfig skillConfig; protected bool isFinished = false; 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 packList; protected SkillRecordAction otherSkillAction; protected List dropPackList = new List(); protected List expPackList = new List(); public SkillBase(BattleObject _caster, SkillConfig _skillCfg, HB427_tagSCUseSkill vNetData, List _packList, BattleField _battleField = null) { caster = _caster; skillConfig = _skillCfg; tagUseSkillAttack = vNetData; battleField = _battleField; packList = _packList; } public virtual void Run() { if (startCounting) { curFrame++; } if (null != skillEffect) { skillEffect.Run(); } if (otherSkillAction != null) { if (otherSkillAction.IsFinished()) { otherSkillAction = null; OnSkillFinished(); } else { otherSkillAction.Run(); } } } public void Pause() { pauseState = startCounting; startCounting = false; } public void Resume() { startCounting = pauseState; } // 0·移动到距离目标n码,的距离释放(可配置,9999即原地释放,负数则是移动到人物背面,人物要转身) // 1·移动到距离阵容位置n码的距离(如2号位,5号位)释放(即战场中央此类) public virtual void Cast() { BattleDebug.LogError(GetType().Name + " Skill Cast Start"); // 高亮所有本次技能相关的目标 HighLightAllTargets(); // 距离配成负数要转身 TurnBack BattleDebug.LogError(GetType().Name + " Skill CastMode : " + skillConfig.castMode); switch (skillConfig.castMode) { case SkillCastMode.Self: CastImpl(); break; case SkillCastMode.Enemy: CastToEnemy(); break; case SkillCastMode.Target: CastToTarget(); break; case SkillCastMode.Allies: CastToAllies(); break; // case SkillCastMode.DashCast: // DashToTarget(() => BackToOrigin(OnSkillFinished)); // break; default: BattleDebug.LogError("暂时不支持其他的方式释放 有需求请联系策划 技能id:" + skillConfig.SkillID + " cast position " + skillConfig.CastPosition); OnSkillFinished(); break; } } protected void MoveToTarget(RectTransform target, Vector2 offset, float duration, Action onComplete = null) { BattleDebug.LogError("Move to target , target is " + target.name); // 原地释放 if (skillConfig.CastDistance >= 9999) { onComplete?.Invoke(); return; } caster.motionBase.PlayAnimation(MotionName.run, true); var tweener = BattleUtility.MoveToTarget(caster.heroRectTrans, target, offset, duration, () => { caster.motionBase.PlayAnimation(MotionName.idle, true); onComplete?.Invoke(); }); battleField.battleTweenMgr.OnPlayTween(tweener); } protected void TurnBack(Action _onComplete, float forward) { if (skillConfig.CastDistance < 0) { // 转身 Vector3 scale = caster.heroGo.transform.localScale; scale.x = Mathf.Abs(scale.x) * forward; caster.heroGo.transform.localScale = scale; } _onComplete?.Invoke(); } protected void CastToEnemy() { RectTransform target = battleField.GetTeamNode(caster.GetEnemyCamp(), skillConfig); MoveToTarget(target, new Vector2(skillConfig.CastDistance, 0), moveTime, () => { // 到位置转身(不一定非要转身 但是流程要写) TurnBack(() => { // 到达目标位置 CastImpl(() => { TurnBack( () => { // 回到原来的位置 MoveToTarget(battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum), Vector2.zero, moveTime, () => { TurnBack(null, 1f); caster.motionBase.PlayAnimation(MotionName.idle, true); OnAllAttackMoveFinished(); }); } , -1f); }); }, -1f); }); } protected void CastToTarget() { // 目标是敌方主目标 if (tagUseSkillAttack.HurtCount <= 0) { BattleDebug.LogError("技能攻击包没有目标 HurtCount <= 0"); OnSkillFinished(); return; } var mainHurt = tagUseSkillAttack.HurtList[0]; BattleObject mainTarget = battleField.battleObjMgr.GetBattleObject((int)mainHurt.ObjID); if (mainTarget == null) { BattleDebug.LogError("目标为空 mainTarget == null ObjID : " + mainHurt.ObjID); OnSkillFinished(); return; } MoveToTarget(mainTarget.heroRectTrans, new Vector2(skillConfig.CastDistance, 0), moveTime, () => { // 到位置转身(不一定非要转身 但是流程要写) TurnBack(() => { // 到达目标位置 CastImpl(() => { TurnBack( () => { // 回到原来的位置 MoveToTarget(battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum), Vector2.zero, moveTime, () => { TurnBack(null, 1f); caster.motionBase.PlayAnimation(MotionName.idle, true); OnAllAttackMoveFinished(); }); } , -1f); }); }, -1f); }); } protected virtual void OnAllAttackMoveFinished() { } protected void CastToAllies() { RectTransform target = battleField.GetTeamNode(caster.Camp, skillConfig); MoveToTarget(target, new Vector2(skillConfig.CastDistance, 0), moveTime, () => { // 到位置转身(不一定非要转身 但是流程要写) TurnBack(() => { // 到达目标位置 CastImpl(() => { TurnBack( () => { // 回到原来的位置 MoveToTarget(battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum), Vector2.zero, moveTime, () => { TurnBack(null, 1f); caster.motionBase.PlayAnimation(MotionName.idle, true); OnAllAttackMoveFinished(); }); } , -1f); }); }, -1f); }); } // 承载技能大部分的逻辑 protected TrackEntry CastImpl(Action onComplete = null) { // 播放施法动作 // onComplete是指施法动作播放完的回调 不代表是技能结束 // 具体技能结束的时间应该看技能对应的逻辑 // 这里只提供6个动作相关的函数 // OnSkillStart 动作第一帧 // OnStartSkillFrameEnd 前摇结束 // OnMiddleFrameStart 中摇开始 // OnMiddleFrameEnd 中摇结束 // OnFinalFrameStart 后摇开始 // OnFinalFrameEnd 后摇结束 return caster.motionBase.PlaySkillAnimation(skillConfig, this, onComplete); } // 技能开始 public virtual void OnSkillStart() { skillEffect = SkillEffectFactory.CreateSkillEffect( caster, skillConfig, tagUseSkillAttack ); if (skillEffect != null) { skillEffect.Play(OnHitTargets); } } // 技能前摇帧结束 public virtual void OnStartSkillFrameEnd() { } /// /// 中摇开始 times=第几次循环 从0开始 /// /// public virtual void OnMiddleFrameStart(int times) { skillEffect.OnMiddleFrameStart(times); } public virtual void OnMiddleFrameEnd(int times, int hitIndex) { skillEffect.OnMiddleFrameEnd(times, hitIndex); } /// /// 后摇开始 /// public virtual void OnFinalFrameStart() { } /// /// 后摇结束 /// public virtual void OnFinalFrameEnd() { } protected void HighLightAllTargets() { // 高亮所有目标 HashSet highlightList = new HashSet(battleField.battleObjMgr.GetBattleObjList(tagUseSkillAttack)); highlightList.Add(caster); // 把这些BO全高亮 或者说把除了这些的都放在遮罩后面 // YYL TODO } // 命中目标后的回调 正常是以各技能的方式来处理的 protected virtual void OnHitTargets(int _hitIndex, List hitList) { for (int i = 0; i < hitList.Count; i++) { HB427_tagSCUseSkill.tagSCUseSkillHurt hurt = hitList[i]; BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID); if (target == null) { BattleDebug.LogError("目标为空 target == null ObjId : " + hurt.ObjID); continue; } // 伤害分布 (万分比) int[] damageDivide = skillConfig.DamageDivide[_hitIndex]; long totalDamage = GeneralDefine.GetFactValue(hurt.HurtHP, hurt.HurtHPEx); // 保证所有分配项加起来等于totalDamage,避免因整除导致的误差 List damageList = BattleUtility.DivideDamageToList(damageDivide, totalDamage); OnHitEachTarget(target, totalDamage, damageList, ref hurt); } HandleDead(); } protected void HandleDead() { var deadPackList = BattleUtility.FindDeadPack(packList); int deadCount = deadPackList.Count; if (deadCount <= 0) { // 如果没死亡就不用管 return; } CheckAfterDeadhPack(); // 处理掉落包 提前distribute之后 PackManager才有掉落物 所以不跟assignexp一样distribute foreach (var _dropPack in dropPackList) { BattleDebug.LogError("distribute pack " + _dropPack.GetType().Name); PackageRegedit.Distribute(_dropPack); packList.Remove(_dropPack); } // 获取掉落物品 var dropPack = PackManager.Instance.GetSinglePack(PackType.DropItem); var itemDict = dropPack.GetAllItems(); List itemList = new List( from item in itemDict.Values where item != null && item.isAuction select item); // 分配掉落和经验 var dropAssign = AssignDrops(itemList, deadCount); var expAssign = AssignExp(expPackList, deadCount); // 构造 BattleDrops 并分配 for (int i = 0; i < deadCount; i++) { BattleObject deadTarget = battleField.battleObjMgr.GetBattleObject((int)deadPackList[i].ObjID); List itemModelDrops = dropAssign[i]; List itemModelDropsIndexList = new List( from item in itemModelDrops select item.gridIndex); BattleDrops battleDrops = new BattleDrops() { rectTransform = deadTarget.heroRectTrans, dropItemPackIndex = itemModelDropsIndexList, expDrops = expAssign[i] }; deadTarget.PushDropItems(battleDrops); } // 分发死亡包 battleField.OnObjsDead(new List(deadPackList)); foreach (var deadPack in deadPackList) { packList.Remove(deadPack); } deadPackList.Clear(); } // 分配掉落 protected List> AssignDrops(List itemList, int deadCount) { var dropAssign = new List>(deadCount); for (int i = 0; i < deadCount; i++) dropAssign.Add(new List()); for (int i = 0; i < itemList.Count; i++) dropAssign[i % deadCount].Add(itemList[i]); return dropAssign; } // 分配经验:每个原始包都平均分配到每个死亡对象 protected List> AssignExp(List expList, int deadCount) { var expAssign = new List>(deadCount); for (int i = 0; i < deadCount; i++) expAssign.Add(new List()); foreach (var expPack in expList) { long totalExp = GeneralDefine.GetFactValue(expPack.Exp, expPack.ExpPoint); long avgExp = totalExp / deadCount; long remain = totalExp % deadCount; for (int i = 0; i < deadCount; i++) { long assignExp = avgExp + (i < remain ? 1 : 0); long expPoint = assignExp / 100000000; long exp = assignExp % 100000000; var newPack = new HB405_tagMCAddExp { Exp = (uint)exp, ExpPoint = (uint)expPoint, Source = expPack.Source // 保持原包来源 }; expAssign[i].Add(newPack); } packList.Remove(expPack); } return expAssign; } protected virtual void OnHitEachTarget(BattleObject target, long totalDamage, List damageList, ref HB427_tagSCUseSkill.tagSCUseSkillHurt hurt) { target.Hurt(damageList, totalDamage, hurt.AttackTypes); } protected void CheckAfterDeadhPack() { List removeIndexList = new List(); for (int i = 0; i < packList.Count; i++) { var pack = packList[i]; // 复活基本都靠技能包 if (pack is CustomHB426CombinePack) { var combinePack = pack as CustomHB426CombinePack; if (combinePack.startTag.Tag.StartsWith("Skill_")) { break; // 找到技能包就不需要再处理了 } } else if (pack is H0704_tagRolePackRefresh) { var h0704Pack = pack as H0704_tagRolePackRefresh; if (h0704Pack.PackType == (byte)PackType.DropItem) { // 掉落的 if (h0704Pack.IsBind == 1) { // 掉落的物品 dropPackList.Add(h0704Pack); removeIndexList.Add(i); } else if (h0704Pack.IsBind == 0) { // 替换的 } } } else if (pack is HB405_tagMCAddExp) { var h405Pack = pack as HB405_tagMCAddExp; //B4 05 获得经验 #tagMCAddExp 通知获得的经验, //可用于做经验获得表现 Source = 2 时为主线击杀怪物获得经验 if (h405Pack.Source == 2) { expPackList.Add(h405Pack); removeIndexList.Add(i); } } } for (int i = removeIndexList.Count - 1; i >= 0; i--) { packList.RemoveAt(removeIndexList[i]); } } public virtual bool IsFinished() { if (skillEffect != null) { if (!skillEffect.IsFinished()) { return false; } else { OnSkillFinished(); skillEffect = null; } } return isFinished; } public virtual void ForceFinished() { isFinished = true; } public void OnSkillFinished() { if (skillEffect != null) { if (!skillEffect.IsFinished()) { return; } } BattleDebug.LogError(GetType().Name + " Skill Finished"); while (packList.Count > 0) { var pack = packList[0]; packList.RemoveAt(0); if (pack is CustomHB426CombinePack) { var combinePack = pack as CustomHB426CombinePack; if (combinePack.startTag.Tag.StartsWith("Skill_")) { otherSkillAction = combinePack.CreateSkillAction(); return; } } BattleDebug.LogError("distribute pack " + pack.GetType().Name); PackageRegedit.Distribute(pack); } isFinished = true; } }