1. Main 함수
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
// TODO: 여기에 코드를 입력합니다.
// 1) 윈도우 창 정보 등록
MyRegisterClass(hInstance);
// 2) 초기화
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
MSG msg;
//3) 메인 루프
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
1) 더미 코드 ( 불필요 )
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
//~~
//단축키가 할당되어있음
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GAMECODING));
//~~
// hAccelTable의 조건도 같이 삭제
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
실행될 때 제거되는 더미 코드와 쓸모 없는 코드들을 삭제한다.
2) szWindowClass ( 중요도 낮음 )
// 전역 문자열을 초기화합니다.
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_GAMECODING, szWindowClass, MAX_LOADSTRING);
리소스 파일 내 포함된 문자열(프로그램 제목)을 초기화하는 구문이다.
szWindowClass는 MyRegisterClass 안에 포함되어 있다. 따로 설정하였다면 삭제한다.
3) 메인 루프
//3) 메인 루프
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
게임의 본격적인 코드가 들어가는 루프이다.
2. MyRegisterClass ; 윈도우 창 정보 등록
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);
}
-> 아이콘, 커서, 창을 초기화한다. RegisterClassExW 함수를 반환한다.
wcex.lpfnWndProc = WndProc;
-> 윈도우의 메시지를 처리하고 작업한다.
1) 메뉴를 제거하고 창의 이름을 바꾸기
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
// ~~
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = L"GameCoding";
// ~~
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
HWND hWnd = CreateWindowW(L"GameCoding", L"Client", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
//~~
3. InitInstance ; 초기화
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;
}
최초 초기화에 구동되는 코드이다.
hWnd와 AdjustWindowRect 함수의 값을 받는 windowRect를 사용하여 윈도우의 크기를 800 * 600으로 변경할 수 있다.
4. WndProc 함수, BeginPaint
메시지가 들어오면 윈도우 프로시져를 이용하여 해결한다.
타입의 앞자리에 h는 int를 뜻한다(커널과 프로그램 사이의 통신은 숫자로 이루어짐).
1) 문자 표현하기
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...
// 문자 그리기
::TextOut(hdc, 100, 100, L"TEST", 4);
hdc는 일종의 도화지 역할을 한다.
TestOut 함수를 사용하여 hdc, 시작 좌표(x, y), 문자열, 문자열의 길이를 적어주면 된다.
2) 그림 표현하기
// 사각형 그리기
::Rectangle(hdc, 200, 200, 400, 400);
// 원 그리기
::Ellipse(hdc, 200, 200, 400, 400);
사각형과 원은 문자와 다르게 끝나는 좌표도 적어주어야 한다.
3) 선 표현하기
// 선 그리기
::MoveToEx(hdc, 300, 300, nullptr);
::LineTo(hdc, 400, 400);
선의 시작점을 MoveToEx 함수로 지정해주고 끝점을 LineTo 함수로 지정해준다.
WM_PAINT는 화면이 움직이거나, 크기가 바뀔 때 다시 그려주도록 작동한다.
5. WndProc 함수, WM_MOUSTMOVE
case WM_MOUSEMOVE:
// lParam & 0xFFFF;
// lParam -> 16
int x = LOWORD(lParam);
int y = HIWORD(lParam);
break;
마우스의 좌표를 추적하는 함수이다.
마우스의 x 좌표는 16비트의 낮은 8비트로 나타나고, 마우스의 y 좌표는 16비트의 큰 쪽 8비트로 나타난다.
1) 마우스의 좌표를 출력하기
위의 x와 y를 전역변수로 선언한다.
int mousePosX;
int mousePosY;
case WM_MOUSEMOVE:
// lParam & 0xFFFF;
// lParam -> 16
mousePosX = LOWORD(lParam);
mousePosY = HIWORD(lParam);
::InvalidateRect(hWnd, nullptr, TRUE);
break;
InvalidateRect를 이용하여 WM_PAINT를 강제로 호출하여 매번 그려준다.
이후에 WM_PAINT를 다음과 같이 수정해준다.
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...
// 문자 그리기
WCHAR buffer[100];
::wsprintf(buffer, L"(%d, %d)", mousePosX, mousePosY);
::TextOut(hdc, 100, 100, buffer, ::wcslen(buffer));
마우스를 움직일 때마다 마우스의 좌표가 그려진다.
6. 결론
WM_PAINT는 매 프레임마다 초기화되지 않기 때문에 게임을 만들기에는 적합하지 않다.
'Windows API & 게임 수학' 카테고리의 다른 글
1-6. 오브젝트(Object) 설계 (1) - 플레이어, 투사체, ObjectManager (0) | 2023.10.17 |
---|---|
1-5. 더블 버퍼링 (Double Buffering) (0) | 2023.10.17 |
1-4. 게임을 위한 프레임워크 제작하기(3) - Scene, SceneManager (1) | 2023.10.16 |
1-3. 게임을 위한 프레임워크 제작하기(2) - TimeManager, InputManager (1) | 2023.10.16 |
1-2. 게임을 위한 프레임워크 제작하기(1) (0) | 2023.10.16 |