Share via


Configurar o projeto de jogo

Observação

Este tópico faz parte da série de tutoriais Criar um jogo de Plataforma Universal do Windows simples (UWP) com DirectX. O tópico nesse link define o contexto da série.

A primeira etapa no desenvolvimento do jogo é criar um projeto no Microsoft Visual Studio. Depois de configurar um projeto especificamente para desenvolvimento de jogos, você poderá reutilização como uma espécie de modelo.

Objetivos

  • Crie um novo projeto no Visual Studio usando um modelo de projeto.
  • Entenda o ponto de entrada e a inicialização do jogo examinando o arquivo de origem da classe App .
  • Veja o loop do jogo.
  • Examine o arquivo package.appxmanifest do projeto.

Criar um novo projeto no Visual Studio

Observação

Para saber mais sobre como configurar o Visual Studio para desenvolvimento em C++/WinRT, incluindo instalação e uso da VSIX (Extensão do Visual Studio) para C++/WinRT e o pacote NuGet (que juntos fornecem um modelo de projeto e suporte ao build), confira Suporte do Visual Studio para C++/WinRT.

Primeiro instale (ou atualize para) a versão mais recente da VSIX (Extensão do Visual Studio) do C++/WinRT; consulte a observação acima. Em seguida, no Visual Studio, crie um novo projeto com base no modelo de projeto aplicativo principal (C++/WinRT ). Direcione a versão mais recente em disponibilidade geral (ou seja, que não esteja em versão prévia) do SDK do Windows.

Examine a classe App para entender IFrameworkViewSource e IFrameworkView

No projeto aplicativo principal, abra o arquivo App.cppde código-fonte . No, há a implementação da classe App , que representa o aplicativo e seu ciclo de vida. Nesse caso, é claro, sabemos que o aplicativo é um jogo. Mas vamos nos referir a ele como um aplicativo para falar de forma mais geral sobre como um aplicativo de Plataforma Universal do Windows (UWP) é inicializado.

A função wWinMain

A função wWinMain é o ponto de entrada para o aplicativo. Veja a aparência do wWinMain (de App.cpp).

int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    CoreApplication::Run(winrt::make<App>());
}

Criamos uma instância da classe App (esta é a única instância do Aplicativo que foi criada) e passamos isso para o método estático CoreApplication.Run . Observe que CoreApplication.Run espera uma interface IFrameworkViewSource . Portanto, a classe App precisa implementar essa interface.

As próximas duas seções deste tópico descrevem as interfaces IFrameworkViewSource e IFrameworkView . Essas interfaces (assim como CoreApplication.Run) representam uma maneira de seu aplicativo fornecer ao Windows um provedor de exibição. O Windows usa esse provedor de exibição para conectar seu aplicativo com o shell do Windows para que você possa lidar com eventos de ciclo de vida do aplicativo.

A interface IFrameworkViewSource

A classe App realmente implementa IFrameworkViewSource, como você pode ver na listagem abaixo.

struct App : winrt::implements<App, IFrameworkViewSource, IFrameworkView>
{
    ...
    IFrameworkView CreateView()
    {
        return *this;
    }
    ...
}

Um objeto que implementa IFrameworkViewSource é um objeto de fábrica do provedor de exibição . O trabalho desse objeto é fabricar e retornar um objeto de provedor de exibição .

IFrameworkViewSource tem o único método IFrameworkViewSource::CreateView. O Windows chama essa função no objeto que você passa para CoreApplication.Run. Como você pode ver acima, a implementação App::CreateView desse método retorna *this. Em outras palavras, o objeto App retorna a si mesmo. Como IFrameworkViewSource::CreateView tem um tipo de valor retornado de IFrameworkView, a classe App também precisa implementar essa interface. E você pode ver que ele faz na listagem acima.

A interface IFrameworkView

Um objeto que implementa IFrameworkView é um objeto de provedor de exibição . E agora fornecemos ao Windows esse provedor de exibição. É o mesmo objeto App que criamos no wWinMain. Portanto, a classe App serve como fábrica do provedor de exibição e provedor de exibição.

Agora o Windows pode chamar as implementações da classe App dos métodos de IFrameworkView. Nas implementações desses métodos, seu aplicativo tem a chance de executar tarefas como inicialização, começar a carregar os recursos necessários, conectar os manipuladores de eventos apropriados e receber o CoreWindow que seu aplicativo usará para exibir sua saída.

Suas implementações dos métodos de IFrameworkView são chamadas na ordem mostrada abaixo.

E aqui está o esqueleto da classe App (em App.cpp), mostrando as assinaturas desses métodos.

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() { ... }
    ...
}

Esta foi apenas uma introdução ao IFrameworkView. Entramos em muito mais detalhes sobre esses métodos e como implementá-los em Definir a estrutura do aplicativo UWP do jogo.

Arrume o projeto

O projeto aplicativo principal que você criou com base no modelo de projeto contém a funcionalidade que devemos arrumar neste momento. Depois disso, podemos usar o projeto para recriar o jogo da galeria de tiro (Simple3DGameDX). Faça as seguintes alterações na classe App em App.cpp.

  • Exclua seus membros de dados.
  • Excluir OnPointerPressed, OnPointerMoved e AddVisual
  • Exclua o código de SetWindow.

O projeto será compilado e executado, mas exibirá apenas uma cor sólida na área do cliente.

O loop do jogo

Para ter uma ideia de como é um loop de jogo, procure no código-fonte do jogo de exemplo Simple3DGameDX que você baixou.

A classe App tem um membro de dados, chamado m_main, do tipo GameMain. E esse membro é usado em App::Run desta forma.

void Run()
{
    m_main->Run();
}

Você pode encontrar GameMain::Run em GameMain.cpp. É o loop main do jogo, e aqui está um contorno muito áspero dele mostrando os recursos mais importantes.

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);
        }
    }
}

E aqui está uma breve descrição do que este loop de jogo main faz.

Se a janela do jogo não estiver fechada, envie todos os eventos, atualize o temporizador e, em seguida, renderize e apresente os resultados do pipeline gráfico. Há muito mais a dizer sobre essas preocupações, e faremos isso nos tópicos Definir a estrutura do aplicativo UWP do jogo, Renderização da estrutura I: Introdução à renderização e Renderização da estrutura II: renderização do jogo. Mas essa é a estrutura de código básica de um jogo UWP DirectX.

Examine e atualize o arquivo package.appxmanifest

O arquivo Package.appxmanifest contém metadados sobre um projeto UWP. Esses metadados são usados para empacotar e iniciar seu jogo e para envio à Microsoft Store. O arquivo também contém informações importantes que o sistema do jogador usa para fornecer acesso aos recursos do sistema que o jogo precisa executar.

Inicie o designer de manifesto clicando duas vezes no arquivo Package.appxmanifest em Gerenciador de Soluções.

captura de tela do editor de manifesto package.appx.

Para saber mais sobre o arquivo package.appxmanifest e empacotamento, veja Designer de Manifesto. Por enquanto, dê uma olhada na guia Funcionalidades e examine as opções fornecidas.

captura de tela com as funcionalidades padrão de um aplicativo direct3d.

Se você não selecionar os recursos que seu jogo usa, como o acesso à Internet para o quadro de pontuação alta global, você não poderá acessar os recursos nem os recursos correspondentes. Ao criar um novo jogo, selecione todos os recursos necessários para as APIs que seu jogo chama.

Agora vamos examinar o restante dos arquivos que vêm com o jogo de exemplo Simple3DGameDX .

Examinar outras bibliotecas importantes e arquivos de código-fonte

Se você pretende criar um tipo de modelo de projeto de jogo para si mesmo, para que possa reutilizar isso como ponto de partida para projetos futuros, então você desejará copiar GameMain.h e GameMain.cpp sair do projeto Simple3DGameDX que você baixou e adicioná-los ao seu novo projeto do Aplicativo Core. Estude esses arquivos, aprenda o que eles fazem e remova tudo o que for específico para Simple3DGameDX. Comente também qualquer coisa que dependa do código que você ainda não copiou. Apenas por meio de um exemplo, GameMain.h depende de GameRenderer.h. Você poderá remover a marca de comentário conforme copiar mais arquivos do Simple3DGameDX.

Aqui está uma breve pesquisa de alguns dos arquivos no Simple3DGameDX que você achará útil incluir em seu modelo, se estiver fazendo um. De qualquer forma, eles são igualmente importantes para entender como o próprio Simple3DGameDX funciona.

Arquivo de origem Pasta do arquivo Descrição
DeviceResources.h/.cpp Utilitários Define a classe DeviceResources , que controla todos os recursos do dispositivo DirectX. Também define a interface IDeviceNotify , usada para notificar seu aplicativo de que o dispositivo do adaptador gráfico foi perdido ou recriado.
DirectXSample.h Utilitários Implementa funções auxiliares, como ConvertDipsToPixels. ConvertDipsToPixels converte um tamanho em pixels independentes de dispositivo (DIPs) para um tamanho em pixels físicos.
GameTimer.h/.cpp Utilitários Define um temporizador de alta resolução, útil para aplicativos de renderização de jogos ou interativos.
GameRenderer.h/.cpp Renderização Define a classe GameRenderer , que implementa um pipeline de renderização básico.
GameHud.h/.cpp Renderização Define uma classe para renderizar um HUD (heads up display) para o jogo, usando Direct2D e DirectWrite.
VertexShader.hlsl e VertexShaderFlat.hlsl Sombreadores Contém o código HLSL (linguagem de sombreador de alto nível) para sombreadores de vértice básicos.
PixelShader.hlsl e PixelShaderFlat.hlsl Sombreadores Contém o código HLSL (linguagem de sombreador de alto nível) para sombreadores de pixel básicos.
ConstantBuffers.hlsli Sombreadores Contém definições de estrutura de dados para buffers constantes e estruturas de sombreador usadas para passar matrizes mvp (model-view-projection) e dados por vértice para o sombreador de vértice.
pch.h/.cpp N/D Contém O C++/WinRT, o Windows e o DirectX comuns incluem.

Próximas etapas

Neste ponto, mostramos como criar um novo projeto UWP para um jogo DirectX, examinamos algumas das partes dele e começamos a pensar em como transformar esse projeto em uma espécie de modelo reutilizável para jogos. Também examinamos algumas das partes importantes do jogo de exemplo Simple3DGameDX .

A próxima seção é Definir a estrutura do aplicativo UWP do jogo. Lá, veremos mais de perto como o Simple3DGameDX funciona.