lcy
9 天以前 485db99b5c51a971c173664cf6e808dc8424b0a0
Main/Component/UI/Effect/EffectPlayer.cs
@@ -5,11 +5,11 @@
using UnityEngine;
using Spine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks;
// 特效播放器,对象池管理:unity特效和spine特效都是做好的预制体
// unity特效预制体是特效师在制作的时候生成的,unity特效必须挂载设置播放时长脚本 EffectTime
// spine特效是特效师制作的动画文件可直接加载用,制作成预制体可增加BoneFollower之类的进行逻辑处理
// 非UI特效使用,UI特效UIEffectPlayer继承EffectPlayer,后续如果逻辑冲突大则不用继承
// 特效播放器,预制体对象池管理,unity的预制体池使用有问题(1个特效1个池但复用又低)后续修改
// unity特效《预制体》是特效师在制作的时候生成的不同预制体,unity特效必须挂载设置播放时长脚本 EffectTime
// spine特效是特效师制作的动画文件,可共同复用一个《预制体》
public class EffectPlayer : MonoBehaviour
{
    [SerializeField]
@@ -24,6 +24,7 @@
        {
            if (value != m_EffectID)
            {
                Stop();
                isInit = false;
                m_EffectID = value;
            }
@@ -36,7 +37,16 @@
    public float speedRate = 1f;
    [Header("是否循环播放spine特效")]
    public bool isPlaySpineLoop = false;
    [Header("是否在显示时播放")]
    public bool isPlayOnEnable = false;
    [Header("延迟播放(毫秒)")]
    public int playDelayTime = 0;
    public int playSpineAnimIndex = -1; //播放spine特效动画索引,代码控制
    [Header("播放完毕立即回收")]
@@ -51,7 +61,11 @@
    protected EffectPenetrationBlocker blocker = null;
    protected bool isInit = false;
    protected bool isPlaying = false;
    public bool isPlaying
    {
        get;
        protected set;
    }
    protected List<ParticleSystem> particleList = new List<ParticleSystem>();
@@ -68,10 +82,15 @@
    protected virtual void OnEnable()
    {
        if (spineComp != null)
        if (isPlayOnEnable)
        {
            Play(false);
        }
        else if (spineComp != null)
        {
            if (!isPlaying)
            {
            {
                //隐藏,会有静态显示问题
                spineComp.enabled = false;
            }
@@ -106,18 +125,25 @@
            return;
        }
        Clear();
        return;
    }
    protected virtual void Clear()
    {
        isInit = false;
        particleList.Clear();
        animatorList.Clear();
        rendererList.Clear();
        if (spineComp != null)
        {
            spineComp.skeletonDataAsset = null;
            // spineComp.Initialize(false);
            spineComp.Clear();
        }
        spineComp = null;
        pool = null;
    }
    public virtual void Stop()
@@ -135,17 +161,24 @@
        {
            spineComp.enabled = false;
        }
        isInit = false;
        isPlaying = false;
        Clear();
        onComplete?.Invoke();
        playSpineAnimIndex = -1;
    }
    public virtual void Play(bool showLog = true)
    protected void Release()
    {
        Stop();
        Clear();
    }
    public virtual void Play(bool showLog = true, bool closePMA = false)
    {
        isPlaying = true;
        if (!isInit)
        {
            InitComponent(showLog);
            //effeid 为0也初始化成功,避免重复处理,在变更effectid时会重新初始化
            isInit = true;
        }
        else
@@ -155,13 +188,20 @@
            {
                this.gameObject.SetActive(true);
            }
            //防范effeid 为0
            if (effectConfig != null && effectConfig.isSpine != 0)
            {
                PlaySpineEffect(closePMA);
            }
            return;
        }
        if (effectConfig == null)
            return;
        if (EffectMgr.IsNotShowBySetting(effectId))
        {
            return;
        }
            {
                return;
            }
        if (null != effectTarget)
        {
@@ -175,28 +215,118 @@
            this.gameObject.SetActive(true);
        }
        PlayerEffect(true);
        // 加载spine特效资源
        if (effectConfig.isSpine != 0)
        {
            PlaySpineEffect(closePMA);
        }
        else
        {
            PlayerEffect();
        }
        SoundPlayer.Instance.PlayUIAudio(effectConfig.audio);
    }
    protected virtual void PlaySpineEffect()
    // 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 void PlaySpineEffect(bool closePMA = false)
    {
        spineComp = gameObject.GetComponentInChildren<SkeletonGraphic>(true);
        spineComp.raycastTarget = false;
        spineComp.Initialize(true);
        spineAnimationState = spineComp.AnimationState;
        spineAnimationState.Complete -= OnSpineAnimationComplete;
        spineAnimationState.Complete += OnSpineAnimationComplete;
        // 外层控制具体播放哪个动画
        // 从特效预制体池获取特效
        if (spineComp == null)
        {
            spineComp = gameObject.AddMissingComponent<SkeletonGraphic>();
        }
        if (spineComp.skeletonDataAsset == null || spineAnimationState == null)
        {
            //LoadAsset 已经有缓存SkeletonDataAsset
            spineComp.skeletonDataAsset = ResManager.Instance.LoadAsset<SkeletonDataAsset>("UIEffect/" + effectConfig.packageName, effectConfig.fxName);
            //为true时会有部分特效不显示 如主界面装备特效;改成伽马后不会出现BUG故注释代码
            // spineComp.MeshGenerator.settings.pmaVertexColors = !closePMA;
            spineComp.raycastTarget = false;
            spineComp.Initialize(true);
            spineComp.timeScale = speedRate;
            // 检查动画是否有相加模式
            // bool hasAdditiveBlend = CheckForAdditiveBlend(spineComp.Skeleton);
            // if (hasAdditiveBlend)
            // {
            //    spineComp.material = ResManager.Instance.LoadAsset<Material>("UIEffect/" + effectConfig.packageName, effectConfig.fxName.Split('_')[0] + "_Material-Additive");
            // }
            // else
            // {
            //     spineComp.material = null;
            // }
            spineComp.material = ResManager.Instance.LoadAsset<Material>("Materials", "SkeletonGraphicDefault-Straight");
            spineAnimationState = spineComp.AnimationState;
            spineAnimationState.Data.DefaultMix = 0f;
            spineAnimationState.Complete -= OnSpineAnimationComplete;
            spineAnimationState.Complete += OnSpineAnimationComplete;
        }
        spineComp.enabled = true;
        return;
        PlayerTheSpineAnim();
    }
    protected virtual void PlayerEffect(bool playSpine)
        // 播放指定动画
    void PlayerTheSpineAnim()
    {
        spineComp.enabled = true;
        var skeletonData = spineComp.Skeleton.Data;
        if (skeletonData.Animations.Count > 0)
        {
            //按配置或者默认第一个
            int defaultAnimIndex = Math.Max(0, effectConfig.animIndex.Length == 0 ? 0 : effectConfig.animIndex[0]);
            if (playSpineAnimIndex >= skeletonData.Animations.Count)
            {
                playSpineAnimIndex = -1;
                Debug.LogError("特效:" + effectConfig.id + " 索引超出播放默认动画。 error:" + playSpineAnimIndex);
            }
            string defaultAnimationName = skeletonData.Animations.Items[playSpineAnimIndex == -1 ? defaultAnimIndex : playSpineAnimIndex].Name;
            spineAnimationState.SetAnimation(0, defaultAnimationName, isPlaySpineLoop);
        }
        else
        {
            Debug.LogError("Spine 数据中没有找到任何动画!" + effectConfig.id);
        }
    }
    private bool CheckForAdditiveBlend(Spine.Skeleton skeleton)
    {
        // 遍历所有插槽,检查是否有相加模式
        foreach (var slot in skeleton.Slots)
        {
            if (slot.Data.BlendMode == Spine.BlendMode.Additive)
            {
                return true;
            }
        }
        return false;
    }
    //unity特效
    protected virtual void PlayerEffect()
    {
        var effectPrefab = ResManager.Instance.LoadAsset<GameObject>("UIEffect/" + effectConfig.packageName, effectConfig.fxName);
        if (effectPrefab == null)
@@ -226,19 +356,13 @@
        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();
        }
        //挂载组件后 开始收集
        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>();
@@ -253,6 +377,18 @@
        }
    }
    public async UniTask PlayAsync(bool showLog = true, bool closePMA = false)
    {
        await UniTask.Delay(playDelayTime);
        try
        {
            Play(showLog, closePMA);
        }
        catch (Exception e)
        {
            Debug.LogError(e);
        }
    }
    protected void OnDestroy()
    {
@@ -262,7 +398,7 @@
            onDestroy = null;
        }
        // 停止特效并归还到池中
        Stop();
        Release();
        if (spineAnimationState != null)
        {
@@ -275,11 +411,17 @@
    //单次播放完毕就会触发,即使是循环
    protected virtual void OnSpineAnimationComplete(Spine.TrackEntry trackEntry)
    {
        if (isReleaseImmediately)
        if (!isPlaySpineLoop)
        {
            spineComp.enabled = false;
            isPlaying = false;
            Stop();
            onComplete?.Invoke();
            // TODO 会报错暂时注释
            // if (isReleaseImmediately)
            // {
            //     Release();
            // }
        }
    }
@@ -299,7 +441,7 @@
    {
        this.DoWaitStop();
        if (isReleaseImmediately)
            Stop();
            Release();
    }