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 float speedRate = 1f;
|
|
[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 void Start()
|
{
|
ReStart();
|
}
|
|
protected void 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;
|
}
|
|
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;
|
}
|
|
|
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));
|
}
|
|
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)
|
{
|
isInit = true;
|
InitCompnent();
|
}
|
|
if (EffectMgr.Instance.IsNotShowBySetting(effectId))
|
{
|
return;
|
}
|
|
if (null != effectTarget)
|
{
|
DestroyImmediate(effectTarget);
|
effectTarget = null;
|
}
|
|
// YYL TODO
|
// 在这里考虑用池的话可能走配置好一点 原本的是无论如何都走池 但是实际上有些特效并不需要
|
|
// 加载特效资源
|
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}";
|
|
// 思考一下在没有挂在节点的时候
|
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;
|
}
|
}
|
|
// 创建后的特效会自动隐藏 需要手动调用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;
|
}
|
}
|
}
|