DOTY
Behavior Tree 본문
AI의 트리
Node : Success, Failure, Running에 따라서 노드 상태 결정
Action : 어떤 동작
Sequence : 일의 순서. 만약 자식이 하나라도 실패하면 실패로 반환
Selector : 일의 선택. 만약 어떤 자식이 하나라도 성공하면 성공으로 반환
네 가지를 구현해보자.
구현할 내용들
1. Node - Interface
NodeState를 enum 형태로 선언
Node에서 필요한 것은 진행 : Running, 성공 : Success, 실패 : Failure 가 필요하다.
Node클래스는 세가지의 노드들에 대해서 각자 평가하는 함수 - Evaluate()가 존재.
이 함수는 Tree형태로 되어있고 각 원하는 동작에 대한 Behavior Tree를 설계할 때 이 Tree의 Root로 정해준다.
2. Action - Node Interface
NodeState를 반환하는 함수를 매개변수로 하고 그 함수의 결과에 따라서 코드가 진행된다.
Sequence, Selector 내부에서 Action Node 의 결과에 따라 진행이 결정된다.
public NodeState Evaluate()
{
return onUpdate?. Invoke() ?? NodeState.Failure;
}
3. Sequence
Sequence와 연결된 모든 Node들을 하나씩 진행한다. List에 여러 Node들을 넣고 매개변수로 넘겨 NodeState를 확인. NodeState가 하나라도 Failure이 있다면 더 이상 진행하지 않고 반환.
public NodeState Evaluate()
{
if(childs == null || childs.Count == 0)
{
return NodeState.Failure;
}
foreach (INode child in childs)
{
switch(child.Evaluate())
{
case NodeState.Failure:
return NodeState.Failure;
case NodeState.Success:
continue;
case NodeState.Running:
return NodeState.Running;
}
}
return NodeState.Success;
}
4. Selector
Selector와 연결된 모든 Node들을 한번씩 확인한다. List에 여러 Node들을 넣고 매개변수로 넘겨 NodeState를 확인.
NodeState를 확인하고 Success가 있다면 더 이상 진행하지 않고 그 순간 해당 Action을 진행 한 후 반환.
public NodeState Evaluate()
{
if(childs == null)
{
return NodeState.Failure;
}
// If Success return Success. If Fail Keep Going.
foreach (INode child in childs)
{
switch(child.Evaluate())
{
case NodeState.Success:
return NodeState.Success;
case NodeState.Running:
return NodeState.Running;
}
}
return NodeState.Failure;
}
플레이어를 따라다니는 오브젝트 구현
[SerializeField] GameObject player;
[SerializeField] float moveSpeed;
[SerializeField] float nearBoundary;
BehaviorTreeRunner btRunner;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
btRunner = new BehaviorTreeRunner(SettingFollowBT());
}
// Update is called once per frame
void Update()
{
btRunner.Operate();
}
INode SettingFollowBT()
{
INode root = new SelectorNode(
new List<INode>()
{
new SequenceNode(
new List<INode>()
{
new ActionNode(IsNearPlayer),
new ActionNode(Wait)
}
),
new ActionNode(FollowPlayer)
}
);
return root;
}
NodeState IsNearPlayer()
{
if(Vector3.Magnitude(player.transform.position - transform.position) < nearBoundary)
{
return NodeState.Success;
}
return NodeState.Failure;
}
NodeState Wait()
{
return NodeState.Success;
}
NodeState FollowPlayer()
{
if(Vector3.Magnitude(player.transform.position - transform.position) < nearBoundary)
{
return NodeState.Success;
}
transform.position = Vector3.MoveTowards(transform.position , player.transform.position, Time.deltaTime * moveSpeed);
return NodeState.Running;
}
'Unity' 카테고리의 다른 글
ECS (Entity Component System) - Setup (1) | 2024.11.21 |
---|---|
ML Agents 준비 (3) | 2024.11.14 |
HpProgressBar 체력에 따라 색 바꾸기 (0) | 2024.10.14 |
[Unity] err1. object reference not set to an instance of an object (0) | 2022.09.24 |
[Unity] 6. Scene 변경 ( + DontDestroyOnLoad ) (0) | 2022.09.07 |