플레이어를 쫓아다니는 몬스터 AI 구현

2024. 7. 4. 19:17Unity/Unity 학습정리

  • StatMachine분리

  • 분리를 하지 않았을 때 문제점
    • 대부분의 기능을 공유하는 두 클래스에서 상속을 받았을때 BaseMonster의 상속도 받는 다는 부분이다.
    • 하지만 PartnerMonster는 플레이어를 따라다니고 멀어지면 추적한다.
    • EnemyMonster는 플레이어가 가까워지면 추적하고 멀어지면 다시 원래 자리로 돌아간다.
  • 해결방법
public MonsterStateMachine(BaseMonster monster)
{
    Monster = monster;

    if (Monster.GetType() == typeof(PartnerMonster))
    {
        Debug.Log(Monster.GetType());
        IdleState = new PartnerMonsterIdleState(this);
        WalkState = new PartnerMonsterWalkState(this);
    }
    else if(Monster.GetType() == typeof(EnemyMonster))
    {
        IdleState = new EnemyMonsterIdleState(this);
        WalkState = new EnemyMonsterWalkState(this);
    }

    DefaultState = new MonsterDefaultState(this);
    AttackState = new MonsterAttackState(this);
    BasicAttackState = new MonsterBasicAttackState(this);
    SkillState = new MonsterSkillState(this);
    HitState = new MonsterHitState(this);
}

각자 가져야하는 State를 들어오는 타입에 따라서 State를 꽃아주는 방식으로 구현

 

AIHandler

파트너 몬스터는 적 몬스터와 플레이어를 둘 다 탐지하고 StateMachine에 탐지 정보를 넘겨주어야한다.

  1.  Player를 탐지 했을 때는 따라가야하는 정보를 주고
  2. Enemy를 탐지 했을 때는 공격하는 State로 전이
public class ParnterMonsterAIHandler : BaseMonsterAIHandler
{
    private float _enemyDetectRange = 5f;
    //적 몬스터 타겟
    protected override void Start()
    {
        base.Start();
        _detectRange = 2.5f;
    }
    //적을 탐지 로직
    protected override void UpdateEnemyTarget()
    {
        base.UpdateEnemyTarget();
        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, _enemyDetectRange, _EnemyTarget);
        if (colliders.Length > 0)
        {
            float closetDistance = Mathf.Infinity;
            Transform closetTarget = null;

            foreach (Collider2D collider in colliders)
            {
                float distanceToTarget = Vector2.Distance(transform.position, collider.transform.position);
                //타겟이 반경안에 있다면
                if (distanceToTarget < closetDistance)
                {
                    closetDistance = distanceToTarget;
                    closetTarget = collider.transform;
                }

                if (closetTarget != null)
                {
                    if ((1 << closetTarget.gameObject.layer) == LayerMask.GetMask("Enemy"))
                    {
                        EnemyTargetTransform = closetTarget;
                    }
                }
                else
                {
                    //Agent.ResetPath();
                    EnemyTargetTransform = null;
                }
            }
        }
        else
        {
            EnemyTargetTransform = null;
        }
    }

    //플레이어 탐지로직
    protected override void UpdatePlayerTarget()
    {
        base.UpdatePlayerTarget();
        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, _detectRange, _playerTarget);
        if (colliders.Length > 0)
        {
            float closetDistance = Mathf.Infinity;
            Transform closetTarget = null;

            foreach (Collider2D collider in colliders)
            {
                float distanceToTarget = Vector2.Distance(transform.position, collider.transform.position);
                //타겟이 반경안에 있다면
                if (distanceToTarget < closetDistance)
                {
                    closetDistance = distanceToTarget;
                    closetTarget = collider.transform;
                }

                if (closetTarget != null)
                {
                    //타겟이 플레이어라면 
                    if ((1 << closetTarget.gameObject.layer) == LayerMask.GetMask("Player"))
                    {
                        TargetTransform = closetTarget;
                        //Agent.SetDestination(TargetTransform.position);
                    }
                }
                else
                {
                    //Agent.ResetPath();
                    TargetTransform = null;
                }
            }
        }
        else
        {
            TargetTransform = null;
        }
    }
}

PartnerMonster 기준 일정한 원의 탐지 영역을 만들고 Layer를 체크해 정보를 전달해준다.

 

'Unity > Unity 학습정리' 카테고리의 다른 글

Unity - 몬스터 모드 변경  (0) 2024.07.11
Unity - Interface로 원하는 동작 해보기  (0) 2024.07.10
FSM StateMachine 상속  (0) 2024.07.01
Unity - Behaviour Tree (1)  (0) 2024.06.25
Unity - FSM(Finite State Machine)(3)  (0) 2024.06.20