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

[게임 프로그래머 입문 올인원] Windows API 입문 : 프레임워크 제작 (87강)

순정법사 2024.04.01

A. 프레임워크 제작

1. 프레임 워크 기초 제작

a. 메인 루프 수정

저번 강의에서 설명했듯, GetMessage만으로는 모든 일 처리를 하는데 무리가 있음

따라서 메인 루프를 수정해줘야 함 

 

PeekMessage로 수정해주기!

 

◽◽◽

    MSG msg = {};

    // 3) 기본 메시지 루프입니다:
    while (msg.message != WM_QUIT)  //창을 끄면 바로 프로그램이 꺼지게 
    {
        //윈도우 메시지 큐에서 다음 메시지를 제거하지 않고 해당 메시지를 확인하는 데 사용
        if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) //메시지가 있을때가 많지 않음 
        {
            ::TranslateMessage(&msg); //추가적인 이벤트를 만들어줌
            ::DispatchMessage(&msg);  //메시지를 처리해줌 (둘이 거의 비슷)
        }
        else
        {
            //게임 로직
        }
    }

 

💙 PeekMessage를 사용하는 이유


👉 즉, 논블로킹 환경에서 메세지를 처리하고자 할 때 사용한다!

 

b. 폴더 정리하기

필터를 생성해 이렇게 만들어주기

 

중요한건 MainGame

 

Headers 폴더에 있는건 잡동사니를 넣어두는 개념이고

Default는 내가 만들지 않은 파일들을 또 넣어줌

 

c.  Defines, Enum, Types 헤더 파일 생성하기

  • Defines.h : 편하게 사용할 수 있는 메크로
  • Enums.h : 중간에 사용되는 Enums
  • Types.h : 변수를 편리하게 사용하기 위한 파일

 

위와같이 Defines, Enum, Types 헤더파일들을 생성하고

 

Types.h에는 변수를 편리하게 사용하기 위한 작업을 해주기

 

◽◽◽ Types.h

#pragma once

using int8 = __int8;
using int16 = __int16;
using int32 = __int32;
using int64 = __int64;

using uint8 = unsigned __int8;
using uint16 = unsigned __int16;
using uint32 = unsigned __int32;
using uint64 = unsigned __int64;

 

d. pch, Utils 클래스 생성하기

📁 99.Headers

 

1) pch 파일 생성하기

 

게임코딩 속성에 들어가서

 

미리 컴파일된 헤더를 사용, pch.h로 수정

 

pch이름으로 헤더와 cpp파일 생성해주고

 

pch.cpp 파일 속성에 들어가

 

미리 컴파일된 헤더를 만들기로 만들어주고

 

위에서 생성한 3개의 헤더 파일과 함께 자주 컴파일하는 헤더를 넣어주기

 

◽◽◽

#pragma once

#include "Types.h"
#include "Defines.h"
#include "Enums.h"

#include <Windows.h>
#include <vector>
#include <list>
#include <map>
#include <unordered_map>
#include <string>
#include <algorithm>
using namespace std;

 

여기까지 하면 오류가 생성되는데 

pch.h 창을 만들기 전에 생성했던 Gamecoding.cpp 파일에도 헤더를 추가하면 끝!

 

 

꼭 맨 위에다가 작성해야 함!!!!!!

 

2) Utils : 자주 활용되는 헬퍼함수들을 매핑해서 우리버전으로 사용

 

📁 99.Headers > 📄 Utils.h

 

헬퍼함수 작성, 여기서 자주사용되는 x,y 좌표는 따로 Pos로 생성하기

 

위에서 HDC를 알 수 있도록 #include <windows.h> 작성해주기 (👉 이건 추가 시점에 따라 달라짐)

 

📁 99.Headers > 📄 Types.h

 

이렇게 자주 사용되는 좌표값 Pos로 만들어주고

 

📁 99.Headers > 📄 Utils.cpp

 

이렇게 맞춰주기, 좌상우하 즉, 시계방향으로 맞춰줬음. static_cast는 x,y좌표를 float로 작성해서 그럼

 

👉 x,y 좌표는 float로 관리해야지 나중에 0.1픽셀 씩 이동할때에 문제가 생기지 않음!!

 

e. 주요 파일 Game 만들기

클래스로 Game이라는 파일을 생성해주고

 

앞으로 GameCoding2가 아닌 Game에서 코드를 침!

 

Game.h에서 기본 틀 작성해주고

 

cpp파일에도 구현부 만들어주기

 

f. GameCoding2 수정하기

여기까지 만들었다면 GameCoding2에 Game.h파일 추가해주고

나머지 코드들 정리해주기

 

Game.h 추가하고

 

전역 핸들 번호 추가

 

InitInstance에서 생기는 hwnd값을 찾으러 들어가보면

 

이렇게 저장되어있는데 이걸 g_hWnd 전역변수에 넣어주고

 

그 내용을 main 함수 내부에 생성한 game.Init() 함수에 넣어주면 된다

 

게임이 실행되어야 하니 Update, Render함수를 반복문에 넣어줌

 

 

2. 게임 틀 구현하기

a. game 코드 작성하기

Init 함수 작성해주고

 

간단하게 테스트 용

 

이렇게 잘 나온다

 

창 끄면 바로 프로그램이 꺼지게 잠시&nbsp; GameCoding2 파일 수정

 

b. Manager 매크로 생성하기

매니저는 싱글톤 방식으로 제작 

 

1) InputManager : 키보드나 마우스 입력을 처리

2) TimeManager : 프레임과 시간과 관련된 모든걸 관리

 

Manager 파일에 생성해주고

 

이렇게 만들어주고 cpp파일에 TimeManager을 정의할 수 있지만

 

이렇게 간편하게 만들 수 있음 (대신 소멸시점을 마음대로 조절 X)

 

이렇게 매니저는 항상 싱글톤으로 작성할 예정이니 매크로를 생성해준다

 

DECLARE_SINGLE이라는 이름으로 정의해주고, 클래스명을 classname, 맨끝을 \로 만들어서 정의한다

 

여기서 오타가 나서 한참 찾았다.. SINGLE로 고쳐주기!!

 

그럼 이렇게 작성할 수 있다

 

같은 방법으로 InputManager의 싱글톤도 생성해준다

 

또한 Get_SINGLE 매크로를 작성해 싱글톤을 생성하는 코드도 생성하기

 

💥 매크로는 나중에 디버깅 하기 힘들어진다는 단점은 있음 (진짜 필요한 부분에만 사용하기)

 

c. TimeManager 작성하기

시간 확인을 위해 필요한 함수들과 멤버변수들을 작성해주고

 

시간초를 가져오는 함수를 작성하고 변수들을 넣어줌 (캐스팅 하는 부분까진 알 필요 없음)

 

결국 fps를 얻기위한 노력을 한 코드!

 

◽◽◽ TimeManager.cpp

#include "pch.h"
#include "TimeManager.h"

void TimeManager::Init()
{
	//GetTickCount64 함수와 동일하지만 좀더 정확함
	::QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(& _frequency));
	::QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&_prevCount));	//cpu 클럭
}

void TimeManager::Update()
{
	uint64 currentCount;
	::QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&currentCount));

	//경과된 시간(초) = 현재시간 - 그전 시간 / 빈도
	_deltaTime = (currentCount - _prevCount) / static_cast<float>(_frequency);
	_prevCount = currentCount;

	_frameCount++; //몇번 호출이 됐는지 계속 추적
	_frameTime += _deltaTime;	//경과된 시간 추적

	if (_frameTime >= 1.f) {
		//1초동안 몇번의 함수가 호출되었는지 
		_fps = static_cast<uint32>(_frameCount / _frameTime);	//fps가 핵심!

		_frameTime = 0.f;
		_frameCount = 0;
	}
}

 

d. Game.cpp파일 작성하기

1) Manager 적용하기

 

Game.cpp파일에 매니저 넣어주고

 

타임 매니저의 Init 실행해주기

 

모두 싱글톤으로 작성

 

2) 텍스트 출력하기

 

wstring은 저번에 사용한 buffer 버전보다 더 현대적임

 

사용하기 전에 적용해야할 사항이 있음

 

GameCoding2 > 속성을 열고

 

언어 > 언어 표준을 C++ 20 으로 적용해준다

 

pch.h 파일에 format을 추가해주고

 

Game.cpp 파일의 Render()함수는 이와같이 작성한다

 

매우빠름, dt는 0.000 이라 0으로 보이는것

 

이건 무한으로 프레임을 높힌 방법이고 프레임을 고정하려면 아래와 같이 하면 됨

 

prevTick 변수를 생성하고

 

프레임도 시간을 계산해서 출력되게 하면 60프레임 정도로 나옴

 

 

e. InputManager 작성하기

먼저 키상태, 키버튼을 관리하는 enum과, 그 둘의 개수를 관리하는 enum을 생성해주고

 

InputManager에 필요한 내용을 작성해준다

 

키보드가 Update될 떄 키보드의 상태를 알려주는 코드를 작성해주고 + 마우스 좌표

 

_states는 private하니&nbsp; Update에서 만든 키의 상태를 긁을 수 있게 만든다

 

f. Game.cpp에서 InputManager 추가하기

Init 추가해주고

 

Update도 추가해준다

 

Render코드에서 마우스 좌표를 확인할 수 있도록 테스트

 

잘 나온당!

 

 

3. 메모리 릭 체크하기

메모리 릭 : new 후 delete를 안하는 것 

 

a. pch.h 파일에 추가하기

👉 메모리 누수를 감지하기 위한 CRT 라이브러리의 디버그 기능을 활성화하는 것

 

위와 같이 작성해주고

 

실행해보면 메모리 해제가 안된 애들을 알려줌

 

하나 추가하면 하나 더 생김!

 

🧡 위에서는 주소도 있는데 주소도 없는 아래같은 애들은 어디서메모리 릭이 일어난걸까?

이렇게 보면 메모리 주소도 없는 애들이 있음

 

이렇게 InputManager같은 애들때문에 생기는데

 

싱글톤에 지역의 static변수를 이용해 만들어서


👉 게임이 제거되는 시점보다 소멸이 더 늦어짐!!

 

 

 


출처 : 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 & 게임 서버 -

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

www.inflearn.com