Ich studiere derzeit Spieleentwicklung und übe das Erstellen von Spielen.
Ich benutze viel OOP in meinen Spielen. Beispielsweise ist jede abgefeuerte Rakete eine Instanz eines Missile
Objekts und wird einer Liste von Missile
Objekten hinzugefügt . Jeder Panzer im Spiel ist ein Tank
Objekt. Usw.
Darauf basiert das gesamte Programmdesign. Wenn ich beispielsweise eine Liste von Missile
Objekten habe, kann jeder Frame die Raketen bewegen, zeichnen usw. Tank
Wenn ich für jeden Panzer eine Instanz eines Objekts habe, kann ich für jeden Panzer prüfen, ob er mit etwas kollidiert usw.
Es fällt mir schwer, mir vorzustellen, wie ein Spiel (das komplexer als Pac-Man ist) in einer Nicht-OO-Sprache programmiert werden könnte. (Natürlich ohne Respektlosigkeit gegenüber Nicht-OO-Programmierern). Nicht nur, wie lange es dauern wird, sondern vor allem, wie ein Spiel auf diese Weise gestaltet werden könnte.
Ich kann mir nicht vorstellen, ein Spiel ohne objektorientierte Programmierung zu entwerfen, da mein gesamtes Verständnis für das Entwerfen eines Spielprogramms auf OOP basiert.
Ich möchte fragen: Gibt es heute Spiele, die nicht mit OOP programmiert wurden, ähnlich wie oben beschrieben? Gibt es professionelle Spiele, bei denen OOP nicht als Hauptfaktor im Entwicklungsprozess verwendet wird?
Wenn ja, können Sie mir eine Vorstellung davon geben, wie beispielsweise die Kollisionserkennung zwischen einem Panzer und N Raketen ohne OOP implementiert werden könnte?
quelle
Antworten:
Dann ist es wahrscheinlich gut für Sie, einige Programme im Nicht-OO-Stil zu schreiben. Selbst wenn Sie feststellen, dass dies für Sie nicht pragmatisch ist, werden Sie wahrscheinlich viel lernen, was Ihnen in Zukunft helfen wird.
Der OO-Stil eignet sich sehr gut für Spiele, da es bei Spielen fast immer um die Manipulation zustandsbehafteter Objekte geht. Ein Laserstrahl trifft auf den Roboter und der Zustand des Roboters ändert sich, während seine Identität gleich bleibt.
Es ist jedoch möglich, Spiele in einem funktionalen Stil zu programmieren . In einem funktionalen Stil ändert sich der Zustand nicht per se. Objekte sind unveränderlich. Anstatt Objekte zu ändern, stellen Sie die Frage, wie das Universum anders wäre, wenn ich dies ändern würde. und dann ein ganz neues Universum erzeugen, das die veränderte Eigenschaft hat. Natürlich können Sie einen Großteil des zuvor existierenden Universums wiederverwenden, da es unveränderlich ist .
Bei der funktionalen Programmierung muss jede Funktion ihren Rückgabewert ausschließlich aus den übergebenen Informationen berechnen. Es gibt keine Lesung aus "globalem Staat".
Wenn Sie dies tun, ist das grundlegende Problem, das Sie durch Ihren Kopf bekommen müssen, dass jedes Update zerstörungsfrei ist . Wenn der Laser auf den Roboter trifft, ändert sich der Zustand des Roboters nicht. Letztendlich berechnen Sie ein völlig neues Universum, das mit dem alten Universum identisch ist, außer dass der Roboter einen anderen Zustand hat. Wenn Sie dieses alte Universum brauchen, ist es immer noch da, unverändert.
Diese Reihe von Blog-Artikeln enthält weitere Gedanken zum Schreiben von Spielen in einem funktionalen Stil:
http://prog21.dadgum.com/23.html
Dieser Artikel befasst sich speziell mit Ihrer Frage "Shell trifft einen Panzer":
http://prog21.dadgum.com/189.html
Lesen Sie einfach den gesamten Blog. Es gibt gute Sachen und die Artikel sind kurz.
quelle
Jedes objektorientierte Programm kann in ein prozedurales Programm umgestaltet werden, indem alle Klassen durch Strukturen ersetzt und alle Elementfunktionen in eigenständige Funktionen konvertiert werden, die das Objekt
this
als Argument verwenden.Damit
wird
oder wenn diese Funktion trivial ist, tun Sie es einfach
Der Hauptunterschied zwischen objektorientierter Programmierung und prozeduraler Programmierung besteht darin, wie Sie Ihre Daten behandeln. In OOP sind Daten intelligent . Es verwaltet und manipuliert sich selbst. Bei der prozeduralen Programmierung sind Daten jedoch dumm . Es macht nichts alleine und muss von außen manipuliert werden.
Wenn Sie Strukturen sogar als zu objektorientiert betrachten, können Sie ein Array von Strukturen durch mehrere Arrays ersetzen, eines für alles, was eine Variable eines Flugkörpers wäre. Damit
wird
In diesem Entwurf würde eine Funktion, die eine Operation mit mehreren Attributen auf derselben Rakete ausführt, jetzt einen Array-Index anstelle eines Verweises auf eine Struktur verwenden. Die Implementierung würde folgendermaßen aussehen:
quelle
missile
aber eine Instanz eines Objekts. In Nicht-OOP gibt es keine Instanzen. Bin ich richtig? Wenn ja, wie könnten Sie setMissileVelocity (missile, 100) einstellen?Missile
, die eine Struktur mit mehreren Feldern, wiex
,y
,angle
undvelocity
.Ich mache es wie folgt:
this
. Umthis
in einem Nicht-OO-Ansatz zu verwenden, übergeben Sie einfach in jedem Fall (siehe nächster Punkt)this
als ersten Parameter.struct
s in Ihre Funktionen als übergebenthis
, aber ich finde, der beste Weg, um eine gute Cache-Leistung für produktive Objekte wie Entitäten oder Partikel zu erzielen, besteht darin, einfach einen einzelnen Index an mehrere Arrays von Grundelementen zu übergeben oder kleinestruct
s. Dieser Index wird also für jedes einzelne Datenelement der ursprünglichen Klasse verwendet. Also zum Beispiel, wenn Sie hatten...
Sie würden das durch ersetzen
Damit übergeben Sie jetzt einen Index an die Funktion, um das zu erhalten, was normalerweise wäre
this
.Beachten Sie, dass Sie möglicherweise entweder Arrays von Grundelementen wie oben oder Arrays von
struct
s verwenden möchten , je nachdem, wie Sie Ihre Daten am besten für eine gute Cache-Lokalität (Referenzlokalität) verschachteln. Eine anständige Cache-Leistung hängt natürlich viel mehr davon ab - insbesondere davon, auf welcher Sprache / Plattform Sie Ihren Code schreiben -, aber selbst in VM-basierten, dynamisch zugewiesenen Sprachen wie Java tendieren große lineare Arrays von Grundelementen dazu zeigen bessere Leistungsmerkmale als Objektinstanzen. Der Hauptgrund dafür ist, dass auf Objekte als Referenz zugegriffen wird. Dies bedeutet, dass Sie über den gesamten Speicher springen, um auf Daten zuzugreifen - ineffizient im Vergleich zum Zugriff auf Grundelemente, die von einem großen Array aus zusammenhängend sind.Weitere Informationen zum Erstellen von Entitäten usw. als Array von Strukturen oder Grundelementen finden Sie unter Mick Wests Evolve your Hierarchy .
quelle
Zusätzlich zu den vorhandenen Antworten möchten Sie möglicherweise wissen, wie Polymorphismus in einer prozeduralen Sprache ausgeführt wird.
Es gibt zwei Ansätze:
Typ speichern
In diesem Fall verfügt die Struktur über ein Feld für die Typkennung, wahrscheinlich eine Aufzählung, das mithilfe einer
switch
Anweisung überprüft wird, wenn eine typspezifische Aktion ausgeführt werden muss.Der andere Weg ist:
Speichern von Funktionszeiger
Sie haben nicht erwähnt, in welcher Programmiersprache Sie Erfahrung haben, aber in verschiedenen Sprachen werden sie auch als Rückrufe, Delegaten, Ereignisse oder Funktionen höherer Ordnung oder einfach als Funktionsobjekte bezeichnet.
In diesem Fall speichern Sie keinen Typ, sondern einen Zeiger / Verweis auf eine Funktion, die die jeweilige Aktion ausführt. Wenn typspezifische Aktionen ausgeführt werden müssen, rufen Sie diese Funktion einfach auf. Dieser sieht den gewöhnlichen virtuellen Methoden sehr ähnlich.
Indem Sie zulassen, dass jede Funktion unabhängig eingestellt wird, erhalten Sie das Strategiemuster frei.
Bezüglich Ihres letzten Absatzes mit der Kollisionserkennung. Ich denke, Sie haben wahrscheinlich mehrere Arten von Panzern und Sie haben mehrere Arten von Raketen, und jede Kombination kann möglicherweise ein anderes Ergebnis haben, wenn sie kollidieren. Wenn Sie danach suchen, haben Sie ein Problem, das noch nicht einmal von OOP-Sprachen gelöst wurde: Mehrfachversand und Mehrfachmethoden, die mehrere
this
Parameter unterschiedlichen Typs haben können. Für dieses Problem gibt es wieder zwei Alternativen:quelle