부트캠프

NavMeshAgent와 CharacterController를 이용한 점프

noyyo 2023. 10. 18. 22:21

네브메쉬 에이전트와 캐릭터 컨트롤러를 사용해 적의 움직임을 구현하려고 했다.

 

생각지 못한 버그들이 많이 발생했는데 알아둬야할 사항들이 몇 가지 있다.

먼저 NavMeshAgent가 enabled 되어 있는 상태에서는 CharacterController의 Move를 사용해도 제대로 동작하지 않는다.

점프등의 행동을 구현하기 위해서는 그 순간 Agent를 꺼주어야 한다.

또 Agent를 끄면 생기는 문제점으로 Agent가 꺼지고 다시 켜지면 기존의 목적지 정보를 상실함과 더불어 velocity가 다시 0부터 시작한다. 해당 정보를 미리 캐싱해놨다가 집어 넣어주어야 한다.

CharacterController로 점프를 구현할 때 생각해야 할 점은 RigidBody를 사용하지 않는다면 직접 중력을 적용시켜 주어야 한다.

그리고 Agent에서 움직이고 있던 방향과 속력을 유지하고 싶다면 해당 정보를 받아와야 하며 공중에서 회전이나 가속이 가능하게끔 하려면 Agent의 velocity를 받아와서 갱신시키는 작업또한 필요하다.

 

이렇게 복잡한 과정을 거쳐야 점프 및 이동을 자연스럽게 구현할 수 있다.

아래는 Jump를 Update에서 실행하는 코드이다. 많이 복잡하고 코드가 더러운 점이 있다.

 

private void Jump()
{
    if (!controller.isGrounded)
    {
        inAirTime += Time.deltaTime;
    }
    else if (controller.isGrounded && inAirTime > 0.2f)
    {
        lastJumpTime = Time.time;
        inAirTime = 0f;
        agent.enabled = true;
        agent.SetDestination(currentDestination);
        movementDirection.y = 0;
        agent.velocity = movementDirection;
    }
    if (Time.time - lastJumpTime > JumpDelay && controller.isGrounded)
    {
        stateMachine.Jump();
        movementDirection = agent.velocity;
        movementDirection.y = 0;
        jumpStartPosition = agent.transform.position;
        jumpStartPosition.y = 0;
        agent.enabled = false;
    }
    if (!agent.enabled)
    {
        Vector3 currentPosition = controller.transform.position;
        currentPosition.y = 0;
        Vector3 destination = currentDestination;
        destination.y = 0;
        float distance = Vector3.Distance(currentPosition, destination);
        Vector3 forward = controller.transform.forward;
        forward.y = 0;
        if (Vector3.Angle(forward, destination) > 1f)
        {
            int rotateDirection;
            Quaternion rotation = controller.transform.rotation;
            if (destination.x < 0 && (rotation.eulerAngles.y > 270 || rotation.eulerAngles.y < 90))
                rotateDirection = -1;
            else if (destination.x < 0 && (rotation.eulerAngles.y < 270 && rotation.eulerAngles.y > 90))
                rotateDirection = 1;
            else if (destination.x > 0 && (rotation.eulerAngles.y > 270 || rotation.eulerAngles.y < 90))
                rotateDirection = 1;
            else
                rotateDirection = -1;
            Quaternion newRotation = Quaternion.Euler(0, rotation.eulerAngles.y + rotateDirection * agent.angularSpeed * Time.deltaTime, 0);
            controller.transform.rotation = newRotation;
        }
        if (distance <= stateMachine.BrakeDistance || Vector3.Angle(movementDirection, destination - currentPosition) > 5f)
        {
            movementDirection = movementDirection - movementDirection.normalized * agent.acceleration * Time.deltaTime;
            Vector3 destinationDirection = destination - jumpStartPosition;

            if (movementDirection.magnitude <= 0.01f)
                movementDirection = -destinationDirection.normalized * agent.acceleration * Time.deltaTime;

            if (Vector3.Angle(destinationDirection, movementDirection) > 5f)
            {
                Vector3 point1 = RepeatPoint1.position;
                point1.y = 0;
                if (destination == point1)
                {
                    currentDestination = RepeatPoint2.position;
                }
                else
                {
                    currentDestination = RepeatPoint1.position;
                }
            }
        }
        else if (agent.velocity.sqrMagnitude < agent.speed * agent.speed)
        {
            movementDirection = movementDirection + movementDirection.normalized * agent.acceleration * Time.deltaTime;
            if (movementDirection.sqrMagnitude > agent.speed * agent.speed)
            {
                movementDirection = movementDirection * (agent.speed * agent.speed) / movementDirection.sqrMagnitude;
            }
        }
        controller.Move((movementDirection + new Vector3(0, stateMachine.verticalVelocity, 0)) * Time.deltaTime);
    }

}

'부트캠프' 카테고리의 다른 글

최종 프로젝트 시작  (0) 2023.10.23
원을 따라 움직이는 적 구현  (0) 2023.10.20
델리게이트를 이용해서 UI를 구성하기  (0) 2023.10.12
유니티 Navigation  (0) 2023.10.10
드래그 앤 드롭을 구현하기  (0) 2023.10.06