상호작용이 불가능한 상태에서도 모달 UI가 나타나도록 변경

This commit is contained in:
2026-02-12 14:49:18 +09:00
parent 2bb4797ec5
commit b32cc925e3
5 changed files with 124 additions and 14 deletions

View File

@@ -9,6 +9,8 @@ namespace Northbound
[SerializeField] private GameObject modalPanel;
[SerializeField] private TextMeshProUGUI keyText;
[SerializeField] private TextMeshProUGUI interactText;
[SerializeField] private GameObject unavailablePanel;
[SerializeField] private TextMeshProUGUI unavailableText;
[Header("Settings")]
[SerializeField] private string defaultKey = "E";
@@ -27,6 +29,11 @@ namespace Northbound
{
modalPanel.SetActive(false);
}
if (unavailablePanel != null)
{
unavailablePanel.SetActive(false);
}
}
public void ShowModal(IInteractable interactable)
@@ -54,6 +61,11 @@ namespace Northbound
{
modalPanel.SetActive(false);
}
if (unavailablePanel != null)
{
unavailablePanel.SetActive(false);
}
}
public void UpdateModalContent()
@@ -86,5 +98,48 @@ namespace Northbound
return prompt;
}
/// <summary>
/// 상호작용 불가능 메시지를 표시합니다.
/// </summary>
/// <param name="interactable">상호작용 불가능한 대상</param>
public void ShowUnavailableMessage(IInteractable interactable)
{
if (interactable == null)
{
HideModal();
return;
}
if (unavailablePanel != null)
{
// unavailablePanel이 할당된 경우 전용 패널 사용
if (modalPanel != null)
{
modalPanel.SetActive(false);
}
unavailablePanel.SetActive(true);
if (unavailableText != null)
{
string prompt = interactable.GetInteractionPrompt();
unavailableText.text = ExtractInteractText(prompt);
}
}
else if (modalPanel != null && interactText != null)
{
// unavailablePanel이 없는 경우 modalPanel을 사용하여 불가능 메시지 표시
modalPanel.SetActive(true);
if (keyText != null)
{
keyText.text = "";
}
string prompt = interactable.GetInteractionPrompt();
interactText.text = ExtractInteractText(prompt);
}
}
}
}

View File

@@ -12,6 +12,7 @@ namespace Northbound
[SerializeField] private PlayerInteraction playerInteraction;
private IInteractable _currentInteractable;
private IInteractable _previousUnavailableInteractable;
private bool _isEnabled = false;
private void Awake()
@@ -33,14 +34,13 @@ namespace Northbound
FindModalComponent();
if (interactableModal != null)
{
interactableModal.HideModal();
}
else
if (interactableModal == null)
{
Debug.LogError("[InteractableModalManager] InteractableModal is still null in Start!");
}
// Start()에서 HideModal()을 호출하지 않음 - 첫 번째 Update에서 Modal이 표시되지 않는 문제 방지
// modalPanel과 unavailablePanel은 InteractableModal.Start()에서 이미 false로 설정됨
}
private void FindModalComponent()
@@ -88,16 +88,26 @@ namespace Northbound
_isEnabled = true;
IInteractable detectedInteractable = GetDetectedInteractable();
IInteractable unavailableInteractable = playerInteraction.CurrentUnavailableInteractable;
if (detectedInteractable != _currentInteractable)
bool interactableChanged = detectedInteractable != _currentInteractable;
bool unavailableChanged = unavailableInteractable != _previousUnavailableInteractable;
if (interactableChanged || unavailableChanged)
{
_currentInteractable = detectedInteractable;
_previousUnavailableInteractable = unavailableInteractable;
if (_currentInteractable != null)
{
Debug.Log($"[InteractableModalManager] Show modal for interactable");
ShowModal(_currentInteractable);
}
else if (unavailableInteractable != null)
{
Debug.Log($"[InteractableModalManager] Show unavailable message");
ShowUnavailableMessageModal(unavailableInteractable);
}
else
{
Debug.Log($"[InteractableModalManager] Hide modal");
@@ -149,6 +159,14 @@ namespace Northbound
}
}
private void ShowUnavailableMessageModal(IInteractable interactable)
{
if (interactableModal != null)
{
interactableModal.ShowUnavailableMessage(interactable);
}
}
private void UpdateModalContent()
{
if (interactableModal != null)

View File

@@ -34,6 +34,7 @@ namespace Northbound
private PlayerInputActions _inputActions;
private IInteractable _currentInteractable;
private IInteractable _unavailableInteractable;
private Camera _mainCamera;
private Animator _animator;
private EquipmentSocket _equipmentSocket;
@@ -45,6 +46,7 @@ namespace Northbound
public bool IsInteracting => _isInteracting;
public float WorkPower => workPower;
public IInteractable CurrentUnavailableInteractable => _unavailableInteractable;
public override void OnNetworkSpawn()
{
@@ -92,30 +94,42 @@ namespace Northbound
{
Vector3 origin = rayOrigin.position;
Vector3 direction = useForwardDirection ? transform.forward : _mainCamera.transform.forward;
Ray ray = new Ray(origin, direction);
if (showDebugRay)
{
Debug.DrawRay(ray.origin, ray.direction * interactionRange,
Debug.DrawRay(ray.origin, ray.direction * interactionRange,
_currentInteractable != null ? Color.green : Color.yellow);
}
if (Physics.Raycast(ray, out RaycastHit hit, interactionRange, interactableLayer))
{
IInteractable interactable = hit.collider.GetComponent<IInteractable>();
if (interactable == null)
interactable = hit.collider.GetComponentInParent<IInteractable>();
if (interactable != null && interactable.CanInteract(OwnerClientId))
if (interactable != null)
{
_currentInteractable = interactable;
return;
if (interactable.CanInteract(OwnerClientId))
{
_currentInteractable = interactable;
_unavailableInteractable = null;
return;
}
else
{
// CanInteract가 false인 경우 추적
_currentInteractable = null;
_unavailableInteractable = interactable;
return;
}
}
}
_currentInteractable = null;
_unavailableInteractable = null;
}
private void OnInteract(InputAction.CallbackContext context)