MoveTo, LookAt 타겟 지정 수정

This commit is contained in:
Jeonghyeon Ha 2025-08-27 19:43:08 +09:00
parent bf1fe51957
commit dfc4fa26d6
6 changed files with 50 additions and 78 deletions

View File

@ -9,7 +9,7 @@ namespace DDD
/// </summary> /// </summary>
public interface IAISharedBlackboard public interface IAISharedBlackboard
{ {
void SetCurrentInteractionTarget(GameObject targetGameObject); void SetBlackboardGameObject(string key, GameObject inGameObject);
GameObject GetCurrentInteractionTarget(); GameObject GetBlackboardGameObject(string key);
} }
} }

View File

@ -30,42 +30,43 @@ public interface ILookAtVisual
void EndLookAt(); void EndLookAt();
} }
private ILookAtVisual visual; private ILookAtVisual _visual;
private GameObject cachedTarget; private GameObject _cachedTarget;
private bool isLooking; private bool _isLooking;
private Vector3 currentLookPosition; private Vector3 _currentLookPosition;
public override void OnStart() public override void OnStart()
{ {
visual = gameObject.GetComponentInParent<ILookAtVisual>(); _visual = gameObject.GetComponentInParent<ILookAtVisual>();
cachedTarget = null; _isLooking = false;
isLooking = false;
var blackboard = gameObject.GetComponent<IAISharedBlackboard>();
_cachedTarget = blackboard.GetBlackboardGameObject(nameof(RestaurantCustomerBlackboardKey.CurrentInteractionTarget));
} }
public override TaskStatus OnUpdate() public override TaskStatus OnUpdate()
{ {
var target = GetTarget(); if (_cachedTarget == null)
if (target == null)
{ {
if (isLooking) if (_isLooking)
{ {
// 타겟이 사라졌다면 정리 // 타겟이 사라졌다면 정리
visual?.EndLookAt(); _visual?.EndLookAt();
isLooking = false; _isLooking = false;
} }
return TaskStatus.Success; return TaskStatus.Success;
} }
currentLookPosition = CalculateLookPosition(target); _currentLookPosition = CalculateLookPosition(_cachedTarget);
if (!isLooking) if (!_isLooking)
{ {
visual?.TryBeginLookAt(currentLookPosition); _visual?.TryBeginLookAt(_currentLookPosition);
isLooking = true; _isLooking = true;
} }
else else
{ {
visual?.UpdateLookAt(currentLookPosition); _visual?.UpdateLookAt(_currentLookPosition);
} }
// 연속 업데이트면 Running, 아니면 1회만 시도 후 Success 반환 // 연속 업데이트면 Running, 아니면 1회만 시도 후 Success 반환
@ -74,33 +75,12 @@ public override TaskStatus OnUpdate()
public override void OnEnd() public override void OnEnd()
{ {
if (isLooking) if (_isLooking)
{ {
visual?.EndLookAt(); _visual?.EndLookAt();
isLooking = false; _isLooking = false;
} }
cachedTarget = null; _cachedTarget = null;
}
private GameObject GetTarget()
{
// 캐시된 타겟이 유효하면 재사용
if (IsValidTarget(cachedTarget))
return cachedTarget;
// 블랙보드에서 타겟 검색
cachedTarget = gameObject.GetComponent<IAISharedBlackboard>()
?.GetCurrentInteractionTarget();
if (IsValidTarget(cachedTarget))
return cachedTarget;
// Interactor의 포커스된 타겟 검색
var interactor = gameObject.GetComponent<IInteractor>();
var focusedInteractable = interactor?.GetFocusedInteractable();
cachedTarget = focusedInteractable?.GetInteractableGameObject();
return cachedTarget;
} }
private static bool IsValidTarget(GameObject target) => target != null && target; private static bool IsValidTarget(GameObject target) => target != null && target;

View File

@ -23,32 +23,30 @@ public class MoveToInteractionTarget : Action
private float _repathTimer; private float _repathTimer;
private Vector3 _currentDestination; private Vector3 _currentDestination;
private bool _isMoving; private bool _isMoving;
private GameObject _target;
public override void OnStart() public override void OnStart()
{ {
_movement = gameObject.GetComponent<IAiMovement>(); _movement = gameObject.GetComponent<IAiMovement>();
_repathTimer = 0f; _repathTimer = 0f;
_isMoving = false; _isMoving = false;
Debug.Log($"MoveToInteractionTarget - GameObject: {gameObject.name}"); var blackboard = gameObject.GetComponent<IAISharedBlackboard>();
_target = blackboard.GetBlackboardGameObject(nameof(RestaurantCustomerBlackboardKey.CurrentInteractionTarget));
} }
public override TaskStatus OnUpdate() public override TaskStatus OnUpdate()
{ {
if (_movement == null) if (_movement == null)
return TaskStatus.Failure; return TaskStatus.Failure;
if (_target == null)
var target = GetTarget();
if (target == null)
{ {
return TaskStatus.Running; // If has no target, stuck in this state return TaskStatus.Failure;
} }
Debug.Log(target.name);
if (ShouldUpdateDestination()) if (ShouldUpdateDestination())
{ {
_currentDestination = CalculateDestination(target); _currentDestination = CalculateDestination(_target);
StartOrUpdateMovement(); StartOrUpdateMovement();
} }
@ -60,15 +58,6 @@ public override void OnEnd()
StopMovement(); StopMovement();
} }
private GameObject GetTarget()
{
// Interactor의 포커스된 타겟 검색
var interactor = gameObject.GetComponent<IInteractor>();
var focusedInteractable = interactor?.GetFocusedInteractable();
if (focusedInteractable != null) return focusedInteractable.GetInteractableGameObject();
return null;
}
private bool ShouldUpdateDestination() private bool ShouldUpdateDestination()
{ {
_repathTimer -= Time.deltaTime; _repathTimer -= Time.deltaTime;

View File

@ -12,6 +12,8 @@ public class StartRestaurantOrder : Action
[SerializeField] private bool _requireCanInteract = true; [SerializeField] private bool _requireCanInteract = true;
[Tooltip("성공 시 블랙보드에 현재 인터랙션 대상을 등록합니다")] [Tooltip("성공 시 블랙보드에 현재 인터랙션 대상을 등록합니다")]
[SerializeField] private bool _registerOnBlackboard = true; [SerializeField] private bool _registerOnBlackboard = true;
[Tooltip("성공 시 블랙보드에 현재 인터랙션 대상을 등록합니다")]
[SerializeField] private bool _UnregisterOnBlackboard = false;
private IInteractor _interactor; private IInteractor _interactor;
private bool _isGetInteractor; private bool _isGetInteractor;
@ -43,9 +45,14 @@ public override TaskStatus OnUpdate()
if (_registerOnBlackboard) if (_registerOnBlackboard)
{ {
// 하위 호환: 고객 전용 블랙보드 지원 var customerBlackboard = gameObject.GetComponent<IAISharedBlackboard>();
var customerBlackboard = gameObject.GetComponent<ICustomerBlackboard>(); customerBlackboard?.SetBlackboardGameObject(nameof(RestaurantCustomerBlackboardKey.CurrentInteractionTarget), outInteractable.gameObject);
customerBlackboard?.SetCurrentInteractionTarget(outInteractable.gameObject); }
if (_UnregisterOnBlackboard)
{
var customerBlackboard = gameObject.GetComponent<IAISharedBlackboard>();
customerBlackboard?.SetBlackboardGameObject(nameof(RestaurantCustomerBlackboardKey.CurrentInteractionTarget), null);
} }
return TaskStatus.Success; return TaskStatus.Success;

View File

@ -6,8 +6,7 @@ namespace DDD
public class CustomerBlackboardComponent : MonoBehaviour, ICustomerBlackboard, IAISharedBlackboard public class CustomerBlackboardComponent : MonoBehaviour, ICustomerBlackboard, IAISharedBlackboard
{ {
private Subtree _subtree; private Subtree _subtree;
private GameObject _currentInteractionTarget;
public void InitializeWithBehaviorTree(Subtree subtree) public void InitializeWithBehaviorTree(Subtree subtree)
{ {
_subtree = subtree; _subtree = subtree;
@ -22,18 +21,17 @@ public void SetCustomerData(CustomerData inCustomerData)
if (_subtree == null) return; if (_subtree == null) return;
_subtree.SetVariableValue(nameof(RestaurantCustomerBlackboardKey.CustomerData), inCustomerData); _subtree.SetVariableValue(nameof(RestaurantCustomerBlackboardKey.CustomerData), inCustomerData);
} }
public void SetCurrentInteractionTarget(GameObject targetGameObject) public void SetBlackboardGameObject(string key, GameObject inGameObject)
{ {
_currentInteractionTarget = targetGameObject;
if (_subtree == null) return; if (_subtree == null) return;
_subtree.SetVariableValue(nameof(RestaurantCustomerBlackboardKey.CurrentInteractionTarget), targetGameObject); _subtree.SetVariableValue(key, inGameObject);
} }
public GameObject GetCurrentInteractionTarget() public GameObject GetBlackboardGameObject(string key)
{ {
// 캐시 우선 반환. 필요 시 Subtree에서 직접 조회하도록 확장 가능. if (_subtree == null) return null;
return _currentInteractionTarget; return _subtree.GetVariable<GameObject>(key)?.Value;
} }
} }
} }

View File

@ -12,7 +12,5 @@ public enum RestaurantCustomerBlackboardKey
public interface ICustomerBlackboard public interface ICustomerBlackboard
{ {
void SetCustomerData(CustomerData inCustomerData); void SetCustomerData(CustomerData inCustomerData);
void SetCurrentInteractionTarget(GameObject targetGameObject);
GameObject GetCurrentInteractionTarget();
} }
} }