| | |
| | | rectTrans.anchoredPosition += new Vector2(effectConfig.effectPos[0], effectConfig.effectPos[1]); |
| | | } |
| | | |
| | | if (effectConfig.effectScale > 0f) |
| | | { |
| | | rectTrans.localScale *= effectConfig.effectScale; |
| | | } |
| | | } |
| | | |
| | | protected virtual void Clear() |
| | |
| | | |
| | | protected void OnSortingChanged(string _sortingLayer, int _sortingOrder) |
| | | { |
| | | if (null == spineComp) |
| | | return; |
| | | |
| | | sortingLayer = _sortingLayer; |
| | | sortingOrder = _sortingOrder; |
| | | // 处理排序变化 |
| | |
| | |
|
| | | // 加载配置文件
|
| | | HashSet<Type> configTypes = new HashSet<Type>() {
|
| | | typeof(ChestsAwardConfig),
|
| | | typeof(CTGConfig),
|
| | | typeof(DamageNumConfig),
|
| | | typeof(DirtyWordConfig),
|
| | | typeof(FaceConfig),
|
| | | typeof(FightPowerRatioConfig),
|
| | | typeof(HeroLineupHaloConfig),
|
| | | typeof(HeroQualityLVConfig),
|
| | | typeof(InvestConfig),
|
| | | typeof(ItemConfig),
|
| | | typeof(MainChapterConfig),
|
| | | typeof(MainLevelConfig),
|
| | | typeof(NPCConfig),
|
| | | typeof(NPCExConfig),
|
| | | typeof(NPCLineupConfig),
|
| | | typeof(OrderInfoConfig),
|
| | | typeof(PlayerAttrConfig),
|
| | | typeof(PlayerFaceConfig),
|
| | | typeof(StoreConfig),
|
| | | typeof(SuccessConfig),
|
| | | typeof(SysInfoConfig),
|
| | | typeof(TitleStarUpConfig),
|
| | | typeof(TreasureSetConfig),
|
| | | typeof(TreeLVConfig),
|
| | | typeof(WindowSearchConfig),
|
| | | typeof(XBGetItemConfig)
|
| | | typeof(PlayerLVConfig),
|
| | | typeof(TitleStarUpConfig)
|
| | | };
|
| | |
|
| | | #if UNITY_EDITOR
|
| | |
| | |
|
| | | public override void Release()
|
| | | {
|
| | | // 清空 ChestsAwardConfig 字典
|
| | | ClearConfigDictionary<ChestsAwardConfig>();
|
| | | // 清空 CTGConfig 字典
|
| | | ClearConfigDictionary<CTGConfig>();
|
| | | // 清空 DamageNumConfig 字典
|
| | | ClearConfigDictionary<DamageNumConfig>();
|
| | | // 清空 DirtyWordConfig 字典
|
| | | ClearConfigDictionary<DirtyWordConfig>();
|
| | | // 清空 FaceConfig 字典
|
| | | ClearConfigDictionary<FaceConfig>();
|
| | | // 清空 FightPowerRatioConfig 字典
|
| | | ClearConfigDictionary<FightPowerRatioConfig>();
|
| | | // 清空 HeroLineupHaloConfig 字典
|
| | |
| | | ClearConfigDictionary<InvestConfig>();
|
| | | // 清空 ItemConfig 字典
|
| | | ClearConfigDictionary<ItemConfig>();
|
| | | // 清空 MainChapterConfig 字典
|
| | | ClearConfigDictionary<MainChapterConfig>();
|
| | | // 清空 MainLevelConfig 字典
|
| | | ClearConfigDictionary<MainLevelConfig>();
|
| | | // 清空 NPCConfig 字典
|
| | | ClearConfigDictionary<NPCConfig>();
|
| | | // 清空 NPCExConfig 字典
|
| | | ClearConfigDictionary<NPCExConfig>();
|
| | | // 清空 NPCLineupConfig 字典
|
| | | ClearConfigDictionary<NPCLineupConfig>();
|
| | | // 清空 OrderInfoConfig 字典
|
| | | ClearConfigDictionary<OrderInfoConfig>();
|
| | | // 清空 PlayerAttrConfig 字典
|
| | | ClearConfigDictionary<PlayerAttrConfig>();
|
| | | // 清空 PlayerFaceConfig 字典
|
| | | ClearConfigDictionary<PlayerFaceConfig>();
|
| | | // 清空 StoreConfig 字典
|
| | | ClearConfigDictionary<StoreConfig>();
|
| | | // 清空 SuccessConfig 字典
|
| | | ClearConfigDictionary<SuccessConfig>();
|
| | | // 清空 SysInfoConfig 字典
|
| | | ClearConfigDictionary<SysInfoConfig>();
|
| | | // 清空 PlayerLVConfig 字典
|
| | | ClearConfigDictionary<PlayerLVConfig>();
|
| | | // 清空 TitleStarUpConfig 字典
|
| | | ClearConfigDictionary<TitleStarUpConfig>();
|
| | | // 清空 TreasureSetConfig 字典
|
| | | ClearConfigDictionary<TreasureSetConfig>();
|
| | | // 清空 TreeLVConfig 字典
|
| | | ClearConfigDictionary<TreeLVConfig>();
|
| | | // 清空 WindowSearchConfig 字典
|
| | | ClearConfigDictionary<WindowSearchConfig>();
|
| | | // 清空 XBGetItemConfig 字典
|
| | | ClearConfigDictionary<XBGetItemConfig>();
|
| | | }
|
| | |
|
| | | #if UNITY_EDITOR
|
| | |
| | | //-------------------------------------------------------- |
| | | // [Author]: YYL |
| | | // [ Date ]: 2025年8月6日 |
| | | // [ Date ]: 2025年9月3日 |
| | | //-------------------------------------------------------- |
| | | |
| | | using System.Collections.Generic; |
| | |
| | | using UnityEngine; |
| | | using LitJson; |
| | | |
| | | public partial class DamageNumConfig : ConfigBase<string, DamageNumConfig> |
| | | public partial class DamageNumConfig : ConfigBase<int, DamageNumConfig> |
| | | { |
| | | static DamageNumConfig() |
| | | { |
| | |
| | | visit = true; |
| | | } |
| | | |
| | | public string id; |
| | | public int TypeID; |
| | | public string id; |
| | | public int prefix; |
| | | public int plus; |
| | | public int minus; |
| | | public int[] nums; |
| | | |
| | | public override string LoadKey(string _key) |
| | | public override int LoadKey(string _key) |
| | | { |
| | | string key = GetKey(_key); |
| | | int key = GetKey(_key); |
| | | return key; |
| | | } |
| | | |
| | |
| | | { |
| | | try { |
| | | string[] tables = input.Split('\t'); |
| | | id = tables[0]; |
| | | int.TryParse(tables[0],out TypeID); |
| | | |
| | | int.TryParse(tables[1],out prefix); |
| | | id = tables[1]; |
| | | |
| | | int.TryParse(tables[2],out plus); |
| | | int.TryParse(tables[2],out prefix); |
| | | |
| | | int.TryParse(tables[3],out minus); |
| | | int.TryParse(tables[3],out plus); |
| | | |
| | | if (tables[4].Contains("[")) |
| | | int.TryParse(tables[4],out minus); |
| | | |
| | | if (tables[5].Contains("[")) |
| | | { |
| | | nums = JsonMapper.ToObject<int[]>(tables[4]); |
| | | nums = JsonMapper.ToObject<int[]>(tables[5]); |
| | | } |
| | | else |
| | | { |
| | | string[] numsStringArray = tables[4].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries); |
| | | string[] numsStringArray = tables[5].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries); |
| | | nums = new int[numsStringArray.Length]; |
| | | for (int i=0;i<numsStringArray.Length;i++) |
| | | { |
| | |
| | | //--------------------------------------------------------
|
| | | // [Author]: YYL
|
| | | // [ Date ]: 2025年8月26日
|
| | | // [ Date ]: 2025年9月2日
|
| | | //--------------------------------------------------------
|
| | |
|
| | | using System.Collections.Generic;
|
| | |
| | | public int frontBack;
|
| | | public float delayPlay;
|
| | | public int[] effectPos;
|
| | | public float effectScale;
|
| | |
|
| | | public override int LoadKey(string _key)
|
| | | {
|
| | |
| | | int.TryParse(effectPosStringArray[i],out effectPos[i]); |
| | | } |
| | | }
|
| | |
|
| | | float.TryParse(tables[14],out effectScale); |
| | | }
|
| | | catch (Exception exception)
|
| | | {
|
| | |
| | | //--------------------------------------------------------
|
| | | // [Author]: YYL
|
| | | // [ Date ]: Friday, August 29, 2025
|
| | | // [ Date ]: 2025年9月2日
|
| | | //--------------------------------------------------------
|
| | |
|
| | | using System.Collections.Generic;
|
| | |
| | | public int BulletEffectId;
|
| | | public int BulletPath;
|
| | | public float BulletFlyTime;
|
| | | public int Scattering;
|
| | | public int ExplosionEffectId;
|
| | | public int ExplosionEffect2;
|
| | | public int ExplosionEffect3;
|
| | | public int EffectId;
|
| | | public int EffectId2;
|
| | | public int MStartEffectId;
|
| | |
| | |
|
| | | float.TryParse(tables[30],out BulletFlyTime);
|
| | |
|
| | | int.TryParse(tables[31],out ExplosionEffectId); |
| | | int.TryParse(tables[31],out Scattering); |
| | |
|
| | | int.TryParse(tables[32],out ExplosionEffect2); |
| | | int.TryParse(tables[32],out ExplosionEffectId); |
| | |
|
| | | int.TryParse(tables[33],out EffectId); |
| | | int.TryParse(tables[33],out ExplosionEffect2); |
| | |
|
| | | int.TryParse(tables[34],out EffectId2); |
| | | int.TryParse(tables[34],out ExplosionEffect3); |
| | |
|
| | | int.TryParse(tables[35],out MStartEffectId); |
| | | int.TryParse(tables[35],out EffectId); |
| | |
|
| | | int.TryParse(tables[36],out TriggerEffect); |
| | | int.TryParse(tables[36],out EffectId2); |
| | |
|
| | | int.TryParse(tables[37],out MStartEffectId); |
| | |
|
| | | int.TryParse(tables[38],out TriggerEffect); |
| | | }
|
| | | catch (Exception exception)
|
| | | {
|
| | |
| | | |
| | | public class CustomB421ActionPack : GameNetPackBasic |
| | | { |
| | | public int actionPackId = 0; |
| | | |
| | | private static int autoincreaseId = 10000; |
| | | |
| | | public CustomB421ActionPack() |
| | | { |
| | | actionPackId = autoincreaseId++; |
| | | } |
| | | public string guid; |
| | | |
| | | public Queue<GameNetPackBasic> actionPacks = new Queue<GameNetPackBasic>(); |
| | | |
| | | public static CustomB421ActionPack CreateB421ActionPack(string _guid, List<GameNetPackBasic> packList) |
| | | { |
| | | CustomB421ActionPack actionPack = new CustomB421ActionPack(); |
| | | |
| | | // 合并一下这个角色的行动内容的技能 制作成CustomB421ActionPack |
| | | List<GameNetPackBasic> combinedPackList = CustomHB426CombinePack.CombineToSkillPackFromList(_guid, packList); |
| | | CustomB421ActionPack actionPack = new CustomB421ActionPack(); |
| | | actionPack.guid = _guid; |
| | | actionPack.actionPacks = new Queue<GameNetPackBasic>(combinedPackList); |
| | | return actionPack; |
| | |
| | | { |
| | | GameNetPackBasic pack = actionPacks.Dequeue(); |
| | | |
| | | BattleDebug.LogError("CustomB421ActionPack distribute pack " + pack.GetType().Name); |
| | | |
| | | if (pack is CustomHB426CombinePack) |
| | | if (pack is CustomHB426CombinePack b426Pack) |
| | | { |
| | | var b426Pack = pack as CustomHB426CombinePack; |
| | | b426Pack.Distribute(); |
| | | } |
| | | else |
| | | { |
| | | BattleDebug.LogError("distribute pack " + pack.GetType().Name); |
| | | PackageRegedit.Distribute(pack); |
| | | } |
| | | } |
| | |
| | | } |
| | | endTag = _endTag; |
| | | toIndex = _toIndex; |
| | | |
| | | packList = CombineToSkillPackFromList(guid, packList); |
| | | } |
| | | |
| | | |
| | |
| | | return startTag.Tag == tag.Tag && tag.Sign == 1; |
| | | } |
| | | |
| | | |
| | | public static List<GameNetPackBasic> CombineToSkillPackFromList(string _guid, List<GameNetPackBasic> b421SeriesPackList) |
| | | { |
| | | CustomHB426CombinePack combinePack = null; |
| | | Dictionary<string, CustomHB426CombinePack> combineDict = new Dictionary<string, CustomHB426CombinePack>(); |
| | | |
| | | Dictionary<int, GameNetPackBasic> indexDict = new Dictionary<int, GameNetPackBasic>(); |
| | | |
| | | 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) |
| | | CustomHB426CombinePack combinePack; |
| | | |
| | | if (!combineDict.TryGetValue(tag.Tag, out combinePack)) |
| | | { |
| | | combinePack = new CustomHB426CombinePack(); |
| | | combinePack.guid = _guid; |
| | | combineDict.Add(tag.Tag, combinePack); |
| | | |
| | | indexDict.Add(i, combinePack); |
| | | } |
| | | |
| | | if (tag.Sign == 0) |
| | | { |
| | | combinePack.SetHB426Start(i, tag); |
| | | continue; |
| | | } |
| | | else |
| | | // 找到对应的开始标签 |
| | | if (combinePack.IsEndPack(tag)) |
| | | { |
| | | if (combinePack.IsEndPack(tag)) |
| | | combinePack.SetHB426End(i, tag); |
| | | continue; |
| | | } |
| | | |
| | | Debug.LogError("No matching start tag or end tag found: " + tag.Tag); |
| | | continue; |
| | | } |
| | | else |
| | | { |
| | | indexDict.Add(i, pack); |
| | | } |
| | | } |
| | | |
| | | // 嵌套包内的包合并 |
| | | foreach (var combinePack in combineDict.Values) |
| | | { |
| | | for (int i = combinePack.fromIndex + 1; i < combinePack.toIndex; i++) |
| | | { |
| | | if (indexDict.TryGetValue(i, out var pack)) |
| | | { |
| | | if (pack is CustomHB426CombinePack) |
| | | { |
| | | combinePack.SetHB426End(i, tag); |
| | | break; |
| | | // 如果是嵌套的包 加入之后 调整i |
| | | combinePack.AddPack(pack); |
| | | i = (pack as CustomHB426CombinePack).toIndex; |
| | | } |
| | | else |
| | | { |
| | | combinePack.AddPack(pack); |
| | | indexDict.Remove(i); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (null != combinePack) |
| | | { |
| | | combinePack.AddPack(pack); |
| | | } |
| | | } |
| | | |
| | | List<GameNetPackBasic> newPackList = new List<GameNetPackBasic>(); |
| | | |
| | | if (null != combinePack) |
| | | // string temp = string.Empty; |
| | | |
| | | for (int i = 0; i < b421SeriesPackList.Count; i++) |
| | | { |
| | | // 技能包前面的包(不包括b426的开始标签) |
| | | for (int i = 0; i < combinePack.fromIndex; i++) |
| | | if (indexDict.TryGetValue(i, out var pack)) |
| | | { |
| | | newPackList.Add(b421SeriesPackList[i]); |
| | | newPackList.Add(pack); |
| | | if (pack is CustomHB426CombinePack) |
| | | { |
| | | var cbpack = pack as CustomHB426CombinePack; |
| | | // temp += "pack type is " + pack.GetType().Name + " tag is " + cbpack.startTag.Tag + "\n"; |
| | | } |
| | | else |
| | | { |
| | | // temp += "pack type is " + pack.GetType().Name + "\n"; |
| | | } |
| | | } |
| | | |
| | | // 把合并的技能包加进来 |
| | | 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; |
| | | } |
| | | |
| | | // Debug.LogError(temp); |
| | | |
| | | return newPackList; |
| | | } |
| | | |
| | | public void Distribute() |
| | |
| | | { |
| | | battleField.PlayRecord(skillAction); |
| | | } |
| | | |
| | | } |
| | | |
| | | public SkillRecordAction CreateSkillAction() |
| | |
| | | packUID = AutoIncreaseUID++; |
| | | } |
| | | |
| | | public bool isDistribute = false; |
| | | |
| | | |
| | | public ServerType socketType = ServerType.Main; //默认且唯一 |
| | |
| | | effectDict[effectId] = new List<BattleEffectPlayer>(); |
| | | } |
| | | |
| | | BattleDebug.LogError("播放特效 " + effectId); |
| | | |
| | | BattleEffectPlayer effectPlayer = BattleEffectPlayer.Create(effectId, battleField.battleRootNode.transform); |
| | | // 设置特效缩放和方向 |
| | |
| | | } |
| | | else |
| | | { |
| | | BattleDebug.LogError("could not find effect in list, effectid : " + effectId); |
| | | Debug.LogError("could not find effect in list, effectid : " + effectId); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | if (operationAgent == null) |
| | | { |
| | | BattleDebug.LogError("you should SetBattleMode before Run"); |
| | | Debug.LogError("you should SetBattleMode before Run"); |
| | | return; |
| | | } |
| | | |
| | |
| | | break; |
| | | } |
| | | |
| | | BattleDebug.LogError("battleMode is " + battleMode.ToString()); |
| | | } |
| | | |
| | | public virtual void AutoSetBattleMode() |
| | |
| | | // TurnNum; // 当前轮次 |
| | | // Len; |
| | | // Msg; //size = Len + |
| | | |
| | | |
| | | if (State == 4) |
| | | { |
| | | //已经结束并结算 |
| | |
| | | if (deadPackList.Count > 0) |
| | | { |
| | | DeathRecordAction recordAction = new DeathRecordAction(this, deadPackList); |
| | | recordPlayer.PlayRecord(recordAction); |
| | | recordPlayer.ImmediatelyPlay(recordAction); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | if (index < 0 || index >= battleRootNode.redTeamNodeList.Count) |
| | | { |
| | | BattleDebug.LogError($"GetTeamNode: Index {index} is out of range for {battleCamp} camp."); |
| | | Debug.LogError($"GetTeamNode: Index {index} is out of range for {battleCamp} camp."); |
| | | return null; |
| | | } |
| | | |
| | |
| | | } |
| | | else |
| | | { |
| | | BattleDebug.LogError($"BattleObject with ID {vNetData.ObjID} not found for reborn."); |
| | | Debug.LogError($"BattleObject with ID {vNetData.ObjID} not found for reborn."); |
| | | } |
| | | } |
| | | |
| | |
| | | // 通过主界面的按钮推动(调用)DoNext |
| | | public override void DoNext() |
| | | { |
| | | BattleDebug.LogError("HandModeOperationAgent DoNext"); |
| | | |
| | | base.DoNext(); |
| | | |
| | | storyBattleField.RequestFight(); |
| | |
| | | : base(RecordActionType.Skill, _battleField, _caster) |
| | | { |
| | | skillBase = SkillFactory.CreateSkill(_caster, vNetData, packList, _battleField); |
| | | BattleDebug.LogError("skill record action tpye : " + skillBase.GetType().Name); |
| | | } |
| | | |
| | | public override bool IsFinished() |
| | |
| | | // 当前没有在播放战斗录像 |
| | | if (!recordPlayer.IsPlaying()) |
| | | { |
| | | BattleDebug.LogError("HandModeOperationAgent DoNext 1"); |
| | | // 没有下一个包可以发了 |
| | | if (!BattleManager.Instance.DistributeNextPackage()) |
| | | { |
| | | |
| | | BattleDebug.LogError("HandModeOperationAgent DoNext 2"); |
| | | |
| | | //再检查一次有没装备未处理 |
| | | if (PackManager.Instance.GetSinglePack(PackType.DropItem).GetItems().Count > 0) |
| | |
| | | // BOSS挑战说明:休息中挑战BOSS恢复到休息状态 不发包; |
| | | // 战斗中挑战BOSS恢复到战斗状态 发4包;服务端挑战boss已经清小怪场 |
| | | |
| | | BattleDebug.LogError("HandModeOperationAgent DoNext 3"); |
| | | byte reqType; |
| | | |
| | | if (battleState == StoryBattleState.Break) |
| | |
| | | return; |
| | | } |
| | | |
| | | BattleDebug.LogError("HandModeOperationAgent DoNext 4 reqType is " + reqType); |
| | | |
| | | |
| | | // 如果请求的是2 说明要初始化一下战场 |
| | |
| | | List<GameNetPackBasic> b421PackList = new List<GameNetPackBasic>(); |
| | | i++; // 跳过当前的B421包 |
| | | |
| | | // 收集所有非B421包,直到遇到下一个B421或队列结束 |
| | | for (; i < packQueueSnapshot.Count; i++) |
| | | { |
| | | GameNetPackBasic nextPack = packQueueSnapshot[i]; |
| | | if (nextPack is HB421_tagMCTurnFightObjAction) |
| | | { |
| | | // 遇到了其他B421 启动角色的Action开始, |
| | | // B421后再碰到B421一定是有一个人的行动结束了 回退一个位置 |
| | | i--; |
| | | i--; // 回退一个位置,留给外层循环处理 |
| | | break; |
| | | } |
| | | else |
| | |
| | | } |
| | | } |
| | | |
| | | // 可能没用了 主要就是利用一下skill的combine 暂留 看之后还有没有别的需求 |
| | | // 合并所有相关包 |
| | | CustomB421ActionPack actionPack = CustomB421ActionPack.CreateB421ActionPack(GetGUID(b421Pack.packUID), b421PackList); |
| | | |
| | | newPackList.Add(actionPack); |
| | |
| | | Debug.LogWarning($"连续空战斗片段封包次数:{continousEmptyCount}"); |
| | | if (continousEmptyCount >= MaxContinousEmptyCount) |
| | | { |
| | | BattleDebug.LogError("连续多次没有战斗片段封包,自动回城休息!"); |
| | | Debug.LogError("连续多次没有战斗片段封包,自动回城休息!"); |
| | | MainFightRequest(0); // 0-停止战斗回城 |
| | | continousEmptyCount = 0; |
| | | packQueue.Clear(); |
| | |
| | | continousEmptyCount = 0; // 有包就重置 |
| | | } |
| | | |
| | | |
| | | // b421跟b426的包已经处理完了 |
| | | packQueue = new Queue<GameNetPackBasic>(newPackList); |
| | | packQueue = new Queue<GameNetPackBasic>(newPackList); |
| | | |
| | | DistributeNextPackage(); |
| | | } |
| | |
| | | // 专属于主线战斗的派发 |
| | | public bool DistributeNextPackage() |
| | | { |
| | | if (packQueue.Count > 0) |
| | | if (packQueue == null) |
| | | { |
| | | GameNetPackBasic pack = packQueue.Peek(); |
| | | |
| | | bool dequeue = false; |
| | | |
| | | if (pack is CustomHB426CombinePack) |
| | | { |
| | | CustomHB426CombinePack combinePack = pack as CustomHB426CombinePack; |
| | | packQueue.Dequeue(); |
| | | combinePack.Distribute(); |
| | | } |
| | | else if (pack is CustomB421ActionPack) |
| | | { |
| | | CustomB421ActionPack actionPack = pack as CustomB421ActionPack; |
| | | |
| | | dequeue = !actionPack.Distribute(); |
| | | } |
| | | else |
| | | { |
| | | BattleDebug.LogError("distribute pack " + pack.GetType().Name); |
| | | packQueue.Dequeue(); |
| | | PackageRegedit.Distribute(pack); |
| | | } |
| | | |
| | | if (dequeue && packQueue.Count > 0) |
| | | { |
| | | packQueue.Dequeue(); |
| | | } |
| | | |
| | | return true; |
| | | Debug.LogWarning("DistributeNextPackage: packQueue为空或已处理完毕"); |
| | | return false; |
| | | } |
| | | else |
| | | |
| | | if (packQueue.Count <= 0) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | GameNetPackBasic pack = null; |
| | | try |
| | | { |
| | | pack = packQueue.Dequeue(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Debug.LogError("DistributeNextPackage: Peek异常 " + ex); |
| | | return false; |
| | | } |
| | | |
| | | try |
| | | { |
| | | if (pack is CustomHB426CombinePack combinePack) |
| | | { |
| | | combinePack.Distribute(); |
| | | } |
| | | else if (pack is CustomB421ActionPack actionPack) |
| | | { |
| | | actionPack.Distribute(); |
| | | } |
| | | else |
| | | { |
| | | PackageRegedit.Distribute(pack); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Debug.LogError("DistributeNextPackage: 分发包异常 " + ex); |
| | | // 出错时主动移除当前包,防止死循环 |
| | | if (packQueue.Count > 0) |
| | | { |
| | | packQueue.Dequeue(); |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | return packQueue.Count > 0; |
| | | } |
| | | |
| | | public void OnConnected() |
| | |
| | | } |
| | | |
| | | var pack = queue.Dequeue(); |
| | | BattleDebug.LogError("distribute pack " + pack.GetType().Name); |
| | | |
| | | PackageRegedit.Distribute(pack); |
| | | |
| | |
| | | battlePackRelationList.Remove(guid); |
| | | } |
| | | |
| | | BattleDebug.LogError("BattlePackage count is " + queue.Count); |
| | | } |
| | | #endregion |
| | | |
| | |
| | | teamHero.rage = (int)GeneralDefine.GetFactValue(_refreshInfo.Value, _refreshInfo.ValueEx); |
| | | break; |
| | | default: |
| | | BattleDebug.LogError("BattleObject.ObjInfoRefresh 出现意外类型 " + _refreshInfo.RefreshType.ToString()); |
| | | Debug.LogError("BattleObject.ObjInfoRefresh 出现意外类型 " + _refreshInfo.RefreshType.ToString()); |
| | | break; |
| | | } |
| | | } |
| | |
| | | return true; |
| | | } |
| | | |
| | | public virtual void Hurt(List<long> damageValues, long _totalDamage, uint attackType) |
| | | public virtual void Hurt(List<long> damageValues, long _totalDamage, HB427_tagSCUseSkill.tagSCUseSkillHurt hurt, SkillConfig skillConfig) |
| | | { |
| | | PopDamage(teamHero.curHp, damageValues, attackType); |
| | | PopDamage(damageValues, hurt, skillConfig); |
| | | |
| | | motionBase.PlayAnimation(MotionName.hit, false); |
| | | |
| | | // 扣血 |
| | | |
| | | // 扣血流给别的敌方刷新好了 |
| | | teamHero.curHp -= _totalDamage; |
| | | } |
| | | } |
| | | |
| | | public void SuckHp(uint suckHP) |
| | | public void SuckHp(uint suckHP, SkillConfig skillConfig) |
| | | { |
| | | |
| | | } |
| | | |
| | | public void HurtByReflect(uint bounceHP) |
| | | public void HurtByReflect(uint bounceHP, SkillConfig skillConfig) |
| | | { |
| | | |
| | | } |
| | |
| | | |
| | | public virtual void OnDeath(Action _onDeathAnimationComplete) |
| | | { |
| | | BattleDebug.LogError(ObjID + " OnDeath called"); |
| | | onDeathAnimationComplete = _onDeathAnimationComplete; |
| | | motionBase.PlayAnimation(MotionName.dead, false); |
| | | } |
| | | |
| | | protected virtual void OnAnimationComplete(MotionName motionName) |
| | | protected virtual void OnAnimationComplete(string motionName) |
| | | { |
| | | if (motionName == MotionName.dead) |
| | | if (motionName == MotionName.dead.ToString().ToLower()) |
| | | { |
| | | OnDeadAnimationComplete(); |
| | | onDeathAnimationComplete?.Invoke(); |
| | |
| | | } |
| | | |
| | | // 伤害还要看 是否闪避 暴击 and so on 需要有一个DamageType 服务器应该会给 |
| | | protected virtual void PopDamage(long curHp, List<long> damageValues, uint attackType) |
| | | protected virtual void PopDamage(List<long> damageValues, HB427_tagSCUseSkill.tagSCUseSkillHurt hurt, SkillConfig skillConfig) |
| | | { |
| | | // 其实应该通知出去给UI界面解耦 让UI界面自己来显示的 YYL TODO |
| | | // 播放伤害数字 |
| | | // 这里可以实现一个伤害数字的弹出效果 |
| | | // 比如使用一个UI组件来显示伤害数字 |
| | | foreach (var damage in damageValues) |
| | | { |
| | | Debug.Log($"Damage: {damage}"); |
| | | } |
| | | |
| | | BattleDmgInfo battleDmgInfo = new BattleDmgInfo(battleField.guid, damageValues, this, (int)attackType); |
| | | BattleDmgInfo battleDmgInfo = new BattleDmgInfo(battleField.guid, damageValues, this, hurt, skillConfig); |
| | | |
| | | // YYL TODO 是否需要挂在在自身的follow点上 |
| | | EventBroadcast.Instance.Broadcast(EventName.BATTLE_DAMAGE_TAKEN, battleDmgInfo); |
| | |
| | | HeroSkinConfig skinCfg = teamHero.skinConfig; |
| | | if (skinCfg == null) |
| | | { |
| | | BattleDebug.LogError(teamHero.heroId + "BattleObjectFactory.CreateBattleObject: skinCfg is null for " + teamHero.SkinID); |
| | | Debug.LogError(teamHero.heroId + "BattleObjectFactory.CreateBattleObject: skinCfg is null for " + teamHero.SkinID); |
| | | return null; |
| | | } |
| | | |
| | | GameObject battleGO = ResManager.Instance.LoadAsset<GameObject>("Hero/SpineRes", "Hero_001"/*skinCfg.SpineRes*/); |
| | | |
| | | if (battleGO == null) |
| | | { |
| | | BattleDebug.LogError("BattleObjectFactory.CreateBattleObject: battleGO is null for " + teamHero.heroId); |
| | | return null; |
| | | } |
| | | |
| | | BattleDebug.LogError("1 BattleObjectFactory.CreateBattleObject: Creating BattleObject for " + teamHero.ObjID + " at position " + teamHero.positionNum); |
| | | |
| | | GameObject goParent = posNodeList[teamHero.positionNum]; |
| | | BattleObject battleObject = new BattleObject(_battleField); |
| | |
| | | var skeletonDataAsset = ResManager.Instance.LoadAsset<SkeletonDataAsset>("Hero/SpineRes/", skinCfg.SpineRes); |
| | | if (skeletonDataAsset == null) |
| | | { |
| | | BattleDebug.LogError("BattleObjectFactory.CreateBattleObject: skeletonDataAsset is null for " + skinCfg.SpineRes); |
| | | Debug.LogError("BattleObjectFactory.CreateBattleObject: skeletonDataAsset is null for " + skinCfg.SpineRes); |
| | | return null; |
| | | } |
| | | |
| | | BattleDebug.LogError("2 BattleObjectFactory.CreateBattleObject: Creating BattleObject for " + teamHero.ObjID + " at position " + teamHero.positionNum); |
| | | |
| | | float finalScaleRate = modelScaleRate * teamHero.modelScale; |
| | | |
| | |
| | | rectTrans.anchoredPosition = Vector2.zero; |
| | | battleObject.Init(realGO, teamHero, _Camp); |
| | | |
| | | BattleDebug.LogError(realGO.name + " /3 BattleObjectFactory.CreateBattleObject: Creating BattleObject for " + teamHero.ObjID + " at position " + teamHero.positionNum); |
| | | |
| | | |
| | | return battleObject; |
| | | } |
| | | |
| | | public static void DestroyBattleObject(int key, BattleObject battleObj) |
| | | { |
| | | BattleDebug.LogError("BattleObject destroy"); |
| | | battleObj.Destroy(); |
| | | battleObj = null; |
| | | } |
| | |
| | | using UnityEngine.UI; |
| | | using DG.Tweening; |
| | | using DG.Tweening.Core; |
| | | |
| | | using System.Linq; |
| | | |
| | | public static class BattleUtility |
| | | { |
| | |
| | | var battleField = BattleManager.Instance.storyBattleField; |
| | | if (battleField == null) |
| | | { |
| | | BattleDebug.LogError("BattleManager.storyBattleField 未初始化!"); |
| | | Debug.LogError("BattleManager.storyBattleField 未初始化!"); |
| | | return; |
| | | } |
| | | |
| | |
| | | |
| | | public static string DisplayDamageNum(long num, int attackType) |
| | | { |
| | | // 服务器位数到客户端类型ID的映射 |
| | | Dictionary<int, int> serverToClientTypeMap = new Dictionary<int, int> |
| | | { |
| | | { 1, 2 }, // 普通伤血 |
| | | { 2, 4 }, // 恢复回血 |
| | | { 3, 8 }, // 反弹伤血 |
| | | { 4, 16 }, // 持续伤血 |
| | | { 5, 32 }, // 格挡 |
| | | { 7, 64 }, // 暴击伤害 |
| | | { 9, 128 }, // 闪避 |
| | | // 其它类型如需补充可继续添加 |
| | | }; |
| | | |
| | | int damageTypeValue = 0; |
| | | for (int i = 0; i < 32; i++) |
| | | { |
| | | int flag = 1 << i; |
| | | if ((attackType & flag) != 0) |
| | | { |
| | | // 只处理有映射的类型 |
| | | if (serverToClientTypeMap.TryGetValue(i + 1, out int clientTypeId)) |
| | | { |
| | | damageTypeValue += clientTypeId; |
| | | } |
| | | } |
| | | } |
| | | DamageType damageType = (DamageType)damageTypeValue; |
| | | |
| | | var config = DamageNumConfig.Get(damageTypeValue); |
| | | var basePowerStr = UIHelper.ReplaceLargeArtNum(num); |
| | | var result = string.Empty; |
| | | for (int i = 0; i < basePowerStr.Length; i++) |
| | | { |
| | | var numChar = (char)GetDamageNumKey((DamageType)attackType, basePowerStr[i]); |
| | | var numChar = (char)GetDamageNumKey(config, basePowerStr[i]); |
| | | if (numChar > 0) |
| | | { |
| | | result += numChar; |
| | |
| | | return result; |
| | | } |
| | | |
| | | public static int GetDamageNumKey(DamageType damageType, int _num) |
| | | public static int GetMainTargetPositionNum(BattleObject caster, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> targetList, SkillConfig skillConfig) |
| | | { |
| | | var config = DamageNumConfig.Get(damageType.ToString()); |
| | | //.的ASCII码是46 |
| | | if (_num == 46) |
| | | int returnIndex = 0; |
| | | // 根据敌方血量阵营 存活人数来选择 |
| | | BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp(); |
| | | List<BattleObject> targetObjList = caster.battleField.battleObjMgr.GetBattleObjList(battleCamp); |
| | | |
| | | |
| | | // 瞄准的目标范围,如果目标个数为0则为范围内全部 |
| | | // 0 全部范围 |
| | | // 1 对位,默认只选1个 |
| | | // 2 前排 |
| | | // 3 后排 |
| | | // 4 纵排,按对位规则选择纵排 |
| | | // 5 自己,默认只选自己 |
| | | // 6 继承主技能/来源技能目标 |
| | | // 一般是额外触发的技能使用,如概率附加某buff |
| | | // 额外触发的技能如果目标与主技能不一致,则重新设定目标即可 |
| | | // 或被动触发的技能,可继承触发来源技能的攻防双方关系 |
| | | |
| | | switch (skillConfig.TagAim) |
| | | { |
| | | return config.nums[10]; |
| | | case 0: |
| | | // 全部范围 |
| | | //全部范围+敌我+目标数量为6 |
| | | //就是取敌我站位中的2号位 |
| | | returnIndex = 1; |
| | | break; |
| | | case 1: |
| | | returnIndex = caster.teamHero.positionNum; |
| | | // 寻找对位是否有人 没有的话选择最小的 |
| | | List<BattleObject> opposite = new List<BattleObject>(from bo in targetObjList where !bo.IsDead() && bo.teamHero.positionNum == returnIndex select bo); |
| | | if (opposite.Count > 0) |
| | | { |
| | | returnIndex = opposite[0].teamHero.positionNum; |
| | | } |
| | | else |
| | | { |
| | | opposite = new List<BattleObject>(from bo in targetObjList where !bo.IsDead() select bo); |
| | | opposite.Sort((a, b) => a.teamHero.positionNum.CompareTo(b.teamHero.positionNum)); |
| | | returnIndex = opposite.Count > 0 ? opposite[0].teamHero.positionNum : returnIndex; |
| | | } |
| | | break; |
| | | case 2: |
| | | // 看看对面前排是否都活着 |
| | | List<BattleObject> front = new List<BattleObject>(from bo in targetObjList where !bo.IsDead() && bo.teamHero.positionNum < 3 select bo); |
| | | if (front.Count > 0) |
| | | { |
| | | returnIndex = 1; |
| | | } |
| | | else |
| | | { |
| | | returnIndex = 4; |
| | | } |
| | | break; |
| | | case 3: |
| | | // 看看对面后排是否都活着 |
| | | List<BattleObject> back = new List<BattleObject>(from bo in targetObjList where !bo.IsDead() && bo.teamHero.positionNum >= 3 select bo); |
| | | if (back.Count > 0) |
| | | { |
| | | returnIndex = 4; |
| | | } |
| | | else |
| | | { |
| | | returnIndex = 1; |
| | | } |
| | | break; |
| | | // 4 纵排,按对位规则选择纵排 |
| | | case 4: |
| | | List<BattleObject> vertical = new List<BattleObject>(from bo in targetObjList where !bo.IsDead() && (bo.teamHero.positionNum - caster.teamHero.positionNum) % 3 == 0 select bo); |
| | | // TODO YYL |
| | | break; |
| | | // 5 自己,默认只选自己 |
| | | case 5: |
| | | returnIndex = caster.teamHero.positionNum; |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | //k的ASCII码是107 |
| | | else if (_num == 107) |
| | | { |
| | | return config.nums[11]; |
| | | } |
| | | //m的ASCII码是109 |
| | | else if (_num == 109) |
| | | { |
| | | return config.nums[12]; |
| | | } |
| | | //b的ASCII码是98 |
| | | else if (_num == 98) |
| | | { |
| | | return config.nums[13]; |
| | | } |
| | | //t的ASCII码是116 |
| | | else if (_num == 116) |
| | | { |
| | | return config.nums[14]; |
| | | } |
| | | |
| | | return returnIndex; |
| | | } |
| | | |
| | | public static int GetDamageNumKey(DamageNumConfig config, int _num) |
| | | { |
| | | if (_num == 46) return config.nums[10]; // '.' |
| | | else if (_num == 107) return config.nums[11]; // 'k' |
| | | else if (_num == 109) return config.nums[12]; // 'm' |
| | | else if (_num == 98) return config.nums[13]; // 'b' |
| | | else if (_num == 116) return config.nums[14]; // 't' |
| | | return config.nums[_num - 48]; |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | using System.Collections.Generic; |
| | | |
| | | public class BattleDmg |
| | | { |
| | | public long damage; |
| | | public int attackType; |
| | | } |
| | | |
| | | public class BattleDmgInfo |
| | | { |
| | | |
| | | public string battleFieldGuid { get; private set; } |
| | | public List<long> damageList { get; private set; } |
| | | public int attackType { get; private set; } |
| | | public BattleObject hurtObj { get; private set; } |
| | | |
| | | public BattleDmgInfo(string battleFieldGuid, List<long> damageList, BattleObject hurtObj, int attackType) |
| | | public HB427_tagSCUseSkill.tagSCUseSkillHurt hurt { get; private set; } |
| | | |
| | | public SkillConfig skillConfig { get; private set; } |
| | | |
| | | // 是否被格挡了 |
| | | public bool isBlocked = false; |
| | | |
| | | public List<BattleDmg> battleDamageList = new List<BattleDmg>(); |
| | | |
| | | public BattleDmgInfo(string battleFieldGuid, List<long> damageList, BattleObject hurtObj, HB427_tagSCUseSkill.tagSCUseSkillHurt hurt, SkillConfig skillConfig) |
| | | { |
| | | this.battleFieldGuid = battleFieldGuid; |
| | | this.damageList = damageList; |
| | | this.hurtObj = hurtObj; |
| | | this.attackType = attackType; |
| | | this.hurt = hurt; |
| | | this.skillConfig = skillConfig; |
| | | HandleAttackTypeAndDamage(); |
| | | } |
| | | |
| | | private void HandleAttackTypeAndDamage() |
| | | { |
| | | isBlocked = HaveBlockDamage(); |
| | | int rawAttackType = (int)hurt.AttackTypes; |
| | | float blockRatio = float.Parse(GeneralDefine.parryCfg.Numerical3); // 格挡减伤率 |
| | | |
| | | for (int i = 0; i < damageList.Count; i++) |
| | | { |
| | | long actualDamage = damageList[i]; |
| | | |
| | | // 格挡处理 |
| | | if (isBlocked) |
| | | { |
| | | // 去掉格挡类型 |
| | | int attackType = rawAttackType & (~(int)DamageType.Block); |
| | | |
| | | // 计算格挡伤害 |
| | | long totalDamage = (long)(actualDamage / (1 - blockRatio)); |
| | | long blockDmg = totalDamage - actualDamage; |
| | | battleDamageList.Add(new BattleDmg { damage = blockDmg, attackType = (int)DamageType.Block }); |
| | | |
| | | // 真实伤害特殊处理 |
| | | if (IsRealdamage()) |
| | | { |
| | | int showAttackType = (int)DamageType.Realdamage + (IsCrit() ? (int)DamageType.Crit : 0); |
| | | battleDamageList.Add(new BattleDmg { damage = actualDamage, attackType = showAttackType }); |
| | | continue; |
| | | } |
| | | |
| | | // 普通伤害/治疗处理 |
| | | if (DamageNumConfig.Get(attackType) == null) |
| | | { |
| | | UnityEngine.Debug.LogError($"服务器给的伤害类型不对,强制转换为普通伤害/治疗, attackType: {attackType}"); |
| | | if ((attackType & (int)DamageType.Damage) != 0) |
| | | attackType = (int)DamageType.Damage; |
| | | else if ((attackType & (int)DamageType.Recovery) != 0) |
| | | attackType = (int)DamageType.Recovery; |
| | | else |
| | | UnityEngine.Debug.LogError($"强制转换失败,该类型不是治疗也不是伤害 {attackType}"); |
| | | } |
| | | battleDamageList.Add(new BattleDmg { damage = actualDamage, attackType = attackType }); |
| | | } |
| | | else |
| | | { |
| | | int attackType = rawAttackType; |
| | | |
| | | // 真实伤害特殊处理 |
| | | if (IsRealdamage()) |
| | | { |
| | | int showAttackType = (int)DamageType.Realdamage + (IsCrit() ? (int)DamageType.Crit : 0); |
| | | battleDamageList.Add(new BattleDmg { damage = actualDamage, attackType = showAttackType }); |
| | | continue; |
| | | } |
| | | |
| | | // 普通伤害/治疗处理 |
| | | if (DamageNumConfig.Get(attackType) == null) |
| | | { |
| | | UnityEngine.Debug.LogError($"服务器给的伤害类型不对,强制转换为普通伤害/治疗, attackType: {attackType}"); |
| | | if ((attackType & (int)DamageType.Damage) != 0) |
| | | attackType = (int)DamageType.Damage; |
| | | else if ((attackType & (int)DamageType.Recovery) != 0) |
| | | attackType = (int)DamageType.Recovery; |
| | | else |
| | | UnityEngine.Debug.LogError($"强制转换失败,该类型不是治疗也不是伤害 {attackType}"); |
| | | } |
| | | battleDamageList.Add(new BattleDmg { damage = actualDamage, attackType = attackType }); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public bool IsType(DamageType damageType) |
| | | { |
| | | return (hurt.AttackTypes & (int)damageType) == (int)damageType; |
| | | } |
| | | |
| | | public bool IsCrit() |
| | | { |
| | | return IsType(DamageType.Crit); |
| | | } |
| | | |
| | | public bool HaveBlockDamage() |
| | | { |
| | | return IsType(DamageType.Block); |
| | | } |
| | | |
| | | public bool IsRealdamage() |
| | | { |
| | | return skillConfig.HurtType / 10 == 1; |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | public enum DamageType |
| | | { |
| | | Damage, //普通伤害 |
| | | Recovery, //治疗 |
| | | Reflect, //反弹伤害 |
| | | Bloody, //流血伤害 |
| | | Block, //格挡 |
| | | Critical, //暴击 |
| | | Dodge, //闪避 |
| | | Combo, //连击 |
| | | CounterAttack, //反击 |
| | | RageUp, //怒气提升 |
| | | Damage = 1, //普通伤害 |
| | | |
| | | |
| | | } |
| | | Recovery = 2, //治疗 |
| | | |
| | | Reflect = 4, //反弹伤害 |
| | | |
| | | Bloody = 8, //流血伤害 |
| | | |
| | | Block = 16, //格挡 |
| | | |
| | | Crit = 32, //暴击 |
| | | |
| | | Dodge = 64, //闪避 |
| | | |
| | | RageUp = 128, //怒气提升 |
| | | |
| | | SuckHP = 256, //吸血 |
| | | |
| | | Realdamage = 512, //真伤 |
| | | |
| | | CritDamage = Crit + Damage, //暴击伤害 |
| | | |
| | | CritHeal = Crit + Recovery, //暴击回血 |
| | | |
| | | CritRealdamage = Crit + Realdamage, //暴击真伤 |
| | | } |
| | | |
| | |
| | | |
| | | public static List<string> AttackMotionList = new List<string> |
| | | { |
| | | MotionName.attack.ToString(), |
| | | MotionName.angerSkill.ToString(), |
| | | MotionName.passiveSkill.ToString(), |
| | | MotionName.attack.ToString().ToLower(), |
| | | MotionName.angerSkill.ToString().ToLower(), |
| | | MotionName.passiveSkill.ToString().ToLower(), |
| | | }; |
| | | |
| | | private Dictionary<Spine.TrackEntry, Action> trackEntryCompleteDict = new Dictionary<Spine.TrackEntry, Action>(); |
| | |
| | | // 动画事件 |
| | | public Action OnAttackAnimationComplete; |
| | | public Action OnHitAnimationComplete; |
| | | public Action<MotionName> onAnimationComplete; |
| | | public Action<string> onAnimationComplete; |
| | | |
| | | #region 组件引用 |
| | | |
| | |
| | | return null; |
| | | } |
| | | |
| | | // 获取动画 |
| | | |
| | | Spine.Animation anim = skeleton.Data.FindAnimation(skillConfig.SkillMotionName); |
| | | |
| | | if (null == anim) |
| | | { |
| | | for (int i = 0; i < skeleton.Data.Animations.Count; i++) |
| | | { |
| | | var skeletonAnim = skeleton.Data.Animations.Items[i]; |
| | | if (skeletonAnim.Name.ToLower() == skillConfig.SkillMotionName.ToLower()) |
| | | { |
| | | anim = skeletonAnim; |
| | | // 找到动画 |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 获取动画 |
| | | if (anim == null) |
| | | { |
| | | BattleDebug.LogError($"找不到动画: {skillConfig.SkillMotionName}"); |
| | |
| | | /// </summary> |
| | | protected virtual void OnAnimationComplete(Spine.TrackEntry trackEntry) |
| | | { |
| | | string animation = trackEntry.Animation.Name; |
| | | string animation = trackEntry.Animation.Name.ToLower(); |
| | | |
| | | // 攻击动画完成后恢复到待机状态 |
| | | if (AttackMotionList.Contains(animation)) |
| | |
| | | PlayAnimation(MotionName.idle, true); |
| | | } |
| | | // 受伤动画完成后恢复到待机状态 可能触发多次 因为有多段攻击的存在 |
| | | else if (animation == MotionName.hit.ToString()) |
| | | else if (animation == MotionName.hit.ToString().ToLower()) |
| | | { |
| | | OnHitAnimationComplete?.Invoke(); |
| | | PlayAnimation(MotionName.idle, true); |
| | | } |
| | | onAnimationComplete?.Invoke((MotionName)Enum.Parse(typeof(MotionName), animation)); |
| | | |
| | | onAnimationComplete?.Invoke(animation); |
| | | |
| | | // 只调用本次TrackEntry的回调 |
| | | if (trackEntryCompleteDict.TryGetValue(trackEntry, out var cb)) |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | 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() |
| | |
| | | private Queue<RecordAction> recordActionQueue = new Queue<RecordAction>(); |
| | | protected RecordAction currentRecordAction; |
| | | |
| | | protected List<RecordAction> immediatelyActionList = new List<RecordAction>(); |
| | | |
| | | private bool isWaitingNextAction = false; |
| | | private float waitTimer = 0f; |
| | | private const float waitInterval = 0.2f; |
| | |
| | | |
| | | public bool IsPlaying() |
| | | { |
| | | return currentRecordAction != null || recordActionQueue.Count > 0; |
| | | return currentRecordAction != null || recordActionQueue.Count > 0 || immediatelyActionList.Count > 0; |
| | | } |
| | | |
| | | public void PlayRecord(RecordAction recordAction) |
| | |
| | | } |
| | | } |
| | | |
| | | public void InsertRecord(RecordAction recordAction) |
| | | { |
| | | BattleDebug.LogError("Insert record action " + recordAction.GetType()); |
| | | if (currentRecordAction != null) |
| | | { |
| | | Queue<RecordAction> tempQueue = new Queue<RecordAction>(); |
| | | tempQueue.Enqueue(recordAction); |
| | | while (recordActionQueue.Count > 0) |
| | | { |
| | | tempQueue.Enqueue(recordActionQueue.Dequeue()); |
| | | } |
| | | recordActionQueue = tempQueue; |
| | | } |
| | | else |
| | | { |
| | | recordActionQueue.Enqueue(recordAction); |
| | | } |
| | | } |
| | | |
| | | public void ImmediatelyPlay(RecordAction recordAction) |
| | | { |
| | | immediatelyActionList.Add(recordAction); |
| | | } |
| | | |
| | | protected void ImmediatelyPlayRun() |
| | | { |
| | | if (immediatelyActionList.Count > 0) |
| | | { |
| | | List<int> removeIndexList = new List<int>(); |
| | | |
| | | for (int i = immediatelyActionList.Count - 1; i >= 0; i--) |
| | | { |
| | | var action = immediatelyActionList[i]; |
| | | if (action.IsFinished()) |
| | | { |
| | | removeIndexList.Add(i); |
| | | } |
| | | else |
| | | { |
| | | action.Run(); |
| | | } |
| | | } |
| | | |
| | | for (int i = removeIndexList.Count - 1; i >= 0; i--) |
| | | { |
| | | immediatelyActionList.RemoveAt(removeIndexList[i]); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public virtual void Run() |
| | | { |
| | | ImmediatelyPlayRun(); |
| | | |
| | | // 等待下一个action |
| | | if (isWaitingNextAction) |
| | | { |
| | |
| | | HB427_tagSCUseSkill _vNetData, List<GameNetPackBasic> _packList, BattleField _battleField) |
| | | : base(_caster, _skillCfg, _vNetData, _packList, _battleField) |
| | | { |
| | | foreach (var pack in packList) |
| | | { |
| | | BattleDebug.LogError("directly damage skill pack type is " + pack.GetType()); |
| | | } |
| | | |
| | | } |
| | | |
| | | protected override void OnHitTargets(int _hitIndex, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hitList) |
| | |
| | | HB427_tagSCUseSkill _vNetData, List<GameNetPackBasic> _packList, BattleField _battleField) |
| | | : base(_caster, _skillCfg, _vNetData, _packList, _battleField) |
| | | { |
| | | foreach (var pack in packList) |
| | | { |
| | | BattleDebug.LogError("directly heal skill pack type is " + pack.GetType()); |
| | | } |
| | | |
| | | } |
| | | |
| | | public override void Run() |
| | |
| | | |
| | | protected List<HB405_tagMCAddExp> expPackList = new List<HB405_tagMCAddExp>(); |
| | | |
| | | protected bool moveFinished = false; |
| | | |
| | | public SkillBase(BattleObject _caster, SkillConfig _skillCfg, HB427_tagSCUseSkill vNetData, List<GameNetPackBasic> _packList, BattleField _battleField = null) |
| | | { |
| | | caster = _caster; |
| | |
| | | tagUseSkillAttack = vNetData; |
| | | battleField = _battleField; |
| | | packList = _packList; |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | |
| | | { |
| | | EventBroadcast.Instance.Broadcast<string, SkillConfig, TeamHero>(EventName.BATTLE_CAST_SKILL, battleField.guid, skillConfig, caster.teamHero); |
| | | |
| | | BattleDebug.LogError(GetType().Name + " Skill Cast Start"); |
| | | // 高亮所有本次技能相关的目标 |
| | | HighLightAllTargets(); |
| | | |
| | | // 距离配成负数要转身 TurnBack |
| | | BattleDebug.LogError(GetType().Name + " Skill CastMode : " + skillConfig.castMode); |
| | | switch (skillConfig.castMode) |
| | | { |
| | | case SkillCastMode.Self: |
| | |
| | | // DashToTarget(() => BackToOrigin(OnSkillFinished)); |
| | | // break; |
| | | default: |
| | | BattleDebug.LogError("暂时不支持其他的方式释放 有需求请联系策划 技能id:" + skillConfig.SkillID + " cast position " + skillConfig.CastPosition); |
| | | Debug.LogError("暂时不支持其他的方式释放 有需求请联系策划 技能id:" + skillConfig.SkillID + " cast position " + skillConfig.CastPosition); |
| | | OnSkillFinished(); |
| | | break; |
| | | } |
| | | |
| | | } |
| | | |
| | | protected void MoveToTarget(RectTransform target, Vector2 offset, float duration, Action onComplete = null) |
| | | { |
| | | BattleDebug.LogError("Move to target , target is " + target.name); |
| | | // 原地释放 |
| | | if (skillConfig.CastDistance >= 9999) |
| | | { |
| | |
| | | // 目标是敌方主目标 |
| | | if (tagUseSkillAttack.HurtCount <= 0) |
| | | { |
| | | BattleDebug.LogError("技能攻击包没有目标 HurtCount <= 0"); |
| | | Debug.LogError("技能攻击包没有目标 HurtCount <= 0"); |
| | | OnSkillFinished(); |
| | | return; |
| | | } |
| | |
| | | BattleObject mainTarget = battleField.battleObjMgr.GetBattleObject((int)mainHurt.ObjID); |
| | | if (mainTarget == null) |
| | | { |
| | | BattleDebug.LogError("目标为空 mainTarget == null ObjID : " + mainHurt.ObjID); |
| | | Debug.LogError("目标为空 mainTarget == null ObjID : " + mainHurt.ObjID); |
| | | OnSkillFinished(); |
| | | return; |
| | | } |
| | |
| | | |
| | | protected virtual void OnAllAttackMoveFinished() |
| | | { |
| | | |
| | | moveFinished = true; |
| | | } |
| | | |
| | | protected void CastToAllies() |
| | |
| | | } |
| | | |
| | | // 技能开始 |
| | | public virtual void OnSkillStart() |
| | | public void OnSkillStart() |
| | | { |
| | | skillEffect = SkillEffectFactory.CreateSkillEffect( |
| | | caster, |
| | |
| | | { |
| | | skillEffect.Play(OnHitTargets); |
| | | } |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | // 技能前摇帧结束 |
| | |
| | | /// <param name="times"></param> |
| | | public virtual void OnMiddleFrameStart(int times) |
| | | { |
| | | skillEffect.OnMiddleFrameStart(times); |
| | | if (skillEffect != null) |
| | | { |
| | | skillEffect.OnMiddleFrameStart(times); |
| | | } |
| | | } |
| | | |
| | | public virtual void OnMiddleFrameEnd(int times, int hitIndex) |
| | | { |
| | | skillEffect.OnMiddleFrameEnd(times, hitIndex); |
| | | if (skillEffect != null) |
| | | { |
| | | skillEffect.OnMiddleFrameEnd(times, hitIndex); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID); |
| | | if (target == null) |
| | | { |
| | | BattleDebug.LogError("目标为空 target == null ObjId : " + hurt.ObjID); |
| | | Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID); |
| | | continue; |
| | | } |
| | | |
| | | OnHitEachTarget(_hitIndex, target, hurt); |
| | | } |
| | | |
| | | HandleDead(); |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | // TODO YYL AttackTypes 要表现成什么样呢? 支持多种类型并存,如无视防御且暴击同时被格挡,二进制或运算最终值;0-失败;1-普通;2-回血;5-格挡;6-无视防御;7-暴击;9-闪避 |
| | | target.Hurt(damageList, totalDamage, hurt.AttackTypes); |
| | | target.Hurt(damageList, totalDamage, hurt, skillConfig); |
| | | |
| | | // TODO YYL 这里是要做统一计算后再hurt跟suckhp还是怎样 |
| | | // caster.SuckHp(hurt.SuckHP);// 吸血 |
| | | // caster.HurtByReflect(hurt.BounceHP);// 反弹伤害 |
| | | caster.SuckHp(hurt.SuckHP, skillConfig);// 吸血 |
| | | caster.HurtByReflect(hurt.BounceHP, skillConfig);// 反弹伤害 |
| | | } |
| | | |
| | | |
| | |
| | | // 处理掉落包 提前distribute之后 PackManager才有掉落物 所以不跟assignexp一样distribute |
| | | foreach (var _dropPack in dropPackList) |
| | | { |
| | | BattleDebug.LogError("distribute pack " + _dropPack.GetType().Name); |
| | | PackageRegedit.Distribute(_dropPack); |
| | | packList.Remove(_dropPack); |
| | | } |
| | |
| | | packList.Remove(deadPack); |
| | | } |
| | | deadPackList.Clear(); |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | return isFinished; |
| | | return isFinished && moveFinished; |
| | | } |
| | | |
| | | public virtual void ForceFinished() |
| | |
| | | } |
| | | } |
| | | |
| | | BattleDebug.LogError(GetType().Name + " Skill Finished"); |
| | | while (packList.Count > 0) |
| | | { |
| | | var pack = packList[0]; |
| | |
| | | var combinePack = pack as CustomHB426CombinePack; |
| | | if (combinePack.startTag.Tag.StartsWith("Skill_")) |
| | | { |
| | | BattleDebug.LogError("other skill casting " + combinePack.startTag.Tag); |
| | | otherSkillAction = combinePack.CreateSkillAction(); |
| | | return; |
| | | } |
| | | } |
| | | BattleDebug.LogError("distribute pack " + pack.GetType().Name); |
| | | PackageRegedit.Distribute(pack); |
| | | } |
| | | |
| | |
| | | return null; |
| | | } |
| | | |
| | | Debug.LogError("skill type is " + skillConfig.SkillType + " skill id is " + vNetData.SkillID); |
| | | |
| | | |
| | | SkillBase skill = null; |
| | | switch (skillConfig.SkillType) |
| | | { |
| | |
| | | } |
| | | else |
| | | { |
| | | BattleDebug.LogError("弹射找不到下一个目标"); |
| | | Debug.LogError("弹射找不到下一个目标"); |
| | | // 如果目标丢失,直接用上一个end |
| | | end = start; |
| | | } |
| | |
| | | public StraightBulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer bulletEffect, RectTransform target, HB427_tagSCUseSkill tagUseSkillAttack, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit) |
| | | : base(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit) |
| | | { |
| | | BattleDebug.LogError("StraightBulletCurve created bulletTrans is null = " + (bulletTrans == null).ToString()); |
| | | |
| | | } |
| | | |
| | | public override void Reset() |
| | |
| | | |
| | | if (bulletTrans == null) |
| | | { |
| | | BattleDebug.LogError("BulletTrans is null, cannot run StraightBulletCurve"); |
| | | return; |
| | | Debug.LogError("BulletTrans is null, cannot run StraightBulletCurve"); |
| | | } |
| | | |
| | | elapsed += Time.deltaTime; |
| | | float t = Mathf.Clamp01(elapsed / duration); |
| | | Vector2 pos = Vector2.Lerp(start, end, t); |
| | | bulletTrans.anchoredPosition = pos; |
| | | if (null != bulletTrans) |
| | | { |
| | | bulletTrans.anchoredPosition = pos; |
| | | } |
| | | |
| | | Vector2 dir = end - start; |
| | | float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg; |
| | | bulletTrans.localRotation = Quaternion.Euler(0, bulletTrans.transform.localScale.x < 0f ? 180 : 0, angle); |
| | | if (null != bulletTrans) |
| | | { |
| | | bulletTrans.localRotation = Quaternion.Euler(0, bulletTrans.transform.localScale.x < 0f ? 180 : 0, angle); |
| | | } |
| | | // if (bulletTrans.transform.localScale.x < 0f) |
| | | // { |
| | | // bulletTrans.transform.localRotation *= Quaternion.Euler(0, 180, 0); |
| | |
| | | BattleObject targetObject = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID); |
| | | if (targetObject == null) |
| | | { |
| | | BattleDebug.LogError("目标为空 target == null ObjId : " + hurt.ObjID); |
| | | Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID); |
| | | return; |
| | | } |
| | | ShotToTarget(targetObject); |
| | |
| | | // 普通的做法 区分打向阵营或者打向个体 |
| | | else |
| | | { |
| | | Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHitFormation = (_hitIndex, _hurtList) => |
| | | { |
| | | onHit?.Invoke(_hitIndex, tagUseSkillAttack.HurtList.ToList()); |
| | | }; |
| | | switch (skillConfig.castMode) |
| | | { |
| | | case SkillCastMode.Self: |
| | | onHitFormation?.Invoke(0, tagUseSkillAttack.HurtList.ToList()); |
| | | BattleDebug.LogError("子弹的目标是自己,暂时不支持 协商程序完成"); |
| | | break; |
| | | case SkillCastMode.Enemy: |
| | | var targetNode = caster.battleField.GetTeamNode(caster.GetEnemyCamp(), skillConfig); |
| | | 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) |
| | | { |
| | | BattleDebug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID); |
| | | continue; |
| | | } |
| | | // 区分散射跟范围攻击 |
| | | |
| | | ShotToTarget(target); |
| | | if (skillConfig.Scattering == 1) |
| | | { |
| | | // 散射 |
| | | 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; |
| | | } |
| | | break; |
| | | case SkillCastMode.Allies: |
| | | var healNode = caster.battleField.GetTeamNode(caster.Camp, skillConfig); |
| | | ShotToFormation(healNode, onHitFormation); |
| | | break; |
| | | default: |
| | | BattleDebug.LogError("暂时不支持其他的方式释放 有需求请联系程序 " + skillConfig.SkillID); |
| | | break; |
| | | |
| | | ShotToTarget(target); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // 范围攻击 |
| | | // 攻击向关键位置 然后所有人受伤 |
| | | int mainTargetIndex = BattleUtility.GetMainTargetPositionNum(caster, tagUseSkillAttack.HurtList.ToList(), skillConfig); |
| | | |
| | | BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp(); |
| | | |
| | | RectTransform rectTarget = caster.battleField.GetTeamNode(battleCamp, mainTargetIndex); |
| | | |
| | | Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHitFormation = (_hitIndex, _hurtList) => |
| | | { |
| | | onHit?.Invoke(_hitIndex, tagUseSkillAttack.HurtList.ToList()); |
| | | }; |
| | | |
| | | if (skillConfig.TagCount >= 6) |
| | | { |
| | | ShotToFormation(rectTarget, onHitFormation); |
| | | } |
| | | else |
| | | { |
| | | ShotToFormationEx(rectTarget, onHitFormation); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void ShotToFormationEx(RectTransform target, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> _onHit) |
| | | { |
| | | BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.BulletEffectId, caster.heroRectTrans, caster.Camp); |
| | | |
| | | RectTransform effectTrans = effectPlayer.transform as RectTransform; |
| | | |
| | | var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, effectPlayer, target, tagUseSkillAttack, (index, hitList) => |
| | | { |
| | | // 击中就销毁子弹 |
| | | caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer); |
| | | // 播放子弹爆炸特效 |
| | | |
| | | BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp(); |
| | | |
| | | 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; |
| | | } |
| | | |
| | | PlayExplosionEffect(skillConfig.ExplosionEffectId, targetObj.heroGo.transform, targetObj.Camp); |
| | | PlayExplosionEffect(skillConfig.ExplosionEffect2, targetObj.heroGo.transform, targetObj.Camp); |
| | | PlayExplosionEffect(skillConfig.ExplosionEffect3, targetObj.heroGo.transform, targetObj.Camp); |
| | | } |
| | | |
| | | // 表现子弹飞行到目标位置 |
| | | _onHit?.Invoke(index, hitList); |
| | | isFinish = true; |
| | | }); |
| | | |
| | | bulletCurves.Add(bulletCurve); |
| | | } |
| | | |
| | | protected void ShotToFormation(RectTransform target, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> _onHit) |
| | |
| | | |
| | | var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, effectPlayer, target, tagUseSkillAttack, (index, hitList) => |
| | | { |
| | | // 表现子弹飞行到目标位置 |
| | | _onHit?.Invoke(index, hitList); |
| | | |
| | | // 击中就销毁子弹 |
| | | caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer); |
| | | // 播放子弹爆炸特效 |
| | | |
| | | BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp(); |
| | | // 首先是目标身上爆炸 |
| | | PlayExplosionEffect(skillConfig.ExplosionEffectId, target, battleCamp); |
| | | PlayExplosionEffect(skillConfig.ExplosionEffect2, target, battleCamp); |
| | | |
| | | foreach (var hurt in hitList) |
| | | { |
| | | BattleObject targetObj = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID); |
| | | if (targetObj == null) |
| | | { |
| | | BattleDebug.LogError("目标为空 target == null ObjId : " + hurt.ObjID); |
| | | Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID); |
| | | continue; |
| | | } |
| | | |
| | | var effect1 = caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffectId, targetObj.heroGo.transform, targetObj.Camp); |
| | | var effect2 = caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffect2, targetObj.heroGo.transform, targetObj.Camp); |
| | | if (effect1 != null) |
| | | { |
| | | effect1.transform.localRotation = effectTrans.localRotation; |
| | | } |
| | | if (effect2 != null) |
| | | { |
| | | effect2.transform.localRotation = effectTrans.localRotation; |
| | | } |
| | | PlayExplosionEffect(skillConfig.ExplosionEffectId, targetObj.heroGo.transform, targetObj.Camp); |
| | | } |
| | | |
| | | // 表现子弹飞行到目标位置 |
| | | _onHit?.Invoke(index, hitList); |
| | | |
| | | isFinish = true; |
| | | }); |
| | | |
| | | bulletCurves.Add(bulletCurve); |
| | |
| | | |
| | | protected void ShotToTarget(BattleObject target) |
| | | { |
| | | BattleDebug.LogError("发射子弹 " + skillConfig.BulletEffectId); |
| | | BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.BulletEffectId, caster.heroRectTrans, caster.Camp); |
| | | |
| | | |
| | | var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, effectPlayer, target.heroRectTrans, tagUseSkillAttack, (index, hitList) => |
| | | { |
| | | // 表现子弹飞行到目标位置 |
| | | onHit?.Invoke(index, hitList); |
| | | |
| | | |
| | | BattleDebug.LogError("回收子弹 " + skillConfig.BulletEffectId); |
| | | // 播放子弹爆炸特效 |
| | | |
| | | |
| | | foreach (var hurt in hitList) |
| | | { |
| | | BattleObject targetObj = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID); |
| | | if (targetObj == null) |
| | | { |
| | | BattleDebug.LogError("目标为空 target == null ObjId : " + hurt.ObjID); |
| | | Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID); |
| | | continue; |
| | | } |
| | | |
| | | if (skillConfig.ExplosionEffectId > 0) |
| | | { |
| | | var eft = caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffectId, targetObj.heroGo.transform, targetObj.Camp); |
| | | eft.transform.localRotation = effectPlayer.transform.localRotation; |
| | | if (eft.transform.localScale.x < 0f) |
| | | { |
| | | eft.transform.localRotation *= Quaternion.Euler(0, 180, 0); |
| | | } |
| | | } |
| | | |
| | | if (skillConfig.ExplosionEffect2 > 0) |
| | | { |
| | | var eft = caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffect2, targetObj.heroGo.transform, targetObj.Camp); |
| | | eft.transform.localRotation = effectPlayer.transform.localRotation; |
| | | if (eft.transform.localScale.x < 0f) |
| | | { |
| | | eft.transform.localRotation *= Quaternion.Euler(0, 180, 0); |
| | | } |
| | | } |
| | | PlayExplosionEffect(skillConfig.ExplosionEffectId, targetObj.heroGo.transform, targetObj.Camp); |
| | | PlayExplosionEffect(skillConfig.ExplosionEffect2, targetObj.heroGo.transform, targetObj.Camp); |
| | | PlayExplosionEffect(skillConfig.ExplosionEffect3, targetObj.heroGo.transform, targetObj.Camp); |
| | | } |
| | | |
| | | // 表现子弹飞行到目标位置 |
| | | onHit?.Invoke(index, hitList); |
| | | // 击中就销毁子弹 |
| | | caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer); |
| | | |
| | | // 播放子弹爆炸特效 |
| | | isFinish = true; |
| | | }); |
| | | |
| | | bulletCurves.Add(bulletCurve); |
| | | } |
| | | |
| | | protected void PlayExplosionEffect(int effectId, Transform parent, BattleCamp camp) |
| | | { |
| | | if (effectId <= 0) |
| | | return; |
| | | |
| | | var effect = caster.battleField.battleEffectMgr.PlayEffect(0, effectId, parent, camp); |
| | | if (effect != null) |
| | | { |
| | | effect.transform.localRotation = parent.localRotation; |
| | | if (effect.transform.localScale.x < 0f) |
| | | { |
| | | effect.transform.localRotation *= Quaternion.Euler(0, 180, 0); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public override void Run() |
| | |
| | | |
| | | public override void OnMiddleFrameEnd(int times, int hitIndex) |
| | | { |
| | | BattleDebug.LogError($" NormalSkillEffect OnMiddleFrameEnd times : {times}, hitIndex : {hitIndex}"); |
| | | for (int i = 0; i < tagUseSkillAttack.HurtList.Length; i++) |
| | | { |
| | | var hurt = tagUseSkillAttack.HurtList[i]; |
| | | BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID); |
| | | if (target == null) |
| | | { |
| | | BattleDebug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID); |
| | | Debug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID); |
| | | continue; |
| | | } |
| | | |
| | | caster.battleField.battleEffectMgr.PlayEffect(target.ObjID, skillConfig.ExplosionEffectId, target.heroGo.transform, target.Camp); |
| | | caster.battleField.battleEffectMgr.PlayEffect(target.ObjID, skillConfig.ExplosionEffect2, target.heroGo.transform, target.Camp); |
| | | if (skillConfig.ExplosionEffectId > 0) |
| | | { |
| | | caster.battleField.battleEffectMgr.PlayEffect(target.ObjID, skillConfig.ExplosionEffectId, target.heroGo.transform, target.Camp); |
| | | } |
| | | |
| | | if (skillConfig.ExplosionEffect2 > 0) |
| | | { |
| | | caster.battleField.battleEffectMgr.PlayEffect(target.ObjID, skillConfig.ExplosionEffect2, target.heroGo.transform, target.Camp); |
| | | } |
| | | |
| | | if (skillConfig.ExplosionEffect3 > 0) |
| | | { |
| | | caster.battleField.battleEffectMgr.PlayEffect(target.ObjID, skillConfig.ExplosionEffect3, target.heroGo.transform, target.Camp); |
| | | } |
| | | } |
| | | |
| | | onHit?.Invoke(hitIndex, tagUseSkillAttack.HurtList.ToList()); |
| | |
| | | { |
| | | if (sourceRect == null || targetRect == null) |
| | | { |
| | | BattleDebug.LogError("请在Inspector中指定sourceRect和targetRect!"); |
| | | Debug.LogError("请在Inspector中指定sourceRect和targetRect!"); |
| | | return; |
| | | } |
| | | |
| | |
| | | { |
| | | OnFinish?.Invoke(); |
| | | OnFinish = null; |
| | | gameObject.SetActive(false); |
| | | return; |
| | | } |
| | | |
| | |
| | | using System.Collections.Generic; |
| | | using UnityEngine; |
| | | using System; |
| | | using Cysharp.Threading.Tasks; |
| | | |
| | | public class DamageContent : MonoBehaviour |
| | | { |
| | |
| | | |
| | | public PositionTween posTween; |
| | | |
| | | public ScaleTween scaleTween; |
| | | |
| | | private BattleDmgInfo battleDmgInfo; |
| | | |
| | | void Awake() |
| | | { |
| | | line.SetActive(false); |
| | | } |
| | | |
| | | public void SetDamage(BattleDmgInfo damageInfo, Action _onComplete) |
| | | public async void SetDamage(BattleDmgInfo _damageInfo, Action _onComplete) |
| | | { |
| | | var damages = damageInfo.damageList; |
| | | battleDmgInfo = _damageInfo; |
| | | |
| | | var damages = battleDmgInfo.battleDamageList; |
| | | |
| | | for (int i = damages.Count; i < damageLineList.Count; i++) |
| | | { |
| | | damageLineList[i].SetActive(false); |
| | | } |
| | | |
| | | posTween.Play(_onComplete); |
| | | |
| | | if (battleDmgInfo.IsCrit()) |
| | | { |
| | | scaleTween.Play(); |
| | | } |
| | | |
| | | for (int i = 0; i < damages.Count; i++) |
| | | { |
| | | if (i >= damageLineList.Count) |
| | |
| | | damageLineList.Add(newLine.GetComponent<DamageLine>()); |
| | | } |
| | | damageLineList[i].SetActive(true); |
| | | damageLineList[i].SetDamage(damageInfo.attackType, damages[i]); |
| | | damageLineList[i].SetDamage(damages[i]); |
| | | await UniTask.Delay(100); |
| | | } |
| | | |
| | | for (int i = damages.Count; i < damageLineList.Count; i++) |
| | | { |
| | | damageLineList[i].SetActive(false); |
| | | } |
| | | |
| | | posTween.Play(_onComplete); |
| | | } |
| | | |
| | | public void Stop() |
| | | { |
| | | posTween.Stop(); |
| | | if (battleDmgInfo.IsCrit()) |
| | | { |
| | | scaleTween.Stop(); |
| | | } |
| | | } |
| | | |
| | | public void Resume() |
| | | { |
| | | posTween.Resume(); |
| | | if (battleDmgInfo.IsCrit()) |
| | | { |
| | | scaleTween.Resume(); |
| | | } |
| | | } |
| | | } |
| | |
| | | public class DamageLine : MonoBehaviour |
| | | { |
| | | |
| | | public TextEx damageTypeLabel; |
| | | public TextEx damageTypeLabel; |
| | | |
| | | public TextEx damageValueLabel; |
| | | public TextEx damageValueLabel; |
| | | |
| | | public void SetDamage(int damageType, long damage) |
| | | { |
| | | damageTypeLabel.SetActive(false); |
| | | damageTypeLabel.SetActive(false); |
| | | damageValueLabel.text = BattleUtility.DisplayDamageNum(damage, damageType); |
| | | } |
| | | |
| | | public void SetDamage(long damage) |
| | | { |
| | | damageTypeLabel.SetActive(false); |
| | | damageValueLabel.text = damage.ToString(); |
| | | damageTypeLabel.SetActive(false); |
| | | damageValueLabel.text = damage.ToString(); |
| | | } |
| | | |
| | | public void SetDamage(BattleDmg damage) |
| | | { |
| | | damageTypeLabel.SetActive(false); |
| | | damageValueLabel.text = BattleUtility.DisplayDamageNum(damage.damage, damage.attackType); |
| | | } |
| | | } |
| | |
| | | public static int acutionItemHour { get; private set; } |
| | | public static int maxXBGridCount { get; private set; } |
| | | |
| | | public static FuncConfigConfig parryCfg; |
| | | |
| | | public static void Init() |
| | | { |
| | |
| | | // flashOpenArr = JsonMapper.ToObject<int[]>(func.Numerical2); |
| | | // flashCntMoreArr = JsonMapper.ToObject<int[]>(func.Numerical3); |
| | | // flashKillMaxCount = int.Parse(func.Numerical4); |
| | | |
| | | parryCfg = FuncConfigConfig.Get("ParryCfg"); |
| | | } |
| | | catch (Exception ex) |
| | | { |