You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			241 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			241 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C#
		
	
| 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)
 | |
|         {
 | |
|             // 忽略normal的y轴 保证特效垂直于墙面
 | |
|             normal.y = 0;
 | |
|             var rot = Vector3.Angle(Vector3.up, 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);
 | |
|         }
 | |
|     }
 | |
| } |