|  |  | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public bool isBindBone = false; | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     public bool isRedCamp = true; | 
 |  |  |     public EffectConfig effectConfig; | 
 |  |  |  | 
 |  |  |     public float speedRate = 1f; | 
 |  |  |     public float speedRate = 1.5f; | 
 |  |  |  | 
 |  |  |     private float m_Alpha = 1f; | 
 |  |  |  | 
 |  |  |     public float Alpha | 
 |  |  |     { | 
 |  |  |         get | 
 |  |  |         { | 
 |  |  |             return m_Alpha; | 
 |  |  |         } | 
 |  |  |         set | 
 |  |  |         { | 
 |  |  |             if (value == m_Alpha) | 
 |  |  |                 return; | 
 |  |  |  | 
 |  |  |             m_Alpha = value; | 
 |  |  |             OnAlphaChanged(); | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private void OnAlphaChanged() | 
 |  |  |     { | 
 |  |  |         if (spineComp != null) | 
 |  |  |         { | 
 |  |  |             var skeleton = spineComp.Skeleton; | 
 |  |  |             skeleton.A = Alpha; | 
 |  |  |             spineComp.LateUpdate(); | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         for (int i = 0; i < rendererList.Count; i++) | 
 |  |  |         { | 
 |  |  |             var renderer = rendererList[i]; | 
 |  |  |             if (renderer != null && renderer.material != null && renderer.material.HasProperty("_Color")) | 
 |  |  |             { | 
 |  |  |                 Color color = renderer.material.color; | 
 |  |  |                 color.a = Alpha; | 
 |  |  |                 renderer.material.color = color; | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     [Header("播放完毕立即回收")] | 
 |  |  |     public bool isReleaseImmediately = false;  //界面特效一般不需要自我销毁,跟随界面或者父对象销毁就行 | 
 |  |  |  | 
 |  |  |     public Action<BattleEffectPlayer> onDestroy; | 
 |  |  |  | 
 |  |  |     [HideInInspector] public Canvas canvas = null; | 
 |  |  |  | 
 |  |  |     [HideInInspector] public GameObject effectTarget = null; | 
 |  |  |  | 
 |  |  |     protected EffectPenetrationBlocker blocker = null; | 
 |  |  |     protected RendererAdjuster blocker = null; | 
 |  |  |  | 
 |  |  |     protected bool isInit = false; | 
 |  |  |  | 
 |  |  | 
 |  |  |  | 
 |  |  |     public Action onComplete; | 
 |  |  |  | 
 |  |  |     private bool isPlaying = false; | 
 |  |  |  | 
 |  |  |     private float timer = 0f; | 
 |  |  |  | 
 |  |  |     protected virtual void OnEnable() | 
 |  |  |     { | 
 |  |  |         if (spineComp != null) | 
 |  |  |         { | 
 |  |  |             //隐藏,会有静态显示问题 | 
 |  |  |             spineComp.enabled = false; | 
 |  |  |         } | 
 |  |  |         // if (spineComp != null) | 
 |  |  |         // { | 
 |  |  |         //     //隐藏,会有静态显示问题 | 
 |  |  |         //     spineComp.enabled = false; | 
 |  |  |         // } | 
 |  |  |  | 
 |  |  |         ApplySortingOrder(); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  | 
 |  |  |         } | 
 |  |  |         //  有特效可能带spine又带unity特效的情况 | 
 |  |  |         spineComp = gameObject.GetComponentInChildren<SkeletonAnimation>(true); | 
 |  |  |  | 
 |  |  |         if (effectConfig.effectPos != null && effectConfig.effectPos.Length >= 2) | 
 |  |  |         { | 
 |  |  |             rectTrans.anchoredPosition += new Vector2((isRedCamp ? 1f : -1f) * effectConfig.effectPos[0], effectConfig.effectPos[1]); | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         if (effectConfig.effectScale > 0f) | 
 |  |  |         { | 
 |  |  |             rectTrans.localScale *= effectConfig.effectScale; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         spineComp.loop = effectConfig.isLoop != 0; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     protected virtual void Clear() | 
 |  |  | 
 |  |  |         onComplete?.Invoke(); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public Func<bool> funcIsHeroFront; | 
 |  |  |  | 
 |  |  |     public void SetSortingOrder(Func<bool> _isHeroFrontCallback) | 
 |  |  |     { | 
 |  |  |         funcIsHeroFront = _isHeroFrontCallback; | 
 |  |  |  | 
 |  |  |         ApplySortingOrder(); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     public void ApplySortingOrder() | 
 |  |  |     { | 
 |  |  |         if (null != blocker && effectConfig != null && funcIsHeroFront != null) | 
 |  |  |         { | 
 |  |  |             bool isEffectFront = effectConfig.frontBack == 1; | 
 |  |  |  | 
 |  |  |             bool isHeroFront = funcIsHeroFront(); | 
 |  |  |  | 
 |  |  |             int finalSortingOrder = isHeroFront ? | 
 |  |  |                 (isEffectFront ? BattleConst.ActiveHeroActionSortingOrder : BattleConst.ActiveHeroBackSortingOrder) : (isEffectFront ? BattleConst.UnactiveHeroFrontSortingOrder : BattleConst.UnactiveHeroBackSortingOrder); | 
 |  |  |  | 
 |  |  |  | 
 |  |  |             blocker.SetSortingOrder(finalSortingOrder); | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public virtual void Play(bool showLog = true) | 
 |  |  |     { | 
 |  |  |  | 
 |  |  |  | 
 |  |  |         if (!isInit) | 
 |  |  |         { | 
 |  |  |             InitComponent(showLog); | 
 |  |  |             isInit = true; | 
 |  |  |         } | 
 |  |  |         else | 
 |  |  |         { | 
 |  |  |             //避免重复创建 | 
 |  |  |             if (!this.gameObject.activeSelf) | 
 |  |  |             { | 
 |  |  |                 InitComponent(showLog); | 
 |  |  |                 isInit = true; | 
 |  |  |                 this.gameObject.SetActive(true); | 
 |  |  |             } | 
 |  |  |             else | 
 |  |  |             { | 
 |  |  |                 //避免重复创建 | 
 |  |  |                 if (!this.gameObject.activeSelf) | 
 |  |  |                 { | 
 |  |  |                     this.gameObject.SetActive(true); | 
 |  |  |                 } | 
 |  |  |                 return; | 
 |  |  |             } | 
 |  |  |             return; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         if (EffectMgr.IsNotShowBySetting(effectId)) | 
 |  |  |         { | 
 |  |  | 
 |  |  |             this.gameObject.SetActive(true); | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         PlayEffect(); | 
 |  |  |          | 
 |  |  |         isPlaying = true; | 
 |  |  |         timer = 0f; | 
 |  |  |  | 
 |  |  |         PlayEffect(); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     public void Run() | 
 |  |  |     { | 
 |  |  |         if (null == effectConfig) | 
 |  |  |         { | 
 |  |  |             return; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         if (!isPlaying) | 
 |  |  |         { | 
 |  |  |             return; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         if (effectConfig.autoDestroy != 0) | 
 |  |  |         { | 
 |  |  |             timer += Time.deltaTime * speedRate; | 
 |  |  |             if (timer >= effectConfig.destroyDelay) | 
 |  |  |             { | 
 |  |  |                 GameObject.DestroyImmediate(gameObject); | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     protected virtual void PlayEffect() | 
 |  |  | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         //  如果delay小于等于0 那会立刻执行 | 
 |  |  |         this.DelayTime(effectConfig.delayPlay, () => | 
 |  |  |         this.DelayTime(effectConfig.delayPlay / speedRate, () => | 
 |  |  |         { | 
 |  |  |             PlayEffectInternal(); | 
 |  |  |         }); | 
 |  |  | 
 |  |  |         { | 
 |  |  |             PlayUnityEffect(); | 
 |  |  |         } | 
 |  |  |         OnAlphaChanged(); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     protected void PlaySpineEffect() | 
 |  |  | 
 |  |  |         spineComp.Initialize(true); | 
 |  |  |         spineComp.timeScale = speedRate; | 
 |  |  |  | 
 |  |  |         spineComp.skeleton.A = Alpha; | 
 |  |  |  | 
 |  |  |         spineAnimationState = spineComp.state; | 
 |  |  |         spineAnimationState.Complete -= OnSpineAnimationComplete; | 
 |  |  |         spineAnimationState.Complete += OnSpineAnimationComplete; | 
 |  |  |  | 
 |  |  |  | 
 |  |  |         if (null == canvas) | 
 |  |  |             canvas = GetComponentInParent<Canvas>(); | 
 |  |  |  | 
 |  |  |         // 添加特效穿透阻挡器 | 
 |  |  |         blocker = spineComp.AddMissingComponent<EffectPenetrationBlocker>(); | 
 |  |  |         blocker = spineComp.AddMissingComponent<RendererAdjuster>(); | 
 |  |  |  | 
 |  |  |         blocker.onSortingChanged = OnSortingChanged; | 
 |  |  |  | 
 |  |  |         //  如果没有canvas的话 正常是因为不在BattleWin下面的节点 意思就是当前没有显示 等到切回战斗的时候再通过BattleField.UpdateCanvas来更新 | 
 |  |  |         if (canvas != null) | 
 |  |  |         { | 
 |  |  |             blocker.SetParentCanvas(canvas); | 
 |  |  |         } | 
 |  |  |         ApplySortingOrder(); | 
 |  |  |  | 
 |  |  |         spineComp.enabled = true; | 
 |  |  |  | 
 |  |  |         spineComp.timeScale = speedRate; | 
 |  |  |         spineAnimationState.TimeScale = speedRate; | 
 |  |  |  | 
 |  |  |         Spine.Animation animation = spineAnimationState.Data.SkeletonData.Animations.First(); | 
 |  |  |         spineAnimationState.SetAnimation(0, animation, effectConfig.isLoop != 0); | 
 |  |  | 
 |  |  |  | 
 |  |  |         OnUnityAnimationComplete(); | 
 |  |  |  | 
 |  |  |         if (null == canvas) | 
 |  |  |             canvas = GetComponentInParent<Canvas>(); | 
 |  |  |  | 
 |  |  |         // 添加特效穿透阻挡器 | 
 |  |  |         blocker = effectTarget.AddMissingComponent<EffectPenetrationBlocker>(); | 
 |  |  |         blocker = effectTarget.AddMissingComponent<RendererAdjuster>(); | 
 |  |  |  | 
 |  |  |         blocker.onSortingChanged = OnSortingChanged; | 
 |  |  |  | 
 |  |  |         //  如果没有canvas的话 正常是因为不在BattleWin下面的节点 意思就是当前没有显示 等到切回战斗的时候再通过BattleField.UpdateCanvas来更新 | 
 |  |  |         if (canvas != null) | 
 |  |  |         { | 
 |  |  |             blocker.SetParentCanvas(canvas); | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         SoundPlayer.Instance.PlayUIAudio(effectConfig.audio); | 
 |  |  |  | 
 |  |  | 
 |  |  |  | 
 |  |  |     public string sortingLayer; | 
 |  |  |     public int sortingOrder; | 
 |  |  |     public RectTransform rectTrans; | 
 |  |  |  | 
 |  |  |     protected void OnSortingChanged(string _sortingLayer, int _sortingOrder) | 
 |  |  |     { | 
 |  |  |         if (null == spineComp) | 
 |  |  |             return; | 
 |  |  |              | 
 |  |  |         sortingLayer = _sortingLayer; | 
 |  |  |         sortingOrder = _sortingOrder; | 
 |  |  |         // 处理排序变化 | 
 |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     //  创建后的特效会自动隐藏 需要手动调用Play才能播放 | 
 |  |  |     public static BattleEffectPlayer Create(int effectId, Transform parent, bool createNewChild = false) | 
 |  |  |     public static BattleEffectPlayer Create(int effectId, Transform parent, bool isRedCamp) | 
 |  |  |     { | 
 |  |  |         // 直接创建特效播放器,不使用对象池 | 
 |  |  |         BattleEffectPlayer BattleEffectPlayer = null; | 
 |  |  |         BattleEffectPlayer battleEffectPlayer = null; | 
 |  |  |  | 
 |  |  |         if (createNewChild) | 
 |  |  |         { | 
 |  |  |             GameObject newGo = new GameObject("BattleEffectPlayer_" + effectId); | 
 |  |  |             newGo.transform.SetParent(parent, false); | 
 |  |  |             BattleEffectPlayer = newGo.AddComponent<BattleEffectPlayer>(); | 
 |  |  |         } | 
 |  |  |         else | 
 |  |  |         { | 
 |  |  |             BattleEffectPlayer = parent.AddMissingComponent<BattleEffectPlayer>(); | 
 |  |  |         } | 
 |  |  |         GameObject newGo = new GameObject("BattleEffectPlayer_" + effectId); | 
 |  |  |         newGo.transform.SetParent(parent, false); | 
 |  |  |         battleEffectPlayer = newGo.AddComponent<BattleEffectPlayer>(); | 
 |  |  |         battleEffectPlayer.rectTrans = newGo.AddMissingComponent<RectTransform>(); | 
 |  |  |          | 
 |  |  |         battleEffectPlayer.effectId = effectId; | 
 |  |  |  | 
 |  |  |         BattleEffectPlayer.effectId = effectId; | 
 |  |  |         BattleEffectPlayer.SetActive(true); | 
 |  |  |         return BattleEffectPlayer; | 
 |  |  |         // 设置阵营 | 
 |  |  |         battleEffectPlayer.isRedCamp = isRedCamp; | 
 |  |  |  | 
 |  |  |         battleEffectPlayer.SetActive(true); | 
 |  |  |         return battleEffectPlayer; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /// <summary> | 
 |  |  | 
 |  |  |  | 
 |  |  |     public void Pause() | 
 |  |  |     { | 
 |  |  |         if (effectTarget == null) return; | 
 |  |  |         // if (effectTarget == null) return; | 
 |  |  |  | 
 |  |  |         // Spine动画 | 
 |  |  |         // var spineGraphics = effectTarget.GetComponentsInChildren<SkeletonGraphic>(true); | 
 |  |  | 
 |  |  |         if (spineComp != null) | 
 |  |  |         { | 
 |  |  |             spineComp.timeScale = 0f; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         if (spineAnimationState != null) | 
 |  |  |         { | 
 |  |  |             spineAnimationState.TimeScale = 0f; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         // Animator动画 | 
 |  |  | 
 |  |  |  | 
 |  |  |     public void Resume() | 
 |  |  |     { | 
 |  |  |         if (effectTarget == null) return; | 
 |  |  |         // if (effectTarget == null) return; | 
 |  |  |  | 
 |  |  |         if (spineComp != null) | 
 |  |  |         { | 
 |  |  |             spineComp.timeScale = speedRate; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         if (spineAnimationState != null) | 
 |  |  |         { | 
 |  |  |             spineAnimationState.TimeScale = speedRate; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         // Animator动画 | 
 |  |  | 
 |  |  |         return true; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /// <summary> | 
 |  |  |     /// 设置遮罩(支持RectMask2D、Mask、SmoothMask等) | 
 |  |  |     /// </summary> | 
 |  |  |     public void SetMask(RectTransform maskArea = null) | 
 |  |  |     public void SetSpeedRatio(float ratio) | 
 |  |  |     { | 
 |  |  |         if (effectTarget == null || blocker == null) | 
 |  |  |             return; | 
 |  |  |  | 
 |  |  |         // 优先使用传入的maskArea | 
 |  |  |         if (maskArea != null) | 
 |  |  |         speedRate = ratio; | 
 |  |  |         if (spineComp != null) | 
 |  |  |         { | 
 |  |  |             blocker.PerformMask(maskArea); | 
 |  |  |             return; | 
 |  |  |             spineComp.timeScale = speedRate; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         // Animator动画 | 
 |  |  |         foreach (var animator in animatorList) | 
 |  |  |         { | 
 |  |  |             animator.speed = speedRate; | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public void BindBone(SkeletonAnimation skeletonAnim, string v) | 
 |  |  |     { | 
 |  |  |         Bone bone = skeletonAnim.skeleton.FindBone(v); | 
 |  |  |  | 
 |  |  |         if (null == bone) | 
 |  |  |         { | 
 |  |  |              return; | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         isBindBone = true; | 
 |  |  |  | 
 |  |  |         BoneFollower boneFollower = gameObject.AddMissingComponent<BoneFollower>(); | 
 |  |  |         boneFollower.boneName = v; | 
 |  |  |         boneFollower.skeletonRenderer = skeletonAnim; | 
 |  |  |          | 
 |  |  |         boneFollower.followBoneRotation = false; | 
 |  |  |         boneFollower.followXYPosition = true; | 
 |  |  |         boneFollower.followZPosition = false; | 
 |  |  |         boneFollower.followLocalScale = false; | 
 |  |  |         boneFollower.followParentWorldScale = false; | 
 |  |  |         boneFollower.followSkeletonFlip = false; | 
 |  |  |  | 
 |  |  |         boneFollower.Initialize(); | 
 |  |  |         boneFollower.LateUpdate(); | 
 |  |  |     } | 
 |  |  | } |