ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Direct2D] 점프 구현
    C++/미분류 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

     

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

    감사합니다.

    댓글

Designed by Tistory.