Welche Programmiermuster sind für die Spieleentwicklung hilfreich? [geschlossen]

129

Ich habe ein paar Bücher über Entwurfsmuster und habe einige Artikel gelesen, kann aber nicht intuitiv herausfinden, welche Entwurfsmuster für die Entwicklung von Spielen nützlich sind.

Ich habe beispielsweise ein Buch mit dem Namen ActionScript 3 mit Entwurfsmustern, in dem verschiedene Entwurfsmuster wie Model View Controller, Singleton, Factory, Command usw. beschrieben sind.

Als Neueinsteiger kann ich nicht herausfinden, welches von diesen nützlich sein würde, oder tatsächlich, ob eines von diesen die Entwurfsmuster sind, die ich lernen und zu verwenden versuchen sollte. Vielleicht gibt es andere, spielprogrammspezifischere Designmuster, die mir nicht einmal bewusst sind?

Wenn Sie Erfahrung mit einem bestimmten Designmuster in der Spieleentwicklung haben, würde ich es gerne hören. Das Begründen, warum es verwendet wurde, Codebeispiele oder Online-Ressourcen wären ebenfalls sehr hilfreich, wenn Sie sie haben. Momentan interessiere ich mich am meisten für ActionScript 3 und C ++ Implementierungen, könnte aber definitiv von Erfahrungen und Beispielen aus jeder Sprache profitieren.

Vielen Dank!

jcurrie33
quelle
"Vielleicht gibt es andere, spielprogrammspezifischere Designmuster, die mir nicht einmal bewusst sind?" - Nein, diese Muster sind allgemein gehalten und betreffen eher die Erweiterung der Fähigkeiten der von Ihnen verwendeten Sprache. Sie haben nichts mit dem Gegenstand Ihrer Bewerbung zu tun.
Kylotan,
3
@Kylotan Aus meiner begrenzten Sicht scheint es, dass, da jedes Entwurfsmuster ein bestimmtes Problem auf effektive Weise angehen soll, einige Entwurfsmuster aufgrund ihrer Natur nützlicher wären als andere, wenn man ein bestimmtes Problemset zugrunde legt, und zwar in diesem Fall: Diese Probleme sind einzigartig für die Spieleentwicklung. Sicher gibt es einige Richtlinien oder basierend auf Ihrer Erfahrung bestimmte Designmuster, die Sie häufiger verwenden als andere?
jcurrie33
Bevor jemand
losgeht
@ BlueRaja-DannyPflughoeft Der Secon-Link ist ungültig. Können Sie es erneut senden
Emadpres

Antworten:

163

Nun zu einer weniger flippigen Antwort mit einigen Vorschlägen. Nehmen Sie diese nicht als Implementierungsempfehlungen, sondern als Beispiele für eine mögliche Verwendung.

  • Builder: Einrichten einer komponentenbasierten Entität auf der Grundlage von Daten für jede Komponente
  • Factory-Methode: Erstellen Sie NPCs oder GUI-Widgets basierend auf einer Zeichenfolge, die aus einer Datei gelesen wurde
  • Prototyp: Speichern Sie ein generisches 'Elf'-Zeichen mit anfänglichen Eigenschaften und erstellen Sie Elf-Instanzen, indem Sie es klonen.
  • Singleton: Dieser Raum wurde absichtlich leer gelassen.
  • Adapter: Integrieren Sie eine optionale Bibliothek von Drittanbietern, indem Sie diese in eine Ebene einbetten, die Ihrem vorhandenen Code entspricht. Sehr nützlich bei DLLs.
  • Zusammengesetzt: Erstellen Sie ein Szenendiagramm mit darstellbaren Objekten, oder erstellen Sie eine grafische Benutzeroberfläche aus einem Widgets-Baum
  • Fassade: Vereinfachen Sie komplexe Bibliotheken von Drittanbietern, indem Sie eine einfachere Benutzeroberfläche bereitstellen, die Ihnen später das Leben erleichtert.
  • Fliegengewicht: Speichern Sie die gemeinsamen Aspekte eines NPC (z. B. Modelle, Texturen, Animationen) getrennt von den einzelnen Aspekten (z. B. Position, Gesundheit) auf weitgehend transparente Weise
  • Proxy: Erstellen Sie auf einem Client kleine Klassen, die größere, komplexere Klassen auf einem Server darstellen, und leiten Sie Anforderungen über das Netzwerk weiter.
  • Verantwortungskette: Behandeln Sie Eingaben wie eine Kette von Bearbeitern, z. globale Tasten (z. B. für Screenshots), dann die GUI (z. B. für den Fall, dass ein Textfeld fokussiert ist oder ein Menü angezeigt wird), dann das Spiel (z. B. zum Bewegen eines Charakters)
  • Befehl: Fassen Sie die Spielfunktionen als Befehle zusammen, die in eine Konsole eingegeben, gespeichert und wiedergegeben oder sogar als Skript zum Testen des Spiels verwendet werden können
  • Vermittler: Implementieren Sie Spieleinheiten als kleine Vermittlerklasse, die mit verschiedenen Komponenten arbeitet (z. B. Lesen aus der Gesundheitskomponente, um die Daten an die KI-Komponente weiterzuleiten).
  • Beobachter: Lassen Sie die renderbare Darstellung eines Charakters Ereignisse aus der logischen Darstellung abhören, um die visuelle Darstellung bei Bedarf zu ändern, ohne dass die Spielelogik etwas über das Rendern von Code wissen muss
  • Status: NPC AI als einen von mehreren Status speichern, z. Angreifen, wandern, fliehen. Jedes kann seine eigene update () -Methode und alle anderen Daten haben, die es benötigt (z. B. das Speichern des Charakters, vor dem es angreift oder flüchtet, des Gebiets, in dem es wandert usw.).
  • Strategie: Wechseln Sie für Ihre A * -Suche zwischen verschiedenen Heuristiken, je nachdem, in welchem ​​Terrain Sie sich befinden, oder verwenden Sie sogar dasselbe A * -Framework, um sowohl die Pfadfindung als auch eine allgemeinere Planung durchzuführen
  • Template-Methode: Richten Sie eine generische "Kampf" -Routine mit verschiedenen Hook-Funktionen ein, um jeden Schritt zu handhaben, z. Verringern Sie die Munition, berechnen Sie die Trefferchance, lösen Sie Treffer oder Fehlschläge, berechnen Sie den Schaden, und jede Art von Angriffsfertigkeit implementiert die Methoden auf ihre eigene Art und Weise

Einige Muster wurden aufgrund mangelnder Inspiration ausgelassen.

Kylotan
quelle
Eine sehr aufschlussreiche Diskussion über Singletons finden Sie hier: misko.hevery.com/2008/08/25/root-cause-of-singletons
Andrew Wang
+1 für das Strategiemuster. Ich habe es für den oben angegebenen genauen Zweck verwendet (Einstecken verschiedener A * -Heuristiken).
Mike Strobel
1
danke für diese antwort, diese klingen eher wie design
muster
Große Liste von Beispielen. Trotz chronischem Missbrauch des Singleton-Musters (global state in disguise) gibt es legitime Verwendungen: Wenn es eine Ressource darstellt, von der Sie tatsächlich nur eine haben (oder wollen). Dies kann so etwas wie das Einbinden von Hardware (z. B. Tastatur / Maus) oder das Einbinden einer Bibliothek sein, die nicht wiedereintrittsfähig ist (es kommt vor, dass nicht alle Sprachen über magische Synchronisationsschlüsselwörter verfügen).
charstar
11
Ich würde immer noch keine Singletons für Hardwareressourcen verwenden - Elemente, von denen Sie glauben, dass Sie nur eines haben werden, das sich später vermehrt, genau wie es Grafikkarten und Monitore im Laufe der Jahre taten. In ähnlicher Weise müssen Sie unter einigen APIs 2 Joysticks lesen, um 1 Gamepad zu verstehen. Also würde ich sagen, wenn Sie nur eines von etwas benötigen, instanziieren Sie einfach ein einzelnes, erzwingen Sie keine willkürlichen Einschränkungen, die wahrscheinlich nicht notwendig sind.
Kylotan
59

Ich habe genau zu diesem Thema ein Buch geschrieben: Game Programming Patterns . Die darin enthaltenen Kapitel könnten für Sie hilfreich sein.

munificent
quelle
2
+1 Ich hatte gehofft, dass jemand darauf verlinkt hat und ich sehe, dass der Autor das hat! Die dortige Beschreibung des Komponentenmusters war sehr hilfreich, und ich finde es gut, dass Sie versuchen, vollständige Codebeispiele zu verwenden, um dies zu demonstrieren.
CodexArcanum
2
Ja - ich erinnere mich, deinen Link vor ein paar Jahren gelesen zu haben. Sie sollten diese Artikel beenden!
EinTagwird
2
Jetzt ist das Buch fertig :)
Dienstag,
1
Eine erstaunliche Ressource, die mir geholfen hat, meine vorhandenen Programmierkenntnisse in Programmierkenntnisse für Spiele umzusetzen. Danke fürs Schreiben!
Diese Erklärung der Spielprogrammierungsmuster hat mir tatsächlich geholfen, -Designmuster- so zu verstehen, wie es kein Musterbuch für Software-Design wirklich getan hat! Dies ist zum Teil die Kraft der Spieleentwicklung (konkrete Beispiele in einer Sprache, die mich anspricht und es mir ermöglicht, meine Entwicklung insgesamt zu verbessern), zum Teil jedoch, weil das Schreiben so hervorragend ist.
Kzqai
19

Eine Sache, die Brandon Eich mit Coders at Work hatte, ist, dass Muster Hacks und Workarounds sind: [Patterns] zeigen eine Art von Defekt in der Sprache. Diese Muster sind nicht frei. Es gibt kein kostenloses Mittagessen. Wir sollten also nach der Evolution in der Sprache suchen, die die richtigen Elemente hinzufügt.

Als Spieleprogrammierer haben wir selten die Möglichkeit, die von uns verwendeten Sprachen weiterzuentwickeln, aber wir können lernen, unseren eigenen Stil weiterzuentwickeln, um unsere Sprache und Anforderungen besser zu erfüllen. Muster sind ein Teil davon, aber das Nicht-Verwenden von Mustern ist ein anderer Teil, zumal, wie Brandon sagt, Muster selten ohne nennenswerte Kosten für Leistung, Speicher oder Code-Agilität auskommen. MVC ist einfach kein großartiges Muster für viele Dinge in Spielen. Singleton ist eine Problemumgehung für statische C ++ - Initialisierungsregeln, die Sie wahrscheinlich sowieso nicht ausführen sollten. Factory vereinfacht die Erstellung komplizierter Objekte - vielleicht sollten Ihre Objekte zunächst einfacher sein. Die gängigen Muster sind Werkzeuge, auf die wir zurückgreifen können, wenn wir sie brauchen Um etwas Komplexes zu managen, sollten wir uns nicht danach sehnen, am Anfang etwas Komplexes zu bauen.

Guter (Spiel-) Code verwendet möglicherweise Muster oder nicht. Wenn es Muster verwendet, sind sie ein großartiges Kommunikationswerkzeug, um anderen Programmierern die Codestruktur auf einer hohen, sprachunabhängigen Ebene zu erklären. Wenn Sie der Meinung sind, dass der Code besser ist, ohne ein Muster zu verwenden, schlagen Sie sich nicht darüber hinweg - wahrscheinlich ist es das auch.

user744
quelle
4
Ja, eines der Dinge, die im ursprünglichen Buch deutlich gemacht wurden (aber oft übersehen werden), ist, dass sie, wenn sie für C anstatt für C ++ / Smalltalk geschrieben worden wären, möglicherweise ein "Vererbungsmuster" und aus dem gleichen Grund einige Sprachen enthalten hätten enthält möglicherweise einige der bereits eingebauten GoF-Muster.
Kylotan
13
Das andere, was im Originalbuch oft übersehen wurde (das Originalbuch von Alexander, nicht GoF), war, dass Muster ein Werkzeug für die Kommunikation sind , nicht für die Umsetzung . Sie ermöglichen Designern die Kommunikation über die Implementierung auf einer höheren Ebene und werden identifiziert, weil sie wiederkehren, nicht notwendigerweise, weil sie nach Möglichkeit verwendet werden sollten.
1
Die bloße Terminologie kann Ihnen jedoch dabei helfen, das Problem zu klären und zu erkennen, wann ein solcher Ansatz eine gute Lösung darstellt. Die besten Muster wurden im Laufe der Zeit in der Regel von erfahrenen Fachleuten verfeinert, und weniger qualifizierte Fachkräfte würden diese Muster nicht selbst entdecken, ohne dass es diese kodifizierten Beispiele gäbe.
Kylotan,
Ich bin damit einverstanden, dass die Terminologie großartig ist, und ein Teil der Definition eines Musters ist, dass es eine gute wiederkehrende Lösung für ein Problem ist. Leider finden die weniger qualifizierten Arbeitskräfte meistens Singleton und wenden es auf jedes Problem an, auch wenn es noch kein Problem gibt.
Danke für diese Antwort; Ich bin erleichtert zu lesen, dass Designmuster erstellt wurden, um Probleme zu lösen, die durch das Design der Software verursacht wurden. Ich denke, dass die Struktur einer ganzen großen Software von Anfang bis Ende durchdacht werden sollte, bevor man anfängt, etwas zu programmieren. Es ist nicht immer möglich, Funktionen gleichzeitig zu implementieren. Manchmal müssen Sie über die einzelnen Funktionen nachdenken und prüfen, ob sie nicht mit der globalen Struktur der Software in Konflikt geraten oder die Funktionsweise der Software beeinträchtigen sich verhalten. Das Aufteilen von Aufgaben auf mehrere Programmierer kann manchmal zu Widersprüchen führen ...
jokoon 01.10.10
7

Natürlich sind, wie andere gesagt haben, alle Muster unter den richtigen Umständen nützlich, und ein Teil des Lernens, wie man sie verwendet, besteht darin, zu lernen, wann man sie verwendet. Das ausgezeichnete Buch Core Techniques and Algorithms in Game Programming von Daniel Sanchez-Crespo Dalmau listet jedoch sechs Programmiermuster und sechs Usability-Muster als besonders nützlich für die Spielprogrammierung auf.

Programmierung:

  • Singleton: Ich hasse diesen nicht wie viele Leute; Es kann für Dinge wie den Einzelspieler- oder den Tastaturleser verwendet werden.
  • Fabrik: Ermöglicht das effiziente Erstellen und Zerstören von Objekten.
  • Strategie: Ermöglicht das elegante Ändern von KI-Strategien.
  • Raumindex: Hilft bei der Durchführung von Abfragen zu Raumdatensätzen.
  • Zusammengesetzt: Richtet eine nützliche Objekterbe ein.
  • Fliegengewicht: Gibt das Gedächtnis frei, indem Dinge wie identische Feinde erzeugt werden.

Benutzerfreundlichkeit:

  • Schild: Schützt vor versehentlicher Aktivierung dramatischer Aktionen.
  • Status: Visuelle Hinweise auf den Welt- / UI-Status.
  • Automatische Deaktivierung des Modus: Das Spiel wird intuitiver.
  • Magnetismus: Autoaiming und einfache Einheitenauswahl.
  • Fokus: Ablenkende UI-Elemente eliminieren.
  • Fortschritt: Universell nützlich.

Das Buch geht natürlich detaillierter auf diese ein.

Gregory Avery-Weir
quelle
Danke für die Eingabe! Mir war dieses Buch nicht bekannt, aber ich werde es jetzt aufgrund Ihres Beitrags untersuchen. Danke noch einmal!
jcurrie33
2
Singleton für den Tastaturleser ist genau die Situation, in der ich fragen muss: Können Sie es wirklich nicht einfach zu einem globalen Zeiger machen, der früh in Ihrer Hauptfunktion gesetzt wird? Haben Sie jemals versehentlich zwei Tastaturleser instanziiert?
Bitte hasse den Singleton. Es macht zwei Dinge schlecht. Globaler Zugang und Arität. Häufig denken Entwickler an globalen Zugriff == Singleton. Es gibt nur sehr wenige Probleme, die einen echten Singleton erfordern, und möglicherweise noch einige, die eleganter sind, wenn sie mit einem Singleton gelöst werden.
deft_code
7

Entitätssysteme sind eine nette Art von Muster. Es ist nicht gerade ein Entwurfsmuster, da es kein strenges OOP ist. Sie können es jedoch mit OOP mischen.

Einige gute Links (Start von oben für Intro):

Wernight
quelle
3
"Es ist nicht gerade ein Entwurfsmuster, da es nicht schwierig ist, OOP." Entwurfsmuster haben nichts mit OOP zu tun. Wenn überhaupt, ist OOP selbst ein Entwurfsmuster. Entwurfsmuster erscheinen nicht nur außerhalb von OOP, sondern vollständig außerhalb der Softwareentwicklung.
Es gibt OOP design patternssolche, die normalerweise Beziehungen und Interaktionen zwischen Klassen / Objekten zeigen. Und es gibt viele andere Designmuster. OOP ist eine Reihe von Konzepten, nicht wirklich ein Muster. Design patternist auch ein Konzept.
topright
6
Sollten Sie nicht die Nützlichkeit der von mir gegebenen Antwort bewerten, anstatt über Semantik zu sprechen?
Wernight
6

Alle von ihnen. Außer Singleton. [/Leichtfertigkeit]

Kylotan
quelle
Könnten Sie vielleicht ein oder zwei Designmuster nennen, die Sie häufig in Ihrer Spieleentwicklung verwendet haben, und aus welchem ​​Grund? Als Anfänger in Bezug auf Designmuster ist "alle von ihnen" keine besonders hilfreiche Antwort. Vielen Dank, dass Sie geantwortet haben.
jcurrie33
5
Fragen "Welche Muster haben Sie verwendet?" ist wie die Frage "Welche Variablennamen haben Sie verwendet?" Es kommt auf den persönlichen Stil, die Anforderungen und die Domäne an. Irgendwann werden Sie wahrscheinlich jedes Muster verwenden, das jemals benannt wurde. Sie werden wahrscheinlich viele weitere verwenden, die noch nicht benannt wurden, und vielleicht sogar einige neue erfinden.
@ jcurrie33: sorry, ich konnte einfach nicht widerstehen, mich zuerst mit Singletons zu beschäftigen. ;)
Kylotan
6

Nicht wirklich über Muster, sondern über Grundprinzipien dahinter. In "Design Patterns: Elemente wiederverwendbarer objektorientierter Software" (1995 ) empfiehlt die vierköpfige Gruppe (Gamma, Erich; Richard Helm, Ralph Johnson und John Vlissides) nur zwei Prinzipien für das objektorientierte Design: (1) program to eine Schnittstelle und nicht zu einer Implementierung und (2) bevorzugen die Objektzusammensetzung gegenüber der Klassenvererbung.

Diese beiden Prinzipien sind bei vielen Aufgaben der Spieleentwicklung sehr hilfreich. Beispielsweise haben viele Spielprogrammierer eine tiefe Klassenhierarchie verwendet , um Spieleinheiten darzustellen. Es gibt einen anderen Ansatz, der auf Komposition basiert - komponentenbasierte Spielobjekte. Artikel über diesen Ansatz. Noch mehr Links . Dies ist ein Beispiel für ein Decorator-Muster .

rechts
quelle
Komponenten, wie sie im Spieledesign verwendet werden, ähneln eher einem statusbehafteten Strategiemuster - das sich natürlich als Closures außerhalb von C / C ++ / Java / C # und als Komponentenobjekte in ihnen ausdrückt. Das Dekorationsmuster ähnelt eher einem Proxy. Eigentum und Datenfluss sind entgegengesetzt zu denen, die wir normalerweise meinen, wenn wir über Komponentensysteme in Spielen sprechen.
Komponenten müssen auch miteinander kommunizieren und Muster wie Mediator, Observer und Composer einfügen. "Component-Based Game" ist ein zusammengesetztes Entwurfsmuster für sich.
CodexArcanum
@CodexArcanum, Observer, definitiv, aber nicht immer Mediator (Chain of Responsibility kann stattdessen verwendet werden). Es ist nur Composer, wenn GameObject (bestehend aus GameObjectComponent) GameObjectComponent selbst ist (nicht erforderlich).
topright
6

Das seltsamerweise wiederkehrende Vorlagenmuster kann sehr nützlich sein, um virtuelle Methoden und die Leistungseinbußen zu vermeiden, die durch die virtuellen Funktionsaufrufe verursacht werden können.

Dies kann das geeignete Muster sein, wenn Sie keinen Container des Basisklassentyps mit der von Ihnen gewünschten Schnittstelle benötigen, aber ähnlich benannte Verhalten und Schnittstellen möchten.

Sie können dies beispielsweise zum Kompilieren von Klassen für mehrere Plattformen oder Engines (dx vs. opengl) verwenden, bei denen die Varianz des Typs zum Kompilierungszeitpunkt bekannt ist.

Rick
quelle
Ich habe es immer gehasst, dass die OS-Abstraktionsschicht virtuell war. Es ist nicht so, dass Sie jemals zwei OS-Abtraktionsschichten benötigen würden. CRTP ist viel besser.
deft_code
Vielleicht bin ich nur alt, aber ich würde CRTP nicht einmal für DX / OpenGL- oder Plattformschnittstellen verwenden. Das Kompilieren ist zu langsam - ich würde nur typedefs verwenden. CRTP ist gut, wenn Sie Schnittstellen und Implementierungen zwischen Klassen teilen möchten, aber keine andere Beziehung haben, und nicht, wenn Sie nur die eine oder die andere Struktur auswählen möchten.
4

Ein Entwurfsmuster, das ich über viele Jahre hinweg entwickelt habe und das mir auf spektakuläre Weise nützlich war, bezeichne ich als "vermittelte Definitionssätze". Wie man es in GOF-Begriffen zusammenfasst, scheint umstritten zu sein, aber diese Frage, die ich darüber auf StackOverflow schrieb, geht ins Detail.

Das Kernkonzept besteht darin, dass eine Eigenschaft eines Modells, wie die Spezies einer Kreatur, so eingerichtet wird, dass jeder mögliche Wert für die Eigenschaft ein entsprechendes Definitionsobjekt hat - ein einzelnes gemeinsames Objekt pro Wert -, das sein Verhalten festlegt. und auf diese wird über einen zentralen Broker zugegriffen (der in Bezug auf GOF eine Registry, eine Factory oder beides sein kann). In meiner Verwendung wird im Allgemeinen auch über skalare Schlüssel auf sie zugegriffen, um eine schwache Bindung für Laufzeitmorphismuszwecke zu ermöglichen.

Chaos
quelle
Ich verstehe nicht, wie das überhaupt ein Singleton ist, und wenn man das Fliegengewicht-Muster bespricht, ist das Wort "Registry" überflüssig. Das ist nur Fliegengewicht.
Mein Verständnis aus dem SO-Thread war, dass die Leute Singleton als Teil davon identifizierten, weil die Definitionen als Klassen eingerichtet wurden. Was die Registrierung angeht, sehe ich nicht, wie sie redundant sein kann, wenn sie ersetzt oder mit Factory kombiniert werden kann.
Chaos
-1, soweit es um schnelle Kommunikation geht, ist dies wahrscheinlich der größte Fehler, den ich je gesehen habe. Ich kann diese Beschreibung wirklich nicht ernst nehmen.
Jesus, verzeih mir, dass ich nicht genug Ausstecher für dich bin. Werden Sie auch die Antwort "Entitätssysteme" ablehnen, da sie nicht sofort in GOF-Begriffen zusammengefasst werden kann?
Chaos
1
Etwas "Ausstechform" oder zumindest semantische Klarheit ist genau das, was Muster sein müssen, um nützlich zu sein. Begriffe wie "Fliegengewicht" und "Singleton", wie sie allgemein verstanden werden, schließen sich gegenseitig aus. Bei der ersten geht es darum, Daten automatisch zwischen mehreren Instanzen auszutauschen. Bei der zweiten geht es darum, genau eine Instanz zu haben. Ich sage nicht, dass Ihre Designauswahl nutzlos oder sogar schlecht ist, aber wenn Sie die Musternamen "nah genug" zusammenfügen, verwirren Sie alle nur noch mehr. (Bitte nimm keine Abstimmungen persönlich, besonders in CW.)