저번 내용에 추가로 다음과 같이 방향키로 사각형을 움직이는 간단한 동작을 추가해본다. 동영상을 gif로 변환해서 그런지 좀 버벅거리는 것처럼 보인다. 이동할 땐 초록색을 가지고 멈춰 있을 땐 빨간색을 가진다.
위 동작의 원리는 매우 단순하다. 현재 사각형의 x 및 y 좌표를 가지고 있다가 방향키가 눌리면 그 방향으로 일정 수만큼 더하거나 뺀다. 그러면 다음에 다시 그려질 때 변경된 좌표에 다시 그려지면서 이동한 것처럼 보이게 된다. 이때, 기존 버퍼를 수정하지 않으면 이전에 그려졌던 사각형이 그대로 남아있을 것이다. 따라서 사각형을 그리기 전에 버퍼 전체를 지우거나 배경을 새로 그린 뒤 사각형을 그려야 한다.
방향키가 눌리고 떼지는 것을 체크하기 위해 WndProc에 WM_KEYDOWN 메세지와 WM_KEYUP 메세지 처리를 추가한다. 키가 눌리고 떼질 때마다 위와 같은 메세지들이 전달된다. 그리고 lParam에 정보를 담아준다. 현재 이 부분이 중요하진 않으므로 자세한 원리는 구글링을 하길 바람.
case WM_KEYDOWN:
{
UINT scanCode = (0x00ff0000 & lParam) >> 16;
UINT vkCode = MapVirtualKey(scanCode, MAPVK_VSC_TO_VK);
if (g_pMyGame)
{
g_pMyGame->OnKeyDown(vkCode, scanCode);
}
}
break;
case WM_KEYUP:
{
UINT scanCode = (0x00ff0000 & lParam) >> 16;
UINT vkCode = MapVirtualKey(scanCode, MAPVK_VSC_TO_VK);
if (g_pMyGame)
{
g_pMyGame->OnKeyUp(vkCode, scanCode);
}
}
break;
OnKeyDown과 OnKeyUP에선 다음과 같이 눌렸을 경우 해당 방향키에 해당하는 BOOL 변수의 값을 TRUE로 변경해준다. 그리고 반대의 경우 FALSE로 변경해준다. 대략 다음과 같다.
VOID MyGame::OnKeyDown(UINT vKey, UINT scanCode)
{
switch (vKey)
{
case VK_LEFT:
{
m_bKeyDown_Left = TRUE;
break;
}
...
}
}
VOID MyGame::OnKeyUp(UINT vKey, UINT scanCode)
{
switch (vKey)
{
case VK_LEFT:
{
m_bKeyDown_Left = FALSE;
break;
}
...
}
}
다음은 좌표를 업데이트하는 부분이다. 이 동작은 사각형을 그리기 전에 수행해 주어야 한다. 오른쪽 방향키가 눌려있다면 x 좌표로 일정 값만큼 더해주면 되고, 아래 방향키가 눌려있다면 y축 방향으로 일정 값만큼 더해주면 된다. (y 값이 클수록 아래로 이동한다는 것을 상기)
// 멈춰있다면 Red, 움직인다면 Green
DWORD dwColor = 0x00ff0000; // Red
if(m_bKeyDown_Right)
{
m_dwSquarePosX += 1;
dwColor = 0x0000ff00; // Green
}
if(m_bKeyDown_Left)
{
m_dwSquarePosX -= 1;
dwColor = 0x0000ff00;
}
...
사각형의 크기를 생각해서 사각형 전체가 스크린의 영역을 넘어선 안된다. 그 부분은 코드에 나타내지 않았으니 필요하다면 예외처리를 따로 해주자. 위 코드에선 x및 y좌표를 1씩 이동시킨다. 여기서 1이라는 단위는 4바이트가 될 것이다.
다음은 백그라운드를 갱신하는 부분이다. 배경을 모두 0으로 초기화하는 방법과 다시 그리는 방법이 있다. 전자는 ZeroMemory(memset)로 화면의 크기만큼 값을 설정해주면 된다. 모두 0x00000000으로 설정되는 것이므로 검은 배경이 될 것이다. 후자는 사각형을 그리듯이 배경 색상을 화면의 크기만큼 write 해주면된다. 여기선 간단하게 전자를 사용.
// Update background
ZeroMemory(m_pLockedBackBuffer, m_dwLockedBackBufferPitch * m_dwScreenHeight);
다음은 미리 업데이트된 좌표를 통해 실제로 백버퍼에 write한다. 이를 위해선 x, y를 통해 그리기 시작할 위치를 계산해야 한다. base는 당연히 Lock된 백버퍼의 주소가 될 것이다.
x는 바이트 단위가 아니고 길이를 의미하므로 4bytes를 곱하여 메모리 오프셋으로 나타낸다. 그 위치로부터 y축으로 y만큼 이동하려면 pitch를 y번 곱해서 더해준다.(이해가 안간다면 이전 포스팅을 참고) 즉 (x, y)위치를 메모리 주소로 변환하면 시작 주소 + (x * 4bytes) + (pitch * y)가 된다. 이후부턴 이전 포스팅과 동일하다. 코드로 표현하면 다음과 같다.
DWORD dwSquareWidth = 50;
DWORD dwSquareHeight = 50;
DWORD dwSrc = dwColor;
char* pDest = m_pLockedBackBuffer + (m_dwSquarePosX * 4) + (m_dwLockedBackBufferPitch * m_dwSquarePosY);
char* pBegin = pDest;
for(DWORD y = 0; y < dwSquareHeight; ++y)
{
for(DWORD x = 0; x < dwSquareWidth; ++x)
{
*(DWORD*)pDest = dwSrc;
pDest += 4;
}
pDest = pBegin + m_dwLockedBackBufferPitch;
pBegin = pDest;
}
아직까지 딱히 어려운 부분은 없다.
다음 포스팅에선 사각형 대신 래스터 이미지로 대체해본다
'게임 공부 > DirectX' 카테고리의 다른 글
깊이스텐실 Desc 중 깊이 func 값 관련 - D3D11_COMPARISON_FUNC (0) | 2021.03.18 |
---|---|
[DirectX] Direct3D 11 programming (1) (0) | 2021.03.05 |
DirectDraw 학습 (3) - Set pixel (0) | 2020.11.21 |
DirectDraw 학습 (2) - Draw (0) | 2020.11.17 |
DirectDraw 학습 (1) - Initialization (0) | 2020.11.15 |
댓글