본문 바로가기
게임 공부/DirectX

DirectDraw 학습 (4) - 사각형 이동시켜보기

by woohyeon 2020. 11. 23.
반응형

저번 내용에 추가로 다음과 같이 방향키로 사각형을 움직이는 간단한 동작을 추가해본다. 동영상을 gif로 변환해서 그런지 좀 버벅거리는 것처럼 보인다. 이동할 땐 초록색을 가지고 멈춰 있을 땐 빨간색을 가진다.

 

위 동작의 원리는 매우 단순하다. 현재 사각형의 x 및 y 좌표를 가지고 있다가 방향키가 눌리면 그 방향으로 일정 수만큼 더하거나 뺀다. 그러면 다음에 다시 그려질 때 변경된 좌표에 다시 그려지면서 이동한 것처럼 보이게 된다. 이때, 기존 버퍼를 수정하지 않으면 이전에 그려졌던 사각형이 그대로 남아있을 것이다. 따라서 사각형을 그리기 전에 버퍼 전체를 지우거나 배경을 새로 그린 뒤 사각형을 그려야 한다.

방향키가 눌리고 떼지는 것을 체크하기 위해 WndProcWM_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;
}

아직까지 딱히 어려운 부분은 없다.

 

다음 포스팅에선 사각형 대신 래스터 이미지로 대체해본다




댓글