본문 바로가기
게임개발/유니티 엔진

네비게이션 시스템

by do_ng 2024. 3. 10.

네비게이션 시스템이란?

 

해당 오브젝트를 지정해서 그 오브젝트가 이동가능한 곳과 이동하지 못하는 곳을 이해할 수 능력을 부여한다. 

출처:https://docs.unity3d.com/kr/2022.3/Manual/nav-NavigationSystem.html

 

여러가지 네비게이션 컴포넌트가 있는데, 

해당 오브젝트에 네비메시 에이전트라는 컴포넌트를 추가하면 다른 오브젝트와 충돌을 피하는 능력을 부여해준다.

 

 

사용방법

 

해당 위치를 마우스로 클릭했을 때, "Wall" Layer가 붙어있는 오브젝트라면 이동을 한다. 

void OnMouseClicked(Defines.MouseEvent evt)
{
    if (playerState == PlayerStateEnum.Die)
        return;

    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 2.0f);        

    RaycastHit hit; 
    if (Physics.Raycast(ray, out hit, 100.0f, LayerMask.GetMask("Wall")))
    {
        destPos = hit.point;
        PlayerMove();
    }
}

 

 

매 프레임마다 클릭한 위치까지 캐릭터를 이동시킴

void Update()
{
    if(_playerController != null)
    {
        if (_playerController.playerState == PlayerController.PlayerStateEnum.Moving)
        {
            UpdateMoving();
        }
    }        
}

void UpdateMoving()
{
    Vector3 dir = _playerController.destPos - transform.position;

    // 목적지 까지 도달한경우 (실수에서 실수를 빼면 오차범위가 있기 때문에 딱 0으로 나눠떨어지지 않음)
    if (dir.magnitude < 0.1f)
    {            
        _playerController.PlayerWait();
    }
    else
    {
        NavMeshAgent nma = gameObject.GetOrAddComponent<NavMeshAgent>();            
        float moveDist = Mathf.Clamp(_playerController.speed * Time.deltaTime, 0, dir.magnitude);
        nma.Move(dir.normalized * moveDist); // 방향벡터

        Debug.DrawRay(transform.position + Vector3.up * 0.5f, dir.normalized, Color.blue);
        if (Physics.Raycast(transform.position + Vector3.up * 0.5f, dir, 1.0f, LayerMask.GetMask("Block")))
        {
            _playerController.PlayerWait();
            return;
        }
        transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(dir), 20 * Time.deltaTime);
        MovingAnimationState(GetComponent<Animator>(), _playerController.speed);
    }
}

클릭한 지점(목적지)에서 매 프레임마다 캐릭터가 이동한 좌표를 빼주면 벡터(이동량)를 구할 수 있는데 벡터의 이동량이 0에 가까이 수렴하게 되면 캐릭터를 이동하지 못하게 만든다. 

(0에 가까이 수렴하게 되었다는 뜻은 목적지까지 이동했다는 뜻이므로)

 

단, 여기서 이동이 불가능한 건물을 클릭했을때 애니메이션은 계속 이동중인 모션을 취하고 있는데 건물을 클릭했을때도 건물 근처까지 캐릭터가 이동할 수 있도록 구현하였다. 

마우스로 해당 위치를 클릭시에 그 위치가 건물일 경우(Layer 마스크에 추가) 이동중인 모션을 멈춰있는 모션으로 바꾸는 형태로 구현을 해버리면 캐릭터가 건물 근처까지 이동을 못하기 때문에 raycasting 작업을 건물을 제외하고 wall인 부분으로만 한정했다.

 

다만, 캐릭터가 건물까지 이동하는 중에 캐릭터 자체에서 RayCast를 캐릭터가 이동하는 방향으로 쏴주면서 건물이 있으면 이동중인 모션을 멈춰있는 모션으로 변경하였다.