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() : 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); } }