using System; using System.Collections.Generic; using UnityEngine; namespace Game { public class EffectPoolItem : ObjectPoolItemBase { public GameObject GameObject; public List ParticleList = new List(); public float DurationMax; private int _effectCount; private int _effectCountMax; private bool _isLoop; protected override void OnDestroy() { base.OnDestroy(); GameObject.transform.position = new Vector3(-100, 0, -100); GameObject.transform.SetParent(EffectPoolManager.Instance.Root.transform); } public void Init(GameObject effectGo) { var particles = effectGo.GetComponentsInChildren(); var effectNum = 0; foreach (var particle in particles) { var renderer = particle.GetComponent(); if (!renderer.enabled) continue; if (particle.main.loop) _isLoop = true; var listener = particle.gameObject.AddComponent(); listener.SetPoolItem(this); var main = particle.main; var duration = main.duration + main.startDelay.constantMax; if (duration > DurationMax) DurationMax = duration; ParticleList.Add(particle); effectNum++; } _effectCountMax += effectNum; _effectCount = _effectCountMax; } public void Play() { foreach (var item in ParticleList) item.Play(); _effectCount = _effectCountMax; } public void EffectStopped() { _effectCount--; if (_effectCount <= 0) Destroy(); } /// /// 销毁特效,区别于直接入池,如果是循环特效直接入池,否则只解绑,等待生命周期结束 /// public void EffectDestroy() { if (_isLoop) Destroy(); GameObject.transform.SetParent(EffectPoolManager.Instance.Root.transform); } } public class EffectPoolManager : ObjectPoolBase { private const string EffectPath = "Effect/"; public override void OnCreate() { CastShadowPoolManager.Create(); } public override void Update() { CastShadowPoolManager.Instance.Update(); } public override void OnDestroy() { CastShadowPoolManager.Instance.OnDestroy(); } private void CreateEffectReal(EffectPoolItem item, Vector3 pos, float rot = 0, int targetEntity = 0, double duration = 0, bool isAttach = false) { var go = item.GameObject; var scale = Vector3.one; //跟随实体移动 if (targetEntity != 0 && isAttach) Util.TryGetEntity(targetEntity, entity => { go.transform.parent = entity.view.TransformViewOther; scale = entity.view.TransformViewMain.localScale; if (scale.x == -1) rot -= 180; }); else go.transform.parent = Root.transform; //跟随实体暂停/销毁 if (targetEntity != 0) Util.TryGetEntity(targetEntity, entity => { entity.view.EffectObject.Add(item); }); go.transform.localRotation = Quaternion.AngleAxis(-rot, Vector3.up); go.transform.position = pos; //镜像翻转 foreach (var particle in item.ParticleList) { var shape = particle.shape; if (shape.enabled) shape.scale = scale; else particle.transform.localScale = scale; } var timeScale = 1f; if (duration > 0) { timeScale = item.DurationMax / (float)duration; } foreach (var particle in item.ParticleList) { var particleMain = particle.main; particleMain.simulationSpeed = timeScale; } item.Play(); } public void CreateEffect(GameObject goModule, Vector3 pos, float rot = 0, int targetEntity = 0, double duration = 0, bool isAttach = false) { var effectNew = Create(goModule, item => { var go = CreateEffectGo(goModule); item.GameObject = go; item.Init(go); }); CreateEffectReal(effectNew, pos, rot, targetEntity, duration, isAttach); } public void CreateEffect(string effectId, Vector3 pos, float rot = 0, int targetEntity = 0, double duration = 0, bool isAttach = false) { var effectNew = Create($"Effect{effectId}", item => { var go = CreateEffectGo(effectId); item.GameObject = go; item.Init(go); }); CreateEffectReal(effectNew, pos, rot, targetEntity, duration, isAttach); } private GameObject CreateEffectGo(GameObject goModule) { return PrefabManager.Instance.CreateGo(goModule); } private GameObject CreateEffectGo(string effectId) { var path = $"{EffectPath}{effectId}"; return PrefabManager.Instance.CreateGo(path); } } } namespace Game { public abstract partial class Util { // 播放跟随实体的特效 private static void CastFollowEffect(string effectId, int targetEntity, float rot = 0) { TryGetEntity(targetEntity, entity => { var pos = entity.PosView(); CastEffect(effectId, pos, rot, targetEntity, 0, true); }); } // 受击特效:跟随实体暂停/销毁 但是不跟随移动 public static void CastHitEffect(string effectId, int targetEntity, float rot = 0) { TryGetEntity(targetEntity, entity => { var pos = entity.PosView(); CastEffect(effectId, pos, rot, targetEntity, 0, false); }); } // 地面特效:在实体对应地面播放,跟随实体暂停/销毁 但是不跟随移动 public static void CastGroundStaticEffect(string effectId, int targetEntity, float rot = 0) { TryGetEntity(targetEntity, entity => { var pos = entity.PosGround() + Vector3.up * 0.0001f; CastEffect(effectId, pos, rot, targetEntity, 0, false); }); } // 墙面特效:在实体对应地面播放,跟随实体暂停/销毁 但是不跟随移动 public static void CastWallStaticEffect(string effectId, int targetEntity, Vector3 pos, Vector3 normal) { var rot = Util.Vec3ToRot(normal); CastEffect(effectId, pos, rot, targetEntity, 0, false); } private static void CastEffect(string effectId, Vector3 pos, float rot, int targetEntity, double duration, bool isAttach) { try { EffectPoolManager.Instance.CreateEffect(effectId, pos, rot, targetEntity, duration, isAttach); } catch (Exception e) { Print("特效释放失败:", effectId, targetEntity); Print(e.StackTrace); } } public static void CastEffect(GameObject goModule, Vector3 pos, float rot = 0, int targetEntity = 0, double duration = 0, bool isAttach = false) { EffectPoolManager.Instance.CreateEffect(goModule, pos, rot, targetEntity, duration, isAttach); } } }