2026-06-09 다이얼로그 프로토타입
This commit is contained in:
Binary file not shown.
@@ -176,16 +176,14 @@ private async Awaitable PlayNode(DialogNode node)
|
|||||||
private async Awaitable<int> WaitForChoice(DialogNode node)
|
private async Awaitable<int> WaitForChoice(DialogNode node)
|
||||||
{
|
{
|
||||||
//선택을 기다리는 함수 수정해서 사용할것
|
//선택을 기다리는 함수 수정해서 사용할것
|
||||||
/*
|
|
||||||
if (ChoiceHud.Instance == null)
|
if (ChoiceHud.Instance == null)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[DialogPlayer] ChoiceHud 없음 — 0번 자동 선택");
|
Debug.LogWarning("[DialogPlayer] ChoiceHud 없음 — 0번 자동 선택");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return await ChoiceHud.Instance.Show(node.Speaker, node.ChoiceQuestion ,node.Choices);
|
return await ChoiceHud.Instance.Show(node.Speaker, node.ChoiceQuestion ,node.Choices);
|
||||||
*/
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Awaitable WaitForAdvanceInput()
|
private async Awaitable WaitForAdvanceInput()
|
||||||
@@ -193,4 +191,19 @@ private async Awaitable WaitForAdvanceInput()
|
|||||||
// TODO: VR 컨트롤러 버튼 입력 대기. 일단은 1초 대기
|
// TODO: VR 컨트롤러 버튼 입력 대기. 일단은 1초 대기
|
||||||
await Awaitable.WaitForSecondsAsync(1f);
|
await Awaitable.WaitForSecondsAsync(1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//테스트용
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
if (Mouse.current == null) return;
|
||||||
|
if (!Mouse.current.leftButton.wasPressedThisFrame) return;
|
||||||
|
if (Camera.main == null) return;
|
||||||
|
|
||||||
|
var ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
|
||||||
|
if (Physics.Raycast(ray, out var hit) && hit.transform.IsChildOf(transform))
|
||||||
|
{
|
||||||
|
Debug.Log("캐릭터 클릭");
|
||||||
|
Play();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: f954c56664544ab45987cd3f22c833bc
|
guid: 540f24a679513b344b55eda149fcb29c
|
||||||
TextScriptImporter:
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
120
Assets/02_Scripts/UI/ChoiceHud.cs
Normal file
120
Assets/02_Scripts/UI/ChoiceHud.cs
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
// 화자 몸통 앞에 떠 있는 World-space 선택지 UI 싱글턴
|
||||||
|
// DialogPlayer가 Show()를 await해서 선택된 인덱스를 받아감
|
||||||
|
public class ChoiceHud : MonoBehaviour
|
||||||
|
{
|
||||||
|
public static ChoiceHud Instance { get; private set; }
|
||||||
|
|
||||||
|
[Header("Refs")]
|
||||||
|
[SerializeField] private GameObject _root;
|
||||||
|
[SerializeField] private Transform _rowContainer;
|
||||||
|
[SerializeField] private DialogChoiceRow _rowPrefab;
|
||||||
|
[SerializeField] private TMP_Text ChoiceQuestion;
|
||||||
|
|
||||||
|
[Header("Placement")]
|
||||||
|
[SerializeField] private float _chestHeight = 1.2f; // 화자 발 기준 가슴 높이
|
||||||
|
[SerializeField] private float _forwardOffset = 0.5f; // 화자→플레이어 방향으로 띄울 거리
|
||||||
|
|
||||||
|
private Transform _speakerTransform;
|
||||||
|
private readonly List<DialogChoiceRow> _rows = new();
|
||||||
|
private AwaitableCompletionSource<int> _completion;
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
if (Instance != null && Instance != this) { Destroy(gameObject); return; }
|
||||||
|
Instance = this;
|
||||||
|
if (_root == null) _root = gameObject;
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
if (Instance == this) Instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
// 진행 중 대기 정리 (씬 전환 등으로 비활성화될 때)
|
||||||
|
_completion?.TrySetCanceled();
|
||||||
|
_completion = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Awaitable<int> Show(CharacterData speaker,string choiceQuestion, List<DialogChoice> choices)
|
||||||
|
{
|
||||||
|
if (choices == null || choices.Count == 0) return 0;
|
||||||
|
|
||||||
|
_speakerTransform = speaker != null ? CharacterVoiceObject.Find(speaker)?.transform : null;
|
||||||
|
|
||||||
|
ChoiceQuestion.text = choiceQuestion;
|
||||||
|
ClearRows();
|
||||||
|
for (int i = 0; i < choices.Count; i++)
|
||||||
|
{
|
||||||
|
var row = Instantiate(_rowPrefab, _rowContainer);
|
||||||
|
row.Bind(i, choices[i].ChoiceText);
|
||||||
|
row.OnClicked += HandleClicked;
|
||||||
|
_rows.Add(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
_root.SetActive(true);
|
||||||
|
_completion = new AwaitableCompletionSource<int>();
|
||||||
|
|
||||||
|
int result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = await _completion.Awaitable;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_completion = null;
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleClicked(int index)
|
||||||
|
{
|
||||||
|
_completion?.TrySetResult(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Hide()
|
||||||
|
{
|
||||||
|
ChoiceQuestion.text = "";
|
||||||
|
ClearRows();
|
||||||
|
if (_root != null) _root.SetActive(false);
|
||||||
|
_speakerTransform = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearRows()
|
||||||
|
{
|
||||||
|
foreach (var row in _rows)
|
||||||
|
{
|
||||||
|
if (row == null) continue;
|
||||||
|
row.OnClicked -= HandleClicked;
|
||||||
|
Destroy(row.gameObject);
|
||||||
|
}
|
||||||
|
_rows.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LateUpdate()
|
||||||
|
{
|
||||||
|
if (_root == null || !_root.activeSelf) return;
|
||||||
|
if (_speakerTransform == null || Camera.main == null) return;
|
||||||
|
|
||||||
|
var camTr = Camera.main.transform;
|
||||||
|
|
||||||
|
// 화자에서 플레이어 카메라로 향하는 수평 방향 (yaw만)
|
||||||
|
Vector3 toCam = camTr.position - _speakerTransform.position;
|
||||||
|
toCam.y = 0f;
|
||||||
|
if (toCam.sqrMagnitude < 0.0001f) return;
|
||||||
|
Vector3 dir = toCam.normalized;
|
||||||
|
|
||||||
|
Vector3 chestWorld = _speakerTransform.position + Vector3.up * _chestHeight;
|
||||||
|
_root.transform.position = chestWorld + dir * _forwardOffset;
|
||||||
|
|
||||||
|
// 빌보드 — 캔버스의 -Z(읽는 면)가 카메라를 향하도록 +Z를 카메라 반대로
|
||||||
|
_root.transform.rotation = Quaternion.LookRotation(-dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/02_Scripts/UI/ChoiceHud.cs.meta
Normal file
2
Assets/02_Scripts/UI/ChoiceHud.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 66c54b72d69da6b4e9c30ef648aade40
|
||||||
26
Assets/02_Scripts/UI/DialogChoiceRow.cs
Normal file
26
Assets/02_Scripts/UI/DialogChoiceRow.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
public class DialogChoiceRow : MonoBehaviour
|
||||||
|
{
|
||||||
|
[SerializeField] private TMP_Text _text;
|
||||||
|
[SerializeField] private Button _button;
|
||||||
|
|
||||||
|
public event Action<int> OnClicked;
|
||||||
|
|
||||||
|
private int _index;
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
if (_button != null)
|
||||||
|
_button.onClick.AddListener(() => OnClicked?.Invoke(_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Bind(int index, string text)
|
||||||
|
{
|
||||||
|
_index = index;
|
||||||
|
if (_text != null) _text.text = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/02_Scripts/UI/DialogChoiceRow.cs.meta
Normal file
2
Assets/02_Scripts/UI/DialogChoiceRow.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 63cb7682c2757f74cad43848f593838f
|
||||||
8
Assets/04_Models/Choice.meta
Normal file
8
Assets/04_Models/Choice.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c038b57f026442c44b4173b9cbc00906
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/04_Models/Choice/Row.meta
Normal file
8
Assets/04_Models/Choice/Row.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d8ed44e79da1eed4d89009c073e6e325
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/04_Models/Choice/Row/ChoiceRow.prefab
LFS
Normal file
BIN
Assets/04_Models/Choice/Row/ChoiceRow.prefab
LFS
Normal file
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 79e9e3274eb3e724490ac16b6706b6ae
|
guid: a4c299230cdcd9442bde6e02b8823135
|
||||||
TextScriptImporter:
|
PrefabImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
@@ -1 +0,0 @@
|
|||||||
지울것
|
|
||||||
Binary file not shown.
Binary file not shown.
BIN
Assets/12_Font/Hakgyoansim_TteokbokkiB SDF.asset
LFS
Normal file
BIN
Assets/12_Font/Hakgyoansim_TteokbokkiB SDF.asset
LFS
Normal file
Binary file not shown.
8
Assets/12_Font/Hakgyoansim_TteokbokkiB SDF.asset.meta
Normal file
8
Assets/12_Font/Hakgyoansim_TteokbokkiB SDF.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 81f0fb85a86d25b4db2a69347ec056fd
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/12_Font/Hakgyoansim_TteokbokkiB.ttf
LFS
Normal file
BIN
Assets/12_Font/Hakgyoansim_TteokbokkiB.ttf
LFS
Normal file
Binary file not shown.
21
Assets/12_Font/Hakgyoansim_TteokbokkiB.ttf.meta
Normal file
21
Assets/12_Font/Hakgyoansim_TteokbokkiB.ttf.meta
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 61af039048c279940929bb3263a04712
|
||||||
|
TrueTypeFontImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 4
|
||||||
|
fontSize: 16
|
||||||
|
forceTextureCase: -2
|
||||||
|
characterSpacing: 0
|
||||||
|
characterPadding: 1
|
||||||
|
includeFontData: 1
|
||||||
|
fontNames:
|
||||||
|
- Hakgyoansim TTeokbokki B
|
||||||
|
fallbackFontReferences: []
|
||||||
|
customCharacters:
|
||||||
|
fontRenderingMode: 0
|
||||||
|
ascentCalculationMode: 1
|
||||||
|
useLegacyBoundsCalculation: 0
|
||||||
|
shouldRoundAdvanceValue: 1
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1 +0,0 @@
|
|||||||
지울것
|
|
||||||
Reference in New Issue
Block a user