#14 Robot! Escape! - AI Behavior Tree (4)

w298·2022년 11월 8일
0

DEVLOG - Robot! Escape!

목록 보기
14/21

마지막으로 Cover 기능을 구현할 것이다.

Cover

public class Cover : Node
{
    private EnemyRobotBT ebt;

    public Cover(BehaviorTree bt) : base(bt)
    {
        ebt = (EnemyRobotBT)bt;
    }

    public override NodeState Evaluate()
    {
        if (!ebt.ai.closestCoverPoint)
        {
            float minDistance = 10000;
            foreach (var coverPoint in GameObject.FindGameObjectsWithTag("CoverPoint"))
            {
                float dPointToAI = Vector3.Distance(coverPoint.transform.position, ebt.ai.transform.position);
                float dEnemyToPoint = ebt.ai.enemyObject ? Vector3.Distance(ebt.ai.enemyObject.transform.position, coverPoint.transform.position) : 1;

                bool isBlock = !ebt.ai.enemyObject || Physics.Linecast(coverPoint.transform.position, ebt.ai.enemyObject.transform.position, 1 << LayerMask.NameToLayer("Obstacle"));

                float value = ebt.ai.enemyObject ? (1 / dEnemyToPoint) : dPointToAI;
                if (value < minDistance && isBlock)
                {
                    ebt.ai.closestCoverPoint = coverPoint;
                    minDistance = value;
                }
            }
        }

        if (!ebt.ai.closestCoverPoint) return NodeState.FAILURE;

        ebt.ai.StartMove(ebt.ai.closestCoverPoint.transform.position);

        if (Vector3.Distance(ebt.ai.navAgent.transform.position, ebt.ai.closestCoverPoint.transform.position) <= ebt.ai.navAgent.stoppingDistance)
        {
            Quaternion toRotation = ebt.ai.closestCoverPoint.transform.rotation;
            ebt.ai.transform.rotation = Quaternion.RotateTowards(ebt.ai.transform.rotation, toRotation, Time.deltaTime * 500);

            ebt.ai.inputHandler.isCrouch = true;
        }

        return NodeState.RUNNING;
    }
}

일정 수치 아래로 체력이 내려가면 주변에 있는 CoverPoint 로 이동하여 Cover 한다.
일정 시간이 지나 체력이 회복되면 Cover 를 종료한다.

IsHealthLow

public class IsHealthLow : Node
{
    private EnemyRobotBT ebt;
    private float threshold;

    public IsHealthLow(BehaviorTree bt, float threshold) : base(bt)
    {
        ebt = (EnemyRobotBT)bt;
        this.threshold = threshold;
    }

    public override NodeState Evaluate()
    {
        return (ebt.ai.statusController.health <= threshold) ? NodeState.SUCCESS : NodeState.FAILURE;
    }
}

체력이 상당히 낮을 경우, Cover 하지 않고 맞서 싸운다.

Behavior Tree 조립

public class EnemyRobotBT : BehaviorTree
{
    [NonSerialized]
    public EnemyRobotAI ai;

    private void Awake()
    {
        ai = GetComponent<EnemyRobotAI>();
    }

    protected override Node CreateTree()
    {
        Node attackSequence = new Sequence(new List<Node>
        {
            new TakeDistance(this),
            new Aim(this),
            new Selector(new List<Node>
            {
                new Sequence(new List<Node>
                {
                    new NeedReload(this),
                    new Reload(this)
                }),
                new Fire(this)
            })
        });

        Node root = new Sequence(new List<Node>
        {
            new Clear(this),
            new Selector(new List<Node>
            {
                new Sequence(new List<Node>
                {
                    new IsHealthLow(this, 30),
                    new Selector(new List<Node>
                    {
                        new Sequence(new List<Node>
                        {
                            new IsDetectEnemy(this),
                            new Selector(new List<Node>
                            {
                                new Sequence(new List<Node>
                                {
                                    new IsHealthLow(this, 20),
                                    attackSequence
                                }),
                                new Cover(this)
                            })
                        }),
                        new Cover(this)
                    })
                }),
                new Sequence(new List<Node>
                {
                    new IsDetectEnemy(this),
                    attackSequence
                }),
                new Sequence(new List<Node>
                {
                    new NeedReload(this),
                    new Reload(this)
                }),
                new Selector(new List<Node>
                {
                    new Sequence(new List<Node>
                    {
                        new IsSeekLevelHigh(this),
                        new Aim(this),
                        new Seek(this)
                    }),
                    new Sequence(new List<Node>
                    {
                        new Walk(this),
                        new Patrol(this)
                    })
                })
            })
        });

        return root;
    }
}
profile
Game Developer & Web Developer

0개의 댓글