게임 프로젝트 설정
참고 항목
이 항목은 DirectX를 사용하여 간단한 UWP(유니버설 Windows 플랫폼) 게임 만들기 자습서 시리즈의 일부입니다. 해당 링크의 항목은 시리즈의 컨텍스트를 설정합니다.
게임 개발의 첫 번째 단계는 Microsoft Visual Studio에서 프로젝트를 만드는 것입니다. 게임 개발을 위해 특별히 프로젝트를 구성한 후에는 나중에 이를 일종의 템플릿으로 재사용할 수 있습니다.
목표
- 프로젝트 템플릿을 사용하여 Visual Studio에서 새 프로젝트를 만듭니다.
- App 클래스의 원본 파일을 검사하여 게임의 진입점과 초기화를 이해합니다.
- 게임 루프를 보세요.
- 프로젝트의 package.appxmanifest 파일을 검토합니다.
Visual Studio에서 새 프로젝트 만들기
참고 항목
프로젝트 템플릿 및 빌드 지원을 함께 제공하는 C++/WinRT Visual Studio 확장(VSIX) 및 NuGet 패키지를 설치하고 사용하는 방법을 포함하는 C++/WinRT용 Visual Studio 개발 설정에 대한 자세한 내용은 C++/WinRT에 대한 Visual Studio 지원을 참조하세요.
먼저 최신 버전의 C++/WinRT VSIX(Visual Studio Extension)를 설치(또는 업데이트)합니다. 위의 메모를 참조하세요. 그런 다음 Visual Studio에서 Core App(C++/WinRT) 프로젝트 템플릿을 기반으로 새 프로젝트를 만듭니다. 일반적으로 사용 가능한 최신(미리 보기 아님) 버전의 Windows SDK를 대상으로 합니다.
IFrameworkViewSource 및 IFrameworkView를 이해하려면 App 클래스를 검토합니다.
핵심 앱 프로젝트에서 소스 코드 파일 App.cpp
를 엽니다. 여기에는 앱과 앱의 수명 주기를 나타내는 App 클래스가 구현되어 있습니다. 물론 이 경우 Microsoft는 앱이 게임이라는 것을 압니다. 그러나 UWP(유니버설 Windows 플랫폼) 앱이 초기화되는 방식에 대해 보다 일반적으로 설명하기 위해 이를 앱이라고 합니다.
wWinMain 함수
wWinMain 함수는 앱의 진입점입니다. wWinMain은 다음과 같습니다(App.cpp
에서).
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
CoreApplication::Run(winrt::make<App>());
}
App 클래스의 인스턴스를 만들고(생성된 App의 유일한 인스턴스임) 이를 정적 CoreApplication.Run 메서드에 전달합니다. CoreApplication.Run에는 IFrameworkViewSource 인터페이스가 필요합니다. 따라서 App 클래스는 해당 인터페이스를 구현해야 합니다.
이 항목의 다음 두 섹션에서는 IFrameworkViewSource 및 IFrameworkView 인터페이스에 대해 설명합니다. 이러한 인터페이스(및 CoreApplication.Run)는 앱이 Windows에 뷰 공급자를 제공하는 방법을 나타냅니다. Windows는 해당 뷰 공급자를 사용하여 애플리케이션 수명 주기 이벤트를 처리할 수 있도록 앱을 Windows 셸과 연결합니다.
IFrameworkViewSource 인터페이스
App 클래스는 아래 목록에서 볼 수 있듯이 실제로 IFrameworkViewSource를 구현합니다.
struct App : winrt::implements<App, IFrameworkViewSource, IFrameworkView>
{
...
IFrameworkView CreateView()
{
return *this;
}
...
}
IFrameworkViewSource를 구현하는 개체는 뷰 공급자 팩터리 개체입니다. 해당 개체의 작업은 뷰 공급자 개체를 제조하고 반환하는 것입니다.
IFrameworkViewSource에는 단일 메서드 IFrameworkViewSource::CreateView가 있습니다. Windows는 CoreApplication.Run에 전달한 개체에서 해당 함수를 호출합니다. 위에서 볼 수 있듯이 해당 메서드의 App::CreateView 구현은 *this
를 반환합니다. 즉, App 개체는 자신을 반환합니다. IFrameworkViewSource::CreateView에는 IFrameworkView의 반환 값 유형이 있으므로 App 클래스도 해당 인터페이스를 구현해야 합니다. 그리고 위의 목록을 보면 알 수 있습니다.
IFrameworkView 인터페이스
IFrameworkView를 구현하는 개체는 뷰 공급자 개체입니다. 그리고 이제 Windows에 해당 뷰 공급자를 제공했습니다. wWinMain에서 만든 것과 동일한 App 개체입니다. 따라서 App 클래스는 뷰 공급자 팩터리 및 뷰 공급자 역할을 합니다.
이제 Windows는 IFrameworkView 메서드의 App 클래스 구현을 호출할 수 있습니다. 이러한 메서드 구현에서 앱은 초기화와 같은 작업을 수행하고, 필요한 리소스를 로드하기 시작하고, 적절한 이벤트 처리기를 연결하고, 앱이 출력을 표시하는 데 사용할 CoreWindow를 받을 수 있습니다.
IFrameworkView 메서드 구현은 아래와 같은 순서로 호출됩니다.
- 초기화
- SetWindow
- 로드
- CoreApplicationView::Activated 이벤트가 발생합니다. 따라서(선택 사항) 해당 이벤트를 처리하도록 등록한 경우 OnActivated 처리기가 이때 호출됩니다.
- Run
- Uninitialize
다음은 App.cpp
에 있는 App 클래스의 골격으로, 해당 메서드의 서명을 보여 줍니다.
struct App : winrt::implements<App, IFrameworkViewSource, IFrameworkView>
{
...
void Initialize(Windows::ApplicationModel::Core::CoreApplicationView const& applicationView) { ... }
void SetWindow(Windows::UI::Core::CoreWindow const& window) { ... }
void Load(winrt::hstring const& entryPoint) { ... }
void OnActivated(
Windows::ApplicationModel::Core::CoreApplicationView const& applicationView,
Windows::ApplicationModel::Activation::IActivatedEventArgs const& args) { ... }
void Run() { ... }
void Uninitialize() { ... }
...
}
IFrameworkView에 대한 소개였습니다. 게임의 UWP 앱 프레임워크 정의에서 이러한 메서드와 메서드를 구현하는 방법에 대해 자세히 알아봅니다.
프로젝트 정리
프로젝트 템플릿에서 만든 Core App 프로젝트에는 이 시점에서 정리해야 할 기능이 포함되어 있습니다. 그런 다음 프로젝트를 사용하여 슈팅 갤러리 게임(Simple3DGameDX)을 다시 만들 수 있습니다. App.cpp
의 App 클래스를 다음과 같이 변경합니다.
- 데이터 멤버를 삭제합니다.
- OnPointerPressed, OnPointerMoved 및 AddVisual을 삭제합니다.
- SetWindow에서 코드를 삭제합니다.
프로젝트가 빌드되고 실행되지만 클라이언트 영역에는 단색만 표시됩니다.
게임 루프
게임 루프가 어떻게 생겼는지 알아보려면 다운로드한 Simple3DGameDX 샘플 게임의 소스 코드를 살펴보세요.
App 클래스에는 GameMain 유형의 m_main이라는 데이터 멤버가 있습니다. 그리고 그 멤버는 다음과 같이 App::Run에서 사용됩니다.
void Run()
{
m_main->Run();
}
GameMain.cpp
에서 GameMain::Run을 찾을 수 있습니다. 게임의 주요 루프이며, 가장 중요한 기능을 보여 주는 대략적인 개요는 다음과 같습니다.
void GameMain::Run()
{
while (!m_windowClosed)
{
if (m_visible)
{
CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
Update();
m_renderer->Render();
m_deviceResources->Present();
}
else
{
CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
}
}
다음은 이 주요 게임 루프가 수행하는 작업을 간략하게 설명한 것입니다.
게임 창이 닫히지 않은 경우 모든 이벤트를 전달하고 타이머를 업데이트한 다음 그래픽 파이프라인의 결과를 렌더링 및 표시합니다. 게임의 UWP 앱 프레임워크 정의, 렌더링 프레임워크 I: 렌더링 소개 및 렌더링 프레임워크 II: 게임 렌더링 항목에서 이러한 문제에 대해 설명하겠습니다. 그러나 이는 UWP DirectX 게임의 기본 코드 구조입니다.
package.appxmanifest 파일을 검토 및 업데이트
Package.appxmanifest 파일에는 UWP 프로젝트에 대한 메타데이터가 포함되어 있습니다. 이러한 메타데이터는 게임을 패키징 및 실행하고 Microsoft Store에 제출하는 데 사용됩니다. 이 파일에는 플레이어의 시스템이 게임을 실행하는 데 필요한 시스템 리소스에 대한 액세스를 제공하는 데 사용하는 중요한 정보도 포함되어 있습니다.
솔루션 탐색기에서 package.appxmanifest 파일을 두 번 클릭하여 Manifest Designer(매니페스트 디자이너)를 시작합니다.
package.appxmanifest 파일 및 패키징에 대한 자세한 내용은 매니페스트 디자이너를 참조하세요. 이제 기능 탭을 살펴보고 제공된 옵션을 살펴봅니다.
전역 최고 점수 보드를 위한 인터넷 액세스 같이 게임에서 사용되는 기능을 선택하지 않으면 해당 리소스나 기능에 액세스할 수 없습니다. 새 게임을 만들 때 게임에서 호출하는 API에 필요한 기능을 선택해야 합니다.
이제 Simple3DGameDX 샘플 게임과 함께 제공되는 나머지 파일을 살펴보겠습니다.
기타 중요한 라이브러리 및 소스 코드 파일 검토
향후 프로젝트의 시작점으로 재사용할 수 있도록 일종의 게임 프로젝트 템플릿을 직접 생성하려는 경우 다운로드한 Simple3DGameDX 프로젝트에서 GameMain.h
및 GameMain.cpp
를 복사하여 새 핵심 앱 프로젝트에 추가할 수 있습니다. 이러한 파일을 연구하고 그 기능을 배우고 Simple3DGameDX와 관련된 모든 것을 제거합니다. 또한 아직 복사하지 않은 코드에 의존하는 모든 내용을 주석으로 처리합니다. 예를 들어 GameMain.h
는 GameRenderer.h
에 따라 달라집니다. Simple3DGameDX에서 더 많은 파일을 복사하면 주석 처리를 제거할 수 있습니다.
다음은 템플릿을 만드는 경우 템플릿에 포함하면 유용할 Simple3DGameDX의 일부 파일에 대한 간단한 설문 조사입니다. 어떤 경우이든 Simple3DGameDX 자체의 작동 방식을 이해하는 데에도 똑같이 중요합니다.
원본 파일 | 파일 폴더 | 설명 |
---|---|---|
DeviceResources.h/.cpp | 유틸리티 | 모든 DirectX 디바이스 리소스를 제어하는 DeviceResources 클래스를 정의합니다. 또한 그래픽 어댑터 디바이스가 분실 또는 다시 만들어졌는지 애플리케이션에 알리는 데 사용되는 IDeviceNotify 인터페이스를 정의합니다. |
DirectXSample.h | 유틸리티 | ConvertDipsToPixels와 같은 도우미 함수를 구현합니다. ConvertDipsToPixels는 디바이스 독립적인 픽셀(DIP)의 길이를 실제 픽셀의 길이로 변환합니다. |
GameTimer.h/.cpp | 유틸리티 | 게임 또는 대화형 렌더링 앱에 유용한 고해상도 타이머를 정의합니다. |
GameRenderer.h/.cpp | 렌더링 | 기본 렌더링 파이프라인을 구현하는 GameRenderer 클래스를 정의합니다. |
GameHud.h/.cpp | 렌더링 | Direct2D 및 DirectWrite를 사용하여 게임의 HUD(헤드업 디스플레이)를 렌더링하는 클래스를 정의합니다. |
VertexShader.hlsl 및 VertexShaderFlat.hlsl | 셰이더 | 기본 꼭짓점 셰이더에 대한 HLSL(고수준 셰이더 언어) 코드가 포함되어 있습니다. |
PixelShader.hlsl 및 PixelShaderFlat.hlsl | 셰이더 | 기본 픽셀 셰이더에 대한 HLSL(고수준 셰이더 언어) 코드가 포함되어 있습니다. |
ConstantBuffers.hlsli | 셰이더 | MVP(Model-View-Projection) 행렬 및 정점별 데이터를 정점 셰이더에 전달하는 데 사용되는 상수 버퍼 및 셰이더 구조에 대한 데이터 구조 정의를 포함합니다. |
pch.h/.cpp | 해당 없음 | 일반적인 C++/WinRT, Windows 및 DirectX가 포함되어 있습니다. |
다음 단계
이 시점에서 DirectX 게임에 대한 새 UWP 프로젝트를 만들고, 일부 부분을 살펴보고, 해당 프로젝트를 게임에 사용할 수 있는 일종의 템플릿으로 전환하는 방법을 고려하는 방법을 살펴보았습니다. 또한 Simple3DGameDX 샘플 게임의 몇 가지 중요한 부분을 살펴보았습니다.
다음 섹션은 게임의 UWP 앱 프레임워크 정의입니다. 여기에서 Simple3DGameDX의 작동 방식을 자세히 살펴보겠습니다.