using System; using System.Collections; using System.Collections.Generic; using Spine.Unity; using UnityEngine; using Spine; using UnityEngine.UI; public class EffectPlayer : MonoBehaviour { public int effectId; public EffectConfig effectConfig; public Action onDestroy; public Action onComplete; public float speedRate = 1f; [Header("是否在显示时播放")] public bool isPlayOnEnable = false; [Header("是否立即播放spine特效")] public bool isPlaySpineImmediately = false; [Header("是否循环播放spine特效")] public bool isPlaySpineLoop = false; [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; protected void OnEnable() { if (isPlayOnEnable) { Play(); } } protected bool InitCompnent() { if (effectId <= 0) { effectConfig = null; // 根据逻辑需求,动态设置特效的情况 // Debug.LogError("EffectPlayer effectId is not set"); // #if UNITY_EDITOR // UnityEditor.Selection.activeGameObject = gameObject; // UnityEditor.EditorGUIUtility.PingObject(gameObject); // #endif return false; } effectConfig = EffectConfig.Get(effectId); if (null == effectConfig) { Debug.LogError("could not find effect config, effect id is " + effectId); #if UNITY_EDITOR UnityEditor.Selection.activeGameObject = gameObject; UnityEditor.EditorGUIUtility.PingObject(gameObject); #endif return false; } particleList.Clear(); animatorList.Clear(); rendererList.Clear(); spineComp = null; //spine是加载文件,需要提前挂载脚本,unity特效是已经做好的预制体待加载后收集组件 if (effectConfig.isSpine != 0) { spineComp = gameObject.AddMissingComponent(); } // else // { // // 收集组件 // particleList.AddRange(gameObject.GetComponentsInChildren(true)); // animatorList.AddRange(gameObject.GetComponentsInChildren(true)); // } // rendererList.AddRange(gameObject.GetComponentsInChildren(true)); return true; } public void Stop() { if (null != effectTarget) { DestroyImmediate(effectTarget); effectTarget = null; } isInit = false; particleList.Clear(); animatorList.Clear(); rendererList.Clear(); spineComp = null; } public void Play() { ReStart(); } protected void ReStart() { if (!isInit) { if (InitCompnent()) { isInit = true; } else { //根据逻辑需求,动态设置特效的情况 return; } } if (EffectMgr.Instance.IsNotShowBySetting(effectId)) { return; } if (null != effectTarget) { DestroyImmediate(effectTarget); effectTarget = null; } // YYL TODO // 在这里考虑用池的话可能走配置好一点 原本的是无论如何都走池 但是实际上有些特效并不需要 // 加载spine特效资源 if (effectConfig.isSpine != 0) { spineComp.skeletonDataAsset = ResManager.Instance.LoadAsset("UIEffect/" + effectConfig.packageName, effectConfig.fxName + "_SkeletonData"); spineComp.raycastTarget = false; spineComp.Initialize(true); spineAnimationState = spineComp.AnimationState; spineAnimationState.Complete -= OnSpineAnimationComplete; spineAnimationState.Complete += OnSpineAnimationComplete; if (isPlaySpineImmediately) { //UI特效常用方式 spineComp.enabled = true; // 播放第一个动画(作为默认动画) var skeletonData = spineComp.Skeleton.Data; if (skeletonData.Animations.Count > 0) { string defaultAnimationName = skeletonData.Animations.Items[0].Name; spineComp.AnimationState.SetAnimation(0, defaultAnimationName, isPlaySpineLoop); } else { Debug.LogError("Spine 数据中没有找到任何动画!" + effectConfig.id); } } else { spineComp.enabled = false; } return; } //加载unity特效 var effectPrefab = ResManager.Instance.LoadAsset("UIEffect/" + effectConfig.packageName, effectConfig.fxName); if (effectPrefab == null) { Debug.LogError($"加载UI特效失败: {effectConfig.packageName}"); return; } // 实例化特效 effectTarget = Instantiate(effectPrefab, transform); effectTarget.name = $"Effect_{effectConfig.fxName}"; //挂载组件后 开始收集 particleList.AddRange(gameObject.GetComponentsInChildren(true)); animatorList.AddRange(gameObject.GetComponentsInChildren(true)); rendererList.AddRange(gameObject.GetComponentsInChildren(true)); // 思考一下在没有挂在节点的时候 if (null == canvas) canvas = GetComponentInParent(); // 添加特效穿透阻挡器 blocker = effectTarget.AddMissingComponent(); // 如果没有canvas的话 正常是因为不在BattleWin下面的节点 意思就是当前没有显示 等到切回战斗的时候再通过BattleField.UpdateCanvas来更新 if (canvas != null) { blocker.SetParentCanvas(canvas); } // 自动销毁 if (effectConfig.autoDestroy != 0) { Destroy(effectTarget, effectConfig.destroyDelay); } } protected void OnDestroy() { if (onDestroy != null) { onDestroy.Invoke(this); onDestroy = null; } if (spineAnimationState != null) { spineAnimationState.Complete -= OnSpineAnimationComplete; } } //单次播放完毕就会触发,即使是循环 protected void OnSpineAnimationComplete(Spine.TrackEntry trackEntry) { if (!isPlaySpineLoop) { if (onComplete == null) { if (effectConfig.isSpine != 0) { spineComp.enabled = false; } } onComplete?.Invoke(); } } // 创建后的特效会自动隐藏 需要手动调用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 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; } } }