using System; 
 | 
using System.Collections; 
 | 
using System.Collections.Generic; 
 | 
using Spine.Unity; 
 | 
using UnityEngine; 
 | 
using Spine; 
 | 
using UnityEngine.UI; 
 | 
using Cysharp.Threading.Tasks; 
 | 
  
 | 
// 特效播放器,预制体对象池管理,unity的预制体池使用有问题(1个特效1个池但复用又低)后续修改 
 | 
// unity特效《预制体》是特效师在制作的时候生成的不同预制体,unity特效必须挂载设置播放时长脚本 EffectTime 
 | 
// spine特效是特效师制作的动画文件,可共同复用一个《预制体》 
 | 
public class EffectPlayer : MonoBehaviour 
 | 
{ 
 | 
    [SerializeField] 
 | 
    private int m_EffectID; 
 | 
    public int effectId 
 | 
    { 
 | 
        get 
 | 
        { 
 | 
            return m_EffectID; 
 | 
        } 
 | 
        set 
 | 
        { 
 | 
            if (value != m_EffectID) 
 | 
            { 
 | 
                Stop(); 
 | 
                isInit = false; 
 | 
                m_EffectID = value; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
  
 | 
  
 | 
    public EffectConfig effectConfig; 
 | 
  
 | 
    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("播放完毕立即回收")] 
 | 
    public bool isReleaseImmediately = false;  //界面特效一般不需要自我销毁,跟随界面或者父对象销毁就行 
 | 
  
 | 
    public Action<EffectPlayer> onDestroy; 
 | 
  
 | 
    [HideInInspector] public Canvas canvas = null; 
 | 
  
 | 
    [HideInInspector] public GameObject effectTarget = null; 
 | 
  
 | 
    protected EffectPenetrationBlocker blocker = null; 
 | 
  
 | 
    protected bool isInit = false; 
 | 
    protected bool isPlaying = false; 
 | 
  
 | 
    protected List<ParticleSystem> particleList = new List<ParticleSystem>(); 
 | 
  
 | 
    protected List<Animator> animatorList = new List<Animator>(); 
 | 
  
 | 
    protected List<Renderer> rendererList = new List<Renderer>(); 
 | 
  
 | 
    protected SkeletonGraphic spineComp; 
 | 
    protected Spine.AnimationState spineAnimationState; 
 | 
  
 | 
    public GameObjectPoolManager.GameObjectPool pool; 
 | 
  
 | 
    public Action onComplete; 
 | 
  
 | 
    protected virtual void OnEnable() 
 | 
    { 
 | 
         
 | 
        if (isPlayOnEnable) 
 | 
        { 
 | 
            Play(false); 
 | 
        } 
 | 
        else if (spineComp != null) 
 | 
        { 
 | 
            if (!isPlaying) 
 | 
            { 
 | 
                //隐藏,会有静态显示问题 
 | 
                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() 
 | 
    { 
 | 
        isInit = false; 
 | 
        particleList.Clear(); 
 | 
        animatorList.Clear(); 
 | 
        rendererList.Clear(); 
 | 
  
 | 
        if (spineComp != null) 
 | 
        { 
 | 
            spineComp.skeletonDataAsset = null; 
 | 
            // spineComp.Initialize(false);     
 | 
            spineComp.Clear(); 
 | 
        } 
 | 
  
 | 
        spineComp = null; 
 | 
    } 
 | 
  
 | 
    public virtual void Stop() 
 | 
    { 
 | 
        if (null != effectTarget) 
 | 
        { 
 | 
            // 如果使用了特效预制体池,则归还到池中 
 | 
            if (pool != null) 
 | 
            { 
 | 
                pool.Release(effectTarget); 
 | 
            } 
 | 
            effectTarget = null; 
 | 
        } 
 | 
        if (spineComp != null) 
 | 
        { 
 | 
            spineComp.enabled = false; 
 | 
        } 
 | 
        isPlaying = false; 
 | 
        playSpineAnimIndex = -1; 
 | 
    } 
 | 
  
 | 
    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 
 | 
        { 
 | 
            //避免重复创建 
 | 
            if (!this.gameObject.activeSelf) 
 | 
            { 
 | 
                this.gameObject.SetActive(true); 
 | 
            } 
 | 
            //防范effeid 为0 
 | 
            if (effectConfig != null && effectConfig.isSpine != 0) 
 | 
            { 
 | 
                PlaySpineEffect(closePMA); 
 | 
            } 
 | 
            return; 
 | 
        } 
 | 
        if (effectConfig == null) 
 | 
            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); 
 | 
        } 
 | 
  
 | 
        // 加载spine特效资源 
 | 
        if (effectConfig.isSpine != 0) 
 | 
        { 
 | 
            PlaySpineEffect(closePMA); 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            PlayerEffect(); 
 | 
        } 
 | 
     
 | 
        SoundPlayer.Instance.PlayUIAudio(effectConfig.audio); 
 | 
  
 | 
    } 
 | 
  
 | 
  
 | 
    // 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) 
 | 
    { 
 | 
  
 | 
        // 从特效预制体池获取特效 
 | 
        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; 
 | 
        PlayerTheSpineAnim(); 
 | 
    } 
 | 
  
 | 
        // 播放指定动画 
 | 
    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) 
 | 
        { 
 | 
            Debug.LogError($"加载UI特效失败: {effectConfig.packageName}"); 
 | 
            return; 
 | 
        } 
 | 
  
 | 
        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}"; 
 | 
  
 | 
  
 | 
        //挂载组件后 开始收集 
 | 
        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>(); 
 | 
  
 | 
        //  如果没有canvas的话 正常是因为不在BattleWin下面的节点 意思就是当前没有显示 等到切回战斗的时候再通过BattleField.UpdateCanvas来更新 
 | 
        if (canvas != null) 
 | 
        { 
 | 
            blocker.SetParentCanvas(canvas); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    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() 
 | 
    { 
 | 
        if (onDestroy != null) 
 | 
        { 
 | 
            onDestroy.Invoke(this); 
 | 
            onDestroy = null; 
 | 
        } 
 | 
        // 停止特效并归还到池中 
 | 
        Release(); 
 | 
  
 | 
        if (spineAnimationState != null) 
 | 
        { 
 | 
            spineAnimationState.Complete -= OnSpineAnimationComplete; 
 | 
        } 
 | 
  
 | 
  
 | 
    } 
 | 
  
 | 
    //单次播放完毕就会触发,即使是循环 
 | 
    protected virtual void OnSpineAnimationComplete(Spine.TrackEntry trackEntry) 
 | 
    { 
 | 
        if (!isPlaySpineLoop) 
 | 
        { 
 | 
            spineComp.enabled = false; 
 | 
            isPlaying = false; 
 | 
            onComplete?.Invoke(); 
 | 
            if (isReleaseImmediately) 
 | 
            { 
 | 
                Release(); 
 | 
            } 
 | 
  
 | 
        } 
 | 
    } 
 | 
  
 | 
  
 | 
    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) 
 | 
            Release(); 
 | 
    } 
 | 
  
 | 
  
 | 
    //  创建后的特效会自动隐藏 需要手动调用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<EffectPlayer>(); 
 | 
        } 
 | 
        else 
 | 
        { 
 | 
            effectPlayer = parent.AddMissingComponent<EffectPlayer>(); 
 | 
        } 
 | 
  
 | 
        effectPlayer.effectId = effectId; 
 | 
        effectPlayer.SetActive(true); 
 | 
        return effectPlayer; 
 | 
    } 
 | 
  
 | 
    /// <summary> 
 | 
    /// 设置游戏对象激活状态 
 | 
    // /// </summary> 
 | 
    // public void SetActive(bool active) 
 | 
    // { 
 | 
    //     if (gameObject != null) 
 | 
    //     { 
 | 
    //         gameObject.SetActive(active); 
 | 
    //     } 
 | 
    // } 
 | 
  
 | 
    public void Pause() 
 | 
    { 
 | 
        if (effectTarget == null) return; 
 | 
  
 | 
        // Spine动画 
 | 
        // var spineGraphics = effectTarget.GetComponentsInChildren<SkeletonGraphic>(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; 
 | 
    } 
 | 
  
 | 
    /// <summary> 
 | 
    /// 设置遮罩(支持RectMask2D、Mask、SmoothMask等) 
 | 
    /// </summary> 
 | 
    public void SetMask(RectTransform maskArea = null) 
 | 
    { 
 | 
        if (effectTarget == null || blocker == null) 
 | 
            return; 
 | 
  
 | 
        // 优先使用传入的maskArea 
 | 
        if (maskArea != null) 
 | 
        { 
 | 
            blocker.PerformMask(maskArea); 
 | 
            return; 
 | 
        } 
 | 
    } 
 | 
  
 | 
  
 | 
} 
 |