129 lines
5.1 KiB
C#
129 lines
5.1 KiB
C#
using UnityEngine;
|
|
using WL.Player;
|
|
|
|
namespace WL.Combat
|
|
{
|
|
/// <summary>
|
|
/// 피격 시 대상 전신을 지정 색으로 물들였다가 되돌리는 하이라이트.
|
|
///
|
|
/// 힘민지는 같은 연출을 `Actor.cs:1595-1600` · `:2045-2066` 에서
|
|
/// `Renderer.material` / `sharedMaterials` 리스트 조작으로 했다가
|
|
/// **GC Alloc 2.3KB 문제로 전량 주석 처리**했다(`Actor.cs:2046` 주석 명시 · himminji-reuse 02 §7-2).
|
|
/// → WL 은 처음부터 **MaterialPropertyBlock** 으로 구현한다(머티리얼 인스턴스 생성 0 · 할당 0).
|
|
///
|
|
/// 대상 셰이더 `Toon/Toon`(Unity Chan Toon Shader)의 색 프로퍼티를 실측해
|
|
/// 베이스색 2종(_BaseColor·_Color) + 그림자색 2종(_1st_ShadeColor·_2nd_ShadeColor)을 함께 덮는다.
|
|
/// 베이스만 바꾸면 그늘진 면이 원래 색으로 남아 플래시가 반쪽만 보인다.
|
|
/// </summary>
|
|
[DisallowMultipleComponent]
|
|
public class HitFlash : MonoBehaviour
|
|
{
|
|
private static readonly string[] ColorProps = { "_BaseColor", "_Color", "_1st_ShadeColor", "_2nd_ShadeColor" };
|
|
|
|
[Header("수치 설정 (ScriptableObject)")]
|
|
[SerializeField] private CombatSettings settings;
|
|
|
|
[Header("참조 (비우면 자식 렌더러 전체)")]
|
|
[SerializeField] private Renderer[] renderers;
|
|
|
|
private MaterialPropertyBlock _block;
|
|
private int[] _propIds;
|
|
private Color[][] _originals; // [renderer][prop]
|
|
private bool[] _hasProp; // [prop] — 셰이더가 그 프로퍼티를 가지고 있는가
|
|
private float _timer;
|
|
private bool _active;
|
|
|
|
private Enemy _enemy;
|
|
|
|
private void Awake()
|
|
{
|
|
if (renderers == null || renderers.Length == 0) renderers = GetComponentsInChildren<Renderer>(true);
|
|
_enemy = GetComponent<Enemy>();
|
|
if (settings == null && _enemy != null) settings = _enemy.Settings;
|
|
|
|
_block = new MaterialPropertyBlock();
|
|
_propIds = new int[ColorProps.Length];
|
|
_hasProp = new bool[ColorProps.Length];
|
|
for (int i = 0; i < ColorProps.Length; i++) _propIds[i] = Shader.PropertyToID(ColorProps[i]);
|
|
|
|
_originals = new Color[renderers.Length][];
|
|
for (int r = 0; r < renderers.Length; r++)
|
|
{
|
|
_originals[r] = new Color[ColorProps.Length];
|
|
var m = renderers[r] != null ? renderers[r].sharedMaterial : null;
|
|
for (int i = 0; i < ColorProps.Length; i++)
|
|
{
|
|
bool has = m != null && m.HasProperty(ColorProps[i]);
|
|
_originals[r][i] = has ? m.GetColor(ColorProps[i]) : Color.white;
|
|
if (has) _hasProp[i] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
if (_enemy != null) _enemy.Damaged += OnDamaged;
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
if (_enemy != null) _enemy.Damaged -= OnDamaged;
|
|
Clear();
|
|
}
|
|
|
|
private void OnDamaged(Enemy e, float amount) { Flash(); }
|
|
|
|
/// <summary>피격 색 플래시 시작. 재피격 시 타이머만 되감는다.</summary>
|
|
public void Flash()
|
|
{
|
|
float dur = settings != null ? settings.hitFlashSeconds : 0.15f;
|
|
if (dur <= 0f) return;
|
|
_timer = dur;
|
|
_active = true;
|
|
Apply(1f);
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (!_active) return;
|
|
float dur = settings != null ? settings.hitFlashSeconds : 0.15f;
|
|
_timer -= Time.deltaTime;
|
|
if (_timer <= 0f) { Clear(); return; }
|
|
Apply(dur > 0f ? Mathf.Clamp01(_timer / dur) : 0f);
|
|
}
|
|
|
|
/// <summary>t = 1 이면 플래시 최대, 0 이면 원래 색.</summary>
|
|
private void Apply(float t)
|
|
{
|
|
Color flash = settings != null ? settings.hitFlashColor : new Color(1f, 0.3f, 0.22f, 1f);
|
|
float strength = (settings != null ? settings.hitFlashStrength : 0.85f) * t;
|
|
|
|
for (int r = 0; r < renderers.Length; r++)
|
|
{
|
|
var rend = renderers[r];
|
|
if (rend == null) continue;
|
|
rend.GetPropertyBlock(_block);
|
|
for (int i = 0; i < _propIds.Length; i++)
|
|
{
|
|
if (!_hasProp[i]) continue;
|
|
Color baseCol = _originals[r][i];
|
|
Color c = Color.Lerp(baseCol, flash, strength);
|
|
c.a = baseCol.a;
|
|
_block.SetColor(_propIds[i], c);
|
|
}
|
|
rend.SetPropertyBlock(_block);
|
|
}
|
|
}
|
|
|
|
/// <summary>덮어쓴 프로퍼티를 걷어내 원래 머티리얼 값으로 되돌린다.</summary>
|
|
public void Clear()
|
|
{
|
|
_active = false;
|
|
_timer = 0f;
|
|
if (renderers == null) return;
|
|
for (int r = 0; r < renderers.Length; r++)
|
|
if (renderers[r] != null) renderers[r].SetPropertyBlock(null);
|
|
}
|
|
}
|
|
}
|