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<EffectPlayer> 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<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;
|
|
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<SkeletonGraphic>();
|
|
}
|
// else
|
// {
|
// // 收集组件
|
// particleList.AddRange(gameObject.GetComponentsInChildren<ParticleSystem>(true));
|
// animatorList.AddRange(gameObject.GetComponentsInChildren<Animator>(true));
|
// }
|
// rendererList.AddRange(gameObject.GetComponentsInChildren<Renderer>(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<SkeletonDataAsset>("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<GameObject>("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<ParticleSystem>(true));
|
animatorList.AddRange(gameObject.GetComponentsInChildren<Animator>(true));
|
rendererList.AddRange(gameObject.GetComponentsInChildren<Renderer>(true));
|
|
|
// 思考一下在没有挂在节点的时候
|
if (null == canvas)
|
canvas = GetComponentInParent<Canvas>();
|
|
|
// 添加特效穿透阻挡器
|
blocker = effectTarget.AddMissingComponent<EffectPenetrationBlocker>();
|
|
// 如果没有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<EffectPlayer>();
|
}
|
else
|
{
|
effectPlayer = parent.AddMissingComponent<EffectPlayer>();
|
effectPlayer.effectId = effectId;
|
}
|
effectPlayer.SetActive(true);
|
return effectPlayer;
|
}
|
|
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;
|
}
|
}
|
}
|