W298.dev
ProjectsPostsAbout Me
youtube
Pages
ProjectsPostsAbout Me
Posts
TAGS
All
RL-Obstacle-Avoid
RL-Competitive
Robot-Escape
Assembly Definition
ML-Agent
RL-Obstacle-Avoid
RL-Competitive
Unity
RL-Obstacle-Avoid
RL-Competitive
Robot-Escape
Assembly Definition
SERIES
RL-Obstacle-Avoid
RL-Competitive
Robot-Escape

AI Behavior Tree (1)

AI 프로그래밍은 Behavior Tree 를 사용할 것이다.
원래 FSM 으로도 구현했으나, 점점 스파게티 코드가 되어가는 것을 보고... Behavior Tree 로 갈아타기로 했다.
앞으로 더 추가될 예정이지만 일단 간단하게 FlowChart 를 그려 보았다.
/imgs/post_imgs/robot_escape_10/1.png

Base 구현

Node

1namespace BT
2{
3    public enum NodeState
4    {
5        RUNNING,
6        SUCCESS,
7        FAILURE
8    }
9
10    public class Node
11    {
12        public NodeState state;
13
14        protected BehaviorTree bt;
15        protected List<Node> children;
16
17        public Node()
18        {
19            this.bt = null;
20            this.children = new List<Node>();
21        }
22
23        public Node(BehaviorTree bt)
24        {
25            this.bt = bt;
26            this.children = new List<Node>();
27        }
28
29        public Node(List<Node> children)
30        {
31            this.bt = null;
32            this.children = children;
33        }
34
35        public virtual NodeState Evaluate() => NodeState.FAILURE;
36    }
37}
38
BehaviorTree 레퍼런스를 가지고 있는 이유는 Node 간 공유하는 변수에 접근하기 위해서이다.

Selector

1namespace BT
2{
3    public class Selector : Node
4    {
5        public Selector() : base() {}
6        public Selector(List<Node> children) : base(children) {}
7
8        public override NodeState Evaluate()
9        {
10
11            foreach (Node child in children)
12            {
13                switch (child.Evaluate())
14                {
15                    case NodeState.RUNNING:
16                        state = NodeState.RUNNING;
17                        return state;
18                    case NodeState.SUCCESS:
19                        state = NodeState.SUCCESS;
20                        return state;
21                    case NodeState.FAILURE:
22                        continue;
23                }
24            }
25
26            state = NodeState.FAILURE;
27            return state;
28        }
29    }
30}
31

Sequence

1namespace BT
2{
3    public class Sequence : Node
4    {
5        public Sequence() : base() {}
6        public Sequence(List<Node> children) : base(children) {}
7
8        public override NodeState Evaluate()
9        {
10            bool anyRunning = false;
11
12            foreach (Node child in children)
13            {
14                switch (child.Evaluate())
15                {
16                    case NodeState.RUNNING:
17                        anyRunning = true;
18                        continue;
19                    case NodeState.SUCCESS:
20                        continue;
21                    case NodeState.FAILURE:
22                        state = NodeState.FAILURE;
23                        return state;
24                }
25            }
26
27            state = anyRunning ? NodeState.RUNNING : NodeState.SUCCESS;
28            return state;
29        }
30    }
31}
32

EnemyRobotBT

위에서 정의한 BehaviorTree 클래스를 상속받아 사용한다.
1public class EnemyRobotBT : BehaviorTree
2{
3    [NonSerialized]
4    public EnemyRobotAI ai;
5
6    private void Awake()
7    {
8        ai = GetComponent<EnemyRobotAI>();
9    }
10
11    protected override Node CreateTree()
12    {
13        Node root = new Sequence();
14        return root;
15    }
16
17    public void OnDeath()
18    {
19        active = false;
20    }
21}
22
앞으로 만들 Task 와 Check 노드들이 전부 root 노드에 Child 로 들어가면 된다.