대화중에 아웃라인 안뜨게
This commit is contained in:
@@ -61,6 +61,33 @@ public struct NodeEvent
|
||||
// 선택 메뉴만 떠 있는 단계는 여기 안 잡힌다 (그 경우는 새 NPC가 메뉴를 취소하고 시작).
|
||||
private static DialogPlayer _entryInProgress;
|
||||
|
||||
// ── 전역 대화 진행 신호 (대화 중 월드 상호작용 차단용) ────────
|
||||
// 선택 메뉴 단계부터 대사 종료까지, 어느 NPC든 대화가 진행 중이면 true.
|
||||
// DialogInteractionBlocker가 구독해서 인터랙터를 잠근다.
|
||||
public static bool IsAnyActive => _activeCount > 0;
|
||||
public static event Action<bool> AnyActiveChanged;
|
||||
private static int _activeCount;
|
||||
|
||||
private static void PushActive()
|
||||
{
|
||||
if (++_activeCount == 1) AnyActiveChanged?.Invoke(true);
|
||||
}
|
||||
|
||||
private static void PopActive()
|
||||
{
|
||||
if (_activeCount <= 0) return;
|
||||
if (--_activeCount == 0) AnyActiveChanged?.Invoke(false);
|
||||
}
|
||||
|
||||
// Enter Play Mode에서 도메인 리로드를 꺼도 이전 상태가 안 남게
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void ResetStatics()
|
||||
{
|
||||
_entryInProgress = null;
|
||||
_activeCount = 0;
|
||||
AnyActiveChanged = null;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_voice = GetComponent<CharacterVoiceObject>();
|
||||
@@ -91,6 +118,7 @@ public async Awaitable Play()
|
||||
|
||||
// 선택 메뉴가 떠 있는 동안에도 재진입을 막아야 하므로 여기서 잠근다.
|
||||
IsPlaying = true;
|
||||
PushActive();
|
||||
try
|
||||
{
|
||||
var playable = FindPlayableIndices();
|
||||
@@ -128,6 +156,7 @@ public async Awaitable Play()
|
||||
RestoreRotations();
|
||||
if (_entryInProgress == this) _entryInProgress = null;
|
||||
IsPlaying = false;
|
||||
PopActive();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +179,7 @@ private async Awaitable PlayGroupForced(DialogGroup group)
|
||||
ChoiceHud.Instance.CancelPending();
|
||||
|
||||
IsPlaying = true;
|
||||
PushActive();
|
||||
try
|
||||
{
|
||||
// 등록된 항목이 있으면 Repeatable/ProgressOnComplete 설정을 그대로 사용
|
||||
@@ -178,6 +208,7 @@ private async Awaitable PlayGroupForced(DialogGroup group)
|
||||
RestoreRotations();
|
||||
if (_entryInProgress == this) _entryInProgress = null;
|
||||
IsPlaying = false;
|
||||
PopActive();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
56
Assets/02_Scripts/Interact/DialogInteractionBlocker.cs
Normal file
56
Assets/02_Scripts/Interact/DialogInteractionBlocker.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.Interaction.Toolkit;
|
||||
using UnityEngine.XR.Interaction.Toolkit.Interactors;
|
||||
|
||||
// 대화 중(선택 메뉴 포함) 월드 상호작용을 차단한다 — UI 상호작용은 유지.
|
||||
// XR Origin(리그 루트)에 붙이면 자식의 모든 인터랙터를 찾아서, 대화가 시작될 때
|
||||
// Interaction Layer를 None으로 바꿔 3D 인터랙터블과의 호버/선택/활성화를 막는다.
|
||||
// 캔버스 UI(선택지 버튼 등)는 인터랙션 레이어를 거치지 않고 XRUIInputModule로
|
||||
// 처리되므로 영향받지 않는다. 대화가 끝나면 원래 레이어로 복원.
|
||||
public class DialogInteractionBlocker : MonoBehaviour
|
||||
{
|
||||
[Tooltip("차단에서 제외할 인터랙터 (예: 대화 중에도 텔레포트를 허용하고 싶을 때 텔레포트 레이 인터랙터)")]
|
||||
[SerializeField] private List<XRBaseInteractor> _exclude = new();
|
||||
|
||||
// 차단 직전의 원래 레이어 — 복원용. 비어있지 않으면 차단 중이라는 뜻.
|
||||
private readonly Dictionary<XRBaseInteractor, InteractionLayerMask> _saved = new();
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
DialogPlayer.AnyActiveChanged += OnDialogActiveChanged;
|
||||
if (DialogPlayer.IsAnyActive) Block(); // 이미 대화 중에 활성화된 경우
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
DialogPlayer.AnyActiveChanged -= OnDialogActiveChanged;
|
||||
Restore();
|
||||
}
|
||||
|
||||
private void OnDialogActiveChanged(bool active)
|
||||
{
|
||||
if (active) Block();
|
||||
else Restore();
|
||||
}
|
||||
|
||||
private void Block()
|
||||
{
|
||||
if (_saved.Count > 0) return; // 이미 차단 중
|
||||
|
||||
// 매번 새로 수집 — 손에 든 도구 등 런타임에 생긴 인터랙터도 포함되게
|
||||
foreach (var interactor in GetComponentsInChildren<XRBaseInteractor>(true))
|
||||
{
|
||||
if (_exclude.Contains(interactor)) continue;
|
||||
_saved[interactor] = interactor.interactionLayers;
|
||||
interactor.interactionLayers = 0; // None — 3D 인터랙터블 전부 차단
|
||||
}
|
||||
}
|
||||
|
||||
private void Restore()
|
||||
{
|
||||
foreach (var kvp in _saved)
|
||||
if (kvp.Key != null) kvp.Key.interactionLayers = kvp.Value;
|
||||
_saved.Clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77d7c7e6b5a73944fbcf03ba2bab1244
|
||||
Reference in New Issue
Block a user