본문 바로가기
카테고리 없음

[유니티] Rigidbody(리지드바디)로 플레이어 움직임 구현하기 - 2

by TODAYCODE 2021. 9. 11.
반응형

이전에 스크립트를 제외한 모든 준비를 끝마쳤으니 이제 스크립트를 본격적으로 작성해보도록하자.

 

3D게임에 기본적으로 존재하는 요소들을 구현해볼 것이다.

구현할 사항들은 다음과 같다.

1. WASD키의 입력을 통한 기본적인 움직임.

2. 플레이어 캐릭터의 점프 구현

3. 점프 제한 추가

 


1. 기본 움직임 구현

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

public class RigidbodyControl : MonoBehaviour
{
    public float speed = 10f;
    Rigidbody rb;
    Vector3 dir = Vector3.zero;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

	// 키 입력과 이동방향 계산
    void Update()
    {
        InputAndDir();
    }

	// 계산된 방향으로 물리적인 이동 구현
    private void FixedUpdate()
    {
        rb.MovePosition(rb.position + dir * speed * Time.deltaTime);
    }

	// 키 입력과 그에 따른 이동방향을 계산하는 함수
    void InputAndDir()
    {
        dir.x = Input.GetAxis("Horizontal");   // x축 방향 키 입력
        dir.z = Input.GetAxis("Vertical");     // z축 방향 키 입력
        if (dir != Vector3.zero)   // 키입력이 존재하는 경우
        {
            transform.forward = dir;	// 키 입력 시, 입력된 방향으로 캐릭터의 방향을 바꿈
        }
    }
}

위의 코드를 작성해주고 유니티상에서 플레이를 해보면 WASD 키조작에 따라서 플레이어 캐릭터가 움직이는 것을 확인할 수 있다.

 

Vector3 dir을 하나 선언한 뒤에 dir의 x와 z값을 Input.GetAxis를 통해서 변경되도록 만들어 준다.

이러면 키 입력에 따라서 방향값을 얻을 수 있고 조건문을 사용해서

키 입력이 있을 경우 그 방향으로 캐릭터의 forward방향을 변경해주면, 이동할때 이동방향으로 캐릭터가 회전하게 된다.

현재는 캡슐만 존재하기 때문에 유니티상에서 플레이를 해보더라도 캐릭터가 회전하고 있는지를 확인할 수가 없다.

Player 하위에 오브젝트 하나를 추가해서 앞방향에 배치해두는 것으로 방향전환을 확인할 수 있으므로 참고하자.

 

리지드바디를 통해서 움직임을 구현하는 것은 물리엔진을 활용해서 물리연산을 진행하겠다는 뜻이다.

고로, FixedUpdate를 사용해줘야 알맞다. FixedUpdate는 물리적인 계산을 해야할 때 사용한다.

자세한 내용은 이전 글 참고.

 

[Unity] : MonoBehaviour 는 무엇인가?

유니티상에서 C# 스크립트를 생성하면, 이름 옆에 항상 MonoBehavior가 적혀있다. 유니티를 처음 배우면 Start , Update 등을 다루면서 사용법을 익히기 시작하는데 그러다보니 오히려 MonoBehavior가 무엇

coding-of-today.tistory.com

 

꽤나 간단하게 기본 움직임 구현이 끝났다.

사실 움직임을 구현하는 방법은 매우매우 다양하다.

내가 아는 방식만 해도 지금 설명한 것 외에도 더 많은데, 이 방법이 비교적 제일 간단하기에 이 방법을 기록했다.

 

 

 

 

2. 점프 구현

 

점프를 구현하는 방법도 매우 다양하므로,

이런 방식으로 구현한다는 것을 이해한 후에 본인이 개발하고 있는 상황에 맞게 커스텀 하면 될 것이다.

 

	public float jumpHeight = 3f;	// 점프 높이 설정

    // Update is called once per frame
    void Update()
    {
        InputAndDir();
        Jump();
    }

    void Jump()
    {
        if (Input.GetButtonDown("Jump"))
        {
            Vector3 jumpVelocity = Vector3.up * Mathf.Sqrt(jumpHeight * -Physics.gravity.y);
            rb.AddForce(jumpVelocity, ForceMode.VelocityChange);
        }
    }

현재 리지드바디에 의해서 중력의 영향을 받고 있으므로,

중력의 영향을 없애기 위해서 -Physics.gravity.y를 곱해주고 높게 뛰어오르기 위해

위에서 선언한 jumpHeight 값을 곱해준다.

점프를 더 높게 하고 싶다면 여기서 숫자를 더 곱해주는 것으로 높게 점프하도록 구현할 수 있다.

 

또한 여기서 Mathf.Sqrt 를 사용해서 제곱근형태로 코드를 작성했는데 그 이유는 직접 해보면 곧장 알 수 있다.

제곱근을 사용하지 않으면, 빠르게 뛰어오르고 천천히 내려와서 굉장히 부자연스럽게 된다.

자연스러운 움직임을 구현하기 위해서 Mathf.Sqrt를 사용했다.

 

이제 유니티 상에서 플레이를 해보고 스페이스바를 누르면 캐릭터가 점프하는 것을 볼 수 있다.

아직 문제점이 남아있는데 스페이스바를 연타하면 공중으로 계속 날아오르게 된다.

그러므로 점프를 특정 상황에서만 할 수 있도록 제한을 걸어두는 작업을 해야한다.

 

 

3. 점프 제한

점프를 한번만 가능하도록 제한하는 방법도 정말 다양하다.

여러가지 방법 중에서 캐릭터의 발 밑으로 짧은 Ray를 쏴서 점프 중이 아닐 때만 점프를 하도록 만들어보자.

 

    bool isGrounded;		// 땅에 서있는지 체크하기 위한 bool값
    public LayerMask ground;	// 레이어마스크 설정
    public float groundDistance = 0.2f;		// Ray를 쏴서 검사하는 거리
    
    
    void Update()
    {
        GroundCheck();	// 땅 위에 서있는지 체크
        InputAndDir();
        Jump();
    }

    void Jump()
    {
        if (Input.GetButtonDown("Jump") && isGrounded == true)	// IsGrounded가 true일 때만 점프할 수 있도록
        {
            Vector3 jumpVelocity = Vector3.up * Mathf.Sqrt(jumpHeight * -2f * Physics.gravity.y);
            rb.AddForce(jumpVelocity, ForceMode.VelocityChange);
        }
    }
    
    void GroundCheck()
    {
        RaycastHit hit;
        
        // 플레이어의 위치에서, 아래방향으로, groundDistance 만큼 ray를 쏴서, ground 레이어가 있는지 검사
        if (Physics.Raycast(transform.position, Vector3.down, out hit, groundDistance, ground))
        {
            isGrounded = true;
        }
        else
        {
            isGrounded = false;
        }
    }

위와같이 소스코드를 작성하고 유니티로 돌아가서 설정을 마무리해야한다.

 

유니티에 제작해 놓은 Ground 오브젝트의 레이어를 Ground로 변경해준다.

 

그리고나서 플레이어 오브젝트의 인스펙터창에서 Ground 부분의 레이어를 Ground로 변경해준다.

완료하게되면 이제 점프를 땅에 있을 때만 딱 한번씩 할 수 있게 된다.

 

주의해야할 점은 groundDistance 값이 너무 작게 되면 땅을 제대로 인식하지 못한다.

그리고 만약 간혹 땅이 캐릭터의 발끝이 묻혀버리는 등의 문제가 발생할 경우 땅을 인식하지 못해서 점프를 못하게 되는 경우가 발생할 수도 있다.

이런 경우를 방지하기 위해서, groundDistance의 거리를 충분하게 주어야하고(물론, 공중에서는 영향이 없을 만큼만),

Ray를 쏘는 위치를 발끝에서 살짝 위로 변경하면 캐릭터의 발끝이 묻히더라도 점프를 할 수 있게 된다.

 


 

이상으로 Rigidbody를 사용하여 기본적인 움직임 구현을 완성했다.

캐릭터 컨트롤을 할 때 리지드바디와 캐릭터컨트롤러가 양대산맥처럼 사용되기 때문에

다음에는 캐릭터컨트롤러로 기본적인 이동구현을 포스팅해보도록 하겠다.

반응형

댓글