> 오늘의 목표: 솔루션 내에서 각각 다른 기능을 하는 3개의 프로젝트를 생성하고, 연결시킨다.
새로 배운 지식들
새로 배운 지식들
💡
컴퓨터 메모리의 구성
- 스택: 지역변수
- 데이터 영역: 전역 변수 혹은 정적변수
- 힙: 동적할당
- 코드: 함수 등 우리가 작성한 코드가 올라가는 영역
💡
정적 라이브러리
- 정적 라이브러리는 아예 프로그램에 라이브러리의 코드를 포함시킨다(바이너리 코드 형태)
→ 그래서 exe 파일이 만들어지면 라이브러리 파일은 필요하지 않다.
- 정적 라이브러리 내부의 바이너리 코드를 사용하기 위해서는, 라이브러리를 포함시킨 프로그램 안에서 정적 라이브러리의 코드들에 대한 선언 파일(헤더 파일)을 반드시 가지고 있어야 한다.
< 사전 설정 >
> 가장 먼저 3개의 솔루션 폴더를 만들어 준다. 01. Client, 02. Engine, 03. Editor
> x64 모드로 전환한다.
01. Client2D 프로젝트 생성
01. Client2D 프로젝트 생성
- Client2D 프로젝트를 생성한다.
- 데스크톱 애플리케이션, 빈 프로젝트로 생성.
- 생성한 프로젝트를 우선 제거하고, 폴더 정리를 해준다.
- 소스코드 폴더로 들어가서, Client2D 폴더 안에 3개의 폴더를 생성한다.
Bin, BinObj, BinObjDebug, Include 폴더 생성
- 정리가 끝났으면, 기존 프로젝트 추가를 통해 도로 추가한다.
- 추가가 완료되었으면, 프로젝트 속성에 들어가 나머지 설정을 해준다.
- 모든 구성

- Debug

- Release

- main.cpp 를 생성해주고, WinMain 함수를 작성해준다.
#include <Windows.h> int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { return 0; }
02. Engine 프로젝트 추가
02. Engine 프로젝트 추가
1. ‘AR41Engine’라는 이름으로 프로젝트를 Windows 데스크톱 마법사를 통해 생성한다.
애플리케이션 종류: ‘정적 라이브러리(.lib)’
추가 옵션: 빈 프로젝트
2. 마찬가지로 프로젝트를 솔루션에서 제거 후 위처럼 폴더 작업을 해준 후 다시 포함시킨다.
3. API 프레임워크의 의 GameInfo.h와 같이, 공통으로 포함시키는 헤더를 모아놓는 헤더 파일을 생성한다.
< EngineInfo.h >
#pragma once #include <Windows.h> #include <vector> #include <list> #include <unordered_map> #include <crtdbg.h> #include <typeinfo> #include <string> #include <functional> #include <algorithm> #include <stack> #define DECLARE_SINGLE(Type) \ private:\ static Type* m_Inst;\ public:\ static Type* GetInst()\ {\ if (!m_Inst)\ m_Inst = new Type;\ return m_Inst;\ }\ static void DestroyInst()\ {\ if(m_Inst)\ {\ delete m_Inst;\ m_Inst = nullptr;\ }\ }\ private:\ Type();\ ~Type(); #define DEFINITION_SINGLE(Type) Type* Type::m_Inst = nullptr; struct Resolution { unsigned int Width; unsigned int Height; };
4. class CEngine
< CEngine.h > 전문 보기
#pragma once #include "EngineInfo.h" class CEngine { private: HINSTANCE m_hInst; HWND m_hWnd; Resolution m_WindowRS; static bool m_Loop; public: Resolution GetWindowResolution() const { return m_WindowRS; } HWND GetWindowHandle() const { return m_hWnd; } HINSTANCE GetWindowInstance() const { return m_hInst; } public: bool Init(HINSTANCE hInst, const TCHAR* Title, const TCHAR* ClassName, int IconID, int SmallIconID, unsigned int WindowWidth, unsigned int WindowHeight, unsigned int DeviceWidth, unsigned int DeviceHeight, bool WindowMode = true); int Run(); private: void Logic(); void Input(float DeltaTime); bool Update(float DeltaTime); bool PostUpdate(float DeltaTime); void Collision(float DeltaTime); void Render(float DeltaTime); private: void Register(const TCHAR* ClassName, int IconID, int SmallIconID); bool Create(const TCHAR* Title, const TCHAR* ClassName); private: static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); DECLARE_SINGLE(CEngine) };
- 싱글턴 형태로 생성한다.
- 윈도우 창을 생성하는 과정과, 메시지 루프를 처리하는 과정은 API때의 프레임워크와 동일하다.
변수
HINSTANCE m_hInst; HWND m_hWnd; Resolution m_WindowRS; static bool m_Loop;
Init()
public: bool Init(HINSTANCE hInst, const TCHAR* Title, const TCHAR* ClassName, int IconID, int SmallIconID, unsigned int WindowWidth, unsigned int WindowHeight, unsigned int DeviceWidth, unsigned int DeviceHeight, bool WindowMode = true);
- 아래의 4가지 변수는 클라이언트 영역에서 전달받을 변수이다.
- const TCHAR* Title
- const TCHAR* ClassName
- int IconID
- int SmallIconID
클라이언트 영역에서 창을 생성하고, 엔진에서는 해당 변수를 받아 창을 생성해준다.(WIN32API 때의 창 생성 과정과 동일
💡윈도우 API에서는 특별하게 설정해주지 않으면 창 크기가 곧 해상도였지만, DX에서는 창 크기와 해상도를 따로 취급하므로 두 가지를 따로 받는다.- 아래의 4가지 변수는 클라이언트 영역에서 전달받을 변수이다.
Register()
private: void Register(const TCHAR* ClassName, int IconID, int SmallIconID);
- Init 메소드 안에서 매개변수를 전달받아 호출한다.
- 상세 내용은 Win32API의 Register() 메소드와 동일하다. 매개변수만 받아서 호출해준다.
Create()
private: bool Create(const TCHAR* Title, const TCHAR* ClassName);
- Init() 안에서 호출한다. 매개변수로 받은 Title과 ClassName을 창의 이름으로 사용한다.
WndProc()
private: static bool m_Loop; static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
- 정적 함수로 선언. 메시지 루프를 처리한다.
03. Editor 프로젝트 추가
03. Editor 프로젝트 추가

다른 프로젝트들과 마찬가지로, 프로젝트를 우선 제거 후 Include, Bin, BinObj, BinObjDebug 폴더를 만들어 정리 후 다시 추가한다.
- 여기에도 main.cpp를 추가해준다. 일단 wWinMain() 함수만 생성한다.
#include <Windows.h>
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
return 0;
}
만들어진 라이브러리를 링크하기
만들어진 라이브러리를 링크하기
💡
위에서 만든 Engine 프로젝트를 빌드하면 Engine.lib 파일이 생성될 것이다.

💡
이제 이 엔진 라이브러리를 클라이언트 영역에서 포함시켜서 사용해야 한다.
- 그런데 매번 엔진 영역의 헤더 파일을 건드릴 때마다 엔진 프로젝트의 헤더 파일을 수동으로 옮겨주어야 하는데, 매번 컴파일 때마다 이 작업을 하는 것은 분명 귀찮을 것이다.
- 그러므로 엔진 영역을 컴파일할 때, 자동으로 헤더 파일을 클라이언트 영역으로 복사하도록 윈도우에 명령을 내려서 자동화를 해보자.
- 이 작업은 윈도우 일괄 처리 명령(.batch 파일)을 통해서 해줄 것이다.
💡
batch 파일에서 해야 할 일은 다음과 같다.
- 라이브러리 프로젝트에서 .lib 파일이 만들어지면 해당 파일을 ‘각 프로젝트/Bin’ 폴더 안으로 복사
- 솔루션 파일이 있는 공간에 Engine 폴더를 생성한다.
추가로 하위 폴더에 Bin 폴더와 Include 폴더를 생성한다.
- Bin 폴더에는 .lib 파일을, Include 폴더에는 .h 파일을 복사
💡
batch 파일 만들기
- .lib 파일은 빌드가 완료되면 생성된다. 그러므로 빌드 이후에 batch 파일이 동작하도록 해 주어야 한다.
💡
프로젝트에서 빌드 후 자동 실행되도록 설정하기
- 엔진 프로젝트 속성 → 빌드 이벤트 → 빌드 후 이벤트 순서로 들어가준다.
- 이러면 프로젝트가 빌드되고 나서 자동으로 솔루션 디렉토리에 있는 ‘Copy.bat’ 파일이 실행된다.
💡
Copy.bat 파일 수정하기
- Engine 프로젝트의 빌드가 끝난 뒤 .bat 파일이 실행되면, 프로젝트 파일이 있는 (SolutionDir)/Engine/Include 폴더가 기준 경로로 잡히게 된다.
- 이 경로에서 다시 솔루션 폴더 기준으로 돌아올 필요가 있다. ‘cd..’ 명령을 사용하면 한 단계 상위 폴더로 이동한다. 솔루션 디렉토리까지는 2단계 위이므로 2번 해준다.
- xcopy: 기준 폴더에 있는 특정 파일(들)을 목표 폴더로 복사하는 명령어🔑dos 명령어의 사용법이 궁금할 때는, 명령 프롬프트에서 ‘(명령어) /?’ 를 치면 사용법이 나온다. ex) xcopy /?
- 변경된 파일들에 대해서만 복사를 하면 되므로 /d를 사용한다.
- 모든 파일 및 폴더의 헤더 파일을 복사애야 하므로 /s를 사용한다.
- 기존 파일이 있으면 무조건 덮어써야 하므로 /y를 사용한다.
- Include 폴더에서 복사하는 경우 .h 파일만 복사하면 된다 → *.h만 복사
//Copy.bat
cd..
cd..
xcopy .\AR41Engine\Include\*.h .\Engine\Include\ /d /s /y
xcopy .\AR41Engine\Bin\*.* .\Engine\Bin\ /d /s /y /exclude:Exclude.txt
xcopy .\AR41Engine\Bin\*.* .\AR41Editor\Bin\ /d /s /y /exclude:Exclude.txt
xcopy .\AR41Engine\Bin\*.* .\Client2D\Bin\ /d /s /y /exclude:Exclude.txt
Uploaded by N2T
'자습' 카테고리의 다른 글
220714_2_DX Device Initialize 1 (0) | 2022.08.20 |
---|---|
220714_1_기본 틀 작업 2 (0) | 2022.08.20 |
12345678 (0) | 2022.08.20 |
TIPS (0) | 2022.08.20 |
삼항 연산자 주의점 (0) | 2022.06.02 |