Um padrão comum na programação é criar uma representação de dados de um conceito, como comandos de personagem, que pode ser passada e tratada como dados no código. Neste minijogo, os comandos precisam ser tratados como dados para serem gerados a partir da interação da IU e passados para o personagem funcionar.
Neste projeto, um comando é representado como uma classe abstrata, e cada comando específico é uma subclasse desta classe command, como forward_command e turnright_command. Usando uma classe abstrata para o comando, apenas comandos válidos são as subclasses que não são abstratas. Se você tentar criar uma instância da classe command diretamente, verá uma mensagem de erro ao tentar compilar seu código.
Os comandos de personagem são subclasses da classe command, por isso, podem ser usados em qualquer lugar onde a classe command é esperada, como na função ExecuteCommand() da etapa anterior. O primeiro parâmetro de ExecuteCommand() recebe o tipo de comando, ou seja, você pode usar uma subclasse command como um argumento sem problemas.
Cada subclasse vem com sua própria implementação de DebugString(); por isso, ao tentar imprimir um valor de comando, o texto correto estará associado a ela, mas você pode adicionar mais diferenças às classes, se necessário.
As classes também têm o especificador unique para comparar as instâncias das classes. Ou seja, é possível compará-las usando esse especificador.
As classes também têm o especificador computes, assim você poderá criar instâncias delas no escopo modular (diretamente no módulo Commands). Ou seja, podemos criar uma única instância para representar cada comando, por exemplo, Commands.Forward para o comando para frente.
Neste exemplo, são utilizadas instâncias das subclasses de comando em vez do tipo enum, assim você poderá adicionar mais comandos depois ao criar mais subclasses. Com o tipo enum, não será possível mudá-lo ou adicionar mais valores à enumeração após a versão inicial do projeto ser publicada. Por isso, o tipo enum é mais adequado quando você não espera que os dados sejam alterados após a publicação do projeto.
A seguir está o código completo para a implementação do comando.
# This file contains the data representation of all the commands that the NPC can receive
# and utilities for the data to help with debugging and troubleshooting issues.
# Each type of command that the NPC can perform will be an instance of this class.
# The class has the unique specifier to make instances of the class comparable.
# The class has the computes specifier to be able to instantiate it at module-scope.
# The class has the abstract specifier so it cannot be instantiated directly, and
# requires subclasses to implement any non-initialized functions, like DebugString().
command := class<computes><unique><abstract>:
DebugString():string
Próxima etapa
Definimos os comandos e mostramos como adicionar quantos você quiser.
Na próxima etapa, descubra como esses comandos são usados na IU e como adicionar uma IU personalizada para controlar o personagem.