Ein allgemeines Muster bei der Programmierung ist das Erstellen einer Datendarstellung eines Konzepts, ähnlich Charakterbefehlen, die du weitergeben und als Daten in deinem Code behandeln kannst. In diesem Minispiel müssen Befehle als Daten behandelt werden, die aus der UI-Interaktion generiert und zur Ausführung an den Charakter übergeben werden.
In diesem Projekt wird ein Befehl als abstrakte Klasse dargestellt und jeder spezifische Befehl ist eine Subklasse dieser Befehlsklasse, wie forward_command und turnright_command. Die Verwendung einer abstrakten Klasse für den Befehl bedeutet, dass die einzigen gültigen Befehle die Subklassen sind, die nicht abstrakt sind. Wenn du versuchst, direkt eine Instanz der Befehlsklasse zu erstellen, wirst du einen Fehler erhalten, wenn du versuchst, deinen Code zu kompilieren.
Da die Charakterbefehle Unterklassen der command-Klasse sind, kannst du sie überall dort verwenden, wo die command-Klasse erwartet wird, zum Beispiel als ExecuteCommand()-Funktion des Charakters im vorherigen Schritt. Der erste Parameter in ExecuteCommand() erwartet den Befehlstyp, was bedeutet, dass du problemlos eine Instanz einer command-Subklasse als Argument verwenden kannst.
Jede Unterklasse bietet ihre eigene Implementierung von DebugString().. Wenn du also einen Befehlswert ausgibst, ist ihm der richtige Text zugeordnet, aber du kannst bei Bedarf weitere Unterschiede zu den Klassen hinzufügen.
Diese Klassen verfügen außerdem über den Bezeichner unique, sodass wir Instanzen der Klassen vergleichen können. Der Bezeichner macht sie vergleichbar.
Des Weiteren verfügen die Klassen über den Bezeichner computes, sodass du Instanzen davon im Modulbereich erstellen kannst (direkt im Commands-Modul). Das bedeutet, dass wir eine einzelne eindeutige Instanz zur Darstellung jedes Befehls erstellen können, z. B. Commands.Forward für den Vorwärtsbefehl.
Dieses Beispiel verwendet Instanzen der command-Subklassen anstelle des enum-Typs, sodass du später weitere Befehle hinzufügen kannst, indem du weitere Subklassen erstellst. Bei einem enum-Typ kannst du das Enum nach der anfänglich veröffentlichten Version des Projekts nicht ändern oder ihm weitere Werte hinzufügen, sodass der enum-Typ besser geeignet ist, wenn du davon ausgehst, dass sich deine Daten nach der Veröffentlichung deines Projekts nicht ändern werden.
Im Folgenden findest du den vollständigen Code für die Befehlsimplementierung.
# 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
Nächster Schritt
Wir haben die Befehle definiert und gezeigt, wie beliebig viele hinzugefügt werden.
Im nächsten Schritt erfährst du, wie diese Befehle in der UI verwendet werden und wie eine benutzerdefinierte UI für die Steuerung des Charakters hinzugefügt wird.