UMG
O sistema de interface de usuário da Unreal Engine é chamado de Unreal Motion Graphics ou UMG. É muito diferente do sistema uGUI padrão do Unity. A ferramenta de criação de design de interface de usuário do UMG é muito semelhante ao UI Toolkit/UI Builder do Unity, caso você já tenha trabalhado com esse sistema anteriormente. O design é abordado em detalhes na documentação oficial; as páginas Criar sua interface de usuário e Melhores práticas do UMG são particularmente úteis para desenvolvedores Unity em transição. No centro do UMG estão os widgets, que são uma série de funções e hierarquias pré-definidas que podem ser utilizadas para construir sua interface de usuário.
Common UI
Common UI é um plugin original criado pela Epic Games que utilizamos no Parrot. O Common UI configura estilos e ações "comuns" em widgets que normalmente levariam muito tempo para serem configurados manualmente de forma repetida. Um exemplo prático é detectar alterações no dispositivo de entrada e alternar automaticamente os ícones de entrada na tela. Isso levaria muito tempo para ser feito manualmente, mas o Common UI automatiza esse processo. O Common UI também é necessário para o suporte ao remapeamento de teclas de Entrada aprimorada, que é abordado com mais detalhes na documentação sobre Entrada aprimorada.
Para configurar o Common UI, primeiro é necessário habilitá-lo na janela Plugins. No menu, acesse Editar, Plugins, procure por "Common UI Plugin", habilite-o e reinicie o editor.
Acesse Configurações do projeto, Configurações gerais e altere a Classe do cliente da janela de visualização do jogo de "GameViewportClient" para "CommonGameViewportClient". Isso possibilita que os widgets Common UI recebam eventos de entrada da Engine.
Em Configurações do projeto, Configurações de entrada comuns, marque a caixa de seleção Habilitar suporte de entrada aprimorado. Isso possibilita que a Entrada aprimorada funcione com o CommonInput. CommonInput é o que lida com a entrada dentro de widgets Common UI.
Por último, é necessário habilitar alguns módulos em seu projeto para poder utilizá-los no código. Acesse o arquivo
$ProjectName.Build.cs, neste caso, o arquivoParrot.Build.cs. Adicione o seguinte à lista de PublicDependencyModuleNames:CommonInputCommonUIEnhancedInputGameplayTagsUMG
Hierarquia de widgets específicos do Parrot
A primeira classe de interface de usuário a ser analisada no Parrot é AParrotHUD. A classe HUD na Unreal Engine é um ator criado para cada jogador local e é responsável pelo HUD. Possui uma tela e uma tela de depuração nas quais é possível desenhar. Você também pode atribuí-lo como parte da configuração do seu modo de jogo. Quando você utiliza essa classe no Parrot, ela atua como um ator que possui o widget raiz a partir do qual todos os seus widgets são criados e gerenciados.
O tipo de classe para este widget proprietário é UParrotGameLayout. UParrotGameLayout é o contêiner de widgets base em C++ para todos os seus outros widgets de interface de usuário. Dentro dele, há uma lista de "camadas" que são do tipo UCommonActivatableWidgetContainerBase. Todos os outros widgets que desejar exibir serão inseridos em uma dessas camadas.
As camadas básicas que configuramos são:
Game: a camada em que o widget HUD do UMG é inserido.
GameMenu: a camada onde você insere qualquer widget que deseja exibir na parte superior do HUD.
Menu: a camada para todos os widgets da tela, como tela de pausa, tela de configurações, tela de inventário e outras telas semelhantes.
Modal: a camada para todos os pop-ups modais.
Apenas um widget por camada fica ativo por vez. É possível adicionar vários widgets de tela diferentes à camada "Menu", mas apenas o último estará ativo e será exibido.
No Parrot, também criamos uma hierarquia de classes para telas ativáveis, uma vez que todos esses widgets compartilham funcionalidades comuns e são enviados para a camada Menu. A hierarquia de classes é a seguinte:
Com essa configuração, criamos todas as telas da interface de usuário no Parrot.
Definição de estilo dos widgets
Com o plugin Common UI e a configuração da tela, você pode iniciar a personalização dos seus widgets. W_ButtonBase em Content/UI/Widgets/Common é um bom exemplo a ser observado. Ele usa os dados de estilo de ButtonStyle_Base em Content/UI/Styling. Ele usa a classe UCommonButtonStyle do Common UI. Existem diversas opções que podem ser personalizadas. Alguns exemplos são sons e pincéis baseados no estado do botão. O Common UI possui diversas classes de estilo diferentes, como esta, dependendo do widget que você está utilizando. Se precisar personalizar algo, o código do mecanismo desses widgets estilizados é um bom lugar para procurar referências.
Tela de Carregamento
A tela de carregamento no Parrot utiliza um plugin original da Epic Games: CommonLoadingScreen. Outro exemplo prático desse plugin pode ser encontrado no projeto de amostra Lyra da Epic Games. Para entender por que estamos usando esse plugin, primeiro precisamos entender os conceitos básicos de carregamento de níveis na Unreal Engine.
Existem algumas maneiras de lidar com o carregamento de níveis na UE. Uma abordagem simples é chamar o nó Abrir nível em um Blueprint. Essa função pode carregar um mapa por meio de uma string ou uma referência de objeto flexível ao mapa. Isso funciona bem para mapas simples, mas há uma ressalva. Quando essa função é invocada, o mapa é carregado de forma síncrona, o que pode causar uma lentidão perceptível, dependendo da quantidade de dados que precisam ser carregados para o novo mapa. Outro problema aqui é que um widget adicionado à janela de visualização ficará vinculado a um controle de jogador que existe no nível anterior. Quando o nível for alterado, ele será limpo como parte do processo de descarregamento do nível.
Pode ser vantajoso carregar um novo modo de jogo com base no mapa (por exemplo, nível para um jogador versus nível multijogador). Mas como manter a tela de carregamento e evitar possíveis falhas no carregamento usando Abrir nível? Vamos analisar BP_ParrotGameInstance:
Carregar o nível de forma assíncrona aqui resolve o problema de ativos não estarem prontos quando Abrir nível é chamado. Conforme mencionado no comentário, o trabalho da tela de carregamento já está sendo feito aqui também. A configuração do plugin é simples, e você pode definir o widget da tela de carregamento em Editar, Configurações do projeto, Tela de carregamento comum.
Preste atenção aos botões de alternância de depuração aqui. Testar com esses recursos no editor permite que você tenha uma melhor noção de como a tela de carregamento funcionará em uma versão empacotada.
Agora, os níveis são carregados com uma tela de carregamento. Vale a pena explorar mais BP_ParrotGameInstance por conta própria para ver como configuramos a ordem dos níveis para um único jogador e para vários jogadores. A configuração do estado do jogo é abordada na documentação Framework de jogabilidade Unreal.