본문 바로가기

카테고리 없음

유니티 07 - Nav Mesh Agent 와 Bake

03-23 목요일 수업 내용입니다.

 

Navigation 창의 컴포넌트입니다. 

아래와 같이 수치를 조정했습니다.

이유는 좀비NPC가 이동 할 때, 발이 땅에 살짝 파묻히는걸 발견 했기 때문에 그랬습니다.

 

위 수치가 어떤 기능을 하는걸까?

Agent는 요원이라는 뜻이 있는데, 지형위에서 움직이는 대상이다.

Agent Radius 는 Navi mash 위에서 움직이는 반지름을 이야기 한다. 

이 값이 커지면 커질 수록 뚱뚱해지고, 벽이나 바닥에 바짝 달라붙어서 이동할 수 없게 된다.

 

Agent Height는 대상이 움직일 때, 통과 할 수 있는 높이다. 이 값이 높아질 수록 대상의 키가 커진다고 생각하면 편하다.

낮은 장애물이나 천장이 낮은 곳은 통과하지 못하거나 진입할 수없을 것이다.

 

 

 

 

 

설명을 보니 Radius 값이 발이 묻히는 현상과 연관이 있어보입니다.

 

오늘은 좀비에 HP를 만들고, 총에 맞으면 히트당해서 움찔거리게 할 겁니다.

그리고, HP가 0이 되면 사망 판정을 받으면서 die 애니메이션을 출력하고, 쓰러지는것 까지 구현할 예정입니다.

 

 

좀비의 상태를 담당하는 Script를 생성했습니다.

 

여기에 필요한 변수들은 어떤게 있을까요?

맞는걸 관리 해야 하니까 HP가 있어야 하고, 맞았을 때 애니메이션을 줘야하니 Animator

맞았을때 깎여야 할 대미지가 있어야 하니 데미지를 넣습니다. ( 사실 제가 만드는 게임이었다면 데미지는 플레이어에게 넣을 것 같아요 )

 

그리고 좀비가 죽으면 더이상 움직여서는 안되겠죠, 따라서 영향을 줄 수 있도록 ZombieCtrl도 불러 왔습니다.

 

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

public class ZombieDamage : MonoBehaviour
{
    public Animator animator;
    public int hp = 100;
    private int damage = 35;
    ZombieCtrl zombieCtrl;
    public bool isDie;
    void Start()
    {
        zombieCtrl = GetComponent<ZombieCtrl>();
        animator = GetComponent<Animator>();
        isDie = false;
    }

    
    //OncollisionEnter와 같은 함수를 콜백함수라 한다. 외부에서 변수 선언을 안해도 자동으로 본인을 선언하면서 쓸 수 있게됨.
    private void OnCollisionEnter(Collision col) //Block되면서충돌 감지,
    {
        if (col.gameObject.CompareTag("BULLET"))
        {
            Destroy(col.gameObject);   //충돌한 게임 오브젝트 삭제
            Debug.Log("총맞았다."); //디버그용 출력문
            animator.SetTrigger("IsHit");   //IsHit트리거를 당겨라
            zombieCtrl.StopZombie();    //좀비의 움직임을 멈추는 메소드를 실행해라
            hp -= damage;   //HP를 대미지 만큼 깎는다.
            if (hp <= 0)    //HP가 0이하인경우
                Die();  //아래에 있는 Die()메소드를 실행한다.
        }
            
    }
    void Die()
    {
        isDie = true;   //죽음 상태 반환을 위한 bool자료형 선언  
        animator.SetTrigger("IsDie");   //죽는 애니메이션 트리거 당겨라
        zombieCtrl.StopZombie();    //이동을 멈추는 메소드, 위에 맞았을때 호출하는것과 같다.
        GetComponent<CapsuleCollider>().enabled = false;    //충돌 효과도 없앤다.
    }
}

위와 같이 스크립트를 만들었습니다.

 

 

 

오늘 콜라이더 충돌 함수의 일종인

OnCollisionEnter 라는 함수를 처음 구현해보게 되었습니다. 유니티 엔진에서 클래스를 제공하고 있으며

전에 배웠던 OnTriggerEnter와 유사하게 사용할 수있습니다. 

차이점은 충돌이냐, 통과냐 차이입니다.

특이사항으로 함수를 사용할 때, 매개변수는 따로 전역쪽에 선언하지 않아도 함수를 호출하면서 바로 자동선언된다는건데요.

함수를 시작하면서 매개변수로 자동으로 선언이 되며, 지역변수로 사용 가능하게 됩니다.

 

 

col.gameObject.CompareTag("BULLET")

이 문장은 BULLET 과 같은 태그를 찾아서 사용하겠다는 이야기 입니다.

 

 

이제 위에서 ZombieCtrl에서 움직임을 멈추는 StopZombie(); 메소드를 구현하기 위해 ZombieCtrl 클래스를 수정하겠습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
//1.플레이어와 좀비의 거리 계산 2. 플레이어 추적 3.공격 사정거리에 들어오면 Attack


public class ZombieCtrl : MonoBehaviour
{
    public Transform zombieTr;
    public Transform playerTr;
    public NavMeshAgent agent;
    public Animator animator;
    public float attackDist = 2.5f;
    public float traceDist = 20.0f;
    ZombieDamage zoBieDamage;



    void Start()
    {
        zoBieDamage = GetComponent<ZombieDamage>();
        animator = GetComponent<Animator>();
        //this는 생략이 가능하다.
        agent = this.GetComponent<NavMeshAgent>();
        zombieTr = this.transform; // 자기 자신의 트랜스폼 정보 초기화
        playerTr = GameObject.FindWithTag("Player").GetComponent<Transform>();
        //하이어라키에서 Player라는 태그를 가진 트랜스폼에 접근한다.
        //playerTr에 대입한다.

    }

    // Update is called once per frame
    void Update()
    {
        if (zoBieDamage.isDie == true) return;
        //위의 조건에 맞는 순간 이 하위로직으로 내려가지 않고 빠져나간다.
        float dist = Vector3.Distance(playerTr.position, zombieTr.position);

        if (dist <= attackDist)
        {
            agent.isStopped = true; //네비메시 에이전트 추적 중지
            animator.SetBool("IsAttack", true);
        }
        else if (dist <= traceDist)
        {
            agent.isStopped = false; //네비메시 에이전트 추적 실행
            agent.destination = playerTr.position;
            animator.SetBool("IsAttack", false);    //공격을 중지하라
            animator.SetBool("IsTrace", true);      //추적을 시작하라
        }
        else
        {
            agent.isStopped = true;
            animator.SetBool("IsTrace", false); //idle 애니메이션 실행
        }



    }
    public void StopZombie()
    {
        agent.isStopped = true;
        agent.velocity = Vector3.zero;
    }



}

StopZombie 메소드를 만들어 주었습니다.

저번시간에 처음 배웠던 Nav Mesh Agent 컴포넌트를 사용했습니다.

agent.isStopped 추적을 멈출지 여부

agent.velocity  = NPC 캐릭터의 속도 입니다.

속도를 0으로 초기화하는 메소드네요

NavMeshAgent라는 컴포넌트 덕분에 속도를 줄이는 과정이 단 한문장으로 간결하게 표현 되었습니다.

 

여담으로 강사님이 NavMeshAgent의 컴포넌트를 몇개 가르쳐 주셨습니다.

위의 사진으로 정리 해보았습니다.

 

또, Update() 함수에서 return 함수를 처음 써보게 되었는데요, return 함수를 만나면 밑의 문장을 컴파일 하지 않고, 바로 탈출하게 됩니다.

 

 

오늘 추가로 외부 에셋을 통해  좀비를 만든것과 같은 방법으로 추적 AI와 상황에 따른 애니메이션을 적용 해 보았습니다.

 

[SerializeField] 에 대해서도 배웠습니다.

이는 애트리뷰트 라는 명칭으로, private으로 선언해서 외부 클래스에서 접근할 수 없지만, 컴포넌트에 보이게 만들 수 있는 속성값을 주는 명령어라고 합니다.

코드에서 주석을 달아주는 것처럼 보여주는것 외에 딱히 역할은 없습니다.