유니티 C#/C#

C#기초 - 이동과 점프 구현할 때 Transform와 Rigidbody 충돌 오류

그린초코 2024. 5. 1. 21:57

유니티에서 오브젝트에 이동 구현 스크립트를 적용하려면 Transform 컴포넌트 설정이 필요하고,

점프 구현 스크립트를 적용하려면 Rigidbody 컴포넌트를 추가하여 설정해야 한다. 

따라서 오브젝트에 이동과 점프 둘 다 구현을 하려면 Transform과 Rigidbody 컴포넌트 둘 다 필요하다.

 

(이동과 점프 구현 스크립트는 아래 참고)

 

이동 구현 스크립크 : https://greenchoco.tistory.com/223

 

C#기초 - 방향키로 이동하기 (Input Manager, GetAxis, Vector3)

유니티는 Input Manager 키를 불러와서 GetAxis로 수치화 한 후 이를 Vector 에 적용시킬 수 있다.  (참고 : Input Manager와 GetAxis https://greenchoco.tistory.com/221) 유니티 기초 - Input Manager 시스템으로 입력신호

greenchoco.tistory.com

 

점프 구현 스크립트 : https://greenchoco.tistory.com/227

 

C#기초 - 스페이스바 점프 구현하기 (Getkey, Addforce함수)

스페이스바를 눌렀을 때 오브젝트가 점프할 수 있도록 하는 방법은 어렵지 않다. 1. 오브젝트가 떨어지지 않게 땅 오브젝트 (Plane)을 추가해준다.1. 플레이 할 플레이어 오브젝트에 Rigidbody 컴포

greenchoco.tistory.com

 

 

위의 스크립트를 참고하여 이동과 점프 둘 다 구현된 스크립트는 아래와 같다. 

 - 플레이어는 캡슐 오브젝트로 이름은 player이다.

 - player오브젝트에는 rigidbody컴포넌트를 추가하고 constraints - freeze rotation x, y, z를 체크했다. (그래야 안쓰러짐)

 - plane 오브젝트를 추가한 뒤 Ground 라는 이름으로 tag를 해주었다. 

 - 장애물 오브젝트로 큐브 오브젝트를 추가해주었다. 

using System.Collections;
using System.Collections.Generic;
using UnityEditor.Rendering;
using UnityEngine;

public class Player : MonoBehaviour
{
    
    public float moveSpeed; // 이동구현 - 속도
    public float jumpPower; // 점프구현 - 점프하는 힘
    int jumpCount; // 점프구현 - 점프 횟수
    Rigidbody rb; // 점프구현 - rigid에 이름짓기
    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody>(); // 점프구현 - 오브젝트의 rigid 가져와서 저장 
    }

    void Update()
    {
        float h = Input.GetAxis("Horizontal"); // 이동구현 - 수평
        float v = Input.GetAxis("Vertical"); // 이동구현 - 수직
        Vector3 dir = new Vector3 (h, 0, v); // 이동구현 - 이동 정규화를 위한 dir 선언
        dir.Normalize(); // 이동구현 - dir의 이동 정규화
        transform.position += dir * moveSpeed * Time.deltaTime; // 이동구현 - 이동함수에 dir 적용

        if(Input.GetKeyDown(KeyCode.Space) && jumpCount<2) // 점프구현 - 만약 스페이스파를 누르면 / 2번 미만일 때
        {
            rb.AddForce(Vector3.up * jumpPower, ForceMode.Impulse); // 점프구현 - 위로 순간적인 힘이 발생
            jumpCount++; // 점프구현 - 점프시 1씩 추가한다. 
        }

    }
    private void OnCollisionEnter(Collision collision) // 점프구현 - 충돌 시작하면 호출
    {
        if (collision.gameObject.tag == "Ground") // 점프구현 - 충돌한 물체의 tag가 Ground 일 때
        {
            jumpCount = 0; // 점프구현 - 점프 횟수를 초기화한다. 
        }
    }
}

 

이렇게 작성했을 때 플에이어 오브젝트는 안정적으로 움직인다. 

하지만 방애물이 발생하였을 때 충돌처리방식에 따라 rigidbody 컴포넌트는 더이상 움직이지 못한다고 판단하지만, transform 는 이동 기능에 따라 position 값이 계속 변하려고 하게 된다.

 

그 결과 장애물이 발생했을 때 아래 플레이어가 흔들거리는 현상이 나타난다. 

 

 

이를 해결하기 위해서는 MovePosition 이라는 함수를 이용하면 된다.

이는 물리 작용을 활용해 위치 정보를 계산하는 함수로, Vector3 값을 인수로 지정할 수 있다. 

 

즉 위 스크립트에서      

transform.position += dir * moveSpeed * Time.deltaTime; 이 부분을 
rb.MovePosition(rb.position +(dir * moveSpeed * Time.deltaTime)); 으로 수정하면 된다. 

 

그럼 플레이어는 흔들리지 않고 잘 움직인다. 

 

참고로 설치한 장애물이 untagged 상태면 장애물에 올라간 플레이어는 점프할 수 없다.

위 스크립트에서 Ground 이름이 tag된 오브젝트랑 충돌할 때 발생한다고 적어두었기 때문이다.

따라서 장애물 위에서도 점프를 하기 위해서는 장애물 오브젝트 인스펙터에서 untagged를 Ground로 바꿔주면 된다 

 

따라서 최종 결과물은 아래와 같다.

 

 

 

728x90