인터랙션 하이라이트 기능 추가, 인터랙션 인터페이스 일부 변경
This commit is contained in:
parent
0444b84249
commit
2d4edba36c
@ -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);
|
||||
}
|
||||
}
|
||||
|
20
Assets/_DDD/_Scripts/GameFramework/PlayerManager.cs
Normal file
20
Assets/_DDD/_Scripts/GameFramework/PlayerManager.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace DDD
|
||||
{
|
||||
public class PlayerManager : Singleton<PlayerManager>
|
||||
{
|
||||
private GameObject _player;
|
||||
|
||||
public void RegisterPlayer(GameObject player)
|
||||
{
|
||||
_player = player;
|
||||
Debug.Log($"Player registered: {player.name}");
|
||||
}
|
||||
|
||||
public GameObject GetPlayer()
|
||||
{
|
||||
return _player ? _player : null;
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,10 @@ namespace DDD
|
||||
{
|
||||
public class RestaurantPlayerCharacter : RestaurantCharacter
|
||||
{
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
PlayerManager.Instance.RegisterPlayer(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<RestaurantCharacterInteraction>();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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<IInteractable>(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)
|
||||
@ -100,6 +100,17 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<HighlightPlus.HighlightEffect>();
|
||||
interaction = GetComponent<RestaurantInteractionComponent>();
|
||||
_highlightComponent = GetComponent<HighlightPlus.HighlightEffect>();
|
||||
_interactionComponent = GetComponent<RestaurantInteractionComponent>();
|
||||
|
||||
// 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<IInteractor>();
|
||||
}
|
||||
}
|
||||
|
||||
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 _interactor?.GetFocusedInteractable() == _interactionComponent;
|
||||
}
|
||||
|
||||
private bool CanExecuteInteraction()
|
||||
{
|
||||
if (_interactionComponent.CanInteract() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_interactor == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _interactor.CanInteractTo(_interactionComponent);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -17,7 +17,7 @@ private async Task Initialize()
|
||||
_restaurantManagementSo = await AssetManager.LoadAsset<RestaurantManagementSo>(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();
|
||||
|
Loading…
Reference in New Issue
Block a user