113 lines
4.3 KiB
C#
113 lines
4.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
|
|
// 표정에 따라 캐릭터의 "커스텀 연출"을 켜고 끄는 범용 컴포넌트. 캐릭터 루트에 붙인다.
|
|
// 눈 하이라이트, 볼 홍조, 땀방울, 눈동자 색 등 표정별로 달라지는 것들을 Key로 등록해 두고,
|
|
// ExpressionData.CustomKeys에 그 Key를 넣으면 그 표정이 재생되는 동안 활성화된다. (DialogPlayer가 호출)
|
|
//
|
|
// 각 Effect는 아래 중 필요한 것만 채운다 (여러 개 동시 가능):
|
|
// - 텍스처 스왑 : Texture Target + Texture Property + Active/Inactive Texture (MaterialPropertyBlock — 가볍고 원본 머티리얼 안 건드림)
|
|
// - 오브젝트 on/off : Toggle Object (+ Invert)
|
|
// - 그 외 무엇이든 : On Set (UnityEvent<bool>) — 활성 시 true, 비활성 시 false
|
|
public class CharacterExpressionCustom : MonoBehaviour
|
|
{
|
|
[Serializable] public class BoolEvent : UnityEvent<bool> { }
|
|
|
|
[Serializable]
|
|
public class Effect
|
|
{
|
|
[Tooltip("표정(ExpressionData.CustomKeys)에서 참조할 키. 예: eyeHighlightOff, blush, sweat")]
|
|
public string Key;
|
|
|
|
[Header("텍스처 스왑 (선택)")]
|
|
[Tooltip("텍스처를 바꿀 렌더러. 비우면 텍스처 스왑 안 함")]
|
|
public Renderer TextureTarget;
|
|
[Tooltip("바꿀 텍스처 프로퍼티. 이 프로젝트 BMAC_Toon 알베도=_Texture2D (URP Lit=_BaseMap)")]
|
|
public string TextureProperty = "_Texture2D";
|
|
[Tooltip("활성 시 텍스처. 비우면 원본 유지")]
|
|
public Texture ActiveTexture;
|
|
[Tooltip("비활성(기본) 시 텍스처. 비우면 시작 시점의 원본으로 복원")]
|
|
public Texture InactiveTexture;
|
|
|
|
[Header("오브젝트 on/off (선택)")]
|
|
public GameObject ToggleObject;
|
|
[Tooltip("켜면 반전 — 활성 시 오브젝트를 '끈다' (예: 하이라이트 오브젝트 숨기기)")]
|
|
public bool Invert;
|
|
|
|
[Header("그 외 (선택)")]
|
|
[Tooltip("활성 시 true, 비활성 시 false로 호출 — 인스펙터에서 무엇이든 연결")]
|
|
public BoolEvent OnSet;
|
|
|
|
// 런타임 내부 상태
|
|
[NonSerialized] public bool Active;
|
|
[NonSerialized] public bool Captured;
|
|
[NonSerialized] public int PropId;
|
|
[NonSerialized] public Texture CapturedDefault; // 시작 시점의 원본 텍스처
|
|
}
|
|
|
|
[SerializeField] private List<Effect> _effects = new();
|
|
|
|
private MaterialPropertyBlock _mpb;
|
|
|
|
private void Awake()
|
|
{
|
|
_mpb = new MaterialPropertyBlock();
|
|
foreach (var e in _effects)
|
|
Capture(e);
|
|
}
|
|
|
|
private static void Capture(Effect e)
|
|
{
|
|
if (e.Captured) return;
|
|
e.PropId = Shader.PropertyToID(e.TextureProperty);
|
|
if (e.TextureTarget != null && e.TextureTarget.sharedMaterial != null)
|
|
e.CapturedDefault = e.TextureTarget.sharedMaterial.GetTexture(e.PropId);
|
|
e.Captured = true;
|
|
}
|
|
|
|
// 주어진 Key 집합에 맞춰 모든 Effect를 켜고 끈다 (집합에 없는 Effect는 비활성/기본으로).
|
|
public void SetActiveKeys(ICollection<string> keys)
|
|
{
|
|
foreach (var e in _effects)
|
|
{
|
|
bool want = keys != null && keys.Count > 0
|
|
&& !string.IsNullOrEmpty(e.Key) && keys.Contains(e.Key);
|
|
Apply(e, want);
|
|
}
|
|
}
|
|
|
|
// 전부 기본(비활성)으로 되돌린다 — 대화 종료 시
|
|
public void ResetAll()
|
|
{
|
|
foreach (var e in _effects)
|
|
Apply(e, false);
|
|
}
|
|
|
|
private void Apply(Effect e, bool active)
|
|
{
|
|
Capture(e);
|
|
if (e.Active == active) return; // 상태 동일하면 스킵
|
|
e.Active = active;
|
|
|
|
// 텍스처 스왑
|
|
if (e.TextureTarget != null)
|
|
{
|
|
var tex = active
|
|
? (e.ActiveTexture != null ? e.ActiveTexture : e.CapturedDefault)
|
|
: (e.InactiveTexture != null ? e.InactiveTexture : e.CapturedDefault);
|
|
e.TextureTarget.GetPropertyBlock(_mpb); // 기존 MPB 값 보존
|
|
_mpb.SetTexture(e.PropId, tex);
|
|
e.TextureTarget.SetPropertyBlock(_mpb);
|
|
}
|
|
|
|
// 오브젝트 on/off
|
|
if (e.ToggleObject != null)
|
|
e.ToggleObject.SetActive(active ^ e.Invert);
|
|
|
|
// 그 외
|
|
e.OnSet?.Invoke(active);
|
|
}
|
|
}
|