[Unity6] 2D Behavior Tree 2( Enumeration -Idle, Patrol, Wander )
์นดํ ๊ณ ๋ฆฌ: Go Unity
์ด๊ฑฐํ์ ์ด์ฉํ ํ๋ ๊ด๋ฆฌ
1.ย BlackBoard -> (+) -> Enumeration
ย
2.ย Enumeration ์์ฑ (currentState) (Idle, Patrol, Wander, Chase, Attack)
ย
ย
3.ย Switch ๋
ธ๋ ์ถ๊ฐ -> currentState (์ด๊ฑฐํ์ด ์์๋
ธ๋๋ก ์๋์์ฑ)
ย
ย
4.ย Try in order, Abort(ํ๊ฒ์ด ์์ผ๋ฉด ์ค๋จ), Random, Set Variable Value ๋
ธ๋๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ ๋ณํ
ย - ๊ฐ ๋
ธ๋ Node์ ์ค๋ช
Idle
Target์ด ๋ฒ์์ ์์ผ๋ฉด 1~3์ด ๋๊ธฐ ํ Patrol, Wander ์ํ๋ก, ์๋ค๋ฉด Chase
ย
Patrol
Target์ด ์๋ค๋ฉด ์์ฐฐ (10์ด๊ฐ ์ง๋๋ฉด ๋๊ธฐ ์ํ๋ก ๋ณ๊ฒฝ), ์๋ค๋ฉด Chase
ย
Wander
Target์ด ์๋ค๋ฉด ์์์ ์์น๋ก ๋ฐฐํ, ์๋ค๋ฉด Chase
ย
Node
โ Switch : Enumeration๋ฅผ ์ ํํ๋ฉด ์ด๊ฑฐํ์ด ์์ ๋
ธ๋๋ก ์๋ ์์ฑ๋ฉ๋๋ค.
ย
โ Try in order : ์ฑ๊ณตํ ๋๊น์ง ๋ถ๊ธฐ๋ฅผ ์์๋๋ก ์คํ(์ข->์ฐ)
ย
โ Abort : ์ง์ ๋ ์กฐ๊ฑด์ด ์ฐธ์ด๋ฉด ํด๋น ๋ถ๊ธฐ ์ค๋จ
ย ย Inspector ๋ทฐ์์ ์ค์ ๊ฐ๋ฅ (๋ณ์ซ๊ฐ ๋น๊ต)
ย
ย
โ Random : ์์์ ์์ ๋
ธ๋๋ฅผ ์ ํํด์ ์คํ
ย
โ Set Variable Value : Blackboard์ ์๋ ๋ณ์ซ๊ฐ์ ์ค์ ํ๋ ๋
ธ๋
ย
โ Create New Action : ์๋ก์ด ํ๋ ๋
ธ๋ ๊ตฌํ
ย - ์ํ๋ ๋
ธ๋๊ฐ ์์ผ๋ฉด ์ง์ ์๋ก์ด ๋
ธ๋๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
ย - ๋จ์ด ๋จ์๋ก ๋ฐ์ด์ฐ๊ธฐ ํ๋ฉฐ ๋จ์ด๋ง๋ค ๋ณ์, ์ผ๋ฐ ํ
์คํธ ํ์์ผ๋ก ์ค์ ๊ฐ๋ฅํฉ๋๋ค.
์ด๊ฒ์ ๊ฒ ๋ฉ๋ชจ
BlackboardEnum
EnemyState(BlackboardEnum)
์ผ๋ฐ์ ์ธ Enum์ BlackboardEnum ์ดํธ๋ฆฌ๋ทฐํธ๋ฅผ ์ด์ฉํด ๋ฏธ๋ฆฌ ์์ฑํด์ BlackBoard์์ ๋ฐ๋ก ์์ฑ ๊ฐ๋ฅํ๋ค.
ย
EnemyState
using Unity.Behavior;
[BlackboardEnum]
public enum EnemyState
{
Idle,
Patrol,
Wandor,
Chase,
Attack
}
Create New Action Node
๋ชจ๋ ๋
ธ๋๋ โญ NodeDescription ์ดํธ๋ฆฌ๋ทฐํธ์ ๋
ธ๋์ ์ด๋ฆ, Story, Category, id ์ ๋ณด๊ฐ ์ถ๋ ฅ๋๋ค.
โญ SerializeReference๋ฅผ ์ฌ์ฉํ๊ณ , BlackboardVariable<>๋ก ์ ์ธํ๋ฉด Behavior Graph์ Intpector์ ๋ณ์ ๋
ธ์ถ์ด ๊ฐ๋ฅํฉ๋๋ค.
OnStart(), OnUdpdate(), OnEnd()
Behavior Graph์์ ์์ฑ
Add - Action - Create New Action
Name : Wander๋ก ํ๋ฉด WanderAction.cs ์คํฌ๋ฆฝํธ๊ฐ ์์ฑ.
ย
ย
Story : ๋จ์ด ๋จ์๋ก ๋์ด์ฐ๊ธฐ ํ๋ฉฐ ๋จ์ด๋ง๋ค ๋ณ์, ์ผ๋ฐ ํ
์คํธ ํ์์ผ๋ก ์ค์ ๊ฐ๋ฅํฉ๋๋ค.
ย
EnemyState
using System;
using Unity.Behavior;
using UnityEngine;
using Action = Unity.Behavior.Action;
using Unity.Properties;
using UnityEngine.AI;
//โญ NodeDescription ์ดํธ๋ฆฌ๋ทฐํธ์ ๋
ธ๋์ ์ด๋ฆ, Story, Category, id ์ ๋ณด๊ฐ ์ถ๋ ฅ๋๋ค.
[Serializable, GeneratePropertyBag]
[NodeDescription(name: "Wander", story: "[Self] Navigate To WanderPosition", category: "Action", id: "7ca2472cbc539bcb9415b66682de271e")]
public partial class WanderAction : Action
{
//โญ SerializeReference๋ฅผ ์ฌ์ฉํ๊ณ , BlackboardVariable<>๋ก ์ ์ธํ๋ฉด Behavior Graph์ Intpector์ ๋ณ์ ๋
ธ์ถ์ด ๊ฐ๋ฅํฉ๋๋ค.
[SerializeReference] public BlackboardVariable<GameObject> Self;
private NavMeshAgent agent;
private Vector3 wanderPosition;
private float currentWanderTime = 0f;
private float maxWanderTime = 5f;
protected override Status OnStart()
{
int jitterMin = 0;
int jitterMax = 360;
float wanderRadius = UnityEngine.Random.Range(2.5f, 6f);
int wanderJitter = UnityEngine.Random.Range(jitterMin, jitterMax);
// ๋ชฉํ ์์น = ์์ (Self)์ ์์น + ๊ฐ๋(wanderJitter)์ ํด๋นํ๋ ๋ฐ์ง๋ฆ(wanderRadius) ํฌ๊ธฐ์ ์์ ๋๋ ์์น
wanderPosition = Self.Value.transform.position + Utils.GetPositionFromAngle(wanderRadius, wanderJitter);
agent = Self.Value.GetComponent<NavMeshAgent>();
agent.SetDestination(wanderPosition);
currentWanderTime = Time.time;
return Status.Running;
}
protected override Status OnUpdate()
{
if ((wanderPosition - Self.Value.transform.position).sqrMagnitude < 0.1f
|| Time.time - currentWanderTime > maxWanderTime)
{
return Status.Success;
}
return Status.Running;
}
protected override void OnEnd()
{
}
}
์ก๋ด, ์ผ๊ธฐ?
์ด๊ฑฐํ์ ์ด์ฉํ ํ๋ ๊ด๋ฆฌ
๋๊ธ๋จ๊ธฐ๊ธฐ