yyl
2025-07-29 6577831ab2883bd05448ce0b1f9f913a9944fc78
125 【战斗】战斗系统
30个文件已修改
9个文件已删除
12 文件已复制
16个文件已添加
1 文件已重命名
2603 ■■■■■ 已修改文件
Main/Common/EventName.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Component/UI/Effect/EffectPlayer.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/ConfigManager.cs 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/SkillConfig.cs 341 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/PartialConfigs/SkillConfig.Partial.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack/CustomB421ActionPack.cs 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack/CustomB421ActionPack.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/H04_Scene/DTC0418_tagObjInfoRefresh.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB426_tagSCTurnFightTag.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB426_tagSCTurnFightTag.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HB4_FightDefine/HB426_tagSCTurnFightTag.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/ServerPack/HB4_FightDefine/HB426_tagSCTurnFightTag.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleConst.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleConst.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleEffectMgr.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/BattleField.cs 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/BattleStartAction.cs 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/BattleStartAction.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/RecordActions/SkillRecordAction.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleManager.cs 117 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/BattleObjMgr.cs 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleObject/BattleObject.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Bullet/Bullet.cs 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Bullet/Bullet.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Bullet/BulletFactory.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Bullet/BulletFactory.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Bullet/CloseCombatBullet.cs 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Bullet/CloseCombatBullet.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Bullet/TrajectoryBullet.cs 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Motion/MotionBase.cs 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/RecordPlayer/RecordActionType.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/DirectlyDamageSkill.cs 146 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/SkillBase.cs 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/SkillCastMode.cs 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/SkillEffectAnchor.cs 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/SkillEffectAnchor.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/SkillEffectType.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/SkillEffectType.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/Skill/SkillFactory.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BezierBulletCurve.cs 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BezierBulletCurve.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BounceBulletCurve.cs 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BounceBulletCurve.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BulletCurve.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BulletCurve.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BulletCurveFactory.cs 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/BulletCurveFactory.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/PenetrateBulletCurve.cs 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/PenetrateBulletCurve.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/StraightBulletCurve.cs 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletCurve/StraightBulletCurve.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletSkillEffect.cs 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/NormalSkillEffect.cs 96 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/SkillEffect.cs 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/SkillEffectFactory.cs 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Hero/HeroFetterInfo.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/KnapSack/PackManager.cs 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/MainLevel.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/MainLevel/MainLevelManager.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/MainLevel/MainLevelManager.cs.meta 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Message/RichTableEvent.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Team/TeamBase.cs 56 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Team/TeamHero.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Team/TeamManager.cs 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Common/EventName.cs
@@ -7,6 +7,6 @@
    public const string BATTLE_BUFF_DISAPEAR = "BATTLE_BUFF_DISAPEAR";//BUFF DISAPEAR
    public const string BATTLE_DAMAGE_TAKEN = "BATTLE_DAMAGE_TAKEN";//造成伤害
    public const string DISPLAY_BATTLE_UI = "DISPLAY_BATTLE_UI";//显示战斗UI
}
Main/Component/UI/Effect/EffectPlayer.cs
@@ -154,7 +154,7 @@
        // 自动销毁
        if (effectConfig.autoDestroy != 0)
        {
            Destroy(effectTarget, effectConfig.destroyDelay);
            Destroy(gameObject, effectConfig.destroyDelay);
        }
    }
Main/Config/ConfigManager.cs
@@ -38,52 +38,9 @@
        // 加载配置文件
        HashSet<Type> configTypes = new HashSet<Type>() {
            typeof(ChatBubbleBoxConfig),
            typeof(CTGConfig),
            typeof(DailyLivenessRewardConfig),
            typeof(DailyQuestConfig),
            typeof(DailyQuestOpenTimeConfig),
            typeof(DienstgradConfig),
            typeof(DirtyNameConfig),
            typeof(DirtyWordConfig),
            typeof(EffectConfig),
            typeof(EquipGSParamConfig),
            typeof(EquipPlaceMapConfig),
            typeof(FamilyEmblemConfig),
            typeof(FrameAnimationConfig),
            typeof(FuncConfigConfig),
            typeof(FuncOpenLVConfig),
            typeof(FunctionTeamSetConfig),
            typeof(GetItemWaysConfig),
            typeof(GmCmdConfig),
            typeof(HeroAwakeConfig),
            typeof(HeroConfig),
            typeof(HeroQualityAwakeConfig),
            typeof(HeroQualityBreakConfig),
            typeof(HeroQualityConfig),
            typeof(HeroSkinConfig),
            typeof(ItemConfig),
            typeof(KickOutReasonConfig),
            typeof(MainChapterConfig),
            typeof(MainLevelConfig),
            typeof(NPCConfig),
            typeof(NPCLineupConfig),
            typeof(OrderInfoConfig),
            typeof(PlayerFaceConfig),
            typeof(PlayerLVConfig),
            typeof(PlayerPropertyConfig),
            typeof(priorbundleConfig),
            typeof(RealmConfig),
            typeof(RealmLVUPTaskConfig),
            typeof(RuleConfig),
            typeof(SkillConfig),
            typeof(TaskConfig),
            typeof(TitleStarUpConfig),
            typeof(TreasureCntAwardConfig),
            typeof(TreasureItemLibConfig),
            typeof(TreasureSetConfig),
            typeof(TreeLVConfig),
            typeof(XBGetItemConfig)
            typeof(TitleStarUpConfig)
        };
#if UNITY_EDITOR
@@ -233,98 +190,12 @@
    public override void Release()
    {
        // 清空 ChatBubbleBoxConfig 字典
        ClearConfigDictionary<ChatBubbleBoxConfig>();
        // 清空 CTGConfig 字典
        ClearConfigDictionary<CTGConfig>();
        // 清空 DailyLivenessRewardConfig 字典
        ClearConfigDictionary<DailyLivenessRewardConfig>();
        // 清空 DailyQuestConfig 字典
        ClearConfigDictionary<DailyQuestConfig>();
        // 清空 DailyQuestOpenTimeConfig 字典
        ClearConfigDictionary<DailyQuestOpenTimeConfig>();
        // 清空 DienstgradConfig 字典
        ClearConfigDictionary<DienstgradConfig>();
        // 清空 DirtyNameConfig 字典
        ClearConfigDictionary<DirtyNameConfig>();
        // 清空 DirtyWordConfig 字典
        ClearConfigDictionary<DirtyWordConfig>();
        // 清空 EffectConfig 字典
        ClearConfigDictionary<EffectConfig>();
        // 清空 EquipGSParamConfig 字典
        ClearConfigDictionary<EquipGSParamConfig>();
        // 清空 EquipPlaceMapConfig 字典
        ClearConfigDictionary<EquipPlaceMapConfig>();
        // 清空 FamilyEmblemConfig 字典
        ClearConfigDictionary<FamilyEmblemConfig>();
        // 清空 FrameAnimationConfig 字典
        ClearConfigDictionary<FrameAnimationConfig>();
        // 清空 FuncConfigConfig 字典
        ClearConfigDictionary<FuncConfigConfig>();
        // 清空 FuncOpenLVConfig 字典
        ClearConfigDictionary<FuncOpenLVConfig>();
        // 清空 FunctionTeamSetConfig 字典
        ClearConfigDictionary<FunctionTeamSetConfig>();
        // 清空 GetItemWaysConfig 字典
        ClearConfigDictionary<GetItemWaysConfig>();
        // 清空 GmCmdConfig 字典
        ClearConfigDictionary<GmCmdConfig>();
        // 清空 HeroAwakeConfig 字典
        ClearConfigDictionary<HeroAwakeConfig>();
        // 清空 HeroConfig 字典
        ClearConfigDictionary<HeroConfig>();
        // 清空 HeroQualityAwakeConfig 字典
        ClearConfigDictionary<HeroQualityAwakeConfig>();
        // 清空 HeroQualityBreakConfig 字典
        ClearConfigDictionary<HeroQualityBreakConfig>();
        // 清空 HeroQualityConfig 字典
        ClearConfigDictionary<HeroQualityConfig>();
        // 清空 HeroSkinConfig 字典
        ClearConfigDictionary<HeroSkinConfig>();
        // 清空 ItemConfig 字典
        ClearConfigDictionary<ItemConfig>();
        // 清空 KickOutReasonConfig 字典
        ClearConfigDictionary<KickOutReasonConfig>();
        // 清空 MainChapterConfig 字典
        ClearConfigDictionary<MainChapterConfig>();
        // 清空 MainLevelConfig 字典
        ClearConfigDictionary<MainLevelConfig>();
        // 清空 NPCConfig 字典
        ClearConfigDictionary<NPCConfig>();
        // 清空 NPCLineupConfig 字典
        ClearConfigDictionary<NPCLineupConfig>();
        // 清空 OrderInfoConfig 字典
        ClearConfigDictionary<OrderInfoConfig>();
        // 清空 PlayerFaceConfig 字典
        ClearConfigDictionary<PlayerFaceConfig>();
        // 清空 PlayerLVConfig 字典
        ClearConfigDictionary<PlayerLVConfig>();
        // 清空 PlayerPropertyConfig 字典
        ClearConfigDictionary<PlayerPropertyConfig>();
        // 清空 priorbundleConfig 字典
        ClearConfigDictionary<priorbundleConfig>();
        // 清空 RealmConfig 字典
        ClearConfigDictionary<RealmConfig>();
        // 清空 RealmLVUPTaskConfig 字典
        ClearConfigDictionary<RealmLVUPTaskConfig>();
        // 清空 RuleConfig 字典
        ClearConfigDictionary<RuleConfig>();
        // 清空 SkillConfig 字典
        ClearConfigDictionary<SkillConfig>();
        // 清空 TaskConfig 字典
        ClearConfigDictionary<TaskConfig>();
        // 清空 TitleStarUpConfig 字典
        ClearConfigDictionary<TitleStarUpConfig>();
        // 清空 TreasureCntAwardConfig 字典
        ClearConfigDictionary<TreasureCntAwardConfig>();
        // 清空 TreasureItemLibConfig 字典
        ClearConfigDictionary<TreasureItemLibConfig>();
        // 清空 TreasureSetConfig 字典
        ClearConfigDictionary<TreasureSetConfig>();
        // 清空 TreeLVConfig 字典
        ClearConfigDictionary<TreeLVConfig>();
        // 清空 XBGetItemConfig 字典
        ClearConfigDictionary<XBGetItemConfig>();
    }
#if UNITY_EDITOR
Main/Config/Configs/SkillConfig.cs
@@ -1,6 +1,6 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2025年7月17日
//    [  Date ]:           2025年7月28日
//--------------------------------------------------------
using System.Collections.Generic;
@@ -15,85 +15,42 @@
    public int SkillID;
    public string SkillName;
    public int SkillTypeID;
    public int SkillLV;
    public int SkillMaxLV;
    public int UseType;
    public string Description;
    public string IconName;
    public int FuncType;
    public int CastTime;
    public int SkillType;
    public int HurtType;
    public int ContinueUse;
    public int AtkType;
    public int AtkRadius;
    public int Tag;
    public int AtkDist;
    public int StiffTime;
    public int TagAim;
    public int LastTime;
    public int CoolDownTime;
    public int MP;
    public int HP;
    public int XP;
    public int UseItemID;
    public int UseItemCount;
    public int Effect1;
    public int EffectValue11;
    public int EffectValue12;
    public int EffectValue13;
    public int Effect2;
    public int EffectValue21;
    public int EffectValue22;
    public int EffectValue23;
    public int Effect3;
    public int EffectValue31;
    public int EffectValue32;
    public int EffectValue33;
    public int Effect4;
    public int EffectValue41;
    public int EffectValue42;
    public int EffectValue43;
    public int Effect5;
    public int EffectValue51;
    public int EffectValue52;
    public int EffectValue53;
    public int Effect6;
    public int EffectValue61;
    public int EffectValue62;
    public int EffectValue63;
    public int HappenRate6;
    public int LastTime6;
    public int SkillEnhance1;
    public int SkillEnhance2;
    public int StateSkillLV;
    public int LearnSkillReq;
    public int LearnSkillLV;
    public int LearnLVReq;
    public int LearnSkillPointReq;
    public int EffectID1;
    public int[] EffectValues1;
    public int EffectID2;
    public int[] EffectValues2;
    public int EffectID3;
    public int[] EffectValues3;
    public int ConnSkill;
    public int[] EnhanceSkillList;
    public int FightPower;
    public int LVUpCostMoneyType;
    public int LVUpCostMoney;
    public int LVUpCostExp;
    public int ClientActionLimit;
    public int ClientSkillSeriesLimit;
    public int SkillOfSeries;
    public int ExpendMPRate;
    public int ExAttr1;
    public int ExAttr3;
    public int ExAttr4;
    public int ExAttr5;
    public int BuffEffectID;
    public int EffectName;
    public string IconName;
    public string Description;
    public string BuffDescription;
    public int BuffDisplay;
    public int StartupFrames;
    public int ActiveFrames;
    public int RecoveryFrames;
    public int LoopCount;
    public int CastPosition;
    public int CastDistance;
    public int[] TriggerFrames;
    public int CastIndexNum;
    public float CastDistance;
    public int[][] DamageDivide;
    public int BulletEffectId;
    public int BulletPos;
    public int BulletPath;
    public int BulletFlyTime;
    public int ExplosionEffectId;
    public int ExplosionPos;
    public string SkillMotionName;
    public int EffectId;
    public int ExplotionEffectId;
    public float FlyTime;
    public int EffectPos;
    public int EffectType;
    public override int LoadKey(string _key)
    {
@@ -109,175 +66,125 @@
            SkillName = tables[1];
            int.TryParse(tables[2],out SkillTypeID);
            Description = tables[2];
            int.TryParse(tables[3],out SkillLV);
            IconName = tables[3];
            int.TryParse(tables[4],out SkillMaxLV);
            int.TryParse(tables[4],out FuncType);
            int.TryParse(tables[5],out UseType);
            int.TryParse(tables[5],out SkillType);
            int.TryParse(tables[6],out FuncType);
            int.TryParse(tables[6],out HurtType);
            int.TryParse(tables[7],out CastTime);
            int.TryParse(tables[7],out AtkType);
            int.TryParse(tables[8],out SkillType);
            int.TryParse(tables[8],out TagAim);
            int.TryParse(tables[9],out HurtType);
            int.TryParse(tables[9],out LastTime);
            int.TryParse(tables[10],out ContinueUse);
            int.TryParse(tables[10],out CoolDownTime);
            int.TryParse(tables[11],out AtkType);
            int.TryParse(tables[11],out EffectID1);
            int.TryParse(tables[12],out AtkRadius);
            int.TryParse(tables[13],out Tag);
            int.TryParse(tables[14],out AtkDist);
            int.TryParse(tables[15],out StiffTime);
            int.TryParse(tables[16],out CoolDownTime);
            int.TryParse(tables[17],out MP);
            int.TryParse(tables[18],out HP);
            int.TryParse(tables[19],out XP);
            int.TryParse(tables[20],out UseItemID);
            int.TryParse(tables[21],out UseItemCount);
            int.TryParse(tables[22],out Effect1);
            int.TryParse(tables[23],out EffectValue11);
            int.TryParse(tables[24],out EffectValue12);
            int.TryParse(tables[25],out EffectValue13);
            int.TryParse(tables[26],out Effect2);
            int.TryParse(tables[27],out EffectValue21);
            int.TryParse(tables[28],out EffectValue22);
            int.TryParse(tables[29],out EffectValue23);
            int.TryParse(tables[30],out Effect3);
            int.TryParse(tables[31],out EffectValue31);
            int.TryParse(tables[32],out EffectValue32);
            int.TryParse(tables[33],out EffectValue33);
            int.TryParse(tables[34],out Effect4);
            int.TryParse(tables[35],out EffectValue41);
            int.TryParse(tables[36],out EffectValue42);
            int.TryParse(tables[37],out EffectValue43);
            int.TryParse(tables[38],out Effect5);
            int.TryParse(tables[39],out EffectValue51);
            int.TryParse(tables[40],out EffectValue52);
            int.TryParse(tables[41],out EffectValue53);
            int.TryParse(tables[42],out Effect6);
            int.TryParse(tables[43],out EffectValue61);
            int.TryParse(tables[44],out EffectValue62);
            int.TryParse(tables[45],out EffectValue63);
            int.TryParse(tables[46],out HappenRate6);
            int.TryParse(tables[47],out LastTime6);
            int.TryParse(tables[48],out SkillEnhance1);
            int.TryParse(tables[49],out SkillEnhance2);
            int.TryParse(tables[50],out StateSkillLV);
            int.TryParse(tables[51],out LearnSkillReq);
            int.TryParse(tables[52],out LearnSkillLV);
            int.TryParse(tables[53],out LearnLVReq);
            int.TryParse(tables[54],out LearnSkillPointReq);
            int.TryParse(tables[55],out FightPower);
            int.TryParse(tables[56],out LVUpCostMoneyType);
            int.TryParse(tables[57],out LVUpCostMoney);
            int.TryParse(tables[58],out LVUpCostExp);
            int.TryParse(tables[59],out ClientActionLimit);
            int.TryParse(tables[60],out ClientSkillSeriesLimit);
            int.TryParse(tables[61],out SkillOfSeries);
            int.TryParse(tables[62],out ExpendMPRate);
            int.TryParse(tables[63],out ExAttr1);
            int.TryParse(tables[64],out ExAttr3);
            int.TryParse(tables[65],out ExAttr4);
            int.TryParse(tables[66],out ExAttr5);
            int.TryParse(tables[67],out BuffEffectID);
            int.TryParse(tables[68],out EffectName);
            IconName = tables[69];
            Description = tables[70];
            BuffDescription = tables[71];
            int.TryParse(tables[72],out BuffDisplay);
            int.TryParse(tables[73],out CastPosition);
            int.TryParse(tables[74],out CastDistance);
            if (tables[75].Contains("["))
            if (tables[12].Contains("["))
            {
                TriggerFrames = JsonMapper.ToObject<int[]>(tables[75]);
                EffectValues1 = JsonMapper.ToObject<int[]>(tables[12]);
            }
            else
            {
                string[] TriggerFramesStringArray = tables[75].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                TriggerFrames = new int[TriggerFramesStringArray.Length];
                for (int i=0;i<TriggerFramesStringArray.Length;i++)
                string[] EffectValues1StringArray = tables[12].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                EffectValues1 = new int[EffectValues1StringArray.Length];
                for (int i=0;i<EffectValues1StringArray.Length;i++)
                {
                     int.TryParse(TriggerFramesStringArray[i],out TriggerFrames[i]);
                     int.TryParse(EffectValues1StringArray[i],out EffectValues1[i]);
                }
            }
            DamageDivide = JsonMapper.ToObject<int[][]>(tables[76].Replace("(", "[").Replace(")", "]"));
            int.TryParse(tables[13],out EffectID2);
            SkillMotionName = tables[77];
            if (tables[14].Contains("["))
            {
                EffectValues2 = JsonMapper.ToObject<int[]>(tables[14]);
            }
            else
            {
                string[] EffectValues2StringArray = tables[14].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                EffectValues2 = new int[EffectValues2StringArray.Length];
                for (int i=0;i<EffectValues2StringArray.Length;i++)
                {
                     int.TryParse(EffectValues2StringArray[i],out EffectValues2[i]);
                }
            }
            int.TryParse(tables[78],out EffectId);
            int.TryParse(tables[15],out EffectID3);
            int.TryParse(tables[79],out ExplotionEffectId);
            if (tables[16].Contains("["))
            {
                EffectValues3 = JsonMapper.ToObject<int[]>(tables[16]);
            }
            else
            {
                string[] EffectValues3StringArray = tables[16].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                EffectValues3 = new int[EffectValues3StringArray.Length];
                for (int i=0;i<EffectValues3StringArray.Length;i++)
                {
                     int.TryParse(EffectValues3StringArray[i],out EffectValues3[i]);
                }
            }
            float.TryParse(tables[80],out FlyTime);
            int.TryParse(tables[17],out ConnSkill);
            if (tables[18].Contains("["))
            {
                EnhanceSkillList = JsonMapper.ToObject<int[]>(tables[18]);
            }
            else
            {
                string[] EnhanceSkillListStringArray = tables[18].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                EnhanceSkillList = new int[EnhanceSkillListStringArray.Length];
                for (int i=0;i<EnhanceSkillListStringArray.Length;i++)
                {
                     int.TryParse(EnhanceSkillListStringArray[i],out EnhanceSkillList[i]);
                }
            }
            int.TryParse(tables[19],out FightPower);
            int.TryParse(tables[20],out StartupFrames);
            int.TryParse(tables[21],out ActiveFrames);
            int.TryParse(tables[22],out RecoveryFrames);
            int.TryParse(tables[23],out LoopCount);
            int.TryParse(tables[24],out CastPosition);
            int.TryParse(tables[25],out CastIndexNum);
            float.TryParse(tables[26],out CastDistance);
            DamageDivide = JsonMapper.ToObject<int[][]>(tables[27].Replace("(", "[").Replace(")", "]"));
            int.TryParse(tables[28],out BulletEffectId);
            int.TryParse(tables[29],out BulletPos);
            int.TryParse(tables[30],out BulletPath);
            int.TryParse(tables[31],out BulletFlyTime);
            int.TryParse(tables[32],out ExplosionEffectId);
            int.TryParse(tables[33],out ExplosionPos);
            SkillMotionName = tables[34];
            int.TryParse(tables[35],out EffectId);
            int.TryParse(tables[36],out EffectPos);
            int.TryParse(tables[37],out EffectType);
        }
        catch (Exception exception)
        {
Main/Config/PartialConfigs/SkillConfig.Partial.cs
@@ -14,8 +14,17 @@
{
    public SkillType skillType;
    public SkillCastMode castMode;
    public SkillEffectType effectType;
    public SkillEffectAnchor effectAnchor;
    protected override void OnConfigParseCompleted()
    {
        base.OnConfigParseCompleted();
        skillType = (SkillType)SkillType;
        castMode = (SkillCastMode)CastPosition;
        effectType = (SkillEffectType)EffectType;
    }
    public MotionName GetMotionName()
    {
Main/Core/NetworkPackage/CustomServerPack.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 65490d004b625604d8f1e94f7547d5c1
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Core/NetworkPackage/CustomServerPack/CustomB421ActionPack.cs
New file
@@ -0,0 +1,25 @@
using System.Collections.Generic;
using UnityEngine;
public class CustomB421ActionPack : GameNetPackBasic
{
    public string guid;
    public Queue<GameNetPackBasic> actionPacks = new Queue<GameNetPackBasic>();
    public static CustomB421ActionPack CreateB421ActionPack(string _guid, List<GameNetPackBasic> packList)
    {
        //  合并一下这个角色的行动内容的技能 制作成CustomB421ActionPack
        List<GameNetPackBasic> combinedPackList = CustomHB426CombinePack.CombineToSkillPackFromList(_guid, packList);
        CustomB421ActionPack actionPack = new CustomB421ActionPack();
        actionPack.guid = _guid;
        actionPack.actionPacks = new Queue<GameNetPackBasic>(combinedPackList);
        return actionPack;
    }
    public void Distribute()
    {
    }
}
Main/Core/NetworkPackage/CustomServerPack/CustomB421ActionPack.cs.meta
copy from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta copy to Main/Core/NetworkPackage/CustomServerPack/CustomB421ActionPack.cs.meta
File was copied from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: 436c83b5afc693841b2b3f51ec07d020
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs
New file
@@ -0,0 +1,150 @@
using System.Collections.Generic;
using UnityEngine;
public class CustomHB426CombinePack : GameNetPackBasic
{
    protected HB426_tagSCTurnFightTag startTag;
    protected HB426_tagSCTurnFightTag endTag;
    public int fromIndex;
    public int toIndex;
    public string guid;
    public List<GameNetPackBasic> packList = new List<GameNetPackBasic>();
    public override void ReadFromBytes(byte[] vBytes)
    {
        base.ReadFromBytes(vBytes);
    }
    public void SetHB426End(int _toIndex, HB426_tagSCTurnFightTag _endTag)
    {
        if (endTag.Sign != 1)
        {
            Debug.LogError("HB426_tagSCTurnFightTag Sign must be 1 for end tag, but got: " + endTag.Sign);
            return;
        }
        endTag = _endTag;
        packList = CombineToSkillPackFromList(guid, packList);
    }
    public void SetHB426Start(int _fromIndex, HB426_tagSCTurnFightTag tag)
    {
        if (tag.Sign != 0)
        {
            Debug.LogError("HB426_tagSCTurnFightTag Sign must be 0 for start tag, but got: " + tag.Sign);
            return;
        }
        fromIndex = _fromIndex;
        startTag = tag;
    }
    public void AddPack(GameNetPackBasic pack)
    {
        if (startTag == null)
        {
            Debug.LogError("startTag is null, please set it first.");
            return;
        }
        packList.Add(pack);
    }
    public bool IsEndPack(HB426_tagSCTurnFightTag tag)
    {
        if (endTag == null)
        {
            Debug.LogError("endTag is null, please set it first.");
            return false;
        }
        return endTag.Tag == tag.Tag && endTag.Sign == 1;
    }
    public static List<GameNetPackBasic> CombineToSkillPackFromList(string _guid, List<GameNetPackBasic> b421SeriesPackList)
    {
        CustomHB426CombinePack combinePack = null;
        for (int i = 0; i < b421SeriesPackList.Count; i++)
        {
            var pack = b421SeriesPackList[i];
            if (pack is HB426_tagSCTurnFightTag)
            {
                var tag = pack as HB426_tagSCTurnFightTag;
                if (null == combinePack)
                {
                    combinePack = new CustomHB426CombinePack();
                    combinePack.guid = _guid;
                    combinePack.SetHB426Start(i, tag);
                }
                else
                {
                    if (combinePack.IsEndPack(tag))
                    {
                        combinePack.SetHB426End(i, tag);
                        break;
                    }
                }
            }
            if (null != combinePack)
            {
                combinePack.AddPack(pack);
            }
        }
        List<GameNetPackBasic> newPackList = new List<GameNetPackBasic>();
        if (null != combinePack)
        {
            //  技能包前面的包(不包括b426的开始标签)
            for (int i = 0; i < combinePack.fromIndex; i++)
            {
                newPackList.Add(b421SeriesPackList[i]);
            }
            //  把合并的技能包加进来
            newPackList.Add(combinePack);
            //  技能包后面的包(不包括b426的结束标签)
            for (int i = combinePack.toIndex + 1; i < b421SeriesPackList.Count; i++)
            {
                newPackList.Add(b421SeriesPackList[i]);
            }
            return CombineToSkillPackFromList(_guid, newPackList);
        }
        else
        {
            return b421SeriesPackList;
        }
    }
    public void Distribute()
    {
        BattleField battleField = BattleManager.Instance.GetBattleField(guid);
        if (null == battleField)
        {
            Debug.LogError("BattleField not found for guid: " + guid);
            return;
        }
        if (startTag.Tag.StartsWith("Skill_"))
        {
            H0604_tagUseSkillAttack skill = packList[0] as H0604_tagUseSkillAttack;
            BattleObject caster = battleField.battleObjMgr.GetBattleObject((int)skill.ObjID);
            SkillRecordAction skillRecordAction = new SkillRecordAction(battleField, caster, skill, packList);
            battleField.PlayRecord(skillRecordAction);
        }
    }
}
Main/Core/NetworkPackage/CustomServerPack/CustomHB426CombinePack.cs.meta
File was renamed from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: 34030b38537bbf6498977ece22d729b5
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/Core/NetworkPackage/DTCFile/ServerPack/H04_Scene/DTC0418_tagObjInfoRefresh.cs
@@ -31,7 +31,7 @@
    {
        if (PlayerDatas.Instance.PlayerId == vNetData.ObjID)
        {
            //  战斗中如果战锤消耗 界面自己去监听消息
            PlayerDatas.Instance.RefreshPlayerData(vNetData);
        }
        else
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB426_tagSCTurnFightTag.cs
New file
@@ -0,0 +1,11 @@
using UnityEngine;
using System.Collections;
// B4 26 回合战斗标签 #tagSCTurnFightTag
public class DTCB426_tagSCTurnFightTag : DtcBasic {
    public override void Done(GameNetPackBasic vNetPack) {
        base.Done(vNetPack);
        HB426_tagSCTurnFightTag vNetData = vNetPack as HB426_tagSCTurnFightTag;
    }
}
Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB426_tagSCTurnFightTag.cs.meta
copy from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta copy to Main/Core/NetworkPackage/DTCFile/ServerPack/HB4_FightDefine/DTCB426_tagSCTurnFightTag.cs.meta
File was copied from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: 77047853a6f0b1f4d879ad8dbf205761
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/Core/NetworkPackage/ServerPack/HB4_FightDefine/HB426_tagSCTurnFightTag.cs
New file
@@ -0,0 +1,21 @@
using UnityEngine;
using System.Collections;
// B4 26 回合战斗标签 #tagSCTurnFightTag
public class HB426_tagSCTurnFightTag : GameNetPackBasic {
    public byte Len;
    public string Tag;    // 标签,释放技能的标签格式: Skill_objID_skillID,其他标签格式可再扩展
    public byte Sign;    // 0-标签头;1-标签尾;
    public HB426_tagSCTurnFightTag () {
        _cmd = (ushort)0xB426;
    }
    public override void ReadFromBytes (byte[] vBytes) {
        TransBytes (out Len, vBytes, NetDataType.BYTE);
        TransBytes (out Tag, vBytes, NetDataType.Chars, Len);
        TransBytes (out Sign, vBytes, NetDataType.BYTE);
    }
}
Main/Core/NetworkPackage/ServerPack/HB4_FightDefine/HB426_tagSCTurnFightTag.cs.meta
copy from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta copy to Main/Core/NetworkPackage/ServerPack/HB4_FightDefine/HB426_tagSCTurnFightTag.cs.meta
File was copied from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: 93503b0ea916f594c9c782f20b013bbf
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/System/Battle/BattleConst.cs
New file
@@ -0,0 +1,8 @@
public static class BattleConst
{
    public const int BattleStartEffectID = 1001; // Example effect ID for battle start
    public const int skillMotionFps = 30;
}
Main/System/Battle/BattleConst.cs.meta
copy from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta copy to Main/System/Battle/BattleConst.cs.meta
File was copied from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: eb7d9bf2b8aa54f47b15a3b378eb38b0
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/System/Battle/BattleEffectMgr.cs
@@ -49,7 +49,7 @@
        }
        EffectPlayer effectPlayer = EffectPlayer.Create(effectId, parent);
        effectPlayer.onDestroy = OnEffectDestroy;
        effectPlayer.onDestroy += OnEffectDestroy;
        if (effectPlayer != null)
        {
            effectDict[effectId].Add(effectPlayer);
Main/System/Battle/BattleField/BattleField.cs
@@ -18,7 +18,7 @@
    public int round = 0;
    public string guid = string.Empty;
    public string guid = string.Empty;//等于string.Empty的时候代表是StoryBattleField 是主线副本
    public int MapID = 0;
@@ -90,7 +90,7 @@
        guid = _guid;
    }
    public virtual void Init(int _MapID, int _FuncLineID, JsonData _extendData,
    public virtual void Init(int _MapID, int _FuncLineID, JsonData _extendData,
        List<TeamBase> _redTeamList, List<TeamBase> _blueTeamList)
    {
        MapID = _MapID;
@@ -108,7 +108,16 @@
        battleRootNodeGO.name = this.GetType().Name;
        battleObjMgr = new BattleObjMgr();
        battleObjMgr.Init(this, redTeamList[redTeamIndex], blueTeamList[blueTeamIndex]);
        if (blueTeamList == null)
        {
            battleObjMgr.Init(this, redTeamList[redTeamIndex], null);
            battleObjMgr.HaveRest(BattleCamp.Red);
        }
        else
        {
            battleObjMgr.Init(this, redTeamList[redTeamIndex], blueTeamList[blueTeamIndex]);
        }
        battleEffectMgr = new BattleEffectMgr();
        battleEffectMgr.Init(this);
        battleTweenMgr = new BattleTweenMgr();
@@ -206,7 +215,7 @@
        battleTweenMgr.PauseGame();
    }
    public virtual void TurnFightState(int TurnNum, int State,
    public virtual void TurnFightState(int TurnNum, int State,
        uint FuncLineID, JsonData extendData)
    {
        round = TurnNum;
@@ -219,8 +228,37 @@
    public virtual void OnTurnFightState(int turnNum, int State, int FuncLineID, JsonData extendData)
    {
        //  切换回合
        //  是每个战斗开始/每个回合的第一个战斗包
        //  MapID = MapID
        //  MapID;    // 自定义地图ID,可用于绑定战斗地图场景功能(如主线关卡、主线boss、爬塔、竞技场等)
        //  FuncLineID;    // MapID对应的扩展值,如具体某个关卡等  章节*10000+关卡编号*100+第x波,如第一章,第10关卡的boss值 = 11001
        //  State;    // 0-起始状态标记;1-准备完毕;2-战斗中;3-战斗结束;4-结算奖励;5-结束状态标记
        //  TurnNum;    // 当前轮次
        //  Len;
        //  Msg;    //size = Len   +
        //  做表现
        if (turnNum == 1)
        {
            if (State == 2)
            {
                Debug.Log("战斗开始");
            }
        }
        else
        {
            Debug.Log("战斗回合 : " + turnNum + ",状态 " + State);
        }
        // 做一个Action 通知UI翻下牌子 然后结束Action
        // TurnFightStateAction turnFightStateAction = new TurnFightStateAction(this, turnNum, State, FuncLineID, extendData);
        // recordPlayer.PlayRecord(turnFightStateAction);
    }
    public void ObjInfoRefresh(H0418_tagObjInfoRefresh _refreshInfo)
    {
@@ -284,6 +322,17 @@
        }
    }
    public RectTransform GetTeamNode(BattleCamp battleCamp, int index)
    {
        if (battleCamp == BattleCamp.Red)
        {
            return battleRootNode.redTeamNodeList[index].transform as RectTransform;
        }
        else
        {
            return battleRootNode.blueTeamNodeList[index].transform as RectTransform;
        }
    }
    public bool IsRoundReachLimit()
    {
@@ -303,4 +352,31 @@
            }
        }
    }
    public void StartBattle(Action onMoveComplete)
    {
        List<BattleObject> redTeam = battleObjMgr.GetBattleObjList(BattleCamp.Red);
        Tween tween = null;
        foreach (var obj in redTeam)
        {
            obj.motionBase.PlayAnimation(MotionName.run, true);
            RectTransform trans = obj.heroGo.transform as RectTransform;
            tween = trans.DOMove(obj.GetAliasTeamNode().position, 0.5f).SetEase(Ease.Linear);
            battleTweenMgr.OnPlayTween(tween);
        }
        tween.onComplete = () =>
        {
            foreach (var obj in redTeam)
            {
                obj.motionBase.PlayAnimation(MotionName.idle, true);
            }
            // 播放战斗开始的特效
            var efplayer = battleEffectMgr.PlayEffect(0, BattleConst.BattleStartEffectID, battleRootNode.transform);
            efplayer.onDestroy += a => onMoveComplete();
        };
    }
}
Main/System/Battle/BattleField/RecordActions/BattleStartAction.cs
New file
@@ -0,0 +1,39 @@
using UnityEngine;
using System.Collections.Generic;
public class BattleStartAction : RecordAction
{
    private bool isRun = false;
    public BattleStartAction(BattleField _battleField, BattleObject _caster, H0604_tagUseSkillAttack vNetData)
        : base(RecordActionType.BattleStart, _battleField, _caster)
    {
    }
    public override bool IsFinished()
    {
        return isFinish;
    }
    public override void Run()
    {
        base.Run();
        if (isRun)
            return;
        //    隐藏部分UI
        EventBroadcast.Instance.Broadcast(EventName.DISPLAY_BATTLE_UI, battleField.guid, false);
        battleField.StartBattle(() =>
        {
            isFinish = true;
            // 完成就开始显示UI
            EventBroadcast.Instance.Broadcast(EventName.DISPLAY_BATTLE_UI, battleField.guid, true);
        });
        isRun = true;
    }
}
Main/System/Battle/BattleField/RecordActions/BattleStartAction.cs.meta
copy from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta copy to Main/System/Battle/BattleField/RecordActions/BattleStartAction.cs.meta
File was copied from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: 6cc7c2a8cefccb64f93a1728173ffbae
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/System/Battle/BattleField/RecordActions/SkillRecordAction.cs
@@ -7,10 +7,10 @@
    private bool isCast = false;
    public SkillRecordAction(BattleField _battleField, BattleObject _caster, H0604_tagUseSkillAttack vNetData)
    public SkillRecordAction(BattleField _battleField, BattleObject _caster, H0604_tagUseSkillAttack vNetData, List<GameNetPackBasic> packList)
        : base(RecordActionType.Skill, _battleField, _caster)
    {
        skillBase = SkillFactory.CreateSkill(_caster, vNetData, _battleField);
        skillBase = SkillFactory.CreateSkill(_caster, vNetData, packList, _battleField);
    }
    public override bool IsFinished()
Main/System/Battle/BattleManager.cs
@@ -17,25 +17,41 @@
        base.Init();
        // StartStoryBattle();
        logicUpdate.Start(Run);
        DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent += OnPlayerLoginOk;
    }
    public override void Release()
    {
        base.Release();
        logicUpdate.Destroy();
        DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent -= OnPlayerLoginOk;
    }
    public void CreateStoryBattle(int MapID, int FuncLineID, JsonData extendData, List<TeamBase> redTeamList, List<TeamBase> blueTeamList)
    protected void OnPlayerLoginOk()
    {
        ulong exAttr1 = PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.ExAttr1);
        ulong exAttr2 = PlayerDatas.Instance.GetPlayerDataByType(PlayerDataType.ExAttr2);
        int MapID = 0;
        int FuncLineID = (int)exAttr2;
        CreateStoryBattle(MapID, FuncLineID, null, null);
    }
    //  上游戏的时候 等战斗阵容更新完毕 创建主线副本 敌方的数据可以暂时不显示 己方表现为睡觉
    //  如果主线副本存在 那么维持当前的副本不变
    protected void CreateStoryBattle(int MapID, int FuncLineID, JsonData extendData, List<TeamBase> blueTeamList = null)
    {
        if (null == storyBattleField)
        {
            storyBattleField = new StoryBattleField();
            storyBattleField.guid = string.Empty; // 主线副本的guid为空
            var redTeamList = new List<TeamBase>();
            redTeamList.Add(TeamManager.Instance.GetTeam(TeamType.Story));
            storyBattleField.Init(MapID, FuncLineID, extendData, redTeamList, blueTeamList);
        }
        storyBattleField.Init(MapID, FuncLineID, extendData, redTeamList, blueTeamList);
    }
    public void OnBattleClose(BattleField _battleField)
    {
@@ -43,7 +59,7 @@
    }
#region 截断网络派发包 只收入当前包的后续
#region 截断网络派发包 只收入当前包的后续 b425是主线的 非主线的包并不会走b425
    private bool allow = true;
    private Queue<GameNetPackBasic> packQueue = new Queue<GameNetPackBasic>();
@@ -62,6 +78,10 @@
            else
            {
                allow = true;
                //  发送战报片段结束包
                AnalysisPackQueueAndDistribute();
            }
        }
        else
@@ -75,12 +95,80 @@
        return allow;
    }
    protected void AnalysisPackQueueAndDistribute()
    {
        List<GameNetPackBasic> packQueueSnapshot = new List<GameNetPackBasic>(packQueue);
        List<GameNetPackBasic> newPackList = new List<GameNetPackBasic>();
        //  这里已经是按照Dequeue的顺序了
        for (int i = 0; i < packQueueSnapshot.Count; i++)
        {
            GameNetPackBasic pack = packQueueSnapshot[i];
            //  碰到B421 截断 往下收集b421里的全部内容
            if (pack is HB421_tagMCTurnFightObjAction)
            {
                HB421_tagMCTurnFightObjAction b421Pack = pack as HB421_tagMCTurnFightObjAction;
                List<GameNetPackBasic> b421PackList = new List<GameNetPackBasic>();
                i++;    //  跳过当前的B421包
                for (; i < packQueueSnapshot.Count; i++)
                {
                    GameNetPackBasic nextPack = packQueueSnapshot[i];
                    if (nextPack is HB421_tagMCTurnFightObjAction)
                    {
                        // 遇到了其他B421 启动角色的Action开始,
                        // B421后再碰到B421一定是有一个人的行动结束了 回退一个位置
                        i--;
                        break;
                    }
                    else
                    {
                        b421PackList.Add(nextPack);
                    }
                }
                //  可能没用了 主要就是利用一下skill的combine 暂留 看之后还有没有别的需求
                CustomB421ActionPack actionPack = CustomB421ActionPack.CreateB421ActionPack(GetGUID(b421Pack.packUID), b421PackList);
                while (actionPack.actionPacks.Count > 0)
                {
                    GameNetPackBasic actionPackItem = actionPack.actionPacks.Dequeue();
                    newPackList.Add(actionPackItem);
                }
            }
            else
            {
                newPackList.Add(pack);
            }
        }
        //  b421跟b426的包已经处理完了
        packQueue = new Queue<GameNetPackBasic>(newPackList);
        DistributeNextPackage();
    }
    public bool DistributeNextPackage()
    {
        if (packQueue.Count > 0)
        {
            GameNetPackBasic pack = packQueue.Dequeue();
            PackageRegedit.Distribute(pack);
            if (pack is CustomHB426CombinePack)
            {
                CustomHB426CombinePack combinePack = pack as CustomHB426CombinePack;
                combinePack.Distribute();
            }
            else
            {
                PackageRegedit.Distribute(pack);
            }
            return true;
        }
        else
@@ -191,15 +279,18 @@
            battleField.Destroy();
        }
        battleField = BattleFieldFactory.CreateBattleField(guid, MapID, FuncLineID, extendData, redTeamList, blueTeamList);
        if (string.IsNullOrEmpty(guid))
        {
            battleField = storyBattleField;
        }
        else
        {
            battleField = BattleFieldFactory.CreateBattleField(guid, MapID, FuncLineID, extendData, redTeamList, blueTeamList);
        }
        battleFields.Add(guid, battleField);
        if (string.Empty == guid)
        {
            storyBattleField = battleField as StoryBattleField;
        }
        battleField.Init(MapID, FuncLineID, extendData, redTeamList, blueTeamList);
        return battleField;
    }
Main/System/Battle/BattleObject/BattleObjMgr.cs
@@ -27,16 +27,21 @@
    protected void CreateTeam(List<GameObject> posNodeList, Dictionary<int, BattleObject> campDict, TeamBase teamBase, BattleCamp _Camp)
    {
        DestroyTeam(campDict);
        for (int i = 0; i < teamBase.teamHeros.Length; i++)
        if (teamBase == null)
        {
            TeamHero teamHero = teamBase.teamHeros[i];
            if (teamHero != null)
            {
                BattleObject battleObj = BattleObjectFactory.CreateBattleObject(battleField, posNodeList, teamHero, _Camp);
                allBattleObjDict.Add(battleObj.ObjID, battleObj);
                campDict.Add(teamHero.positionNum, battleObj);
            }
            return;
        }
        for (int i = 0; i < teamBase.serverHeroes.Length; i++)
            {
                TeamHero teamHero = teamBase.serverHeroes[i];
                if (teamHero != null)
                {
                    BattleObject battleObj = BattleObjectFactory.CreateBattleObject(battleField, posNodeList, teamHero, _Camp);
                    allBattleObjDict.Add(battleObj.ObjID, battleObj);
                    campDict.Add(teamHero.positionNum, battleObj);
                }
            }
    }
    
    public BattleObject GetBattleObject(int objId)
@@ -46,6 +51,18 @@
            return battleObj;
        }
        return null;
    }
    public List<BattleObject> GetBattleObjList(BattleCamp _Camp)
    {
        if (_Camp == BattleCamp.Red)
        {
            return redCampList;
        }
        else
        {
            return blueCampList;
        }
    }
    public List<BattleObject> GetBattleObjList(H0604_tagUseSkillAttack tagUseSkillAttack)
@@ -78,6 +95,26 @@
    }
    //  空闲状态
    public void HaveRest(BattleCamp _Camp)
    {
        //  休息状态
        if (_Camp == BattleCamp.Red)
        {
            foreach (var item in redCampDict.Values)
            {
                item.HaveRest();
            }
        }
        else
        {
            foreach (var item in blueCampDict.Values)
            {
                item.HaveRest();
            }
        }
    }
    public void Release()
    {
        DestroyTeam(redCampDict);
Main/System/Battle/BattleObject/BattleObject.cs
@@ -269,7 +269,7 @@
        heroGo.SetActive(false);
    }
     // 伤害还要看 是否闪避 暴击 and so on 需要有一个DamageType 服务器应该会给
    // 伤害还要看 是否闪避 暴击 and so on 需要有一个DamageType 服务器应该会给
    protected virtual void PopDamage(long curHp, List<long> damageValues, int attackType)
    {
        //  其实应该通知出去给UI界面解耦 让UI界面自己来显示的 YYL TODO
@@ -294,6 +294,18 @@
        return battleField.GetTeamNode(Camp == BattleCamp.Red ? BattleCamp.Blue : BattleCamp.Red);
    }
    public BattleCamp GetEnemyCamp()
    {
        return Camp == BattleCamp.Red ? BattleCamp.Blue : BattleCamp.Red;
    }
    public void HaveRest()
    {
        // YYL TODO
        //  休息状态
        //  多一个zzz的一个特效
    }
#if UNITY_EDITOR_STOP_USING
    public void EditorRevive()
    {
Main/System/Battle/Bullet/Bullet.cs
File was deleted
Main/System/Battle/Bullet/Bullet.cs.meta
File was deleted
Main/System/Battle/Bullet/BulletFactory.cs
File was deleted
Main/System/Battle/Bullet/BulletFactory.cs.meta
File was deleted
Main/System/Battle/Bullet/CloseCombatBullet.cs
File was deleted
Main/System/Battle/Bullet/CloseCombatBullet.cs.meta
File was deleted
Main/System/Battle/Bullet/TrajectoryBullet.cs
Main/System/Battle/Motion/MotionBase.cs
@@ -125,6 +125,88 @@
        return currentTrackEntry;
    }
    public Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, Action onComplete = null, Action onBeginPhaseEnd = null, Action onActivePhaseEnd = null)
    {
        if (skillConfig == null)
        {
            Debug.LogError("技能配置为空,无法播放技能动画");
            return null;
        }
        return PlayAnimation(skillConfig.SkillMotionName, skillConfig.StartupFrames, skillConfig.ActiveFrames, skillConfig.LoopCount,
            onComplete, onBeginPhaseEnd, onActivePhaseEnd);
    }
    public virtual Spine.TrackEntry PlayAnimation(
            string animationName,
            int loopBeginFrame,
            int loopEndFrame,
            int loopTimes,
            Action _onComplete = null,
            Action onBeginPhaseEnd = null,    // 前摇结束回调
            Action onActivePhaseEnd = null    // 中摇结束回调
        )
    {
        if (spineAnimationState == null || skeleton == null) return null;
        var anim = skeleton.Data.FindAnimation(animationName);
        if (anim == null) return null;
        float fps = BattleConst.skillMotionFps;
        float beginTime = loopBeginFrame / fps;
        float endTime = loopEndFrame / fps;
        currentTrackEntry = spineAnimationState.SetAnimation(0, anim, false);
        int curLoop = 0;
        bool finished = false;
        bool beginPhaseTriggered = false;
        Spine.Unity.UpdateBonesDelegate updateLocalHandler = null;
        updateLocalHandler = (ISkeletonAnimation animated) =>
        {
            if (finished) return;
            var entry = currentTrackEntry;
            if (entry == null || entry.Animation != anim)
            {
                skeletonGraphic.UpdateLocal -= updateLocalHandler;
                return;
            }
            // 前摇结束(只触发一次)
            if (!beginPhaseTriggered && entry.TrackTime >= beginTime)
            {
                beginPhaseTriggered = true;
                onBeginPhaseEnd?.Invoke();
            }
            // 中摇结束(每次到endTime都触发)
            if (entry.TrackTime >= endTime)
            {
                onActivePhaseEnd?.Invoke();
                curLoop++;
                if (curLoop >= loopTimes)
                {
                    finished = true;
                    skeletonGraphic.UpdateLocal -= updateLocalHandler;
                    _onComplete?.Invoke();
                    return;
                }
                entry.TrackTime = beginTime;
                beginPhaseTriggered = false; // 重置,下一轮前摇可再次触发
            }
        };
        skeletonGraphic.UpdateLocal += updateLocalHandler;
        if (_onComplete != null && currentTrackEntry != null)
        {
            trackEntryCompleteDict[currentTrackEntry] = _onComplete;
        }
        return currentTrackEntry;
    }
    
    
    /// <summary>
@@ -166,7 +248,53 @@
            trackEntryCompleteDict.Remove(trackEntry);
        }
    }
    public void Test(string animationName, int beginFrame, int activeFrame, int endFrame, int activeFrameLoopCount)
    {
        // 要处理前摇beginFrame 后摇endFrame 中摇activeFrame
        // 中摇是有多次的activeFrameLoopCount
        var state = spineAnimationState;
        var anim = skeleton.Data.FindAnimation(animationName);
        // 设定你要循环的区间(单位:秒)
        float loopStart = 0.5f;
        float loopEnd = 1.2f;
        // 播放动画
        state.SetAnimation(0, anim, true);
        // state.GetCurrent(0).TrackTime = loopStart;
        int curFrame = 0;
        skeletonGraphic.UpdateLocal += (skeletonAnim) =>
        {
            // if (curFrame == beginFrame)
            // {
            //     OnBeginFrame?.Invoke();
            // }
            // else if (curFrame == activeFrame)
            // {
            //     OnActiveFrame?.Invoke();
            // }
            // else if (curFrame == endFrame)
            // {
            //     OnEndFrame?.Invoke();
            // }
            // var trackEntry = state.GetCurrent(0);
            // if (trackEntry != null && trackEntry.Animation == anim)
            // {
            //     if (trackEntry.TrackTime > loopEnd)
            //     {
            //         // 回到loopStart,实现区间循环
            //         trackEntry.TrackTime = loopStart;
            //     }
            // }
        };
    }
    public virtual void Run()
    {
Main/System/Battle/RecordPlayer/RecordActionType.cs
@@ -5,4 +5,6 @@
    Guard,//格挡
    Skill,//技能
    Death,//死亡
    BattleStart,//战斗开始
}
Main/System/Battle/Skill/DirectlyDamageSkill.cs
@@ -6,93 +6,79 @@
public class DirectlyDamageSkill : SkillBase
{
    public DirectlyDamageSkill(BattleObject _caster, SkillConfig _skillCfg,
            H0604_tagUseSkillAttack vNetData, BattleField _battleField) : base(_caster, _skillCfg, vNetData, _battleField)
    {
    protected SkillEffect skillEffect;
    public DirectlyDamageSkill(BattleObject _caster, SkillConfig _skillCfg,
            H0604_tagUseSkillAttack _vNetData, List<GameNetPackBasic> _packList, BattleField _battleField)
            : base(_caster, _skillCfg, _vNetData, _packList, _battleField)
    {
        foreach (var pack in packList)
        {
            Debug.LogError("directly damage skill pack type is " + pack.GetType());
        }
    }
    public override void Run()
    {
        base.Run();
    }
    protected override void OnTriggerEvent(int triggerIndex, int triggerFrame)
    {
        if (0 == triggerIndex)
        if (null != skillEffect)
        {
            List<BattleObject> targetList = GetTargetList();
            //    子类实现具体的技能逻辑
            SkillEffect effect = SkillEffectFactory.CreateSkillEffect(caster, skillConfig, tagUseSkillAttack);
            if (null != effect)
            {
                //    如果是子弹类型的
                effect.Play((hitIndex, hurList) =>
                {
                    for (int i = 0; i < hurList.Count; i++)
                    {
                        var hurt = hurList[i];
                        BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                        List<long> damageList = new List<long>();
                        //    计算伤害 分段的话
                        if (hitIndex >= skillConfig.DamageDivide.Length)
                        {
                            Debug.LogError("DamageDivide有问题 需要检查 只显示一段伤害 取triggerFrames的");
                            long totalDamage = GeneralDefine.GetFactValue(hurt.HurtHP, hurt.HurtHPEx) / (skillConfig.TriggerFrames.Length == 0 ? 1 : skillConfig.TriggerFrames.Length);
                            damageList.Add(totalDamage);
                        }
                        else
                        {
                            long totalDamage = GeneralDefine.GetFactValue(hurt.HurtHP, hurt.HurtHPEx);
                            if (hitIndex >= skillConfig.DamageDivide.Length)
                            {
                                int[] tenKDamagePercentArray = skillConfig.DamageDivide[hitIndex];
                                long factDamage = totalDamage;
                                for (int j = 0; j < tenKDamagePercentArray.Length; j++)
                                {
                                    long damage = (long)(Mathf.Round(factDamage * tenKDamagePercentArray[j] / 10000.0f));
                                    damageList.Add(damage);
                                }
                            }
                        }
                        target.Hurt(damageList, hurt.AttackType);
                    }
                });
            }
        }
    }
    protected override void DoSkillLogic(Action _onComplete = null)
    {
        //    开始记录帧数
        startCounting = true;
    }
#if UNITY_EDITOR_STOP_USING
    //    伤害列表理应由服务器发给客户端 这边只做粗浅模拟
    public override List<Dictionary<int, List<int>>> GetDamageList(BattleField battleField)
    {
        List<Dictionary<int, List<int>>> damageList = new List<Dictionary<int, List<int>>>();
        List<BattleObject> affectList = GetTargetList(battleField);
        Dictionary<int, List<int>> oneRoundDamage = new Dictionary<int, List<int>>();
        for (int j = 0; j < affectList.Count; j++)
        {
            BattleObject obj = affectList[j];
            List<int> tryDmgList = caster.TryAttack(obj, skillConfig);
            oneRoundDamage.Add(obj.ObjID, tryDmgList);
            skillEffect.Run();
        }
        damageList.Add(oneRoundDamage);
        return damageList;
        base.Run();
    }
#endif
    //    技能动画播放完毕
    protected override void DoSkillLogic(Action _onComplete = null)
    {
        // if (skillConfig.EffectId > 0)
        // {
        //     // 播放技能特效
        //     caster.battleField.battleEffectMgr.PlayEffect(
        //         caster.ObjID,
        //         skillConfig.EffectId,
        //         caster.heroGo.transform
        //     );
        // }
        _onComplete?.Invoke();
    }
    //    前摇结束
    protected override void OnStartSkillFrame()
    {
        skillEffect = SkillEffectFactory.CreateSkillEffect(
                caster,
                skillConfig,
                tagUseSkillAttack
            );
        if (skillEffect != null)
        {
            skillEffect.Play(OnHitTargets);
        }
    }
    protected override void OnHitTargets(int _hitIndex, List<H0604_tagUseSkillAttack.tagSkillHurtObj> hitList)
    {
        base.OnHitTargets(_hitIndex, hitList);
    }
    protected override void OnHitEachTarget(BattleObject target, List<long> damageList, ref H0604_tagUseSkillAttack.tagSkillHurtObj hurt)
    {
        base.OnHitEachTarget(target, damageList, ref hurt);
    }
    //  中摇结束
    protected override void OnActiveSkillFrame()
    {
    }
    //    后摇结束
    protected override void OnEndSkillFrame()
    {
    }
}
Main/System/Battle/Skill/SkillBase.cs
@@ -25,35 +25,41 @@
    protected int curFrame = 0;
    protected List<int> triggerFrames = new List<int>();
    protected List<GameNetPackBasic> packList;
    public SkillBase(BattleObject _caster, SkillConfig _skillCfg, H0604_tagUseSkillAttack vNetData, BattleField _battleField = null)
    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;
        triggerFrames.Clear();
        triggerFrames.AddRange(skillConfig.TriggerFrames);
    }
    }
    public virtual void Run()
    {
        if (startCounting)
        {
            curFrame++;
            if (triggerFrames.Contains(curFrame))
            {
                OnTriggerEvent(triggerFrames.IndexOf(curFrame), curFrame);
            }
        }
    }
    protected virtual void OnTriggerEvent(int triggerIndex, int triggerFrame)
    protected virtual void OnActiveSkillFrame()
    {
    }
    protected virtual void OnStartSkillFrame()
    {
    }
    protected virtual void OnEndSkillFrame()
    {
    }
    public void Pause()
@@ -74,17 +80,33 @@
        //    高亮所有本次技能相关的目标
        HighLightAllTargets();
        //    距离配成负数要转身 TurnBack
        switch (skillConfig.castMode)
        {
            case SkillCastMode.StandCast:
            case SkillCastMode.Self:
                PlayCastAnimation(() => DoSkillLogic(OnSkillFinished));
                break;
            case SkillCastMode.MoveToTarget:
                MoveToTarget(_onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
            case SkillCastMode.Enemy:
                MoveToTarget(caster.GetEnemyCamp(), skillConfig.CastIndexNum, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); }))));
                break;
            case SkillCastMode.DashCast:
                DashToTarget(() => BackToOrigin(OnSkillFinished));
            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;
@@ -92,73 +114,40 @@
    }
    //    冲刺的技能 动作 跟移动 是同时进行的 移动到目标的一瞬间就要进行技能逻辑
    protected void DashToTarget(Action _onComplete)
    {
        TrackEntry entry = PlayCastAnimation();
        //    做一个微微的提前
        MoveToTarget(entry.TrackTime - 0.05f, () => DoSkillLogic(_onComplete));
    }
    // 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;
    //     }
    protected void GetTargetNode()
    {
        targetNode = null;
    //     //    做一个微微的提前
    //     MoveToTarget(mainTarget.Camp, mainTarget.teamHero.positionNum, entry.AnimationEnd - 0.05f, () => DoSkillLogic(_onComplete));
    // }
        if (skillConfig.castMode == SkillCastMode.StandCast)
        {
            //    原地施法
            targetNode = caster.heroGo.transform as RectTransform;
        }
        else if (skillConfig.castMode == SkillCastMode.MoveToTarget || skillConfig.castMode == SkillCastMode.DashCast)
        {
            if (tagUseSkillAttack.AttackID <= 0)
            {
                Debug.LogError("技能没有指定目标");
                return;
            }
            //    移动到目标位置施法
            BattleObject _mainTarget = battleField.battleObjMgr.GetBattleObject((int)tagUseSkillAttack.AttackID);
            if (_mainTarget == null)
            {
                Debug.LogError("技能指定的目标不存在");
                return;
            }
            targetNode = _mainTarget.heroGo.transform as RectTransform;
        }
        else if (skillConfig.castMode == SkillCastMode.MoveToFormation)
        {
            //    TODO YYL
            targetNode = /*caster.GetEnemyTeamNode();*/ battleField.GetTeamNode(caster.Camp == BattleCamp.Blue ? BattleCamp.Red : BattleCamp.Blue);
        }
        else
        {
            Debug.LogError("未知的施法方式 技能id:" + skillConfig.SkillID);
            return;
        }
    }
    protected List<BattleObject> GetTargetList()
    {
        return battleField.battleObjMgr.GetBattleObjList(tagUseSkillAttack);
    }
    //    这里其实是技能后摇结束的地方
    protected virtual void DoSkillLogic(Action _onComplete = null)
    {
        //    子类实现具体的技能逻辑
    }
    protected TrackEntry PlayCastAnimation(Action onComplete = null)
    {
        // 播放施法动作
        MotionName motionName = skillConfig.GetMotionName();
        TrackEntry trackEntry = caster.motionBase.PlayAnimation(motionName, false, onComplete);
        return trackEntry;
        return caster.motionBase.PlaySkillAnimation(skillConfig, onComplete,
                OnStartSkillFrame,//攻击前摇结束
                OnActiveSkillFrame);//攻击中摇结束
    }
    public void MoveToTarget(float duration = 0.2f, Action _onComplete = null)
    public void MoveToTarget(BattleCamp camp, int index, float duration = 0.2f, Action _onComplete = null)
    {
        GetTargetNode();
        // GetTargetNode();
        targetNode = battleField.GetTeamNode(camp, index);
        Vector2 offset = new Vector2(skillConfig.CastDistance, 0);
        RectTransform selfRect = caster.heroGo.transform as RectTransform;
        RectTransform targetRect = targetNode;
@@ -171,6 +160,7 @@
    {
        if (skillConfig.CastDistance < 0)
        {
            //    转身
            caster.heroGo.transform.localScale = new Vector3(-1, 1, 1);
        }
        _onComplete?.Invoke();
@@ -184,6 +174,7 @@
            .SetEase(Ease.Linear)
            .OnComplete(() =>
            {
                //    转成正确方向
                caster.heroGo.transform.localScale = Vector3.one;
                _onComplete?.Invoke();
            });
@@ -203,6 +194,53 @@
        //    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()
    {
        return isFinished;
@@ -217,21 +255,4 @@
    {
        isFinished = true;
    }
#if UNITY_EDITOR_STOP_USING
    public virtual List<BattleObject> GetTargetList(BattleField _battleField)
    {
        SkillTargetType targetType = SkillTargetType.Enemy;
        SkillTargetRangeType rangeType = SkillTargetRangeType.LowestHP;
        List<BattleObject> affectList = _battleField.battleObjMgr.GetTargetList(caster, targetType, rangeType);
        return affectList;
    }
    public virtual List<Dictionary<int, List<int>>> GetDamageList(BattleField _battleField)
    {
        Debug.LogError("SkillBase GetDamageList should be overridden by derived class");
        return null;
    }
#endif
}
Main/System/Battle/Skill/SkillCastMode.cs
@@ -2,8 +2,19 @@
public enum SkillCastMode
{
    StandCast,      // 原地释放
    MoveToTarget,   // 跑到目标面前释放再回来
    DashCast,       // 原地动作但角色会冲到目标面前
    MoveToFormation, // 移动到阵容位置施法
    // 移动到的位置 CastPosition
    // 1.敌 2.我 3.自己的位置(原地不动) 4.敌方主目标
    // 敌我的扩展 CastIndexNum
    // 几号位
    None,
    Enemy, //敌
    Allies, //我
    Self,
    Target,
}
Main/System/Battle/Skill/SkillEffectAnchor.cs
File was deleted
Main/System/Battle/Skill/SkillEffectAnchor.cs.meta
File was deleted
Main/System/Battle/Skill/SkillEffectType.cs
@@ -1,7 +1,10 @@
public enum SkillEffectType
{
    Bullet, //  子弹类型
    Direct, // 直接伤害
    BuffEffect, //  Buff
    StageEffect, // 场景技
    None,
    Bullet,
    Direct,
    BuffEffect,
    StageEffect,
}
Main/System/Battle/Skill/SkillEffectType.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 0e224e8034be71b4d8571bb3adba5ecf
guid: cde6d4bfbadd30544972f057d02b37e9
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/System/Battle/Skill/SkillFactory.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using UnityEngine;
@@ -40,7 +41,7 @@
    public static SkillBase CreateSkill(BattleObject _caster, H0604_tagUseSkillAttack vNetData, BattleField battleField)
    public static SkillBase CreateSkill(BattleObject _caster, H0604_tagUseSkillAttack vNetData, List<GameNetPackBasic> packList, BattleField battleField)
    {
        SkillConfig skillConfig = SkillConfig.Get(vNetData.SkillID);
@@ -49,7 +50,7 @@
        {
            case 1:
                //    先实现一个攻击的 后续有再慢慢增加
                skill = new DirectlyDamageSkill(_caster, skillConfig, vNetData, battleField);
                skill = new DirectlyDamageSkill(_caster, skillConfig, vNetData, packList, battleField);
                break;
            case 2:
                // skill = new DirectlyHealSkill(_skillConfig);
Main/System/Battle/SkillEffect/BulletCurve.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e629a2dca5d56a24daca10dac6956487
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Battle/SkillEffect/BulletCurve/BezierBulletCurve.cs
New file
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using UnityEngine;
public class BezierBulletCurve : BulletCurve
{
    private Vector2 start;
    private Vector2 end;
    private Vector2 control;
    public BezierBulletCurve(BattleObject caster, SkillConfig skillConfig, EffectPlayer effectPlayer, RectTransform target, Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHit)
        : base(caster, skillConfig, effectPlayer, target, onHit) { }
    public override void Reset()
    {
        base.Reset();
        start = WorldToLocalAnchoredPosition(bulletTrans.position);
        end = WorldToLocalAnchoredPosition(target.position);
        control = (start + end) / 2 + Vector2.up * 100f;
    }
    public override void Run()
    {
        if (finished) return;
        elapsed += Time.deltaTime;
        float t = Mathf.Clamp01(elapsed / duration);
        Vector2 pos = Mathf.Pow(1 - t, 2) * start + 2 * (1 - t) * t * control + Mathf.Pow(t, 2) * end;
        bulletTrans.anchoredPosition = pos;
        Vector2 tangent = 2 * (1 - t) * (control - start) + 2 * t * (end - control);
        float angle = Mathf.Atan2(tangent.y, tangent.x) * Mathf.Rad2Deg - 90f;
        bulletTrans.localRotation = Quaternion.Euler(0, 0, angle);
        if (t >= 1f)
        {
            finished = true;
            onHit?.Invoke(0, null);
        }
    }
}
Main/System/Battle/SkillEffect/BulletCurve/BezierBulletCurve.cs.meta
copy from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta copy to Main/System/Battle/SkillEffect/BulletCurve/BezierBulletCurve.cs.meta
File was copied from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: 143c64c0c71854347bb8249a0f1d3d61
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/System/Battle/SkillEffect/BulletCurve/BounceBulletCurve.cs
New file
@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 弹射型子弹曲线:依次弹射到 HurtList 的每个目标,每次弹射飞行时间固定为0.2秒
/// </summary>
public class BounceBulletCurve : BulletCurve
{
    private List<H0604_tagUseSkillAttack.tagSkillHurtObj> hurtList;
    private int curIndex = 0;
    private Vector2 start;
    private Vector2 end;
    private float bounceTime = 0.2f; // 每次弹射时间
    private float bounceElapsed = 0f;
    public BounceBulletCurve(BattleObject caster, SkillConfig skillConfig, EffectPlayer effectPlayer,
        RectTransform target, H0604_tagUseSkillAttack tagUseSkillAttack, Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHit)
        : base(caster, skillConfig, effectPlayer, target, onHit)
    {
        this.hurtList = new List<H0604_tagUseSkillAttack.tagSkillHurtObj>(tagUseSkillAttack.HurtList);
    }
    public override void Reset()
    {
        base.Reset();
        curIndex = 0;
        bounceElapsed = 0f;
        if (hurtList.Count > 0)
        {
            start = WorldToLocalAnchoredPosition(bulletTrans.position);
            end = WorldToLocalAnchoredPosition(target.position);
        }
    }
    public override void Run()
    {
        if (finished || hurtList.Count == 0) return;
        bounceElapsed += Time.deltaTime;
        float t = Mathf.Clamp01(bounceElapsed / bounceTime);
        Vector2 pos = Vector2.Lerp(start, end, t) + Vector2.up * Mathf.Sin(t * Mathf.PI) * 50f;
        bulletTrans.anchoredPosition = pos;
        Vector2 dir = end - start;
        float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90f;
        bulletTrans.localRotation = Quaternion.Euler(0, 0, angle);
        if (t >= 1f)
        {
            // 命中当前目标
            onHit?.Invoke(curIndex, hurtList);
            curIndex++;
            if (curIndex >= hurtList.Count)
            {
                finished = true;
                return;
            }
            // 下一段弹射
            start = end;
            var nextTargetObj = caster.battleField.battleObjMgr.GetBattleObject((int)hurtList[curIndex].ObjID);
            if (nextTargetObj != null)
            {
                end = WorldToLocalAnchoredPosition(nextTargetObj.heroGo.transform.position);
            }
            else
            {
                Debug.LogError("弹射找不到下一个目标");
                // 如果目标丢失,直接用上一个end
                end = start;
            }
            bounceElapsed = 0f;
        }
    }
}
Main/System/Battle/SkillEffect/BulletCurve/BounceBulletCurve.cs.meta
copy from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta copy to Main/System/Battle/SkillEffect/BulletCurve/BounceBulletCurve.cs.meta
File was copied from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: 4296c603d2e1eeb498af28d3d6ae3f7d
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/System/Battle/SkillEffect/BulletCurve/BulletCurve.cs
New file
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using UnityEngine;
public class BulletCurve
{
    protected BattleObject caster;
    protected SkillConfig skillConfig;
    protected EffectPlayer bulletEffect;
    protected RectTransform bulletTrans; // 子弹的RectTransform
    protected RectTransform target;
    protected Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHit;
    protected bool finished = false;
    protected float duration = 0f;
    protected float elapsed = 0f;
    public BulletCurve() { }
    public BulletCurve(BattleObject caster, SkillConfig skillConfig, EffectPlayer bulletEffect, RectTransform target, Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHit)
    {
        this.caster = caster;
        this.skillConfig = skillConfig;
        this.bulletEffect = bulletEffect;
        this.target = target;
        this.onHit = onHit;
        this.bulletTrans = bulletEffect.transform as RectTransform;
    }
    public virtual void Reset()
    {
        finished = false;
        elapsed = 0f;
        duration = skillConfig.BulletFlyTime;
    }
    // 世界坐标转为bulletTrans父节点下的本地坐标
    protected Vector2 WorldToLocalAnchoredPosition(Vector3 worldPos)
    {
        var parent = bulletTrans.parent as RectTransform;
        Vector2 localPoint;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(parent, RectTransformUtility.WorldToScreenPoint(null, worldPos), null, out localPoint);
        return localPoint;
    }
    // Run就是Update,每帧调用
    public virtual void Run()
    {
        if (finished) return;
        Vector2 targetPos = WorldToLocalAnchoredPosition(target.position);
        bulletTrans.anchoredPosition = targetPos;
        ReachTarget();
    }
    protected virtual void ReachTarget()
    {
        finished = true;
        onHit?.Invoke(0, null);
        caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, bulletEffect);
    }
    public bool IsFinished => finished;
}
Main/System/Battle/SkillEffect/BulletCurve/BulletCurve.cs.meta
copy from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta copy to Main/System/Battle/SkillEffect/BulletCurve/BulletCurve.cs.meta
File was copied from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: 6fa6db282bea72441bbb2c13c6a353e3
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/System/Battle/SkillEffect/BulletCurve/BulletCurveFactory.cs
New file
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using UnityEngine;
public class BulletCurveFactory
{
    // 1·直线消失于目标
    // 2·直线贯穿消失在屏幕外
    // 3·抛物线弧线
    // 4·弹射
    // 5·透明
    public static BulletCurve CreateBulletCurve(
        BattleObject caster,
        SkillConfig skillConfig,
        EffectPlayer bulletEffect,
        RectTransform target,
        H0604_tagUseSkillAttack tagUseSkillAttack,
        Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHit)
    {
        switch (skillConfig.BulletPath)
        {
            case 1: // 直线消失于目标
                return new StraightBulletCurve(caster, skillConfig, bulletEffect, target, onHit);
            case 2: // 直线贯穿消失在屏幕外
                return new PenetrateBulletCurve(caster, skillConfig, bulletEffect, target, onHit);
            case 3: // 抛物线弧线
                return new BezierBulletCurve(caster, skillConfig, bulletEffect, target, onHit);
            case 4: // 弹射
                return new BounceBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack,onHit);
            default:
                return new BulletCurve(caster, skillConfig, bulletEffect, target, onHit);
        }
    }
}
Main/System/Battle/SkillEffect/BulletCurve/BulletCurveFactory.cs.meta
copy from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta copy to Main/System/Battle/SkillEffect/BulletCurve/BulletCurveFactory.cs.meta
File was copied from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: 66b56fd690393d44a81cebd1ddb43506
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/System/Battle/SkillEffect/BulletCurve/PenetrateBulletCurve.cs
New file
@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using UnityEngine;
public class PenetrateBulletCurve : BulletCurve
{
    private Vector2 start;      // 子弹起点(本地坐标)
    private Vector2 end;        // 目标点(本地坐标)
    private Vector2 outPos;     // 屏幕外延长点(本地坐标)
    private bool hitTriggered = false; // 是否已触发onHit
    public PenetrateBulletCurve(BattleObject caster, SkillConfig skillConfig, EffectPlayer effectPlayer, RectTransform target, Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHit)
        : base(caster, skillConfig, effectPlayer, target, onHit) { }
    /// <summary>
    /// 初始化弹道参数
    /// </summary>
    public override void Reset()
    {
        base.Reset();
        hitTriggered = false;
        start = WorldToLocalAnchoredPosition(bulletTrans.position);
        end = WorldToLocalAnchoredPosition(target.position);
        Vector2 dir = (end - start).normalized;
        float extend = 500f; // 贯穿距离,可根据需求调整
        outPos = end + dir * extend;
    }
    /// <summary>
    /// 每帧调用,驱动子弹移动和表现
    /// </summary>
    public override void Run()
    {
        if (finished) return;
        elapsed += Time.deltaTime;
        float t = Mathf.Clamp01(elapsed / duration);
        // 贯穿分两段:0~0.5到目标点,0.5~1.0继续飞出
        float mid = 0.5f;
        Vector2 pos;
        if (t < mid)
        {
            // 前半段:插值到目标点
            pos = Vector2.Lerp(start, end, t / mid);
        }
        else
        {
            // 后半段:插值到屏幕外
            pos = Vector2.Lerp(end, outPos, (t - mid) / (1f - mid));
            // 到达目标点瞬间触发onHit,只触发一次
            if (!hitTriggered)
            {
                hitTriggered = true;
                onHit?.Invoke(0, null);
            }
        }
        bulletTrans.anchoredPosition = pos;
        // 旋转:始终朝向运动方向,子弹默认90°向上
        Vector2 dir = (t < mid) ? (end - start) : (outPos - end);
        float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90f;
        bulletTrans.localRotation = Quaternion.Euler(0, 0, angle);
        // 到达终点,结束
        if (t >= 1f)
        {
            finished = true;
        }
    }
}
Main/System/Battle/SkillEffect/BulletCurve/PenetrateBulletCurve.cs.meta
copy from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta copy to Main/System/Battle/SkillEffect/BulletCurve/PenetrateBulletCurve.cs.meta
File was copied from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: d033c1638a667574bb58dd52f50f75ff
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/System/Battle/SkillEffect/BulletCurve/StraightBulletCurve.cs
New file
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using UnityEngine;
public class StraightBulletCurve : BulletCurve
{
    private Vector2 start;
    private Vector2 end;
    public StraightBulletCurve(BattleObject caster, SkillConfig skillConfig, EffectPlayer bulletEffect, RectTransform target, Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHit)
        : base(caster, skillConfig, bulletEffect, target, onHit) { }
    public override void Reset()
    {
        base.Reset();
        start = WorldToLocalAnchoredPosition(bulletTrans.position);
        end = WorldToLocalAnchoredPosition(target.position);
    }
    public override void Run()
    {
        if (finished) return;
        elapsed += Time.deltaTime;
        float t = Mathf.Clamp01(elapsed / duration);
        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;
        bulletTrans.localRotation = Quaternion.Euler(0, 0, angle);
        if (t >= 1f)
        {
            finished = true;
            onHit?.Invoke(0, null);
        }
    }
}
Main/System/Battle/SkillEffect/BulletCurve/StraightBulletCurve.cs.meta
copy from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta copy to Main/System/Battle/SkillEffect/BulletCurve/StraightBulletCurve.cs.meta
File was copied from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: c29cc9a862a7b724f82ec4bbd0a4432d
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/System/Battle/SkillEffect/BulletSkillEffect.cs
@@ -11,6 +11,8 @@
    // protected BattleObject caster;
    // protected List<BattleObject> targets; // 目标列表
    protected List<BulletCurve> bulletCurves = new List<BulletCurve>();
    public BulletSkillEffect(SkillConfig _skillConfig, BattleObject _caster, H0604_tagUseSkillAttack _tagUseSkillAttack)
        : base(_skillConfig, _caster, _tagUseSkillAttack)
    {
@@ -21,80 +23,115 @@
    public override void Play(Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> _onHit)
    {
        // Caster, //在施法者上
        // Target, //在目标上
        // AlliesCenter,// 在友方中心
        // EnemiesCenter,// 在敌方中心
        Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHitFormation = (_hitIndex, _hurtList) =>
        //  弹射 另外的做法了
        if (skillConfig.effectType == SkillEffectType.Bullet && skillConfig.BulletPath == 4)
        {
            _onHit?.Invoke(_hitIndex, tagUseSkillAttack.HurtList.ToList());
        };
        if (skillConfig.effectAnchor == SkillEffectAnchor.Caster)
        {
            // 不可能子弹射向自己吧
            Debug.LogError("子弹技能特效不能锚定在施法者上 skillConfig.effectAnchor");
            _onHit?.Invoke(0, default);
        }
        else if (skillConfig.effectAnchor == SkillEffectAnchor.Target)
        {
            if (tagUseSkillAttack == null || tagUseSkillAttack.HurtList.Length <= 0)
            var hurt = tagUseSkillAttack.HurtList[0];
            BattleObject targetObject = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
            if (targetObject == null)
            {
                Debug.LogError("子弹技能特效没有目标 tagUseSkillAttack.HurtList.Length <= 0");
                _onHit?.Invoke(0, default);
                Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                return;
            }
            foreach (var hurt in tagUseSkillAttack.HurtList)
            {
                BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                if (target == null)
                {
                    Debug.LogError("子弹技能特效目标为空 target == null ObjId : " + hurt.ObjID);
                    continue;
                }
                ShotToTarget(target.heroGo.transform as RectTransform, (index, list) => _onHit(0, new List<H0604_tagUseSkillAttack.tagSkillHurtObj>() { hurt }));
            }
            ShotToTarget(targetObject, _onHit);
        }
        else if (skillConfig.effectAnchor == SkillEffectAnchor.AlliesCenter)
        {
            ShotToTarget(caster.battleField.GetTeamNode(caster.Camp), onHitFormation);
        }
        else if (skillConfig.effectAnchor == SkillEffectAnchor.EnemiesCenter)
        {
            ShotToTarget(caster.battleField.GetTeamNode(caster.Camp == BattleCamp.Blue ? BattleCamp.Red : BattleCamp.Blue), onHitFormation);
        }
        //  普通的做法
        else
        {
            Debug.LogError("未知的技能特效锚点类型: " + skillConfig.effectAnchor);
            Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHitFormation = (_hitIndex, _hurtList) =>
            {
                _onHit?.Invoke(_hitIndex, tagUseSkillAttack.HurtList.ToList());
            };
            switch (skillConfig.castMode)
            {
                case SkillCastMode.Self:
                    onHitFormation?.Invoke(0, tagUseSkillAttack.HurtList.ToList());
                    Debug.LogError("子弹的目标是自己,暂时不支持 协商程序完成");
                    break;
                case SkillCastMode.Enemy:
                    var targetNode = caster.battleField.GetTeamNode(caster.GetEnemyCamp(), skillConfig.CastIndexNum);
                    ShotToFormation(targetNode, onHitFormation);
                    break;
                case SkillCastMode.Target:
                    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);
                            continue;
                        }
                        ShotToTarget(target, _onHit);
                    }
                    break;
                case SkillCastMode.Allies:
                    var healNode = caster.battleField.GetTeamNode(caster.Camp, skillConfig.CastIndexNum);
                    ShotToFormation(healNode, onHitFormation);
                    break;
                default:
                    Debug.LogError("暂时不支持其他的方式释放 有需求请联系程序 " + skillConfig.SkillID);
                    break;
            }
        }
    }
    protected void ShotToTarget(RectTransform target, Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> _onHit)
    protected void ShotToFormation(RectTransform target, Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> _onHit)
    {
        EffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.EffectId, caster.effectNode);
        EffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.BulletEffectId, caster.effectNode);
        RectTransform effectTrans = effectPlayer.transform as RectTransform;
        var tween = BattleUtility.MoveToTarget(effectTrans, target, Vector2.zero, skillConfig.FlyTime, () =>
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, effectPlayer, target, tagUseSkillAttack, (index, hitList) =>
        {
            // 表现子弹飞行到目标位置
            _onHit?.Invoke(0, null);
            _onHit?.Invoke(index, hitList);
            //  击中就销毁子弹
            caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.EffectId, effectPlayer);
            //  播放子弹爆炸特效
            caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.ExplotionEffectId, target);
            // 击中就销毁子弹
            caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer);
            // 播放子弹爆炸特效
            foreach (var hurt in hitList)
            {
                BattleObject targetObj = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                if (targetObj == null)
                {
                    Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                    continue;
                }
                caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffectId, targetObj.heroGo.transform);
            }
            // caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.ExplosionEffectId, target);
        });
        caster.battleField.battleTweenMgr.OnPlayTween(tween);
        bulletCurves.Add(bulletCurve);
    }
    protected void ShotToTarget(BattleObject target, Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> _onHit)
    {
        EffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.BulletEffectId, caster.effectNode);
        RectTransform effectTrans = effectPlayer.transform as RectTransform;
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, effectPlayer, target.heroGo.transform as RectTransform, tagUseSkillAttack, (index, hitList) =>
        {
            //  击中就销毁子弹 子弹不需要自动销毁 配置表里autoDestroy为false
            caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer);
            _onHit?.Invoke(index, hitList);
        });
        bulletCurves.Add(bulletCurve);
    }
    public override void Run()
    {
        foreach (var bulletCurve in bulletCurves)
        {
            if (!bulletCurve.IsFinished)
                bulletCurve.Run();
        }
    }
}
Main/System/Battle/SkillEffect/NormalSkillEffect.cs
@@ -14,70 +14,70 @@
    public NormalSkillEffect(SkillConfig _skillConfig, BattleObject _caster, H0604_tagUseSkillAttack _tagUseSkillAttack)
        : base(_skillConfig, _caster, _tagUseSkillAttack)
    {
    }
    public override void Play(Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> _onHit)
    {
        // 特效炸开在阵容的中间的回调
        Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHitLineUpCenter = (_hitIndex, _hurtList) =>
        {
            _onHit?.Invoke(_hitIndex, tagUseSkillAttack.HurtList.ToList());
        };
        // // 特效炸开在阵容的中间的回调
        // Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHitLineUpCenter = (_hitIndex, _hurtList) =>
        // {
        //     _onHit?.Invoke(_hitIndex, tagUseSkillAttack.HurtList.ToList());
        // };
        if (skillConfig.effectAnchor == SkillEffectAnchor.Caster)
        {
            CastInTarget(caster.heroGo.transform as RectTransform, onHitLineUpCenter);
        }
        else if (skillConfig.effectAnchor == SkillEffectAnchor.Target)
        {
            if (tagUseSkillAttack == null || tagUseSkillAttack.HurtList.Length <= 0)
            {
                Debug.LogError("没有目标 tagUseSkillAttack.HurtList.Length <= 0");
                _onHit?.Invoke(0, default);
                return;
            }
        // if (skillConfig.effectAnchor == SkillEffectAnchor.Caster)
        // {
        //     CastInTarget(caster.heroGo.transform as RectTransform, onHitLineUpCenter);
        // }
        // else if (skillConfig.effectAnchor == SkillEffectAnchor.Target)
        // {
        //     if (tagUseSkillAttack == null || tagUseSkillAttack.HurtList.Length <= 0)
        //     {
        //         Debug.LogError("没有目标 tagUseSkillAttack.HurtList.Length <= 0");
        //         _onHit?.Invoke(0, default);
        //         return;
        //     }
            foreach (var hurt in tagUseSkillAttack.HurtList)
            {
                BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                if (target == null)
                {
                    Debug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID);
                    continue;
                }
        //     foreach (var hurt in tagUseSkillAttack.HurtList)
        //     {
        //         BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
        //         if (target == null)
        //         {
        //             Debug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID);
        //             continue;
        //         }
                CastInTarget(target.heroGo.transform as RectTransform, (index, list) => _onHit(0, new List<H0604_tagUseSkillAttack.tagSkillHurtObj>() { hurt }));
            }
        }
        else if (skillConfig.effectAnchor == SkillEffectAnchor.AlliesCenter)
        {
            CastInTarget(caster.battleField.GetTeamNode(caster.Camp), onHitLineUpCenter);
        }
        else if (skillConfig.effectAnchor == SkillEffectAnchor.EnemiesCenter)
        {
            CastInTarget(caster.battleField.GetTeamNode(caster.Camp == BattleCamp.Blue ? BattleCamp.Red : BattleCamp.Blue), onHitLineUpCenter);
        }
        else
        {
            Debug.LogError("未知的技能特效锚点类型: " + skillConfig.effectAnchor);
        }
        //         CastInTarget(target.heroGo.transform as RectTransform, (index, list) => _onHit(0, new List<H0604_tagUseSkillAttack.tagSkillHurtObj>() { hurt }));
        //     }
        // }
        // else if (skillConfig.effectAnchor == SkillEffectAnchor.AlliesCenter)
        // {
        //     CastInTarget(caster.battleField.GetTeamNode(caster.Camp), onHitLineUpCenter);
        // }
        // else if (skillConfig.effectAnchor == SkillEffectAnchor.EnemiesCenter)
        // {
        //     CastInTarget(caster.battleField.GetTeamNode(caster.Camp == BattleCamp.Blue ? BattleCamp.Red : BattleCamp.Blue), onHitLineUpCenter);
        // }
        // else
        // {
        //     Debug.LogError("未知的技能特效锚点类型: " + skillConfig.effectAnchor);
        // }
    }
    protected void CastInTarget(RectTransform target, Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> _onHit)
    {
        EffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.EffectId, caster.effectNode);
        // EffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.EffectId, caster.effectNode);
        RectTransform effectTrans = effectPlayer.transform as RectTransform;
        // RectTransform effectTrans = effectPlayer.transform as RectTransform;
        _onHit?.Invoke(0, null);
        // _onHit?.Invoke(0, null);
        //  销毁自身上的特效应该是等特效播放完毕之后
        // caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.EffectId, effectPlayer);
        //  播放受击特效
        caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.ExplotionEffectId, target);
        // //  销毁自身上的特效应该是等特效播放完毕之后
        // // caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.EffectId, effectPlayer);
        // //  播放受击特效
        // caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.ExplotionEffectId, target);
    }
Main/System/Battle/SkillEffect/SkillEffect.cs
@@ -15,35 +15,10 @@
        tagUseSkillAttack = _tagUseSkillAttack;
    }
    public Action OnHit; // 表现到达目标时回调
    //  
    public virtual void Play(Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> _onHit)
    {
        // OnHit = _onHit;
        // switch (skillConfig.effectType)
        // {
        //     case SkillEffectType.StageEffect:
        //         Debug.LogError("播放场景特效");
        //         break;
        //     case SkillEffectType.Bullet:
        //         // 伪代码:表现子弹飞行
        //         Debug.Log("播放子弹特效");
        //         // 到达目标时
        //         OnHit?.Invoke();
        //         break;
        //     case SkillEffectType.Direct:
        //         // 伪代码:直接在目标身上播放特效
        //         Debug.Log("播放直接特效");
        //         OnHit?.Invoke();
        //         break;
        //     case SkillEffectType.BuffEffect:
        //         // 伪代码:播放持续特效
        //         Debug.Log("播放Buff特效");
        //         break;
        //     default:
        //         break;
        // }
    }
    public virtual void Run()
Main/System/Battle/SkillEffect/SkillEffectFactory.cs
@@ -6,20 +6,20 @@
{
    public static SkillEffect CreateSkillEffect(BattleObject caster, SkillConfig skillConfig, H0604_tagUseSkillAttack tagUseSkillAttack)
    {
        switch (skillConfig.effectType)
        {
            case SkillEffectType.Bullet:
                return new BulletSkillEffect(skillConfig, caster, tagUseSkillAttack);
            case SkillEffectType.Direct:
                return new NormalSkillEffect(skillConfig, caster, tagUseSkillAttack);
            // case SkillEffectType.BuffEffect:
            //     return new BuffSkillEffect(skillConfig, caster, targets);
            // case SkillEffectType.StageEffect:
            //     return new StageSkillEffect(skillConfig, caster, targets);
            default:
                UnityEngine.Debug.LogError("Unknown Skill Effect Type");
                break;
        }
        // switch (skillConfig.effectType)
        // {
        //     case SkillEffectType.Bullet:
        //         return new BulletSkillEffect(skillConfig, caster, tagUseSkillAttack);
        //     case SkillEffectType.Direct:
        //         return new NormalSkillEffect(skillConfig, caster, tagUseSkillAttack);
        //     // case SkillEffectType.BuffEffect:
        //     //     return new BuffSkillEffect(skillConfig, caster, targets);
        //     // case SkillEffectType.StageEffect:
        //     //     return new StageSkillEffect(skillConfig, caster, targets);
        //     default:
        //         UnityEngine.Debug.LogError("Unknown Skill Effect Type");
        //         break;
        // }
        return null;
    }
}
Main/System/Hero/HeroFetterInfo.cs
@@ -30,9 +30,9 @@
        int count = 0;
        for (int i = 0; i < teamBase.teamHeros.Length; i++)
        for (int i = 0; i < teamBase.serverHeroes.Length; i++)
        {
            TeamHero teamHero = teamBase.teamHeros[i];
            TeamHero teamHero = teamBase.serverHeroes[i];
            if (null == teamHero)
                continue;
Main/System/KnapSack/PackManager.cs
@@ -887,23 +887,23 @@
    private void AddItemUseTypeDict(int id)
    {
        SkillConfig skillConfig = GetSkillConfig(id);
        int itemCount = GetItemCountByID(PackType.Item, id);
        if (skillConfig != null && itemCount > 0)
        {
            if (!itemUseTypeDict.ContainsKey(skillConfig.SkillTypeID))
            {
                itemUseTypeDict.Add(skillConfig.SkillTypeID, id);
            }
            else
            {
                SkillConfig preSkillConfig = GetSkillConfig(itemUseTypeDict[skillConfig.SkillTypeID]);
                if (skillConfig.SkillLV > preSkillConfig.SkillLV)
                {
                    itemUseTypeDict[skillConfig.SkillTypeID] = id;
                }
            }
        }
        // SkillConfig skillConfig = GetSkillConfig(id);
        // int itemCount = GetItemCountByID(PackType.Item, id);
        // if (skillConfig != null && itemCount > 0)
        // {
        //     if (!itemUseTypeDict.ContainsKey(skillConfig.SkillTypeID))
        //     {
        //         itemUseTypeDict.Add(skillConfig.SkillTypeID, id);
        //     }
        //     else
        //     {
        //         SkillConfig preSkillConfig = GetSkillConfig(itemUseTypeDict[skillConfig.SkillTypeID]);
        //         if (skillConfig.SkillLV > preSkillConfig.SkillLV)
        //         {
        //             itemUseTypeDict[skillConfig.SkillTypeID] = id;
        //         }
        //     }
        // }
    }
Main/System/MainLevel.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a02c6eff6ff37404ab5bdfb3357a7fa1
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/MainLevel/MainLevelManager.cs
New file
@@ -0,0 +1,21 @@
using System.Collections.Generic;
using UnityEngine;
using LitJson;
public class MainLevelManager : GameSystemManager<MainLevelManager>
{
    public override void Init()
    {
        base.Init();
    }
    public override void Release()
    {
        base.Release();
    }
}
Main/System/MainLevel/MainLevelManager.cs.meta
copy from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta copy to Main/System/MainLevel/MainLevelManager.cs.meta
File was copied from Main/System/Battle/Bullet/TrajectoryBullet.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3d40a22572b07c24e9eefb52db0bfd87
guid: 8b71fdc64f650e34c972f50e1a10300f
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
Main/System/Message/RichTableEvent.cs
@@ -193,7 +193,7 @@
                                        var _cfg = SkillConfig.Get(_id);
                                        if (_cfg != null)
                                        {
                                            return _cfg.BuffDescription;
                                            return _cfg.Description;
                                        }
                                    }
                                }
Main/System/Team/TeamBase.cs
@@ -28,9 +28,9 @@
    private int ShapeType;
    public int ServerShapeType { get; private set; }
    public TeamHero[] teamHeros = new TeamHero[TeamConst.MaxTeamHeroCount];
    public TeamHero[] tempHeroes = new TeamHero[TeamConst.MaxTeamHeroCount];
    public TeamHero[] serverData { get; private set; } = new TeamHero[TeamConst.MaxTeamHeroCount];
    public TeamHero[] serverHeroes { get; private set; } = new TeamHero[TeamConst.MaxTeamHeroCount];
    public TeamBase(TeamType _teamType)
    {
@@ -49,12 +49,12 @@
        for (int i = 0; i < lineUp.ObjCnt; i++)
        {
            if (i < teamHeros.Length)
            if (i < tempHeroes.Length)
            {
                var fightObj = lineUp.ObjList[i];
                TeamHero hero = new TeamHero(fightObj, this);
                teamHeros[fightObj.PosNum] = hero;
                serverData[fightObj.PosNum] = hero;
                tempHeroes[fightObj.PosNum] = hero;
                serverHeroes[fightObj.PosNum] = hero;
            }
            else
            {
@@ -70,9 +70,9 @@
    public int GetTeamHeroCount()
    {
        int count = 0;
        for (int i = 0; i < teamHeros.Length; i++)
        for (int i = 0; i < tempHeroes.Length; i++)
        {
            if (teamHeros[i] != null)
            if (tempHeroes[i] != null)
            {
                count++;
            }
@@ -83,7 +83,7 @@
    public bool IsFull()
    {
        return GetTeamHeroCount() >= teamHeros.Length;
        return GetTeamHeroCount() >= tempHeroes.Length;
    }
    public bool IsEmpty()
@@ -109,7 +109,7 @@
        savePack.PosCnt = (byte)GetTeamHeroCount();
        savePack.HeroPosList = new CB412_tagCSHeroLineupSave.tagCSHeroLineupPos[savePack.PosCnt];
        foreach (var hero in teamHeros)
        foreach (var hero in tempHeroes)
        {
            if (hero != null)
            {
@@ -160,7 +160,7 @@
        for (int i = 0; i < heroInfos.Count; i++)
        {
            if (i < teamHeros.Length)
            if (i < tempHeroes.Length)
            {
                var heroInfo = heroInfos[i];
                TeamHero hero = new TeamHero(heroInfo, i, this);
@@ -175,7 +175,7 @@
    public TeamHero GetHero(string guid)
    {
        foreach (var hero in teamHeros)
        foreach (var hero in tempHeroes)
        {
            if (hero != null && hero.guid == guid)
            {
@@ -187,7 +187,7 @@
    public TeamHero GetServerHero(string guid)
    {
        foreach (var hero in serverData)
        foreach (var hero in serverHeroes)
        {
            if (hero != null && hero.guid == guid)
            {
@@ -200,7 +200,7 @@
    //  布阵接口
    public bool HasHero(string guid)
    {
        foreach (var hero in teamHeros)
        foreach (var hero in tempHeroes)
        {
            if (hero != null && hero.guid == guid)
            {
@@ -212,9 +212,9 @@
    public int GetEmptyPosition()
    {
        for (int i = 0; i < teamHeros.Length; i++)
        for (int i = 0; i < tempHeroes.Length; i++)
        {
            if (teamHeros[i] == null)
            if (tempHeroes[i] == null)
            {
                return i;
            }
@@ -225,25 +225,25 @@
    //  布阵接口
    public void SetTeamHero(int posNum, TeamHero hero)
    {
        teamHeros[posNum] = hero;
        tempHeroes[posNum] = hero;
    }
    //  布阵接口
    public void SetServerTeamHero(int posNum, TeamHero hero)
    {
        serverData[posNum] = hero;
        teamHeros[posNum] = hero;
        serverHeroes[posNum] = hero;
        tempHeroes[posNum] = hero;
    }
    public void AddHero(HeroInfo heroInfo, int targetPosition)
    {
        if (targetPosition < 0 || targetPosition >= teamHeros.Length)
        if (targetPosition < 0 || targetPosition >= tempHeroes.Length)
        {
            Debug.LogError("Invalid target position for adding hero.");
            return;
        }
        TeamHero targetHero = teamHeros[targetPosition];
        TeamHero targetHero = tempHeroes[targetPosition];
        if (null == targetHero)
        {
@@ -308,9 +308,9 @@
    {
        if (teamHero == null) return false;
        for (int i = 0; i < teamHeros.Length; i++)
        for (int i = 0; i < tempHeroes.Length; i++)
        {
            if (teamHeros[i] != null && teamHeros[i].guid == teamHero.guid)
            if (tempHeroes[i] != null && tempHeroes[i].guid == teamHero.guid)
            {
                SetTeamHero(i, null);
                return true; // Hero removed successfully
@@ -321,19 +321,19 @@
    public void SwapPosition(int index1, int index2)
    {
        if (index1 < 0 || index1 >= teamHeros.Length || index2 < 0 || index2 >= teamHeros.Length)
        if (index1 < 0 || index1 >= tempHeroes.Length || index2 < 0 || index2 >= tempHeroes.Length)
        {
            Debug.LogError("Invalid indices for swapping positions.");
            return;
        }
        TeamHero temp = teamHeros[index1];
        teamHeros[index1] = teamHeros[index2];
        teamHeros[index2] = temp;
        TeamHero temp = tempHeroes[index1];
        tempHeroes[index1] = tempHeroes[index2];
        tempHeroes[index2] = temp;
        //  更新位置编号
        if (teamHeros[index1] != null) teamHeros[index1].positionNum = index1;
        if (teamHeros[index2] != null) teamHeros[index2].positionNum = index2;
        if (tempHeroes[index1] != null) tempHeroes[index1].positionNum = index1;
        if (tempHeroes[index2] != null) tempHeroes[index2].positionNum = index2;
    }
    
}
Main/System/Team/TeamHero.cs
@@ -80,8 +80,8 @@
        positionNum = teamHero.positionNum;
        teamHero.positionNum = tempPosNum;
        teamBase.teamHeros[positionNum] = this;
        teamBase.teamHeros[teamHero.positionNum] = teamHero;
        teamBase.tempHeroes[positionNum] = this;
        teamBase.tempHeroes[teamHero.positionNum] = teamHero;
        Update();
    }
Main/System/Team/TeamManager.cs
@@ -35,30 +35,39 @@
        //  英雄当前所有在的队伍
        List<int> heroTeams = heroInfo.itemHero.GetUseData(81);
        Dictionary<TeamType, KeyValuePair<int, int>> teamTypeShapeTypePositionDict = new Dictionary<TeamType, KeyValuePair<int, int>>();
        foreach (var teamMsg in heroTeams)
        {
            // 所在阵容信息列表 [阵容类型*10000+阵型类型*100+位置编号, ...]
            int teamType = teamMsg / 10000;
            int shapeType = (teamMsg % 10000) / 100;
            int positionIndex = teamMsg % 100;
            if (teamTypeShapeTypePositionDict.ContainsKey((TeamType)teamType))
        //  当前英雄所在的队伍信息 <队伍类型, <队形, 位置>>
        Dictionary<TeamType, KeyValuePair<int, int>> teamTypeShapeTypePositionDict = new Dictionary<TeamType, KeyValuePair<int, int>>();
        //  处理当前记录在英雄信息里的队伍信息
        if (null != heroTeams)
        {
            foreach (var teamMsg in heroTeams)
            {
                //  队伍类型相同,更新阵型和位置
                Debug.LogError("当前英雄拥有两个相同的队伍信息: " + teamType + " " + shapeType + " " + positionIndex + ", hero guid is " + heroInfo.itemHero.guid);
            }
            else
            {
                //  队伍类型不同,添加新的
                KeyValuePair<int, int> shapeTypePosition = new KeyValuePair<int, int>(shapeType, positionIndex);
                teamTypeShapeTypePositionDict.Add((TeamType)teamType, shapeTypePosition);
                // 所在阵容信息列表 [阵容类型*10000+阵型类型*100+位置编号, ...]
                int teamType = teamMsg / 10000;
                int shapeType = (teamMsg % 10000) / 100;
                int positionIndex = teamMsg % 100;
                if (teamTypeShapeTypePositionDict.ContainsKey((TeamType)teamType))
                {
                    //  队伍类型相同,更新阵型和位置
                    Debug.LogError("当前英雄拥有两个相同的队伍信息: " + teamType + " " + shapeType + " " + positionIndex + ", hero guid is " + heroInfo.itemHero.guid);
                }
                else
                {
                    //  队伍类型不同,添加新的
                    KeyValuePair<int, int> shapeTypePosition = new KeyValuePair<int, int>(shapeType, positionIndex);
                    teamTypeShapeTypePositionDict.Add((TeamType)teamType, shapeTypePosition);
                }
            }
        }
        //  遍历当前所有队伍 判断当前队伍里是否有该英雄
        //  如果有的话 读取一下当前是否该英雄还在队伍里 位置是否发生变化
        //  或者是阵型发生变化 或者单纯的英雄发生变化
        //  如果有的话 根据英雄里的信息当前是否该英雄还在队伍里 是否发生变化
        //      =>1.阵型发生变化 2.位置发生变化
        //  如果没有的话 就说明该英雄被移出队伍了
        foreach (var team in teamDict.Values)
        {