운영체제/입출력 시스템 : Windows API

[게임 프로그래머 입문 올인원] Windows API 입문 : 기본 템플릿 분석 (86강)

순정법사 2024.04.01

A. 기본 템플릿 분석

Windows API는 미니 엔진을 만드는 단계라고 생각하면 됨!

1. 새 프로젝트 만들기

a. 새 프로젝트 생성하기

Windows 데스크톱 애플리케이션 클릭

 

GameCoding2로 이름 정하고 만들기

 

바로 이런 화면이 나오는데 이 템플릿을 분석할것임

 

바로 실행시키면 이런 그냥 하얀 윈도우 창이 뜸

 

 

2. main함수

 

a. 윈도우 창 정보 등록

MyRegisterClass에 대한 내용을 공부

 

이렇게 수정해주고

 

키를 수정했다면 아래 코드까지 이렇게 맞춰주기

 

여기까지의 코드

 

◽◽◽

//
//  함수: 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_GAMECODING2));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = nullptr; //메뉴 이름 MAKEINTRESOURCEW(IDC_GAMECODING2);
    wcex.lpszClassName  = L"GameCoding2";    //윈도우 클래스의 키 (이름) 
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

 

b. 윈도우 창 생성 및 애플리케이션 초기화

여기 InitInstance에 대한 내용을 공부

 

아래 있는 코드는 제거 (게임에서 단축키 사용할 일이 없음)

 

아래 이 코드까지 제거하기

 

이렇게 모르는게 있으면 msdn에 물어보기

 

위 함수를 살펴보면 윈도우 창을 어떻게 설정할 것인지에 대한 내용이 나옴

 

이렇게 800, 600으로 만들어주면 모든 크기가 메뉴바 포함해서 맞춰짐

 

따라서 게임 크기만 800, 600으로 맞추기 위해 AdjstWindowRect라는 함수를 사용

 

이 코드는 나중에 전역으로 처리할 예정!

 

💙 표준함수

표준함수는 앞에 ::를 붙여도 됨!!


어떤게 주어지는 함수(::)인지 구분하기 위해 사용 (새로 만든건 없음!!)

 

여기까지 코드

 

◽◽◽

//
//   함수: InitInstance(HINSTANCE, int)
//
//   용도: 인스턴스 핸들을 저장하고 주 창을 만듭니다.
//
//   주석:
//
//        이 함수를 통해 인스턴스 핸들을 전역 변수에 저장하고
//        주 프로그램 창을 만든 다음 표시합니다.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
   
   RECT windowRect = {0, 0, 800, 600};      //원하는 크기를 넣어주고
   ::AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, false);     //좌상우하 좌표를 윈도우 크기에 맞춰서
   //다시 windowRect에 넣어줌

   //위에서 등록된 정보를 바탕으로 윈도우를 만들어줌
   HWND hWnd = CreateWindowW(L"Test1", L"Client", WS_OVERLAPPEDWINDOW,  //이름을 Client로 바꿔주고
       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;
}

 

c. 기본 메시지 루프

메시지라는 개념을 등장시켜서 그걸 순차적으로 처리하는 방식

 

이 처리방식에 문제점이 있지만 일단 공부(문제점은 3.에 있음)

 

처음 등록할 때 WndProc의 함수를 이용해 처리해달라고 콜백이 들어가 여기로 넘어감

 

WndProc에서는 이런식으로 일을 처리하고, WM_PAINT에서 원하는 행동을 추가한다

 

💙 H가 많은 이유

특별한 의미는 없고 정수라는 의미!

여기서 사용된 HDC, HWND처럼 H~가 붙은 키워드가 많은데

 

내부를 살펴보면 스트럭트에 int가 들어가있음

 

이는 실질적으로 운영체제랑 통신을 하면서 관리하는데 

이런 창에서도 윈도우 내부에서도 정보를 관리하고 있음


이럴때마다 아이디를 구분해서 사용(핸들이라는 용어를 사용)하기 위해 정수로 관리해줌 


즉, 일정의 식별번호이고,
👉 HDC, HWND는 정수가 어떤 내용으로 사용되는지 알려주는 이름표 역할!

 

1) WM_PAINT

 

::TextOut이라는 함수를 통해 TEST를 출력해봄

 

잘 출력된다!

 

자주 사용하는 함수를 실행해보면

 

이렇게 나온다

 

WM_PAINT 함수는 윈도우 창을 껐다 키거나, 창의 크기를 수정할 때마다 함수가 호출이 됨 

따라서 게임을 만들기에는 약간 무리가 있음! 

 

2) WM_MOUSEMOVE

 

마우스가 이동하면 좌표를 받아주는 함수 

 

wParam, lParam을 이용해 사용되는데

 

lParam은 이런데이터를 가지고 / x 좌표가 아래, y좌표가 위임

 

이렇게 비트를 이용해 꺼내거나 / 메크로를 사용해서 꺼내면 됨 

 

전역변수로 마우스 포즈를 선언해주고

 

int x, int y를 각 변수로 넣어줌 (임시적으로 넣어주는 코드)

 

마우스 위치를 그려주는 코드를 WM_PAINT에 넣어주기

 

그대신 wsprint함수는 창이 변해야지만 실행됨

 

그래서 강제로 wsprint 코드를 실행시킬 수 있지만 (이런식으론 작업하지 않지만 그냥 이런 방식이 있따)

 

이렇게 깜빡깜빡 거리는 오류가 생김 (지우고 다시 그리는걸 무한반복중)

 

◽◽◽

int mousePosX;
int mousePosY; 

//
//  함수: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  용도: 주 창의 메시지를 처리합니다.
//
//  WM_COMMAND  - 애플리케이션 메뉴를 처리합니다.
//  WM_PAINT    - 주 창을 그립니다.
//  WM_DESTROY  - 종료 메시지를 게시하고 반환합니다.
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)    //메시지 번호에 따라서 실행함 
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 메뉴 선택을 구문 분석합니다:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:  //원하는 행동을 추가할 수 있음 
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...

            //마우스 위치가 바뀔때마다 그려줌 
            WCHAR buffer[100];
            ::wsprintf(buffer, L"(%d, %d)", mousePosX, mousePosY);  //포맷을 지정해 mousePosX, Y를 각각에 넣어줌
            ::TextOut(hdc, 100, 100, buffer, ::wcslen(buffer)); //길이를 구해주는 wcslen

            //사각형
            ::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); //x 좌표를 가져옴 
        mousePosY = HIWORD(lParam); //y 좌표를 가져옴
        ::InvalidateRect(hWnd, nullptr, TRUE);//강제로 WM_PAINT 만들기 
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

 

d. About 코드 삭제하기

단축키 사용 관련한 코드들은 지워도 상관없음

 

타고들어가면 여기에 정의되어있는데 이것도 꼭 삭제

 

여기까지 삭제해줘야 정상적으로 작동됨!

 

3. 문제점

a. main 루프

 

게임은 위와같이 입력, 로직, 렌더링이 3가지 단계로 무한으로 돌아가야 하는데

GetMessage로는 아무런 이벤트가 발생하지 않아도

몬스터 AI같은 것들은 처리할 수 없음 

 

강제로 이런 코드를 실행시키긴 했지만 사용 X

 

그래서 실습한 내용을 정리해줘야 함!

 

이 코드도 삭제

 

 

 


출처 : https://www.inflearn.com/course/%EA%B2%8C%EC%9E%84-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8-%EC%9E%85%EB%AC%B8-%EC%98%AC%EC%9D%B8%EC%9B%90-rookiss#curriculum

 

[게임 프로그래머 입문 올인원] C++ & 자료구조/알고리즘 & STL & 게임 수학 & Windows API & 게임 서버 |

Rookiss | 어디부터 시작할지 막막한 게임 프로그래밍 입문자를 위한 All-In-One 커리큘럼입니다. C++, 자료구조/알고리즘, STL, 게임 수학, Windows API, 게임 서버 입문으로 이어지는 알찬 커리큘럼으로

www.inflearn.com