Trennung von Physik und Spielelogik vom UI-Code

12

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:

  1. Der Spieler beginnt, eine Figur zu ziehen
  2. Die Benutzeroberfläche fragt die Spiellogik nach dem zulässigen Bewegungsbereich dieser Figur und lässt den Spieler sie in diesen Bereich ziehen
  3. Spieler lässt ein Stück los
  4. Die Benutzeroberfläche fängt das Teil am Raster (so dass es sich an einer gültigen logischen Position befindet)
  5. 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:

  1. Ist eine solche Physik-Ebene üblich oder ist es typischer, dass die Spielelogik-Ebene dies tut?
  2. Würde der Code zum Fangen von Gittern und Teilen zur Benutzeroberfläche oder zur Physikebene gehören?
  3. Funktioniert eine solche Physik-Ebene normalerweise mit Pixelgrößen oder mit einer Art logischer Einheit wie meiner Spielelogik-Ebene?
  4. 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.


quelle
Hat meine Antwort geholfen, brauchten Sie weitere Informationen?
Will Marcouiller
Bitte stimmen Sie entweder zu und akzeptieren Sie die Antwort, wenn dies geholfen hat, oder teilen Sie uns Ihre Probleme bei der Implementierung einer solchen Architektur mit. Halten Sie uns jedoch über Ihre Situation auf dem Laufenden, damit wir Sie besser unterstützen können. =)
Will Marcouiller

Antworten:

3

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, layerist 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:

  1. Die GUI-Ebene: Diese Ebene enthält nur Methoden zum Anzeigen der Spielsteine ​​auf dem Spielplan, um die Interaktion zwischen dem Spiel selbst und dem Spieler zu ermöglichen.
  2. Die Gamecontroller-Ebene: Ist für die Eingaben des Spielers verantwortlich. Dies ist die Ebene, die einem Teil die Anweisung geben soll, sich in die verschiedenen Richtungen zu bewegen und den Spielplan zu fragen, ob es bei Bewegungen zu Kollisionen kommen wird und so weiter.
  3. Die Business-Ebene: Diese Ebene enthält alle Ihre Business-Klassen, dh die Teile Ihres Spiels und das Spielbrett-Objekt, das die Puzzleteile enthält.

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,MoveRightusw. 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! =)

Will Marcouiller
quelle
2
Das klingt dem Model View Controller sehr ähnlich.
07.
Um ehrlich zu sein, wird jede Beschreibung der Abstraktion der Benutzeroberfläche von der zugrunde liegenden Implementierung nach Model View Controller klingen. Dies liegt jedoch daran, dass die verwendete Terminologie und die verwendeten Techniken identisch sind (weg von Implementierungsdetails und Trennung der Benutzeroberfläche von der Implementierung). Es wird jedoch eine sehr einfache Umgebung vorausgesetzt. Hier gibt es mehrere Ebenen und in jeder Ebene befinden sich Controller. Hier reicht es nicht aus, die Ansicht vom Modell zu trennen. Sie müssen auch die Benutzerinteraktionssteuerung von der Spielsteuerung trennen.
MrCranky
Ich frage mich, was hier so komplex ist, da wir Puzzleteile auf ein begrenztes Spielbrett verschieben. Die Steuerelemente werden über die grafische Benutzeroberfläche abgerufen, was in der Tat ein guter Weg ist, und an eine Abstraktionsschicht, dh den Gamecontroller, weitergeleitet. Der Gamecontroller überprüft bei Bewegung, ob Kollisionen vorliegen, und weist das Teil an, sich zu bewegen, wenn keine Kollision festgestellt wird. Das Puzzleteil bewegt sich dann ordnungsgemäß in die angeforderte Richtung und zeigt seine neue Position über die PositionEigenschafts-Getter-Funktion an, sodass der Gamecontroller jetzt von der GUI verlangt, dass dieses verschobene Teil an dieser neuen Position angezeigt wird.
Will Marcouiller
heh, ich habe vor ein paar Monaten über "MVC" in der Spieleentwicklung gebloggt. Ja, es ist ein gutes Gateway-Konzept für diejenigen, die noch keine Erfahrung
Joel Martinez
1
Entschuldigung für die verspätete Annahme, ich war leider für eine Weile vom Projekt abgelenkt. Der Controller-Ansatz gefällt mir sehr gut, ich übernehme ihn!