ProjectDDD/Packages/SLUnity/UnitSytem/View/EffectView.cs
2025-06-25 11:33:17 +09:00

338 lines
9.4 KiB (Stored with Git LFS)
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Superlazy;
using UnityEngine;
public class EffectView : MonoBehaviour
{
private static readonly Queue<EffectView> unused = new Queue<EffectView>();
private static readonly Dictionary<string, EffectView> used = new Dictionary<string, EffectView>();
private static Transform unusedRoot;
public static void InitGlobal()
{
unusedRoot = new GameObject("UnusedEffectView").transform;
unusedRoot.gameObject.SetActive(false);
}
public static EffectView MakeUnitEffect(UnitView unit, string effectName, SLEntity effectContext)
{
var instance = GetEffect(effectName);
instance.transform.SetParent(unit.Zone.Root, false);
//// TODO: 추후 개선이 가능할지 모르겠지만 이펙트뷰 레벨에서 유닛을 가져다 쓰는게 맞는지 고민
//if (effectContext["CellEffect"])
//{
// instance.transform.position = unit.Position.ToEntity().PositionToCell().CellToPosition().ToVector3();
//}
//else
{
instance.transform.position = unit.Position;
}
instance.transform.rotation = unit.Rotation;
instance.transform.localScale = unit.EffectScale;
instance.OnStart(effectContext.Override(), unit.Zone, unit);
instance.gameObject.SetActive(true);
return instance;
}
public static EffectView MakeEffect(IZoneView zone, string effectName, SLEntity effectContext/*, IWorld world*/, Vector3 position, Quaternion rotation, Vector3 scale)
{
var instance = GetEffect(effectName);
instance.transform.SetParent(zone.Root, false);
instance.transform.SetPositionAndRotation(position, rotation);
instance.transform.localScale = scale;
instance.OnStart(effectContext.Override(), zone, null);
instance.gameObject.SetActive(true);
return instance;
}
private static EffectView GetEffect(string effectName)
{
EffectView newEffect;
if (unused != null && unused.Count != 0)
{
newEffect = unused.Dequeue();
}
else
{
var newObject = new GameObject();
newObject.SetActive(false);
newEffect = newObject.AddComponent<EffectView>();
}
if (newEffect.baseRoot == null)
{
newEffect.baseRoot = SLResources.CreateInstance(effectName, newEffect.gameObject.transform);
newEffect.Init();
}
newEffect.baseRoot.gameObject.SetActive(true);
newEffect.gameObject.name = effectName;
return newEffect;
}
public static void ClearEffect()
{
foreach (var key in used.Keys.ToList())
{
used[key].EndEffect(true);
}
used.Clear();
}
public static void RemoveEffect(string effectID)
{
if (used.ContainsKey(effectID))
{
used[effectID].EndEffect();
}
}
private SLResourceObject baseRoot;
private SLEntity context;
private UnitView unit;
private Vector3 offset;
private Vector3 rotationOffset;
private Animator[] anims;
private Renderer[] renderers;
private ParticleSystem[] particles;
private TrailRenderer[] trails;
private Transform bindTransform;
private void Init()
{
anims = GetComponentsInChildren<Animator>();
renderers = GetComponentsInChildren<Renderer>();
particles = GetComponentsInChildren<ParticleSystem>();
trails = GetComponentsInChildren<TrailRenderer>();
}
public void EndEffect(bool force = false)
{
if (gameObject.activeSelf == false)
{
SLLog.Error($"Already Destroy Effect {context["EffectID"]}");
return;
}
bindTransform = null;
if (used.ContainsKey(context["EffectID"]))
{
used.Remove(context["EffectID"]);
}
if (unusedRoot)
{
transform.localScale = Vector3.one;
baseRoot.Destroy(force);
baseRoot = null;
gameObject.SetActive(false);
unused.Enqueue(this);
transform.SetParent(unusedRoot);
}
else
{
Destroy(gameObject);
}
}
private void OnStart(SLEntity context, IZoneView zone, UnitView unit)
{
this.context = context.Override();
this.unit = unit;
if (this.context["Scale"] != false)
{
transform.localScale *= this.context["Scale"];
}
if (this.context["ForceY"])
{
transform.Translate(0, -transform.localPosition.y + context["ForceY"], 0);
}
if (this.context["ForceRotate"])
{
transform.localRotation = Quaternion.Euler(this.context["ForceRotate"].ToVector3());
}
offset = this.context["Offset"].ToVector3() * transform.localScale.x;
rotationOffset = this.context["RotationOffset"].ToVector3();
if (unit != null)
{
if (context["Bind"]["Height"])
{
enabled = true;
var bindHeight = unit.Entity[context["Bind"]["Height"]];
offset += Vector3.up * bindHeight;
}
if (context["Bind"]["Part"])
{
enabled = true;
var part = unit.Entity[context["Bind"]["Part"]];
bindTransform = unit.transform.GetComponentsInChildren<Transform>().FirstOrDefault(t => t.name == part["Transform"]);
offset += part["Offset"].ToVector3();
transform.localScale *= part["Scale"];
}
if (context["Bind"]["Transform"])
{
enabled = true;
bindTransform = unit.transform.GetComponentsInChildren<Transform>().FirstOrDefault(t => t.name == context["Bind"]["Transform"]);
}
if (context["Bind"]["ShadowScale"])
{
enabled = true;
var scaleDelta = unit.Entity["ShadowRadius"] / SLSystem.Data["Default"]["DefaultShadowScale"];
transform.localScale *= scaleDelta;
}
if (bindTransform == null)
{
bindTransform = unit.transform.Find("OffsetRoot");
}
foreach (var r in renderers)
{
r.gameObject.layer = unit.Zone.Layer;
}
foreach (var p in particles)
{
p.gameObject.layer = unit.Zone.Layer;
}
foreach (var t in trails)
{
t.gameObject.layer = unit.Zone.Layer;
}
}
transform.Translate(offset, Space.Self);
transform.Rotate(rotationOffset, Space.Self);
foreach (var p in particles)
{
p.Clear();
}
foreach (var t in trails)
{
t.Clear();
}
if (context["EffectID"] == false)
{
context["EffectID"] = context["Effect"];
var index = 1;
while (used.ContainsKey(context["EffectID"]))
{
context["EffectID"] = context["Effect"].ToString() + index;
++index;
}
}
used.Add(context["EffectID"], this);
//string layer = "Default";
//if (this.context["Layer"])
//{
// layer = this.context["Layer"];
//}
//gameObject.SetLayerRecursively(layer);
}
private void Update()
{
if (unit != null)
{
if (unit.isActiveAndEnabled == false)
{
EndEffect();
return;
}
if (context["Bind"]["TopPosition"])
{
transform.position = unit.Entity["TopPosition"].ToVector3();
transform.Translate(offset, Space.Self);
}
if (context["Bind"]["Position"])
{
transform.position = bindTransform.position;
transform.Translate(offset, Space.Self);
}
if (context["Bind"]["Rotation"])
{
transform.rotation = bindTransform.rotation;
transform.Rotate(rotationOffset, Space.Self);
}
if (unit.Entity["ActionSpeed"])
{
foreach (var particle in particles)
{
var particleMain = particle.main;
particleMain.simulationSpeed = unit.Entity["ActionSpeed"];
}
}
}
if (context["Duration"])
{
context["Duration"] -= Time.deltaTime;
if (context["Duration"] <= 0)
{
EndEffect();
}
return;
}
if (context["End"])
{
EndEffect();
return;
}
if (context["Loop"]) return; // 자연종료 안한다
foreach (var animator in anims)
{
if (animator.GetCurrentAnimatorStateInfo(0).loop || animator.GetCurrentAnimatorStateInfo(0).normalizedTime < 1.0f)
{
return;
}
}
foreach (var particle in particles)
{
if (particle.isPlaying)
{
return;
}
}
EndEffect();
}
public static void NoUsePool()
{
Destroy(unusedRoot.gameObject);
}
}