오늘은 개인 일정이 있어 거의 진행을 못했다 ㅠ
어제 작성해 둔 코드 로직 한번 더 검토하고 다시 나가봐야한다...
조건 분기가 많아 Condition을 주로 사용하게 될 줄 알았는데 직접 구현해보니 Sequence와 Selector만 사용하게 되었다.
이부분은 테스트 진행하면서 제대로 로직상 상태가 변경되어야 하는 부분 있으면 트리 구조 스크립트만 수정하면 되므로 차차 다듬어나가면 될 것 같다.
기본 노드는 튜터님이 참고하라고 공유해주신 블로그 자료를 베이스로 작성되었다.
Condition과 Action은 지금 당장 사용하지는 않는데, 혹시 나중에 사용될 수도 있어서 만드는 김에 미리 작성했다.
INode
public enum NodeState { Success, Failure, Running }
public interface INode
{
// 현재 노드 어떤 상태인지 반환
NodeState Evaluate();
}
SelectorNode
using System.Collections.Generic;
// 자식 노드에서 처음으로 Success나 Running 상태 노드 발생하면
// 그 노드까지 진행하고 멈추는 노드
public class SelectorNode : INode
{
private List<INode> _children = new List<INode>();
public void AddChild(INode child)
{
_children.Add(child);
}
public NodeState Evaluate()
{
if (_children == null) return NodeState.Failure;
foreach (INode child in _children)
{
switch (child.Evaluate())
{
case NodeState.Success:
return NodeState.Success;
case NodeState.Running:
return NodeState.Running;
// 자식 상태가 Failure 면 다음 자식으로 이동
}
}
return NodeState.Failure;
}
}
SequenceNode
using System.Collections.Generic;
// 자식 노드를 순서대로 진행하면서 Failure 상태가 나올 때까지 진행하는 노드
public class SequenceNode : INode
{
private readonly List<INode> _children = new List<INode>();
public void AddChild(INode child)
{
_children.Add(child);
}
public NodeState Evaluate()
{
if (_children == null || _children.Count == 0)
return NodeState.Failure;
foreach (INode child in _children)
{
switch (child.Evaluate())
{
case NodeState.Success:
continue; // 자식 상태 Success 면 다음 자식으로 이동
case NodeState.Running:
return NodeState.Running;
case NodeState.Failure:
return NodeState.Failure;
}
}
return NodeState.Failure;
}
}
ConditionNode
using System;
// 조건문 확인 후 true면 하위 노드 실행, false면 failure 반환
public class ConditionNode : INode
{
private INode _node;
private Func<bool> _condition;
public ConditionNode(Func<bool> condition, INode node)
{
_condition = condition;
_node = node;
}
public NodeState Evaluate()
{
bool result = _condition.Invoke();
return result ? _node.Evaluate() : NodeState.Failure;
}
}
ActionNode
using System;
// 실제로 행위를 하는 노드
public class ActionNode : INode
{
private Func<NodeState> _onUpdate;
public ActionNode(Func<NodeState> onUpdate)
{
_onUpdate = onUpdate;
}
public NodeState Evaluate() => _onUpdate?.Invoke() ?? NodeState.Failure;
}
BehaviorTree
public class BehaviorTree
{
private readonly INode root;
public BehaviorTree(INode rootNode)
{
root = rootNode;
}
public void Update()
{
root.Evaluate();
}
}
참고자료:
https://unity-programming-study.tistory.com/14
https://leekangw.github.io/posts/91/
https://husk321.tistory.com/412
https://learn.unity.com/tutorial/2d-game-kit-advanced-topics#64883466edbc2a498872116c
https://www.gamedeveloper.com/programming/behavior-trees-for-ai-how-they-work
https://lifeisforu.tistory.com/327
https://maplestoryworlds-creators.nexon.com/ko/docs?postId=562
'내일배움캠프 > TIL' 카테고리의 다른 글
| [내배캠][Unity6기][TIL] 11.15 최종 프로젝트 시작 전, 알아두면 좋을 것들 특강(스탠다드) (2) (0) | 2024.12.03 |
|---|---|
| [내배캠][Unity6기][TIL] UGS 데이터 로드 (0) | 2024.12.02 |
| [내배캠][Unity6기][TIL] Behavior Tree 구조 설계 (1) (0) | 2024.11.29 |
| [내배캠][Unity6기][TIL] 캐릭터 행동 구현 설계 (0) | 2024.11.28 |
| [내배캠][Unity6기][TIL] ObjectPool (0) | 2024.11.27 |