히든분기
This commit is contained in:
@@ -269,17 +269,41 @@ private async Awaitable PlayEntry(DialogEntry entry)
|
||||
var node = entry.Group.StartNode;
|
||||
while (node != null)
|
||||
{
|
||||
await PlayNode(node);
|
||||
// 이 노드가 히든 분기를 가지면, 노드가 재생되는 동안 제스처 감시를 무장한다.
|
||||
// (무장 안 된 노드는 아래 대기/선택이 기존과 완전히 동일하게 동작)
|
||||
bool armed = node.HiddenBranch != null;
|
||||
if (armed) HiddenBranchResolver.Arm(node.HiddenGestureKey);
|
||||
try
|
||||
{
|
||||
bool diverted = await PlayNode(node); // 대사 표시 + 대기(무장 시 제스처 감시 포함)
|
||||
|
||||
if (node.Choices != null && node.Choices.Count > 0)
|
||||
{
|
||||
int picked = await WaitForChoice(node);
|
||||
RecordChoice(node, picked);
|
||||
node = node.Choices[picked].DestinationNode;
|
||||
if (diverted)
|
||||
{
|
||||
RecordHiddenChoice(node);
|
||||
node = node.HiddenBranch; // 대사 도중 제스처 발동 → 몰래 분기
|
||||
}
|
||||
else if (node.Choices != null && node.Choices.Count > 0)
|
||||
{
|
||||
int picked = await WaitForChoice(node); // 메뉴(무장 시 제스처 감시 포함)
|
||||
if (picked == DivertIndex)
|
||||
{
|
||||
RecordHiddenChoice(node);
|
||||
node = node.HiddenBranch; // 메뉴 도중 제스처 발동 → 메뉴엔 없던 히든 분기
|
||||
}
|
||||
else
|
||||
{
|
||||
RecordChoice(node, picked);
|
||||
node = node.Choices[picked].DestinationNode;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node.Next;
|
||||
}
|
||||
}
|
||||
else
|
||||
finally
|
||||
{
|
||||
node = node.Next;
|
||||
if (armed) HiddenBranchResolver.Disarm();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,7 +457,8 @@ private void LateUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
private async Awaitable PlayNode(DialogNode node)
|
||||
// 반환: true = 대기 도중 히든 제스처가 발동됨(→ HiddenBranch로 분기), false = 평범하게 진행
|
||||
private async Awaitable<bool> PlayNode(DialogNode node)
|
||||
{
|
||||
// 화자 옆 DialogHud에 대사 표시
|
||||
// (배치는 화자의 DialogHudPlacement 담당, 없으면 DialogHud 기본값. 이름은 노드 오버라이드 우선)
|
||||
@@ -528,6 +553,11 @@ private async Awaitable PlayNode(DialogNode node)
|
||||
}
|
||||
|
||||
// 진행 방식 결정
|
||||
// 히든 분기가 무장된 노드는 대기 중 제스처를 함께 감시(레이스)한다.
|
||||
// 무장 안 된 노드는 아래 기존 대기 그대로 → 동작 100% 동일, 반환 false.
|
||||
if (HiddenBranchResolver.Armed)
|
||||
return await WaitAdvanceOrDivert(node);
|
||||
|
||||
if (node.WaitForInput)
|
||||
{
|
||||
await WaitForAdvanceInput(); // B버튼 입력이 있어야만 다음으로
|
||||
@@ -543,6 +573,7 @@ private async Awaitable PlayNode(DialogNode node)
|
||||
else
|
||||
await WaitForAdvanceInput(); // 지정 시간이 없으면 입력으로 진행
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 노드의 EventKey와 같은 Key를 가진 이벤트들을 호출
|
||||
@@ -564,17 +595,102 @@ private void RecordChoice(DialogNode node, int index)
|
||||
StoryManager.Instance.RecordChoice(code);
|
||||
}
|
||||
|
||||
// 히든 분기 기록: 노드의 HiddenCode를 선택지 Code와 동일하게 StoryState에 영구 기록
|
||||
private void RecordHiddenChoice(DialogNode node)
|
||||
{
|
||||
string code = DialogVariables.Format(node.HiddenCode); // {token} 치환
|
||||
if (!string.IsNullOrEmpty(code))
|
||||
StoryManager.Instance.RecordChoice(code);
|
||||
}
|
||||
|
||||
// 히든 분기 신호값 — 선택지 인덱스(0..n-1)와 절대 겹치지 않는 값.
|
||||
private const int DivertIndex = -1;
|
||||
|
||||
private async Awaitable<int> WaitForChoice(DialogNode node)
|
||||
{
|
||||
//선택을 기다리는 함수 수정해서 사용할것
|
||||
|
||||
if (ChoiceHud.Instance == null)
|
||||
{
|
||||
Debug.LogWarning("[DialogPlayer] ChoiceHud 없음 — 0번 자동 선택");
|
||||
return 0;
|
||||
}
|
||||
return await ChoiceHud.Instance.Show(node.ChoiceQuestion, node.Choices);
|
||||
|
||||
// 무장 안 된 노드는 기존과 동일 — 그냥 메뉴 선택을 기다린다.
|
||||
if (!HiddenBranchResolver.Armed)
|
||||
return await ChoiceHud.Instance.Show(node.ChoiceQuestion, node.Choices);
|
||||
|
||||
// 무장된 노드: 메뉴가 떠 있는 동안 제스처가 들어오면 메뉴를 취소하고 히든으로 분기.
|
||||
if (HiddenBranchResolver.Fired)
|
||||
return DivertIndex; // 메뉴가 뜨기 전에 이미 발동한 경우
|
||||
|
||||
void OnFired() => ChoiceHud.Instance.CancelPending(); // 제스처 → 메뉴 즉시 취소
|
||||
HiddenBranchResolver.FiredEvent += OnFired;
|
||||
try
|
||||
{
|
||||
return await ChoiceHud.Instance.Show(node.ChoiceQuestion, node.Choices);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 우리가 제스처로 취소한 것이면 히든 분기, 아니면(씬 전환 등) 위로 전파
|
||||
if (HiddenBranchResolver.Fired) return DivertIndex;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
HiddenBranchResolver.FiredEvent -= OnFired;
|
||||
}
|
||||
}
|
||||
|
||||
// 노드 대기 + 히든 제스처 감시(레이스). 무장된 노드에서만 호출된다.
|
||||
// 반환: true = 대기 도중 제스처 발동(→히든 분기), false = 평범하게 진행(입력/시간)
|
||||
private async Awaitable<bool> WaitAdvanceOrDivert(DialogNode node)
|
||||
{
|
||||
// 기존 PlayNode 대기 규칙 그대로 계산 — 입력 대기냐, 시간 대기냐
|
||||
bool waitForInput;
|
||||
float timeoutSeconds;
|
||||
if (node.WaitForInput)
|
||||
{
|
||||
waitForInput = true; timeoutSeconds = -1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
float wait = (node.Voice != null && node.Voice.Clip != null)
|
||||
? node.Voice.Clip.length
|
||||
: node.LineDuration;
|
||||
if (wait > 0f) { waitForInput = false; timeoutSeconds = wait; }
|
||||
else { waitForInput = true; timeoutSeconds = -1f; }
|
||||
}
|
||||
|
||||
var im = InputManager.Instance;
|
||||
bool advance = false;
|
||||
void OnAdvance() => advance = true;
|
||||
if (waitForInput && im != null) im.OnDialogNext_Event += OnAdvance;
|
||||
|
||||
// 입력 대기인데 InputManager가 없으면 기존 WaitForAdvanceInput처럼 1초 후 진행
|
||||
float timeLeft = timeoutSeconds;
|
||||
if (waitForInput && im == null) timeLeft = 1f;
|
||||
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (HiddenBranchResolver.Fired) return true; // 제스처 발동 → 히든 분기
|
||||
if (waitForInput && advance) return false; // B버튼 → 평범하게 진행
|
||||
if (timeLeft >= 0f)
|
||||
{
|
||||
timeLeft -= Time.deltaTime;
|
||||
if (timeLeft <= 0f) return false; // 시간 경과 → 평범하게 진행
|
||||
}
|
||||
await Awaitable.NextFrameAsync(destroyCancellationToken);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return false; // 대기 중 파괴/씬 전환 — 기존과 동일하게 조용히 종료
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (waitForInput && im != null) im.OnDialogNext_Event -= OnAdvance;
|
||||
}
|
||||
}
|
||||
|
||||
// 대화 진행 입력(OnDialogNext = VR B버튼) 한 번을 대기
|
||||
|
||||
Reference in New Issue
Block a user