C++/미분류

[Direct2D] 점프 구현

ruru14 2024. 6. 13. 15:50

지난 글에서 플레이어 캐릭터가 착지할 수 있는 플랫폼을 만들었습니다.

[Direct2D] 충돌 및 지형 구현

위 글에서 생성된 플랫폼은 두 개 입니다.

하지만, 플레이어 캐릭터는 위로 올라갈 방법이 없었습니다.

 

이번 글에서는 플레이어 캐릭터에 점프 기능을 추가하도록 하겠습니다.

 


 

1. 키 입력 추가

 

더보기

이전에 구현한 중력 기능의 일부를 살펴보도록 하겠습니다.

FLOAT downSpeed = ~~~;
FLOAT gravity = ~~~;

void Update() {
    ...
    FLOAT deltaDown = deltaTime * downSpeed;
    downSpeed += deltaTime * gravity;
    ...
}

위와 같이 낙하 속도를 증가시키는 등가속 운동을 구현했습니다.

착지 판정 시 downSpeed는 0이 되어 더 이상 낙하하지 않습니다.

 

점프는 초기에는 상승 운동을, 이후 속도가 점점 줄어들며 하강 운동을 하는 형태의 운동으로 볼 수 있습니다.

따라서, 점프 키에 초기 속도인 downSpeed를 음수로 (좌표계 상 음수가 위쪽 방향이므로) 지정합니다.

코드는 다음과 같습니다.

void MyApp::HandleKeyboardInput() {
    ...
    if (GetAsyncKeyState(VK_MENU) & 0x8000) {
        if (!inputFlag[VK_MENU]) {
            inputFlag[VK_MENU] = true;
            if (curJumpCount++ < maxJumpCount) {
                downSpeed = jumpPower;
            }
        }
    } else {
        if (inputFlag[VK_MENU]) {
            inputFlag[VK_MENU] = false;
        }
    }
    ...
}

기존의 키 입력을 구현한 함수 HandleKeyboardInput함수에 점프 관련 키를 추가했습니다.

키보드 입력과 관련된 글은 아래 글에 정리되어 있습니다.

[WinAPI] 키보드 입력 (WM_KEYDOWN, WM_KEYUP, GetAsyncKeyState)

VK_MENU는 왼쪽 Alt키를 지정하는 값입니다.

해당 값을 변경하면 임의의 점프 키를 할당할 수 있습니다.

코드를 상세히 분석하면 아래와 같습니다

  - inputFlag는 키다운 상태에서 지속적인 호출이 되지 않도록 하기 위한 플래그입니다.

  - curJumpCount와 maxJumpCount는 MyApp의 클래스 변수입니다.

  - 위 두 JumpCount는 한 번에 여러 회의 점프를 가능하도록 하는 값 입니다.

 

2. Update함수 수정

 

더보기

Update함수의 충돌 판정 코드를 위 기능에 맞춰 수정해야 합니다.

우선, 기존 코드는 아래와 같습니다.

...
D2D1_RECT_F t = myCharacterBitmap->GetBitmapRect();
for (auto& i : ground) {
    if (IsCollision(t, i)) {
        downSpeed = 0;
        deltaDown = 0;
    }
}
...

위 코드의 문제점은 다음과 같습니다

  - ground가 많아질 경우, 연산량이 커질 수 있습니다.

  - 낙하속도가 클 경우, ground를 통과할 수 있습니다.

 

우선 첫 번째, 연산량 부분입니다.

위 코드는 좌우 이동이 아닌, 상하 이동에 관한 충돌만 판정합니다.

따라서, 현재 플레이어 캐릭터의 위치에서 착지할 수 있는 플랫폼에 대한 계산만 수행하도록 제한할 수 있습니다.

구체적으로는 다음과 같습니다.

for (auto& i : ground) {
    if (!(i.left <= t.right && i.right >= t.left)) continue;
    ...
}

위 조건문은 좌우 충돌 판정 코드와 동일합니다.

이미지의 좌우가 걸리지 않았을 경우, 해당 플랫폼에는 착지할 수 없습니다.

따라서, 충돌과 관련된 계산이 불필요합니다.

 

다음은 낙하속도입니다.

낙하속도가 클 경우, 속도를 줄이는 방법을 생각해볼 수 있습니다.

구체적으로, 낙하속도와 플랫폼까지의 거리를 비교하여, 속도를 보정하도록 하겠습니다.

코드는 다음과 같습니다.

for (auto& i : ground) {
    ...
    float groundDist = abs(i.top - t.bottom);
    if (groundDist <= deltaDown) {
        deltaDown = groundDist;
        curJumpCount = 0;
        downSpeed = 0;
    }
}

 

기존 IsCollision함수를 이용한 코드를 제거하고 코드를 새로 추가했습니다.

위 코드의 groundDist는 캐릭터와 바닥 사이의 거리입니다.

이미지가 다음 프레임에 이동할 거리는 deltaDown입니다.

두 값을 비교하여, deltaDown이 클 경우 이미지가 플랫폼을 통과한다는 것을 알 수 있습니다.

이 경우 이미지는 groundDist만큼만 이동하여 착지할 수 있도록 합니다.

추가적으로, 착지 시 필요한 연산 (하강속도 초기화, 점프 횟수 초기화)을 수행합니다. 

 


 

중력이 이미 구현되었기 때문에, 점프에 대한 구현이 간단했습니다.

이번 글에서 사용된 코드의 전문은 아래 Github에서 확인하실 수 있습니다.

 

GitHub - ruru14/WinapiStudy: WinAPI및 DirectX를 공부하며, 간단한 운동 법칙을 적용해봅니다.

WinAPI및 DirectX를 공부하며, 간단한 운동 법칙을 적용해봅니다. Contribute to ruru14/WinapiStudy development by creating an account on GitHub.

github.com

 

이번 글이 도움이 되셨기를 바랍니다.

감사합니다.