Partilhar via


Fundamentos do exemplo do labirinto de mármore

Este tópico descreve as características fundamentais do projeto Marble Maze — por exemplo, como utiliza o Visual C++ no Ambiente de Execução do Windows, como é concebido e estruturado, e como é implementado. O tópico também descreve várias das convenções usadas no código.

Observação

O código de exemplo que corresponde a este documento encontra-se no exemplo de jogo DirectX Marble Maze .

Aqui estão alguns dos principais pontos que este documento discute para quando você planeja e desenvolve seu jogo da Plataforma Universal do Windows (UWP).

  • Utilize o modelo DirectX 11 App (Universal Windows - C++/CX) no Visual Studio para criar o seu jogo UWP DirectX.
  • O Tempo de Execução do Windows fornece classes e interfaces para que você possa desenvolver aplicativos UWP de uma maneira mais moderna e orientada a objetos.
  • Use referências de objeto com o símbolo hat (^) para gerenciar o tempo de vida das variáveis do Tempo de Execução do Windows, Microsoft::WRL::ComPtr para gerenciar o tempo de vida de objetos COM e std::shared_ptr ou std::unique_ptr para gerenciar o tempo de vida de todos os outros objetos C++ alocados por heap.
  • Na maioria dos casos, use o tratamento de exceções, em vez de códigos de resultado, para lidar com erros inesperados.
  • Use anotações SAL juntamente com ferramentas de análise de código para ajudar a descobrir erros em seu aplicativo.

Criando o projeto do Visual Studio

Se você tiver baixado e extraído o exemplo, poderá abrir o arquivo MarbleMaze_VS2017.sln (na pasta C++ ) no Visual Studio e terá o código na sua frente.

Quando criamos o projeto do Visual Studio para o Marble Maze, começamos com um projeto existente. No entanto, se você ainda não tiver um projeto existente que forneça a funcionalidade básica que seu jogo DirectX UWP exige, recomendamos que você crie um projeto com base no modelo de Visual Studio DirectX 11 App (Universal Windows - C++/CX) porque ele fornece um aplicativo 3D de trabalho básico. Para o fazer, siga estes passos:

  1. No Visual Studio 2019, selecione Arquivo > Novo Projeto >...

  2. Na janela Criar um novo projeto, selecione Aplicação DirectX 11 (Universal Windows - C++/CX). Se não vir esta opção, poderá não ter os componentes necessários instalados — consulte Modificar o Visual Studio 2019 adicionando ou removendo cargas de trabalho e componentes para obter informações sobre como instalar componentes adicionais.

Novo Projeto

  1. Selecione Seguintee, em seguida, introduza um nome Projeto, um de Localização para os ficheiros a armazenar e um nome Soluçãoe, em seguida, selecione Criar.

Uma configuração de projeto importante no modelo de do DirectX 11 App (Universal Windows - C++/CX) é a opção /ZW, que permite que o programa use as extensões de linguagem do Tempo de Execução do Windows. Essa opção é habilitada por padrão quando você usa o modelo do Visual Studio. Consulte as opções do compilador e vinculador () (C++/CX) para obter mais informações sobre como definir as opções de compilador no Visual Studio.

Cuidado A opção de /ZW não é compatível com opções como /clr. No caso de /clr, isso significa que não é possível direcionar o .NET Framework e o Runtime do Windows a partir do mesmo projeto de Visual C++.

 

Cada aplicativo UWP adquirido na Microsoft Store vem na forma de um pacote de aplicativo. Um pacote de aplicativo contém um manifesto de pacote, que contém informações sobre seu aplicativo. Por exemplo, você pode especificar os recursos (ou seja, o acesso necessário a recursos protegidos do sistema ou dados do usuário) do seu aplicativo. Se você determinar que seu aplicativo requer determinados recursos, use o manifesto do pacote para declarar os recursos necessários. O manifesto também permite especificar as propriedades do projeto, como rotações de dispositivos suportadas, imagens de bloco e a tela inicial. Você pode editar o manifesto abrindo Package.appxmanifest em seu projeto. Para obter mais informações sobre pacotes de aplicativos, consulte empacotamento de aplicativos.

Criando, implantando e executando o jogo

Nos menus suspensos na parte superior do Visual Studio, à esquerda do botão verde de execução, selecione a sua configuração de implementação. Recomendamos defini-lo como Depurar visando a arquitetura do seu dispositivo (x86 para 32 bits, x64 para 64 bits) e para o seu Máquina Local. Você também pode testar em uma máquina remota ou em um dispositivo conectado via USB. Em seguida, clique no botão verde 'play' para compilar e desenvolver no seu dispositivo.

Depuração; x64; Máquina Local

Controlar o jogo

Você pode usar o toque, o acelerômetro, um controlador de jogo ou o mouse para controlar o Marble Maze.

  • Use o direcional no controlador para alterar o item de menu ativo.
  • Use o toque, o botão A ou Iniciar no controle ou o mouse para escolher um item de menu.
  • Use o toque, o acelerômetro, o polegar esquerdo ou o mouse para inclinar o labirinto.
  • Use o toque, o botão A ou Iniciar no controle ou o mouse para fechar menus, como a tabela de pontuação alta.
  • Use o botão Iniciar no controle ou a tecla P no teclado para pausar ou retomar o jogo.
  • Use o botão Voltar no controle ou a tecla Home no teclado para reiniciar o jogo.
  • Quando a tabela de pontuação alta estiver visível, use o botão Voltar no controle ou a tecla Home no teclado para limpar todas as pontuações.

Convenções de código

O Tempo de Execução do Windows é uma interface de programação que você pode usar para criar aplicativos UWP que são executados somente em um ambiente de aplicativo especial. Esses aplicativos usam funções, tipos de dados e dispositivos autorizados e são distribuídos da Microsoft Store. No nível mais baixo, o Tempo de Execução do Windows consiste em uma Interface Binária de Aplicativo (ABI). A ABI é um contrato binário de baixo nível que torna as APIs do Tempo de Execução do Windows acessíveis a várias linguagens de programação, como JavaScript, as linguagens .NET e Visual C++.

Para chamar APIs do Windows Runtime a partir do JavaScript e .NET, essas linguagens exigem projeções específicas para cada ambiente linguístico. Quando se chama uma API do Windows Runtime a partir de JavaScript ou .NET, está a invocar a projeção, que, por sua vez, chama a função ABI subjacente. Embora você possa chamar as funções ABI diretamente em C++, a Microsoft também fornece projeções para C++, porque elas tornam muito mais simples consumir as APIs do Tempo de Execução do Windows, mantendo o alto desempenho. A Microsoft também fornece extensões de linguagem para o Visual C++ que suportam especificamente as projeções do Tempo de Execução do Windows. Muitas dessas extensões de linguagem se assemelham à sintaxe da linguagem C++/CLI. No entanto, em vez de direcionar o Common Language Runtime (CLR), os aplicativos nativos usam essa sintaxe para direcionar o Tempo de Execução do Windows. O modificador de referência de objeto, ou hat (^), é uma parte importante desta nova sintaxe porque permite a exclusão automática de objetos em tempo de execução por meio da contagem de referências. Em vez de chamar métodos como AddRef e Release para gerenciar o tempo de vida de um objeto do Tempo de Execução do Windows, o tempo de execução exclui o objeto quando nenhum outro componente faz referência a ele, por exemplo, quando ele deixa o escopo ou você define todas as referências para nullptr. Outra parte importante do uso do Visual C++ para criar aplicativos UWP é a palavra-chave ref new. Use ref new em vez de novo para criar objetos do Tempo de Execução do Windows com contagem de referências. Para obter mais informações, consulte Type System (C++/CX).

Importante

Você só precisa usar ^ e ref new quando criar objetos do Tempo de Execução do Windows ou componentes do Tempo de Execução do Windows. Você pode usar a sintaxe C++ padrão ao escrever o código principal do aplicativo que não usa o Tempo de Execução do Windows.

O Marble Maze usa ^ em conjunto com Microsoft::WRL::ComPtr para gerir objetos alocados no heap e minimizar vazamentos de memória. Recomendamos que você use ^ para gerenciar o tempo de vida das variáveis do Tempo de Execução do Windows, ComPtr para gerenciar o tempo de vida das variáveis COM (como quando você usa DirectX) e std::shared_ptr ou std::unique_ptr para gerenciar o tempo de vida de todos os outros objetos C++ alocados por heap.

 

Para obter mais informações sobre as extensões de linguagem disponíveis para um aplicativo UWP C++, consulte Referência de linguagem Visual C++ (C++/CX).

Tratamento de erros

O Marble Maze usa o tratamento de exceções como a principal maneira de lidar com erros inesperados. Embora o código do jogo tradicionalmente use códigos de log ou códigos de erro, como valores HRESULT de e, para indicar erros, o tratamento de exceções tem duas vantagens principais. Primeiro, pode tornar o código mais fácil de ler e manter. Do ponto de vista do código, o tratamento de exceções é uma maneira mais eficiente de propagar um erro para uma rotina que possa lidar com esse erro. O uso de códigos de erro normalmente requer que cada função propague erros explicitamente. Uma segunda vantagem é que pode configurar o depurador do Visual Studio para interromper quando uma exceção ocorrer, permitindo assim parar imediatamente no local e no contexto do erro. O Windows Runtime também faz uso extensivo do tratamento de exceções. Portanto, usando o tratamento de exceções em seu código, você pode combinar todo o tratamento de erros em um modelo.

Recomendamos que você use as seguintes convenções em seu modelo de tratamento de erros:

  • Use exceções para comunicar erros inesperados.

  • Não use exceções para controlar o fluxo de código.

  • Pegue apenas as exceções que você pode lidar e recuperar com segurança. Caso contrário, não detete a exceção e permita que o aplicativo seja encerrado.

  • Quando chamar uma rotina DirectX que retorna HRESULT, use a função DX::ThrowIfFailed. Esta função é definida em DirectXHelper.h. ThrowIfFailed lança uma exceção se o HRESULT fornecido for um código de erro. Por exemplo, E_POINTER faz com que ThrowIfFailed lance Platform::NullReferenceException.

    Quando você usa ThrowIfFailed, coloque a chamada DirectX em uma linha separada para ajudar a melhorar a legibilidade do código, conforme mostrado no exemplo a seguir.

    // Identify the physical adapter (GPU or card) this device is running on.
    ComPtr<IDXGIAdapter> dxgiAdapter;
    DX::ThrowIfFailed(
        dxgiDevice->GetAdapter(&dxgiAdapter)
        );
    
  • Embora seja recomendável evitar o uso de HRESULT para erros inesperados, é mais importante evitar o uso de manipulação de exceções para controlar o fluxo de código. Portanto, é preferível usar um HRESULT valor de retorno quando necessário para controlar o fluxo de código.

Anotações SAL

Use anotações SAL juntamente com ferramentas de análise de código para ajudar a descobrir erros em seu aplicativo.

Usando a linguagem de anotação de código-fonte (SAL) da Microsoft, você pode anotar ou descrever como uma função usa seus parâmetros. As anotações SAL também descrevem valores de retorno. As anotações SAL funcionam com a ferramenta Análise de Código C/C++ para descobrir possíveis defeitos no código-fonte C e C++. Os erros comuns de codificação relatados pela ferramenta incluem saturações de buffer, memória não inicializada, desreferências de ponteiro nulo e vazamentos de memória e recursos.

Considere o método BasicLoader::LoadMesh, que é declarado em BasicLoader.h. Esse método usa _In_ para especificar que de nome de arquivo é um parâmetro de entrada (e, portanto, só será lido), _Out_ para especificar que vertexBuffer e indexBuffer são parâmetros de saída (e, portanto, só serão gravados) e _Out_opt_ para especificar que vertexCount e indexCount são parâmetros de saída opcionais (e podem ser gravados). Como vertexCount e indexCount são parâmetros de saída opcionais, eles podem ser nullptr. A ferramenta de análise de código C/C++ examina chamadas para esse método para garantir que os parâmetros aprovados atendam a esses critérios.

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

Para executar a análise de código em seu aplicativo, na barra de menus, escolha Compilar > Executar Análise de Código na Solução. Para obter mais informações sobre análise de código, consulte Analisando a qualidade do código C/C++ usando a análise de código.

A lista completa de anotações disponíveis é definida em sal.h. Para obter mais informações, consulte Anotações SAL.

Próximos passos

Leia a estrutura do aplicativo Marble Maze para informação sobre como o código do aplicativo Marble Maze está estruturado e como a estrutura de uma aplicação UWP DirectX difere da de uma aplicação de ambiente de trabalho tradicional.