게임 프로젝트 설정

참고 항목

이 항목은 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를 대상으로 합니다.

IFrameworkViewSourceIFrameworkView를 이해하려면 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 클래스는 해당 인터페이스를 구현해야 합니다.

이 항목의 다음 두 섹션에서는 IFrameworkViewSourceIFrameworkView 인터페이스에 대해 설명합니다. 이러한 인터페이스(및 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 메서드 구현은 아래와 같은 순서로 호출됩니다.

다음은 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.cppApp 클래스를 다음과 같이 변경합니다.

  • 데이터 멤버를 삭제합니다.
  • OnPointerPressed, OnPointerMovedAddVisual을 삭제합니다.
  • 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(매니페스트 디자이너)를 시작합니다.

screenshot of the package.appx manifest editor.

package.appxmanifest 파일 및 패키징에 대한 자세한 내용은 매니페스트 디자이너를 참조하세요. 이제 기능 탭을 살펴보고 제공된 옵션을 살펴봅니다.

screenshot with the default capabilities of a direct3d app.

전역 최고 점수 보드를 위한 인터넷 액세스 같이 게임에서 사용되는 기능을 선택하지 않으면 해당 리소스나 기능에 액세스할 수 없습니다. 새 게임을 만들 때 게임에서 호출하는 API에 필요한 기능을 선택해야 합니다.

이제 Simple3DGameDX 샘플 게임과 함께 제공되는 나머지 파일을 살펴보겠습니다.

기타 중요한 라이브러리 및 소스 코드 파일 검토

향후 프로젝트의 시작점으로 재사용할 수 있도록 일종의 게임 프로젝트 템플릿을 직접 생성하려는 경우 다운로드한 Simple3DGameDX 프로젝트에서 GameMain.hGameMain.cpp를 복사하여 새 핵심 앱 프로젝트에 추가할 수 있습니다. 이러한 파일을 연구하고 그 기능을 배우고 Simple3DGameDX와 관련된 모든 것을 제거합니다. 또한 아직 복사하지 않은 코드에 의존하는 모든 내용을 주석으로 처리합니다. 예를 들어 GameMain.hGameRenderer.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의 작동 방식을 자세히 살펴보겠습니다.