-
[Direct2D] 비트맵 이미지 움직이기 (2)C++/미분류 2024. 3. 13. 14:59
지지난글에서 DirectX와 WIP로 이미지를 출력하는 방법을 알아보았습니다.
[Direct2D] 비트맵 이미지 그리기
[Direct2D] 움직이는 비트맵 이미지 그리기그리고 지난 글에서, 출력한 이미지의 위치값을 변화시켜 움직이는 방법을 알아보았습니다.
[Direct2D] 비트맵 이미지 움직이기 (1)
이번 글에서는 특정 값이 아닌, 사용자의 입력(이번 글에서는 방향키)으로 이미지를 움직여보도록 하겠습니다.
이번 글의 코드는 지난 글에서 일부 이어집니다.
0. MyBitmap 기능 추가 (이미지 크기 조정)
더보기이번 글에서 사용될 이미지가 윈도우 사이즈에 비해 큰 관계로, MyBitmap에 이미지 크기를 조정하는 기능을 추가하도록 하겠습니다.
class MyBitmap { public: void SetScale(FLOAT x, FLOAT y); ... private: FLOAT bitmapScaleX = 1.f; FLOAT bitmapScaleY = 1.f; ... };
SetScale함수는 지정한 값으로 이미지의 크기를 조정하는 함수입니다.
FLOAT변수 두 개는 SetScale에 의해 지정된 값이 저장됩니다.
지정한 Scale값은 Bitmap의 출력 위치를 지정할 때 사용됩니다.
다음은 해당 기능을 수행하는 GetBitmapPosition함수입니다.
// Before D2D1_RECT_F MyBitmap::GetBitmapPosition() { return D2D1::RectF( 0 + currentPosition.width, 0 + currentPosition.height, bitmapSize[currentFrame].width + currentPosition.width, bitmapSize[currentFrame].height + currentPosition.height ); } // After D2D1_RECT_F MyBitmap::GetBitmapPosition() { return D2D1::RectF( 0 + currentPosition.width, 0 + currentPosition.height, (bitmapSize[currentFrame].width * bitmapSacleX) + currentPosition.width, (bitmapSize[currentFrame].height * bitmapSacleY) + currentPosition.height ); }
우측 하단의 위치를 지정하는 값에 Scale을 곱했습니다.
이것으로 이미지의 크기는 지정한 Scale비율로 출력됩니다.
1. 변수 추가
더보기이전 글의 이동하는 이미지를 그대로 두고, 입력에 의해 이동할 객체를 추가로 만들겠습니다.
class MyApp { private: MyBitmap* myCharacterBitmap = nullptr; FLOAT MoveSpeed = 100.f; FLOAT MoveDirection[4] = {0.f, 0.f, 0.f, 0.f}; ... };
myCharacterBitmap은 입력받아 움직일 이미지 객체입니다.
MoveSpeed는 이미지가 이동할 속도, MoveDirection은 이미지가 움직이는 방향입니다.
방향 배열의 순서는 임의로 설정해도 되지만, 이번 글에서는 RectF의 순서에 맞게 Left, Top, Right, Bottom순으로 사용하도록 하겠습니다.
2. 이미지 이동 구현
더보기이동에 대한 구현은 프레임 함수인 OnRender함수에서 수행됩니다.
우선, 이미지를 지정한 속도만큼 이동합니다.
myCharacterBitmap->Move( deltaTime * MoveSpeed * (MoveDirection[0] + MoveDirection[2]), deltaTime * MoveSpeed * (MoveDirection[1] + MoveDirection[3]) );
프레임에 관계 없이 일정한 속도로 이동할 수 있도록 deltaTime을 곱해주었습니다.
또한, 각각의 축에 대응하는 값 (왼쪽 + 오른쪽 / 위 + 아래)을 더해준 모습을 볼 수 있습니다.
이번 글에서는 오른쪽을 양수로, 왼쪽을 음수로 지정해줄 예정이기 때문에 두 값을 더했으나, 구현에 따라 각각의 방향이 부호가 없는 값이 될 수 있습니다. 이 경우 두 값의 차로 계산하는 것이 맞습니다.
이후 이미지의 출력은 지난 글의 이미지 출력과 유사합니다.
if (myCharacterBitmap) { ID2D1Bitmap* tmp = myCharacterBitmap->GetBitmap(); if (tmp) { myRenderTarget->DrawBitmap(tmp, myCharacterBitmap->GetBitmapPosition() ); } }
출력 객체의 프레임을 받아 Render target으로 출력합니다.
3. 키보드 입력 추가
더보기키보드 입력으로 위 문단의 MoveDirection을 변화시키면 이미지가 이동할것입니다.
키보드 입력을 받는 방법은 지난 글에서 소개된 바 있습니다.
[WinAPI] 키보드 입력
이번 글에서는 위 글에서 소개된 두 가지 기능 중, GetAsyncKeyState함수를 사용하도록 하겠습니다.
예제 코드에는 이미 해당 기능을 사용하는 HandleKeyboardInput함수가 있습니다.
이전 글의 내용을 참조하여, 방향키 입력을 처리할 수 있는 코드를 추가하겠습니다.
void MyApp::HandleKeyboardInput() { ... if (GetAsyncKeyState(VK_LEFT) & 0x8000) { inputFlag[VK_LEFT] = true; MoveDirection[0] = -1; } else { if (inputFlag[VK_LEFT]) { inputFlag[VK_LEFT] = false; MoveDirection[0] = 0; } } ... }
4가지 방향키는 각각 VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN으로 지정되어 있습니다.
코드가 중복되기 때문에, 왼쪽 방향키에 대응하는 예제 코드만 보여드렸습니다.
윈도우 프로그램 좌표계는 오른쪽이 +X, 아래쪽이 +Y인 것에 유의하여 MoveDirection의 값을 지정합니다.
4. 방향 전환 구현하기 (1)
더보기이번 예제에 사용된 이미지는 특정 방향 (오른쪽)을 바라보고 있습니다.
따라서, 이미지가 왼쪽으로 이동할때에는 왼쪽을 바라보는 것이 자연스럽습니다.
이번 문단에서는 해당 기능을 구현하도록 하겠습니다.
우선, 이미지를 좌우반전 하는 코드는 다음과 같습니다.
myRenderTarget->SetTransform(D2D1::Matrix3x2F::Scale(-1.f, 1.f));
Scale값을 음수로 바꾸는 것으로, 해당 축에 대한 반전이 가능합니다.
두 번째 인자인 Y값을 음수로 할 경우 상하반전이 됩니다.
Scale은 크기를 조정하는 기능입니다.
크기를 조정할 때, 조정하게 되는 기준점을 지정할 수 있습니다.
지정하지 않을 경우 좌측 상단인 0, 0이 지정됩니다.
이것이 좌우 반전에 적용될 경우, 이미지가 반전될 때 화면 밖으로 넘어갈 것을 예상할 수 있습니다.
따라서, 반전 기준점을 현재 이미지 위치의 중앙으로 변경할 필요가 있습니다.
현재 이미지 위치의 중앙 좌표를 구하는 코드는 다음과 같습니다.
D2D1_POINT_2F center = D2D1::Point2F( ps.right - ((ps.right - ps.left) / 2), ps.bottom - ((ps.bottom - ps.top) / 2) );
출력에 변환을 적용하는 것은 Render target을 통해서 할 수 있습니다.
myRenderTarget->SetTransform(D2D1::Matrix3x2F::Scale(-1.f, 1.f, center)); myRenderTarget->DrawBitmap(tmp, myCharacterBitmap->GetBitmapPosition() ); myRenderTarget->SetTransform(D2D1::Matrix3x2F::Scale(1.f, 1.f));
또한, Render target의 Scale이 다른 출력에 영향을 받지 않도록, 출력 이후 Scale을 정상으로 변경했습니다.
5. 방향 전환 구현하기 (2)
더보기위 코드를 적용시킬 경우, 이미지의 좌우가 반전된 상태로 움직이는 것을 볼 수 있습니다.
이번 문단에서는 이미지가 이동 방향을 볼 수 있도록 바꿔보겠습니다.
우선, 변수를 하나 추가합니다.
class MyApp { private: bool isLeft = false; ... };
이 변수는 이미지의 방향을 지정합니다.
추가한 bool변수는 Render target의 Scale에 사용됩니다.
// Before myRenderTarget->SetTransform(D2D1::Matrix3x2F::Scale(-1.f, 1.f, center)); ... // After myRenderTarget->SetTransform(D2D1::Matrix3x2F::Scale((isLeft ? -1.f : 1.f), 1.f, center));
isLeft의 상태에 따라서 좌우 반전을 수행할 수 있도록 수정했습니다.
isLeft의 값은 키보드 입력에 의해 변환됩니다.
void MyApp::HandleKeyboardInput() { ... if (GetAsyncKeyState(VK_LEFT) & 0x8000) { ... if (MoveDirection[2] != 0) { isLeft = false; } else { isLeft = true; } ... } ... }
좌우 방향키가 눌릴 때, MoveDirection의 값으로 반대 방향키의 상태를 확인할 수 있습니다.
이를 통해, 이미 방향키가 눌려있을 때에 반대 방향키가 눌릴 경우 정지하고 방향은 바뀌지 않도록 구현했습니다.
원하는 조작 방법에 따라, 값을 변경하는 것으로 조작감을 바꿀 수 있습니다.
위 코드를 통해 구현된 프로그램은 다음과 같습니다.
이번 글에서 사용된 전체 코드는 아래 Github에서 보실 수 있습니다.
이번 글이 도움이 되셨기를 바랍니다.
감사합니다.
'C++ > 미분류' 카테고리의 다른 글
[Direct2D] Device context 사용하기 (ID2D1DeviceContext) (1) 2024.03.29 [DirectX] 스마트 포인터 ComPtr (0) 2024.03.21 [Direct2D] 비트맵 이미지 움직이기 (1) (0) 2024.03.10 [Direct2D] 움직이는 비트맵 이미지 그리기 (1) 2024.02.28 [Direct2D] 비트맵 이미지 그리기 (1) 2024.02.26