using System; using System.Collections; using System.Collections.Generic; using Spine.Unity; using UnityEngine; using Spine; using UnityEngine.UI; // 特效播放器,对象池管理:unity特效和spine特效都是做好的预制体 // unity特效预制体是特效师在制作的时候生成的,unity特效必须挂载设置播放时长脚本 EffectTime // spine特效是特效师制作的动画文件可直接加载用,制作成预制体可增加BoneFollower之类的进行逻辑处理 // 非UI特效使用,UI特效UIEffectPlayer继承EffectPlayer,后续如果逻辑冲突大则不用继承 public class EffectPlayer : MonoBehaviour { [SerializeField] private int m_EffectID; public int effectId { get { return m_EffectID; } set { if (value != m_EffectID) { isInit = false; m_EffectID = value; } } } public EffectConfig effectConfig; public float speedRate = 1f; [Header("播放完毕立即回收")] public bool isReleaseImmediately = true; //界面特效一般不需要自我销毁,跟随界面或者父对象销毁就行 public Action onDestroy; [HideInInspector] public Canvas canvas = null; [HideInInspector] public GameObject effectTarget = null; protected EffectPenetrationBlocker blocker = null; protected bool isInit = false; protected List particleList = new List(); protected List animatorList = new List(); protected List rendererList = new List(); protected SkeletonGraphic spineComp; protected Spine.AnimationState spineAnimationState; public GameObjectPoolManager.GameObjectPool pool; public Action onComplete; protected virtual void OnEnable() { if (spineComp != null) { //隐藏,会有静态显示问题 spineComp.enabled = false; } } protected void InitComponent(bool showLog = true) { if (effectId <= 0) { effectConfig = null; #if UNITY_EDITOR if (showLog) { Debug.LogError("EffectPlayer effectId is not set"); UnityEditor.Selection.activeGameObject = gameObject; UnityEditor.EditorGUIUtility.PingObject(gameObject); } #endif return; } effectConfig = EffectConfig.Get(effectId); if (null == effectConfig) { #if UNITY_EDITOR Debug.LogError("could not find effect config, effect id is " + effectId); UnityEditor.Selection.activeGameObject = gameObject; UnityEditor.EditorGUIUtility.PingObject(gameObject); #endif return; } Clear(); return; } protected virtual void Clear() { particleList.Clear(); animatorList.Clear(); rendererList.Clear(); spineComp = null; pool = null; } public virtual void Stop() { if (null != effectTarget) { // 如果使用了特效预制体池,则归还到池中 if (pool != null) { pool.Release(effectTarget); } effectTarget = null; } isInit = false; Clear(); onComplete?.Invoke(); } public virtual void Play(bool showLog = true) { if (!isInit) { InitComponent(showLog); isInit = true; } else { //避免重复创建 if (!this.gameObject.activeSelf) { this.gameObject.SetActive(true); } return; } if (EffectMgr.IsNotShowBySetting(effectId)) { return; } if (null != effectTarget) { if (pool != null) pool.Release(effectTarget); effectTarget = null; } if (!this.gameObject.activeSelf) { this.gameObject.SetActive(true); } PlayerEffect(true); } protected virtual void PlaySpineEffect() { spineComp = gameObject.GetComponentInChildren(true); spineComp.raycastTarget = false; spineComp.Initialize(true); spineAnimationState = spineComp.AnimationState; spineAnimationState.Complete -= OnSpineAnimationComplete; spineAnimationState.Complete += OnSpineAnimationComplete; // 外层控制具体播放哪个动画 spineComp.enabled = true; return; } protected virtual void PlayerEffect(bool playSpine) { var effectPrefab = ResManager.Instance.LoadAsset("UIEffect/" + effectConfig.packageName, effectConfig.fxName); if (effectPrefab == null) { Debug.LogError($"加载UI特效失败: {effectConfig.packageName}"); return; } if (effectConfig.isSpine == 0) { //unity特效 判断预制体是否挂载EffectTime var timeObj = effectPrefab.GetComponent(); if (null == timeObj) { Debug.LogError($"{effectPrefab.name}预制体没有挂载EffectTime"); return; } } // 从特效预制体池获取特效 pool = GameObjectPoolManager.Instance.RequestPool(effectPrefab); effectTarget = pool.Request(); // 设置父节点和位置 effectTarget.transform.SetParent(transform); effectTarget.transform.localPosition = Vector3.zero; effectTarget.transform.localScale = Vector3.one; effectTarget.transform.localRotation = Quaternion.identity; effectTarget.name = $"Effect_{effectConfig.fxName}"; if (effectConfig.isSpine != 0 && playSpine) { //预制体 PlaySpineEffect(); } else { //挂载组件后 开始收集 particleList.AddRange(gameObject.GetComponentsInChildren(true)); animatorList.AddRange(gameObject.GetComponentsInChildren(true)); rendererList.AddRange(gameObject.GetComponentsInChildren(true)); OnUnityAnimationComplete(); } if (null == canvas) canvas = GetComponentInParent(); // 添加特效穿透阻挡器 blocker = effectTarget.AddMissingComponent(); // 如果没有canvas的话 正常是因为不在BattleWin下面的节点 意思就是当前没有显示 等到切回战斗的时候再通过BattleField.UpdateCanvas来更新 if (canvas != null) { blocker.SetParentCanvas(canvas); } } protected void OnDestroy() { if (onDestroy != null) { onDestroy.Invoke(this); onDestroy = null; } // 停止特效并归还到池中 Stop(); if (spineAnimationState != null) { spineAnimationState.Complete -= OnSpineAnimationComplete; } } //单次播放完毕就会触发,即使是循环 protected virtual void OnSpineAnimationComplete(Spine.TrackEntry trackEntry) { if (isReleaseImmediately) { spineComp.enabled = false; Stop(); } } private void OnUnityAnimationComplete() { var timeObj = effectTarget.GetComponent(); if (!timeObj.isLoop) { this.SetWait(timeObj.playTime); this.DoWaitRestart(); this.OnWaitCompelete(OnEffectComplete); } } private void OnEffectComplete(Component comp) { this.DoWaitStop(); if (isReleaseImmediately) Stop(); } // 创建后的特效会自动隐藏 需要手动调用Play才能播放 public static EffectPlayer Create(int effectId, Transform parent, bool createNewChild = false) { // 直接创建特效播放器,不使用对象池 EffectPlayer effectPlayer = null; if (createNewChild) { GameObject newGo = new GameObject("EffectPlayer_" + effectId); newGo.transform.SetParent(parent, false); effectPlayer = newGo.AddComponent(); } else { effectPlayer = parent.AddMissingComponent(); } effectPlayer.effectId = effectId; effectPlayer.SetActive(true); return effectPlayer; } /// /// 设置游戏对象激活状态 // /// // public void SetActive(bool active) // { // if (gameObject != null) // { // gameObject.SetActive(active); // } // } public void Pause() { if (effectTarget == null) return; // Spine动画 // var spineGraphics = effectTarget.GetComponentsInChildren(true); // foreach (var sg in spineGraphics) if (spineComp != null) { spineComp.timeScale = 0f; } // Animator动画 foreach (var animator in animatorList) { animator.speed = 0f; } // 粒子特效 foreach (var ps in particleList) { ps.Pause(); } } public void Resume() { if (effectTarget == null) return; if (spineComp != null) { spineComp.timeScale = speedRate; } // Animator动画 foreach (var animator in animatorList) { animator.speed = speedRate; } // 粒子特效 foreach (var ps in particleList) { ps.Play(); } } public bool IsFinish() { if (effectTarget == null) return true; // Spine动画 if (!spineComp.AnimationState.GetCurrent(0).IsComplete) { return false; } // Animator动画 foreach (var animator in animatorList) { AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0); // 循环动画不考虑结束的问题 if (!stateInfo.loop && stateInfo.normalizedTime < 1f) { return false; } } // 粒子特效 foreach (var ps in particleList) { if (ps.IsAlive()) { return false; } } return true; } /// /// 设置遮罩(支持RectMask2D、Mask、SmoothMask等) /// public void SetMask(RectTransform maskArea = null) { if (effectTarget == null || blocker == null) return; // 优先使用传入的maskArea if (maskArea != null) { blocker.PerformMask(maskArea); return; } } }