고정각도 회전
This commit is contained in:
@@ -33,6 +33,13 @@ public class DialogNode : ScriptableObject
|
||||
[Header("Behavior")]
|
||||
public bool LookAtPlayer;
|
||||
public bool ForcePlayerLook; // true면 이 대사 시작 시 플레이어(카메라)가 화자를 바라보도록 리그를 회전
|
||||
|
||||
[Tooltip("켜면 이 대사 시작 시 화자를 아래 Fixed Angle Y(월드 Y각)로 고정 회전한다. " +
|
||||
"특정 각도에서만 자연스러운 제스처/애니메이션용. 대화 종료 시 원래 각도로 복원")]
|
||||
public bool UseFixedAngle;
|
||||
|
||||
[Tooltip("UseFixedAngle이 켜졌을 때 화자가 향할 월드 Y 회전(도). 0 = +Z(월드 forward), 90 = +X 방향")]
|
||||
public float FixedAngleY;
|
||||
public bool WaitForInput; // true면 LineDuration 무시하고 B버튼(OnDialogNext) 입력까지 대기
|
||||
public bool StagingOnly; // true면 대화창을 숨기고 연출(회전·제스처·VFX·이벤트·대기)만 수행
|
||||
|
||||
|
||||
@@ -393,6 +393,11 @@ private void RotateTowardPlayer(Transform target)
|
||||
|
||||
private void RotateToRotation(Transform target, Quaternion rotation) => AddRotationJob(target, rotation, hold: false);
|
||||
|
||||
// 화자를 특정 월드 Y각(yaw)으로 고정 회전한다. hold=true라 대화 동안 Animator가 루트를 덮어써도 유지되고,
|
||||
// 대화 종료 시 _originalRotations 복원으로 원래 각도로 돌아간다. (특정 각도 전용 애니메이션용)
|
||||
private void RotateToFixedYaw(Transform target, float yawDegrees)
|
||||
=> AddRotationJob(target, Quaternion.Euler(0f, yawDegrees, 0f), hold: true);
|
||||
|
||||
// 플레이어가 지정 위치를 바라보도록 리그를 수평(yaw)으로만 돌린다.
|
||||
// VR에서는 HMD 카메라를 직접 못 돌리므로 "Player" 태그 루트(XR Origin)를 돌려서
|
||||
// 카메라 정면이 목표를 향하게 한다. 대화가 끝나도 원상복구하지 않는다 (플레이어 시점이므로).
|
||||
@@ -548,6 +553,15 @@ private async Awaitable<bool> PlayNode(DialogNode node)
|
||||
RotatePlayerToward(voiceObj.transform.position);
|
||||
}
|
||||
|
||||
// 고정 각도 회전 — 특정 각도에서만 자연스러운 애니메이션/제스처용 (화자, 못 찾으면 대화 주인 NPC)
|
||||
if (node.UseFixedAngle)
|
||||
{
|
||||
var speakerObj = node.Speaker != null ? CharacterVoiceObject.Find(node.Speaker) : null;
|
||||
var fixedTarget = speakerObj != null ? speakerObj.transform : transform;
|
||||
_originalRotations.TryAdd(fixedTarget, GetOriginalRotation(fixedTarget));
|
||||
RotateToFixedYaw(fixedTarget, node.FixedAngleY);
|
||||
}
|
||||
|
||||
// 제스처/표정은 화자(Target)의 Animator에 적용 — 끼어든 NPC의 대사/연출 노드도 그 캐릭터가 움직인다.
|
||||
// 화자를 못 찾으면 대화 주인 NPC의 Animator로 폴백.
|
||||
if (node.Gesture != null || node.Expression != null)
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace DinoLove.Dialog.GraphTool.Editor
|
||||
// .dlg 그래프 에셋을 기존 런타임 타입(DialogGroup / DialogNode / DialogChoice)으로 변환한다.
|
||||
// 생성된 DialogNode들은 서브에셋으로, DialogGroup이 메인 에셋으로 등록된다.
|
||||
// 따라서 DialogPlayer는 수정 없이 임포트된 .dlg 에셋(= DialogGroup)을 그대로 사용한다.
|
||||
[ScriptedImporter(9, DialogGraph.AssetExtension)] // 버전 올리면 기존 .dlg 에셋이 재임포트됨
|
||||
[ScriptedImporter(10, DialogGraph.AssetExtension)] // 버전 올리면 기존 .dlg 에셋이 재임포트됨
|
||||
internal class DialogGraphImporter : ScriptedImporter
|
||||
{
|
||||
public override void OnImportAsset(AssetImportContext ctx)
|
||||
@@ -96,6 +96,8 @@ public override void OnImportAsset(AssetImportContext ctx)
|
||||
dn.LineDuration = GetInputPortValue<float>(gn.GetInputPortByName(DialogLineNode.PORT_DURATION));
|
||||
dn.LookAtPlayer = GetInputPortValue<bool>(gn.GetInputPortByName(DialogLineNode.PORT_LOOKAT));
|
||||
dn.ForcePlayerLook = GetInputPortValue<bool>(gn.GetInputPortByName(DialogLineNode.PORT_FORCELOOK));
|
||||
dn.UseFixedAngle = GetInputPortValue<bool>(gn.GetInputPortByName(DialogLineNode.PORT_USE_FIXED_ANGLE));
|
||||
dn.FixedAngleY = GetInputPortValue<float>(gn.GetInputPortByName(DialogLineNode.PORT_FIXED_ANGLE_Y));
|
||||
dn.WaitForInput = GetInputPortValue<bool>(gn.GetInputPortByName(DialogLineNode.PORT_WAITINPUT));
|
||||
dn.Affection = GetInputPortValue<int>(gn.GetInputPortByName(DialogLineNode.PORT_AFFECTION));
|
||||
dn.Progress = GetInputPortValue<int>(gn.GetInputPortByName(DialogLineNode.PORT_PROGRESS));
|
||||
@@ -162,6 +164,8 @@ static void FillStagingNode(DialogStagingNode gn, DialogNode dn)
|
||||
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));
|
||||
dn.UseFixedAngle = GetInputPortValue<bool>(gn.GetInputPortByName(DialogStagingNode.PORT_USE_FIXED_ANGLE));
|
||||
dn.FixedAngleY = GetInputPortValue<float>(gn.GetInputPortByName(DialogStagingNode.PORT_FIXED_ANGLE_Y));
|
||||
dn.Affection = GetInputPortValue<int>(gn.GetInputPortByName(DialogStagingNode.PORT_AFFECTION));
|
||||
dn.Progress = GetInputPortValue<int>(gn.GetInputPortByName(DialogStagingNode.PORT_PROGRESS));
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ internal class DialogLineNode : DialogGraphNode
|
||||
public const string PORT_DURATION = "LineDuration";
|
||||
public const string PORT_LOOKAT = "LookAtPlayer";
|
||||
public const string PORT_FORCELOOK = "ForcePlayerLook";
|
||||
public const string PORT_USE_FIXED_ANGLE = "UseFixedAngle";
|
||||
public const string PORT_FIXED_ANGLE_Y = "FixedAngleY";
|
||||
public const string PORT_WAITINPUT = "WaitForInput";
|
||||
public const string PORT_AFFECTION = "Affection";
|
||||
public const string PORT_PROGRESS = "Progress";
|
||||
@@ -95,6 +97,10 @@ protected override void OnDefinePorts(IPortDefinitionContext context)
|
||||
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_USE_FIXED_ANGLE).WithDisplayName("Use Fixed Angle")
|
||||
.WithTooltip("켜면 화자를 Fixed Angle Y(월드 Y각)로 고정 회전. 특정 각도에서만 자연스러운 애니메이션용").Build();
|
||||
context.AddInputPort<float>(PORT_FIXED_ANGLE_Y).WithDisplayName("Fixed Angle Y")
|
||||
.WithTooltip("Use Fixed Angle이 켜졌을 때 화자가 향할 월드 Y 회전(도)").Build();
|
||||
context.AddInputPort<bool>(PORT_WAITINPUT).WithDisplayName("Wait For Input").Build();
|
||||
context.AddInputPort<int>(PORT_AFFECTION).WithDisplayName("Affection ±")
|
||||
.WithTooltip("0이 아니면 이 대사 재생 시 화자(비우면 대화 주인 NPC)의 호감도를 이만큼 증감").Build();
|
||||
|
||||
@@ -19,6 +19,8 @@ internal class DialogStagingNode : DialogGraphNode
|
||||
public const string PORT_DURATION = "Duration";
|
||||
public const string PORT_LOOKAT = "LookAtPlayer";
|
||||
public const string PORT_FORCELOOK = "ForcePlayerLook";
|
||||
public const string PORT_USE_FIXED_ANGLE = "UseFixedAngle";
|
||||
public const string PORT_FIXED_ANGLE_Y = "FixedAngleY";
|
||||
public const string PORT_AFFECTION = "Affection";
|
||||
public const string PORT_PROGRESS = "Progress";
|
||||
|
||||
@@ -50,6 +52,10 @@ protected override void OnDefinePorts(IPortDefinitionContext context)
|
||||
.WithTooltip("대상 캐릭터가 플레이어를 바라봄").Build();
|
||||
context.AddInputPort<bool>(PORT_FORCELOOK).WithDisplayName("Force Player Look")
|
||||
.WithTooltip("플레이어가 대상 캐릭터를 바라봄").Build();
|
||||
context.AddInputPort<bool>(PORT_USE_FIXED_ANGLE).WithDisplayName("Use Fixed Angle")
|
||||
.WithTooltip("켜면 대상을 Fixed Angle Y(월드 Y각)로 고정 회전. 특정 각도에서만 자연스러운 애니메이션용").Build();
|
||||
context.AddInputPort<float>(PORT_FIXED_ANGLE_Y).WithDisplayName("Fixed Angle Y")
|
||||
.WithTooltip("Use Fixed Angle이 켜졌을 때 대상이 향할 월드 Y 회전(도)").Build();
|
||||
context.AddInputPort<int>(PORT_AFFECTION).WithDisplayName("Affection ±")
|
||||
.WithTooltip("0이 아니면 이 연출 재생 시 대상(비우면 대화 주인 NPC)의 호감도를 이만큼 증감").Build();
|
||||
context.AddInputPort<int>(PORT_PROGRESS).WithDisplayName("Progress +")
|
||||
|
||||
Reference in New Issue
Block a user