Ich arbeite an einem einfachen blockbasierten Puzzlespiel.
Das Spiel besteht so ziemlich aus beweglichen Blöcken im Spielfeld, es ist also eine triviale Physiksimulation. Meine Implementierung ist jedoch meiner Meinung nach alles andere als ideal und ich frage mich, ob Sie mir Hinweise geben können, wie ich es besser machen kann.
Ich habe den Code in zwei Bereiche aufgeteilt: Spielelogik und Benutzeroberfläche, wie ich es bei vielen Puzzlespielen getan habe:
- Die Spiellogik ist verantwortlich für die allgemeinen Spielregeln (zB das formale Regelsystem im Schach)
- Die Benutzeroberfläche zeigt den Spielbereich und die Figuren (z. B. Schachbrett und Figuren) an und ist für Animationen (z. B. animierte Bewegung von Schachfiguren) verantwortlich.
Die Spielelogik stellt den Spielstatus als logisches Raster dar, wobei jede Einheit die Breite / Höhe einer Zelle im Raster darstellt. Bei einem Gitter der Breite 6 können Sie also einen Block der Breite 2 viermal verschieben, bis er mit der Begrenzung kollidiert.
Die Benutzeroberfläche verwendet dieses Raster und zeichnet es, indem sie logische Größen in Pixelgrößen umwandelt (dh mit einer Konstanten multipliziert). Da das Spiel jedoch kaum Spielelogik enthält, hat meine Spielelogik-Ebene [1] außer der Kollisionserkennung nicht viel zu tun. So funktioniert das:
- Der Spieler beginnt, eine Figur zu ziehen
- Die Benutzeroberfläche fragt die Spiellogik nach dem zulässigen Bewegungsbereich dieser Figur und lässt den Spieler sie in diesen Bereich ziehen
- Spieler lässt ein Stück los
- Die Benutzeroberfläche fängt das Teil am Raster (so dass es sich an einer gültigen logischen Position befindet)
- Die Benutzeroberfläche teilt der Spielelogik die neue logische Position mit (über Mutatormethoden, die ich lieber vermeiden möchte).
Damit bin ich nicht ganz zufrieden:
- Ich schreibe Komponententests für meine Spielelogikebene, aber nicht für die Benutzeroberfläche, und es stellte sich heraus, dass der gesamte heikle Code in der Benutzeroberfläche enthalten ist: Verhindern, dass das Teil mit anderen oder der Grenze kollidiert, und Fangen am Raster.
- Die Tatsache, dass die Benutzeroberfläche der Spielelogik den neuen Status mitteilt, gefällt mir nicht. Ich hätte es vorgezogen, eine
movePieceLeft()
Methode oder ähnliches wie in meinen anderen Spielen aufzurufen , aber ich bin mit diesem Ansatz nicht weit gekommen, weil Die Spielelogik weiß nichts über das Ziehen und Fangen, das in der Benutzeroberfläche möglich ist.
Ich denke, das Beste wäre, meine Spielelogik-Ebene loszuwerden und stattdessen eine Physik-Ebene zu implementieren. Ich habe ein paar Fragen dazu:
- Ist eine solche Physik-Ebene üblich oder ist es typischer, dass die Spielelogik-Ebene dies tut?
- Würde der Code zum Fangen von Gittern und Teilen zur Benutzeroberfläche oder zur Physikebene gehören?
- Funktioniert eine solche Physik-Ebene normalerweise mit Pixelgrößen oder mit einer Art logischer Einheit wie meiner Spielelogik-Ebene?
- Ich habe einmal eine ereignisbasierte Kollisionserkennung in der Codebasis eines Spiels gesehen, das heißt, der Spieler hat einfach die Figur gezogen, die Benutzeroberfläche hat das gehorsam gerendert und das Physiksystem benachrichtigt, und das Physiksystem hat eine onCollision () -Methode aufgerufen auf dem Stück, sobald eine Kollision erkannt wird. Was ist häufiger? Diesen Ansatz oder erst nach dem Bereich der legalen Bewegung fragen?
[1] Die Ebene ist wahrscheinlich nicht das richtige Wort für das, was ich meine, aber das Subsystem klingt übertrieben und die Klasse ist irreführend, da jede Ebene aus mehreren Klassen bestehen kann.
Antworten:
Ich werde versuchen, diese Frage zu beantworten, da ich verstehen kann, was Sie fragen, obwohl ich nicht viel Erfahrung in der Spieleentwicklung habe, da ich immer noch nur lerne.
Wie ich es sehe, müssen Sie den GUI-Code von Ihren Spielelogik- und Domänenobjekten, dh den Puzzleteilen, trennen. Dies sind in der Tat drei separate Schichten - und ja,
layer
ist meiner Meinung nach ein angemessener Begriff. Es wird häufig verwendet, um die Konzepte der Trennung der einzelnen Objektebenen eines Systems in voneinander unabhängige Subsysteme zu erläutern.In Bezug auf die objektorientierte Programmierung muss jedes Objekt eine Klasse sein. Jedes Puzzleteil soll also aus einer Klasse für sich und damit dem Spielplan bestehen. Der Spielplan sollte je nach Größe und Bewegungskapazität, die Sie dem Spieler geben möchten, X Puzzleteile enthalten.
Also, hier sind meine Gedanken zum Thema - ich hoffe, dass es helfen wird:
In dieser Architektur müsste die GUI-Ebene dem Spieler den Spielstatus und die Position der einzelnen Puzzleteile anzeigen. Die GUI-Schicht ist dann dafür verantwortlich, die Eingaben des Spielers abzurufen und an eine darunter liegende Gamecontroller-Schicht weiterzuleiten, die dann für die Kollisionserkennung verantwortlich ist. Wenn es keine gibt, kann das Stück angewiesen werden, sich in diese Eingaberichtung zu bewegen. Um dies zu tun, müssten Sie einfach dieses Stück nennen
MoveLeft
,MoveRight
usw. Methoden, um das Stück in Bewegung zu setzen. Sie können dem Spielplan auch mitteilen, welche Figur Sie bewegen möchten, und dann ordnet er selbst die Bewegung der Figur an, und die Figur bewegt sich dann in die gewünschte Richtung. Diese Architektur erleichtert das Testen jedes einzelnen Codeteils in den verschiedenen Ebenen und ermöglicht Ihnen dann das Testen von Einheiten, Integrationsprüfungen und Funktionsprüfungen.Ich weiß, dass dies auf den ersten Blick etwas verwirrend wirken könnte, und Gott sei Dank, wenn es nicht so ist! Sollten Sie weitere Informationen und Hilfe benötigen, wenden Sie sich bitte an uns. Ich bin gerne bereit, Ihnen so gut wie möglich zu helfen, obwohl ich ein Anfänger in der Spieleentwicklung bin.
Danke fürs Lesen! =)
quelle
Position
Eigenschafts-Getter-Funktion an, sodass der Gamecontroller jetzt von der GUI verlangt, dass dieses verschobene Teil an dieser neuen Position angezeigt wird.