Compare commits

...

2 Commits

5 changed files with 124 additions and 14 deletions

1
.gitignore vendored
View File

@@ -14,3 +14,4 @@ Assets/_Recovery
Assets/_Recovery.meta
GameData/Backups
.claude/settings.local.json
AGENTS.md

View File

@@ -59,7 +59,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
GlobalObjectIdHash: 4211758632
GlobalObjectIdHash: 1360081626
InScenePlacedSourceGlobalObjectIdHash: 4211758632
DeferredDespawnTick: 0
Ownership: 1
@@ -714,6 +714,18 @@ PrefabInstance:
serializedVersion: 3
m_TransformParent: {fileID: 1710962577221812646}
m_Modifications:
- target: {fileID: 1325989084779099817, guid: 274613c415998a647a86a5e09950ce41, type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 1325989084779099817, guid: 274613c415998a647a86a5e09950ce41, type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 1325989084779099817, guid: 274613c415998a647a86a5e09950ce41, type: 3}
propertyPath: m_AnchorMax.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1325989084779099817, guid: 274613c415998a647a86a5e09950ce41, type: 3}
propertyPath: m_AnchorMax.y
value: 0
@@ -724,7 +736,11 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 1325989084779099817, guid: 274613c415998a647a86a5e09950ce41, type: 3}
propertyPath: m_SizeDelta.x
value: 4
value: 500
objectReference: {fileID: 0}
- target: {fileID: 1325989084779099817, guid: 274613c415998a647a86a5e09950ce41, type: 3}
propertyPath: m_SizeDelta.y
value: 50
objectReference: {fileID: 0}
- target: {fileID: 1325989084779099817, guid: 274613c415998a647a86a5e09950ce41, type: 3}
propertyPath: m_AnchoredPosition.x
@@ -834,6 +850,10 @@ PrefabInstance:
propertyPath: m_Name
value: ModalPanel
objectReference: {fileID: 0}
- target: {fileID: 7839034454177399683, guid: 274613c415998a647a86a5e09950ce41, type: 3}
propertyPath: m_fontStyle
value: 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
@@ -878,6 +898,8 @@ MonoBehaviour:
modalPanel: {fileID: 4694931302848755623}
keyText: {fileID: 4193449683656256336}
interactText: {fileID: 8795452566802714605}
unavailablePanel: {fileID: 4694931302848755623}
unavailableText: {fileID: 8795452566802714605}
defaultKey: E
--- !u!114 &8795452566802714605 stripped
MonoBehaviour:

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()
{
@@ -108,14 +110,26 @@ namespace Northbound
if (interactable == null)
interactable = hit.collider.GetComponentInParent<IInteractable>();
if (interactable != null && interactable.CanInteract(OwnerClientId))
if (interactable != null)
{
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)