Merge remote-tracking branch 'origin/develop' into develop
# Conflicts: # Assets/_DDD/_Scripts/Restaurant/Character/AI/Customer/CustomerAiComponent.cs # Assets/_DDD/_Scripts/Restaurant/Character/AI/Customer/CustomerBlackboardComponent.cs # Assets/_DDD/_Scripts/Restaurant/Character/Interfaces/ICustomerBlackboard.cs
This commit is contained in:
commit
86c0f67c7c
BIN
Assets/_DDD/_Addressables/AI/Customer/Subtree/CustomerDefault.asset
(Stored with Git LFS)
BIN
Assets/_DDD/_Addressables/AI/Customer/Subtree/CustomerDefault.asset
(Stored with Git LFS)
Binary file not shown.
BIN
Assets/_DDD/_Addressables/AI/Customer/Subtree/OrderSubtree.asset
(Stored with Git LFS)
BIN
Assets/_DDD/_Addressables/AI/Customer/Subtree/OrderSubtree.asset
(Stored with Git LFS)
Binary file not shown.
@ -1210,9 +1210,6 @@ PrefabInstance:
|
||||
- targetCorrespondingSourceObject: {fileID: 7462519206451630147, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
|
||||
insertIndex: -1
|
||||
addedObject: {fileID: 3825874317044733320}
|
||||
- targetCorrespondingSourceObject: {fileID: 7462519206451630147, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
|
||||
insertIndex: -1
|
||||
addedObject: {fileID: 1122074513716966771}
|
||||
m_SourcePrefab: {fileID: 100100000, guid: ceeea618d8ee23642a0e56b3f963448c, type: 3}
|
||||
--- !u!1 &4266090516809920735 stripped
|
||||
GameObject:
|
||||
@ -1255,23 +1252,3 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: af69e82818254bfa9cabb2dbf9430850, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &1122074513716966771
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4266090516809920735}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 201f9e6d7ca7404baa9945950292a392, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_interactionType: 4
|
||||
_executionParameters:
|
||||
_holdTime: 0
|
||||
_displayParameters:
|
||||
_messageKey:
|
||||
_interactionAvailableFlows: 2
|
||||
_aiInteractionPoints: []
|
||||
autoInitialize: 1
|
||||
|
@ -426,7 +426,7 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 81e01dd8c1cc3404d805400eba1bb4ae, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_availableInteractions: 5
|
||||
_availableInteractions: 7
|
||||
_nearColliders:
|
||||
- {fileID: 0}
|
||||
- {fileID: 0}
|
||||
|
@ -9,7 +9,7 @@ namespace DDD
|
||||
/// </summary>
|
||||
public interface IAISharedBlackboard
|
||||
{
|
||||
void SetCurrentInteractionTarget(GameObject targetGameObject);
|
||||
GameObject GetCurrentInteractionTarget();
|
||||
void SetBlackboardGameObject(string key, GameObject inGameObject);
|
||||
GameObject GetBlackboardGameObject(string key);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ public enum InteractionType : uint
|
||||
None = 0u,
|
||||
RestaurantManagement = 1u << 0,
|
||||
RestaurantOrder = 1u << 1,
|
||||
RestaurantMeal = 1u << 2,
|
||||
RestaurantCook = 1u << 3,
|
||||
All = 0xFFFFFFFFu
|
||||
}
|
||||
|
@ -12,11 +12,7 @@ public class LookAtInteractionTarget : Action
|
||||
{
|
||||
[Header("Target Settings")]
|
||||
[Tooltip("InteractionPoints를 사용해 가장 적절한 지점을 바라봄")]
|
||||
[SerializeField] private bool useInteractionPoints = true;
|
||||
|
||||
[Header("Update Settings")]
|
||||
[Tooltip("프레임마다 갱신하여 지속적으로 바라볼지 (Running 반환) 여부. 비활성화 시 1회만 시도하고 성공 처리")]
|
||||
[SerializeField] private bool continuousUpdate = true;
|
||||
[SerializeField] private bool _useInteractionPoints = true;
|
||||
|
||||
// Visual 전용 컴포넌트(나중 구현)를 위한 최소 인터페이스
|
||||
// 실제 구현은 Spine/애니메이션 제어 컴포넌트에서 이 인터페이스를 구현하세요.
|
||||
@ -30,84 +26,63 @@ public interface ILookAtVisual
|
||||
void EndLookAt();
|
||||
}
|
||||
|
||||
private ILookAtVisual visual;
|
||||
private GameObject cachedTarget;
|
||||
private bool isLooking;
|
||||
private Vector3 currentLookPosition;
|
||||
private ILookAtVisual _visual;
|
||||
private GameObject _cachedTarget;
|
||||
private bool _isLooking;
|
||||
private Vector3 _currentLookPosition;
|
||||
|
||||
public override void OnStart()
|
||||
{
|
||||
visual = gameObject.GetComponentInParent<ILookAtVisual>();
|
||||
cachedTarget = null;
|
||||
isLooking = false;
|
||||
_visual = gameObject.GetComponentInParent<ILookAtVisual>();
|
||||
_isLooking = false;
|
||||
|
||||
var blackboard = gameObject.GetComponent<IAISharedBlackboard>();
|
||||
_cachedTarget = blackboard.GetBlackboardGameObject(nameof(RestaurantCustomerBlackboardKey.CurrentInteractionTarget));
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
var target = GetTarget();
|
||||
if (target == null)
|
||||
{
|
||||
if (_cachedTarget == null)
|
||||
{
|
||||
if (isLooking)
|
||||
if (_isLooking)
|
||||
{
|
||||
// 타겟이 사라졌다면 정리
|
||||
visual?.EndLookAt();
|
||||
isLooking = false;
|
||||
_visual?.EndLookAt();
|
||||
_isLooking = false;
|
||||
}
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
|
||||
currentLookPosition = CalculateLookPosition(target);
|
||||
_currentLookPosition = CalculateLookPosition(_cachedTarget);
|
||||
|
||||
if (!isLooking)
|
||||
if (!_isLooking)
|
||||
{
|
||||
visual?.TryBeginLookAt(currentLookPosition);
|
||||
isLooking = true;
|
||||
_visual?.TryBeginLookAt(_currentLookPosition);
|
||||
_isLooking = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
visual?.UpdateLookAt(currentLookPosition);
|
||||
_visual?.UpdateLookAt(_currentLookPosition);
|
||||
}
|
||||
|
||||
// 연속 업데이트면 Running, 아니면 1회만 시도 후 Success 반환
|
||||
return continuousUpdate ? TaskStatus.Running : TaskStatus.Success;
|
||||
|
||||
return TaskStatus.Success;
|
||||
}
|
||||
|
||||
public override void OnEnd()
|
||||
{
|
||||
if (isLooking)
|
||||
if (_isLooking)
|
||||
{
|
||||
visual?.EndLookAt();
|
||||
isLooking = false;
|
||||
_visual?.EndLookAt();
|
||||
_isLooking = false;
|
||||
}
|
||||
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;
|
||||
_cachedTarget = null;
|
||||
}
|
||||
|
||||
private static bool IsValidTarget(GameObject target) => target != null && target;
|
||||
|
||||
private Vector3 CalculateLookPosition(GameObject target)
|
||||
{
|
||||
if (!useInteractionPoints)
|
||||
if (!_useInteractionPoints)
|
||||
return target.transform.position;
|
||||
|
||||
if (target.TryGetComponent<RestaurantInteractionComponent>(out var ric))
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Opsive.BehaviorDesigner.Runtime.Tasks;
|
||||
using Opsive.BehaviorDesigner.Runtime.Tasks.Actions;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DDD.Restaurant
|
||||
@ -19,39 +20,45 @@ public class MoveToInteractionTarget : Action
|
||||
[Tooltip("목적지 재계산 주기(초), 0 이하면 비활성화")]
|
||||
[SerializeField] private float repathInterval = 0.5f;
|
||||
|
||||
[Header("Debug Settings")]
|
||||
[Tooltip("디버그 드로우 활성화")]
|
||||
[SerializeField] private bool enableDebugDraw = true;
|
||||
[Tooltip("디버그 선 색상")]
|
||||
[SerializeField] private Color debugLineColor = Color.red;
|
||||
[Tooltip("타겟 위치 기즈모 색상")]
|
||||
[SerializeField] private Color targetGizmoColor = Color.yellow;
|
||||
|
||||
private IAiMovement _movement;
|
||||
private float _repathTimer;
|
||||
private Vector3 _currentDestination;
|
||||
private bool _isMoving;
|
||||
private GameObject _target;
|
||||
|
||||
public override void OnStart()
|
||||
{
|
||||
_movement = gameObject.GetComponent<IAiMovement>();
|
||||
_repathTimer = 0f;
|
||||
_isMoving = false;
|
||||
|
||||
Debug.Log($"MoveToInteractionTarget - GameObject: {gameObject.name}");
|
||||
|
||||
var blackboard = gameObject.GetComponent<IAISharedBlackboard>();
|
||||
_target = blackboard.GetBlackboardGameObject(nameof(RestaurantCustomerBlackboardKey.CurrentInteractionTarget));
|
||||
}
|
||||
|
||||
public override TaskStatus OnUpdate()
|
||||
{
|
||||
if (_movement == null)
|
||||
return TaskStatus.Failure;
|
||||
|
||||
var target = GetTarget();
|
||||
if (target == null)
|
||||
if (_target == null)
|
||||
{
|
||||
return TaskStatus.Running; // If has no target, stuck in this state
|
||||
return TaskStatus.Failure;
|
||||
}
|
||||
|
||||
Debug.Log(target.name);
|
||||
|
||||
|
||||
if (ShouldUpdateDestination())
|
||||
{
|
||||
_currentDestination = CalculateDestination(target);
|
||||
_currentDestination = CalculateDestination(_target);
|
||||
StartOrUpdateMovement();
|
||||
}
|
||||
|
||||
|
||||
return CheckMovementCompletion();
|
||||
}
|
||||
|
||||
@ -59,14 +66,72 @@ public override void OnEnd()
|
||||
{
|
||||
StopMovement();
|
||||
}
|
||||
|
||||
private GameObject GetTarget()
|
||||
|
||||
protected override void OnDrawGizmos()
|
||||
{
|
||||
// Interactor의 포커스된 타겟 검색
|
||||
var interactor = gameObject.GetComponent<IInteractor>();
|
||||
var focusedInteractable = interactor?.GetFocusedInteractable();
|
||||
if (focusedInteractable != null) return focusedInteractable.GetInteractableGameObject();
|
||||
return null;
|
||||
if (!enableDebugDraw || _target == null) return;
|
||||
|
||||
// 타겟 이름을 자신의 게임오브젝트 위에 표시
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.Handles.Label(transform.position + Vector3.up * 2f,
|
||||
$"Target: {_target.name}");
|
||||
#endif
|
||||
|
||||
// 타겟 위치에 기즈모 그리기
|
||||
Gizmos.color = targetGizmoColor;
|
||||
if (_isMoving && _currentDestination != Vector3.zero)
|
||||
{
|
||||
Gizmos.DrawWireSphere(_currentDestination, 0.5f);
|
||||
}
|
||||
else if (_target != null)
|
||||
{
|
||||
Gizmos.DrawWireSphere(_target.transform.position, 0.5f);
|
||||
}
|
||||
|
||||
// 현재 위치에서 타겟까지 직선 그리기
|
||||
Gizmos.color = debugLineColor;
|
||||
Vector3 targetPos = _isMoving && _currentDestination != Vector3.zero
|
||||
? _currentDestination
|
||||
: (_target != null ? _target.transform.position : Vector3.zero);
|
||||
|
||||
if (targetPos != Vector3.zero)
|
||||
{
|
||||
Gizmos.DrawLine(transform.position, targetPos);
|
||||
}
|
||||
|
||||
// 현재 오브젝트 위치에 작은 기즈모 그리기
|
||||
Gizmos.color = Color.blue;
|
||||
Gizmos.DrawWireCube(transform.position, Vector3.one * 0.3f);
|
||||
}
|
||||
|
||||
protected override void OnDrawGizmosSelected()
|
||||
{
|
||||
if (!enableDebugDraw || _target == null) return;
|
||||
|
||||
// 선택되었을 때 추가 정보 표시
|
||||
#if UNITY_EDITOR
|
||||
Vector3 targetPos = _isMoving && _currentDestination != Vector3.zero
|
||||
? _currentDestination
|
||||
: _target.transform.position;
|
||||
|
||||
float distance = Vector3.Distance(transform.position, targetPos);
|
||||
UnityEditor.Handles.Label(targetPos + Vector3.up * 1f,
|
||||
$"Distance: {distance:F2}m\nStopping: {stoppingDistance:F2}m");
|
||||
|
||||
// InteractionPoints가 있다면 모두 표시
|
||||
if (useInteractionPoints && _target.TryGetComponent<RestaurantInteractionComponent>(out var ric))
|
||||
{
|
||||
var points = ric.GetInteractionPoints();
|
||||
if (points != null && points.Length > 0)
|
||||
{
|
||||
Gizmos.color = Color.cyan;
|
||||
foreach (var point in points)
|
||||
{
|
||||
Gizmos.DrawWireSphere(point, 0.2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private bool ShouldUpdateDestination()
|
||||
|
@ -188,7 +188,7 @@ public void Execute(ref DynamicBuffer<BranchComponent> branchComponents,
|
||||
branchComponents[taskComponent.BranchIndex] = branchComponent;
|
||||
continue;
|
||||
}
|
||||
else if (taskComponent.Status != TaskStatus.Running)
|
||||
if (taskComponent.Status != TaskStatus.Running)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ public class StartRestaurantOrder : Action
|
||||
[SerializeField] private bool _requireCanInteract = true;
|
||||
[Tooltip("성공 시 블랙보드에 현재 인터랙션 대상을 등록합니다")]
|
||||
[SerializeField] private bool _registerOnBlackboard = true;
|
||||
[Tooltip("성공 시 블랙보드에 현재 인터랙션 대상을 등록합니다")]
|
||||
[SerializeField] private bool _UnregisterOnBlackboard = false;
|
||||
|
||||
private IInteractor _interactor;
|
||||
private bool _isGetInteractor;
|
||||
@ -19,6 +21,7 @@ public class StartRestaurantOrder : Action
|
||||
public override void OnStart()
|
||||
{
|
||||
_isGetInteractor = gameObject.TryGetComponent(out _interactor);
|
||||
|
||||
if (!_isGetInteractor)
|
||||
Debug.LogError($"[{GetType().Name}] IInteractor를 찾을 수 없습니다: {gameObject.name}");
|
||||
}
|
||||
@ -43,9 +46,14 @@ public override TaskStatus OnUpdate()
|
||||
|
||||
if (_registerOnBlackboard)
|
||||
{
|
||||
// 하위 호환: 고객 전용 블랙보드 지원
|
||||
var customerBlackboard = gameObject.GetComponent<ICustomerBlackboard>();
|
||||
customerBlackboard?.SetCurrentInteractionTarget(outInteractable.gameObject);
|
||||
var customerBlackboard = gameObject.GetComponent<IAISharedBlackboard>();
|
||||
customerBlackboard?.SetBlackboardGameObject(nameof(RestaurantCustomerBlackboardKey.CurrentInteractionTarget), outInteractable.gameObject);
|
||||
}
|
||||
|
||||
if (_UnregisterOnBlackboard)
|
||||
{
|
||||
var customerBlackboard = gameObject.GetComponent<IAISharedBlackboard>();
|
||||
customerBlackboard?.SetBlackboardGameObject(nameof(RestaurantCustomerBlackboardKey.CurrentInteractionTarget), null);
|
||||
}
|
||||
|
||||
return TaskStatus.Success;
|
||||
|
@ -8,78 +8,42 @@ namespace DDD.Restaurant
|
||||
//차후 제네릭으로 변경 가능성 있음
|
||||
public class WaitForPlayerInteraction : Action
|
||||
{
|
||||
[Tooltip("기다릴 상호작용 타입")]
|
||||
[SerializeField] private RestaurantMealType _targetOrderType = RestaurantMealType.WaitForOrder;
|
||||
|
||||
private IInteractionSubsystemObject<RestaurantMealType> _interactionSubsystem;
|
||||
[SerializeField] private RestaurantOrderType _targetOrderType;
|
||||
private IInteractionSubsystemObject<RestaurantOrderType> _interactionSubsystem;
|
||||
private bool _isGetInteractionSubsystem;
|
||||
|
||||
public override void OnStart()
|
||||
{
|
||||
// 의자가 복합 상태를 가지게 될 경우
|
||||
// GameObject interactionTarget = null;
|
||||
// var shared = gameObject.GetComponentInChildren<IAISharedBlackboard>();
|
||||
// if (shared != null)
|
||||
// {
|
||||
// interactionTarget = shared.GetCurrentInteractionTarget();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // 하위 호환: 고객 전용 블랙보드 지원
|
||||
// var customerBb = gameObject.GetComponentInParent<IRestaurantCustomerBlackboard>();
|
||||
// interactionTarget = customerBb?.GetCurrentInteractionTarget();
|
||||
// }
|
||||
//
|
||||
// if (interactionTarget == null)
|
||||
// {
|
||||
// Debug.LogError($"[{GetType().Name}] interactionTarget을 찾을 수 없습니다: {gameObject.name}");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (!interactionTarget.TryGetComponent<RestaurantInteractionComponent>(out var interactionComponent))
|
||||
// Debug.LogError($"[{interactionTarget.name}] {nameof(interactionComponent)}를 찾을 수 없습니다: {gameObject.name}");
|
||||
// if (interactionComponent is IInteractionSubsystemOwner subsystemOwner)
|
||||
// {
|
||||
// if (!subsystemOwner.TryGetSubsystemObject<RestaurantMealType>(out var subsystem))
|
||||
// {
|
||||
// Debug.LogError($"[{GetType().Name}] {nameof(_targetOrderType)}의 Subsystem을 찾을 수 없습니다: {gameObject.name}");
|
||||
// _isGetInteractionSubsystem = false;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// _isGetInteractionSubsystem = true;
|
||||
// subsystem.SetInteractionSubsystemType(_targetOrderType);
|
||||
//
|
||||
// if (!gameObject.TryGetComponent<IInteractor>(out var interactor))
|
||||
// {
|
||||
// Debug.LogError($"[{GetType().Name}] IInteractor를 찾을 수 없습니다: {gameObject.name}");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// interactor.CanInteractTo(interactionComponent);
|
||||
//
|
||||
// _interactionSubsystem = subsystem;
|
||||
// }
|
||||
GameObject interactionTarget = null;
|
||||
if (!gameObject.TryGetComponent<IAISharedBlackboard>(out var sharedBlackboard)) return;
|
||||
interactionTarget =
|
||||
sharedBlackboard.GetBlackboardGameObject(
|
||||
nameof(RestaurantCustomerBlackboardKey.CurrentInteractionTarget));
|
||||
|
||||
if (!gameObject.TryGetComponent<RestaurantInteractionComponent>(out var interactionComponent))
|
||||
if (interactionTarget == null)
|
||||
{
|
||||
Debug.LogError($"[{GetType().Name}]에서 interactionComponent를 찾을 수 없습니다: {gameObject.name}");
|
||||
Debug.LogError($"[{GetType().Name}] interactionTarget을 찾을 수 없습니다: {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!interactionTarget.TryGetComponent<RestaurantInteractionComponent>(out var interactionComponent))
|
||||
Debug.LogError(
|
||||
$"[{interactionTarget.name}] {nameof(interactionComponent)}를 찾을 수 없습니다: {gameObject.name}");
|
||||
|
||||
if (interactionComponent is not IInteractionSubsystemOwner subsystemOwner)
|
||||
{
|
||||
Debug.LogError($"[{GetType().Name}]에서 {nameof(IInteractionSubsystemOwner)}를 찾을 수 없습니다: {gameObject.name}");
|
||||
Debug.LogError(
|
||||
$"[{GetType().Name}]에서 {nameof(IInteractionSubsystemOwner)}를 찾을 수 없습니다: {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!subsystemOwner.TryGetSubsystemObject(out _interactionSubsystem))
|
||||
{
|
||||
Debug.LogError($"[{GetType().Name}]에서 {nameof(IInteractionSubsystemObject)}를 찾을 수 없습니다: {gameObject.name}");
|
||||
Debug.LogError(
|
||||
$"[{GetType().Name}]에서 {nameof(IInteractionSubsystemObject)}를 찾을 수 없습니다: {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
_interactionSubsystem.SetInteractionSubsystemType(_targetOrderType);
|
||||
|
||||
_isGetInteractionSubsystem = true;
|
||||
}
|
||||
|
||||
@ -91,7 +55,7 @@ public override TaskStatus OnUpdate()
|
||||
if (result == TaskStatus.Success) Debug.Log($"[{GetType().Name}] Success");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private TaskStatus CheckToSubsystemStatus()
|
||||
{
|
||||
return _interactionSubsystem.GetInteractionSubsystemType() == _targetOrderType
|
||||
|
@ -47,8 +47,8 @@ private async Task InitializeAiInternal(CustomerDataEntry inCustomerDataEntry)
|
||||
}
|
||||
|
||||
_behaviorTree.Subgraph = subtree;
|
||||
_blackboardComponent.InitializeWithBehaviorTree(subtree);
|
||||
_blackboardComponent.SetCustomerData(inCustomerDataEntry);
|
||||
_blackboardComponent.InitializeWithBehaviorTree(_behaviorTree);
|
||||
_blackboardComponent.SetCustomerData(inCustomerDataEntry.Id);
|
||||
// TODO : 1. Subtree - Action, Condition
|
||||
// TODO : 2. Blackboard
|
||||
_behaviorTree.StartBehavior();
|
||||
|
@ -5,35 +5,34 @@ namespace DDD
|
||||
{
|
||||
public class CustomerBlackboardComponent : MonoBehaviour, ICustomerBlackboard, IAISharedBlackboard
|
||||
{
|
||||
private Subtree _subtree;
|
||||
private GameObject _currentInteractionTarget;
|
||||
|
||||
public void InitializeWithBehaviorTree(Subtree subtree)
|
||||
// private Subtree _behaviorTree;
|
||||
private BehaviorTree _behaviorTree;
|
||||
|
||||
public void InitializeWithBehaviorTree(BehaviorTree inBehaviorTree)
|
||||
{
|
||||
_subtree = subtree;
|
||||
if (_subtree != null)
|
||||
_behaviorTree = inBehaviorTree;
|
||||
if (_behaviorTree)
|
||||
{
|
||||
_subtree.SetVariableValue(nameof(RestaurantCustomerBlackboardKey.SelfGameObject), gameObject);
|
||||
_behaviorTree.SetVariableValue(nameof(RestaurantCustomerBlackboardKey.SelfGameObject), gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCustomerData(CustomerDataEntry inCustomerDataEntry)
|
||||
public void SetCustomerData(string inCustomerDataId)
|
||||
{
|
||||
if (_subtree == null) return;
|
||||
_subtree.SetVariableValue(nameof(RestaurantCustomerBlackboardKey.CustomerData), inCustomerDataEntry);
|
||||
if (!_behaviorTree) return;
|
||||
_behaviorTree.SetVariableValue(nameof(RestaurantCustomerBlackboardKey.CustomerDataId), inCustomerDataId);
|
||||
}
|
||||
|
||||
public void SetBlackboardGameObject(string key, GameObject inGameObject)
|
||||
{
|
||||
if (_behaviorTree == null) return;
|
||||
_behaviorTree.SetVariableValue(key, inGameObject);
|
||||
}
|
||||
|
||||
public void SetCurrentInteractionTarget(GameObject targetGameObject)
|
||||
public GameObject GetBlackboardGameObject(string key)
|
||||
{
|
||||
_currentInteractionTarget = targetGameObject;
|
||||
if (_subtree == null) return;
|
||||
_subtree.SetVariableValue(nameof(RestaurantCustomerBlackboardKey.CurrentInteractionTarget), targetGameObject);
|
||||
}
|
||||
|
||||
public GameObject GetCurrentInteractionTarget()
|
||||
{
|
||||
// 캐시 우선 반환. 필요 시 Subtree에서 직접 조회하도록 확장 가능.
|
||||
return _currentInteractionTarget;
|
||||
if (_behaviorTree == null) return null;
|
||||
return _behaviorTree.GetVariable<GameObject>(key)?.Value;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
@ -99,5 +100,27 @@ public bool CanInteractTo(IInteractable interactable, ScriptableObject payloadSo
|
||||
if (TryGetSolverFor(interactable, out var solver) == false) return false;
|
||||
return solver.CanExecuteInteraction(this, interactable, payloadSo);
|
||||
}
|
||||
|
||||
public virtual void InitializeSolvers()
|
||||
{
|
||||
var typesToSolver = RestaurantInteractionEventSolvers.TypeToSolver;
|
||||
InitializeInteractionSolvers(typesToSolver);
|
||||
}
|
||||
|
||||
protected void InitializeInteractionSolvers(Dictionary<InteractionType, Type> typesToSolver)
|
||||
{
|
||||
foreach (var typeToSolver in typesToSolver)
|
||||
{
|
||||
var flag = typeToSolver.Key;
|
||||
if (flag == InteractionType.None) continue;
|
||||
|
||||
if ((AvailableInteractions & flag) == 0) continue;
|
||||
|
||||
if (!TryGetComponent(typeToSolver.Value, out _))
|
||||
{
|
||||
gameObject.AddComponent(typeToSolver.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,19 +13,8 @@ public class RestaurantCharacter : MonoBehaviour, IGameCharacter, IInteractor
|
||||
protected virtual void Awake()
|
||||
{
|
||||
_interactionComponent = GetComponent<CharacterInteraction>();
|
||||
_interactionComponent.InitializeSolvers();
|
||||
_spineController = GetComponent<SpineController>();
|
||||
foreach (var typeToSolver in RestaurantInteractionEventSolvers.TypeToSolver)
|
||||
{
|
||||
var flag = typeToSolver.Key;
|
||||
if (flag == InteractionType.None) continue;
|
||||
|
||||
if ((_interactionComponent.AvailableInteractions & flag) == 0) continue;
|
||||
|
||||
if (!TryGetComponent(typeToSolver.Value, out _))
|
||||
{
|
||||
gameObject.AddComponent(typeToSolver.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Start()
|
||||
|
@ -5,14 +5,12 @@ namespace DDD
|
||||
public enum RestaurantCustomerBlackboardKey
|
||||
{
|
||||
SelfGameObject,
|
||||
CustomerData,
|
||||
CustomerDataId,
|
||||
CurrentInteractionTarget,
|
||||
}
|
||||
|
||||
public interface ICustomerBlackboard
|
||||
{
|
||||
void SetCustomerData(CustomerDataEntry inCustomerDataEntry);
|
||||
void SetCurrentInteractionTarget(GameObject targetGameObject);
|
||||
GameObject GetCurrentInteractionTarget();
|
||||
void SetCustomerData(string inCustomerDataId);
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
@ -35,6 +37,18 @@ private Task Initialize()
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public override void InitializeSolvers()
|
||||
{
|
||||
var typesToSolver = RestaurantInteractionEventSolvers.TypeToSolver;
|
||||
var playerSolver = RestaurantInteractionEventSolvers.TypeToPlayerSolver;
|
||||
foreach(var pair in playerSolver)
|
||||
{
|
||||
typesToSolver.Remove(pair.Key);
|
||||
}
|
||||
InitializeInteractionSolvers(typesToSolver);
|
||||
InitializeInteractionSolvers(playerSolver);
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DDD
|
||||
@ -23,11 +24,13 @@ public RestaurantMealType GetInteractionSubsystemType()
|
||||
|
||||
public void SetInteractionSubsystemType(RestaurantMealType inValue)
|
||||
{
|
||||
Debug.Log($"[{gameObject.GetHashCode()}, {GetType().Name}] SetInteractionSubsystemType {inValue.ToString()}");
|
||||
_currentRestaurantMealType = inValue;
|
||||
}
|
||||
|
||||
public void InitializeSubsystem()
|
||||
{
|
||||
Debug.Log($"[{gameObject.GetHashCode()}, {GetType().Name}] InitializeSubsystem");
|
||||
_currentRestaurantMealType = RestaurantMealType.None;
|
||||
}
|
||||
|
||||
@ -38,6 +41,7 @@ public bool CanInteract()
|
||||
|
||||
public bool OnInteracted(IInteractor interactor, ScriptableObject payloadSo = null)
|
||||
{
|
||||
Debug.Log($"[{gameObject.GetHashCode()}, {GetType().Name}] OnInteracted");
|
||||
var prev = _currentRestaurantMealType;
|
||||
_currentRestaurantMealType = GetNextState(prev);
|
||||
return true;
|
||||
|
@ -13,7 +13,6 @@ public static class RestaurantInteractionSubsystems
|
||||
{
|
||||
{InteractionType.RestaurantOrder, typeof(InteractionSubsystem_Order)},
|
||||
{InteractionType.RestaurantManagement, typeof(InteractionSubsystem_Management)},
|
||||
{InteractionType.RestaurantMeal, typeof(InteractionSubsystem_Meal)}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -10,9 +10,12 @@ public static class RestaurantInteractionEventSolvers
|
||||
{
|
||||
{InteractionType.RestaurantManagement, typeof(RestaurantManagementSolver)},
|
||||
{InteractionType.RestaurantOrder, typeof(RestaurantOrderSolver)},
|
||||
{InteractionType.RestaurantMeal, typeof(RestaurantMealSolver)},
|
||||
{InteractionType.RestaurantCook, typeof(RestaurantCookSolver)}
|
||||
};
|
||||
public static Dictionary<InteractionType, Type> TypeToPlayerSolver = new()
|
||||
{
|
||||
{InteractionType.RestaurantOrder, typeof(RestaurantOrderPlayerSolver)},
|
||||
};
|
||||
}
|
||||
|
||||
public class RestaurantInteractionEvent : IEvent
|
||||
|
@ -10,9 +10,19 @@ public class RestaurantOrderSolver : RestaurantSubsystemSolver<RestaurantOrderTy
|
||||
{
|
||||
{ RestaurantOrderType.Wait, typeof(RestaurantOrderSolver_Wait) },
|
||||
{ RestaurantOrderType.Reserved, typeof(RestaurantOrderSolver_Reserved) },
|
||||
{ RestaurantOrderType.Busy, typeof(RestaurantOrderSolver_Busy) },
|
||||
};
|
||||
protected override Dictionary<RestaurantOrderType, Type> GetSubsystemSolverTypeMappings()
|
||||
{
|
||||
return _typeToOrderSolver;
|
||||
}
|
||||
}
|
||||
public class RestaurantOrderPlayerSolver : RestaurantSubsystemSolver<RestaurantOrderType>
|
||||
{
|
||||
private Dictionary<RestaurantOrderType, Type> _typeToOrderSolver = new()
|
||||
{
|
||||
{ RestaurantOrderType.Order, typeof(RestaurantOrderSolver_Order) },
|
||||
{ RestaurantOrderType.Serve, typeof(RestaurantOrderSolver_Serve) },
|
||||
{ RestaurantOrderType.Busy, typeof(RestaurantOrderSolver_Busy) },
|
||||
{ RestaurantOrderType.Dirty, typeof(RestaurantOrderSolver_Dirty) }
|
||||
};
|
||||
protected override Dictionary<RestaurantOrderType, Type> GetSubsystemSolverTypeMappings()
|
||||
|
@ -0,0 +1,9 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace DDD.Restaurant
|
||||
{
|
||||
public class PropUiDisplayComponent : MonoBehaviour
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37e749c7ec5440d587f83c715f29ca8f
|
||||
timeCreated: 1756353198
|
Loading…
Reference in New Issue
Block a user