F.R.I.D.A.Y.

물리엔진 - 점프 구현하기 본문

DEV/Direct2D

물리엔진 - 점프 구현하기

F.R.I.D.A.Y. 2021. 5. 13. 15:03
반응형

 이전 시간에는 캐릭터가 바닥을 만났을 때, 더이상 아래로 내려가지 않도록 했습니다. 이번에는 점프를 구현해보겠습니다.


점프 구현

 단순히 만들면 그냥 키 입력을 받았을 때 이동속도로 음수(-)값을 주면 됩니다. 근데, 이러면 다시 점프가 가능해지죠. 그래서 우리는 키 상태를 저장하고 실 계산은 Calculate 메서드에서 처리하도록 구성할겁니다.

 

 키 상태를 저장하는 방법은 아래 포스트를 참고하세요.

 

Win32 - 키보드 입력으로 사각형 움직이기

 키보드 입력으로 사각형을 움직여봅니다. # Win32 프로그래밍을 이해하고 있어야합니다. # 알지 못하는 경우 여기에서부터 시작할 것을 권장합니다. # 본 문서는 Direct2D 기반으로 구현합니다. Win3

pang2h.tistory.com

 

 위 페이지의 정보대로 참고하면 키 상태를 저장하는 변수[# 이 포스트에서 변수명은 keyState입니다.]와 OnKeyDown, OnKeyUp 메서드가 생성되었을 것입니다.

LRESULT MainWindow::OnKeyDown(WPARAM key)
{
	keyState[key] = true;
	return 0;
}

LRESULT MainWindow::OnKeyUp(WPARAM key)
{
	keyState[key] = false;
	return 0;
}

 

 경우에 따라선 여러 번 점프하는 것을 만들 수 있겠지만, 지금은 한 번만 점프가 가능한 것으로 만들겠습니다. MainWindow의 멤버 메서드로 bool 타입의 변수 하나를 생성해줍니다.

	bool keyState[256];
	bool canJump = false;

 기존 Calculate 메서드입니다.

void MainWindow::Calculate()
{
    static float gravity = 3.f;
    static float dropSpeed = 0.f;
    dropSpeed += gravity;			// 여기부터

    if (dropSpeed >= 0.f) {
        for (size_t i = 0; i < 3; ++i) {
            if (!(ground[i].left < rcCenter.x + rcSize.width/ 2.f && 
                rcCenter.x - rcSize.width / 2.f < ground[i].right)) continue;

            if (ground[i].top < rcCenter.y + rcSize.height / 2) continue;

            if (abs(ground[i].top - rcCenter.y - rcSize.height / 2) < 0.001f) {
                dropSpeed = 0.f;
                break;
            }

            if (rcCenter.y + rcSize.height / 2 + dropSpeed > ground[i].top) {
                float gap = ground[i].top - rcCenter.y - rcSize.height / 2.f;
                dropSpeed = gap;
            
            }

        }
    }

    rcCenter.y += dropSpeed;
}

 

 

 

 표시된 부분부터 코드 수정을 진행하겠습니다.

 

 

 점프를 하기 위해선 일단 반발력을 가질 수 있는 벽에 위치한지를 알아야하고, 점프를 취하는 키가 눌린 상태인지를 알아야합니다. 지금 상태에선 바닥에 위치한 상태를 canJump 변수가 가지고 있다고 생각하겠습니다. 그럼 아래와 같은 판정식을 만들 수 있습니다.

if(canJump && keyState[VK_SPACE]){

}else{

}

 

 생각해봅시다. 우리가 점프를 하면 속도의 변화는 어떤 그래프를 가지나요? 아마도 COS(θ)[# θ는 0 ~ π/2]와 유사한 그래프를 그릴겁니다. 즉, 가속은 땅을 박차고 오를 때 한 번 뿐입니다. 따라서 코드를 작성할 때도 가속을 한 번만 해주면 되는거죠. 다시 점프하면 안되니까 이 과정을 하면 canJump는 false로 전환해주고요.

if(canJump && keyState[VK_SPACE]){
	dropSpeed = -30.f;
    canJump = false;
}else{
	dropSpeed += gravity;
}

 그리고 점프를 했으면 이젠 떨어지도록 중력 가속도를 더해줍니다. 이렇게만 하면 프로그램 시작 후 한 번만 점프할 수 있습니다. 바닥을 만났으면 다시 점프할 수 있도록 아래 분기문에 추가해줍니다.

			if (abs(ground[i].top - rcCenter.y - rcSize.height / 2) < 0.001f) {
				dropSpeed = 0.f;
				canJump = true;  // 추가
				break;
			}

 

결과

 이렇게 코드를 따라하면 아래와같이 반복 점프가 가능해졌습니다.

 

 

 아래는 변경된 Calculate 메서드의 전문입니다.

void MainWindow::Calculate()
{
	static float gravity = 4.3f;
	static float dropSpeed = 0.f;
	if (canJump && keyState[VK_SPACE]) {
		dropSpeed = -30.f;
		canJump = false;
	}
	else {
		dropSpeed += gravity;

	}

	if (dropSpeed >= 0.f) {
		for (size_t i = 0; i < 3; ++i) {
			if (!(ground[i].left < rcCenter.x + rcSize.width/ 2.f && 
            	rcCenter.x - rcSize.width / 2.f < ground[i].right)) continue;

			if (ground[i].top < rcCenter.y + rcSize.height / 2) continue;

			if (abs(ground[i].top - rcCenter.y - rcSize.height / 2) < 0.001f) {
				dropSpeed = 0.f;
				canJump = true;
				break;
			}

			if (rcCenter.y + rcSize.height / 2 + dropSpeed > ground[i].top) {
				float gap = ground[i].top - rcCenter.y - rcSize.height / 2.f;
				dropSpeed = gap;
			
			}

		}
	}

	rcCenter.y += dropSpeed;
}

 

더 생각해보기

 현재 코드에서는 캐릭턱 공중에 있더라도 착지하지 않은 상황이라면 공중에서 한 번 뛸 수 있습니다. 일부러 공중에서도 점프가 가능하도록 한 번은 허용하는 방식으로 게임을 구현하는 분들도 계시지만, 그렇지 않은 경우도 있죠.

 어떻게 하면 공중인 경우엔 점프를 하지 못하도록 구성할 수 있을까요? 한번 생각해보세요. 댓글로 코드를 입력하면 제가 생각한 것과 같은 답인지 답글 달겠습니다.

 

# index

728x90
반응형
Comments