Files
StoryGame_Unity/Assets/02_Scripts/Story/CharacterSlot.cs
2026-08-06 20:49:36 +09:00

47 lines
3.0 KiB
C#

using UnityEngine;
// 캐릭터 하나의 등장 자리.
// 이 캐릭터가 지금 장소에서 걸 수 있는 대화(StoryBeat)가 하나라도 있으면 캐릭터를 켜고, 없으면 끈다.
// 갱신은 LocationManager가 장소 입장 시 / 스토리 상태 변화 시 Refresh를 호출해서 이뤄진다.
//
// 슬롯은 장소 프리팹이 아니라 **씬**에 두고 LocationManager의 Character Slots에 연결한다.
// 어느 장소에 나타날지는 오브젝트 배치가 아니라 StoryDatabase가 정한다 —
// 배치까지 같은 사실을 표현하면 원본이 둘이 되어 "비트는 넣었는데 슬롯을 안 넣음" 같은
// 어긋남이 생기기 때문이다. 캐릭터가 늘 같은 자리에 선다는 전제이고,
// 장소마다 자리가 달라져야 하면 그때 LocationData에 앵커를 두고 옮기면 된다.
//
// 배치법: 이 컴포넌트는 항상 켜져 있는 빈 오브젝트에 붙이고,
// 캐릭터 본체(CharacterVoiceObject + DialogPlayer)는 그 자식으로 두고 _character에 연결.
// 참고: 조건 없는 잡담 비트를 하나 등록해 두면 그 캐릭터는 그 장소에 항상 등장한다.
public class CharacterSlot : MonoBehaviour
{
[Tooltip("캐릭터 본체 (CharacterVoiceObject + DialogPlayer가 붙은 자식 오브젝트)")]
[SerializeField] private CharacterVoiceObject _character;
[Tooltip("켜면 걸 대화가 없어도 오브젝트를 끄지 않는다.\n\n" +
"대화 중에만 끼어드는 동행자(마요이 등)용이다. 오브젝트가 살아 있어야 " +
"CharacterVoiceObject가 등록돼 대사가 포즈·보이스로 찾을 수 있는데, " +
"그렇다고 화면에 서 있어야 하는 건 아니다 — 화면 표시는 CharacterPoses의 " +
"Start Pose를 '숨김'으로 두어 따로 정한다.\n\n" +
"이 인물이 그 장소의 대화 상대가 되는 때(예: 구치소에 갇힘)에는 " +
"그 장소·인물의 StoryBeat를 조건과 함께 등록하면 된다 — " +
"그러면 아래 IsPresent가 켜지면서 「이야기한다」 대상이 된다")]
[SerializeField] private bool _alwaysActive;
// 이 슬롯의 캐릭터에게 지금 걸 수 있는 대화가 있는가 = 이 장소의 대화 상대인가.
// 동행자 슬롯은 오브젝트가 켜져 있어도 이 값이 false라 「이야기한다」 대상이 되지 않는다.
public bool IsPresent { get; private set; }
// 이 슬롯 캐릭터의 대화 재생기 (캐릭터 본체에 같이 붙어 있다)
public DialogPlayer Player => _character != null ? _character.GetComponent<DialogPlayer>() : null;
public void Refresh(StoryDatabase database, LocationData location)
{
IsPresent = false;
if (_character == null || _character.Character == null) return;
IsPresent = database.HasPlayableBeat(location, _character.Character);
_character.gameObject.SetActive(IsPresent || _alwaysActive);
}
}