Das Command Pattern in Sport Games

Das Command Pattern zählt zu meinen Favoriten unter den Design Patterns, daher wollte ich schon länger einen Artikel dazu verfassen.. Nach einer kurzen allgemeinen Erklärung des Pattern werden wir eine Handball Simulation als Anwendungsbeispiel betrachten. Damit ist es uns möglich Potentiale des Pattern hervorzuheben, die sonst wenig thematisiert werden.

Eine Übersicht über einige wenige Patterns findet ihr in meinem Vortrag zum Thema Design Patterns auf Youtube (TBP, engl.), den ich im April 2022 für Software-nahe Bio- und Chemieingenieure an der TU Dortmund gehalten habe. Außerdem empfehle ich die Bücher [1] „Design Patterns: Elements of Reusable Object-Oriented Software.“ von der „Gang of Four“, sowie [2] „Refactoring: Improving the Design of Existing Code.“ von Martin Fowler.

Motivation

Wir werden Objekte zum Kapseln von Aktionen verwenden. Damit decken wir mehrere Requirements ab, die in der Softwareentwicklung auftreten können:

  1. Gleiche Aktionen verschiedenen Auslöser. (Z.B. User Eingaben, Netzwerkanfragen, wiederkehrende Aktionen wie Autosave.)
  2. Die Sequenzen einfacher Aktionen kann verwendet werden um eine komplexere Aktion umzusetzen.
  3. Es kann gewünscht sein eine Aktion zu einem späteren Zeitpunkt auszuführen.
  4. Es kann gewünscht sein eine Aktion wieder rückgängig zu machen.

Wichtig ist auch die Einhaltung des SRP (Single Responsibility Principle). Mit Hilfe des Command Pattern trennen wir die Daten die für eine Aktion nötig sind von der Implementierung ihrer Funktionalität und vereinheitlichen so das Erzeugen von Aktionen an verschiedenen Stellen in unserer Codebase.

Klassisches Beispiel des Command Pattern als UML Diagramm

Klassisches Beispiel für ein Command Pattern von refactoring.guru [3]

Ein klassisches Beispiel für die Anwendung des Command Pattern ist ein Editor. Dabei übernehmen in einem Editor die Buttons und Shortcuts das Aufrufen, bzw. Erzeugen von Commands. Sie sind also Sender/Aufrufer. In dem Diagramm ist das Application Objekt verantwortlich für die Ausführung und ist damit der einzige Empfänger. Die einzelnen Aktionen, Copy, Cut, Paste und Undo implementieren die gemeinsame Schnittstelle Command. Mit Hilfe eines stapelartigen Containers CommandHistory wird eine Historie von Aktionen gespeichert und die Undo Funktionalität umgesetzt.

Anwendungsbeispiele: Handball Sportspiel

Statt des klassischen Beispiels „Editor“ möchte ich hier tiefer auf Möglichkeiten für Computerspiele, im speziellen in einem Sportspiel, eingehen. Eine Undo Funktion brauchen wir nicht, aber wir nehmen an, dass uns das Game folgende Reqiurements vorgibt.

  • Die Simulation erfolgt in diskreten Zeitschritten
  • Spieler, bzw. ihre Eingabegeräte und die KI können Aktionen erzeugen
  • Wiederholung von Höhepunkten, wie z.B. ein Tor
  • KI-Entwicklung und Analyse

Wir verwenden das folgende Diagramm mit einer ähnlichen Struktur wie oben.

Command Beispiel umgemünzt auf ein Handball Computerspiel

Wir gehen jetzt genauer auf die Requirements ein. Erstens, die Simulation in diskreten Zeitschritten z.B. dt=1.0 / 30.0 ist eine wichtige Annahme die Reprozierbarkeit ermöglicht, weil sonst numerische Berechnungen der Simulation von der vergangen Zeit abhängen. Das ist wichtig für andere Requirements, hat aber keinen direkten Einfluss auf das Pattern.

Das zweite Requirement fordert, dass Aktionen von verschiedenen Sendern ausgehen können wie Eingabegeräte der Spieler, die KI und möglicherweise Netzwerkpakete bei einem Onlinegame (nicht im Diagramm dargestellt).

Das dritte Requirement ist nicht allein mit dem Command Pattern umsetzbar.. Ein separates Snapshot Pattern (auch Memento), das z.B. auch für Savegames verwendet werden kann speichert alle relevanten Daten zu einem gewissen Zeitpunkt. In unserem Fall z.B. alle 30 Sekunden um Startpunkte für Wiederholungen parat zu haben. In der CommandHistory speichern wir eine Liste von Commands die dann für die Wiederholung erneut abgespielt werden.

Das vierte Requirement offenbart die Stärke des Command Pattern. Neben einer Wiederholung von Highlights ist es auch auf dessen Basis möglich Analysen durchzuführen. Ein typisches Beispiel sind Spielzüge, die zu Bugs führen oder Spielzüge, die zu häufig zum Erfolg führen, weil die KI in dem Fall noch zu schwach ist. In Kombination mit dem Pseudo-Zufallszahlen Generator kann man entweder genau einen speziellen Bug reproduzieren, oder man simuliert den Spielzug sehr häufig um zu wissen zu welchen Prozentsatz der Spieler so gegen die KI gewinnt. Damit eine schnellere Simulation als in Realzeit funktioniert sind weitere Konzepte nötig. Zum Beispiel die Entkoppelung des Rendering und der Spiellogik.

Diskussion

Wir haben das populäre Design Pattern „Command“ detailliert betrachtet. Neben dem Standardanwendungsbeispiel, Editor, haben wir das Pattern für die Architektur eines Sportgame angewendet. Zahlreiche Use-Cases können durch das Command Pattern abgebildet werden. Für eine Wiederholung bildet das Command Pattern einen wichtigen Part, es muss jedoch mit dem Pattern Snapshot kombiniert werden. Auch Use-Cases wie die Analyse verschiedener KI Implementierung gegen zuvor aufgenommen Spielzügen finden im Command Pattern eine wichtige Grundlage.

Referenzen

[1] Gamma, E., Helm, R., Johnson, R., Vlissides, J. M. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley Professional. ISBN: 0201633612
[2] Fowler, M. (1999). Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley. ISBN: 0-201-48567-2
[3] https://refactoring.guru/design-patterns/command
[4] https://refactoring.guru/design-patterns/memento

Schreibe einen Kommentar