yyl
2025-07-29 b0a5d4688f1af73b5ad03ccc2df11c9aac1523a9
Main/Component/UI/Effect/EffectPlayer.cs
@@ -6,15 +6,43 @@
using Spine;
using UnityEngine.UI;
// 特效播放器,对象池管理:unity特效和spine特效都是做好的预制体
// unity特效预制体是特效师在制作的时候生成的,unity特效约定挂载设置播放时长脚本
// spine特效是特效师制作的动画文件可直接加载用,制作成预制体可增加BoneFollower之类的进行逻辑处理
// 非UI特效使用,UI特效UIEffectPlayer继承EffectPlayer,后续如果逻辑冲突大则不用继承
public class EffectPlayer : MonoBehaviour
{
    public int effectId;
    [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 Action<EffectPlayer> onDestroy;
    public float speedRate = 1f;
    [Header("播放完毕立即回收")]
    public bool isReleaseImmediately = true;  //界面特效一般不需要自我销毁,跟随界面或者父对象销毁就行
    public Action<EffectPlayer> onDestroy;
    [HideInInspector] public Canvas canvas = null;
@@ -31,21 +59,33 @@
    protected List<Renderer> rendererList = new List<Renderer>();
    protected SkeletonGraphic spineComp;
    protected Spine.AnimationState spineAnimationState;
    protected void Start()
    public GameObjectPoolManager.GameObjectPool pool;
    public Action onComplete;
    protected virtual void OnEnable()
    {
        ReStart();
        if (spineComp != null)
        {
            //隐藏,会有静态显示问题
            spineComp.enabled = false;
        }
    }
    protected void InitCompnent()
    protected void InitComponent(bool showLog = true)
    {
        if (effectId <= 0)
        {
            effectConfig = null;
            Debug.LogError("EffectPlayer effectId is not set");
#if UNITY_EDITOR
            if (showLog)
            {
                Debug.LogError("EffectPlayer effectId is not set");
            UnityEditor.Selection.activeGameObject = gameObject;
            UnityEditor.EditorGUIUtility.PingObject(gameObject);
            }
#endif
            return;
        }
@@ -54,8 +94,8 @@
        if (null == effectConfig)
        {
            Debug.LogError("could not find effect config, effect id is " + effectId);
#if UNITY_EDITOR
            Debug.LogError("could not find effect config, effect id is " + effectId);
            UnityEditor.Selection.activeGameObject = gameObject;
            UnityEditor.EditorGUIUtility.PingObject(gameObject);
#endif
@@ -63,69 +103,93 @@
        }
        Clear();
        return;
    }
    protected virtual void Clear()
    {
        particleList.Clear();
        animatorList.Clear();
        rendererList.Clear();
        spineComp = null;
        if (effectConfig.isSpine != 0)
        {
            spineComp = gameObject.GetComponentInChildren<SkeletonGraphic>(true);
        }
        else
        {
            //  收集组件
            particleList.AddRange(gameObject.GetComponentsInChildren<ParticleSystem>(true));
            animatorList.AddRange(gameObject.GetComponentsInChildren<Animator>(true));
        }
        rendererList.AddRange(gameObject.GetComponentsInChildren<Renderer>(true));
        pool = null;
    }
    public void Stop()
    public virtual void Stop()
    {
        if (null != effectTarget)
        {
            DestroyImmediate(effectTarget);
            // 如果使用了特效预制体池,则归还到池中
            if (pool != null)
            {
                pool.Release(effectTarget);
            }
            effectTarget = null;
        }
        isInit = false;
        particleList.Clear();
        animatorList.Clear();
        rendererList.Clear();
        spineComp = null;
        Clear();
        onComplete?.Invoke();
    }
    public void Play()
    {
        ReStart();
    }
    protected void ReStart()
    public virtual void Play(bool showLog = true)
    {
        if (!isInit)
        {
            InitComponent(showLog);
            isInit = true;
            InitCompnent();
        }
        else
        {
            //避免重复创建
            if (!this.gameObject.activeSelf)
            {
                this.gameObject.SetActive(true);
            }
            return;
        }
        if (EffectMgr.Instance.IsNotShowBySetting(effectId))
        if (EffectMgr.IsNotShowBySetting(effectId))
        {
            return;
        }
        if (null != effectTarget)
        {
            DestroyImmediate(effectTarget);
            if (pool != null)
                pool.Release(effectTarget);
            effectTarget = null;
        }
        //   YYL TODO
        //   在这里考虑用池的话可能走配置好一点 原本的是无论如何都走池 但是实际上有些特效并不需要
        if (!this.gameObject.activeSelf)
        {
            this.gameObject.SetActive(true);
        }
        // 加载特效资源
        PlayerEffect(true);
    }
    protected virtual void PlaySpineEffect()
    {
        spineComp = gameObject.GetComponentInChildren<SkeletonGraphic>(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<GameObject>("UIEffect/" + effectConfig.packageName, effectConfig.fxName);
        if (effectPrefab == null)
        {
@@ -133,14 +197,43 @@
            return;
        }
        // 实例化特效
        effectTarget = Instantiate(effectPrefab, transform);
        if (effectConfig.isSpine == 0)
        {
            //unity特效 判断预制体是否挂载EffectTime
            var timeObj = effectPrefab.GetComponent<EffectTime>();
            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<ParticleSystem>(true));
            animatorList.AddRange(gameObject.GetComponentsInChildren<Animator>(true));
            rendererList.AddRange(gameObject.GetComponentsInChildren<Renderer>(true));
            OnUnityAnimationComplete();
        }
        if (null == canvas)
            canvas = GetComponentInParent<Canvas>();
        // 添加特效穿透阻挡器
        blocker = effectTarget.AddMissingComponent<EffectPenetrationBlocker>();
@@ -149,12 +242,6 @@
        if (canvas != null)
        {
            blocker.SetParentCanvas(canvas);
        }
        // 自动销毁
        if (effectConfig.autoDestroy != 0)
        {
            Destroy(gameObject, effectConfig.destroyDelay);
        }
    }
@@ -166,11 +253,51 @@
            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<EffectTime>();
        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)
@@ -182,11 +309,23 @@
        else
        {
            effectPlayer = parent.AddMissingComponent<EffectPlayer>();
            effectPlayer.effectId = effectId;
        }
        effectPlayer.effectId = effectId;
        effectPlayer.SetActive(true);
        return effectPlayer;
    }
    /// <summary>
    /// 设置游戏对象激活状态
    // /// </summary>
    // public void SetActive(bool active)
    // {
    //     if (gameObject != null)
    //     {
    //         gameObject.SetActive(active);
    //     }
    // }
    public void Pause()
    {
@@ -284,4 +423,6 @@
            return;
        }
    }
}