Files
WhaleAdventure_VR/Assets/My project/maze Scripts/Ui/FootprintEffect.cs
2026-06-24 17:13:40 +09:00

248 lines
6.8 KiB
C#

using System.Collections;
using UnityEngine;
[DisallowMultipleComponent]
public class FootprintEffect : MonoBehaviour
{
[Header("Timing")]
[SerializeField] private float appearTime = 0.25f;
[SerializeField] private float lifeTime = 3f;
[SerializeField] private float fadeTime = 0.8f;
[Header("Scale Effect")]
[SerializeField] private bool useScaleEffect = true;
[SerializeField] private float startScaleMultiplier = 0.75f;
[SerializeField] private float popScaleMultiplier = 1.08f;
[SerializeField] private float endScaleMultiplier = 0.85f;
[Header("Unlit Brightness Effect")]
[Tooltip("URP Unlit 머티리얼에서 Emission 대신 색 밝기를 조절합니다.")]
[SerializeField] private bool useBrightnessEffect = true;
[SerializeField] private float appearBrightness = 1.4f;
[SerializeField] private float normalBrightness = 1.0f;
[SerializeField] private float fadeBrightness = 0.5f;
[Header("Destroy")]
[SerializeField] private bool destroyAfterFade = true;
[Tooltip("renderer.materials로 생성된 머티리얼 인스턴스를 OnDestroy에서 정리합니다.")]
[SerializeField] private bool cleanupMaterialInstances = true;
private Renderer[] renderers;
private Material[] materials;
private Color[] originalColors;
private Vector3 originalScale;
private Coroutine effectRoutine;
private void Awake()
{
originalScale = transform.localScale;
CacheMaterials();
ApplyVisual(0f, startScaleMultiplier, fadeBrightness);
}
private void OnEnable()
{
if (effectRoutine != null)
StopCoroutine(effectRoutine);
effectRoutine = StartCoroutine(EffectRoutine());
}
private void OnDisable()
{
if (effectRoutine != null)
{
StopCoroutine(effectRoutine);
effectRoutine = null;
}
}
private void OnDestroy()
{
if (!cleanupMaterialInstances || materials == null)
return;
for (int i = 0; i < materials.Length; i++)
{
if (materials[i] != null)
Destroy(materials[i]);
}
}
private void CacheMaterials()
{
renderers = GetComponentsInChildren<Renderer>(true);
int materialCount = 0;
for (int i = 0; i < renderers.Length; i++)
materialCount += renderers[i].materials.Length;
materials = new Material[materialCount];
originalColors = new Color[materialCount];
int index = 0;
for (int i = 0; i < renderers.Length; i++)
{
Material[] rendererMaterials = renderers[i].materials;
for (int j = 0; j < rendererMaterials.Length; j++)
{
materials[index] = rendererMaterials[j];
originalColors[index] = GetMaterialColor(materials[index]);
index++;
}
}
}
private IEnumerator EffectRoutine()
{
yield return AppearRoutine();
if (lifeTime > 0f)
yield return new WaitForSeconds(lifeTime);
yield return FadeRoutine();
effectRoutine = null;
if (destroyAfterFade)
Destroy(gameObject);
}
private IEnumerator AppearRoutine()
{
if (appearTime <= 0f)
{
ApplyVisual(1f, 1f, normalBrightness);
yield break;
}
float timer = 0f;
while (timer < appearTime)
{
timer += Time.deltaTime;
float t = Mathf.Clamp01(timer / appearTime);
float alpha = Mathf.Lerp(0f, 1f, t);
float brightness = useBrightnessEffect
? Mathf.Lerp(fadeBrightness, appearBrightness, t)
: 1f;
float scaleMultiplier;
if (t < 0.75f)
{
float popT = t / 0.75f;
scaleMultiplier = Mathf.Lerp(startScaleMultiplier, popScaleMultiplier, popT);
}
else
{
float settleT = (t - 0.75f) / 0.25f;
scaleMultiplier = Mathf.Lerp(popScaleMultiplier, 1f, settleT);
}
ApplyVisual(alpha, scaleMultiplier, brightness);
yield return null;
}
ApplyVisual(1f, 1f, normalBrightness);
}
private IEnumerator FadeRoutine()
{
if (fadeTime <= 0f)
{
ApplyVisual(0f, endScaleMultiplier, fadeBrightness);
yield break;
}
float timer = 0f;
while (timer < fadeTime)
{
timer += Time.deltaTime;
float t = Mathf.Clamp01(timer / fadeTime);
float alpha = Mathf.Lerp(1f, 0f, t);
float brightness = useBrightnessEffect
? Mathf.Lerp(normalBrightness, fadeBrightness, t)
: 1f;
float scaleMultiplier = Mathf.Lerp(1f, endScaleMultiplier, t);
ApplyVisual(alpha, scaleMultiplier, brightness);
yield return null;
}
ApplyVisual(0f, endScaleMultiplier, fadeBrightness);
}
private void ApplyVisual(float alpha, float scaleMultiplier, float brightness)
{
if (useScaleEffect)
transform.localScale = originalScale * scaleMultiplier;
if (materials == null)
return;
for (int i = 0; i < materials.Length; i++)
{
if (materials[i] == null)
continue;
Color color = originalColors[i];
color.r *= brightness;
color.g *= brightness;
color.b *= brightness;
color.a = alpha;
SetMaterialColor(materials[i], color);
}
}
private Color GetMaterialColor(Material material)
{
if (material == null)
return Color.white;
if (material.HasProperty("_BaseColor"))
return material.GetColor("_BaseColor");
if (material.HasProperty("_Color"))
return material.GetColor("_Color");
return Color.white;
}
private void SetMaterialColor(Material material, Color color)
{
if (material == null)
return;
if (material.HasProperty("_BaseColor"))
material.SetColor("_BaseColor", color);
else if (material.HasProperty("_Color"))
material.SetColor("_Color", color);
}
#if UNITY_EDITOR
private void OnValidate()
{
appearTime = Mathf.Max(0f, appearTime);
lifeTime = Mathf.Max(0f, lifeTime);
fadeTime = Mathf.Max(0f, fadeTime);
startScaleMultiplier = Mathf.Max(0.01f, startScaleMultiplier);
popScaleMultiplier = Mathf.Max(0.01f, popScaleMultiplier);
endScaleMultiplier = Mathf.Max(0.01f, endScaleMultiplier);
appearBrightness = Mathf.Max(0f, appearBrightness);
normalBrightness = Mathf.Max(0f, normalBrightness);
fadeBrightness = Mathf.Max(0f, fadeBrightness);
}
#endif
}