[Unity6] 2D Behavior Tree 2( Enumeration -Idle, Patrol, Wander )

์—…๋ฐ์ดํŠธ:

์นดํ…Œ๊ณ ๋ฆฌ:

ํƒœ๊ทธ: ,




์—ด๊ฑฐํ˜•์„ ์ด์šฉํ•œ ํ–‰๋™ ๊ด€๋ฆฌ

1.ย BlackBoard -> (+) -> Enumeration
ย 
2.ย Enumeration ์ƒ์„ฑ (currentState) (Idle, Patrol, Wander, Chase, Attack)
ย Image
ย 
3.ย Switch ๋…ธ๋“œ ์ถ”๊ฐ€ -> currentState (์—ด๊ฑฐํ˜•์ด ์ž์‹๋…ธ๋“œ๋กœ ์ž๋™์ƒ์„ฑ)
ย Image
ย 
4.ย Try in order, Abort(ํƒ€๊ฒŸ์ด ์žˆ์œผ๋ฉด ์ค‘๋‹จ), Random, Set Variable Value ๋…ธ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ–‰๋™ ๋ณ€ํ™˜
ย - ๊ฐ ๋…ธ๋“œ Node์— ์„ค๋ช…




Idle

Target์ด ๋ฒ”์œ„์— ์—†์œผ๋ฉด 1~3์ดˆ ๋Œ€๊ธฐ ํ›„ Patrol, Wander ์ƒํƒœ๋กœ, ์žˆ๋‹ค๋ฉด Chase
ย Image

Patrol

Target์ด ์—†๋‹ค๋ฉด ์ˆœ์ฐฐ (10์ดˆ๊ฐ€ ์ง€๋‚˜๋ฉด ๋Œ€๊ธฐ ์ƒํƒœ๋กœ ๋ณ€๊ฒฝ), ์žˆ๋‹ค๋ฉด Chase
ย Image

Wander

Target์ด ์—†๋‹ค๋ฉด ์ž„์˜์˜ ์œ„์น˜๋กœ ๋ฐฐํšŒ, ์žˆ๋‹ค๋ฉด Chase
ย Image




Node

โœ” Switch : Enumeration๋ฅผ ์„ ํƒํ•˜๋ฉด ์—ด๊ฑฐํ˜•์ด ์ž์‹ ๋…ธ๋“œ๋กœ ์ž๋™ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
ย 
โœ” Try in order : ์„ฑ๊ณตํ•  ๋•Œ๊นŒ์ง€ ๋ถ„๊ธฐ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰(์ขŒ->์šฐ)
ย 
โœ” Abort : ์ง€์ •๋œ ์กฐ๊ฑด์ด ์ฐธ์ด๋ฉด ํ•ด๋‹น ๋ถ„๊ธฐ ์ค‘๋‹จ
ย ย  Inspector ๋ทฐ์—์„œ ์„ค์ • ๊ฐ€๋Šฅ (๋ณ€์ˆซ๊ฐ’ ๋น„๊ต)
ย Image
ย 
โœ” Random : ์ž„์˜์˜ ์ž์‹ ๋…ธ๋“œ๋ฅผ ์„ ํƒํ•ด์„œ ์‹คํ–‰
ย 
โœ” Set Variable Value : Blackboard์— ์žˆ๋Š” ๋ณ€์ˆซ๊ฐ’์„ ์„ค์ •ํ•˜๋Š” ๋…ธ๋“œ
ย 
โœ” Create New Action : ์ƒˆ๋กœ์šด ํ–‰๋™ ๋…ธ๋“œ ๊ตฌํ˜„
ย - ์›ํ•˜๋Š” ๋…ธ๋“œ๊ฐ€ ์—†์œผ๋ฉด ์ง์ ‘ ์ƒˆ๋กœ์šด ๋…ธ๋“œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย - ๋‹จ์–ด ๋‹จ์œ„๋กœ ๋›ฐ์–ด์“ฐ๊ธฐ ํ•˜๋ฉฐ ๋‹จ์–ด๋งˆ๋‹ค ๋ณ€์ˆ˜, ์ผ๋ฐ˜ ํ…์ŠคํŠธ ํ˜•์‹์œผ๋กœ ์„ค์ • ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.




์ด๊ฒƒ์ €๊ฒƒ ๋ฉ”๋ชจ

BlackboardEnum

EnemyState(BlackboardEnum)
์ผ๋ฐ˜์ ์ธ Enum์— BlackboardEnum ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์ด์šฉํ•ด ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด์„œ BlackBoard์—์„œ ๋ฐ”๋กœ ์ƒ์„ฑ ๊ฐ€๋Šฅํ•˜๋‹ค.
ย Image

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 ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ƒ์„ฑ.
ย Image
ย 
Story : ๋‹จ์–ด ๋‹จ์œ„๋กœ ๋„์–ด์“ฐ๊ธฐ ํ•˜๋ฉฐ ๋‹จ์–ด๋งˆ๋‹ค ๋ณ€์ˆ˜, ์ผ๋ฐ˜ ํ…์ŠคํŠธ ํ˜•์‹์œผ๋กœ ์„ค์ • ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
ย Image

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()
    {
    }
}





์žก๋‹ด, ์ผ๊ธฐ?

์—ด๊ฑฐํ˜•์„ ์ด์šฉํ•œ ํ–‰๋™ ๊ด€๋ฆฌ




๐Ÿ“”

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ