|
|
|
|
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 = 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|