부트캠프

[멋쟁이사자처럼 유니티 TIL] 회전 및 점프 구현(+FixedUpdate와 Update의 차이)

맛난과자 2024. 6. 3. 23:48

벡터의 정규화

w,a,s,d 입력이 가능하게 해놓은 상태에서 대각선으로 이동할 경우, 이동 거리가 늘어나게 되는 문제가 있음.

대각선 이동거리는 루트값이 나옴

이러한 문제를 해결하기 위해 벡터의 정규화 사용.

 

Normalize(): 길이가 1인 벡터를 만들어줌.

direction.Normalize();
rotDirection.Normalize();

 

 

 

회전 구현

① 먼저 rotDirection을 선언.

② a, d를 누를 때 회전할 수 있도록 rotDirection에 값 넣기

if (Input.GetKey(KeyCode.A))
{
    rotDirection += -transform.right;
}
if (Input.GetKey(KeyCode.D))
{
    rotDirection += transform.right;
}

 

③ rotDirection 값이 있을 경우, 바라볼 방향을 현재 내 방향으로 회전하는 값 로컬 설정.

④ 회전 값 transform에 넣기.

if (rotDirection.sqrMagnitude > 0.001f)
{
    // newRot 계산
    // transform.rotation은 현재 내가 보고 있는 방향
    // Quaternion.LookRotation(direction) // 내가 바라볼 방향이다.
    // Quaternion의 RotateToward는 current -> new 로 회전할 값을 정하는데
    // 그 양이 Time.fixedDeltaTime * rotSpeed 값이다.
    Quaternion newRot = Quaternion.RotateTowards(transform.rotation,
        Quaternion.LookRotation(rotDirection), rotSpeed * Time.fixedDeltaTime);
    // newRot으로 회전
    charObj.transform.rotation = newRot;
}

 

 

Quaternion

: 회전을 나타내는 구조체.

아직 물리 수학을 배우지 않아 자세한 내용은 가르쳐주지 않으심.

 

● LookRotation : Vector를 Quaternion으로 변경해주는 함수. 방향에 대한 벡터.

● RotateTowards : from에서 to로 maxDegreesDelta만큼 회전

 

결과

 

 

점프 구현

Rigidbody의 AddFoce 함수를 이용하여, 

Space를 누를 시 위로 순간적인 힘이 가하겠끔 함.

if (Input.GetKeyDown(KeyCode.Space))
{
    GetComponent<Rigidbody>().AddForce(Vector3.up * jumpPower, ForceMode.Impulse);
}

 

● Rigidbody.AddForce: 오브젝트에 힘을 가하는 함수

● ForceMode.Impulse: 순간적으로 속도를 붙여줌. 정지 상태에서 이동을 시작하려 할 때 적합.

 

 

다중 점프 방지

다중 점프 발생

위의 코드로 작성할 경우, 점프를 끝내기 전에 점프를 하는 문제가 발생함.

이를 방지하기 위해, 

플레이어가 땅에 닿아있을 때만 점프를 할 수 있게 작성함.

 

① bool 타입 isGrounded을 false로 정의

bool isGrounded = false;

 

② 점프의 조건에 isGrounded 추가

③ 조건문 안에서 isGrounded에 false 값 넣기

if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
{
    GetComponent<Rigidbody>().AddForce(Vector3.up * jumpPower, ForceMode.Impulse);
    isGrounded = false ;   // 점프를 하면 땅에서 떨어짐
}

 

④ Inspector 창에서 Tag 클릭 후 Add Tag... 클릭

 

⑤ 플러스 버튼(+) 을 클릭하여 "Ground" 태그 추가

 

⑥ 땅 오브젝트들을 선택한 후 Inspector 창에서 위의 Tag 버튼을 클릭하여 태그를 "Ground"로 변경

⑦ CompareTag를 이용하여 충돌체의 태그가 "Ground"인지 확인하는 조건문 생성

⑧ 조건문 안에서 isGrounded에 true 값 넣기

void OnCollisionEnter(Collision collision)
{
    // 땅 오브젝트가 플레이어의 콜라이더에 닿았을 경우
    if (collision.gameObject.CompareTag("Ground"))
    {
        // 땅에 닿은 것으로 처리
        isGrounded = true;
    }
}

 

결과

 

 

 

FixedUpdate와 Update의 차이

FixedUpdate

- Fixed Timestep 의 값에 한 번씩 틱이 돎 

- 조건 상관 없이 무조건 실행

- Input 이 이 값 이전에 눌리면 생략되어 반응이 없을 수 있음

 

Update

- 1 프레임 당 1틱.

- Input 받은 후 Update가 실행되기 때문에 생략되지 않음.

 

=> 키 입력은 Update에서 받는 게 좋다!

private void Update()
{
    // 매 업데이트 마다 direction, rotDirection을 초기화 해줘서
    // 그 다음 인풋 적용되도록 한다.
    direction = Vector3.zero ;
    rotDirection = Vector3.zero ;

    // direction 들에 값 넣어주기
    if (Input.GetKey(KeyCode.W))
    {
        direction += charObj.transform.forward;
    }

    if (Input.GetKey(KeyCode.A))
    {
        rotDirection += -charObj.transform.right;
    }

    if (Input.GetKey(KeyCode.S))
    {
        direction += -charObj.transform.forward;
    }

    if (Input.GetKey(KeyCode.D))
    {
        rotDirection += charObj.transform.right;
    }

    if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
    {
        GetComponent<Rigidbody>().AddForce(Vector3.up * jumpPower, ForceMode.Impulse);
        isGrounded = false ;
    }

    // 대각선 방향은 값은 루트가 나오기 때문에 정규화
    direction.Normalize();
    rotDirection.Normalize();
}

 

 

 

회전과 점프는 게임에 거의 필수적인 요소.

손에 익숙해지기 위해 반복학습을 해야겠다 느낌.