yyl
3 天以前 cec8b67d82c2c2c1662d55c818c4a46bcc0487db
125 【战斗】战斗系统 战斗技能
33个文件已修改
10个文件已添加
1122 ■■■■ 已修改文件
Main/Component/UI/Effect/BattleEffectPlayer.cs 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack/CustomB421ActionPack.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/H04_Scene/DTC0418_tagObjInfoRefresh.cs 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleDebug.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleDebug.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleEffectMgr.cs 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/BattleField.cs 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/OperationAgent/HandModeOperationAgent.cs 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/OperationAgent/StopModeOperationAgent.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/BattleEndAction.cs 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/BattleEndAction.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/DeathRecordAction.cs 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/EditorSkillRecordAction.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/SkillTestAction.cs 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/SkillTestAction.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/TestAction.cs 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/TestAction.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/StoryBattleField.cs 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleManager.cs 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/BattleObjMgr.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/BattleObject.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/BattleObjectFactory.cs 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleUtility.cs 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleWin.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Motion/MotionBase.cs 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/RecordPlayer/RecordAction.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/RecordPlayer/RecordPlayer.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/DirectlyDamageSkill.cs 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/DirectlyHealSkill.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/SkillBase.cs 194 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/SkillFactory.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BounceBulletCurve.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BulletCurve.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BulletCurveFactory.cs 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/StraightBulletCurve.cs 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletSkillEffect.cs 73 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/NormalSkillEffect.cs 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/SkillEffect.cs 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/SkillEffectFactory.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/TestMoveToTarget.cs 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/TestMoveToTarget.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Team/TeamHero.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Component/UI/Effect/BattleEffectPlayer.cs
@@ -184,6 +184,12 @@
            this.gameObject.SetActive(true);
        }
        if (effectConfig.autoDestroy != 0)
        {
            GameObject.Destroy(gameObject, effectConfig.destroyDelay);
        }
        PlayEffect();
        
@@ -396,25 +402,19 @@
    //  创建后的特效会自动隐藏 需要手动调用Play才能播放
    public static BattleEffectPlayer Create(int effectId, Transform parent, bool createNewChild = false)
    public static BattleEffectPlayer Create(int effectId, Transform parent)
    {
        // 直接创建特效播放器,不使用对象池
        BattleEffectPlayer BattleEffectPlayer = null;
        BattleEffectPlayer battleEffectPlayer = null;
        if (createNewChild)
        {
            GameObject newGo = new GameObject("BattleEffectPlayer_" + effectId);
            newGo.transform.SetParent(parent, false);
            BattleEffectPlayer = newGo.AddComponent<BattleEffectPlayer>();
        }
        else
        {
            BattleEffectPlayer = parent.AddMissingComponent<BattleEffectPlayer>();
        }
        BattleEffectPlayer.effectId = effectId;
        BattleEffectPlayer.SetActive(true);
        return BattleEffectPlayer;
        GameObject newGo = new GameObject("BattleEffectPlayer_" + effectId);
        newGo.transform.SetParent(parent, false);
        newGo.AddMissingComponent<RectTransform>();
        battleEffectPlayer = newGo.AddComponent<BattleEffectPlayer>();
        battleEffectPlayer.effectId = effectId;
        battleEffectPlayer.SetActive(true);
        return battleEffectPlayer;
    }
    /// <summary>
Main/Core/NetworkPackage/CustomServerPack/CustomB421ActionPack.cs
@@ -18,13 +18,13 @@
        return actionPack;
    }
    public void Distribute()
    public bool Distribute()
    {
        while (actionPacks.Count > 0)
        if (actionPacks.Count > 0)
        {
            GameNetPackBasic pack = actionPacks.Dequeue();
            Debug.LogError("CustomB421ActionPack distribute pack " + pack.GetType().Name);
            BattleDebug.LogError("CustomB421ActionPack distribute pack " + pack.GetType().Name);
            if (pack is CustomHB426CombinePack)
            {
@@ -33,8 +33,11 @@
            }
            else
            {
                BattleDebug.LogError("distribute pack " + pack.GetType().Name);
                PackageRegedit.Distribute(pack);
            }
        }
        return actionPacks.Count > 0;
    }
}
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs
@@ -166,6 +166,7 @@
        if (startTag.Tag.StartsWith("Skill_"))
        {
            HB427_tagSCUseSkill skill = packList[0] as HB427_tagSCUseSkill;
            packList.Remove(skill);
            BattleObject _caster = battleField.battleObjMgr.GetBattleObject((int)skill.ObjID);
            SkillRecordAction skillAction = new SkillRecordAction(battleField, _caster, skill, packList);
            return skillAction;
@@ -173,4 +174,22 @@
        return null;
    }
#if UNITY_EDITOR
    public static CustomHB426CombinePack CreateCustomPack(string _guid, HB427_tagSCUseSkill skill)
    {
        CustomHB426CombinePack pack = new CustomHB426CombinePack();
        pack.guid = string.Empty;
        pack.startTag = new HB426_tagSCTurnFightTag
        {
            Tag = "Skill_Start",
            Sign = 0
        };
        pack.packList.Add(skill);
        return pack;
    }
#endif
}
Main/Core/NetworkPackage/DTCFile/ServerPack/H04_Scene/DTC0418_tagObjInfoRefresh.cs
@@ -5,7 +5,8 @@
//04 18 周围对象刷新#tagObjInfoRefresh
public class DTC0418_tagObjInfoRefresh : DtcBasic {
    public override void Done(GameNetPackBasic vNetPack) {
    public override void Done(GameNetPackBasic vNetPack)
    {
        base.Done(vNetPack);
        H0418_tagObjInfoRefresh vNetData = vNetPack as H0418_tagObjInfoRefresh;
@@ -22,6 +23,12 @@
                break;
            default:
                break;
        }
        BattleField battleField = BattleManager.Instance.GetBattleField(vNetData.packUID);
        if (null != battleField)
        {
            battleField.DistributeNextPackage();
        }
    }
@@ -44,6 +51,5 @@
    {
        BattleField battleField = BattleManager.Instance.GetBattleField(vNetData.packUID);
        battleField.ObjInfoRefresh(vNetData);
        battleField.DistributeNextPackage();
    }
}
Main/System/Battle/BattleDebug.cs
New file
@@ -0,0 +1,13 @@
using UnityEngine;
public static class BattleDebug
{
    public static void LogError(string _logMessage)
    {
        if (Launch.Instance.isOpenBattleDebug)
        {
            Debug.LogError(_logMessage);
        }
    }
}
Main/System/Battle/BattleDebug.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 404517adec3b9ab41ad061c30e7bea6c
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Battle/BattleEffectMgr.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class BattleEffectMgr : MonoBehaviour
@@ -45,12 +46,14 @@
    {
        if (effectId <= 0)
        {
            BattleDebug.LogError("effect id <= 0");
            return null;
        }
        var effectCfg = EffectConfig.Get(effectId);
        if (null == effectCfg)
        {
            BattleDebug.LogError("effect config is null, effectId : " + effectId);
            return null;
        }
@@ -59,12 +62,16 @@
            effectDict[effectId] = new List<BattleEffectPlayer>();
        }
        BattleEffectPlayer effectPlayer = BattleEffectPlayer.Create(effectId, parent);
        BattleEffectPlayer effectPlayer = BattleEffectPlayer.Create(effectId, battleField.battleRootNode.transform);
        effectPlayer.transform.position = parent.position;
        float effectScale = parent.transform.localScale.x;
        effectPlayer.transform.localScale *= effectScale;
        effectPlayer.onDestroy += OnEffectDestroy;
        if (effectPlayer != null)
        {
            effectDict[effectId].Add(effectPlayer);
        }
        effectPlayer.Play(true);
        return effectPlayer;
    }
@@ -80,7 +87,7 @@
        }
        else
        {
            Debug.LogError("could not find effect in list, effectid : " + effectId);
            BattleDebug.LogError("could not find effect in list, effectid : " + effectId);
        }
    }
@@ -98,16 +105,25 @@
    public void HaveRest()
    {
        foreach (KeyValuePair<int, List<BattleEffectPlayer>> kvPair in effectDict)
        List<int> fKeys = effectDict.Keys.ToList();
        for (int i = 0; i < fKeys.Count; i++)
        {
            foreach (BattleEffectPlayer effectPlayer in kvPair.Value)
            List<BattleEffectPlayer> effectPlayers = effectDict[fKeys[i]];
            while (effectPlayers.Count > 0)
            {
                var effectPlayer = effectPlayers[0];
                if (effectPlayer != null)
                {
                    GameObject.DestroyImmediate(effectPlayer.gameObject);
                }
                else
                {
                    effectPlayers.RemoveAt(0);
                }
            }
        }
        effectDict.Clear();
    }
Main/System/Battle/BattleField/BattleField.cs
@@ -146,7 +146,7 @@
        if (operationAgent == null)
        {
            Debug.LogError("you should SetBattleMode before Run");
            BattleDebug.LogError("you should SetBattleMode before Run");
            return;
        }
@@ -178,7 +178,7 @@
                break;
        }
        Debug.LogError("battleMode is " + battleMode.ToString());
        BattleDebug.LogError("battleMode is " + battleMode.ToString());
    }
    public virtual void AutoSetBattleMode()
@@ -283,8 +283,11 @@
    public virtual void OnObjsDead(List<HB422_tagMCTurnFightObjDead> deadPackList)
    {
        DeathRecordAction recordAction = new DeathRecordAction(this, deadPackList);
        recordPlayer.PlayRecord(recordAction);
        if (deadPackList.Count > 0)
        {
            DeathRecordAction recordAction = new DeathRecordAction(this, deadPackList);
            recordPlayer.PlayRecord(recordAction);
        }
    }
    public virtual void Destroy()
@@ -328,7 +331,7 @@
    {
        if (index < 0 || index >= battleRootNode.redTeamNodeList.Count)
        {
            Debug.LogError($"GetTeamNode: Index {index} is out of range for {battleCamp} camp.");
            BattleDebug.LogError($"GetTeamNode: Index {index} is out of range for {battleCamp} camp.");
            return null;
        }
@@ -402,18 +405,95 @@
        }
        else
        {
            Debug.LogError($"BattleObject with ID {vNetData.ObjID} not found for reborn.");
            BattleDebug.LogError($"BattleObject with ID {vNetData.ObjID} not found for reborn.");
        }
    }
    protected virtual void OnSettlement(JsonData turnFightStateData)
    {
    }
    public virtual void OnBattleEnd(JsonData turnFightStateData)
    {
        BattleEndAction battleEndAction = new BattleEndAction(this, turnFightStateData, () =>
        {
            BattleDebug.LogError(turnFightStateData.ToJson());
            // 这里可以添加战斗结束的具体逻辑
            OnSettlement(turnFightStateData);
            int winFaction = (int)turnFightStateData["winFaction"];
            //获胜阵营:   一般为1或者2,当玩家发起的战斗时,如果获胜阵营不等于1代表玩家失败了
            if (winFaction == 1)
            {
                Debug.LogError("战斗胜利");
                //  战斗胜利
                //  如果是自动战斗转自动战斗?
            }
            else
            {
                //  战斗失败
                Debug.LogError("战斗失败");
                HaveRest();
            }
            IsBattleFinish = true;
        });
        recordPlayer.PlayRecord(battleEndAction);
        // 处理战斗结束逻辑
        IsBattleFinish = true;
        // IsBattleFinish = true;
        // 结算逻辑
        // {"winFaction":获胜阵营, "statInfo":统计信息, “itemInfo“:[奖励物品信息列表]}
            // {
            // "itemInfo": [],
            // "winFaction": 1,//获胜阵营:   一般为1或者2,当玩家发起的战斗时,如果获胜阵营不等于1代表玩家失败了
            // "statInfo": {
            //     "1": {
            //     "1": {
            //         "5": {
            //         "NPCID": 0,
            //         "DefHurt": 633,
            //         "CureHP": 0,
            //         "AtkHurt": 169247,
            //         "ObjID": 1,
            //         "HeroID": 510006
            //         }
            //     }
            //     },
            //     "2": {
            //     "1": {
            //         "2": {
            //         "NPCID": 10101001,
            //         "DefHurt": 169246,
            //         "CureHP": 143096,
            //         "AtkHurt": 999952,
            //         "ObjID": 2,
            //         "HeroID": 0
            //         },
            //         "4": {
            //         "NPCID": 10101001,
            //         "DefHurt": 0,
            //         "CureHP": 0,
            //         "AtkHurt": 0,
            //         "ObjID": 3,
            //         "HeroID": 0
            //         },
            //         "6": {
            //         "NPCID": 10101001,
            //         "DefHurt": 1,
            //         "CureHP": 0,
            //         "AtkHurt": 0,
            //         "ObjID": 4,
            //         "HeroID": 0
            //         }
            //     }
            //     }
            // }
            // }
    }
    public virtual void HaveRest()
Main/System/Battle/BattleField/OperationAgent/HandModeOperationAgent.cs
@@ -19,14 +19,14 @@
    //    通过主界面的按钮推动(调用)DoNext
    public override void DoNext()
    {
        Debug.LogError("HandModeOperationAgent DoNext");
        BattleDebug.LogError("HandModeOperationAgent DoNext");
        base.DoNext();
        //    当前没有在播放战斗录像
        if (!battleField.recordPlayer.IsPlaying())
        {
            Debug.LogError("HandModeOperationAgent DoNext  1");
            BattleDebug.LogError("HandModeOperationAgent DoNext  1");
            // 没有下一个包可以发了
            if (!BattleManager.Instance.DistributeNextPackage())
            {
@@ -39,14 +39,14 @@
                //    检查一下锤子的消耗
                //FightPoint             用于记录消耗战锤倍数,小于等于1时默认1倍,大于1时为对应消耗倍值,0418刷新类型22
                Debug.LogError("HandModeOperationAgent DoNext  2");
                BattleDebug.LogError("HandModeOperationAgent DoNext  2");
                ulong costRate = PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.FightPoint);
                ulong cost = (costRate > 1 ? costRate : 1) * 1; // 1是默认消耗
                Debug.LogError("HandModeOperationAgent DoNext  3");
                BattleDebug.LogError("HandModeOperationAgent DoNext  3");
                byte reqType;
                if (storyBattleField.battleState == StoryBattleState.Break)
@@ -66,11 +66,11 @@
                }
                else
                {
                    Debug.LogError("unknown battle state");
                    BattleDebug.LogError("unknown battle state");
                    return;
                }
                Debug.LogError("HandModeOperationAgent DoNext  4   reqType is " + reqType);
                BattleDebug.LogError("HandModeOperationAgent DoNext  4   reqType is " + reqType);
                //    检查一下锤子的消耗
                if (!ItemLogicUtility.CheckCurrencyCount(41, cost, true))
@@ -90,7 +90,7 @@
        }
        else
        {
            Debug.LogError("action doesnt finish, wait a moment please");
            BattleDebug.LogError("action doesnt finish, wait a moment please");
        }
    }
Main/System/Battle/BattleField/OperationAgent/StopModeOperationAgent.cs
@@ -19,5 +19,6 @@
        base.DoNext();
        battleField.AutoSetBattleMode();
        battleField.operationAgent.DoNext();
    }
}
Main/System/Battle/BattleField/RecordActions/BattleEndAction.cs
New file
@@ -0,0 +1,35 @@
using UnityEngine;
using System.Collections.Generic;
using System;
using LitJson;
public class BattleEndAction : RecordAction
{
    //  奖励数据之类的
    protected JsonData endData;
    protected Action onComplete;
    public BattleEndAction(BattleField _battleField, JsonData _endData, Action _onComplete)
        : base(RecordActionType.Death, _battleField, null)
    {
        endData = _endData;
        onComplete = _onComplete;
    }
    public override void Run()
    {
        base.Run();
        Debug.Log("Battle Ended");
        onComplete?.Invoke();
        isFinish = true;
    }
    public override bool IsFinished()
    {
        return isFinish;
    }
}
Main/System/Battle/BattleField/RecordActions/BattleEndAction.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 874d81ccb0bf1804c9c459982190f4da
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Battle/BattleField/RecordActions/DeathRecordAction.cs
@@ -25,25 +25,35 @@
        if (!isRunOnce)
        {
            isRunOnce = true;
            bool isLastOne = false;
            int index = 0;
            int total = deadPackList.Count;
            foreach (var deadPack in deadPackList)
            {
                index++;
                isLastOne = index >= total;
                BattleObject deadObj = battleField.battleObjMgr.GetBattleObject((int)deadPack.ObjID);
                deadObj.OnDeath(OnDeathAnimationEnd);
                deadObj.OnDeath(() =>
                {
                    OnDeathAnimationEnd(deadObj);
                    if (isLastOne)
                    {
                        isFinish = true;
                    }
                });
            }
            return;
        }
        
    }
    private void OnDeathAnimationEnd()
    private void OnDeathAnimationEnd(BattleObject deadObj)
    {
        //  只有主线掉落物品
        if (battleField.MapID == 1 || battleField.MapID == 2)
        {
            battleObject.PerformDrop();
            deadObj.PerformDrop();
        }
        // 掉落物品 增加经验
        isFinish = true;
    }
}
Main/System/Battle/BattleField/RecordActions/EditorSkillRecordAction.cs
@@ -24,7 +24,7 @@
//         if (null == skillConfig)
//         {
//             Debug.LogError("找不到技能配置 " + SkillId);
//             BattleDebug.LogError("找不到技能配置 " + SkillId);
//         }
//         skillBase = SkillFactory.CreateSkill(skillConfig);
@@ -42,7 +42,7 @@
//         if (null == skillConfig)
//         {
//             Debug.LogError("找不到技能配置 " + SkillId);
//             BattleDebug.LogError("找不到技能配置 " + SkillId);
//         }
//         skillBase = SkillFactory.CreateSkill(skillConfig);
Main/System/Battle/BattleField/RecordActions/SkillTestAction.cs
New file
@@ -0,0 +1,73 @@
using UnityEngine;
using System.Collections.Generic;
using System;
#if UNITY_EDITOR
public class TestSkillAction : RecordAction
{
    public HB427_tagSCUseSkill vNetData;
    public TestSkillAction(BattleField _battleField, int skillId, int hurtIndex)
        : base(RecordActionType.Skill, _battleField, null)
    {
        try
        {
            vNetData = new HB427_tagSCUseSkill();
            BattleObject battleObj = battleField.battleObjMgr.redCampList[0];
            vNetData.ObjID = (uint)battleObj.ObjID;
            vNetData.SkillID = (uint)skillId;
            vNetData.PMType = 0;
            vNetData.BattleType = 0;
            vNetData.CurHP = 100;
            vNetData.CurHPEx = 0;
            vNetData.HurtCount = 1;
            vNetData.HurtList = new HB427_tagSCUseSkill.tagSCUseSkillHurt[vNetData.HurtCount];
            //  伤害的对象
            BattleObject hurtObj = battleField.battleObjMgr.GetBattleObjectByIndex(BattleCamp.Blue, hurtIndex);
            var hurt = new HB427_tagSCUseSkill.tagSCUseSkillHurt();
            hurt.ObjID = (uint)hurtObj.ObjID;
            hurt.AttackTypes = 1; // 普通伤害
            hurt.HurtHP = 2; // 伤害值
            hurt.HurtHPEx = 0;
            hurt.CurHP = 100;
            hurt.CurHPEx = 0;
            hurt.SuckHP = 0;
            hurt.BounceHP = 0;
            vNetData.HurtList[0] = hurt;
        }
        catch (Exception err)
        {
            BattleDebug.LogError("Error occurred while creating TestSkillAction: " + err.Message);
        }
    }
    public override bool IsFinished()
    {
        return isFinish;
    }
    public override void Run()
    {
        base.Run();
        if (!isRunOnce)
        {
            isRunOnce = true;
            CustomHB426CombinePack pack = CustomHB426CombinePack.CreateCustomPack(string.Empty, vNetData);
            battleField.recordPlayer.PlayRecord(pack.CreateSkillAction());
            isFinish = true;
            return;
        }
    }
}
#endif
Main/System/Battle/BattleField/RecordActions/SkillTestAction.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bae3c8afb50af6f48977e93e0994dee5
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Battle/BattleField/RecordActions/TestAction.cs
New file
@@ -0,0 +1,69 @@
using UnityEngine;
using System.Collections.Generic;
using System;
#if UNITY_EDITOR
public class TestAction : RecordAction
{
    protected int targetIndex;
    protected int selfIndex;
    protected int distance = 100;
    protected float duration = 2f;
    public TestAction(BattleField _battleField, int _targetIndex, int _selfIndex, int _distance, float _duration)
        : base(RecordActionType.Death, _battleField, null)
    {
        targetIndex = _targetIndex;
        selfIndex = _selfIndex;
        distance = _distance;
        duration = _duration;
    }
    public override bool IsFinished()
    {
        return isFinish;
    }
    public override void Run()
    {
        base.Run();
        if (!isRunOnce)
        {
            isRunOnce = true;
            RectTransform target = battleField.GetTeamNode(BattleCamp.Blue, targetIndex);
            MoveToTarget(target, new Vector2(distance, 0), duration, () =>
            {
                BattleDebug.LogError(" reach to the target ");
                isFinish = true;
            });
            return;
        }
    }
    protected void MoveToTarget(RectTransform target, Vector2 offset, float duration, Action onComplete = null)
    {
        try
        {
            BattleObject caster = battleField.battleObjMgr.GetBattleObjectByIndex(BattleCamp.Red, selfIndex);
            BattleDebug.LogError("Move to target , target is " + target.name);
            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);
        }
        catch (Exception e)
        {
            BattleDebug.LogError("Error in MoveToTarget: " + e.Message);
            isFinish = true;
        }
    }
}
#endif
Main/System/Battle/BattleField/RecordActions/TestAction.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c718ef62f36d7b240980acefa56958fd
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Battle/BattleField/StoryBattleField.cs
@@ -104,7 +104,7 @@
            case 5://结束状态标记
                break;
            default:
                Debug.LogError("recieve a unknown State");
                BattleDebug.LogError("recieve a unknown State");
                break;
        }
    }
@@ -142,12 +142,12 @@
        battleObjMgr.ReloadTeam(TeamManager.Instance.GetTeam(TeamType.Story), BattleCamp.Red);
    }
    public override void OnBattleEnd(JsonData turnFightStateData)
    {
        base.OnBattleEnd(turnFightStateData);
    // public override void OnBattleEnd(JsonData turnFightStateData)
    // {
    //     base.OnBattleEnd(turnFightStateData);
        HaveRest();
    }
    //     // HaveRest();
    // }
    // public override void Run()
    // {
Main/System/Battle/BattleManager.cs
@@ -168,7 +168,7 @@
            Debug.LogWarning($"连续空战斗片段封包次数:{continousEmptyCount}");
            if (continousEmptyCount >= MaxContinousEmptyCount)
            {
                Debug.LogError("连续多次没有战斗片段封包,自动回城休息!");
                BattleDebug.LogError("连续多次没有战斗片段封包,自动回城休息!");
                MainFightRequest(0); // 0-停止战斗回城
                continousEmptyCount = 0;
                packQueue.Clear();
@@ -191,21 +191,32 @@
    {
        if (packQueue.Count > 0)
        {
            GameNetPackBasic pack = packQueue.Dequeue();
            GameNetPackBasic pack = packQueue.Peek();
            bool dequeue = false;
            if (pack is CustomHB426CombinePack)
            {
                CustomHB426CombinePack combinePack = pack as CustomHB426CombinePack;
                packQueue.Dequeue();
                combinePack.Distribute();
            }
            else if (pack is CustomB421ActionPack)
            {
                CustomB421ActionPack actionPack = pack as CustomB421ActionPack;
                actionPack.Distribute();
                dequeue = !actionPack.Distribute();
            }
            else
            {
                BattleDebug.LogError("distribute pack " + pack.GetType().Name);
                packQueue.Dequeue();
                PackageRegedit.Distribute(pack);
            }
            if (dequeue && packQueue.Count > 0)
            {
                packQueue.Dequeue();
            }
            return true;
@@ -287,17 +298,22 @@
        if (!battleReportDict.TryGetValue(guid, out queue))
        {
            Debug.LogError("DistributeNextReportPackage could not find queue for guid : " + guid);
            BattleDebug.LogError("DistributeNextReportPackage could not find queue for guid : " + guid);
            return;
        }
        PackageRegedit.Distribute(queue.Dequeue());
        var pack = queue.Dequeue();
        BattleDebug.LogError("distribute pack " + pack.GetType().Name);
        PackageRegedit.Distribute(pack);
        if (queue.Count <= 0)
        {
            battleReportDict.Remove(guid);
            battlePackRelationList.Remove(guid);
        }
        BattleDebug.LogError("BattlePackage count is " + queue.Count);
    }
    #endregion
@@ -307,7 +323,7 @@
        if (battleFields.TryGetValue(guid, out battleField))
        {
            Debug.LogError("战场已存在 先进行销毁");
            BattleDebug.LogError("战场已存在 先进行销毁");
            battleField.Destroy();
        }
@@ -331,7 +347,7 @@
    {
        if (battleField == null)
        {
            Debug.LogError("DestroyBattleField called with null battleField");
            BattleDebug.LogError("DestroyBattleField called with null battleField");
            return;
        }
Main/System/Battle/BattleObject/BattleObjMgr.cs
@@ -217,6 +217,20 @@
        return blueCampList;
    }
    public BattleObject GetBattleObjectByIndex(BattleCamp camp, int selfIndex)
    {
        if (camp == BattleCamp.Red)
        {
            redCampDict.TryGetValue(selfIndex, out BattleObject battleObj);
            return battleObj;
        }
        else
        {
            blueCampDict.TryGetValue(selfIndex, out BattleObject battleObj);
            return battleObj;
        }
    }
#if UNITY_EDITOR_STOP_USING
    public void ReviveAll()
    {
Main/System/Battle/BattleObject/BattleObject.cs
@@ -110,7 +110,6 @@
    public virtual void Destroy()
    {
        motionBase.onAnimationComplete -= OnAnimationComplete;
        motionBase.Release();
@@ -139,7 +138,7 @@
                teamHero.rage = (int)GeneralDefine.GetFactValue(_refreshInfo.Value, _refreshInfo.ValueEx);
                break;
            default:
                Debug.LogError("BattleObject.ObjInfoRefresh 出现意外类型 " + _refreshInfo.RefreshType.ToString());
                BattleDebug.LogError("BattleObject.ObjInfoRefresh 出现意外类型 " + _refreshInfo.RefreshType.ToString());
                break;
        }
    }
@@ -262,6 +261,7 @@
    public virtual void OnDeath(Action _onDeathAnimationComplete)
    {
        BattleDebug.LogError(ObjID + " OnDeath called");
        onDeathAnimationComplete = _onDeathAnimationComplete;
        motionBase.PlayAnimation(MotionName.dead, false);
    }
@@ -326,7 +326,7 @@
        // YYL TODO
        //  休息状态
        //  多一个zzz的一个特效
        heroGo.SetActive(true);
        motionBase.PlayAnimation(MotionName.idle, true);
        heroRectTrans.anchoredPosition = Vector2.zero;
    }
Main/System/Battle/BattleObject/BattleObjectFactory.cs
@@ -17,7 +17,7 @@
        HeroSkinConfig skinCfg = teamHero.skinConfig;
        if (skinCfg == null)
        {
            Debug.LogError(teamHero.heroId + "BattleObjectFactory.CreateBattleObject: skinCfg is null for " + teamHero.SkinID);
            BattleDebug.LogError(teamHero.heroId + "BattleObjectFactory.CreateBattleObject: skinCfg is null for " + teamHero.SkinID);
            return null;
        }
@@ -25,11 +25,11 @@
        if (battleGO == null)
        {
            Debug.LogError("BattleObjectFactory.CreateBattleObject: battleGO is null for " + teamHero.heroId);
            BattleDebug.LogError("BattleObjectFactory.CreateBattleObject: battleGO is null for " + teamHero.heroId);
            return null;
        }
        Debug.LogError("1 BattleObjectFactory.CreateBattleObject: Creating BattleObject for " + teamHero.ObjID + " at position " + teamHero.positionNum);
        BattleDebug.LogError("1 BattleObjectFactory.CreateBattleObject: Creating BattleObject for " + teamHero.ObjID + " at position " + teamHero.positionNum);
        GameObject goParent = posNodeList[teamHero.positionNum];
        BattleObject battleObject = new BattleObject(_battleField);
@@ -41,11 +41,11 @@
        var skeletonDataAsset = ResManager.Instance.LoadAsset<SkeletonDataAsset>("Hero/SpineRes/", skinCfg.SpineRes);
        if (skeletonDataAsset == null)
        {
            Debug.LogError("BattleObjectFactory.CreateBattleObject: skeletonDataAsset is null for " + skinCfg.SpineRes);
            BattleDebug.LogError("BattleObjectFactory.CreateBattleObject: skeletonDataAsset is null for " + skinCfg.SpineRes);
            return null;
        }
        Debug.LogError("2 BattleObjectFactory.CreateBattleObject: Creating BattleObject for " + teamHero.ObjID + " at position " + teamHero.positionNum);
        BattleDebug.LogError("2 BattleObjectFactory.CreateBattleObject: Creating BattleObject for " + teamHero.ObjID + " at position " + teamHero.positionNum);
        float finalScaleRate = modelScaleRate * teamHero.modelScale;
@@ -53,10 +53,11 @@
        skeletonGraphic.Initialize(true);
        realGO.name = battleObject.ObjID.ToString();
        realGO.transform.localScale = new Vector3(finalScaleRate, finalScaleRate, finalScaleRate);
        (realGO.transform as RectTransform).anchoredPosition = Vector2.zero;
        RectTransform rectTrans = realGO.GetComponent<RectTransform>();
        rectTrans.anchoredPosition = Vector2.zero;
        battleObject.Init(realGO, teamHero, _Camp);
        Debug.LogError(realGO.name +  " /3 BattleObjectFactory.CreateBattleObject: Creating BattleObject for " + teamHero.ObjID + " at position " + teamHero.positionNum);
        BattleDebug.LogError(realGO.name +  " /3 BattleObjectFactory.CreateBattleObject: Creating BattleObject for " + teamHero.ObjID + " at position " + teamHero.positionNum);
        return battleObject;
@@ -64,7 +65,7 @@
    public static void DestroyBattleObject(int key, BattleObject battleObj)
    {
        Debug.LogError("BattleObject destroy");
        BattleDebug.LogError("BattleObject destroy");
        battleObj.Destroy();
        battleObj = null;
    }
Main/System/Battle/BattleUtility.cs
@@ -10,28 +10,110 @@
{
    // 其他通用的战斗工具方法可以放在这里
    public static TweenerCore<Vector2, Vector2, DG.Tweening.Plugins.Options.VectorOptions> MoveToTarget(RectTransform transform, RectTransform target, Vector2 offset, float duration, Action onComplete = null)
    public static void MarkStartAndEnd(RectTransform startNode, RectTransform endNode)
    {
        // 1. 获取目标的最终 anchoredPosition(加上 offset)
        Vector2 targetAnchoredPos = target.anchoredPosition + offset;
        Vector3 worldAnchorPos = target.TransformPoint(targetAnchoredPos);
        // 运行时才执行
        if (!Application.isPlaying)
        {
            Debug.LogWarning("请在运行时使用该功能!");
            return;
        }
        var battleField = BattleManager.Instance.storyBattleField;
        if (battleField == null)
        {
            BattleDebug.LogError("BattleManager.storyBattleField 未初始化!");
            return;
        }
        // 转换 target 的 anchoredPosition 到 sourceParent 的坐标系
        BattleWin battleWin = UIManager.Instance.GetUI<BattleWin>();
        RectTransform canvasRect = battleWin.transform as RectTransform;
        CreateMarker(canvasRect, startNode, "StartMarker");
        CreateMarker(canvasRect, endNode, "EndMarker");
    }
    private static void CreateMarker(RectTransform canvasRect, RectTransform targetNode, string markerName)
    {
        // 获取目标节点的世界坐标(中心点)
        Vector3 worldPos = targetNode.TransformPoint(targetNode.rect.center);
        // 转换到Canvas本地坐标
        Vector2 localPoint;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            transform,
            RectTransformUtility.WorldToScreenPoint(CameraManager.uiCamera, worldAnchorPos),
            CameraManager.uiCamera,
            canvasRect,
            RectTransformUtility.WorldToScreenPoint(null, worldPos),
            null,
            out localPoint);
        // 3. DOTween 移动
        // 创建RawImage
        GameObject marker = new GameObject(markerName, typeof(RawImage));
        GameObject.Destroy(marker, 5f);
        marker.transform.SetParent(canvasRect, false);
        var rawImage = marker.GetComponent<RawImage>();
        rawImage.color = Color.white;
        rawImage.rectTransform.sizeDelta = new Vector2(100, 100);
        rawImage.rectTransform.anchoredPosition = localPoint;
    }
    public static TweenerCore<Vector2, Vector2, DG.Tweening.Plugins.Options.VectorOptions> MoveToTarget(
        RectTransform transform, RectTransform target, Vector2 offset, float duration, Action onComplete = null)
    {
        // 获取目标节点的世界坐标(中心点)
        Vector3 worldPos = target.TransformPoint(target.rect.center + offset);
        RectTransform canvasRect = transform.parent as RectTransform;
        // 转换到Canvas本地坐标
        Vector2 localPoint;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            canvasRect,
            RectTransformUtility.WorldToScreenPoint(null, worldPos),
            null,
            out localPoint);
        // 创建RawImage
        var tween = transform.DOAnchorPos(localPoint, duration).SetEase(Ease.Linear);
        tween.onComplete += () =>
        {
            onComplete?.Invoke();
        };
        // MarkStartAndEnd(transform as RectTransform, target);
        // // 1. 获取目标的世界坐标(加 offset)
        // Vector3 targetWorldPos = target.TransformPoint(target.anchoredPosition + offset);
        // // 2. 获取源节点的 parent
        // RectTransform sourceParent = transform.parent as RectTransform;
        // if (sourceParent == null)
        // {
        //     BattleDebug.LogError("源节点没有父节点,无法转换坐标!");
        //     return null;
        // }
        // // 3. 把目标世界坐标转换到源 parent 的本地坐标
        // Vector2 targetAnchoredPos;
        // RectTransformUtility.ScreenPointToLocalPointInRectangle(
        //     sourceParent,
        //     RectTransformUtility.WorldToScreenPoint(CameraManager.uiCamera, targetWorldPos),
        //     CameraManager.uiCamera,
        //     out targetAnchoredPos);
        // // 4. DOTween 移动
        // var tween = transform.DOAnchorPos(targetAnchoredPos, duration).SetEase(Ease.Linear);
        // tween.onComplete += () =>
        // {
        //     onComplete?.Invoke();
        // };
        return tween;
    }
Main/System/Battle/BattleWin.cs
@@ -24,13 +24,13 @@
    private void PauseGame()
    {
        // Debug.LogError("PauseeGame");
        // BattleDebug.LogError("PauseeGame");
        // if (null == battleField)
        //     return;
        // battleField.IsPause = !battleField.IsPause;
        // Debug.LogError(" is pause " + battleField.IsPause.ToString());
        // BattleDebug.LogError(" is pause " + battleField.IsPause.ToString());
        if (battleField != null)
        {
Main/System/Battle/Motion/MotionBase.cs
@@ -75,7 +75,7 @@
        }
        else
        {
            Debug.LogError("缺少SkeletonGraphic组件!");
            BattleDebug.LogError("缺少SkeletonGraphic组件!");
        }
        
@@ -138,12 +138,12 @@
        // 参数校验
        if (skillConfig == null)
        {
            Debug.LogError("技能配置为空,无法播放技能动画");
            BattleDebug.LogError("技能配置为空,无法播放技能动画");
            return null;
        }
        if (spineAnimationState == null || skeleton == null)
        {
            Debug.LogError("SkeletonGraphic或AnimationState未初始化,无法播放技能动画");
            BattleDebug.LogError("SkeletonGraphic或AnimationState未初始化,无法播放技能动画");
            return null;
        }
@@ -151,7 +151,7 @@
        Spine.Animation anim = skeleton.Data.FindAnimation(skillConfig.SkillMotionName);
        if (anim == null)
        {
            Debug.LogError($"找不到动画: {skillConfig.SkillMotionName}");
            BattleDebug.LogError($"找不到动画: {skillConfig.SkillMotionName}");
            return null;
        }
@@ -194,7 +194,7 @@
            }
            // 中摇开始(每轮loop的开始,只触发一次)
            if (!middleFrameStarted && trackTime >= middleBeginTime && curLoop < loopCount)
            if (!middleFrameStarted && trackTime >= middleBeginTime && curLoop <= loopCount)
            {
                middleFrameStarted = true;
                skillBase.OnMiddleFrameStart(curLoop);
Main/System/Battle/RecordPlayer/RecordAction.cs
@@ -10,7 +10,6 @@
    //  本次Action的主角
    protected BattleObject battleObject;
    //  给子类用的 并不代表事件的结束与否
    protected bool isFinish = false;
    protected bool isRunOnce = false;
@@ -26,7 +25,7 @@
    public virtual bool IsFinished()
    {
        return false;
        return isFinish;
    }
    public virtual void Run()
Main/System/Battle/RecordPlayer/RecordPlayer.cs
@@ -11,7 +11,7 @@
    private bool isWaitingNextAction = false;
    private float waitTimer = 0f;
    private const float waitInterval = 1f;
    private const float waitInterval = 0.2f;
    public void Init(BattleField _battleField)
    {
@@ -25,7 +25,7 @@
    public void PlayRecord(RecordAction recordAction)
    {
        Debug.LogError("Enqueue record action " + recordAction.GetType());
        BattleDebug.LogError("Enqueue record action " + recordAction.GetType());
        recordActionQueue.Enqueue(recordAction);
    }
@@ -70,7 +70,7 @@
        if (currentRecordAction != null && currentRecordAction.IsFinished())
        {
            Debug.LogError("record action " + currentRecordAction.GetType() + " play finished");
            BattleDebug.LogError("record action " + currentRecordAction.GetType() + " play finished");
            currentRecordAction = null;
            isWaitingNextAction = true;
            waitTimer = 0f;
@@ -82,7 +82,7 @@
            if (recordActionQueue.Count > 0)
            {
                currentRecordAction = recordActionQueue.Dequeue();
                Debug.LogError("play record action " + currentRecordAction.GetType());
                BattleDebug.LogError("play record action " + currentRecordAction.GetType());
            }
        }
    }
Main/System/Battle/Skill/DirectlyDamageSkill.cs
@@ -7,7 +7,6 @@
public class DirectlyDamageSkill : SkillBase
{
    protected SkillEffect skillEffect;
    public DirectlyDamageSkill(BattleObject _caster, SkillConfig _skillCfg,
            HB427_tagSCUseSkill _vNetData, List<GameNetPackBasic> _packList, BattleField _battleField)
@@ -15,38 +14,8 @@
    {
        foreach (var pack in packList)
        {
            Debug.LogError("directly damage skill pack type is " + pack.GetType());
            BattleDebug.LogError("directly damage skill pack type is " + pack.GetType());
        }
    }
    public override void Run()
    {
        if (null != skillEffect)
        {
            skillEffect.Run();
        }
        base.Run();
    }
    //    技能开始
    public override void OnSkillStart()
    {
        skillEffect = SkillEffectFactory.CreateSkillEffect(
                caster,
                skillConfig,
                tagUseSkillAttack
            );
        if (skillEffect != null)
        {
            skillEffect.Play(OnHitTargets);
        }
    }
    //    前摇结束
    public override void OnStartSkillFrameEnd()
    {
        base.OnStartSkillFrameEnd();
    }
    protected override void OnHitTargets(int _hitIndex, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hitList)
@@ -54,29 +23,11 @@
        base.OnHitTargets(_hitIndex, hitList);
    }
    protected override void OnHitEachTarget(BattleObject target, long totalDamage, List<long> damageList, ref HB427_tagSCUseSkill.tagSCUseSkillHurt hurt)
    protected override void OnAllAttackMoveFinished()
    {
        base.OnHitEachTarget(target, totalDamage, damageList, ref hurt);
        base.OnAllAttackMoveFinished();
        OnSkillFinished();
    }
    public override void OnMiddleFrameStart(int times)
    {
        base.OnMiddleFrameStart(times);
        skillEffect?.OnMiddleFrameStart(times);
    }
    //  中摇结束(命中帧)
    public override void OnMiddleFrameEnd(int times, int hitIndex)
    {
        skillEffect?.OnMiddleFrameEnd(times, hitIndex);
    }
    //    后摇结束
    public override void OnFinalFrameEnd()
    {
    }
}
Main/System/Battle/Skill/DirectlyHealSkill.cs
@@ -14,7 +14,7 @@
    {
        foreach (var pack in packList)
        {
            Debug.LogError("directly heal skill pack type is " + pack.GetType());
            BattleDebug.LogError("directly heal skill pack type is " + pack.GetType());
        }
    }
Main/System/Battle/Skill/SkillBase.cs
@@ -9,6 +9,8 @@
public class SkillBase
{
    const float moveTime = 0.5f;
    protected SkillEffect skillEffect;
    protected HB427_tagSCUseSkill tagUseSkillAttack;
@@ -54,6 +56,11 @@
            curFrame++;
        }
        if (null != skillEffect)
        {
            skillEffect.Run();
        }
        if (otherSkillAction != null)
        {
            if (otherSkillAction.IsFinished())
@@ -86,12 +93,12 @@
    // 1·移动到距离阵容位置n码的距离(如2号位,5号位)释放(即战场中央此类)
    public virtual void Cast()
    {
        Debug.LogError(GetType().Name + " Skill Cast Start");
        BattleDebug.LogError(GetType().Name + " Skill Cast Start");
        //    高亮所有本次技能相关的目标
        HighLightAllTargets();
        //    距离配成负数要转身 TurnBack
        Debug.LogError(GetType().Name + " Skill CastMode : " + skillConfig.castMode);
        BattleDebug.LogError(GetType().Name + " Skill CastMode : " + skillConfig.castMode);
        switch (skillConfig.castMode)
        {
            case SkillCastMode.Self:
@@ -110,7 +117,7 @@
            //     DashToTarget(() => BackToOrigin(OnSkillFinished));
            //     break;
            default:
                Debug.LogError("暂时不支持其他的方式释放 有需求请联系策划 技能id:" + skillConfig.SkillID + " cast position " + skillConfig.CastPosition);
                BattleDebug.LogError("暂时不支持其他的方式释放 有需求请联系策划 技能id:" + skillConfig.SkillID + " cast position " + skillConfig.CastPosition);
                OnSkillFinished();
                break;
        }
@@ -118,6 +125,14 @@
    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, () =>
        {
@@ -141,7 +156,6 @@
    protected void CastToEnemy()
    {
        const float moveTime = 0.5f;
        RectTransform target = battleField.GetTeamNode(caster.GetEnemyCamp(), skillConfig);
@@ -161,6 +175,7 @@
                            {
                                TurnBack(null, 1f);
                                caster.motionBase.PlayAnimation(MotionName.idle, true);
                                OnAllAttackMoveFinished();
                            });
                        }
                    , -1f);
@@ -176,7 +191,7 @@
        // 目标是敌方主目标
        if (tagUseSkillAttack.HurtCount <= 0)
        {
            Debug.LogError("技能攻击包没有目标 HurtCount <= 0");
            BattleDebug.LogError("技能攻击包没有目标 HurtCount <= 0");
            OnSkillFinished();
            return;
        }
@@ -186,22 +201,85 @@
        BattleObject mainTarget = battleField.battleObjMgr.GetBattleObject((int)mainHurt.ObjID);
        if (mainTarget == null)
        {
            Debug.LogError("目标为空 mainTarget == null ObjID : " + mainHurt.ObjID);
            BattleDebug.LogError("目标为空 mainTarget == null ObjID : " + mainHurt.ObjID);
            OnSkillFinished();
            return;
        }
        // MoveToTarget(mainTarget.Camp, mainTarget, _onComplete: () => TurnBack(() => CastImpl(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
        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()
    {
        // MoveToTarget(caster.Camp, skillConfig, _onComplete: () => TurnBack(() => CastImpl(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
        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)
    {
        // 播放施法动作
        return caster.motionBase.PlaySkillAnimation(skillConfig, this, onComplete);//攻击中摇结束
        //    onComplete是指施法动作播放完的回调 不代表是技能结束
        //    具体技能结束的时间应该看技能对应的逻辑
        //    这里只提供6个动作相关的函数
        // OnSkillStart 动作第一帧
        // OnStartSkillFrameEnd 前摇结束
        // OnMiddleFrameStart 中摇开始
        // OnMiddleFrameEnd 中摇结束
        // OnFinalFrameStart 后摇开始
        // OnFinalFrameEnd 后摇结束
        return caster.motionBase.PlaySkillAnimation(skillConfig, this, onComplete);
    }
    //    技能开始
@@ -230,12 +308,12 @@
    /// <param name="times"></param>
    public virtual void OnMiddleFrameStart(int times)
    {
        skillEffect.OnMiddleFrameStart(times);
    }
    public virtual void OnMiddleFrameEnd(int times, int hitIndex)
    {
        skillEffect.OnMiddleFrameEnd(times, hitIndex);
    }
    /// <summary>
@@ -256,56 +334,6 @@
    // public void MoveToTarget(BattleCamp camp, BattleObject target, float duration = 0.2f, Action _onComplete = null)
    // {
    //     targetNode = battleField.GetTeamNode(camp, target);
    //     Vector2 offset = new Vector2(skillConfig.CastDistance, 0);
    //     RectTransform selfRect = caster.heroRectTrans;
    //     RectTransform targetRect = targetNode;
    //     var tweener = BattleUtility.MoveToTarget(selfRect, targetRect, offset, duration, _onComplete);
    //     battleField.battleTweenMgr.OnPlayTween(tweener);
    // }
    // public void MoveToTarget(BattleCamp camp, SkillConfig skillCfg, float duration = 0.2f, Action _onComplete = null)
    // {
    //     targetNode = battleField.GetTeamNode(camp, skillCfg);
    //     Vector2 offset = new Vector2(skillConfig.CastDistance, 0);
    //     RectTransform selfRect = caster.heroRectTrans;
    //     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.heroRectTrans;
    //     Vector2 targetAnchoredPos = Vector2.zero;
    //     var tween = selfRect.DOAnchorPos(targetAnchoredPos, 0.2f)
    //         .SetEase(Ease.Linear);
    //     tween.onComplete += () =>
    //     {
    //         //    转成正确方向
    //         caster.heroGo.transform.localScale = Vector3.one;
    //         _onComplete?.Invoke();
    //     };
    //     battleField.battleTweenMgr.OnPlayTween(tween);
    // }
    protected void HighLightAllTargets()
    {
@@ -328,7 +356,7 @@
            BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
            if (target == null)
            {
                Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                BattleDebug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                continue;
            }
@@ -349,11 +377,20 @@
    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);
        }
@@ -366,7 +403,7 @@
            where item != null && item.isAuction
            select item);
        int deadCount = deadPackList.Count;
        // 分配掉落和经验
        var dropAssign = AssignDrops(itemList, deadCount);
@@ -378,7 +415,7 @@
            BattleObject deadTarget = battleField.battleObjMgr.GetBattleObject((int)deadPackList[i].ObjID);
            List<ItemModel> itemModelDrops = dropAssign[i];
            List<int> itemModelDropsIndexList = new List<int>(
                from item in itemModelDrops  select item.gridIndex);
                from item in itemModelDrops select item.gridIndex);
            BattleDrops battleDrops = new BattleDrops()
            {
                rectTransform = deadTarget.heroRectTrans,
@@ -389,12 +426,15 @@
        }
        // 分发死亡包
        battleField.OnObjsDead(deadPackList);
        battleField.OnObjsDead(new List<HB422_tagMCTurnFightObjDead>(deadPackList));
        foreach (var deadPack in deadPackList)
        {
            packList.Remove(deadPack);
        }
        deadPackList.Clear();
    }
@@ -447,16 +487,6 @@
    {
        target.Hurt(damageList, totalDamage, hurt.AttackTypes);
        //    击中目标的时候,不管近战远程 都确认一下是否有爆炸特效 然后播放
        if (skillConfig.ExplosionEffectId > 0)
        {
            // 播放爆炸特效
            target.battleField.battleEffectMgr.PlayEffect(
                target.ObjID,
                skillConfig.ExplosionEffectId,
                target.heroGo.transform
            );
        }
    }
    protected void CheckAfterDeadhPack()
@@ -515,6 +545,14 @@
    }
    public virtual bool IsFinished()
    {
        if (skillEffect != null)
        {
            if (!skillEffect.IsFinished())
            {
                return false;
            }
        }
        return isFinished;
    }
@@ -525,8 +563,8 @@
    public void OnSkillFinished()
    {
        Debug.LogError(GetType().Name + " Skill Finished");
        if (packList.Count > 0)
        BattleDebug.LogError(GetType().Name + " Skill Finished");
        while (packList.Count > 0)
        {
            var pack = packList[0];
            packList.RemoveAt(0);
@@ -540,7 +578,7 @@
                    return;
                }
            }
            BattleDebug.LogError("distribute pack " + pack.GetType().Name);
            PackageRegedit.Distribute(pack);
        }
Main/System/Battle/Skill/SkillFactory.cs
@@ -65,7 +65,7 @@
                // skill = new ReviveSkill(_skillConfig);
                break;
            default:
                Debug.LogError("超出了技能类型范围 请检查配置");
                BattleDebug.LogError("超出了技能类型范围 请检查配置");
                break;
        }
Main/System/Battle/SkillEffect/BulletCurve/BounceBulletCurve.cs
@@ -67,7 +67,7 @@
            }
            else
            {
                Debug.LogError("弹射找不到下一个目标");
                BattleDebug.LogError("弹射找不到下一个目标");
                // 如果目标丢失,直接用上一个end
                end = start;
            }
Main/System/Battle/SkillEffect/BulletCurve/BulletCurve.cs
@@ -27,6 +27,19 @@
        this.onHit = onHit;
        this.bulletTrans = bulletEffect.transform as RectTransform;
        this.hurts = tagUseSkillAttack.HurtList.ToList();
        // 设置bulletTrans坐标为caster.heroRectTrans的世界坐标转换到bulletTrans父节点下的本地坐标
        if (bulletTrans != null && caster.heroRectTrans != null)
        {
            var parent = bulletTrans.parent as RectTransform;
            Vector2 localPoint;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                parent,
                RectTransformUtility.WorldToScreenPoint(null, caster.heroRectTrans.position),
                null,
                out localPoint);
            bulletTrans.anchoredPosition = localPoint;
        }
    }
    public virtual void Reset()
Main/System/Battle/SkillEffect/BulletCurve/BulletCurveFactory.cs
@@ -18,18 +18,28 @@
        HB427_tagSCUseSkill tagUseSkillAttack,
        Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit)
    {
        BulletCurve curve = null;
        switch (skillConfig.BulletPath)
        {
            case 1: // 直线消失于目标
                return new StraightBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit);
                curve = new StraightBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit);
                break;
            case 2: // 直线贯穿消失在屏幕外
                return new PenetrateBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit);
                curve = new PenetrateBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit);
                break;
            case 3: // 抛物线弧线
                return new BezierBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit);
                curve = new BezierBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit);
                break;
            case 4: // 弹射
                return new BounceBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit);
                curve = new BounceBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit);
                break;
            default:
                return new BulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit);
                curve = new BulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit);
                break;
        }
        curve.Reset();
        return curve;
    }
}
Main/System/Battle/SkillEffect/BulletCurve/StraightBulletCurve.cs
@@ -8,25 +8,37 @@
    private Vector2 end;
    public StraightBulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer bulletEffect, RectTransform target, HB427_tagSCUseSkill tagUseSkillAttack, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit)
        : base(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit) { }
        : base(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit)
    {
        BattleDebug.LogError("StraightBulletCurve created bulletTrans is null = " + (bulletTrans == null).ToString());
    }
    public override void Reset()
    {
        base.Reset();
        start = WorldToLocalAnchoredPosition(bulletTrans.position);
        end = WorldToLocalAnchoredPosition(target.position);
        // BattleUtility.MarkStartAndEnd(bulletTrans, target);
    }
    public override void Run()
    {
        if (finished) return;
        if (bulletTrans == null)
        {
            BattleDebug.LogError("BulletTrans is null, cannot run StraightBulletCurve");
            return;
        }
        elapsed += Time.deltaTime;
        float t = Mathf.Clamp01(elapsed / duration);
        float t = Mathf.Clamp01(elapsed / 0.3f);
        Vector2 pos = Vector2.Lerp(start, end, t);
        bulletTrans.anchoredPosition = pos;
        Vector2 dir = end - start;
        float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90f;
        float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
        bulletTrans.localRotation = Quaternion.Euler(0, 0, angle);
        if (t >= 1f)
Main/System/Battle/SkillEffect/BulletSkillEffect.cs
@@ -19,11 +19,8 @@
    }
    public override void Play(Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> _onHit)
    public override void OnMiddleFrameStart(int times)
    {
        base.Play(_onHit);
        //  弹射 另外的做法了
        if (skillConfig.effectType == SkillEffectType.Bullet && skillConfig.BulletPath == 4)
        {
@@ -31,7 +28,7 @@
            BattleObject targetObject = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
            if (targetObject == null)
            {
                Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                BattleDebug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                return;
            }
            ShotToTarget(targetObject);
@@ -47,7 +44,7 @@
            {
                case SkillCastMode.Self:
                    onHitFormation?.Invoke(0, tagUseSkillAttack.HurtList.ToList());
                    Debug.LogError("子弹的目标是自己,暂时不支持 协商程序完成");
                    BattleDebug.LogError("子弹的目标是自己,暂时不支持 协商程序完成");
                    break;
                case SkillCastMode.Enemy:
                    var targetNode = caster.battleField.GetTeamNode(caster.GetEnemyCamp(), skillConfig);
@@ -60,7 +57,7 @@
                        BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                        if (target == null)
                        {
                            Debug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID);
                            BattleDebug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID);
                            continue;
                        }
@@ -72,10 +69,17 @@
                    ShotToFormation(healNode, onHitFormation);
                    break;
                default:
                    Debug.LogError("暂时不支持其他的方式释放 有需求请联系程序 " + skillConfig.SkillID);
                    BattleDebug.LogError("暂时不支持其他的方式释放 有需求请联系程序 " + skillConfig.SkillID);
                    break;
            }
        }
    }
    public override void Play(Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> _onHit)
    {
        base.Play(_onHit);
    }
    protected void ShotToFormation(RectTransform target, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> _onHit)
@@ -98,12 +102,20 @@
                BattleObject targetObj = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                if (targetObj == null)
                {
                    Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                    BattleDebug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                    continue;
                }
                caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffectId, targetObj.heroGo.transform);
                caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffect2, targetObj.heroGo.transform);
                var effect1 = caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffectId, targetObj.heroGo.transform);
                var effect2 = caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffect2, targetObj.heroGo.transform);
                if (effect1 != null)
                {
                    effect1.transform.localRotation = effectTrans.localRotation;
                }
                if (effect2 != null)
                {
                    effect2.transform.localRotation = effectTrans.localRotation;
                }
            }
        });
@@ -114,30 +126,45 @@
    protected void ShotToTarget(BattleObject target)
    {
        BattleDebug.LogError("发射子弹 " + skillConfig.BulletEffectId);
        BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.BulletEffectId, caster.heroRectTrans);
        RectTransform effectTrans = effectPlayer.transform as RectTransform;
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, effectPlayer, target.heroRectTrans, tagUseSkillAttack, (index, hitList) =>
        {
            // 表现子弹飞行到目标位置
            onHit?.Invoke(index, hitList);
            // 击中就销毁子弹
            caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer);
            BattleDebug.LogError("回收子弹 " + skillConfig.BulletEffectId);
            // 播放子弹爆炸特效
            foreach (var hurt in hitList)
            {
                BattleObject targetObj = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                if (targetObj == null)
                {
                    Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                    BattleDebug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                    continue;
                }
                caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffectId, targetObj.heroGo.transform);
                caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffect2, targetObj.heroGo.transform);
                if (skillConfig.ExplosionEffectId > 0)
                {
                    var eft = caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffectId, targetObj.heroGo.transform);
                    eft.transform.localRotation = effectPlayer.transform.localRotation;
                }
                if (skillConfig.ExplosionEffect2 > 0)
                {
                    var eft = caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffect2, targetObj.heroGo.transform);
                    eft.transform.localRotation = effectPlayer.transform.localRotation;
                }
            }
            // 击中就销毁子弹
            caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer);
            isFinish = true;
        });
        bulletCurves.Add(bulletCurve);
@@ -153,4 +180,16 @@
                bulletCurve.Run();
        }
    }
    public override bool IsFinished()
    {
        bool isCurveFinish = false;
        foreach (var bulletCurve in bulletCurves)
        {
            isCurveFinish |= bulletCurve.IsFinished;
        }
        return isCurveFinish && isFinish;
    }
}
Main/System/Battle/SkillEffect/NormalSkillEffect.cs
@@ -37,21 +37,34 @@
    public override void OnMiddleFrameEnd(int times, int hitIndex)
    {
        BattleDebug.LogError($" NormalSkillEffect OnMiddleFrameEnd times : {times}, hitIndex : {hitIndex}");
        for (int i = 0; i < tagUseSkillAttack.HurtList.Length; i++)
        {
            var hurt = tagUseSkillAttack.HurtList[i];
            BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
            if (target == null)
            {
                Debug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID);
                BattleDebug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID);
                continue;
            }
            /*var effect1 = */
            caster.battleField.battleEffectMgr.PlayEffect(target.ObjID, skillConfig.ExplosionEffectId, target.heroGo.transform);
            /*var effect2 = */
            caster.battleField.battleEffectMgr.PlayEffect(target.ObjID, skillConfig.ExplosionEffect2, target.heroGo.transform);
            // if (effect1 != null)
            // {
            //     effect1.transform.localRotation = effectTrans.localRotation;
            // }
            // if (effect2 != null)
            // {
            //     effect2.transform.localRotation = effectTrans.localRotation;
            // }
        }
        //  为什么没触发
        onHit?.Invoke(hitIndex, tagUseSkillAttack.HurtList.ToList());
        isFinish = true;
    }
    public override void OnMiddleFrameStart(int times)
Main/System/Battle/SkillEffect/SkillEffect.cs
@@ -8,6 +8,8 @@
    protected BattleObject caster;
    protected HB427_tagSCUseSkill tagUseSkillAttack;// 目标列表
    protected bool isFinish = false;
    protected Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit;
    public SkillEffect(SkillConfig _skillConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack)
@@ -30,11 +32,16 @@
    public virtual void OnMiddleFrameEnd(int times, int hitIndex)
    {
    }
    public virtual void OnMiddleFrameStart(int times)
    {
    }
    public virtual bool IsFinished()
    {
        return isFinish;
    }
}
Main/System/Battle/SkillEffect/SkillEffectFactory.cs
@@ -17,7 +17,7 @@
            // case SkillEffectType.StageEffect:
            //     return new StageSkillEffect(skillConfig, caster, targets);
            default:
                UnityEngine.Debug.LogError("Unknown Skill Effect Type");
                BattleDebug.LogError("Unknown Skill Effect Type");
                break;
        }
        return null;
Main/System/Battle/TestMoveToTarget.cs
New file
@@ -0,0 +1,25 @@
using UnityEngine;
using UnityEngine.UI;
public class TestMoveToTarget : MonoBehaviour
{
    public RectTransform sourceRect;
    public RectTransform targetRect;
    public Vector2 offset = Vector2.zero;
    public float duration = 1f;
    [ContextMenu("Test MoveToTarget")]
    public void TestMove()
    {
        if (sourceRect == null || targetRect == null)
        {
            BattleDebug.LogError("请在Inspector中指定sourceRect和targetRect!");
            return;
        }
        BattleUtility.MoveToTarget(sourceRect, targetRect, offset, duration, () =>
        {
            Debug.Log("移动完成!");
        });
    }
}
Main/System/Battle/TestMoveToTarget.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b5d256c2bd57a6a47aab490b2dc84a4d
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Team/TeamHero.cs
@@ -36,7 +36,7 @@
            NPCConfig npcConfig = NPCConfig.Get((int)fightObj.NPCID);
            Country = (HeroCountry)npcConfig.Country;
            SkinID = npcConfig.SkinID;
            Debug.LogError("npc skin id is " + SkinID);
            BattleDebug.LogError("npc skin id is " + SkinID);
            modelScale = npcConfig.ModelScale;
        }
        else
@@ -45,7 +45,7 @@
            var heroConfig = HeroConfig.Get(heroId);
            Country = (HeroCountry)heroConfig.Country;
            SkinID = (int)fightObj.SkinID;
            Debug.LogError("normal hero skin id is " + SkinID);
            BattleDebug.LogError("normal hero skin id is " + SkinID);
            modelScale = 1f;
        }