본문 바로가기
공부/Unity 기초

3D FPS - 9 / 네비게이션 알고리즘으로 길찾기

by svcbn 2022. 5. 21.

cube와 capsule로 지형을 만들어주고

네비게이션을 테스트해본다.

 

 

 

 

Agent와 Navigation 기능을 이용할 AgentManager를 만들어준다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class AgentTest : MonoBehaviour
{

    NavMeshAgent agent;
    public Transform target;

    // Start is called before the first frame update
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        
    }

    // Update is called once per frame
    void Update()
    {
        agent.destination = target.position;
    }
}

 

 

 

 

 

 

정상적으로 동작하는것을 확인하고 기존에 만들던 Scene으로 돌아와서

벽과 바닥에는 Navigation Static, Enemy에는 Agent를 적용한다.

private void UpdateMove()
    {
        // 현재 위치가 최대 추적 가능 거리를 넘어갔는지 여부를 판단한다.
        float trace = Vector3.Distance(originPosition, transform.position);

        // 만일, 최대 추적 가능 거리를 넘어갔다면 상태를 복귀 상태로 전환한다.
        if (trace > traceDistance)
        {
            state = State.Return;
        }


        // target방향으로 이동하다가
        //Vector3 dir = target.transform.position - transform.position;
        //dir.Normalize();
        //transform.position += dir * speed * Time.deltaTime;
        agent.destination = target.transform.position;

        // 나와 target의 거리를 구해서
        float distance = Vector3.Distance(transform.position, target.transform.position);

        // 만약 그 거리가 공격거리보다 작으면
        if (distance < attackDistance)
        {
            // Attack으로 전이하고싶다.
            state = State.Attack;
            agent.isStopped = true;
        }


    }

    private void UpdateAttack()
    {
        // 시간이 흐르다가
        currentTime += Time.deltaTime;

        // 만약 현재시간이 공격시간이 되면
        if (currentTime > attackTime)
        {
            // 현재시간을 초기화하고
            currentTime = 0;

            

            // 만약 target이 공격거리 밖에 있으면 Move상태로 전이하고싶다.
            // 나와 target의 거리를 구해서
            float distance = Vector3.Distance(transform.position, target.transform.position);

            // 만약 그 거리가 공격거리보다 크다면
            if (distance > attackDistance)
            {
                // Move상태로 전이하고싶다.
                state = State.Move;
                agent.isStopped = false;

            }

            // 공격 성공
            else
            {
                // 플레이어를 공격하고
                php.AddDamage();
                

            }


        }

    }

    
    public void AddDamage (int damage)
    {
        agent.isStopped = true;
        Destroy(gameObject);

    }

 

 

Enemy 전문

더보기
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

// FSM으로 상태를 제어하고싶다.
// 정지, 이동, 공격, 죽음
public class Enemy : MonoBehaviour
{
    NavMeshAgent agent;

    public float speed = 1;
    
    public float findDistance = 5;
    public float attackDistance = 1.5f;
    public float traceDistance = 15;

    
    enum State
    {
        Idle,
        Move,
        Attack,
        Die,
        Return
    }

    State state;
    PlayerHP php;

    GameObject target;

    float currentTime;
    float attackTime = 1;

    Vector3 originPosition;

    // Start is called before the first frame update
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        
        state = State.Idle;

        target = GameObject.Find("Player");

        php = target.GetComponent<PlayerHP>();

        // 최초 위치를 originPosition 변수에 저장한다.
        originPosition = transform.position;


    }

    // Update is called once per frame
    void Update()
    {
        if (state == State.Idle)
        {
            UpdateIdle();
        }

        else if (state == State.Move)
        {
            UpdateMove();
        }

        else if (state == State.Attack)
        {
            UpdateAttack();
        }

        else if (state == State.Return)
        {
            UpdateReturn();
        }
    }

    
    private void UpdateIdle()
    {
        // 나와 target의 거리를 구해서
        float distance = Vector3.Distance(transform.position, target.transform.position);

        // 만약 그 거리가 감지거리보다 작으면
        if (distance < findDistance)
        {
            // Move상태로 전이하고싶다.
            state = State.Move;

            agent.destination = target.transform.position;

        }

    }

    private void UpdateMove()
    {
        // 현재 위치가 최대 추적 가능 거리를 넘어갔는지 여부를 판단한다.
        float trace = Vector3.Distance(originPosition, transform.position);

        // 만일, 최대 추적 가능 거리를 넘어갔다면 상태를 복귀 상태로 전환한다.
        if (trace > traceDistance)
        {
            state = State.Return;
        }


        // target방향으로 이동하다가
        //Vector3 dir = target.transform.position - transform.position;
        //dir.Normalize();
        //transform.position += dir * speed * Time.deltaTime;
        agent.destination = target.transform.position;

        // 나와 target의 거리를 구해서
        float distance = Vector3.Distance(transform.position, target.transform.position);

        // 만약 그 거리가 공격거리보다 작으면
        if (distance < attackDistance)
        {
            // Attack으로 전이하고싶다.
            state = State.Attack;
            agent.isStopped = true;
        }


    }

    private void UpdateAttack()
    {
        // 시간이 흐르다가
        currentTime += Time.deltaTime;

        // 만약 현재시간이 공격시간이 되면
        if (currentTime > attackTime)
        {
            // 현재시간을 초기화하고
            currentTime = 0;

            

            // 만약 target이 공격거리 밖에 있으면 Move상태로 전이하고싶다.
            // 나와 target의 거리를 구해서
            float distance = Vector3.Distance(transform.position, target.transform.position);

            // 만약 그 거리가 공격거리보다 크다면
            if (distance > attackDistance)
            {
                // Move상태로 전이하고싶다.
                state = State.Move;
                agent.isStopped = false;

            }

            // 공격 성공
            else
            {
                // 플레이어를 공격하고
                php.AddDamage();
                

            }


        }

    }

    
    public void AddDamage (int damage)
    {
        agent.isStopped = true;
        Destroy(gameObject);

    }

    private void OnDestroy()
    {
        EnemyManager.instance.COUNT--;
    }

    void UpdateReturn()
    {
        // 만일, 나의 현재 위치가 originPosition 위치에서 10센티미터 이상이라면
        Vector3 dir = originPosition - transform.position;

        if (dir.magnitude > 0.1f)
        {
            // originPosition 방향으로 이동한다.
            transform.position += dir.normalized * speed * Time.deltaTime;
        }


        // 그렇지 않다면, 나의 위치를 originPosition으로 설정한다.
        else
        {
            transform.position = originPosition;

            // 상태를 다시 대기 상태로 전환한다.
            state = State.Idle;

        }

        // 나와 target의 거리를 구해서
        //float distance = Vector3.Distance(transform.position, target.transform.position);

        // 복귀 중 감지거리 안으로 Player가 들어오면
        //if (distance < findDistance)
        {
            // 상태를 Move 상태로 전이한다.
            //state = State.Move;
        }

        
    }
}

'공부 > Unity 기초' 카테고리의 다른 글

3D FPS - 11 / 적 시야각  (0) 2022.05.23
3D FPS - 10 / 적 생성 유지  (0) 2022.05.21
3D FPS - 8 / 게임 오버 처리  (0) 2022.05.19
3D FPS - 7 / 피격 처리  (0) 2022.05.19
3D FPS - 6 / 위치 복귀  (0) 2022.05.19