diff --git a/Assets/_DDD/_Scripts/GameEvent/IInteractable.cs b/Assets/_DDD/_Scripts/GameEvent/IInteractable.cs index 556fae820..eee983bff 100644 --- a/Assets/_DDD/_Scripts/GameEvent/IInteractable.cs +++ b/Assets/_DDD/_Scripts/GameEvent/IInteractable.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using UnityEngine; namespace DDD @@ -15,21 +16,27 @@ public enum InteractionType : uint public interface IInteractable { bool CanInteract(); - bool OnInteracted(IInteractor interactor, ScriptableObject interactionPayloadSo = null); + bool OnInteracted(IInteractor interactor, ScriptableObject payloadSo = null); InteractionType GetInteractionType(); GameObject GetInteractableGameObject(); void InitializeInteraction(InteractionType interactionType); float GetRequiredHoldTime(); string GetInteractionMessageKey(); } + public interface IInteractor { GameObject GetInteractorGameObject(); + IInteractable GetFocusedInteractable(); + bool CanSolveInteractionType(InteractionType interactionType); + bool CanInteractTo(IInteractable interactable, + ScriptableObject payloadSo = null); } public interface IInteractionSolver { - bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject interactionPayloadSo = null); - bool CanExecuteInteraction(); + bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null); + bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null, + ScriptableObject payloadSo = null); } } diff --git a/Assets/_DDD/_Scripts/GameFramework/PlayerManager.cs b/Assets/_DDD/_Scripts/GameFramework/PlayerManager.cs new file mode 100644 index 000000000..df2473e08 --- /dev/null +++ b/Assets/_DDD/_Scripts/GameFramework/PlayerManager.cs @@ -0,0 +1,20 @@ +using UnityEngine; + +namespace DDD +{ + public class PlayerManager : Singleton + { + private GameObject _player; + + public void RegisterPlayer(GameObject player) + { + _player = player; + Debug.Log($"Player registered: {player.name}"); + } + + public GameObject GetPlayer() + { + return _player ? _player : null; + } + } +} \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/RestaurantCharacter/Player/RestaurantPlayerCharacter.cs b/Assets/_DDD/_Scripts/RestaurantCharacter/Player/RestaurantPlayerCharacter.cs index 851c03542..82d75099d 100644 --- a/Assets/_DDD/_Scripts/RestaurantCharacter/Player/RestaurantPlayerCharacter.cs +++ b/Assets/_DDD/_Scripts/RestaurantCharacter/Player/RestaurantPlayerCharacter.cs @@ -4,6 +4,10 @@ namespace DDD { public class RestaurantPlayerCharacter : RestaurantCharacter { - + protected override void Awake() + { + base.Awake(); + PlayerManager.Instance.RegisterPlayer(gameObject); + } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/RestaurantCharacter/Player/RestaurantPlayerInteraction.cs b/Assets/_DDD/_Scripts/RestaurantCharacter/Player/RestaurantPlayerInteraction.cs index 74429f15b..8bd90b1de 100644 --- a/Assets/_DDD/_Scripts/RestaurantCharacter/Player/RestaurantPlayerInteraction.cs +++ b/Assets/_DDD/_Scripts/RestaurantCharacter/Player/RestaurantPlayerInteraction.cs @@ -45,7 +45,7 @@ protected override void OnDestroy() private void OnInteractPerformed(InputAction.CallbackContext context) { - if (_nearestInteractable == null || CanInteract(_nearestInteractable) == false) return; + if (_nearestInteractable == null || CanInteractTo(_nearestInteractable) == false) return; float requiredHoldTime = _nearestInteractable.GetRequiredHoldTime(); @@ -71,7 +71,7 @@ protected override void OnNearestInteractableChanged(IInteractable newTarget) { if (newTarget != null) { - BroadcastShowUi(newTarget, CanInteract(newTarget), 0f); + BroadcastShowUi(newTarget, CanInteractTo(newTarget), 0f); } else { @@ -83,7 +83,7 @@ protected override void OnInteractionHoldProgress(float ratio) { if (_interactingTarget != null) { - BroadcastShowUi(_interactingTarget, CanInteract(_interactingTarget), ratio); + BroadcastShowUi(_interactingTarget, CanInteractTo(_interactingTarget), ratio); } } diff --git a/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacter.cs b/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacter.cs index 46ecfa207..8d4921018 100644 --- a/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacter.cs +++ b/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacter.cs @@ -7,7 +7,11 @@ public class RestaurantCharacter : MonoBehaviour, IGameCharacter, IInteractor { [EnumToggleButtons, SerializeField] protected InteractionType _interactionType; - protected virtual void Awake() { } + RestaurantCharacterInteraction _interactionComponent; + protected virtual void Awake() + { + _interactionComponent = GetComponent(); + } protected virtual void Start() { @@ -27,7 +31,22 @@ protected virtual void Start() public GameObject GetInteractorGameObject() { - return gameObject; + return _interactionComponent.GetInteractorGameObject(); + } + + public IInteractable GetFocusedInteractable() + { + return _interactionComponent.GetFocusedInteractable(); + } + + public bool CanSolveInteractionType(InteractionType interactionType) + { + return _interactionComponent.CanSolveInteractionType(interactionType); + } + + public bool CanInteractTo(IInteractable interactable, ScriptableObject payloadSo = null) + { + return _interactionComponent.CanInteractTo(interactable, payloadSo); } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacterInteraction.cs b/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacterInteraction.cs index f8a8df49e..6455a7fb5 100644 --- a/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacterInteraction.cs +++ b/Assets/_DDD/_Scripts/RestaurantCharacter/RestaurantCharacterInteraction.cs @@ -33,7 +33,7 @@ protected virtual void Update() if (_isInteracting) { - if (_nearestInteractable != _interactingTarget || CanInteract(_interactingTarget) == false) + if (_nearestInteractable != _interactingTarget || CanInteractTo(_interactingTarget) == false) { ResetInteractionState(); return; @@ -83,7 +83,7 @@ protected IInteractable GetNearestInteractable() if (col.TryGetComponent(out var interactable) == false) continue; var type = interactable.GetInteractionType(); - if (ContainsSolverForType(type) == false) continue; + if (CanSolveInteractionType(type) == false) continue; float distance = Vector3.Distance(transform.position, col.transform.position); if (distance < closestDistance) @@ -99,7 +99,18 @@ protected IInteractable GetNearestInteractable() public virtual void Invoke(RestaurantInteractionEvent evt) { } public GameObject GetInteractorGameObject() => gameObject; - + + public IInteractionSolver GetInteractionSolver(InteractionType interactionType) + { + TryGetSolverForType(interactionType, out var solver); + return solver; + } + + public IInteractable GetFocusedInteractable() + { + return _nearestInteractable; + } + private bool TryGetSolverFor(IInteractable interactable, out IInteractionSolver solver) { solver = null; @@ -124,7 +135,7 @@ private bool TryGetSolverForType(InteractionType type, out IInteractionSolver so return solver != null; } - private bool ContainsSolverForType(InteractionType type) + public bool CanSolveInteractionType(InteractionType type) { if (_cachedSolvers.TryGetValue(type, out var cachedSolver)) return cachedSolver != null; @@ -137,13 +148,12 @@ private bool ContainsSolverForType(InteractionType type) return solver != null; } - protected bool CanInteract(IInteractable interactable) + public bool CanInteractTo(IInteractable interactable, ScriptableObject payloadSo = null) { if (interactable == null) return false; if (interactable.CanInteract() == false) return false; if (TryGetSolverFor(interactable, out var solver) == false) return false; - - return solver.CanExecuteInteraction(); + return solver.CanExecuteInteraction(this, interactable, payloadSo); } } } diff --git a/Assets/_DDD/_Scripts/RestaurantEvent/InteractableHighlight.cs b/Assets/_DDD/_Scripts/RestaurantEvent/InteractableHighlight.cs index 2bfb7f17b..e98a86ffc 100644 --- a/Assets/_DDD/_Scripts/RestaurantEvent/InteractableHighlight.cs +++ b/Assets/_DDD/_Scripts/RestaurantEvent/InteractableHighlight.cs @@ -36,50 +36,61 @@ public class InteractableHighlight : MonoBehaviour {InteractionOutlineType.None, new InteractionOutlineData() {Color = Color.clear, Width = 0.5f, Opacity = 0f}} }; - private float OpacityMultiply = 1.0f; - private HighlightEffect highlight; - private RestaurantInteractionComponent interaction; + private HighlightEffect _highlightComponent; + private RestaurantInteractionComponent _interactionComponent; + private IInteractor _interactor; private void Awake() { // Cache HighlightEffect - highlight = GetComponent(); - interaction = GetComponent(); + _highlightComponent = GetComponent(); + _interactionComponent = GetComponent(); // highlightEffect에 alphaCutoff, constantWidth, combineMeshes, outlineQuality, outlineIndependent 등의 필수 옵션이 켜져있는지 확인 - highlight.alphaCutOff = 0.5f; - highlight.combineMeshes = true; - highlight.constantWidth = true; - highlight.outlineQuality = QualityLevel.Highest; - highlight.outlineIndependent = true; - highlight.outlineBlurPasses = 1; - highlight.outlineSharpness = 8; + _highlightComponent.alphaCutOff = 0.5f; + _highlightComponent.combineMeshes = true; + _highlightComponent.constantWidth = true; + _highlightComponent.outlineQuality = QualityLevel.Highest; + _highlightComponent.outlineIndependent = true; + _highlightComponent.outlineBlurPasses = 1; + _highlightComponent.outlineSharpness = 8; } private void Update() { + FetchPlayerInteractorComponent(); + var currentType = GetCurrentOutlineType(); ApplyOutlineType(currentType); + + + } + + private void FetchPlayerInteractorComponent() + { + if (_interactor == null) + { + var player = PlayerManager.Instance.GetPlayer(); + _interactor = player?.GetComponent(); + } } private InteractionOutlineType GetCurrentOutlineType() { // interaction이 null이거나 컴포넌트가 비활성화된 경우 - if (interaction == null || !interaction.enabled) + if (!_interactionComponent || !_interactionComponent.enabled) return InteractionOutlineType.None; // IInteractable 인터페이스로 캐스팅하여 상태 확인 - var interactable = interaction as IInteractable; - if (interactable == null) + if (_interactionComponent is not IInteractable interactable) return InteractionOutlineType.None; try { // 상호작용 불가능한 경우 - if (!interactable.CanInteract()) + if (CanExecuteInteraction() == false) return InteractionOutlineType.Unavailable; // TODO: 여기에 추가 상태 로직을 구현 - // - isHovered, isFocused 등의 상태를 체크 // - isObjective 등의 퀘스트 상태를 체크 // 플레이어가 현재 이 오브젝트를 포커스 중인지 확인 @@ -93,7 +104,6 @@ private InteractionOutlineType GetCurrentOutlineType() } catch { - // CanInteract() 호출 중 예외 발생 시 안전하게 처리 return InteractionOutlineType.Unavailable; } } @@ -108,7 +118,7 @@ private void ApplyOutlineType(InteractionOutlineType type) lastAppliedType = type; - if (highlight == null) + if (!_highlightComponent) return; // OutlineData에서 해당 타입의 스타일 가져오기 @@ -121,35 +131,35 @@ private void ApplyOutlineType(InteractionOutlineType type) // HighlightEffect에 적용 if (type == InteractionOutlineType.None) { - highlight.highlighted = false; - highlight.outline = 0; + _highlightComponent.highlighted = false; + _highlightComponent.outline = 0; } else { - highlight.highlighted = true; - highlight.outlineColor = data.Color; - highlight.outlineWidth = data.Width; - highlight.outline = data.Opacity * OpacityMultiply; + _highlightComponent.highlighted = true; + _highlightComponent.outlineColor = data.Color; + _highlightComponent.outlineWidth = data.Width; + _highlightComponent.outline = data.Opacity * opacityMultiply; } } - private bool IsPlayerFocusing() { - // 방법 1: 싱글톤 패턴의 플레이어 매니저 사용 - // if (PlayerManager.Instance != null) - // { - // return PlayerManager.Instance.CurrentFocusTarget == gameObject; - // } - - // 방법 3: 정적 참조를 통한 현재 포커스 대상 확인 - // if (InteractionSystem.CurrentFocusedObject == gameObject) - // { - // return true; - // } - - return false; + return _interactor?.GetFocusedInteractable() == _interactionComponent; } + + private bool CanExecuteInteraction() + { + if (_interactionComponent.CanInteract() == false) + { + return false; + } + if (_interactor == null) + { + return false; + } + return _interactor.CanInteractTo(_interactionComponent); + } } } \ No newline at end of file diff --git a/Assets/_DDD/_Scripts/RestaurantEvent/RestaurantInteractionComponent.cs b/Assets/_DDD/_Scripts/RestaurantEvent/RestaurantInteractionComponent.cs index c52e944e6..0adfe0412 100644 --- a/Assets/_DDD/_Scripts/RestaurantEvent/RestaurantInteractionComponent.cs +++ b/Assets/_DDD/_Scripts/RestaurantEvent/RestaurantInteractionComponent.cs @@ -13,14 +13,14 @@ public bool CanInteract() return true; } - public bool OnInteracted(IInteractor interactor, ScriptableObject interactionPayloadSo = null) + public bool OnInteracted(IInteractor interactor, ScriptableObject payloadSo = null) { if (CanInteract() == false) { return false; } bool interactionResult = RestaurantInteractionEvents.RestaurantInteraction.RequestInteraction(interactor.GetInteractorGameObject(), - GetInteractableGameObject(), GetInteractionType(), interactionPayloadSo, true); + GetInteractableGameObject(), GetInteractionType(), payloadSo, true); return interactionResult; } diff --git a/Assets/_DDD/_Scripts/RestaurantEvent/Solvers/RestaurantManagementUiEventSolver.cs b/Assets/_DDD/_Scripts/RestaurantEvent/Solvers/RestaurantManagementUiEventSolver.cs index 6407cdb0e..c740cfb4f 100644 --- a/Assets/_DDD/_Scripts/RestaurantEvent/Solvers/RestaurantManagementUiEventSolver.cs +++ b/Assets/_DDD/_Scripts/RestaurantEvent/Solvers/RestaurantManagementUiEventSolver.cs @@ -4,7 +4,7 @@ namespace DDD { public class RestaurantManagementUiEventSolver : MonoBehaviour, IInteractionSolver { - public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject interactionPayloadSo = null) + public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null) { if (CanExecuteInteraction() == false) return false; @@ -14,7 +14,8 @@ public bool ExecuteInteraction(IInteractor interactor, IInteractable interactabl return true; } - public bool CanExecuteInteraction() + public bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null, + ScriptableObject payloadSo = null) { GameFlowState currentGameFlowState = GameFlowManager.Instance.GameFlowDataSo.CurrentGameState; return currentGameFlowState == GameFlowState.ReadyForRestaurant; diff --git a/Assets/_DDD/_Scripts/RestaurantEvent/Solvers/RestaurantOpenEventSolver.cs b/Assets/_DDD/_Scripts/RestaurantEvent/Solvers/RestaurantOpenEventSolver.cs index 0ea0c75fa..ae0a832bc 100644 --- a/Assets/_DDD/_Scripts/RestaurantEvent/Solvers/RestaurantOpenEventSolver.cs +++ b/Assets/_DDD/_Scripts/RestaurantEvent/Solvers/RestaurantOpenEventSolver.cs @@ -17,7 +17,7 @@ private async Task Initialize() _restaurantManagementSo = await AssetManager.LoadAsset(DataConstants.RestaurantManagementSo); } - public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject interactionPayloadSo = null) + public bool ExecuteInteraction(IInteractor interactor, IInteractable interactable, ScriptableObject payloadSo = null) { if (CanExecuteInteraction() == false) return false; @@ -25,7 +25,8 @@ public bool ExecuteInteraction(IInteractor interactor, IInteractable interactabl return true; } - public bool CanExecuteInteraction() + public bool CanExecuteInteraction(IInteractor interactor = null, IInteractable interactable = null, + ScriptableObject payloadSo = null) { GameFlowState currentGameFlowState = GameFlowManager.Instance.GameFlowDataSo.CurrentGameState; return currentGameFlowState == GameFlowState.ReadyForRestaurant && _restaurantManagementSo.IsOpenable();