Unity | 유니티/Unity 개발 일지

[Unity] 이단 점프 구현, 점프 높이 일정하게 조절, 물체 통과 해결 | Rigidbody

maintain_H 2023. 8. 7. 16:44
반응형

 캐릭터의 이단점프를 구현하게 되었는데, 이단점프 높이가 일정하지 않았다..

이걸 해결하는 방법을 구글링해봤지만 나오지 않아서 직접 해경 방법을 포스팅한다!

 

캐릭터를 움직이게 하는 방법에는 "Rigidbody"를 사용하는 방법이랑

"Character Controller"를 사용하는 방법이 있는데, 본인은 Rigidbody를 사용한 방법을 작성하도록 하겠다.

 

[ Rigidbody ]

 먼저 Rigidbody에 대해 간단히 설명하고 넘어가겠다

 

유니티 공식 레퍼런스(클릭하면 공식 레퍼런스로 넘어간다)에 따르면

Rigidbody는 GameObject가 물리 제어로 동작하게 합니다. 리지드바디는 힘과 토크를 받아 오브젝트가 사실적으로 움직이도록 해줍니다. 리지드바디가 포함된 모든 게임 오브젝트는 중력의 영향을 받아야 하며 스크립팅을 통해 가해진 힘으로 움직이거나 NVIDIA PhysX 물리 엔진을 통해 다른 오브젝트와 상호 작용해야 합니다.

 쉽게 말하면 물리적인 동작을 할 수 있도록 도와준다고 생각하면 된다.

물체가 부딪혔을 때 효과나 중력의 영향을 받는 걸 코드로 구현하지 않고,

이 Rigidbody 컴포넌트만 추가하면 된다..! 이 말이다! 유니티 최고야 짜릿해 늘 새로워!

 

 

[ Rigidbody Properties ]

내가 생각했을 때 Rigidbody에서 자주 쓰는 기능에 대해 설명하자면, 다른 것들은 유니티 공식 레퍼런스에 들어가면 또 나와있다!

 

Property 기능
Mass 오브젝트의 질량(기본 값은 kg)
Drag 오브젝트가 힘에 의해 움직일 때 공기 저항이 영향을 미치는 정도.
(0이면 공기 저항이 없고, 무한대라면 오브젝트는 즉시 정지)
Use Gravity 활성화되면 오브젝트는 중력의 영향을 받음.
Interpolate Rigidbody의 움직임이 어색해 보일 경우 시도해봐야 한다.

- None(기본값): 보간이 적용되지 않는다.
-- 이 아래는 CPU 사용량이 증가한다. 큰 프로젝트라면 프레임드랍을 야기할 수 있다!
- Interpolate: 이전 프레임의 트랜스폼에 맞게 움직임을 부드럽게 처리.
- Extrapolate: 다음 프레임의 트랜스폼을 추정해 움직임을 부드럽게 처리.
Collision Detection 빠르게 움직이는 오브젝트가 충돌의 감지 없이 다른 오브젝트를 지나치는 것을 방지.

- Discrete(기본값): 씬에서 다른 모든 콜라이더에 대해 불연속 충돌 검사를 사용. 다른 콜라이더는 충돌 테스트에 불연속 충돌 검사를 사용. 일반적인 충돌에 활용된다.

- Continuous 및 Continuous Dynamic: 충돌로 설정된 게임 오브젝트에 스위핑 기반 연속 충돌 검사를 사용. 또한 (Rigidbody가 없는) 정적 콜라이더에도 연속 충돌 검사를 사용. 그 외 다른 콜라이더에는 불연속 충돌 검사를 사용. 빠르게 움직이는 오브젝트에 쓰인다.(CPU 사용량이 증가)
Constraints Rigidbody의 움직임에 대한 제약사항.
- Freeze Position: 월드 자표계의 X, Y, Z 축에 이동을 제한.
- Freeze Rotation: 로컬 좌표계의 X, Y, Z 축에 회전을 제한.

 

 

[ 오브젝트 물체 통과 해결 방법 ]

 간혹 가다가 Rigidbody, 물체가 벽을 통과할 때가 있는데, 이건 rigidbody.velocity를 이용하지 않고, transform.Translate를 이용해 물체를 이동시켰을 때 일어나는 현상이다. 그때는 Translate를 rigidbody.velocity를 이용해 오브젝트를 이동시키면 된다.

그럼 CPU 사용량이 높은 Interpolate, Collision Detection을 사용하지 않고 해결할 수 있다!

 

[ 참고 ]

 또한 캐릭터의 움직임이 끊긴다면, Rigidbody의 움직임을 담당하는 함수나 코드가 FixedUpdate가 아닌 Update에 들어가있는지 확인한다.

 움직임을 담당하는 코드가 Update함수 내에 구현되어 있다면, FixedUpdate로 이동시켜준다..!

 

 

 

[ 점프 구현 ]

 이제 점프를 구현하도록 하겠다.

 

Player, Ground 생성

 먼저 땅이랑 플레이어를 생성한다.

 

Collider 추가

 그리고 각각 Collider를 추가해준다.

 

Rigidbody 추가

 그리고 플레이어에 Rigidbody를 추가해준다.

 

[ 점프 구현 ]

public class Player : MonoBehaviour
{
    public Rigidbody2D rb;
	
    // 점프 높이!
    public float jumpPower = 7;

    void Start()
    {
        if (!rb) rb = GetComponent<Rigidbody2D>();        
    }
		
    // Rigidbody를 사용할 때는 무조건 FixedUpdate에 움직임을 구현!!
    private void FixedUpdate()
    {
    	// 좌클릭 하면 점프
       	if (Input.GetMouseButtonDown(0))
        {
            rb.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
        }
    }

}

 

코드를 실행하면..!

 

무한 점프

이렇게 하늘을 날아간다.. boolean을 이용해 점프에 제한을 줘야 한다.

 

public class Player : MonoBehaviour
{
    public Rigidbody2D rb;

    public float jumpPower = 7;
	
    // 점프 중인지 확인
    bool isJumping;

    void Start()
    {
        if (!rb) rb = GetComponent<Rigidbody2D>();        
    }

    private void FixedUpdate()
    {
    	// 점프 중이 아니고, 좌클릭 했을 때
        if (Input.GetMouseButtonDown(0) && !isJumping)
        {
        	// 점프하면 isJumping = true;
            isJumping = true;
            rb.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
        }
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
    	// 바닥에 오브젝트에 닿으면 isJumping = false
        switch (collision.gameObject.name)
        {
            case "Ground":
                isJumping = false;
                break;
        }
    }
}

 

 

[ 이단 점프 구현 ]

public class Player : MonoBehaviour
{
    public Rigidbody2D rb;

    public float jumpPower = 7;
	
    // 점프 횟수
    int jumpCnt;

    void Start()
    {
        if (!rb) rb = GetComponent<Rigidbody2D>();        
    }

    private void FixedUpdate()
    {
    	// 점프 횟수가 2번 미만일 때
        if (Input.GetMouseButtonDown(0) && jumpCnt < 2)
        {
            rb.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
            // 점프횟수 증가
            jumpCnt++;
        }
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        switch (collision.gameObject.name)
        {
        	// 땅 오브젝트에 닿았을 때 점프횟수 0으로 초기화.
            case "Ground":
                jumpCnt = 0;
                break;
        }
    }
}

 

[ 이단 점프 문제점 ]

 

 

점프 높이가 일정하지 않은 이단 점프

이렇게 점프 높이가 일정하지 않는다..! 

뭐가 문제일까 생각해봤는데 Rigidbody안에 velocity가 초기화되지 않아서 그랬던 것이다..!

 

velocity

점프할 때마다 AddForce를 이용해 순간적으로 힘을 주는데,

현실에서도 같은 힘이라도 내려오는 중에 힘을 받으면 상대적으로 적게 뛰고,

올라가는 중에 힘을 받으면 상대적으로 더 높게 뛸 수 있다..!! 역시 유니티..!

 

그래서 나는 velocity를 초기화하는 코드 한 줄 추가해줬다.

 

 

[ 최종 코드 ]

public class Player : MonoBehaviour
{
    public Rigidbody2D rb;

    public float jumpPower = 7;

    int jumpCnt;

    void Start()
    {
        if (!rb) rb = GetComponent<Rigidbody2D>();        
    }

    private void FixedUpdate()
    {
        if (Input.GetMouseButtonDown(0) && jumpCnt < 2)
        {
        	// velocity 초기화
            rb.velocity = Vector2.zero;
            rb.AddForce(Vector2.up * jumpPower, ForceMode2D.Impulse);
            jumpCnt++;
        }
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        switch (collision.gameObject.name)
        {
            case "Ground":
                jumpCnt = 0;
                break;

        }
    }
}

 

최종 실행화면

 

 이상으로 이단 점프 높이 일정하지 않은 문제 해결 과정 포스팅이었습니다

반응형