Testgetriebene Entwicklung für komplexe Spiele

8

Ich programmiere ein Spiel in meiner Freizeit, aber ich bin meistens noch ein Anfänger, wenn es um Programmierung geht. Es tut mir leid, wenn diese Frage nicht zum Thema gehört oder wenn sie für andere nicht hilfreich ist, aber hoffentlich wird sie es sein.

Ich habe viel Zeit damit verbracht, Bücher über das Design von Code sowie verschiedene Methoden und Ansätze für das Codieren zu lesen. Im Verlauf dieser Forschung stoße ich immer wieder auf das Konzept der testgetriebenen Entwicklung. Die Leute, die diese Idee vertreten, scheinen normalerweise sehr leidenschaftlich darüber zu sein. Ich glaube, dass es die Geschwindigkeit und Effizienz des Schreibens von Software verbessern kann. Zeit ist eine sehr wertvolle Ressource, daher würde ich lieber lernen, die Dinge am besten zu machen, als mich durchzumischen, ohne mein Wissen über das Programmierhandwerk zu erweitern.

Wie auch immer, möglicherweise weil ich ein Anfänger bin, kann ich mir nicht vorstellen, wie man testgetriebene Entwicklung auf Spiele anwendet. Ich habe ein paar Artikel zu diesem Thema gefunden, aber sie waren nicht sehr hilfreich. Die meisten Beispiele für Unit-Tests, die ich gesehen habe, sind sehr einfache Beispiele für Boilerplates oder Beispiele für Software, die überhaupt nicht wie ein Spiel ist.

In meiner eigenen Codierung versuche ich, es mit einer ähnlichen Denkweise wie die testgetriebene Entwicklung anzugehen, obwohl ich sicher bin, dass es nicht als TDD qualifiziert ist. Ich schreibe die Mindestmenge an Code, um zu versuchen, die Funktion zu implementieren, die ich dem Spiel hinzufüge, und teste das Spiel dann sofort, um festzustellen, ob es funktioniert. Wenn die Dinge nicht so laufen, wie ich es beabsichtigt habe, nehme ich sofort Änderungen vor, um sie näher an das zu bringen, was ich will. Wenn es nicht funktioniert oder defekt ist und ich die Fehler durch Lesen des Codes nicht finden kann, gehe ich die Methoden im Debugger durch, bis ich das unerwartete Verhalten finde, und entferne es dann. Was ich damit sagen will, ist, dass ich das Spiel ständig teste, so ziemlich nach jeder inkrementellen Änderung. Testen treibt meine Entwicklung an. Der "Unit Test" ist in meinem Kopf,

Weiter zu meiner eigentlichen Frage. Wie kann man Unit-Tests für ein komplexes Spiel schreiben? Mit komplex meine ich mit vielen neuen Aspekten des Gameplays, so dass das Fleisch des Gameplays aus der Interaktion zwischen den vielen verschiedenen Elementen im Spiel in Kombination mit den Entscheidungen des Spielers hervorgeht. Zum Beispiel ein schurkenhaftes RPG mit einer prozeduralen Welt. Welche Art von Unit-Tests würde man für ein solches Spiel schreiben? Wie könnte man eine testgetriebene Entwicklung auf ein solches Spiel anwenden?

Bazola
quelle
2
Dieser König der Frage könnte besser zum Game Dev Abschnitt geeignet sein: gamedev.stackexchange.com
glampert
1
Es ist erwähnenswert, dass die testgetriebene Entwicklung Sie dazu ermutigt, Ihr Design in kleine überschaubare Einheiten zu unterteilen. Ich verwende Unit-Tests, um Logik zu testen, die möglicherweise sogar für die Funktionalität im Projekt verwendet wird oder nicht. Stattdessen dient der Zweck manchmal dazu, das Konzept selbst zu testen. Suchen Sie nach ausgereiften Open-Source-Spielen, um gute Beispiele dafür zu finden, wie Unit-Tests in der
Spieleentwicklung

Antworten:

12

Unit-Tests testen das Gameplay nicht . Es gibt keine programmatischen Kriterien, um festzustellen, ob ein Spiel Spaß macht oder ein Level die richtige Schwierigkeit ist. Unit-Tests testen, ob Ihr schurkenhafter Mapgen tatsächlich ein Level mit einer Treppe nach oben und einer Treppe nach unten erzeugt. Es wird getestet, ob Ihre Belastungsregeln so eingestellt sind, dass sich Ihr Charakter tatsächlich langsamer bewegt, wenn er gewichtet wird. Dadurch wird sichergestellt, dass Ihr Charakter keine 50 Hüte tragen kann . Dadurch wird sichergestellt, dass die Mechanik alle relativ isoliert korrekt implementiert ist.

Telastyn
quelle
1
Ihre Antwort hilft mir, die Dinge ein wenig besser zu verstehen, aber nicht vollständig. Nach meinem Verständnis sollten die Tests zuerst geschrieben werden, damit es sich wirklich um eine testgetriebene Entwicklung handelt. Schreiben Sie also fehlgeschlagene Tests, schreiben Sie Code, um ihn zu bestehen, und korrigieren Sie dann den Code. Wie kann dies angewendet werden, um zu testen, ob ein Mapgen eine Ebene mit Treppen nach oben und unten erzeugt? Welche Art von Unit-Test würde die TDD-Anforderungen erfüllen?
Bazola
1
@ Bazola - Ich fürchte, ich verstehe nicht? Sie schreiben einen Test, um den Mapgen anzurufen, und prüfen dann, ob das Ergebnis Treppen hoch und runter hat. Das lässt sich nicht kompilieren, da Sie weder ein Mapgen noch das Konzept der Treppe haben. Also machst du die. Dann lässt du den Mapgen tatsächlich die Kriterien erfüllen ...
Telastyn
Das macht Sinn. Sehr geschätzt!
Bazola
4
Relevant: TDD nicht unbedingt bedeuten , dass Ihre Einheit Tests der einzige Fahrer in der Entwicklung sind. Sie können das "Laufwerk" starten, indem Sie einen fehlerhaften "Akzeptanz" - und / oder Integrationstest auf hoher Ebene schreiben, aus dem Sie möglicherweise eine Lösung entwickeln und Ihren ersten fehlgeschlagenen Komponententest schreiben. Ich bin mir jedoch ehrlich gesagt nicht sicher, was Es braucht einen aussagekräftigen, automatisierten Abnahmetest für ein nicht triviales Spiel.
Svidgen
2

Es ist schwierig, Komponententests für Code zu schreiben, der nicht deterministisch ist. Wenn Sie Code mit Zufallszahlen haben, können Sie keinen Komponententest schreiben, der ein erwartetes Ergebnis bestätigt.

Unit-Tests eignen sich daher besser für den deterministischen Code. Wenn ich einer Methode diese Eingaben gebe, erwarte ich diese Ausgaben. Als Beispiel: Wenn ein Kämpfer mit 15 Stärken mit seinem Zweihand-Breitschwert einen untoten Ghul mit 10 Rüstungen erfolgreich trifft, erwarte ich 8 Schaden. Der nicht deterministische Teil (ob der Treffer erfolgreich war oder nicht) kann nicht unbedingt einem Unit-Test unterzogen werden, aber was danach passiert, kann sein. Selbst wenn die Schadensmenge voraussichtlich in einem bestimmten Bereich liegt, können Sie dies testen.

Wenn Sie Schwierigkeiten haben, Code zum Schreiben von Komponententests zu finden, müssen Sie eine Umgestaltung vornehmen, damit die deterministische Logik in Methoden oder Klassen isoliert ist. Wirf zuerst die Würfel, um den Erfolg zu bestimmen, und übergebe dann die relevanten Eingaben (Klasse, Stärke, Rüstung usw.) an eine testbare Methode.

Bei Ihrem Kommentar zum Unit-Test im Kopf geht es beim Unit-Test nicht nur um frisch geschriebenen Code. Es geht auch darum, darauf zu vertrauen, dass der Code auch nach unvermeidlichen Änderungen noch funktioniert .

Sam Jones
quelle
3
Eine Möglichkeit zum Unit-Test-Code, der Zufälligkeit verwendet, besteht darin, ihn viele Male auszuführen und zu überprüfen, ob die Ergebnisse statistisch in etwa der erwarteten Verteilung entsprechen. Wenn ein Angriff 10 + 2W6 Schaden verursachen soll, führen Sie den Code 1000 Mal aus und überprüfen, ob kein Ergebnis größer als 22, nicht kleiner als 12 und eine grob glockenförmige Verteilung in diesem Bereich vorliegt.
Philipp
1
Sie können diese Methode auch auf komplexere Situationen anwenden, z. B. um sicherzustellen, dass ein Charakter der Stufe 1 in etwa 90% der Fälle einen simulierten Kampf gegen einen Kobold gewinnt.
Philipp
3
Wenn ein Teil Ihres Codes Zufallszahlen verwendet, abstrahieren Sie normalerweise Ihren Zufallszahlengenerator in einen Dienst ( IRandomNumberGenerator), und alles, was Zufallszahlen verwenden muss, akzeptiert einen Verweis auf diese Dienstschnittstelle in ihrem Konstruktor. Wenn Ihr Test dann dieses Objekt erstellt, um einen Komponententest auszuführen, injiziert er ein Objekt MockRandomNumberGenerator, das einen festen bekannten Zahlenstrom ausgibt. Dann haben Sie einen wiederholbaren Test. Die gleiche Idee ist nützlich für alles, was das aktuelle Datum / die aktuelle Uhrzeit abrufen oder Informationen von einem Webdienst herunterladen muss - fügen Sie einfach einen Scheindienst ein.
Scott Whitlock
... dann können Sie einen separaten Test schreiben, der statistische Methoden verwendet, um die tatsächliche Funktionsweise Ihrer tatsächlichen Implementierung von zu überprüfen RandomNumberGenerator.
Scott Whitlock
Ich würde abstimmen, wenn ich könnte. Statistische Merkmale des Ergebnisses sollen für den Zufallsalgorithmus getestet werden.
Riga