Exemplo do Design Pattern Command na Unity com C#
Sempre recomendo o livro Game Programming Patterns, que possui versões física e digital à venda, além de uma online gratuita disponibilizada pelo autor, Robert Nystrom. Este livro revisita os design patterns definidos na década de 1990 pela “Gangue dos Quatro”, focando no seu uso para o desenvolvimento de jogos.
O livro conta com excelentes exemplos e com pseudocódigo baseado em C/C++, além de descreve situações em que cada programming pattern pode ser utilizado. Já realizei algumas palestras sobre este assunto e utilizei este livro como base, sendo a mais recente na TDC Porto Alegre 2019. Meu objetivo com este post e, com os próximos que virão, é criar exemplos do uso de cada programming pattern na game engine Unity e com a linguagem de programação C#.
Seguindo a ordem do livro, este primeiro post será sobre o Design Pattern Command. O código deste exemplo, assim como de todos os próximos, pode ser acessado neste repositório do GitHub. Os demais posts desta série podem ser acessados neste link.
Design Pattern Command
O Command é um design pattern que tem como objetivo encapsular um método ou ação. Em uma definição muito simples pode-se dizer que é um padrão para callbacks. Um exemplo bem prático do Command é o input de um jogo. Imagine que seu jogo possui uma opção para que o jogador modifique as ações de cada botão, seja por preferencia pessoal ou acessibilidade. Com a Implementação do Command fica simples modificar o comando que um botão executa, como demonstrado no exemplo a seguir.
Implementação na Unity com C#
Neste exemplo de implementação existem duas ações possíveis para o jogador: Pular e Atirar. Para simplificar o exemplo, cada ação será apenas uma mensagem de log. O código abaixo define exatamente isso, dois comandos que podem ser executados. É importante ter uma interface neste caso, ou pelo menos uma classe base, para que o código que executar estas ações não precise necessariamente saber o tipo de cada classe derivada.
E é basicamente isso, uma interface com o método que executará uma ação e duas implementações desta interface. Agora ambas ações podem ser utilizadas em outra classe, como será demonstrado no MonoBehaviour abaixo. A classe abaixo possui dois métodos públicos executados por botões na Unity, o ButtonA()
e o ButtonB()
. Estes métodos executam qualquer comando associado com as respectivas variáveis, as quais possuem o tipo da interface ICommand
.
Quando executado, o código acima irá atribuir a ação de pular para o botão A e a ação de atirar para o botão B. Agora imagine que, neste exemplo, teremos uma opção que permite o jogador inverter os comandos dos botões. Para isso, um método como este abaixo irá alterar o comando dos botões sem a necessidade de qualquer outra modificação no código.
Este é um exemplo bem simples para explicar o conceito por trás deste programming pattern. A partir disso pode-se ver como o Command é um poderoso recurso para todo programador, pois permite alterar ações sem criar dependências no código. Existem outros exemplos interessantes para o seu uso, como um sistema de avançar e voltar no tempo onde todas as ações do jogador podem ser uma lista de comandos executados. Isso pode ser utilizado até mesmo em um editor para desfazer e refazer uma determinada ação.
Exemplo
Neste repositório do GitHub existe um exemplo utilizando o código acima, porém com 4 botões de ações do jogador e um outro botão que permite embaralhar as ações.
O Command é um padrão simples, mas que é muito poderoso quando entendido e utilizado corretamente na arquitetura de um jogo. Imagine ter que adicionar novos botões no exemplo acima, ou um hardware diferente para o input. Tudo isso pode ser feito de forma prática com o Command. Este programming pattern é um bom aliado para tornar um jogo mais acessível, permitindo a customização do controle do jogo pelo jogador.