A common pattern in programming is creating a data representation of a concept, like character commands, that you can pass around and treat as data within your code. In this minigame, commands need to be treated as data to generate from the UI interaction and pass to the character to perform.
In this project, a command is represented as an abstract class, and each specific command is a subclass of this command class, such as forward_command and turnright_command. Using an abstract class for the command means that the only valid commands are the subclasses that are not abstract. If you try to create an instance of the command class directly, you'll get an error when you try to compile your code.
Because the character commands are subclasses of the command class, you can use them anywhere the command class is expected, such as the character's ExecuteCommand() function in the previous step. The first parameter in ExecuteCommand() expects the command type, which means you can use an instance of a command subclass as the argument without issue.
Each subclass provides its own implementation of DebugString() so when you print a command value it has the correct text associated with it, but you can add more differences to the classes if you need to.
These classes also have the unique specifier so we can compare instances of the classes. This specifier makes them comparable.
The classes also have the computes specifier so you can create instances of them at module-scope (in the Commands module directly). This means we can create a single unique instance to represent each command, for example, Commands.Forward for the forward command.
This example uses instances of command subclasses instead of the enum type so you can add more commands later by creating more subclasses. With an enum type, you cannot change it or add more values to the enum after the initial published version of the project, so the enum type is better when you don't expect your data to change after you publish your project.
The following is the complete code for the command implementation.
# 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
Next Step
We've defined the commands and shown how to add as many as you want.
In the next step, learn how these commands are used in the UI and how to add a custom UI for controlling the character.