2026-07-10 다이얼로그 시스템 대대적 수정

This commit is contained in:
2026-07-10 12:17:10 +09:00
parent 5edc62d6c4
commit 51056f0994
28 changed files with 2173 additions and 64 deletions

Binary file not shown.

View File

@@ -0,0 +1,22 @@
using System.Collections.Generic;
using UnityEngine;
// 이 캐릭터가 화자일 때 대화창(DialogHud)을 어디에 띄울지 캐릭터별로 지정한다.
// 진행 중인 대화에 다른 NPC의 대사가 끼어들 때도 화자 본인의 이 값이 쓰인다.
// 이 컴포넌트가 없으면 DialogHud 자체의 기본값으로 배치된다 (후보 자동 회피 없음).
// CharacterVoiceObject와 같은 오브젝트(NPC 루트)에 붙일 것.
public class DialogHudPlacement : MonoBehaviour
{
[Tooltip("배치 후보들 — 위에서부터 검사해 벽에 안 겹치고 안 가려지는 첫 후보 사용. " +
"각 후보가 완전한 배치값(높이/앞/좌우/회전)이며 캐릭터 크기에 맞게 조절할 것. " +
"전부 실패하면 첫 후보(기본)로 표시")]
public List<DialogHud.PlacementCandidate> Candidates = new()
{
new DialogHud.PlacementCandidate { Name = "기본", Height = 1.2f, Forward = 0.7f, Lateral = 0f },
new DialogHud.PlacementCandidate { Name = "우", Height = 1.2f, Forward = 0.5f, Lateral = 0.8f },
new DialogHud.PlacementCandidate { Name = "좌", Height = 1.2f, Forward = 0.5f, Lateral = -0.8f },
new DialogHud.PlacementCandidate { Name = "우상단", Height = 1.8f, Forward = 0.5f, Lateral = 0.5f },
new DialogHud.PlacementCandidate { Name = "좌상단", Height = 1.8f, Forward = 0.5f, Lateral = -0.5f },
new DialogHud.PlacementCandidate { Name = "중앙상단", Height = 2.0f, Forward = 0.5f, Lateral = 0f },
};
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c42d3e6d9a0d3fc4788ddda76e366167

View File

@@ -8,6 +8,9 @@ public class DialogNode : ScriptableObject
[Header("Speaker")] [Header("Speaker")]
public CharacterData Speaker; public CharacterData Speaker;
[Tooltip("비우면 Speaker의 이름 그대로, 채우면 이 이름으로 표시 (예: ???)")]
public string SpeakerNameOverride;
[Header("Content")] [Header("Content")]
[TextArea(2,5)] public string TalkText; [TextArea(2,5)] public string TalkText;
public GestureData Gesture; public GestureData Gesture;
@@ -25,7 +28,9 @@ public class DialogNode : ScriptableObject
[Header("Behavior")] [Header("Behavior")]
public bool LookAtPlayer; public bool LookAtPlayer;
public bool ForcePlayerLook; // true면 이 대사 시작 시 플레이어(카메라)가 화자를 바라보도록 리그를 회전
public bool WaitForInput; // true면 LineDuration 무시하고 B버튼(OnDialogNext) 입력까지 대기 public bool WaitForInput; // true면 LineDuration 무시하고 B버튼(OnDialogNext) 입력까지 대기
public bool StagingOnly; // true면 대화창을 숨기고 연출(회전·제스처·VFX·이벤트·대기)만 수행
[Header("Flow")] [Header("Flow")]
public DialogNode Next; // 선택지 없을 때 자동으로 갈 노드 public DialogNode Next; // 선택지 없을 때 자동으로 갈 노드

View File

@@ -42,11 +42,7 @@ public struct NodeEvent
[Tooltip("말을 건 뒤 대화창(선택 메뉴·첫 대사)이 뜨기까지의 딜레이(초)")] [Tooltip("말을 건 뒤 대화창(선택 메뉴·첫 대사)이 뜨기까지의 딜레이(초)")]
[Min(0)] [SerializeField] private float _dialogStartDelay = 0.2f; [Min(0)] [SerializeField] private float _dialogStartDelay = 0.2f;
[Header("Dialog HUD Placement")] // 씬에서 캐릭터 위치/주변(벽 등)에 맞춰 조절 // HUD 배치는 화자(NPC)의 DialogHudPlacement 컴포넌트가 담당한다 (없으면 DialogHud 기본값).
[SerializeField] private float _hudChestHeight = 1.2f; // 화자 발 기준 가슴 높이
[SerializeField] private float _hudForwardOffset = 0.5f; // 화자가 바라보는 방향으로 띄울 거리
[SerializeField] private float _hudLateralOffset = 0f; // 좌우 오프셋 (+ 화자와 마주보는 시점 오른쪽)
[SerializeField] private Vector3 _hudRotationOffset = Vector3.zero; // 화자 회전 기준 추가 회전 (+α, 오일러 각)
[Header("Dialog Events")] [Header("Dialog Events")]
[Tooltip("노드의 Event Key와 같은 Key가 그 노드 재생 시 호출됨")] [Tooltip("노드의 Event Key와 같은 Key가 그 노드 재생 시 호출됨")]
@@ -54,10 +50,11 @@ public struct NodeEvent
private CharacterVoiceObject _voice; // 이 NPC의 캐릭터 정보 (호감도 조건 대상) private CharacterVoiceObject _voice; // 이 NPC의 캐릭터 정보 (호감도 조건 대상)
private Animator _animator; private Animator _animator;
private int _initialGestureHash;
private int _initialExpressionHash;
private bool _hasInitialExpression;
private readonly Dictionary<Transform, Quaternion> _originalRotations = new(); private readonly Dictionary<Transform, Quaternion> _originalRotations = new();
// 대화 중 제스처/표정을 재생한 Animator들의 원래 상태 — 대화 종료 시 전부 복원.
// (끼어든 다른 NPC의 Animator도 포함되므로 딕셔너리로 추적한다)
private readonly Dictionary<Animator, (int gestureHash, int expressionHash, bool hasExpression)> _touchedAnimators = new();
public bool IsPlaying { get; private set; } public bool IsPlaying { get; private set; }
// 지금 실제 대사를 재생 중인 DialogPlayer (전역 1개) — 이때 다른 NPC의 Play()는 무시된다. // 지금 실제 대사를 재생 중인 DialogPlayer (전역 1개) — 이때 다른 NPC의 Play()는 무시된다.
@@ -67,17 +64,7 @@ public struct NodeEvent
private void Awake() private void Awake()
{ {
_voice = GetComponent<CharacterVoiceObject>(); _voice = GetComponent<CharacterVoiceObject>();
_animator = GetComponentInChildren<Animator>(); _animator = GetComponentInChildren<Animator>(); // 화자를 못 찾을 때의 폴백 Animator
if (_animator != null)
{
_initialGestureHash = _animator.GetCurrentAnimatorStateInfo(0).fullPathHash;
if (_animator.layerCount > 1)
{
_initialExpressionHash = _animator.GetCurrentAnimatorStateInfo(1).fullPathHash;
_hasInitialExpression = true;
}
}
} }
private void OnDestroy() private void OnDestroy()
@@ -168,7 +155,7 @@ private async Awaitable<int> SelectDialog(List<int> playable)
// ChoiceHud는 DialogHud를 따라 배치되므로, 먼저 화자 옆에 HUD를 띄운다. // ChoiceHud는 DialogHud를 따라 배치되므로, 먼저 화자 옆에 HUD를 띄운다.
// (플레이어 쪽 회전은 Play() 시작 시 이미 걸려 있음) // (플레이어 쪽 회전은 Play() 시작 시 이미 걸려 있음)
if (DialogHud.Instance != null) if (DialogHud.Instance != null)
DialogHud.Instance.Show(_voice.Character, _dialogSelectPrompt, _hudChestHeight, _hudForwardOffset, _hudLateralOffset, _hudRotationOffset); DialogHud.Instance.Show(_voice.Character, _dialogSelectPrompt);
var options = new List<DialogChoice>(playable.Count); var options = new List<DialogChoice>(playable.Count);
foreach (int i in playable) foreach (int i in playable)
@@ -235,12 +222,29 @@ private async Awaitable PlayEntry(DialogEntry entry)
} }
} }
// 대화 중 제스처/표정을 재생했던 모든 Animator(끼어든 NPC 포함)를 원래 상태로 복원
private void RestoreDefaultAnimations() private void RestoreDefaultAnimations()
{ {
if (_animator == null) return; foreach (var kvp in _touchedAnimators)
_animator.CrossFade(_initialGestureHash, 0.3f, 0, normalizedTimeOffset: 0f); {
if (_hasInitialExpression) var anim = kvp.Key;
_animator.CrossFade(_initialExpressionHash, 0.3f, 1, normalizedTimeOffset: 0f); if (anim == null) continue;
anim.CrossFade(kvp.Value.gestureHash, 0.3f, 0, normalizedTimeOffset: 0f);
if (kvp.Value.hasExpression)
anim.CrossFade(kvp.Value.expressionHash, 0.3f, 1, normalizedTimeOffset: 0f);
}
_touchedAnimators.Clear();
}
// 처음 건드리는 Animator면 현재 상태를 기억해 둔다 (대화 종료 시 복원 기준)
private void CaptureInitialAnimState(Animator anim)
{
if (_touchedAnimators.ContainsKey(anim)) return;
bool hasExpression = anim.layerCount > 1;
_touchedAnimators[anim] = (
anim.GetCurrentAnimatorStateInfo(0).fullPathHash,
hasExpression ? anim.GetCurrentAnimatorStateInfo(1).fullPathHash : 0,
hasExpression);
} }
// ── 대화 중 캐릭터 회전 ──────────────────────────────────────── // ── 대화 중 캐릭터 회전 ────────────────────────────────────────
@@ -270,6 +274,28 @@ private void RotateTowardPlayer(Transform target)
private void RotateToRotation(Transform target, Quaternion rotation) => AddRotationJob(target, rotation, hold: false); private void RotateToRotation(Transform target, Quaternion rotation) => AddRotationJob(target, rotation, hold: false);
// 플레이어가 지정 위치를 바라보도록 리그를 수평(yaw)으로만 돌린다.
// VR에서는 HMD 카메라를 직접 못 돌리므로 "Player" 태그 루트(XR Origin)를 돌려서
// 카메라 정면이 목표를 향하게 한다. 대화가 끝나도 원상복구하지 않는다 (플레이어 시점이므로).
private void RotatePlayerToward(Vector3 worldPos)
{
var cam = Camera.main;
if (cam == null) return;
var rigObj = GameObject.FindWithTag("Player");
Transform rig = rigObj != null ? rigObj.transform : cam.transform; // 리그 없는 테스트 씬은 카메라 직접
Vector3 toTarget = worldPos - cam.transform.position;
toTarget.y = 0f;
Vector3 camForward = cam.transform.forward;
camForward.y = 0f;
if (toTarget.sqrMagnitude < 0.0001f || camForward.sqrMagnitude < 0.0001f) return;
// 카메라 기준 부족한 만큼만 리그를 돌린다 (리그가 돌면 카메라도 같이 돌므로 델타 방식)
float yawDelta = Vector3.SignedAngle(camForward, toTarget, Vector3.up);
RotateToRotation(rig, Quaternion.AngleAxis(yawDelta, Vector3.up) * rig.rotation);
}
private void AddRotationJob(Transform target, Quaternion goal, bool hold) private void AddRotationJob(Transform target, Quaternion goal, bool hold)
{ {
// 같은 타깃의 기존 잡이 있으면 진행 중이던 회전(Current)을 이어받아 교체 (바라보기 ↔ 복원 충돌 방지) // 같은 타깃의 기존 잡이 있으면 진행 중이던 회전(Current)을 이어받아 교체 (바라보기 ↔ 복원 충돌 방지)
@@ -328,9 +354,16 @@ private void LateUpdate()
private async Awaitable PlayNode(DialogNode node) private async Awaitable PlayNode(DialogNode node)
{ {
// 화자 옆 DialogHud에 대사 표시 (배치 오프셋은 이 NPC의 설정값 사용) // 화자 옆 DialogHud에 대사 표시
// (배치는 화자의 DialogHudPlacement 담당, 없으면 DialogHud 기본값. 이름은 노드 오버라이드 우선)
// 연출 전용 노드(StagingOnly)는 대화창을 잠시 내리고 연출만 수행한다.
if (DialogHud.Instance != null) if (DialogHud.Instance != null)
DialogHud.Instance.Show(node.Speaker, node.TalkText, _hudChestHeight, _hudForwardOffset, _hudLateralOffset, _hudRotationOffset); {
if (node.StagingOnly)
DialogHud.Instance.Hide();
else
DialogHud.Instance.Show(node.Speaker, node.TalkText, node.SpeakerNameOverride);
}
RaiseNodeEvent(node.EventKey); // EventKey 있으면 매칭 이벤트 호출 RaiseNodeEvent(node.EventKey); // EventKey 있으면 매칭 이벤트 호출
@@ -375,10 +408,31 @@ private async Awaitable PlayNode(DialogNode node)
} }
} }
if (node.Gesture != null) // 플레이어가 화자를 바라보도록 강제 회전
_animator.CrossFade(node.Gesture.StateName, node.Gesture.CrossFadeDuration, node.Gesture.AnimationLayer); if (node.ForcePlayerLook && node.Speaker != null)
if (node.Expression != null) {
_animator.CrossFade(node.Expression.StateName, node.Expression.CrossFadeDuration, node.Expression.AnimationLayer); var voiceObj = CharacterVoiceObject.Find(node.Speaker);
if (voiceObj != null)
RotatePlayerToward(voiceObj.transform.position);
}
// 제스처/표정은 화자(Target)의 Animator에 적용 — 끼어든 NPC의 대사/연출 노드도 그 캐릭터가 움직인다.
// 화자를 못 찾으면 대화 주인 NPC의 Animator로 폴백.
if (node.Gesture != null || node.Expression != null)
{
var gestureObj = node.Speaker != null ? CharacterVoiceObject.Find(node.Speaker) : null;
var anim = gestureObj != null ? gestureObj.GetComponentInChildren<Animator>() : _animator;
if (anim == null) anim = _animator;
if (anim != null)
{
CaptureInitialAnimState(anim); // 대화 종료 시 복원할 원래 상태 기억
if (node.Gesture != null)
anim.CrossFade(node.Gesture.StateName, node.Gesture.CrossFadeDuration, node.Gesture.AnimationLayer);
if (node.Expression != null)
anim.CrossFade(node.Expression.StateName, node.Expression.CrossFadeDuration, node.Expression.AnimationLayer);
}
}
// 진행 방식 결정 // 진행 방식 결정
if (node.WaitForInput) if (node.WaitForInput)

View File

@@ -10,7 +10,7 @@ namespace DinoLove.Dialog.GraphTool.Editor
// .dlg 그래프 에셋을 기존 런타임 타입(DialogGroup / DialogNode / DialogChoice)으로 변환한다. // .dlg 그래프 에셋을 기존 런타임 타입(DialogGroup / DialogNode / DialogChoice)으로 변환한다.
// 생성된 DialogNode들은 서브에셋으로, DialogGroup이 메인 에셋으로 등록된다. // 생성된 DialogNode들은 서브에셋으로, DialogGroup이 메인 에셋으로 등록된다.
// 따라서 DialogPlayer는 수정 없이 임포트된 .dlg 에셋(= DialogGroup)을 그대로 사용한다. // 따라서 DialogPlayer는 수정 없이 임포트된 .dlg 에셋(= DialogGroup)을 그대로 사용한다.
[ScriptedImporter(2, DialogGraph.AssetExtension)] // 버전 올리면 기존 .dlg 에셋이 재임포트됨 [ScriptedImporter(6, DialogGraph.AssetExtension)] // 버전 올리면 기존 .dlg 에셋이 재임포트됨
internal class DialogGraphImporter : ScriptedImporter internal class DialogGraphImporter : ScriptedImporter
{ {
public override void OnImportAsset(AssetImportContext ctx) public override void OnImportAsset(AssetImportContext ctx)
@@ -47,7 +47,7 @@ public override void OnImportAsset(AssetImportContext ctx)
while (queue.Count > 0) while (queue.Count > 0)
{ {
var gn = queue.Dequeue(); var gn = queue.Dequeue();
if (gn == null || map.ContainsKey(gn) || gn is not DialogLineNode) if (gn == null || map.ContainsKey(gn) || (gn is not DialogLineNode && gn is not DialogStagingNode))
continue; continue;
var dn = ScriptableObject.CreateInstance<DialogNode>(); var dn = ScriptableObject.CreateInstance<DialogNode>();
@@ -71,10 +71,21 @@ public override void OnImportAsset(AssetImportContext ctx)
// 2패스: 데이터/링크 채우기 // 2패스: 데이터/링크 채우기
foreach (var gn in order) foreach (var gn in order)
{ {
var line = (DialogLineNode)gn;
var dn = map[gn]; var dn = map[gn];
// 연출 전용 노드 — 대사 없이 StagingOnly로 변환, 선형 진행만 지원
if (gn is DialogStagingNode stagingNode)
{
FillStagingNode(stagingNode, dn);
var stagingNext = GetConnectedNode(gn, DialogGraphNode.EXEC_OUT);
dn.Next = stagingNext != null && map.TryGetValue(stagingNext, out var stagingNextDn) ? stagingNextDn : null;
continue;
}
var line = (DialogLineNode)gn;
dn.Speaker = GetInputPortValue<CharacterData>(gn.GetInputPortByName(DialogLineNode.PORT_SPEAKER)); dn.Speaker = GetInputPortValue<CharacterData>(gn.GetInputPortByName(DialogLineNode.PORT_SPEAKER));
dn.SpeakerNameOverride = GetInputPortValue<DialogShortText>(gn.GetInputPortByName(DialogLineNode.PORT_NAME_OVERRIDE)).Value;
dn.TalkText = GetInputPortValue<DialogText>(gn.GetInputPortByName(DialogLineNode.PORT_TALK)).Value; dn.TalkText = GetInputPortValue<DialogText>(gn.GetInputPortByName(DialogLineNode.PORT_TALK)).Value;
dn.Gesture = GetInputPortValue<GestureData>(gn.GetInputPortByName(DialogLineNode.PORT_GESTURE)); dn.Gesture = GetInputPortValue<GestureData>(gn.GetInputPortByName(DialogLineNode.PORT_GESTURE));
dn.Expression = GetInputPortValue<ExpressionData>(gn.GetInputPortByName(DialogLineNode.PORT_EXPRESSION)); dn.Expression = GetInputPortValue<ExpressionData>(gn.GetInputPortByName(DialogLineNode.PORT_EXPRESSION));
@@ -83,6 +94,7 @@ public override void OnImportAsset(AssetImportContext ctx)
dn.Vfx = GetInputPortValue<GameObject>(gn.GetInputPortByName(DialogLineNode.PORT_VFX)); dn.Vfx = GetInputPortValue<GameObject>(gn.GetInputPortByName(DialogLineNode.PORT_VFX));
dn.LineDuration = GetInputPortValue<float>(gn.GetInputPortByName(DialogLineNode.PORT_DURATION)); dn.LineDuration = GetInputPortValue<float>(gn.GetInputPortByName(DialogLineNode.PORT_DURATION));
dn.LookAtPlayer = GetInputPortValue<bool>(gn.GetInputPortByName(DialogLineNode.PORT_LOOKAT)); dn.LookAtPlayer = GetInputPortValue<bool>(gn.GetInputPortByName(DialogLineNode.PORT_LOOKAT));
dn.ForcePlayerLook = GetInputPortValue<bool>(gn.GetInputPortByName(DialogLineNode.PORT_FORCELOOK));
dn.WaitForInput = GetInputPortValue<bool>(gn.GetInputPortByName(DialogLineNode.PORT_WAITINPUT)); dn.WaitForInput = GetInputPortValue<bool>(gn.GetInputPortByName(DialogLineNode.PORT_WAITINPUT));
string eventKey = null; string eventKey = null;
@@ -118,9 +130,34 @@ public override void OnImportAsset(AssetImportContext ctx)
group.StartNode = map.TryGetValue(firstGraphNode, out var startDn) ? startDn : null; group.StartNode = map.TryGetValue(firstGraphNode, out var startDn) ? startDn : null;
} }
// 연출 전용 노드의 데이터 채우기 (대사·선택지 없음)
static void FillStagingNode(DialogStagingNode gn, DialogNode dn)
{
dn.StagingOnly = true;
dn.Speaker = GetInputPortValue<CharacterData>(gn.GetInputPortByName(DialogStagingNode.PORT_SPEAKER));
dn.Gesture = GetInputPortValue<GestureData>(gn.GetInputPortByName(DialogStagingNode.PORT_GESTURE));
dn.Expression = GetInputPortValue<ExpressionData>(gn.GetInputPortByName(DialogStagingNode.PORT_EXPRESSION));
dn.Bgm = GetInputPortValue<AudioClip>(gn.GetInputPortByName(DialogStagingNode.PORT_BGM));
dn.Vfx = GetInputPortValue<GameObject>(gn.GetInputPortByName(DialogStagingNode.PORT_VFX));
dn.LineDuration = GetInputPortValue<float>(gn.GetInputPortByName(DialogStagingNode.PORT_DURATION));
dn.LookAtPlayer = GetInputPortValue<bool>(gn.GetInputPortByName(DialogStagingNode.PORT_LOOKAT));
dn.ForcePlayerLook = GetInputPortValue<bool>(gn.GetInputPortByName(DialogStagingNode.PORT_FORCELOOK));
string eventKey = null;
gn.GetNodeOptionByName(DialogStagingNode.OPTION_EVENT_KEY)?.TryGetValue(out eventKey);
dn.EventKey = eventKey;
}
// 노드의 실행 흐름상 후속 노드들 (선형이면 1개, N지선다면 N개) // 노드의 실행 흐름상 후속 노드들 (선형이면 1개, N지선다면 N개)
static IEnumerable<INode> GetSuccessors(INode node) static IEnumerable<INode> GetSuccessors(INode node)
{ {
// 연출 전용 노드는 항상 선형
if (node is DialogStagingNode)
{
yield return GetConnectedNode(node, DialogGraphNode.EXEC_OUT);
yield break;
}
if (node is not DialogLineNode line) if (node is not DialogLineNode line)
yield break; yield break;

View File

@@ -15,6 +15,7 @@ namespace DinoLove.Dialog.GraphTool.Editor
internal class DialogLineNode : DialogGraphNode internal class DialogLineNode : DialogGraphNode
{ {
public const string PORT_SPEAKER = "Speaker"; public const string PORT_SPEAKER = "Speaker";
public const string PORT_NAME_OVERRIDE = "SpeakerNameOverride";
public const string PORT_TALK = "TalkText"; public const string PORT_TALK = "TalkText";
public const string PORT_GESTURE = "Gesture"; public const string PORT_GESTURE = "Gesture";
public const string PORT_EXPRESSION = "Expression"; public const string PORT_EXPRESSION = "Expression";
@@ -23,6 +24,7 @@ internal class DialogLineNode : DialogGraphNode
public const string PORT_VFX = "Vfx"; public const string PORT_VFX = "Vfx";
public const string PORT_DURATION = "LineDuration"; public const string PORT_DURATION = "LineDuration";
public const string PORT_LOOKAT = "LookAtPlayer"; public const string PORT_LOOKAT = "LookAtPlayer";
public const string PORT_FORCELOOK = "ForcePlayerLook";
public const string PORT_WAITINPUT = "WaitForInput"; public const string PORT_WAITINPUT = "WaitForInput";
public const string PORT_QUESTION = "ChoiceQuestion"; public const string PORT_QUESTION = "ChoiceQuestion";
@@ -54,6 +56,8 @@ protected override void OnDefinePorts(IPortDefinitionContext context)
// DialogNode의 라인 데이터 (모두 선택 입력, 비워두면 default) // DialogNode의 라인 데이터 (모두 선택 입력, 비워두면 default)
context.AddInputPort<CharacterData>(PORT_SPEAKER).WithDisplayName("Speaker").Build(); context.AddInputPort<CharacterData>(PORT_SPEAKER).WithDisplayName("Speaker").Build();
context.AddInputPort<DialogShortText>(PORT_NAME_OVERRIDE).WithDisplayName("Name Override")
.WithTooltip("비우면 Speaker 이름 그대로, 채우면 이 이름으로 표시 (예: ???)").Build();
context.AddInputPort<DialogText>(PORT_TALK).WithDisplayName("Talk Text").Build(); context.AddInputPort<DialogText>(PORT_TALK).WithDisplayName("Talk Text").Build();
context.AddInputPort<GestureData>(PORT_GESTURE).WithDisplayName("Gesture").Build(); context.AddInputPort<GestureData>(PORT_GESTURE).WithDisplayName("Gesture").Build();
context.AddInputPort<ExpressionData>(PORT_EXPRESSION).WithDisplayName("Expression").Build(); context.AddInputPort<ExpressionData>(PORT_EXPRESSION).WithDisplayName("Expression").Build();
@@ -64,6 +68,8 @@ protected override void OnDefinePorts(IPortDefinitionContext context)
.WithTooltip("이 대사 시작 시 화자 위치에서 1회 재생할 이펙트 프리팹").Build(); .WithTooltip("이 대사 시작 시 화자 위치에서 1회 재생할 이펙트 프리팹").Build();
context.AddInputPort<float>(PORT_DURATION).WithDisplayName("Line Duration").Build(); context.AddInputPort<float>(PORT_DURATION).WithDisplayName("Line Duration").Build();
context.AddInputPort<bool>(PORT_LOOKAT).WithDisplayName("Look At Player").Build(); context.AddInputPort<bool>(PORT_LOOKAT).WithDisplayName("Look At Player").Build();
context.AddInputPort<bool>(PORT_FORCELOOK).WithDisplayName("Force Player Look")
.WithTooltip("이 대사 시작 시 플레이어(카메라)가 화자를 바라보도록 강제 회전").Build();
context.AddInputPort<bool>(PORT_WAITINPUT).WithDisplayName("Wait For Input").Build(); context.AddInputPort<bool>(PORT_WAITINPUT).WithDisplayName("Wait For Input").Build();
int choiceCount = 0; int choiceCount = 0;

View File

@@ -0,0 +1,18 @@
using System;
namespace DinoLove.Dialog.GraphTool.Editor
{
// 그래프 노드의 한 줄짜리 텍스트 포트용 래퍼 타입 (이름 오버라이드 등 짧은 텍스트).
// DialogText와 마찬가지로 string 포트의 IME 중복입력 버그를 피하기 위한 타입이며,
// 전용 DialogShortTextDrawer가 한 줄 TextField로 렌더한다.
// 임포트 시 Value 문자열만 전달된다(런타임은 이 타입을 모름).
//
// public인 이유: GraphToolkit이 포트 임베드 값을 편집할 때 이 타입을 감싸는
// 래퍼 ScriptableObject를 Reflection.Emit으로 다른 어셈블리에 생성하므로
// 접근 가능해야 한다.
[Serializable]
public struct DialogShortText
{
public string Value;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9432f3355b50d3d458cff5e56b6c9206

View File

@@ -0,0 +1,22 @@
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace DinoLove.Dialog.GraphTool.Editor
{
// DialogShortText를 한 줄 입력 필드로 그린다. (DialogTextDrawer의 싱글라인 버전)
[CustomPropertyDrawer(typeof(DialogShortText))]
internal class DialogShortTextDrawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
var valueProp = property.FindPropertyRelative(nameof(DialogShortText.Value));
var field = new TextField();
if (valueProp != null)
field.BindProperty(valueProp);
return field;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 15b46c322dec78d438a144f875d67d42

View File

@@ -0,0 +1,55 @@
using System;
using Unity.GraphToolkit.Editor;
using UnityEngine;
namespace DinoLove.Dialog.GraphTool.Editor
{
// 연출 전용 노드. 대사/대화창 없이 몇 초간 연출만 수행한다.
// (플레이어 강제 회전, 대상 캐릭터 회전/제스처, VFX, BGM, 이벤트 호출 등)
// DialogNode(StagingOnly=true) 하나로 변환되며, 선형 진행만 지원한다.
// 예: "잠깐" 대사 → [연출 노드: Force Player Look + Duration 2초] → 다음 대사
[Serializable]
internal class DialogStagingNode : DialogGraphNode
{
public const string PORT_SPEAKER = "Speaker"; // 연출 대상 (바라볼 상대 / 제스처·VFX의 주인)
public const string PORT_GESTURE = "Gesture";
public const string PORT_EXPRESSION = "Expression";
public const string PORT_BGM = "Bgm";
public const string PORT_VFX = "Vfx";
public const string PORT_DURATION = "Duration";
public const string PORT_LOOKAT = "LookAtPlayer";
public const string PORT_FORCELOOK = "ForcePlayerLook";
public const string OPTION_EVENT_KEY = "EventKey";
protected override void OnDefineOptions(IOptionDefinitionContext context)
{
context.AddOption<string>(OPTION_EVENT_KEY)
.WithDisplayName("Event Key")
.WithTooltip("비우면 없음. 이 노드 재생 시 DialogPlayer의 같은 Key 이벤트 호출 (영문 키 권장)")
.Delayed();
}
protected override void OnDefinePorts(IPortDefinitionContext context)
{
AddExecInput(context);
context.AddInputPort<CharacterData>(PORT_SPEAKER).WithDisplayName("Target")
.WithTooltip("연출 대상 캐릭터 — 플레이어가 바라볼 상대이자 제스처·VFX의 주인").Build();
context.AddInputPort<GestureData>(PORT_GESTURE).WithDisplayName("Gesture").Build();
context.AddInputPort<ExpressionData>(PORT_EXPRESSION).WithDisplayName("Expression").Build();
context.AddInputPort<AudioClip>(PORT_BGM).WithDisplayName("BGM")
.WithTooltip("있으면 이 연출부터 전용 BGM 재생, 비우면 기본 BGM으로 복귀").Build();
context.AddInputPort<GameObject>(PORT_VFX).WithDisplayName("VFX Prefab")
.WithTooltip("연출 시작 시 대상 위치에서 1회 재생할 이펙트 프리팹").Build();
context.AddInputPort<float>(PORT_DURATION).WithDisplayName("Duration")
.WithTooltip("연출 시간(초). 0이면 B버튼 입력까지 대기").Build();
context.AddInputPort<bool>(PORT_LOOKAT).WithDisplayName("Look At Player")
.WithTooltip("대상 캐릭터가 플레이어를 바라봄").Build();
context.AddInputPort<bool>(PORT_FORCELOOK).WithDisplayName("Force Player Look")
.WithTooltip("플레이어가 대상 캐릭터를 바라봄").Build();
AddExecOutput(context, EXEC_OUT, string.Empty);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fafb2723eb8f0c54a8ca67baac92d8aa

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
@@ -25,6 +26,28 @@ public class DialogHud : MonoBehaviour
[SerializeField] private float _lateralOffset = 0f; // 좌우 오프셋 (+ 화자와 마주보는 시점 오른쪽) [SerializeField] private float _lateralOffset = 0f; // 좌우 오프셋 (+ 화자와 마주보는 시점 오른쪽)
[SerializeField] private Vector3 _rotationOffset = Vector3.zero; // 화자 회전 기준 추가 회전 (+α, 오일러 각) [SerializeField] private Vector3 _rotationOffset = Vector3.zero; // 화자 회전 기준 추가 회전 (+α, 오일러 각)
// ── 후보 위치 자동 선택 ─────────────────────────────────────
// 대사창을 띄울 때 후보를 우선순위 순서대로 검사해서, 벽/지형에 겹치지 않고
// 플레이어에게 가려지지 않는 첫 후보 위치에 창을 띄운다.
// 후보 목록 자체는 NPC마다 크기가 달라 화자의 DialogHudPlacement에서 넘어온다.
// 후보 하나가 완전한 배치값을 갖는다 (기본값 + 보정 방식 아님 — 그대로 적용됨)
[System.Serializable]
public struct PlacementCandidate
{
public string Name; // 인스펙터 식별용
public float Height; // 화자 발 기준 높이
public float Forward; // 화자가 바라보는 방향으로 띄울 거리
public float Lateral; // 좌우 오프셋 (+ 화자와 마주보는 시점 오른쪽)
public Vector3 RotationOffset; // 추가 회전 (오일러 각)
}
[Header("Auto Placement (후보 위치 자동 선택)")]
[Tooltip("대사창이 피해야 할 레이어 (벽/지형 = Default). NPC·플레이어 레이어는 넣지 말 것")]
[SerializeField] private LayerMask _obstacleMask = 1; // Default 레이어
[Tooltip("충돌 검사에 쓰는 대사창 절반 크기 — 실제 캔버스 크기에 맞출 것")]
[SerializeField] private Vector3 _panelHalfExtents = new(0.5f, 0.3f, 0.05f);
private Transform _speakerTransform; private Transform _speakerTransform;
private float _activeChestHeight; private float _activeChestHeight;
private float _activeForwardOffset; private float _activeForwardOffset;
@@ -43,21 +66,37 @@ private void OnDestroy()
if (Instance == this) Instance = null; if (Instance == this) Instance = null;
} }
// DialogHud 자체 기본 오프셋 사용 // 화자 옆에 대사 표시.
public void Show(CharacterData speaker, string text) // - 배치는 화자 오브젝트의 DialogHudPlacement 값 사용, 없으면 이 컴포넌트의 기본값 폴백
=> Show(speaker, text, _chestHeight, _forwardOffset, _lateralOffset, _rotationOffset); // - speakerNameOverride가 비어있지 않으면 CharacterData.Name 대신 그 이름을 표시한다 (예: "???")
// - 화자의 DialogHudPlacement에 후보 목록이 있으면 벽/가림 검사를 통과하는 첫 후보 위치로 자동 배치
// 배치 오프셋을 직접 넘겨 사용 (DialogPlayer가 NPC/씬별 값 전달) public void Show(CharacterData speaker, string text, string speakerNameOverride = null)
public void Show(CharacterData speaker, string text, float chestHeight, float forwardOffset, float lateralOffset, Vector3 rotationOffset)
{ {
_speakerTransform = speaker != null ? CharacterVoiceObject.Find(speaker)?.transform : null; var voiceObj = speaker != null ? CharacterVoiceObject.Find(speaker) : null;
_activeChestHeight = chestHeight; _speakerTransform = voiceObj != null ? voiceObj.transform : null;
_activeForwardOffset = forwardOffset;
_activeLateralOffset = lateralOffset; DialogHudPlacement placement = null;
_activeRotationOffset = rotationOffset; if (voiceObj != null) voiceObj.TryGetComponent(out placement);
if (placement != null && placement.Candidates != null && placement.Candidates.Count > 0)
{
ApplyCandidate(placement.Candidates[0]); // 일단 첫 후보(기본)로 배치하고
ApplyBestCandidate(placement.Candidates); // 검사를 통과하는 후보가 있으면 교체
}
else
{
_activeChestHeight = _chestHeight;
_activeForwardOffset = _forwardOffset;
_activeLateralOffset = _lateralOffset;
_activeRotationOffset = _rotationOffset;
}
if (_speakerName != null) if (_speakerName != null)
_speakerName.text = speaker != null ? DialogVariables.Format(speaker.Name) : string.Empty; {
string speakerName = !string.IsNullOrEmpty(speakerNameOverride) ? speakerNameOverride
: speaker != null ? speaker.Name : string.Empty;
_speakerName.text = DialogVariables.Format(speakerName); // {key} 토큰 치환
}
if (_dialogueText != null) if (_dialogueText != null)
_dialogueText.text = DialogVariables.Format(text); // {key} 토큰 치환 _dialogueText.text = DialogVariables.Format(text); // {key} 토큰 치환
@@ -72,6 +111,51 @@ public void Hide()
_speakerTransform = null; _speakerTransform = null;
} }
// 선택된 후보의 배치값을 그대로 적용한다
private void ApplyCandidate(PlacementCandidate cand)
{
_activeChestHeight = cand.Height;
_activeForwardOffset = cand.Forward;
_activeLateralOffset = cand.Lateral;
_activeRotationOffset = cand.RotationOffset;
}
// 후보 위치들을 우선순위대로 검사해 통과하는 첫 후보를 적용한다. 전부 실패하면 첫 후보 유지.
// 검사 기준은 호출 시점의 화자→플레이어(카메라) 방향 — 대화가 시작되면 NPC가
// 플레이어 쪽으로 돌아서므로, 돌아선 뒤의 실제 배치와 일치한다.
private void ApplyBestCandidate(List<PlacementCandidate> candidates)
{
if (candidates == null || candidates.Count == 0) return;
if (_speakerTransform == null || Camera.main == null) return;
Vector3 camPos = Camera.main.transform.position;
Vector3 dir = camPos - _speakerTransform.position;
dir.y = 0f;
if (dir.sqrMagnitude < 0.0001f) return;
dir.Normalize();
Vector3 right = Vector3.Cross(dir, Vector3.up);
foreach (var cand in candidates)
{
Vector3 pos = _speakerTransform.position
+ Vector3.up * cand.Height
+ dir * cand.Forward
+ right * cand.Lateral;
Quaternion rot = Quaternion.LookRotation(-dir) * Quaternion.Euler(cand.RotationOffset);
// 벽/지형에 겹치는가
if (Physics.CheckBox(pos, _panelHalfExtents, rot, _obstacleMask, QueryTriggerInteraction.Ignore))
continue;
// 플레이어 눈에서 벽에 가려지는가
if (Physics.Linecast(camPos, pos, _obstacleMask, QueryTriggerInteraction.Ignore))
continue;
ApplyCandidate(cand);
return;
}
// 전부 실패 — 미리 적용해 둔 첫 후보(기본) 그대로 사용
}
private void LateUpdate() private void LateUpdate()
{ {
if (_speakerTransform == null) return; if (_speakerTransform == null) return;

Binary file not shown.

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c6477f09ddbfaaa43b73a8eb323ba389
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -230,6 +230,8 @@ MonoBehaviour:
- LineDuration - LineDuration
- LookAtPlayer - LookAtPlayer
- WaitForInput - WaitForInput
- SpeakerNameOverride
- ForcePlayerLook
m_ValueList: m_ValueList:
- rid: 4848514365209968924 - rid: 4848514365209968924
- rid: 4848514365209968925 - rid: 4848514365209968925
@@ -243,6 +245,8 @@ MonoBehaviour:
- rid: 4848514365209968933 - rid: 4848514365209968933
- rid: 4848514365209968934 - rid: 4848514365209968934
- rid: 4848514365209968935 - rid: 4848514365209968935
- rid: 4848514453388656932
- rid: 4848514453388656849
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -303,7 +307,7 @@ MonoBehaviour:
- rid: 4848514365209968934 - rid: 4848514365209968934
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data: data:
m_Value: 1 m_Value: 0
- rid: 4848514365209968935 - rid: 4848514365209968935
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data: data:
@@ -373,6 +377,8 @@ MonoBehaviour:
- LineDuration - LineDuration
- LookAtPlayer - LookAtPlayer
- WaitForInput - WaitForInput
- SpeakerNameOverride
- ForcePlayerLook
m_ValueList: m_ValueList:
- rid: 4848514365209968940 - rid: 4848514365209968940
- rid: 4848514365209968941 - rid: 4848514365209968941
@@ -386,6 +392,8 @@ MonoBehaviour:
- rid: 4848514365209968949 - rid: 4848514365209968949
- rid: 4848514365209968950 - rid: 4848514365209968950
- rid: 4848514365209968951 - rid: 4848514365209968951
- rid: 4848514453388656933
- rid: 4848514453388656851
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -515,6 +523,8 @@ MonoBehaviour:
- LineDuration - LineDuration
- LookAtPlayer - LookAtPlayer
- WaitForInput - WaitForInput
- SpeakerNameOverride
- ForcePlayerLook
m_ValueList: m_ValueList:
- rid: 4848514430811766893 - rid: 4848514430811766893
- rid: 4848514430811766894 - rid: 4848514430811766894
@@ -528,6 +538,8 @@ MonoBehaviour:
- rid: 4848514430811766902 - rid: 4848514430811766902
- rid: 4848514430811766903 - rid: 4848514430811766903
- rid: 4848514430811766904 - rid: 4848514430811766904
- rid: 4848514453388656934
- rid: 4848514453388656853
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -658,6 +670,8 @@ MonoBehaviour:
- LineDuration - LineDuration
- LookAtPlayer - LookAtPlayer
- WaitForInput - WaitForInput
- SpeakerNameOverride
- ForcePlayerLook
m_ValueList: m_ValueList:
- rid: 4848514430811766908 - rid: 4848514430811766908
- rid: 4848514430811766909 - rid: 4848514430811766909
@@ -671,6 +685,8 @@ MonoBehaviour:
- rid: 4848514430811766917 - rid: 4848514430811766917
- rid: 4848514430811766918 - rid: 4848514430811766918
- rid: 4848514430811766919 - rid: 4848514430811766919
- rid: 4848514453388656935
- rid: 4848514453388656855
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -803,6 +819,8 @@ MonoBehaviour:
- LineDuration - LineDuration
- LookAtPlayer - LookAtPlayer
- WaitForInput - WaitForInput
- SpeakerNameOverride
- ForcePlayerLook
m_ValueList: m_ValueList:
- rid: 4848514430811766923 - rid: 4848514430811766923
- rid: 4848514430811766924 - rid: 4848514430811766924
@@ -816,6 +834,8 @@ MonoBehaviour:
- rid: 4848514430811766932 - rid: 4848514430811766932
- rid: 4848514430811766933 - rid: 4848514430811766933
- rid: 4848514430811766934 - rid: 4848514430811766934
- rid: 4848514453388656936
- rid: 4848514453388656857
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -915,3 +935,48 @@ MonoBehaviour:
- rid: 4848514430811766935 - rid: 4848514430811766935
type: {class: DialogLineNode, ns: DinoLove.Dialog.GraphTool.Editor, asm: Assembly-CSharp-Editor} type: {class: DialogLineNode, ns: DinoLove.Dialog.GraphTool.Editor, asm: Assembly-CSharp-Editor}
data: data:
- rid: 4848514453388656849
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656851
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656853
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656855
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656857
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656932
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value:
- rid: 4848514453388656933
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value:
- rid: 4848514453388656934
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value:
- rid: 4848514453388656935
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value:
- rid: 4848514453388656936
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value:

View File

@@ -194,6 +194,8 @@ MonoBehaviour:
- LineDuration - LineDuration
- LookAtPlayer - LookAtPlayer
- WaitForInput - WaitForInput
- SpeakerNameOverride
- ForcePlayerLook
m_ValueList: m_ValueList:
- rid: 4848514365209968924 - rid: 4848514365209968924
- rid: 4848514365209968925 - rid: 4848514365209968925
@@ -207,6 +209,8 @@ MonoBehaviour:
- rid: 4848514365209968933 - rid: 4848514365209968933
- rid: 4848514365209968934 - rid: 4848514365209968934
- rid: 4848514365209968935 - rid: 4848514365209968935
- rid: 4848514453388656928
- rid: 4848514453388656841
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -267,7 +271,7 @@ MonoBehaviour:
- rid: 4848514365209968934 - rid: 4848514365209968934
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data: data:
m_Value: 1 m_Value: 0
- rid: 4848514365209968935 - rid: 4848514365209968935
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data: data:
@@ -337,6 +341,8 @@ MonoBehaviour:
- LineDuration - LineDuration
- LookAtPlayer - LookAtPlayer
- WaitForInput - WaitForInput
- SpeakerNameOverride
- ForcePlayerLook
m_ValueList: m_ValueList:
- rid: 4848514365209968940 - rid: 4848514365209968940
- rid: 4848514365209968941 - rid: 4848514365209968941
@@ -350,6 +356,8 @@ MonoBehaviour:
- rid: 4848514365209968949 - rid: 4848514365209968949
- rid: 4848514365209968950 - rid: 4848514365209968950
- rid: 4848514365209968951 - rid: 4848514365209968951
- rid: 4848514453388656929
- rid: 4848514453388656843
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -480,6 +488,8 @@ MonoBehaviour:
- LineDuration - LineDuration
- LookAtPlayer - LookAtPlayer
- WaitForInput - WaitForInput
- SpeakerNameOverride
- ForcePlayerLook
m_ValueList: m_ValueList:
- rid: 4848514430811767025 - rid: 4848514430811767025
- rid: 4848514430811767026 - rid: 4848514430811767026
@@ -493,6 +503,8 @@ MonoBehaviour:
- rid: 4848514430811767034 - rid: 4848514430811767034
- rid: 4848514430811767035 - rid: 4848514430811767035
- rid: 4848514430811767036 - rid: 4848514430811767036
- rid: 4848514453388656930
- rid: 4848514453388656845
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -592,3 +604,30 @@ MonoBehaviour:
- rid: 4848514430811767037 - rid: 4848514430811767037
type: {class: DialogLineNode, ns: DinoLove.Dialog.GraphTool.Editor, asm: Assembly-CSharp-Editor} type: {class: DialogLineNode, ns: DinoLove.Dialog.GraphTool.Editor, asm: Assembly-CSharp-Editor}
data: data:
- rid: 4848514453388656841
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656843
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656845
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656928
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value:
- rid: 4848514453388656929
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value:
- rid: 4848514453388656930
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value:

View File

@@ -45,8 +45,8 @@ MonoBehaviour:
serializedVersion: 2 serializedVersion: 2
x: -86 x: -86
y: 92 y: 92
width: 659 width: 678
height: 432 height: 480
m_GraphElementMetaData: m_GraphElementMetaData:
- m_Guid: - m_Guid:
m_Value0: 11886921906498108818 m_Value0: 11886921906498108818
@@ -158,6 +158,8 @@ MonoBehaviour:
- LineDuration - LineDuration
- LookAtPlayer - LookAtPlayer
- WaitForInput - WaitForInput
- SpeakerNameOverride
- ForcePlayerLook
m_ValueList: m_ValueList:
- rid: 4848514365209968924 - rid: 4848514365209968924
- rid: 4848514365209968925 - rid: 4848514365209968925
@@ -171,6 +173,8 @@ MonoBehaviour:
- rid: 4848514365209968933 - rid: 4848514365209968933
- rid: 4848514365209968934 - rid: 4848514365209968934
- rid: 4848514365209968935 - rid: 4848514365209968935
- rid: 4848514453388656939
- rid: 4848514453388656863
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -230,7 +234,7 @@ MonoBehaviour:
- rid: 4848514365209968934 - rid: 4848514365209968934
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data: data:
m_Value: 1 m_Value: 0
- rid: 4848514365209968935 - rid: 4848514365209968935
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data: data:
@@ -270,3 +274,12 @@ MonoBehaviour:
m_PortDirection: 1 m_PortDirection: 1
m_PortOrientation: 0 m_PortOrientation: 0
m_Title: m_Title:
- rid: 4848514453388656863
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656939
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: de03eebbf679a194f82454b82efc6802
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 11500000, guid: 2ae5ca89bbed445479d9023586f0c041, type: 3}

View File

@@ -0,0 +1,285 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &1
MonoBehaviour:
m_ObjectHideFlags: 61
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 12501, guid: 0000000000000000e000000000000000, type: 0}
m_Name: Chapter1_Styracosaurus1
m_EditorClassIdentifier: UnityEditor.dll::Unity.GraphToolkit.Editor.Implementation.GraphObjectImp
m_GraphModel:
rid: 4848514453388656899
references:
version: 2
RefIds:
- rid: -2
type: {class: , ns: , asm: }
- rid: 4848514453388656899
type: {class: GraphModelImp, ns: Unity.GraphToolkit.Editor.Implementation, asm: UnityEditor.GraphToolkitModule}
data:
m_Guid:
m_Value0: 10378577389719029742
m_Value1: 14990812597565823167
m_HashGuid:
serializedVersion: 2
Hash: ee871adc251d0890bf985cfca1100ad0
m_Name:
m_GraphNodeModels:
- rid: 4848514453388656902
- rid: 4848514453388656904
m_GraphWireModels:
- rid: 4848514453388656905
m_GraphStickyNoteModels: []
m_GraphPlacematModels: []
m_GraphVariableModels: []
m_GraphPortalModels: []
m_SectionModels:
- rid: 4848514453388656900
m_LocalSubgraphs: []
m_LastKnownBounds:
serializedVersion: 2
x: 173
y: 87
width: 655
height: 480
m_GraphElementMetaData:
- m_Guid:
m_Value0: 3953896658662454792
m_Value1: 17132231479142926168
m_HashGuid:
serializedVersion: 2
Hash: 08f62dfa0f10df3658471484c2e9c1ed
m_Category: 0
m_Index: 0
- m_Guid:
m_Value0: 1570429254835387755
m_Value1: 6686057499624100012
m_HashGuid:
serializedVersion: 2
Hash: 6b3d58371649cb15ac50ee24dfa5c95c
m_Category: 0
m_Index: 1
- m_Guid:
m_Value0: 6438258882588987619
m_Value1: 16280232558899195376
m_HashGuid:
serializedVersion: 2
Hash: e350b8a4574a5959f06def854101efe1
m_Category: 2
m_Index: 0
m_EntryPoint:
rid: 4848514453388656902
m_Graph:
rid: 4848514453388656901
- rid: 4848514453388656900
type: {class: SectionModel, ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Guid:
m_Value0: 5167448814378227062
m_Value1: 6149631618382083437
m_HashGuid:
serializedVersion: 2
Hash: 761507805177b6476db52cf15fe15755
m_Version: 2
m_Items: []
m_Title:
- rid: 4848514453388656901
type: {class: DialogGraph, ns: DinoLove.Dialog.GraphTool.Editor, asm: Assembly-CSharp-Editor}
data:
- rid: 4848514453388656902
type: {class: UserNodeModelImp, ns: Unity.GraphToolkit.Editor.Implementation, asm: UnityEditor.GraphToolkitModule}
data:
m_Guid:
m_Value0: 3953896658662454792
m_Value1: 17132231479142926168
m_HashGuid:
serializedVersion: 2
Hash: 08f62dfa0f10df3658471484c2e9c1ed
m_Version: 2
m_Position: {x: 172.69565, y: 140}
m_Title:
m_Tooltip:
m_NodePreviewModel:
rid: -2
m_State: 0
m_InputConstantsById:
m_KeyList: []
m_ValueList: []
m_InputPortInfos:
expandedPortsById:
m_KeyList: []
m_ValueList:
m_OutputPortInfos:
expandedPortsById:
m_KeyList: []
m_ValueList:
m_Collapsed: 0
m_CurrentModeIndex: 0
m_ElementColor:
m_Color: {r: 0, g: 0, b: 0, a: 0}
m_HasUserColor: 0
m_Node:
rid: 4848514453388656903
- rid: 4848514453388656903
type: {class: DialogStartNode, ns: DinoLove.Dialog.GraphTool.Editor, asm: Assembly-CSharp-Editor}
data:
- rid: 4848514453388656904
type: {class: UserNodeModelImp, ns: Unity.GraphToolkit.Editor.Implementation, asm: UnityEditor.GraphToolkitModule}
data:
m_Guid:
m_Value0: 1570429254835387755
m_Value1: 6686057499624100012
m_HashGuid:
serializedVersion: 2
Hash: 6b3d58371649cb15ac50ee24dfa5c95c
m_Version: 2
m_Position: {x: 406, y: 87.17392}
m_Title:
m_Tooltip:
m_NodePreviewModel:
rid: -2
m_State: 0
m_InputConstantsById:
m_KeyList:
- __option_ChoiceCount
- __option_EventKey
- Speaker
- SpeakerNameOverride
- TalkText
- Gesture
- Expression
- Voice
- Bgm
- Vfx
- LineDuration
- LookAtPlayer
- ForcePlayerLook
- WaitForInput
m_ValueList:
- rid: 4848514453388656906
- rid: 4848514453388656907
- rid: 4848514453388656908
- rid: 4848514453388656909
- rid: 4848514453388656910
- rid: 4848514453388656911
- rid: 4848514453388656912
- rid: 4848514453388656913
- rid: 4848514453388656914
- rid: 4848514453388656915
- rid: 4848514453388656916
- rid: 4848514453388656917
- rid: 4848514453388656918
- rid: 4848514453388656919
m_InputPortInfos:
expandedPortsById:
m_KeyList: []
m_ValueList:
m_OutputPortInfos:
expandedPortsById:
m_KeyList: []
m_ValueList:
m_Collapsed: 0
m_CurrentModeIndex: 0
m_ElementColor:
m_Color: {r: 0, g: 0, b: 0, a: 0}
m_HasUserColor: 0
m_Node:
rid: 4848514453388656920
- rid: 4848514453388656905
type: {class: WireModel, ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Guid:
m_Value0: 6438258882588987619
m_Value1: 16280232558899195376
m_HashGuid:
serializedVersion: 2
Hash: e350b8a4574a5959f06def854101efe1
m_Version: 2
m_FromPortReference:
m_NodeModelGuid:
m_Value0: 3953896658662454792
m_Value1: 17132231479142926168
m_NodeModelHashGuid:
serializedVersion: 2
Hash: 08f62dfa0f10df3658471484c2e9c1ed
m_UniqueId: Out
m_PortDirection: 2
m_PortOrientation: 0
m_Title:
m_ToPortReference:
m_NodeModelGuid:
m_Value0: 1570429254835387755
m_Value1: 6686057499624100012
m_NodeModelHashGuid:
serializedVersion: 2
Hash: 6b3d58371649cb15ac50ee24dfa5c95c
m_UniqueId: In
m_PortDirection: 1
m_PortOrientation: 0
m_Title:
- rid: 4848514453388656906
type: {class: 'Constant`1[[System.Int32, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656907
type: {class: 'Constant`1[[System.String, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
- rid: 4848514453388656908
type: {class: 'Constant`1[[CharacterData, Assembly-CSharp]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: {fileID: 11400000, guid: c6477f09ddbfaaa43b73a8eb323ba389, type: 2}
- rid: 4848514453388656909
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value:
- rid: 4848514453388656910
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value: "\uB108 \uC774\uB984\uC774 \uBB50\uC57C?"
- rid: 4848514453388656911
type: {class: 'Constant`1[[GestureData, Assembly-CSharp]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: {fileID: 0}
- rid: 4848514453388656912
type: {class: 'Constant`1[[ExpressionData, Assembly-CSharp]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: {fileID: 0}
- rid: 4848514453388656913
type: {class: 'Constant`1[[VoiceClip, Assembly-CSharp]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: {fileID: 0}
- rid: 4848514453388656914
type: {class: 'Constant`1[[UnityEngine.AudioClip, UnityEngine.AudioModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: {fileID: 0}
- rid: 4848514453388656915
type: {class: 'Constant`1[[UnityEngine.GameObject, UnityEngine.CoreModule]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: {fileID: 0}
- rid: 4848514453388656916
type: {class: 'Constant`1[[System.Single, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 3
- rid: 4848514453388656917
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656918
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656919
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656920
type: {class: DialogLineNode, ns: DinoLove.Dialog.GraphTool.Editor, asm: Assembly-CSharp-Editor}
data:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f42113d9153a3cf45b4d92be59747e1b
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 11500000, guid: 2ae5ca89bbed445479d9023586f0c041, type: 3}

View File

@@ -47,8 +47,8 @@ MonoBehaviour:
serializedVersion: 2 serializedVersion: 2
x: -86 x: -86
y: 92 y: 92
width: 1053 width: 1072
height: 432 height: 480
m_GraphElementMetaData: m_GraphElementMetaData:
- m_Guid: - m_Guid:
m_Value0: 11886921906498108818 m_Value0: 11886921906498108818
@@ -176,6 +176,8 @@ MonoBehaviour:
- LineDuration - LineDuration
- LookAtPlayer - LookAtPlayer
- WaitForInput - WaitForInput
- SpeakerNameOverride
- ForcePlayerLook
m_ValueList: m_ValueList:
- rid: 4848514365209968924 - rid: 4848514365209968924
- rid: 4848514365209968925 - rid: 4848514365209968925
@@ -189,6 +191,8 @@ MonoBehaviour:
- rid: 4848514365209968933 - rid: 4848514365209968933
- rid: 4848514365209968934 - rid: 4848514365209968934
- rid: 4848514365209968935 - rid: 4848514365209968935
- rid: 4848514453388656921
- rid: 4848514453388656816
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -248,7 +252,7 @@ MonoBehaviour:
- rid: 4848514365209968934 - rid: 4848514365209968934
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data: data:
m_Value: 1 m_Value: 0
- rid: 4848514365209968935 - rid: 4848514365209968935
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data: data:
@@ -318,6 +322,8 @@ MonoBehaviour:
- LineDuration - LineDuration
- LookAtPlayer - LookAtPlayer
- WaitForInput - WaitForInput
- SpeakerNameOverride
- ForcePlayerLook
m_ValueList: m_ValueList:
- rid: 4848514365209968940 - rid: 4848514365209968940
- rid: 4848514365209968941 - rid: 4848514365209968941
@@ -331,6 +337,8 @@ MonoBehaviour:
- rid: 4848514365209968949 - rid: 4848514365209968949
- rid: 4848514365209968950 - rid: 4848514365209968950
- rid: 4848514365209968951 - rid: 4848514365209968951
- rid: 4848514453388656922
- rid: 4848514453388656818
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -430,3 +438,21 @@ MonoBehaviour:
- rid: 4848514365209968952 - rid: 4848514365209968952
type: {class: DialogLineNode, ns: DinoLove.Dialog.GraphTool.Editor, asm: Assembly-CSharp-Editor} type: {class: DialogLineNode, ns: DinoLove.Dialog.GraphTool.Editor, asm: Assembly-CSharp-Editor}
data: data:
- rid: 4848514453388656816
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656818
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656921
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value:
- rid: 4848514453388656922
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value:

View File

@@ -45,8 +45,8 @@ MonoBehaviour:
serializedVersion: 2 serializedVersion: 2
x: -86 x: -86
y: 92 y: 92
width: 617 width: 636
height: 432 height: 480
m_GraphElementMetaData: m_GraphElementMetaData:
- m_Guid: - m_Guid:
m_Value0: 11886921906498108818 m_Value0: 11886921906498108818
@@ -158,6 +158,8 @@ MonoBehaviour:
- LineDuration - LineDuration
- LookAtPlayer - LookAtPlayer
- WaitForInput - WaitForInput
- SpeakerNameOverride
- ForcePlayerLook
m_ValueList: m_ValueList:
- rid: 4848514365209968924 - rid: 4848514365209968924
- rid: 4848514365209968925 - rid: 4848514365209968925
@@ -171,6 +173,8 @@ MonoBehaviour:
- rid: 4848514365209968933 - rid: 4848514365209968933
- rid: 4848514365209968934 - rid: 4848514365209968934
- rid: 4848514365209968935 - rid: 4848514365209968935
- rid: 4848514453388656931
- rid: 4848514453388656847
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -231,7 +235,7 @@ MonoBehaviour:
- rid: 4848514365209968934 - rid: 4848514365209968934
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data: data:
m_Value: 1 m_Value: 0
- rid: 4848514365209968935 - rid: 4848514365209968935
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule} type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data: data:
@@ -271,3 +275,12 @@ MonoBehaviour:
m_PortDirection: 1 m_PortDirection: 1
m_PortOrientation: 0 m_PortOrientation: 0
m_Title: m_Title:
- rid: 4848514453388656847
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value: 0
- rid: 4848514453388656931
type: {class: 'Constant`1[[DinoLove.Dialog.GraphTool.Editor.DialogShortText, Assembly-CSharp-Editor]]', ns: Unity.GraphToolkit.Editor, asm: UnityEditor.GraphToolkitModule}
data:
m_Value:
Value: