|  |  |  | using System; | 
					
						
							|  |  |  | using System.Collections.Generic; | 
					
						
							|  |  |  | using UnityEngine; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Game | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     public class EffectPoolItem : ObjectPoolItemBase | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         public GameObject GameObject; | 
					
						
							|  |  |  |         public List<ParticleSystem> ParticleList = new List<ParticleSystem>(); | 
					
						
							|  |  |  |         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<ParticleSystem>(); | 
					
						
							|  |  |  |             var effectNum = 0; | 
					
						
							|  |  |  |             foreach (var particle in particles) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 var renderer = particle.GetComponent<ParticleSystemRenderer>(); | 
					
						
							|  |  |  |                 if (!renderer.enabled) continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (particle.main.loop) _isLoop = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 var listener = particle.gameObject.AddComponent<EffectListener>(); | 
					
						
							|  |  |  |                 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(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /// <summary> | 
					
						
							|  |  |  |         ///     销毁特效,区别于直接入池,如果是循环特效直接入池,否则只解绑,等待生命周期结束 | 
					
						
							|  |  |  |         /// </summary> | 
					
						
							|  |  |  |         public void EffectDestroy() | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (_isLoop) Destroy(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             GameObject.transform.SetParent(EffectPoolManager.Instance.Root.transform); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public class EffectPoolManager : ObjectPoolBase<EffectPoolManager> | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         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<EffectPoolItem>(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<EffectPoolItem>($"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); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |