| | |
| | | |
| | | protected GameObject spineContainer; |
| | | |
| | | protected SkeletonGraphic spineComp; |
| | | protected SkeletonAnimation spineComp; |
| | | protected Spine.AnimationState spineAnimationState; |
| | | |
| | | public GameObjectPoolManager.GameObjectPool pool; |
| | |
| | | } |
| | | |
| | | // 初始化spine组件 |
| | | if (effectConfig != null && effectConfig.isSpine != 1) |
| | | if (effectConfig != null && effectConfig.isSpine != 0) |
| | | { |
| | | GameObject spineContainerPrefab = ResManager.Instance.LoadAsset<GameObject>("UIComp", "SpineContainer"); |
| | | spineContainer = GameObject.Instantiate(spineContainerPrefab, transform); |
| | | GameObject spineContainerPrefab = ResManager.Instance.LoadAsset<GameObject>("UIComp", "SpineAnimContainer"); |
| | | spineContainer = GameObject.Instantiate(spineContainerPrefab, transform, true); |
| | | spineContainer.transform.localPosition = Vector3.zero; |
| | | } |
| | | // 有特效可能带spine又带unity特效的情况 |
| | | spineComp = gameObject.GetComponentInChildren<SkeletonGraphic>(true); |
| | | spineComp = gameObject.GetComponentInChildren<SkeletonAnimation>(true); |
| | | } |
| | | |
| | | protected virtual void Clear() |
| | |
| | | |
| | | public virtual void Play(bool showLog = true) |
| | | { |
| | | |
| | | |
| | | if (!isInit) |
| | | { |
| | | InitComponent(showLog); |
| | | isInit = true; |
| | | } |
| | | else |
| | | { |
| | | //避免重复创建 |
| | | if (!this.gameObject.activeSelf) |
| | | { |
| | | this.gameObject.SetActive(true); |
| | | InitComponent(showLog); |
| | | isInit = true; |
| | | } |
| | | return; |
| | | } |
| | | else |
| | | { |
| | | //避免重复创建 |
| | | if (!this.gameObject.activeSelf) |
| | | { |
| | | this.gameObject.SetActive(true); |
| | | } |
| | | return; |
| | | } |
| | | |
| | | if (EffectMgr.IsNotShowBySetting(effectId)) |
| | | { |
| | |
| | | return; |
| | | } |
| | | |
| | | // 如果delay小于等于0 那会立刻执行 |
| | | this.DelayTime(effectConfig.delayPlay, () => |
| | | { |
| | | PlayEffectInternal(); |
| | | }); |
| | | } |
| | | |
| | | protected void PlayEffectInternal() |
| | | { |
| | | if (effectConfig.isSpine != 0) |
| | | { |
| | | PlaySpineEffect(); |
| | |
| | | { |
| | | PlayUnityEffect(); |
| | | } |
| | | |
| | | } |
| | | |
| | | protected void PlaySpineEffect() |
| | |
| | | return; |
| | | } |
| | | |
| | | SkeletonDataAsset skeletonDataAsset = ResManager.Instance.LoadAsset<SkeletonDataAsset>("UIEffect/BattleSpine/" + effectConfig.packageName, effectConfig.fxName); |
| | | SkeletonDataAsset skeletonDataAsset = ResManager.Instance.LoadAsset<SkeletonDataAsset>("UIEffect/" + effectConfig.packageName, effectConfig.fxName); |
| | | spineComp.skeletonDataAsset = skeletonDataAsset; |
| | | spineComp.Initialize(true); |
| | | spineComp.raycastTarget = false; |
| | | spineComp.timeScale = speedRate; |
| | | |
| | | spineAnimationState = spineComp.AnimationState; |
| | | spineAnimationState.Complete -= OnSpineAnimationComplete; |
| | | spineAnimationState.Complete += OnSpineAnimationComplete; |
| | | |
| | | |
| | | if (null == canvas) |
| | | canvas = GetComponentInParent<Canvas>(); |
| | | |
| | | // 添加特效穿透阻挡器 |
| | | blocker = spineComp.AddMissingComponent<EffectPenetrationBlocker>(); |
| | | |
| | | blocker.onSortingChanged = OnSortingChanged; |
| | | |
| | | // 如果没有canvas的话 正常是因为不在BattleWin下面的节点 意思就是当前没有显示 等到切回战斗的时候再通过BattleField.UpdateCanvas来更新 |
| | | if (canvas != null) |
| | | { |
| | | blocker.SetParentCanvas(canvas); |
| | | } |
| | | |
| | | spineComp.enabled = true; |
| | | |
| | | Spine.Animation animation = spineAnimationState.Data.SkeletonData.Animations.First(); |
| | | spineAnimationState.SetAnimation(0, animation, false); |
| | | spineAnimationState.SetAnimation(0, animation, effectConfig.isLoop != 0); |
| | | |
| | | SoundPlayer.Instance.PlayUIAudio(effectConfig.audio); |
| | | |
| | | } |
| | | |
| | | private bool CheckForAdditiveBlend(Spine.Skeleton skeleton) |
| | | { |
| | | // 遍历所有插槽,检查是否有相加模式 |
| | | foreach (var slot in skeleton.Slots) |
| | | { |
| | | if (slot.Data.BlendMode == Spine.BlendMode.Additive) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | protected void PlayUnityEffect() |
| | |
| | | // 添加特效穿透阻挡器 |
| | | blocker = effectTarget.AddMissingComponent<EffectPenetrationBlocker>(); |
| | | |
| | | blocker.onSortingChanged = OnSortingChanged; |
| | | |
| | | // 如果没有canvas的话 正常是因为不在BattleWin下面的节点 意思就是当前没有显示 等到切回战斗的时候再通过BattleField.UpdateCanvas来更新 |
| | | if (canvas != null) |
| | | { |
| | |
| | | |
| | | } |
| | | |
| | | void LateUpdate() |
| | | { |
| | | if (string.IsNullOrEmpty(sortingLayer)) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | OnSortingChanged(sortingLayer, sortingOrder); |
| | | } |
| | | |
| | | public string sortingLayer; |
| | | public int sortingOrder; |
| | | |
| | | protected void OnSortingChanged(string _sortingLayer, int _sortingOrder) |
| | | { |
| | | sortingLayer = _sortingLayer; |
| | | sortingOrder = _sortingOrder; |
| | | // 处理排序变化 |
| | | var renderers = spineComp.GetComponents<Renderer>(); |
| | | foreach (var renderer in renderers) |
| | | { |
| | | renderer.sortingLayerName = sortingLayer; |
| | | renderer.sortingOrder = sortingOrder; |
| | | } |
| | | } |
| | | |
| | | protected void OnDestroy() |
| | | { |
| | | if (onDestroy != null) |
| | |
| | | //--------------------------------------------------------
|
| | | // [Author]: YYL
|
| | | // [ Date ]: 2025年8月14日
|
| | | // [ Date ]: 2025年8月19日
|
| | | //--------------------------------------------------------
|
| | |
|
| | | using System.Collections.Generic;
|
| | |
| | | public int autoDestroy;
|
| | | public float destroyDelay;
|
| | | public int isLoop;
|
| | | public int frontBack;
|
| | | public float delayPlay;
|
| | |
|
| | | public override int LoadKey(string _key)
|
| | | {
|
| | |
| | | float.TryParse(tables[9],out destroyDelay);
|
| | |
|
| | | int.TryParse(tables[10],out isLoop);
|
| | |
|
| | | int.TryParse(tables[11],out frontBack); |
| | |
|
| | | float.TryParse(tables[12],out delayPlay); |
| | | }
|
| | | catch (Exception exception)
|
| | | {
|
| | |
| | | //--------------------------------------------------------
|
| | | // [Author]: YYL
|
| | | // [ Date ]: 2025年8月5日
|
| | | // [ Date ]: 2025年8月18日
|
| | | //--------------------------------------------------------
|
| | |
|
| | | using System.Collections.Generic;
|
| | |
| | | //-------------------------------------------------------- |
| | | // [Author]: YYL |
| | | // [ Date ]: 2025年8月7日 |
| | | // [ Date ]: Wednesday, August 20, 2025 |
| | | //-------------------------------------------------------- |
| | | |
| | | using System.Collections.Generic; |
| | |
| | | public int TagAffect; |
| | | public int TagCount; |
| | | public int HappenRate; |
| | | public int LastTime; |
| | | public int CoolDownTime; |
| | | public int Priority; |
| | | public int EffectID1; |
| | | public int[] EffectValues1; |
| | | public int EffectID2; |
| | |
| | | public int EffectID3; |
| | | public int[] EffectValues3; |
| | | public int ConnSkill; |
| | | public int CoolDownTime; |
| | | public int[] EnhanceSkillList; |
| | | public int FightPower; |
| | | public int StartupFrames; |
| | | public int ActiveFrames; |
| | | public int[] ActiveFrames; |
| | | public int RecoveryFrames; |
| | | public int LoopCount; |
| | | public int CastPosition; |
| | |
| | | public int EffectPos; |
| | | public int EffectType; |
| | | public string IconName; |
| | | public int ExplosionEffect2; |
| | | |
| | | public override int LoadKey(string _key) |
| | | { |
| | |
| | | |
| | | int.TryParse(tables[13],out HappenRate); |
| | | |
| | | int.TryParse(tables[14],out LastTime); |
| | | int.TryParse(tables[14],out EffectID1); |
| | | |
| | | int.TryParse(tables[15],out CoolDownTime); |
| | | |
| | | int.TryParse(tables[16],out Priority); |
| | | |
| | | int.TryParse(tables[17],out EffectID1); |
| | | |
| | | if (tables[18].Contains("[")) |
| | | if (tables[15].Contains("[")) |
| | | { |
| | | EffectValues1 = JsonMapper.ToObject<int[]>(tables[18]); |
| | | EffectValues1 = JsonMapper.ToObject<int[]>(tables[15]); |
| | | } |
| | | else |
| | | { |
| | | string[] EffectValues1StringArray = tables[18].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries); |
| | | string[] EffectValues1StringArray = tables[15].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries); |
| | | EffectValues1 = new int[EffectValues1StringArray.Length]; |
| | | for (int i=0;i<EffectValues1StringArray.Length;i++) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | int.TryParse(tables[19],out EffectID2); |
| | | int.TryParse(tables[16],out EffectID2); |
| | | |
| | | if (tables[20].Contains("[")) |
| | | if (tables[17].Contains("[")) |
| | | { |
| | | EffectValues2 = JsonMapper.ToObject<int[]>(tables[20]); |
| | | EffectValues2 = JsonMapper.ToObject<int[]>(tables[17]); |
| | | } |
| | | else |
| | | { |
| | | string[] EffectValues2StringArray = tables[20].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries); |
| | | string[] EffectValues2StringArray = tables[17].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries); |
| | | EffectValues2 = new int[EffectValues2StringArray.Length]; |
| | | for (int i=0;i<EffectValues2StringArray.Length;i++) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | int.TryParse(tables[21],out EffectID3); |
| | | int.TryParse(tables[18],out EffectID3); |
| | | |
| | | if (tables[22].Contains("[")) |
| | | if (tables[19].Contains("[")) |
| | | { |
| | | EffectValues3 = JsonMapper.ToObject<int[]>(tables[22]); |
| | | EffectValues3 = JsonMapper.ToObject<int[]>(tables[19]); |
| | | } |
| | | else |
| | | { |
| | | string[] EffectValues3StringArray = tables[22].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries); |
| | | string[] EffectValues3StringArray = tables[19].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries); |
| | | EffectValues3 = new int[EffectValues3StringArray.Length]; |
| | | for (int i=0;i<EffectValues3StringArray.Length;i++) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | int.TryParse(tables[23],out ConnSkill); |
| | | int.TryParse(tables[20],out ConnSkill); |
| | | |
| | | if (tables[24].Contains("[")) |
| | | int.TryParse(tables[21],out CoolDownTime); |
| | | |
| | | if (tables[22].Contains("[")) |
| | | { |
| | | EnhanceSkillList = JsonMapper.ToObject<int[]>(tables[24]); |
| | | EnhanceSkillList = JsonMapper.ToObject<int[]>(tables[22]); |
| | | } |
| | | else |
| | | { |
| | | string[] EnhanceSkillListStringArray = tables[24].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries); |
| | | string[] EnhanceSkillListStringArray = tables[22].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries); |
| | | EnhanceSkillList = new int[EnhanceSkillListStringArray.Length]; |
| | | for (int i=0;i<EnhanceSkillListStringArray.Length;i++) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | int.TryParse(tables[25],out FightPower); |
| | | int.TryParse(tables[23],out FightPower); |
| | | |
| | | int.TryParse(tables[26],out StartupFrames); |
| | | int.TryParse(tables[24],out StartupFrames); |
| | | |
| | | int.TryParse(tables[27],out ActiveFrames); |
| | | if (tables[25].Contains("[")) |
| | | { |
| | | ActiveFrames = JsonMapper.ToObject<int[]>(tables[25]); |
| | | } |
| | | else |
| | | { |
| | | string[] ActiveFramesStringArray = tables[25].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries); |
| | | ActiveFrames = new int[ActiveFramesStringArray.Length]; |
| | | for (int i=0;i<ActiveFramesStringArray.Length;i++) |
| | | { |
| | | int.TryParse(ActiveFramesStringArray[i],out ActiveFrames[i]); |
| | | } |
| | | } |
| | | |
| | | int.TryParse(tables[28],out RecoveryFrames); |
| | | int.TryParse(tables[26],out RecoveryFrames); |
| | | |
| | | int.TryParse(tables[29],out LoopCount); |
| | | int.TryParse(tables[27],out LoopCount); |
| | | |
| | | int.TryParse(tables[30],out CastPosition); |
| | | int.TryParse(tables[28],out CastPosition); |
| | | |
| | | int.TryParse(tables[31],out CastIndexNum); |
| | | int.TryParse(tables[29],out CastIndexNum); |
| | | |
| | | float.TryParse(tables[32],out CastDistance); |
| | | float.TryParse(tables[30],out CastDistance); |
| | | |
| | | DamageDivide = JsonMapper.ToObject<int[][]>(tables[33].Replace("(", "[").Replace(")", "]")); |
| | | DamageDivide = JsonMapper.ToObject<int[][]>(tables[31].Replace("(", "[").Replace(")", "]")); |
| | | |
| | | int.TryParse(tables[34],out BulletEffectId); |
| | | int.TryParse(tables[32],out BulletEffectId); |
| | | |
| | | int.TryParse(tables[35],out BulletPos); |
| | | int.TryParse(tables[33],out BulletPos); |
| | | |
| | | int.TryParse(tables[36],out BulletPath); |
| | | int.TryParse(tables[34],out BulletPath); |
| | | |
| | | int.TryParse(tables[37],out BulletFlyTime); |
| | | int.TryParse(tables[35],out BulletFlyTime); |
| | | |
| | | int.TryParse(tables[38],out ExplosionEffectId); |
| | | int.TryParse(tables[36],out ExplosionEffectId); |
| | | |
| | | int.TryParse(tables[39],out ExplosionPos); |
| | | int.TryParse(tables[37],out ExplosionPos); |
| | | |
| | | SkillMotionName = tables[40]; |
| | | SkillMotionName = tables[38]; |
| | | |
| | | int.TryParse(tables[41],out EffectId); |
| | | int.TryParse(tables[39],out EffectId); |
| | | |
| | | int.TryParse(tables[42],out EffectPos); |
| | | int.TryParse(tables[40],out EffectPos); |
| | | |
| | | int.TryParse(tables[43],out EffectType); |
| | | int.TryParse(tables[41],out EffectType); |
| | | |
| | | IconName = tables[44]; |
| | | IconName = tables[42]; |
| | | |
| | | int.TryParse(tables[43],out ExplosionEffect2); |
| | | } |
| | | catch (Exception exception) |
| | | { |
| | |
| | | public class DTCB422_tagMCTurnFightObjDead : DtcBasic { |
| | | public override void Done(GameNetPackBasic vNetPack) { |
| | | base.Done(vNetPack); |
| | | HB422_tagMCTurnFightObjDead vNetData = vNetPack as HB422_tagMCTurnFightObjDead; |
| | | |
| | | BattleField battleField = BattleManager.Instance.GetBattleField(vNetPack.packUID); |
| | | |
| | | battleField.OnObjDead((int)vNetData.ObjID); |
| | | |
| | | // 由技能去通知战场死亡 battleField.OnObjsDead(deadList) |
| | | } |
| | | } |
| | |
| | | public class HB418_tagSCObjPropertyRefreshView : GameNetPackBasic { |
| | | public uint ObjID; |
| | | public ushort RefreshType; // 同0418刷新类型,如血量、怒气 |
| | | public uint AttackTypes; // 飘字类型汇总,支持多种类型并存,如无视防御且暴击同时被格挡,二进制或运算最终值;0-失败;1-普通;2-回血;5-格挡;6-无视防御;7-暴击;9-闪避 |
| | | public uint Value; // 更新值 |
| | | public uint ValueEx; // 更新值,如果是大数值的此值为整除亿部分 |
| | | public byte DiffType; // 变化类型,0-减少;1-增加 |
| | |
| | | public override void ReadFromBytes (byte[] vBytes) { |
| | | TransBytes (out ObjID, vBytes, NetDataType.DWORD); |
| | | TransBytes (out RefreshType, vBytes, NetDataType.WORD); |
| | | TransBytes (out AttackTypes, vBytes, NetDataType.DWORD); |
| | | TransBytes (out Value, vBytes, NetDataType.DWORD); |
| | | TransBytes (out ValueEx, vBytes, NetDataType.DWORD); |
| | | TransBytes (out DiffType, vBytes, NetDataType.BYTE); |
| | |
| | | |
| | | public BattleEffectPlayer PlayEffect(int ObjID, int effectId, Transform parent) |
| | | { |
| | | if (effectId <= 0) |
| | | { |
| | | return null; |
| | | } |
| | | |
| | | var effectCfg = EffectConfig.Get(effectId); |
| | | if (null == effectCfg) |
| | | { |
| | | return null; |
| | | } |
| | | |
| | | if (!effectDict.ContainsKey(effectId)) |
| | | { |
| | | effectDict[effectId] = new List<BattleEffectPlayer>(); |
| | |
| | | |
| | | } |
| | | |
| | | public virtual void OnObjDead(int ObjID) |
| | | public virtual void OnObjsDead(List<HB422_tagMCTurnFightObjDead> deadPackList) |
| | | { |
| | | DeathRecordAction recordAction = new DeathRecordAction(this, battleObjMgr.GetBattleObject(ObjID)); |
| | | DeathRecordAction recordAction = new DeathRecordAction(this, deadPackList); |
| | | recordPlayer.PlayRecord(recordAction); |
| | | } |
| | | |
| | |
| | | return GetTeamNode(battleCamp, index); |
| | | } |
| | | |
| | | private RectTransform GetTeamNode(BattleCamp battleCamp, int index) |
| | | public RectTransform GetTeamNode(BattleCamp battleCamp, int index) |
| | | { |
| | | if (index < 0 || index >= battleRootNode.redTeamNodeList.Count) |
| | | { |
| | |
| | | |
| | | public class DeathRecordAction : RecordAction |
| | | { |
| | | protected List<HB422_tagMCTurnFightObjDead> deadPackList = new List<HB422_tagMCTurnFightObjDead>(); |
| | | |
| | | public DeathRecordAction(BattleField _battleField, BattleObject _battleObj) |
| | | : base(RecordActionType.Death, _battleField, _battleObj) |
| | | { |
| | | isFinish = false; |
| | | } |
| | | public DeathRecordAction(BattleField _battleField, List<HB422_tagMCTurnFightObjDead> _deadPackList) |
| | | : base(RecordActionType.Death, _battleField, null) |
| | | { |
| | | isFinish = false; |
| | | deadPackList = _deadPackList; |
| | | } |
| | | |
| | | public override bool IsFinished() |
| | | { |
| | |
| | | public override void Run() |
| | | { |
| | | base.Run(); |
| | | isFinish = true; |
| | | battleObject.OnDeath(OnDeathAnimationEnd); |
| | | |
| | | if (!isRunOnce) |
| | | { |
| | | isRunOnce = true; |
| | | foreach (var deadPack in deadPackList) |
| | | { |
| | | BattleObject deadObj = battleField.battleObjMgr.GetBattleObject((int)deadPack.ObjID); |
| | | deadObj.OnDeath(OnDeathAnimationEnd); |
| | | } |
| | | return; |
| | | } |
| | | |
| | | } |
| | | |
| | | private void OnDeathAnimationEnd() |
| | |
| | | // 多一个zzz的一个特效 |
| | | |
| | | motionBase.PlayAnimation(MotionName.idle, true); |
| | | heroRectTrans.anchoredPosition = Vector2.zero; |
| | | } |
| | | |
| | | public void PushDropItems(BattleDrops _battleDrops) |
| | |
| | | |
| | | Debug.LogError("2 BattleObjectFactory.CreateBattleObject: Creating BattleObject for " + teamHero.ObjID + " at position " + teamHero.positionNum); |
| | | |
| | | |
| | | float finalScaleRate = modelScaleRate * teamHero.modelScale; |
| | | |
| | | skeletonGraphic.skeletonDataAsset = skeletonDataAsset; |
| | | skeletonGraphic.Initialize(true); |
| | | realGO.name = battleObject.ObjID.ToString(); |
| | | realGO.transform.localScale = new Vector3(finalScaleRate, finalScaleRate, finalScaleRate); |
| | | (realGO.transform as RectTransform).anchoredPosition = Vector2.zero; |
| | | battleObject.Init(realGO, teamHero, _Camp); |
| | | |
| | | Debug.LogError(realGO.name + " /3 BattleObjectFactory.CreateBattleObject: Creating BattleObject for " + teamHero.ObjID + " at position " + teamHero.positionNum); |
| | |
| | | |
| | | public static void DestroyBattleObject(int key, BattleObject battleObj) |
| | | { |
| | | Debug.LogError("BattleObject destroy"); |
| | | battleObj.Destroy(); |
| | | battleObj = null; |
| | | } |
| | |
| | | } |
| | | |
| | | tweenList.Add(tween); |
| | | tween.OnComplete(() => |
| | | { |
| | | tween.onComplete += () => |
| | | { |
| | | tweenList.Remove(tween); |
| | | }); |
| | | }; |
| | | |
| | | tween.Play(); |
| | | // tween.Play(); |
| | | } |
| | | |
| | | public void HaveRest() |
| | |
| | | |
| | | public static TweenerCore<Vector2, Vector2, DG.Tweening.Plugins.Options.VectorOptions> MoveToTarget(RectTransform transform, RectTransform target, Vector2 offset, float duration, Action onComplete = null) |
| | | { |
| | | Vector3 targetWorldPos = target.TransformPoint(target.anchoredPosition + offset); |
| | | // 1. 获取目标的最终 anchoredPosition(加上 offset) |
| | | Vector2 targetAnchoredPos = target.anchoredPosition + offset; |
| | | Vector3 worldAnchorPos = target.TransformPoint(targetAnchoredPos); |
| | | |
| | | RectTransform parentRect = transform.parent as RectTransform; |
| | | |
| | | Vector2 targetAnchoredPos; |
| | | // 转换 target 的 anchoredPosition 到 sourceParent 的坐标系 |
| | | Vector2 localPoint; |
| | | RectTransformUtility.ScreenPointToLocalPointInRectangle( |
| | | parentRect, |
| | | RectTransformUtility.WorldToScreenPoint(null, targetWorldPos), |
| | | null, |
| | | out targetAnchoredPos); |
| | | transform, |
| | | RectTransformUtility.WorldToScreenPoint(CameraManager.uiCamera, worldAnchorPos), |
| | | CameraManager.uiCamera, |
| | | out localPoint); |
| | | |
| | | // 3. DOTween 移动 |
| | | return transform.DOAnchorPos(targetAnchoredPos, duration) |
| | | .SetEase(Ease.Linear) |
| | | .OnComplete(() => onComplete?.Invoke()); |
| | | var tween = transform.DOAnchorPos(localPoint, duration).SetEase(Ease.Linear); |
| | | tween.onComplete += () => |
| | | { |
| | | onComplete?.Invoke(); |
| | | }; |
| | | |
| | | return tween; |
| | | } |
| | | |
| | | public static string DisplayDamageNum(long num, int attackType) |
| | |
| | | return config.nums[_num - 48]; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 保证所有分配项加起来等于totalDamage,避免因整除导致的误差 |
| | | /// </summary> |
| | | public static List<long> DivideDamageToList(int[] damageDivide, long totalDamage) |
| | | { |
| | | List<long> fixedDamageList = new List<long>(); |
| | | long assigned = 0; |
| | | int count = damageDivide.Length; |
| | | |
| | | for (int i = 0; i < count; i++) |
| | | { |
| | | long damage; |
| | | if (i == count - 1) |
| | | { |
| | | // 最后一个分配项修正为剩余 |
| | | damage = totalDamage - assigned; |
| | | } |
| | | else |
| | | { |
| | | damage = (totalDamage * damageDivide[i] + 5000) / 10000; // 四舍五入 |
| | | assigned += damage; |
| | | } |
| | | fixedDamageList.Add(damage); |
| | | } |
| | | return fixedDamageList; |
| | | } |
| | | |
| | | public static List<HB422_tagMCTurnFightObjDead> FindDeadPack(List<GameNetPackBasic> packList) |
| | | { |
| | | List<HB422_tagMCTurnFightObjDead> deadPacks = new List<HB422_tagMCTurnFightObjDead>(); |
| | | for (int i = 0; i < packList.Count; i++) |
| | | { |
| | | var pack = packList[i]; |
| | | // 寻找死亡包 找到死亡包之后要找掉落包 不能超过技能包 |
| | | if (pack is HB422_tagMCTurnFightObjDead) |
| | | { |
| | | var deadPack = pack as HB422_tagMCTurnFightObjDead; |
| | | deadPacks.Add(deadPack); |
| | | } |
| | | else if (pack is CustomHB426CombinePack) |
| | | { |
| | | // 找死亡包不要越过技能包 |
| | | var combinePack = pack as CustomHB426CombinePack; |
| | | if (combinePack.startTag.Tag.StartsWith("Skill_")) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | return deadPacks; |
| | | } |
| | | |
| | | |
| | | public static List<HB423_tagMCTurnFightObjReborn> FindRebornPack(List<GameNetPackBasic> packList) |
| | | { |
| | | List<HB423_tagMCTurnFightObjReborn> rebornPack = new List<HB423_tagMCTurnFightObjReborn>(); |
| | | for (int i = 0; i < packList.Count; i++) |
| | | { |
| | | var pack = packList[i]; |
| | | // 寻找死亡包 找到死亡包之后要找掉落包 不能超过技能包 |
| | | if (pack is HB423_tagMCTurnFightObjReborn) |
| | | { |
| | | var deadPack = pack as HB423_tagMCTurnFightObjReborn; |
| | | rebornPack.Add(deadPack); |
| | | } |
| | | else if (pack is CustomHB426CombinePack) |
| | | { |
| | | // 找死亡包不要越过技能包 |
| | | var combinePack = pack as CustomHB426CombinePack; |
| | | if (combinePack.startTag.Tag.StartsWith("Skill_")) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | return rebornPack; |
| | | } |
| | | } |
| | |
| | | /// </summary> |
| | | public class MotionBase |
| | | { |
| | | public static float MotionTimeScale = 2f; |
| | | public static float MotionTimeScale = 1f; |
| | | |
| | | public static List<string> AttackMotionList = new List<string> |
| | | { |
| | |
| | | return currentTrackEntry; |
| | | } |
| | | |
| | | public Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, Action onComplete = null, Action onBeginPhaseEnd = null, Action onActivePhaseEnd = null) |
| | | public Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, SkillBase skillBase, Action _onComplete = null) |
| | | { |
| | | // 参数校验 |
| | | if (skillConfig == null) |
| | | { |
| | | Debug.LogError("技能配置为空,无法播放技能动画"); |
| | | return null; |
| | | } |
| | | if (spineAnimationState == null || skeleton == null) |
| | | { |
| | | Debug.LogError("SkeletonGraphic或AnimationState未初始化,无法播放技能动画"); |
| | | return null; |
| | | } |
| | | |
| | | return PlayAnimation(skillConfig.SkillMotionName, skillConfig.StartupFrames, skillConfig.ActiveFrames, skillConfig.LoopCount, |
| | | onComplete, onBeginPhaseEnd, onActivePhaseEnd); |
| | | } |
| | | // 获取动画 |
| | | Spine.Animation anim = skeleton.Data.FindAnimation(skillConfig.SkillMotionName); |
| | | if (anim == null) |
| | | { |
| | | Debug.LogError($"找不到动画: {skillConfig.SkillMotionName}"); |
| | | return null; |
| | | } |
| | | |
| | | 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; |
| | | float middleBeginTime = skillConfig.StartupFrames / fps; |
| | | int loopCount = skillConfig.LoopCount; |
| | | int[] activeFrames = skillConfig.ActiveFrames; |
| | | int activeFrameCount = activeFrames.Length; |
| | | float recoveryFrameTime = skillConfig.RecoveryFrames / fps; |
| | | |
| | | currentTrackEntry = spineAnimationState.SetAnimation(0, anim, false); |
| | | // 播放动画 |
| | | var skillTrackEntry = spineAnimationState.SetAnimation(0, anim, false); |
| | | currentTrackEntry = skillTrackEntry; |
| | | |
| | | // 事件状态 |
| | | int curLoop = 0; |
| | | bool finished = false; |
| | | bool isFinish = false; |
| | | bool beginPhaseTriggered = false; |
| | | bool finalFrameStarted = false; |
| | | bool finalFrameEnded = false; |
| | | bool middleFrameStarted = false; |
| | | bool[] triggeredActiveFrame = new bool[activeFrameCount]; |
| | | |
| | | // 技能开始 |
| | | skillBase.OnSkillStart(); |
| | | |
| | | // 动画帧更新处理 |
| | | 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 (isFinish) return; |
| | | float trackTime = skillTrackEntry.TrackTime; |
| | | |
| | | // 前摇结束(只触发一次) |
| | | if (!beginPhaseTriggered && entry.TrackTime >= beginTime) |
| | | if (!beginPhaseTriggered && trackTime >= middleBeginTime && curLoop == 0) |
| | | { |
| | | beginPhaseTriggered = true; |
| | | onBeginPhaseEnd?.Invoke(); |
| | | skillBase.OnStartSkillFrameEnd(); |
| | | } |
| | | |
| | | // 中摇结束(每次到endTime都触发) |
| | | if (entry.TrackTime >= endTime) |
| | | // 中摇开始(每轮loop的开始,只触发一次) |
| | | if (!middleFrameStarted && trackTime >= middleBeginTime && curLoop < loopCount) |
| | | { |
| | | onActivePhaseEnd?.Invoke(); |
| | | middleFrameStarted = true; |
| | | skillBase.OnMiddleFrameStart(curLoop); |
| | | } |
| | | |
| | | curLoop++; |
| | | if (curLoop >= loopTimes) |
| | | // 多段攻击帧触发 |
| | | for (int hitIndex = 0; hitIndex < activeFrameCount; hitIndex++) |
| | | { |
| | | float activeFrameTime = activeFrames[hitIndex] / fps; |
| | | if (!triggeredActiveFrame[hitIndex] && trackTime >= activeFrameTime) |
| | | { |
| | | finished = true; |
| | | skeletonGraphic.UpdateLocal -= updateLocalHandler; |
| | | _onComplete?.Invoke(); |
| | | return; |
| | | skillBase.OnMiddleFrameEnd(curLoop, hitIndex); |
| | | triggeredActiveFrame[hitIndex] = true; |
| | | } |
| | | entry.TrackTime = beginTime; |
| | | beginPhaseTriggered = false; // 重置,下一轮前摇可再次触发 |
| | | } |
| | | |
| | | // 判断是否所有activeFrame都已触发,准备进入下一轮loop |
| | | bool allTriggered = true; |
| | | for (int i = 0; i < activeFrameCount; i++) |
| | | { |
| | | if (!triggeredActiveFrame[i]) |
| | | { |
| | | allTriggered = false; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // 进入下一轮loop |
| | | if (allTriggered && curLoop < loopCount) |
| | | { |
| | | curLoop++; |
| | | Array.Clear(triggeredActiveFrame, 0, activeFrameCount); |
| | | middleFrameStarted = false; |
| | | |
| | | if (curLoop < loopCount) |
| | | { |
| | | // 重新设置到第一次的中摇时间 |
| | | skillTrackEntry.TrackTime = middleBeginTime; |
| | | beginPhaseTriggered = false; |
| | | } |
| | | else |
| | | { |
| | | finalFrameStarted = false; |
| | | finalFrameEnded = false; |
| | | // 收尾阶段由后续逻辑处理 |
| | | } |
| | | } |
| | | |
| | | // 收尾阶段:OnFinalFrameStart 和 OnFinalFrameEnd |
| | | if (curLoop >= loopCount) |
| | | { |
| | | if (!finalFrameStarted && trackTime >= recoveryFrameTime) |
| | | { |
| | | finalFrameStarted = true; |
| | | skillBase.OnFinalFrameStart(); |
| | | } |
| | | if (finalFrameStarted && !finalFrameEnded && trackTime >= recoveryFrameTime) |
| | | { |
| | | finalFrameEnded = true; |
| | | skillBase.OnFinalFrameEnd(); |
| | | skeletonGraphic.UpdateLocal -= updateLocalHandler; |
| | | isFinish = true; |
| | | } |
| | | } |
| | | }; |
| | | skeletonGraphic.UpdateLocal += updateLocalHandler; |
| | | |
| | | if (_onComplete != null && currentTrackEntry != null) |
| | | { |
| | | trackEntryCompleteDict[currentTrackEntry] = _onComplete; |
| | | } |
| | | |
| | | return currentTrackEntry; |
| | | skeletonGraphic.UpdateLocal += updateLocalHandler; |
| | | return skillTrackEntry; |
| | | } |
| | | |
| | | |
| | | |
| | | /// <summary> |
| | | /// 设置动画事件监听 |
| | |
| | | protected BattleField battleField; |
| | | |
| | | private Queue<RecordAction> recordActionQueue = new Queue<RecordAction>(); |
| | | |
| | | protected RecordAction currentRecordAction; |
| | | |
| | | private bool isWaitingNextAction = false; |
| | | private float waitTimer = 0f; |
| | | private const float waitInterval = 1f; |
| | | |
| | | public void Init(BattleField _battleField) |
| | | { |
| | |
| | | |
| | | public virtual void Run() |
| | | { |
| | | // 等待下一个action |
| | | if (isWaitingNextAction) |
| | | { |
| | | waitTimer += Time.deltaTime; |
| | | if (waitTimer >= waitInterval) |
| | | { |
| | | isWaitingNextAction = false; |
| | | waitTimer = 0f; |
| | | } |
| | | else |
| | | { |
| | | return; |
| | | } |
| | | } |
| | | |
| | | if (currentRecordAction == null) |
| | | { |
| | | if (recordActionQueue.Count <= 0) |
| | |
| | | if (currentRecordAction != null && currentRecordAction.IsFinished()) |
| | | { |
| | | Debug.LogError("record action " + currentRecordAction.GetType() + " play finished"); |
| | | |
| | | currentRecordAction = null; |
| | | isWaitingNextAction = true; |
| | | waitTimer = 0f; |
| | | return; |
| | | } |
| | | |
| | | if (currentRecordAction == null) |
| | |
| | | using System; |
| | | using System.Linq; |
| | | |
| | | |
| | | public class DirectlyDamageSkill : SkillBase |
| | | { |
| | | protected SkillEffect skillEffect; |
| | |
| | | base.Run(); |
| | | } |
| | | |
| | | |
| | | // 技能动画播放完毕 |
| | | 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() |
| | | // 技能开始 |
| | | public override void OnSkillStart() |
| | | { |
| | | skillEffect = SkillEffectFactory.CreateSkillEffect( |
| | | caster, |
| | |
| | | } |
| | | } |
| | | |
| | | // 前摇结束 |
| | | public override void OnStartSkillFrameEnd() |
| | | { |
| | | base.OnStartSkillFrameEnd(); |
| | | } |
| | | |
| | | protected override void OnHitTargets(int _hitIndex, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hitList) |
| | | { |
| | | base.OnHitTargets(_hitIndex, hitList); |
| | | } |
| | | } |
| | | |
| | | protected override void OnHitEachTarget(BattleObject target, long totalDamage, List<long> damageList, ref HB427_tagSCUseSkill.tagSCUseSkillHurt hurt) |
| | | { |
| | |
| | | } |
| | | |
| | | |
| | | // 中摇结束 |
| | | protected override void OnActiveSkillFrame() |
| | | public override void OnMiddleFrameStart(int times) |
| | | { |
| | | |
| | | base.OnMiddleFrameStart(times); |
| | | |
| | | skillEffect?.OnMiddleFrameStart(times); |
| | | } |
| | | |
| | | |
| | | // 中摇结束(命中帧) |
| | | public override void OnMiddleFrameEnd(int times, int hitIndex) |
| | | { |
| | | skillEffect?.OnMiddleFrameEnd(times, hitIndex); |
| | | } |
| | | |
| | | // 后摇结束 |
| | | protected override void OnEndSkillFrame() |
| | | public override void OnFinalFrameEnd() |
| | | { |
| | | |
| | | } |
| | |
| | | base.Run(); |
| | | } |
| | | |
| | | |
| | | // 技能动画播放完毕 |
| | | 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() |
| | | public override void OnStartSkillFrameEnd() |
| | | { |
| | | skillEffect = SkillEffectFactory.CreateSkillEffect( |
| | | caster, |
| | |
| | | } |
| | | |
| | | |
| | | // 中摇结束 |
| | | protected override void OnActiveSkillFrame() |
| | | { |
| | | // // 中摇结束 |
| | | // protected override void OnActiveSkillFrame() |
| | | // { |
| | | |
| | | } |
| | | // } |
| | | |
| | | // 后摇结束 |
| | | protected override void OnEndSkillFrame() |
| | | { |
| | | // // 后摇结束 |
| | | // protected override void OnEndSkillFrame() |
| | | // { |
| | | |
| | | } |
| | | // } |
| | | } |
| | |
| | | base.Run(); |
| | | } |
| | | |
| | | |
| | | // 技能动画播放完毕 |
| | | 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() |
| | | public override void OnStartSkillFrameEnd() |
| | | { |
| | | skillEffect = SkillEffectFactory.CreateSkillEffect( |
| | | caster, |
| | |
| | | base.OnHitEachTarget(target, totalDamage, damageList, ref hurt); |
| | | } |
| | | |
| | | |
| | | // 中摇结束 |
| | | protected override void OnActiveSkillFrame() |
| | | { |
| | | |
| | | } |
| | | |
| | | // 后摇结束 |
| | | protected override void OnEndSkillFrame() |
| | | { |
| | | |
| | | } |
| | | } |
| | |
| | | |
| | | public class SkillBase |
| | | { |
| | | protected SkillEffect skillEffect; |
| | | |
| | | protected HB427_tagSCUseSkill tagUseSkillAttack; |
| | | |
| | | protected SkillConfig skillConfig; |
| | |
| | | |
| | | |
| | | |
| | | |
| | | public void Pause() |
| | | { |
| | | pauseState = startCounting; |
| | |
| | | startCounting = pauseState; |
| | | } |
| | | |
| | | |
| | | // 0·移动到距离目标n码,的距离释放(可配置,9999即原地释放,负数则是移动到人物背面,人物要转身) |
| | | // 1·移动到距离阵容位置n码的距离(如2号位,5号位)释放(即战场中央此类) |
| | | public virtual void Cast() |
| | | { |
| | | Debug.LogError(GetType().Name + " Skill Cast Start"); |
| | | // 高亮所有本次技能相关的目标 |
| | | HighLightAllTargets(); |
| | | |
| | | // 距离配成负数要转身 TurnBack |
| | | |
| | | Debug.LogError(GetType().Name + " Skill CastMode : " + skillConfig.castMode); |
| | | switch (skillConfig.castMode) |
| | | { |
| | | case SkillCastMode.Self: |
| | | PlayCastAnimation(() => DoSkillLogic(OnSkillFinished)); |
| | | CastImpl(); |
| | | break; |
| | | case SkillCastMode.Enemy: |
| | | MoveToTarget(caster.GetEnemyCamp(), skillConfig, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); })))); |
| | | CastToEnemy(); |
| | | break; |
| | | case SkillCastMode.Target: |
| | | // 目标是敌方主目标 |
| | | if (tagUseSkillAttack.HurtCount <= 0) |
| | | { |
| | | Debug.LogError("技能攻击包没有目标 HurtCount <= 0"); |
| | | OnSkillFinished(); |
| | | return; |
| | | } |
| | | |
| | | var mainHurt = tagUseSkillAttack.HurtList[0]; |
| | | |
| | | BattleObject mainTarget = battleField.battleObjMgr.GetBattleObject((int)mainHurt.ObjID); |
| | | if (mainTarget == null) |
| | | { |
| | | Debug.LogError("目标为空 mainTarget == null ObjID : " + mainHurt.ObjID); |
| | | OnSkillFinished(); |
| | | return; |
| | | } |
| | | MoveToTarget(mainTarget.Camp, mainTarget, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); })))); |
| | | CastToTarget(); |
| | | break; |
| | | case SkillCastMode.Allies: |
| | | MoveToTarget(caster.Camp, skillConfig, _onComplete: () => TurnBack(() => PlayCastAnimation(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); })))); |
| | | CastToAllies(); |
| | | break; |
| | | // case SkillCastMode.DashCast: |
| | | // DashToTarget(() => BackToOrigin(OnSkillFinished)); |
| | | // break; |
| | | default: |
| | | Debug.LogError("暂时不支持其他的方式释放 有需求请联系策划" + skillConfig.SkillID); |
| | | Debug.LogError("暂时不支持其他的方式释放 有需求请联系策划 技能id:" + skillConfig.SkillID + " cast position " + skillConfig.CastPosition); |
| | | OnSkillFinished(); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // 这里其实是技能后摇结束的地方 |
| | | protected virtual void DoSkillLogic(Action _onComplete = null) |
| | | protected void MoveToTarget(RectTransform target, Vector2 offset, float duration, Action onComplete = null) |
| | | { |
| | | |
| | | } |
| | | |
| | | protected TrackEntry PlayCastAnimation(Action onComplete = null) |
| | | { |
| | | // 播放施法动作 |
| | | return caster.motionBase.PlaySkillAnimation(skillConfig, onComplete, |
| | | OnStartSkillFrame,//攻击前摇结束 |
| | | OnActiveSkillFrame);//攻击中摇结束 |
| | | } |
| | | |
| | | public void MoveToTarget(BattleCamp camp, BattleObject target, float duration = 0.2f, Action _onComplete = null) |
| | | { |
| | | targetNode = battleField.GetTeamNode(camp, target); |
| | | |
| | | Vector2 offset = new Vector2(skillConfig.CastDistance, 0); |
| | | RectTransform selfRect = caster.heroRectTrans; |
| | | RectTransform targetRect = targetNode; |
| | | |
| | | var tweener = BattleUtility.MoveToTarget(selfRect, targetRect, offset, duration, _onComplete); |
| | | caster.motionBase.PlayAnimation(MotionName.run, true); |
| | | var tweener = BattleUtility.MoveToTarget(caster.heroRectTrans, target, offset, duration, () => |
| | | { |
| | | caster.motionBase.PlayAnimation(MotionName.idle, true); |
| | | onComplete?.Invoke(); |
| | | }); |
| | | battleField.battleTweenMgr.OnPlayTween(tweener); |
| | | } |
| | | |
| | | public void MoveToTarget(BattleCamp camp, SkillConfig skillCfg, float duration = 0.2f, Action _onComplete = null) |
| | | { |
| | | targetNode = battleField.GetTeamNode(camp, skillCfg); |
| | | |
| | | Vector2 offset = new Vector2(skillConfig.CastDistance, 0); |
| | | RectTransform selfRect = caster.heroRectTrans; |
| | | RectTransform targetRect = targetNode; |
| | | |
| | | var tweener = BattleUtility.MoveToTarget(selfRect, targetRect, offset, duration, _onComplete); |
| | | battleField.battleTweenMgr.OnPlayTween(tweener); |
| | | } |
| | | |
| | | public void TurnBack(Action _onComplete) |
| | | protected void TurnBack(Action _onComplete, float forward) |
| | | { |
| | | if (skillConfig.CastDistance < 0) |
| | | { |
| | | // 转身 |
| | | caster.heroGo.transform.localScale = new Vector3(-1, 1, 1); |
| | | Vector3 scale = caster.heroGo.transform.localScale; |
| | | scale.x = Mathf.Abs(scale.x) * forward; |
| | | caster.heroGo.transform.localScale = scale; |
| | | } |
| | | _onComplete?.Invoke(); |
| | | } |
| | | |
| | | public void BackToOrigin(Action _onComplete = null) |
| | | protected void CastToEnemy() |
| | | { |
| | | RectTransform selfRect = caster.heroRectTrans; |
| | | Vector2 targetAnchoredPos = Vector2.zero; |
| | | var tween = selfRect.DOAnchorPos(targetAnchoredPos, 0.2f) |
| | | .SetEase(Ease.Linear) |
| | | .OnComplete(() => |
| | | { |
| | | // 转成正确方向 |
| | | caster.heroGo.transform.localScale = Vector3.one; |
| | | _onComplete?.Invoke(); |
| | | }); |
| | | const float moveTime = 0.5f; |
| | | |
| | | battleField.battleTweenMgr.OnPlayTween(tween); |
| | | RectTransform target = battleField.GetTeamNode(caster.GetEnemyCamp(), skillConfig); |
| | | |
| | | MoveToTarget(target, new Vector2(skillConfig.CastDistance, 0), moveTime, () => |
| | | { |
| | | // 到位置转身(不一定非要转身 但是流程要写) |
| | | TurnBack(() => |
| | | { |
| | | // 到达目标位置 |
| | | CastImpl(() => |
| | | { |
| | | TurnBack( |
| | | () => |
| | | { |
| | | // 回到原来的位置 |
| | | MoveToTarget(battleField.GetTeamNode(caster.Camp, caster.teamHero.positionNum), Vector2.zero, moveTime, () => |
| | | { |
| | | TurnBack(null, 1f); |
| | | caster.motionBase.PlayAnimation(MotionName.idle, true); |
| | | }); |
| | | } |
| | | , -1f); |
| | | }); |
| | | }, -1f); |
| | | }); |
| | | } |
| | | |
| | | |
| | | |
| | | protected void CastToTarget() |
| | | { |
| | | // 目标是敌方主目标 |
| | | if (tagUseSkillAttack.HurtCount <= 0) |
| | | { |
| | | Debug.LogError("技能攻击包没有目标 HurtCount <= 0"); |
| | | OnSkillFinished(); |
| | | return; |
| | | } |
| | | |
| | | var mainHurt = tagUseSkillAttack.HurtList[0]; |
| | | |
| | | BattleObject mainTarget = battleField.battleObjMgr.GetBattleObject((int)mainHurt.ObjID); |
| | | if (mainTarget == null) |
| | | { |
| | | Debug.LogError("目标为空 mainTarget == null ObjID : " + mainHurt.ObjID); |
| | | OnSkillFinished(); |
| | | return; |
| | | } |
| | | // MoveToTarget(mainTarget.Camp, mainTarget, _onComplete: () => TurnBack(() => CastImpl(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); })))); |
| | | } |
| | | |
| | | protected void CastToAllies() |
| | | { |
| | | // MoveToTarget(caster.Camp, skillConfig, _onComplete: () => TurnBack(() => CastImpl(() => DoSkillLogic(() => { BackToOrigin(OnSkillFinished); })))); |
| | | } |
| | | |
| | | protected TrackEntry CastImpl(Action onComplete = null) |
| | | { |
| | | // 播放施法动作 |
| | | return caster.motionBase.PlaySkillAnimation(skillConfig, this, onComplete);//攻击中摇结束 |
| | | } |
| | | |
| | | // 技能开始 |
| | | public virtual void OnSkillStart() |
| | | { |
| | | skillEffect = SkillEffectFactory.CreateSkillEffect( |
| | | caster, |
| | | skillConfig, |
| | | tagUseSkillAttack |
| | | ); |
| | | if (skillEffect != null) |
| | | { |
| | | skillEffect.Play(OnHitTargets); |
| | | } |
| | | } |
| | | |
| | | // 技能前摇帧结束 |
| | | public virtual void OnStartSkillFrameEnd() |
| | | { |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 中摇开始 times=第几次循环 从0开始 |
| | | /// </summary> |
| | | /// <param name="times"></param> |
| | | public virtual void OnMiddleFrameStart(int times) |
| | | { |
| | | |
| | | } |
| | | |
| | | public virtual void OnMiddleFrameEnd(int times, int hitIndex) |
| | | { |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 后摇开始 |
| | | /// </summary> |
| | | public virtual void OnFinalFrameStart() |
| | | { |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 后摇结束 |
| | | /// </summary> |
| | | public virtual void OnFinalFrameEnd() |
| | | { |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | // public void MoveToTarget(BattleCamp camp, BattleObject target, float duration = 0.2f, Action _onComplete = null) |
| | | // { |
| | | // targetNode = battleField.GetTeamNode(camp, target); |
| | | |
| | | // Vector2 offset = new Vector2(skillConfig.CastDistance, 0); |
| | | // RectTransform selfRect = caster.heroRectTrans; |
| | | // RectTransform targetRect = targetNode; |
| | | |
| | | // var tweener = BattleUtility.MoveToTarget(selfRect, targetRect, offset, duration, _onComplete); |
| | | // battleField.battleTweenMgr.OnPlayTween(tweener); |
| | | // } |
| | | |
| | | // public void MoveToTarget(BattleCamp camp, SkillConfig skillCfg, float duration = 0.2f, Action _onComplete = null) |
| | | // { |
| | | // targetNode = battleField.GetTeamNode(camp, skillCfg); |
| | | |
| | | // Vector2 offset = new Vector2(skillConfig.CastDistance, 0); |
| | | // RectTransform selfRect = caster.heroRectTrans; |
| | | // RectTransform targetRect = targetNode; |
| | | |
| | | // var tweener = BattleUtility.MoveToTarget(selfRect, targetRect, offset, duration, _onComplete); |
| | | // battleField.battleTweenMgr.OnPlayTween(tweener); |
| | | // } |
| | | |
| | | // public void TurnBack(Action _onComplete) |
| | | // { |
| | | // if (skillConfig.CastDistance < 0) |
| | | // { |
| | | // // 转身 |
| | | // caster.heroGo.transform.localScale = new Vector3(-1, 1, 1); |
| | | // } |
| | | // _onComplete?.Invoke(); |
| | | // } |
| | | |
| | | // public void BackToOrigin(Action _onComplete = null) |
| | | // { |
| | | // RectTransform selfRect = caster.heroRectTrans; |
| | | // Vector2 targetAnchoredPos = Vector2.zero; |
| | | // var tween = selfRect.DOAnchorPos(targetAnchoredPos, 0.2f) |
| | | // .SetEase(Ease.Linear); |
| | | |
| | | // tween.onComplete += () => |
| | | // { |
| | | // // 转成正确方向 |
| | | // caster.heroGo.transform.localScale = Vector3.one; |
| | | // _onComplete?.Invoke(); |
| | | // }; |
| | | |
| | | // battleField.battleTweenMgr.OnPlayTween(tween); |
| | | // } |
| | | |
| | | protected void HighLightAllTargets() |
| | | { |
| | |
| | | long totalDamage = GeneralDefine.GetFactValue(hurt.HurtHP, hurt.HurtHPEx); |
| | | |
| | | // 保证所有分配项加起来等于totalDamage,避免因整除导致的误差 |
| | | List<long> damageList = DivideDamageToList(damageDivide, totalDamage); |
| | | List<long> damageList = BattleUtility.DivideDamageToList(damageDivide, totalDamage); |
| | | |
| | | OnHitEachTarget(target, totalDamage, damageList, ref hurt); |
| | | } |
| | |
| | | |
| | | protected void HandleDead() |
| | | { |
| | | var deadPackList = FindDeadPack(); |
| | | var deadPackList = BattleUtility.FindDeadPack(packList); |
| | | CheckAfterDeadhPack(); |
| | | |
| | | // 处理掉落包 提前distribute之后 PackManager才有掉落物 所以不跟assignexp一样distribute |
| | |
| | | } |
| | | |
| | | // 分发死亡包 |
| | | battleField.OnObjsDead(deadPackList); |
| | | foreach (var deadPack in deadPackList) |
| | | { |
| | | PackageRegedit.Distribute(deadPack); |
| | | packList.Remove(deadPack); |
| | | } |
| | | deadPackList.Clear(); |
| | | } |
| | | |
| | | |
| | | |
| | | // 分配掉落 |
| | |
| | | return expAssign; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 保证所有分配项加起来等于totalDamage,避免因整除导致的误差 |
| | | /// </summary> |
| | | protected List<long> DivideDamageToList(int[] damageDivide, long totalDamage) |
| | | { |
| | | List<long> fixedDamageList = new List<long>(); |
| | | long assigned = 0; |
| | | int count = damageDivide.Length; |
| | | |
| | | for (int i = 0; i < count; i++) |
| | | { |
| | | long damage; |
| | | if (i == count - 1) |
| | | { |
| | | // 最后一个分配项修正为剩余 |
| | | damage = totalDamage - assigned; |
| | | } |
| | | else |
| | | { |
| | | damage = (totalDamage * damageDivide[i] + 5000) / 10000; // 四舍五入 |
| | | assigned += damage; |
| | | } |
| | | fixedDamageList.Add(damage); |
| | | } |
| | | return fixedDamageList; |
| | | } |
| | | |
| | | protected virtual void OnHitEachTarget(BattleObject target, long totalDamage, List<long> damageList, ref HB427_tagSCUseSkill.tagSCUseSkillHurt hurt) |
| | | { |
| | |
| | | target.heroGo.transform |
| | | ); |
| | | } |
| | | } |
| | | |
| | | protected HB423_tagMCTurnFightObjReborn FindRebornPack(BattleObject target) |
| | | { |
| | | HB423_tagMCTurnFightObjReborn rebornPack = null; |
| | | for (int i = 0; i < packList.Count; i++) |
| | | { |
| | | var pack = packList[i]; |
| | | if (pack is HB423_tagMCTurnFightObjReborn) |
| | | { |
| | | rebornPack = pack as HB423_tagMCTurnFightObjReborn; |
| | | if (rebornPack.ObjID == target.ObjID) |
| | | { |
| | | return rebornPack; |
| | | } |
| | | } |
| | | else if (pack is CustomHB426CombinePack) |
| | | { |
| | | var combinePack = pack as CustomHB426CombinePack; |
| | | if (combinePack.startTag.Tag.StartsWith("Skill_")) |
| | | { |
| | | break; // 找到技能包就不需要再处理了 |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | protected List<HB422_tagMCTurnFightObjDead> FindDeadPack() |
| | | { |
| | | List<HB422_tagMCTurnFightObjDead> deadPacks = new List<HB422_tagMCTurnFightObjDead>(); |
| | | for (int i = 0; i < packList.Count; i++) |
| | | { |
| | | var pack = packList[i]; |
| | | // 寻找死亡包 找到死亡包之后要找掉落包 不能超过技能包 |
| | | if (pack is HB422_tagMCTurnFightObjDead) |
| | | { |
| | | var deadPack = pack as HB422_tagMCTurnFightObjDead; |
| | | deadPacks.Add(deadPack); |
| | | } |
| | | else if (pack is CustomHB426CombinePack) |
| | | { |
| | | // 找死亡包不要越过技能包 |
| | | var combinePack = pack as CustomHB426CombinePack; |
| | | if (combinePack.startTag.Tag.StartsWith("Skill_")) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | return deadPacks; |
| | | } |
| | | |
| | | protected void CheckAfterDeadhPack() |
| | |
| | | |
| | | public void OnSkillFinished() |
| | | { |
| | | while (packList.Count > 0) |
| | | Debug.LogError(GetType().Name + " Skill Finished"); |
| | | if (packList.Count > 0) |
| | | { |
| | | var pack = packList[0]; |
| | | packList.RemoveAt(0); |
| | |
| | | } |
| | | |
| | | isFinished = true; |
| | | } |
| | | |
| | | |
| | | protected virtual void OnActiveSkillFrame() |
| | | { |
| | | |
| | | } |
| | | |
| | | protected virtual void OnStartSkillFrame() |
| | | { |
| | | |
| | | } |
| | | |
| | | protected virtual void OnEndSkillFrame() |
| | | { |
| | | |
| | | } |
| | | } |
| | |
| | | private Vector2 end; |
| | | private Vector2 control; |
| | | |
| | | public BezierBulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer effectPlayer, RectTransform target, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit) |
| | | : base(caster, skillConfig, effectPlayer, target, onHit) { } |
| | | public BezierBulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer effectPlayer, |
| | | RectTransform target, HB427_tagSCUseSkill tagUseSkillAttack, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit) |
| | | : base(caster, skillConfig, effectPlayer, target, tagUseSkillAttack, onHit) { } |
| | | |
| | | public override void Reset() |
| | | { |
| | |
| | | if (t >= 1f) |
| | | { |
| | | finished = true; |
| | | onHit?.Invoke(0, null); |
| | | onHit?.Invoke(0, hurts); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | public BounceBulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer effectPlayer, |
| | | RectTransform target, HB427_tagSCUseSkill tagUseSkillAttack, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit) |
| | | : base(caster, skillConfig, effectPlayer, target, onHit) |
| | | : base(caster, skillConfig, effectPlayer, target, tagUseSkillAttack, onHit) |
| | | { |
| | | this.hurtList = new List<HB427_tagSCUseSkill.tagSCUseSkillHurt>(tagUseSkillAttack.HurtList); |
| | | } |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using UnityEngine; |
| | | |
| | | public class BulletCurve |
| | |
| | | protected float duration = 0f; |
| | | protected float elapsed = 0f; |
| | | |
| | | public BulletCurve() { } |
| | | protected List<HB427_tagSCUseSkill.tagSCUseSkillHurt> hurts = new List<HB427_tagSCUseSkill.tagSCUseSkillHurt>(); |
| | | |
| | | public BulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer bulletEffect, RectTransform target, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit) |
| | | public BulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer bulletEffect, RectTransform target, HB427_tagSCUseSkill tagUseSkillAttack, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit) |
| | | { |
| | | this.caster = caster; |
| | | this.skillConfig = skillConfig; |
| | |
| | | this.target = target; |
| | | this.onHit = onHit; |
| | | this.bulletTrans = bulletEffect.transform as RectTransform; |
| | | this.hurts = tagUseSkillAttack.HurtList.ToList(); |
| | | } |
| | | |
| | | public virtual void Reset() |
| | |
| | | protected virtual void ReachTarget() |
| | | { |
| | | finished = true; |
| | | onHit?.Invoke(0, null); |
| | | onHit?.Invoke(0, hurts); |
| | | caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, bulletEffect); |
| | | } |
| | | |
| | |
| | | switch (skillConfig.BulletPath) |
| | | { |
| | | case 1: // 直线消失于目标 |
| | | return new StraightBulletCurve(caster, skillConfig, bulletEffect, target, onHit); |
| | | return new StraightBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit); |
| | | case 2: // 直线贯穿消失在屏幕外 |
| | | return new PenetrateBulletCurve(caster, skillConfig, bulletEffect, target, onHit); |
| | | return new PenetrateBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit); |
| | | case 3: // 抛物线弧线 |
| | | return new BezierBulletCurve(caster, skillConfig, bulletEffect, target, onHit); |
| | | return new BezierBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit); |
| | | case 4: // 弹射 |
| | | return new BounceBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack,onHit); |
| | | return new BounceBulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit); |
| | | default: |
| | | return new BulletCurve(caster, skillConfig, bulletEffect, target, onHit); |
| | | return new BulletCurve(caster, skillConfig, bulletEffect, target, tagUseSkillAttack, onHit); |
| | | } |
| | | } |
| | | } |
| | |
| | | private Vector2 outPos; // 屏幕外延长点(本地坐标) |
| | | private bool hitTriggered = false; // 是否已触发onHit |
| | | |
| | | public PenetrateBulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer effectPlayer, RectTransform target, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit) |
| | | : base(caster, skillConfig, effectPlayer, target, onHit) { } |
| | | public PenetrateBulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer effectPlayer, RectTransform target, HB427_tagSCUseSkill tagUseSkillAttack, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit) |
| | | : base(caster, skillConfig, effectPlayer, target, tagUseSkillAttack, onHit) { } |
| | | |
| | | /// <summary> |
| | | /// 初始化弹道参数 |
| | |
| | | if (!hitTriggered) |
| | | { |
| | | hitTriggered = true; |
| | | onHit?.Invoke(0, null); |
| | | onHit?.Invoke(0, hurts); |
| | | } |
| | | } |
| | | bulletTrans.anchoredPosition = pos; |
| | |
| | | private Vector2 start; |
| | | private Vector2 end; |
| | | |
| | | public StraightBulletCurve(BattleObject caster, SkillConfig skillConfig, BattleEffectPlayer bulletEffect, RectTransform target, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit) |
| | | : base(caster, skillConfig, bulletEffect, target, onHit) { } |
| | | 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) { } |
| | | |
| | | public override void Reset() |
| | | { |
| | |
| | | if (t >= 1f) |
| | | { |
| | | finished = true; |
| | | onHit?.Invoke(0, null); |
| | | onHit?.Invoke(0, hurts); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | public override void Play(Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> _onHit) |
| | | { |
| | | base.Play(_onHit); |
| | | // 弹射 另外的做法了 |
| | | if (skillConfig.effectType == SkillEffectType.Bullet && skillConfig.BulletPath == 4) |
| | | { |
| | |
| | | Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID); |
| | | return; |
| | | } |
| | | ShotToTarget(targetObject, _onHit); |
| | | ShotToTarget(targetObject); |
| | | } |
| | | // 普通的做法 |
| | | // 普通的做法 区分打向阵营或者打向个体 |
| | | else |
| | | { |
| | | Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHitFormation = (_hitIndex, _hurtList) => |
| | | { |
| | | _onHit?.Invoke(_hitIndex, tagUseSkillAttack.HurtList.ToList()); |
| | | onHit?.Invoke(_hitIndex, tagUseSkillAttack.HurtList.ToList()); |
| | | }; |
| | | switch (skillConfig.castMode) |
| | | { |
| | |
| | | continue; |
| | | } |
| | | |
| | | ShotToTarget(target, _onHit); |
| | | ShotToTarget(target); |
| | | } |
| | | break; |
| | | case SkillCastMode.Allies: |
| | |
| | | } |
| | | |
| | | caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffectId, targetObj.heroGo.transform); |
| | | caster.battleField.battleEffectMgr.PlayEffect(targetObj.ObjID, skillConfig.ExplosionEffect2, targetObj.heroGo.transform); |
| | | } |
| | | |
| | | // caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.ExplosionEffectId, target); |
| | | }); |
| | | |
| | | bulletCurves.Add(bulletCurve); |
| | | |
| | | } |
| | | |
| | | protected void ShotToTarget(BattleObject target, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> _onHit) |
| | | protected void ShotToTarget(BattleObject target) |
| | | { |
| | | BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.BulletEffectId, caster.effectNode); |
| | | BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.BulletEffectId, caster.heroRectTrans); |
| | | RectTransform effectTrans = effectPlayer.transform as RectTransform; |
| | | |
| | | var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, effectPlayer, target.heroRectTrans, tagUseSkillAttack, (index, hitList) => |
| | | { |
| | | // 击中就销毁子弹 子弹不需要自动销毁 配置表里autoDestroy为false |
| | | // 表现子弹飞行到目标位置 |
| | | onHit?.Invoke(index, hitList); |
| | | |
| | | // 击中就销毁子弹 |
| | | caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.BulletEffectId, effectPlayer); |
| | | _onHit?.Invoke(index, hitList); |
| | | // 播放子弹爆炸特效 |
| | | |
| | | 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(targetObj.ObjID, skillConfig.ExplosionEffect2, targetObj.heroGo.transform); |
| | | } |
| | | }); |
| | | |
| | | bulletCurves.Add(bulletCurve); |
| | | } |
| | | |
| | | |
| | | |
| | | public override void Run() |
| | | { |
| | | foreach (var bulletCurve in bulletCurves) |
| | |
| | | public NormalSkillEffect(SkillConfig _skillConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack) |
| | | : base(_skillConfig, _caster, _tagUseSkillAttack) |
| | | { |
| | | |
| | | |
| | | } |
| | | |
| | | |
| | | // 技能动作第一帧 |
| | | // 不用理会回调 |
| | | public override void Play(Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> _onHit) |
| | | { |
| | | |
| | | // // 特效炸开在阵容的中间的回调 |
| | | // Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> 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; |
| | | // } |
| | | |
| | | // 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<HB427_tagSCUseSkill.tagSCUseSkillHurt>() { 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); |
| | | // } |
| | | // 播放技能特效 |
| | | BattleEffectPlayer battleEffectPlayer = caster.battleField.battleEffectMgr.PlayEffect( |
| | | caster.ObjID, |
| | | skillConfig.EffectId, |
| | | caster.heroGo.transform |
| | | ); |
| | | } |
| | | |
| | | protected void CastInTarget(RectTransform target, Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> _onHit) |
| | | { |
| | | // EffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.EffectId, caster.effectNode); |
| | | |
| | | // RectTransform effectTrans = effectPlayer.transform as RectTransform; |
| | | |
| | | // _onHit?.Invoke(0, null); |
| | | |
| | | // // 销毁自身上的特效应该是等特效播放完毕之后 |
| | | // // caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.EffectId, effectPlayer); |
| | | // // 播放受击特效 |
| | | // caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.ExplotionEffectId, target); |
| | | |
| | | } |
| | | |
| | | public override void Run() |
| | | { |
| | | base.Run(); |
| | | } |
| | | |
| | | public override void OnMiddleFrameEnd(int times, int hitIndex) |
| | | { |
| | | for (int i = 0; i < tagUseSkillAttack.HurtList.Length; i++) |
| | | { |
| | | var hurt = tagUseSkillAttack.HurtList[i]; |
| | | BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID); |
| | | if (target == null) |
| | | { |
| | | Debug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID); |
| | | continue; |
| | | } |
| | | |
| | | caster.battleField.battleEffectMgr.PlayEffect(target.ObjID, skillConfig.ExplosionEffectId, target.heroGo.transform); |
| | | caster.battleField.battleEffectMgr.PlayEffect(target.ObjID, skillConfig.ExplosionEffect2, target.heroGo.transform); |
| | | } |
| | | |
| | | onHit?.Invoke(hitIndex, tagUseSkillAttack.HurtList.ToList()); |
| | | } |
| | | |
| | | public override void OnMiddleFrameStart(int times) |
| | | { |
| | | |
| | | } |
| | | } |
| | |
| | | protected BattleObject caster; |
| | | protected HB427_tagSCUseSkill tagUseSkillAttack;// 目标列表 |
| | | |
| | | protected Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> onHit; |
| | | |
| | | public SkillEffect(SkillConfig _skillConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack) |
| | | { |
| | | skillConfig = _skillConfig; |
| | |
| | | // |
| | | public virtual void Play(Action<int, List<HB427_tagSCUseSkill.tagSCUseSkillHurt>> _onHit) |
| | | { |
| | | |
| | | onHit = _onHit; |
| | | } |
| | | |
| | | public virtual void Run() |
| | | { |
| | | |
| | | } |
| | | |
| | | public virtual void OnMiddleFrameEnd(int times, int hitIndex) |
| | | { |
| | | |
| | | } |
| | | |
| | | public virtual void OnMiddleFrameStart(int times) |
| | | { |
| | | |
| | | } |
| | | } |
| | |
| | | { |
| | | public static SkillEffect CreateSkillEffect(BattleObject caster, SkillConfig skillConfig, HB427_tagSCUseSkill 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; |
| | | } |
| | | } |
| | |
| | | { |
| | | var fightObj = lineUp.ObjList[i]; |
| | | TeamHero hero = new TeamHero(fightObj, this); |
| | | tempHeroes[fightObj.PosNum] = hero; |
| | | serverHeroes[fightObj.PosNum] = hero; |
| | | tempHeroes[hero.positionNum] = hero; |
| | | serverHeroes[hero.positionNum] = hero; |
| | | } |
| | | else |
| | | { |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using Spine.Unity; |
| | | using UnityEngine; |
| | | using UnityEngine.UI; |
| | | |
| | | |
| | | |
| | | /// <summary> |
| | | /// 特效穿透阻挡器 |
| | |
| | | { |
| | | [Tooltip("是否在UI层级下自动调整排序顺序")] |
| | | public bool autoAdjustSorting = true; |
| | | |
| | | |
| | | [Tooltip("特效渲染器,如果为空则自动获取")] |
| | | public List<Renderer> effectRenderers = new List<Renderer>(); |
| | | |
| | | |
| | | [Tooltip("自定义排序顺序,仅在不自动调整时有效")] |
| | | public int customSortingOrder = 0; |
| | | |
| | | |
| | | [Tooltip("自定义排序层,为空则使用默认UI层")] |
| | | public string customSortingLayer = "UI"; |
| | | |
| | | |
| | | [Tooltip("特效所属的Canvas,如果为空则查找父级Canvas")] |
| | | public Canvas parentCanvas; |
| | | |
| | | |
| | | [Tooltip("特效在Canvas中的排序偏移量")] |
| | | public int sortingOrderOffset = 1; |
| | | |
| | | |
| | | public int canvasSortingOrder = 0; |
| | | |
| | | public int renderQueue = 3000;//默认值 |
| | | |
| | | |
| | | public Action<string, int> onSortingChanged; |
| | | |
| | | private void Awake() |
| | | { |
| | | transform.GetComponentsInChildren(true, effectRenderers); |
| | |
| | | ApplySortingSettings(customSortingOrder, customSortingLayer); |
| | | } |
| | | } |
| | | |
| | | |
| | | private void OnEnable() |
| | | { |
| | | if (autoAdjustSorting) |
| | |
| | | UpdateSortingOrder(); |
| | | } |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 更新排序顺序,确保特效显示在当前UI界面上方 |
| | | /// </summary> |
| | | public void UpdateSortingOrder() |
| | | { |
| | | if (!autoAdjustSorting) return; |
| | | |
| | | |
| | | // 获取父级Canvas的排序顺序 |
| | | if (parentCanvas != null) |
| | | { |
| | |
| | | // 将特效的排序顺序设置为Canvas排序顺序加上偏移量 |
| | | ApplySortingSettings(canvasSortingOrder + sortingOrderOffset, customSortingLayer); |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 应用排序设置到所有渲染器和粒子系统 |
| | | /// </summary> |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | onSortingChanged?.Invoke(sortingLayer, sortingOrder); |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 手动设置排序顺序 |
| | | /// </summary> |
| | |
| | | { |
| | | customSortingLayer = sortingLayer; |
| | | } |
| | | |
| | | |
| | | autoAdjustSorting = false; |
| | | ApplySortingSettings(customSortingOrder, customSortingLayer); |
| | | } |
| | | |
| | | |
| | | /// <summary> |
| | | /// 设置父级Canvas |
| | | /// </summary> |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | #if UNITY_EDITOR |
| | | [ContextMenu("Apply")] |
| | | public void Apply() |
| | |
| | | { |
| | | DelayFrameInternal(1, action); |
| | | } |
| | | |
| | | public static void DelayTime(this GameObject go, float time, Action action) |
| | | { |
| | | DelayTimeInternal(time, action); |
| | | } |
| | | |
| | | public static void DelayTime(this Component cmp, float time, Action action) |
| | | { |
| | | DelayTimeInternal(time, action); |
| | | } |
| | | |
| | | private async static UniTask DelayTimeInternal(float time, Action action) |
| | | { |
| | | if (time <= 0f) |
| | | { |
| | | action?.Invoke(); |
| | | return; |
| | | } |
| | | await UniTask.Delay(TimeSpan.FromSeconds(time)); |
| | | action?.Invoke(); |
| | | } |
| | | } |