Files
StoryGame_Unity/Assets/02_Scripts/Communication/Dialog/DialogNode.cs
2026-08-06 09:30:08 +09:00

103 lines
5.0 KiB
C#

using System.Collections.Generic;
using UnityEngine;
// 노드의 역할. 서로 배타적이므로 플래그 여러 개가 아니라 하나의 종류로 둔다.
public enum DialogNodeKind
{
[InspectorName("대사")] Line, // 평범한 대사 노드
[InspectorName("호감도 분기")] AffectionCheck, // 대사 없이 조건만 검사해 즉시 라우팅
[InspectorName("종료")] End, // 대화를 끝낸다 (BGM 처리만 정함)
}
// 이 대사에서 이미 떠 있던 화면 그림을 걷어낼지.
// 그림 지정이 "비우면 변경 없음"(BGM과 같은 규칙)이라 지우는 길을 따로 열어 둔 것이다.
public enum SpriteClear
{
[InspectorName("없음")] None,
[InspectorName("앞 그림")] Front,
[InspectorName("옆 그림")] Side,
[InspectorName("둘 다")] Both,
}
[CreateAssetMenu(menuName = "Communication/Dialog Node")]
public class DialogNode : ScriptableObject
{
[Tooltip("이 노드의 역할. 그래프에서 어떤 노드를 썼는지에 따라 임포터가 정한다")]
public DialogNodeKind Kind = DialogNodeKind.Line;
[Header("Speaker")]
public CharacterData Speaker;
[Tooltip("비우면 Speaker의 이름 그대로, 채우면 이 이름으로 표시 (예: ???)")]
public string SpeakerNameOverride;
[Header("Content")]
[TextArea(2,5)] public string TalkText;
public GestureData Gesture;
public ExpressionData Expression;
public VoiceClip Voice;
// 진행은 항상 플레이어 입력(OnDialogNext)으로 넘어간다.
[Header("Presentation")]
[Tooltip("있으면 이 대사부터 이 BGM으로 갈아탄다. 비우면 변경 없음 — " +
"다시 바꾸기 전까지 계속 이어진다")]
public AudioClip Bgm;
[Tooltip("이 대사가 시작될 때 한 번 재생할 효과음 (문 여는 소리, 쿵 소리 등). " +
"BGM과 달리 이어지지 않고 1회성이다")]
public AudioClip Sfx;
[Tooltip("이 대사만의 타이핑 연출(속도·글자색·타이핑 사운드). " +
"비우면 DialogHud의 기본 스타일을 쓴다")]
public TypewriterStyle Typewriter;
[Header("Sprite")]
[Tooltip("이 대사 동안 화면 앞쪽(가운데 아래)에 세울 그림. 인물이 보통이지만 물건·서류도 된다. " +
"비우면 변경 없음 — BGM과 같은 규칙이라 인물이 서 있는 동안 매 대사에 다시 꽂을 필요가 없다. " +
"대화가 끝나면 대화 전에 떠 있던 그림으로 되돌아간다")]
public Sprite FrontSprite;
[Tooltip("이 대사 동안 화면 옆(왼쪽)에 놓을 그림. 제시한 물건을 놓고 설명할 때 쓴다. " +
"비우면 변경 없음. 대화가 끝나면 자동으로 걷힌다")]
public Sprite SideSprite;
[Tooltip("이미 떠 있던 그림을 이 대사에서 걷어낸다. 그림 지정이 '비우면 변경 없음'이라 " +
"지울 때만 쓴다. 같은 노드에서 새 그림도 지정했다면 새 그림이 이긴다")]
public SpriteClear ClearSprite;
[Header("Flow")]
public DialogNode Next; // 선택지 없을 때 자동으로 갈 노드
public List<DialogChoice> Choices; // 있으면 플레이어 선택 대기
[Header("Hidden Branch")]
[Tooltip("이 대사가 재생되는 동안 특정 행동(부위 터치·증거품 제출 등)을 하면 " +
"Next/선택지 대신 몰래 분기한다. 키마다 다른 목적지를 줄 수 있고, " +
"Key가 빈 항목은 나머지 전부를 받는 catch-all이 된다. " +
"비우면 히든 분기 없음 — 평소엔 존재하지 않는 것처럼 보인다")]
public List<HiddenBranch> HiddenBranches = new();
[Header("Affection Branch")]
[Tooltip("(Kind = 호감도 분기 전용) 검사할 호감도 조건들 (캐릭터·연산자·값 + 다음 조건과의 and/or). " +
"캐릭터를 비우면 대화 주인 NPC. AND가 OR보다 우선. 비어 있으면 무조건 통과")]
public List<AffectionRequirement> AffectionRequirements = new();
[Tooltip("조건을 만족했을 때 갈 노드 (실패하면 Next로)")]
public DialogNode AffectionPassBranch;
[Header("End")]
[Tooltip("(Kind = 종료 전용) 켜면 대화가 끝나도 마지막에 재생 중이던 BGM을 유지한다. " +
"끄면 장소 BGM으로 복귀. 종료 노드마다 따로 정할 수 있어서 분기별로 다르게 끝낼 수 있다")]
public bool KeepBgmOnEnd;
[Header("ChoiceQuestion")]
[TextArea(2,5)] public string ChoiceQuestion;
[Header("Story")]
[Tooltip("0이 아니면 이 노드 재생 시 화자(비우면 대화 주인 NPC)의 호감도를 이만큼 증감")]
public int Affection;
[Tooltip("0이 아니면 이 노드 재생 시 메인 진행도를 이만큼 증가. " +
"분기 끝 노드마다 다른 값을 주면 선택지에 따라 진행도를 다르게 줄 수 있다")]
public int Progress;
}