[Unity2D] 플레이어 점프 구현

Herring·2021년 3월 21일

매우 간단한 기능이지만 주의해야 할 사항이 있어 글로 남겨본다.
일단 점프는 Rigidbody.AddForce(Vector2.up)로 구현했다.

💡 점프 조건: 플레이어가 땅 위에 있는가?

특수한 경우를 제외하면 점프 도중 다시 점프가 되지 않도록 조건을 걸어주어야 한다.
즉 땅 위에 있을 때만 점프가 가능하도록 해야 한다.

OnCollisionEnter2D 사용

처음에는 플레이어와 바닥이 닿은 것을 땅 위에 있음으로 보고 OnCollisionEnter2D를 사용하여 다음과 같이 구현했다.

    private void OnCollisionEnter2D(Collision2D collision)
    {
        isJumping = false;
    }

    //...

    public void Jump()
    {
        if (!isJumping)
        {
            this.GetComponent<Rigidbody2D>().AddForce(Vector2.up * jumpForce);
            isJumping = true;
        }
    }

(isJumping은 점프 후~착지하기 전 까지 중복점프가 되지 않기 위한 bool형 변수이다.)

OnCollisionEnter2D 사용 시 문제점

언뜻 잘 작동되는 것처럼 보이나 경우에 따라서는 문제가 발생한다.
만약 슈퍼마리오처럼 바닥(땅)이 공중에도 존재하는 경우, 그런 바닥의 밑면이나 측면에 닿았을 때도 OnCollisionEnter2D가 호출되어 버린다.

그러니까 예를들면 위 이미지처럼 [원래 바닥]에서 점프해서 [공중바닥]의 밑면에 충돌하게 되면 점프 중인데도 isJumping=false가 되니, 점프버튼을 연타할 시 중복점프가 가능해져 이상한 움직임이 발생한다는 것이다.

Physics2D.BoxCast 사용

플레이어 자체의 콜라이더 말고, 플레이어로부터 Vector2.down 방향으로 Ray를 쏘아서 Raycast의 충돌로써 땅 위에 있는지를 판정하는 방법도 있었다.
단 플레이어 너비가 있기 때문에 RayCast가 아닌 BoxCast를 사용하는 것이 더 정확하다.
BoxCast의 최대 거리는 플레이어의 발 끝에 맞추었다. 더 길어지면 공중에 있어도 박스가 충돌하여 점프되어버리기 때문.

    private Vector2 boxCastSize = new Vector2(0.4f,0.05f);
    private float boxCastMaxDistance = 0.7f;

    //...    

    private bool IsOnGround()
    {
        RaycastHit2D raycastHit = Physics2D.BoxCast(transform.position, boxCastSize, 0f, Vector2.down, boxCastMaxDistance, LayerMask.GetMask("Ground"));
        return (raycastHit.collider != null);
    }

    public void Jump()
    {
        if (IsOnGround())
        {
            this.GetComponent<Rigidbody2D>().AddForce(Vector2.up * jumpForce);
        }
     }

OnDrawGizmos 사용

만들어놓은 박스캐스트를 씬 뷰에서 눈으로 확인할 수 있도록 기즈모를 그리는 함수이다.

    void OnDrawGizmos()
    {
        RaycastHit2D raycastHit = Physics2D.BoxCast(transform.position, boxCastSize, 0f, Vector2.down, boxCastMaxDistance, LayerMask.GetMask("Ground"));

        Gizmos.color = Color.red;
        if (raycastHit.collider != null)
        {
            Gizmos.DrawRay(transform.position, Vector2.down * raycastHit.distance);
            Gizmos.DrawWireCube(transform.position + Vector3.down * raycastHit.distance, boxCastSize);
        }
        else
        {
            Gizmos.DrawRay(transform.position, Vector2.down * boxCastMaxDistance);
        }
    }

똑같이 점프버튼을 연타했으나 중복점프가 되지 않는다.
빨간 선은 OnDrawGizmos()로 그려진 레이캐스트이다. 피를 흘리고있는게 아니다

0개의 댓글