다음을 통해 공유


Marble Maze 샘플 기본 사항

이 항목에서는 프로젝트가 Windows 런타임 환경에서 Visual C++를 사용하는 방법, 프로젝트를 만들고 구성하는 방법, 프로젝트 빌드 방법 등 Marble Maze 프로젝트의 기본 특성에 대해 설명합니다. 또한 코드에 사용되는 여러 규칙에 대해서도 설명합니다.

참고 항목

이 문서에 해당하는 샘플 코드는 DirectX Marble Maze 게임 샘플에 있습니다.

다음은 이 문서에서 UWP(유니버설 Windows 플랫폼) 게임을 계획하고 개발할 경우 설명하는 몇 가지 핵심 사항입니다.

  • Visual Studio의 DirectX 11 앱(유니버설 Windows - C++/CX) 템플릿을 사용하여 DirectX UWP 게임을 만듭니다.
  • Windows 런타임 클래스와 인터페이스를 제공하므로 최신의 개체 지향 방식으로 UWP 앱을 개발할 수 있습니다.
  • 개체 참조에 캐럿(^) 기호를 사용하여 Windows 런타임 변수의 수명을 관리하고, Microsoft::WRL::ComPtr을 사용하여 COM 개체의 수명을 관리하고, std::shared_ptr 또는 std::unique_ptr을 사용하여 다른 모든 힙 할당 C++ 개체의 수명을 관리합니다.
  • 결과 코드 대신 예외 처리를 사용하여 예기치 않은 오류를 처리하는 경우가 대부분입니다.
  • 앱에서 오류를 찾는 데 도움이 되도록 SAL 주석을 코드 분석 도구와 함께 사용합니다.

Visual Studio 프로젝트 만들기

샘플을 다운로드하여 압축을 푼 경우 Visual Studio에서 MarbleMaze_VS2017.sln 파일(C++ 폴더에서)을 열어 코드를 직접 확인할 수 있습니다.

Marble Maze용 Visual Studio 프로젝트를 생성할 때 기존 프로젝트를 시작했습니다. 그러나 DirectX UWP 게임에 필요한 기본 기능을 제공하는 기존 프로젝트가 없는 경우 작동하는 기본 3D 응용 프로그램을 제공하는 Visual Studio DirectX 11 앱(유니버설 Windows - C++/CX) 템플릿을 기준으로 프로젝트를 만드는 것이 좋습니다. 이렇게 하려면 다음 단계를 수행하세요.

  1. Visual Studio 2019에서 파일 > 새로 만들기 > 프로젝트...를 선택합니다.

  2. 새 프로젝트 만들기 창에서 DirectX 11 앱(유니버설 Windows - C++/CX)를 선택합니다. 이 옵션이 표시되지 않으면 필요한 구성 요소가 설치되어 있지 않은 것일 수 있습니다. 추가적인 구성 요소 설치 방법에 대한 내용은 작업과 구성 요소를 추가하거나 제거하여 Visual Studio 2019 수정을 참조하세요.

새 프로젝트

  1. 다음을 선택한 후 Project 이름, 저장할 파일의 위치솔루션 이름 입력하고 만들기를 선택합니다.

DirectX 11 앱(유니버설 Windows - C++/CX) 템플릿의 한 가지 중요한 프로젝트 설정은 /ZW 옵션으로, 프로그램이 Windows 런타임 언어 확장을 사용할 수 있도록 합니다. 이 옵션은 Visual Studio 템플릿을 사용하는 경우 기본 사용하도록 설정됩니다. Visual Studio에서 컴파일러 옵션을 설정하는 방법에 대한 자세한 내용은 컴파일러 및 링커 옵션(C++/CX)을 참조하세요.

주의 /ZW 옵션은 /clr 같은 옵션과 호환되지 않습니다. /clr의 경우 동일한 Visual C++ 프로젝트에서 .NET Framework 및 Windows 런타임을 둘 다 대상으로 지정할 수 없다는 의미입니다.

 

Microsoft Store에서 가져오는 모든 UWP 앱은 앱 패키지 형태로 제공됩니다. 앱 패키지에는 앱에 대한 정보가 포함된 패키지 매니페스트가 포함되어 있습니다. 예를 들어, 앱의 기능(즉, 보호된 시스템 리소스 또는 사용자 데이터에 필요한 액세스)을 지정할 수 있습니다. 앱에 특정 기능이 필요하다고 판단될 경우, 패키지 매니페스트를 사용하여 필요한 기능을 선언합니다. 매니페스트를 사용하면 지원되는 디바이스 회전, 타일 이미지, 시작 화면과 같은 프로젝트 속성을 지정할 수도 있습니다. 프로젝트에서 Package.appxmanifest를 열어 매니페스트를 편집할 수 있습니다. 앱 패키지에 대한 자세한 내용은 패키징 앱을 참조하세요.

게임 빌드, 배포, 실행

Visual Studio 맨 위에 있는 드롭다운 메뉴의 녹색 재생 버튼 왼쪽에서 배포 구성을 선택합니다. 디바이스의 아키텍처(32비트는 x86, 64비트는 x64) 및 로컬 컴퓨터를 대상으로 하는 디버그로 설정하는 것이 좋습니다. 원격 컴퓨터 또는 USB를 통해 연결된 디바이스에서 테스트할 수도 있습니다. 그런 다음 녹색 재생 버튼을 클릭하여 디바이스를 빌드하고 배포합니다.

디버그; x64; 로컬 컴퓨터

게임 제어

터치, 가속도계, 게임 컨트롤러 또는 마우스를 사용하여 Marble Maze를 제어할 수 있습니다.

  • 컨트롤러의 방향 패드를 사용하여 활성 메뉴 항목을 변경합니다.
  • 터치, 컨트롤러의 A 버튼이나 시작 버튼 또는 마우스를 사용하여 메뉴 항목을 선택합니다.
  • 터치, 가속도계, 왼쪽 엄지스틱 또는 마우스를 사용하여 미로를 기울입니다.
  • 터치, 또는 컨트롤러의 A 버튼 또는 시작 버튼 또는 마우스를 사용하여 최고 점수 테이블 등의 메뉴를 닫습니다.
  • 컨트롤러의 시작 버튼 또는 키보드의 P 키를 사용하여 게임을 중지하거나 다시 시작합니다.
  • 컨트롤러의 뒤로 버튼 또는 키보드의 홈 키를 사용하여 게임을 재시작합니다.
  • 최소 점수 테이블이 표시될 때 컨트롤러의 뒤로 버튼 또는 키보드의 Home 키를 사용하여 모든 점수를 지웁니다.

코드 규칙

Windows Runtime은 특수한 애플리케이션 환경에서만 실행되는 UWP 앱을 만드는 데 사용할 수 있는 프로그래밍 인터페이스입니다. 이러한 앱은 인증된 기능, 데이터 형식 및 디바이스를 사용하고 Microsoft Store에서 배포됩니다. 가장 낮은 수준에서 Windows 런타임 ABI(애플리케이션 이진 인터페이스)로 구성됩니다. ABI는 JavaScript, .NET 언어, Visual C++와 같은 여러 프로그래밍 언어에서 Windows 런타임 API에 액세스할 수 있도록 하는 하위 수준 이진 계약입니다.

JavaScript 및 .NET에서 Windows 런타임 API를 호출하기 위해 해당 언어에는 각 언어 환경과 관련된 프로젝션이 필요합니다. JavaScript 또는 .NET에서 Windows 런타임 API를 호출할 경우 프로젝션을 호출하고, 이 프로젝션은 기본 ABI 함수를 호출합니다. C++에서 직접 ABI 함수를 호출할 수 있더라도, Microsoft는 C++에 대한 프로젝션도 제공하기 때문에 Windows 런타임 API를 훨씬 더 간단하게 사용할 수 있지만 기본 고성능을 얻을 수 있습니다. Microsoft는 특히 Windows 런타임 프로젝션을 지원하는 Visual C++에 언어 확장을 제공합니다. 이러한 언어 확장의 대부분은 C++/CLI 언어의 구문과 유사합니다. 그러나 네이티브 앱은 CLR(공용 언어 런타임)을 대상으로 하는 대신 해당 구문을 사용하여 Windows 런타임 대상으로 합니다. 개체 참조 또는 hat(^) 한정자는 참조 계산을 통해 런타임 개체를 자동 삭제할 수 있으므로 이 새 구문의 중요한 부분입니다. AddRef릴리스와 같은 메서드를 호출하여 Windows 런타임 개체의 수명을 관리하는 대신, 다른 구성 요소가 개체를 참조하지 않을 때(예: 범위를 벗어나거나 모든 참조를 nullptr로 설정한 경우) 런타임에서 개체를 삭제합니다. Visual C++를 사용하여 UWP 앱을 생성하는 또 다른 중요한 부분은 ref new 키워드. 참조 계산 Windows 런타임 개체를 생성하려면 new 대신 ref new를 사용합니다. 자세한 내용은 형식 시스템(C++/CX)을 참조하세요.

Important

Windows 런타임 개체를 만들거나 Windows 런타임 구성 요소를 만드는 경우 ^ref new만 사용하면 됩니다. Windows 런타임을 사용하지 않는 핵심 애플리케이션 코드를 작성할 때 표준 C++ 구문을 사용할 수 있습니다.

Marble Maze는 ^Microsoft::WRL::ComPtr과 함께 사용하여 힙 할당 개체를 관리하고 메모리 누수를 최소화합니다. ^을 사용하여 Windows 런타임 변수의 수명을 관리하고, ComPtr을 사용하여 COM 변수의 수명을 관리하고(예: DirectX를 사용하는 경우), std::shared_ptr 또는 std::unique_ptr을 사용하여 다른 모든 힙 할당 C++ 개체의 수명을 관리하는 것이 좋습니다.

 

C++ UWP 앱에서 사용할 수 있는 언어 확장에 대한 자세한 내용은 Visual C++ 언어 참조(C++/CX)를 참조하세요.

오류 처리

Marble Maze는 예기치 않은 오류를 처리하는 기본 방법으로 예외 처리를 사용합니다. 게임 코드는 일반적으로 HRESULT 값과 같은 로깅 또는 오류 코드를 사용하여 오류를 나타내지만 예외 처리에는 두 가지 기본 이점이 있습니다. 첫째, 코드를 더 쉽게 읽고 유지관리할 수 있습니다. 코드 관점에서 예외 처리는 오류를 해당 오류를 처리할 수 있는 루틴으로 전파하는 보다 효율적인 방법입니다. 일반적으로 오류 코드를 사용하려면 각 함수가 오류를 명시적으로 전파해야 합니다. 두 번째 장점은 예외가 발생할 때 중단되도록 Visual Studio 디버거를 구성하여 오류의 위치 및 컨텍스트에서 즉시 중지할 수 있다는 것입니다. 또한 Windows 런타임 예외 처리를 광범위하게 사용합니다. 따라서 코드에서 예외 처리를 사용하여 모든 오류 처리를 하나의 모델로 결합할 수 있습니다.

오류 처리 모델에서 다음 규칙을 사용하는 것을 권장합니다.

  • 예외를 사용하여 예기치 않은 오류를 전달합니다.

  • 예외를 사용하여 코드 흐름을 제어하지 마세요.

  • 안전하게 처리하고 복구할 수 있는 예외만 포착합니다. 그렇지 않으면 예외를 포착하지 않고 앱이 종료되도록 허용합니다.

  • HRESULT를 반환하는 DirectX 루틴을 호출하는 경우 DX::ThrowIfFailed 함수를 사용합니다. 이 함수는 DirectXHelper.h에 정의되어 있습니다. 제공된 HRESULT가 오류 코드인 경우 ThrowIfFailed에서 예외가 발생합니다. 예를 들어 E\_POINTER인 경우 ThrowIfFailed에서 Platform::NullReferenceException이 발생합니다.

    ThrowIfFailed를 사용하는 경우 다음 예제와 같이 코드 가독성을 향상시키기 위해 DirectX 호출을 별도의 줄에 배치합니다.

    // Identify the physical adapter (GPU or card) this device is running on.
    ComPtr<IDXGIAdapter> dxgiAdapter;
    DX::ThrowIfFailed(
        dxgiDevice->GetAdapter(&dxgiAdapter)
        );
    
  • 예기치 않은 오류에는 HRESULT를 사용하지 않는 것이 좋지만 코드 흐름을 제어하는 데 예외 처리를 사용하지 않는 것이 더 중요합니다. 따라서 코드 흐름을 제어하는 데 필요한 경우 HRESULT 반환 값을 사용하는 것이 좋습니다.

SAL 주석

앱에서 오류를 찾는 데 도움이 되도록 SAL 주석을 코드 분석 도구와 함께 사용합니다.

Microsoft SAL(소스 코드 주석 언어)을 사용하여 함수에서 해당 매개 변수를 사용하는 방법에 주석을 달거나 설명할 수 있습니다. SAL 주석은 반환 값도 설명합니다. SAL 주석은 C/C++ 코드 분석 도구와 함께 작동하여 C 및 C++ 소스 코드에서 가능한 결함을 검색합니다. 이 도구를 통해 보고되는 일반적인 코딩 오류에는 버퍼 오버런, 초기화되지 않은 메모리, null 포인터 역참조, 메모리 및 리소스 누수 등이 포함됩니다.

BasicLoader.h에 선언되어 있는 BasicLoader::LoadMesh 메서드를 고려합니다. 이 메서드는 _In_을 사용하여 filename을 입력 매개 변수(따라서 읽기만 수행됨)로 지정하고, _Out_을 사용하여 vertexBufferindexBuffer를 출력 매개 변수(따라서 쓰기만 수행됨)로 지정하고, _Out_opt_를 사용하여 vertexCountindexCount를 선택적 출력 매개 변수(쓰기도 가능함)로 지정합니다. vertexCountindexCount는 선택적 출력 매개 변수이므로 nullptr로 허용됩니다. C/C++ 코드 분석 도구는 이 메서드에 대한 호출을 검사하여 전달하는 매개 변수가 이러한 조건을 충족하는지 확인합니다.

void LoadMesh(
    _In_ Platform::String^ filename,
    _Out_ ID3D11Buffer** vertexBuffer,
    _Out_ ID3D11Buffer** indexBuffer,
    _Out_opt_ uint32* vertexCount,
    _Out_opt_ uint32* indexCount
    );

앱에서 코드 분석을 수행하려면 메뉴 모음에서 빌드 > 솔루션에서 코드 분석 실행을 선택합니다. 코드 분석에 대한 자세한 내용은 코드 분석을 사용하여 C/C++ 코드 품질 분석을 참조하세요.

전체 사용 가능한 주석 목록은 sal.h에 정의되어 있습니다. 자세한 내용은 SAL 주석을 참조하세요.

다음 단계

Marble Maze 응용 프로그램 코드가 구조화되는 방식 및 DirectX UWP 앱의 구조가 기존 데스크톱 응용 프로그램의 구조와 어떻게 다른지에 대한 자세한 내용은 Marble Maze 응용 프로그램 구조를 참조하세요.