Windows API를 활용해 미니 엔진을 제작하는 과정은 게임 개발의 첫 단계로, Windows 데스크톱 애플리케이션 템플릿을 분석하며 시작합니다.
GameCoding으로 설정하여 시작합니다.main 함수는 Windows 애플리케이션의 시작점으로, wWinMain 함수로 구현되어 있습니다.
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
hInstance: 현재 애플리케이션 인스턴스를 식별하는 핸들입니다.hPrevInstance: 이전 인스턴스 핸들입니다. Windows 95 이후 의미가 없습니다.lpCmdLine: 명령줄 인수로 전달된 문자열입니다.nCmdShow: 창 표시 상태를 지정합니다.LoadStringW를 통해 문자열을 초기화하지만, 분석 단계에서는 불필요한 코드를 제거합니다.MyRegisterClass(hInstance);
MyRegisterClass: 창 클래스를 등록하는 함수입니다.if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
InitInstance: 주 창을 생성하고 표시하는 역할을 합니다.while (::GetMessage(&msg, nullptr, 0, 0))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
GetMessage: 메시지 큐에서 메시지를 가져옵니다. nullptr은 모든 메시지를 대상으로 지정합니다.TranslateMessage: 키보드 메시지를 추가적으로 변환합니다.DispatchMessage: 메시지를 처리하기 위해 창 절차(WndProc)로 보냅니다.ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GAMECODING));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = L"GameCoding";
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
WNDCLASSEXW** 구조체**: 윈도우 클래스 정보를 저장합니다.lpfnWndProc: 윈도우 메시지를 처리하는 콜백 함수로 WndProc 지정.hCursor: 마우스 커서를 설정.lpszClassName: 창 클래스 이름.RegisterClassExW: 위에서 설정한 클래스를 등록합니다.BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 전역 변수에 인스턴스 핸들 저장
RECT windowRect = { 0, 0, 800, 600 };
::AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, false);
HWND hWnd = CreateWindowW(L"GameCoding", L"Client", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, windowRect.right - windowRect.left,
windowRect.bottom - windowRect.top, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
::ShowWindow(hWnd, nCmdShow);
::UpdateWindow(hWnd);
return TRUE;
}
AdjustWindowRect: 클라이언트 영역을 원하는 크기로 맞춥니다.CreateWindowW: 윈도우를 생성합니다.CW_USEDEFAULT: 기본 위치와 크기를 설정합니다.nullptr: 부모 창과 메뉴를 설정하지 않음.LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
// 명령 처리
break;
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
WCHAR buffer[100];
::wsprintf(buffer, L"(%d , %d)", mousePosX, mousePosY);
::TextOut(hdc, 100, 100, buffer, ::wcslen(buffer));
::Rectangle(hdc, 200, 200, 400, 400);
::Ellipse(hdc, 200, 200, 400, 400);
::MoveToEx(hdc, 300, 300, nullptr);
::LineTo(hdc, 400, 400);
::LineTo(hdc, 500, 300);
EndPaint(hWnd, &ps);
break;
case WM_MOUSEMOVE:
mousePosX = LOWORD(lParam);
mousePosY = HIWORD(lParam);
::InvalidateRect(hWnd, nullptr, TRUE);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
WM_PAINT: 창을 다시 그릴 때 호출됩니다.::TextOut: 텍스트 출력.::Rectangle, ::Ellipse: 사각형과 원 그리기.::MoveToEx, ::LineTo: 선 그리기.WM_MOUSEMOVE: 마우스 이동 이벤트 처리.LOWORD(lParam), HIWORD(lParam): X, Y 좌표를 분리.::InvalidateRect: 강제로 WM_PAINT 호출.WM_DESTROY: 애플리케이션 종료 메시지를 전달.기본 메시지 루프의 한계
GetMessage는 메시지가 없으면 대기 상태로 들어갑니다.WM_PAINT 사용의 한계