O'Reilly logo

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Design Patterns für die Spieleprogrammierung

Book Description

  • Die bekannten Design Patterns der Gang of Four im konkreten Einsatz für die Entwicklung von Games
  • Zahlreiche weitere vom Autor entwickelte Patterns
  • Sequenzierungs-, Verhaltens-, Entkopplungs- und Optimierungsmuster

Für viele Spieleprogrammierer stellt die Finalisierung ihres Spiels die größte Herausforderung dar. Viele Projekte verlaufen im Sande, weil Programmierer der Komplexität des eigenen Codes nicht gewachsen sind. Die im Buch beschriebenen Design Patterns nehmen genau dieses Problem in Angriff.

Der Autor blickt auf jahrelange Erfahrung in der Entwicklung von weltweit erfolgreichen Games zurück und stellt erprobte Patterns vor, mit deren Hilfe Sie Ihren Code entwirren und optimieren können. Die Patterns sind in Form unabhängiger Fallbeispiele organisiert, so dass Sie sich nur mit den für Sie relevanten zu befassen brauchen und das Buch auch hervorragend zum Nachschlagen verwenden können. Sie erfahren, wie man eine stabile Game Loop schreibt, wie Spielobjekte mithilfe von Komponenten organisiert werden können und wie man den CPU-Cache nutzt, um die Performance zu verbessern. Außerdem werden Sie sich damit beschäftigen, wie Skript-Engines funktionieren, wie Sie Ihren Code mittels Quadtrees und anderen räumlichen Aufteilungen optimieren und wie sich die klassischen Design Patterns in Spielen einsetzen lassen.

Table of Contents

  1. Impressum
  2. Danksagungen
  3. Teil I: Einführung
  4. Kapitel 1: Architektur, Performance und Spiele
    1. 1.1 Was ist Softwarearchitektur?
      1. 1.1.1 Was zeichnet eine gute Softwarearchitektur aus?
      2. 1.1.2 Wie nimmt man Änderungen vor?
      3. 1.1.3 Inwiefern hilft eine Entkopplung?
    2. 1.2 Zu welchem Preis?
    3. 1.3 Performance und Geschwindigkeit
    4. 1.4 Das Gute an schlechtem Code
    5. 1.5 Ein ausgewogenes Verhältnis finden
    6. 1.6 Einfachheit
    7. 1.7 Fang endlich an!
  5. Teil II: Design Patterns neu überdacht
  6. Kapitel 2: Command (Befehl)
    1. 2.1 Eingabekonfiguration​
    2. 2.2 Regieanweisungen
    3. 2.3 Rückgängig und Wiederholen
    4. 2.4 Klassen ohne Funktionen?
    5. 2.5 Siehe auch ...
  7. Kapitel 3: Flyweight (Fliegengewicht)
    1. 3.1 Den Wald vor lauter Bäumen nicht sehen
    2. 3.2 Tausend Instanzen
    3. 3.3 Das Flyweight-Pattern​​
    4. 3.4 Ein Ort, um Wurzeln zu schlagen
    5. 3.5 Und die Performance?
    6. 3.6 Siehe auch ...
  8. Kapitel 4: Observer (Beobachter)
    1. 4.1 Erzielte Leistungen
    2. 4.2 Funktionsweise
      1. 4.2.1 Der Observer
      2. 4.2.2 Das Subjekt​
      3. 4.2.3 Beobachtung der Physik-Engine
    3. 4.3 »Das ist zu langsam!«
      1. 4.3.1 Oder ist es doch zu schnell?
    4. 4.4 »Zu viele dynamische Allokationen«
      1. 4.4.1 Verkettete Observer
      2. 4.4.2 Ein Pool von Listenknoten
    5. 4.5 Verbleibende Schwierigkeiten
      1. 4.5.1 Subjekte und Observer löschen
      2. 4.5.2 Keine Sorge, der Garbage Collector erledigt das schon
      3. 4.5.3 Was geht hier vor?
    6. 4.6 Heutige Observer
    7. 4.7 Zukünftige Observer
  9. Kapitel 5: Prototype (Prototyp)
    1. 5.1 Das Design Pattern Prototype
      1. 5.1.1 Wie gut funktioniert es?
      2. 5.1.2 Spawn-Funktionen
      3. 5.1.3 Templates
      4. 5.1.4 First-Class-Typen
    2. 5.2 Eine auf Prototypen beruhende Sprache
      1. 5.2.1 Self​
      2. 5.2.2 Wie ist es gelaufen?
      3. 5.2.3 Was ist mit JavaScript?​
    3. 5.3 Prototypen zur Datenmodellierung
  10. Kapitel 6: Singleton
    1. 6.1 Das Singleton-Pattern
      1. 6.1.1 Beschränkung einer Klasse auf eine Instanz
      2. 6.1.2 Bereitstellung eines globalen Zugriffspunkts
    2. 6.2 Gründe für die Verwendung
    3. 6.3 Gründe, die Verwendung zu bereuen
      1. 6.3.1 Singletons sind globale Variablen
      2. 6.3.2 Das Pattern löst zwei Probleme, selbst wenn es nur eins gibt
      3. 6.3.3 Die späte Initialisierung entzieht Ihnen die Kontrolle
    4. 6.4 Verzicht auf Singletons
      1. 6.4.1 Wird die Klasse überhaupt benötigt?
      2. 6.4.2 Nur eine Instanz einer Klasse
      3. 6.4.3 Bequemer Zugriff auf eine Instanz
    5. 6.5 Was bleibt dem Singleton?
  11. Kapitel 7: State (Zustand)
    1. 7.1 Altbekanntes
    2. 7.2 Zustandsautomaten erledigen das
    3. 7.3 Enumerationen und Switch-Anweisungen
    4. 7.4 Das State-Pattern
      1. 7.4.1 Das Interface für den Zustand
      2. 7.4.2 Klassen für alle Zustände
      3. 7.4.3 An den Zustand delegieren
    5. 7.5 Wo sind die Zustandsobjekte?
      1. 7.5.1 Statische Zustände
      2. 7.5.2 Instanziierte Zustandsobjekte​
    6. 7.6 Eintritts- und Austrittsaktionen
    7. 7.7 Wo ist der Haken?
    8. 7.8 Nebenläufige Zustandsautomaten
    9. 7.9 Hierarchische Zustandsautomaten
    10. 7.10 Kellerautomaten
    11. 7.11 Wie nützlich sind sie?
  12. Teil III: Sequenzierungsmuster (Sequencing Patterns)
  13. Kapitel 8: Double Buffer (Doppelter Buffer)
    1. 8.1 Motivation
      1. 8.1.1 Computergrafik kurz und bündig
      2. 8.1.2 Erster Akt, erste Szene
      3. 8.1.3 Zurück zur Grafik
    2. 8.2 Das Pattern
    3. 8.3 Anwendbarkeit
    4. 8.4 Konsequenzen
      1. 8.4.1 Der Austausch selbst kostet Zeit
      2. 8.4.2 Zwei Framebuffer belegen mehr Arbeitsspeicher
    5. 8.5 Beispielcode
      1. 8.5.1 Nicht nur Grafik
      2. 8.5.2 Künstliche Unintelligenz
      3. 8.5.3 Gebufferte Ohrfeigen
    6. 8.6 Designentscheidungen
      1. 8.6.1 Wie werden die Buffer ausgetauscht?​
      2. 8.6.2 Wie fein ist der Buffer untergliedert?
    7. 8.7 Siehe auch ...
  14. Kapitel 9: Game Loop (Hauptschleife)
    1. 9.1 Motivation
      1. 9.1.1 Interview mit einer CPU
      2. 9.1.2 Ereignisschleifen
      3. 9.1.3 Eine aus dem Takt geratene Welt
      4. 9.1.4 Sekunden pro Sekunde
    2. 9.2 Das Pattern
    3. 9.3 Anwendbarkeit
    4. 9.4 Konsequenzen
      1. 9.4.1 Abstimmung mit der Ereignisschleife des Betriebssystems
    5. 9.5 Beispielcode
      1. 9.5.1 Die Beine in die Hand nehmen
      2. 9.5.2 Ein kleines Nickerchen
      3. 9.5.3 Ein kleiner und ein großer Schritt
      4. 9.5.4 Aufholjagd
      5. 9.5.5 In der Mitte hängen geblieben
    6. 9.6 Designentscheidungen
      1. 9.6.1 Stammt die Game Loop aus Ihrer Feder oder benutzen Sie die der Plattform?
      2. 9.6.2 Wie handhaben Sie die Leistungsaufnahme?​
      3. 9.6.3 Wie steuern Sie die Spielgeschwindigkeit?​
    7. 9.7 Siehe auch ...
  15. Kapitel 10: Update Method (Aktualisierungsmethode)
    1. 10.1 Motivation
    2. 10.2 Das Pattern
    3. 10.3 Anwendbarkeit
    4. 10.4 Konsequenzen
      1. 10.4.1 Verkomplizierung durch Aufteilen des Codes in einzelne Frames
      2. 10.4.2 Der Zustand muss gespeichert werden, um im nächsten Frame fortfahren zu können
      3. 10.4.3 Alle Objekte simulieren jeden Frame, aber nicht wirklich exakt gleichzeitig
      4. 10.4.4 Obacht bei der Modifizierung der Objektliste während der Aktualisierung
    5. 10.5 Beispielcode
      1. 10.5.1 Entity-Unterklassen?
      2. 10.5.2 Entities definieren
      3. 10.5.3 Zeitablauf
    6. 10.6 Designentscheidungen
      1. 10.6.1 Zu welcher Klasse gehört die update()-Methode?
      2. 10.6.2 Wie werden inaktive Objekte gehandhabt?​
    7. 10.7 Siehe auch ...
  16. Teil IV: Verhaltensmuster (Behavioral Patterns)
  17. Kapitel 11: Bytecode​
    1. 11.1 Motivation
      1. 11.1.1 Wettkampf der Zaubersprüche
      2. 11.1.2 Daten > Code
      3. 11.1.3 Das Interpreter-Pattern​
      4. 11.1.4 Faktisch Maschinencode
    2. 11.2 Das Pattern
    3. 11.3 Anwendbarkeit
    4. 11.4 Konsequenzen
      1. 11.4.1 Befehlsformat
      2. 11.4.2 Fehlender Debugger
    5. 11.5 Beispielcode
      1. 11.5.1 Eine zauberhafte API
      2. 11.5.2 Ein bezaubernder Befehlssatz​
      3. 11.5.3 Eine Stackmaschine
      4. 11.5.4 Verhalten = Komposition
      5. 11.5.5 Eine virtuelle Maschine​
      6. 11.5.6 Hexerwerkzeuge
    6. 11.6 Designentscheidungen
      1. 11.6.1 Wie greifen Befehle auf den Stack zu?
      2. 11.6.2 Welche Befehle gibt es?
      3. 11.6.3 Wie werden Werte repräsentiert?
      4. 11.6.4 Wie wird der Bytecode erzeugt?
    7. 11.7 Siehe auch ...
  18. Kapitel 12: Subclass Sandbox (Unterklassen-Sandbox)​​
    1. 12.1 Motivation
    2. 12.2 Das Pattern
    3. 12.3 Anwendbarkeit
    4. 12.4 Konsequenzen
    5. 12.5 Beispielcode
    6. 12.6 Designentscheidungen
      1. 12.6.1 Welche Operationen sollen bereitgestellt werden?
      2. 12.6.2 Sollen Methoden direkt oder durch Objekte, die sie enthalten, bereitgestellt werden?
      3. 12.6.3 Wie gelangt die Basisklasse an die benötigten Zustände?
    7. 12.7 Siehe auch ...
  19. Kapitel 13: Type Object (Typ-Objekt)​
    1. 13.1 Motivation
      1. 13.1.1 Die typische OOP-Lösung
      2. 13.1.2 Eine Klasse für eine Klasse
    2. 13.2 Das Pattern
    3. 13.3 Anwendbarkeit
    4. 13.4 Konsequenzen
      1. 13.4.1 Typ-Objekte müssen manuell gehandhabt werden
      2. 13.4.2 Die Definition des Verhaltens der verschiedenen Typen ist schwieriger
    5. 13.5 Beispielcode
      1. 13.5.1 Typartiges Verhalten von Typ-Objekten: Konstruktoren​
      2. 13.5.2 Gemeinsame Nutzung von Daten durch Vererbung​
    6. 13.6 Designentscheidungen
      1. 13.6.1 Ist das Typ-Objekt gekapselt oder zugänglich?​
      2. 13.6.2 Wie werden Typ-Objekte erzeugt?​
      3. 13.6.3 Kann sich der Typ ändern?​
      4. 13.6.4 Welche Formen der Vererbung werden unterstützt?
    7. 13.7 Siehe auch ...
  20. Teil V: Entkopplungsmuster (Decoupling Patterns)
  21. Kapitel 14: Component (Komponente)
    1. 14.1 Motivation
      1. 14.1.1 Der Gordische Knoten
      2. 14.1.2 Den Knoten durchschlagen
      3. 14.1.3 Unerledigtes
      4. 14.1.4 Wiederverwendung
    2. 14.2 Das Pattern
    3. 14.3 Anwendbarkeit
    4. 14.4 Konsequenzen
    5. 14.5 Beispielcode
      1. 14.5.1 Eine monolithische Klasse
      2. 14.5.2 Abspalten eines Bereichs
      3. 14.5.3 Abspalten der übrigen Bereiche
      4. 14.5.4 Robo-Bjørn
      5. 14.5.5 Ganz ohne Bjørn?
    6. 14.6 Designentscheidungen
      1. 14.6.1 Wie gelangt ein Objekt an seine Komponenten?
      2. 14.6.2 Wie kommunizieren die Komponenten untereinander?​
    7. 14.7 Siehe auch ...
  22. Kapitel 15: Event Queue (Ereigniswarteschlange)
    1. 15.1 Motivation
      1. 15.1.1 Ereignisschleife der grafischen Benutzeroberfläche
      2. 15.1.2 Zentrale Ereignissammlung
      3. 15.1.3 Wie bitte?
    2. 15.2 Das Pattern
    3. 15.3 Anwendbarkeit
    4. 15.4 Konsequenzen
      1. 15.4.1 Eine zentrale Ereigniswarteschlange ist eine globale Variable
      2. 15.4.2 Den Boden unter den Füßen verlieren
      3. 15.4.3 Steckenbleiben in Rückkopplungsschleifen
    5. 15.5 Beispielcode
      1. 15.5.1 Ein Ring-Buffer
      2. 15.5.2 Anfragen zusammenfassen
      3. 15.5.3 Threads​
    6. 15.6 Designentscheidungen
      1. 15.6.1 Was soll in die Warteschlange aufgenommen werden?​
      2. 15.6.2 Wer darf lesend auf die Warteschlange zugreife​n?
      3. 15.6.3 Wer darf schreibend auf die Warteschlange zugreifen?
      4. 15.6.4 Wie lang ist die Lebensdauer der Objekte in der Warteschlange?
    7. 15.7 Siehe auch ...
  23. Kapitel 16: Service Locator (Dienstlokalisierung)
    1. 16.1 Motivation
    2. 16.2 Das Pattern
    3. 16.3 Anwendbarkeit
    4. 16.4 Konsequenzen
      1. 16.4.1 Der Dienst muss auch tatsächlich lokalisiert werden können
      2. 16.4.2 Dem Dienst ist nicht bekannt, wer ihn nutzt
    5. 16.5 Beispielcode
      1. 16.5.1 Der Dienst​
      2. 16.5.2 Der Dienstanbieter
      3. 16.5.3 Ein einfacher Service Locator
      4. 16.5.4 Ein leerer Dienst
      5. 16.5.5 Protokollierender Dekorierer
    6. 16.6 Designentscheidungen
      1. 16.6.1 Wie wird der Dienst lokalisiert?
      2. 16.6.2 Was geschieht, wenn die Lokalisierung des Dienstes scheitert?
      3. 16.6.3 Wer darf auf den Dienst zugreifen?
    7. 16.7 Siehe auch ...
  24. Teil VI: Optimierungsmuster (Optimization Patterns)
  25. Kapitel 17: Data Locality (Datenlokalität)
    1. 17.1 Motivation
      1. 17.1.1 Ein Datenlager
      2. 17.1.2 Eine Palette für die CPU
      3. 17.1.3 Daten = Performance?
    2. 17.2 Das Pattern
    3. 17.3 Anwendbarkeit
    4. 17.4 Konsequenzen
    5. 17.5 Beispielcode
      1. 17.5.1 Aneinandergereihte Arrays​
      2. 17.5.2 Gebündelte Daten
      3. 17.5.3 Hot/Cold Splitting
    6. 17.6 Designentscheidungen
      1. 17.6.1 Wie wird Polymorphismus gehandhabt?
      2. 17.6.2 Wie werden Spielobjekte definiert?
    7. 17.7 Siehe auch ...
  26. Kapitel 18: Dirty Flag (Veraltet-Flag)
    1. 18.1 Motivation
      1. 18.1.1 Lokale Koordinaten und Weltkoordinaten
      2. 18.1.2 Gecachete Weltkoordinaten
      3. 18.1.3 Verzögerte Berechnung
    2. 18.2 Das Pattern
    3. 18.3 Anwendbarkeit
    4. 18.4 Konsequenzen
      1. 18.4.1 Nicht zu lange verzögern
      2. 18.4.2 Das Flag bei jedem Zustandswechsel ändern
      3. 18.4.3 Vorherige abgeleitete Daten verbleiben im Speicher
    5. 18.5 Beispielcode
      1. 18.5.1 Nicht-optimierte Traversierung
      2. 18.5.2 Let’s Get Dirty
    6. 18.6 Designentscheidungen
      1. 18.6.1 Wann wird das Dirty Flag gelöscht?
      2. 18.6.2 Wie feingranular ist Ihr »Dirty-Tracking«?
    7. 18.7 Siehe auch ...
  27. Kapitel 19: Object Pool (Objektpool)​
    1. 19.1 Motivation
      1. 19.1.1 Der Fluch der Fragmentierung
      2. 19.1.2 Das Beste beider Welten
    2. 19.2 Das Pattern
    3. 19.3 Anwendbarkeit
    4. 19.4 Konsequenzen
      1. 19.4.1 Der Pool verschwendet möglicherweise Speicherplatz für ungenutzte Objekte
      2. 19.4.2 Es steht nur eine feste Anzahl von Objekten zur Verfügung
      3. 19.4.3 Die Objekte sind von fester Größe
      4. 19.4.4 Wiederverwendete Objekte werden nicht automatisch zurückgesetzt
      5. 19.4.5 Unbenutzte Objekte verbleiben im Arbeitsspeicher
    5. 19.5 Beispielcode
      1. 19.5.1 Eine kostenlose Liste
    6. 19.6 Designentscheidungen
      1. 19.6.1 Sind Objekte an den Pool gekoppelt?
      2. 19.6.2 Wer ist für die Initialisierung der wiederverwendeten Objekte verantwortlich?
    7. 19.7 Siehe auch ...
  28. Kapitel 20: Spatial Partition (Räumliche Aufteilung)​​
    1. 20.1 Motivation
      1. 20.1.1 Kampfeinheiten auf dem Schlachtfeld
      2. 20.1.2 Schlachtreihen zeichnen
    2. 20.2 Das Pattern
    3. 20.3 Anwendbarkeit
    4. 20.4 Konsequenzen
    5. 20.5 Beispielcode
      1. 20.5.1 Ein Bogen Millimeterpapier
      2. 20.5.2 Ein Gitternetz verketteter Einheiten
      3. 20.5.3 Betreten des Schlachtfeldes
      4. 20.5.4 Klirrende Schwerter
      5. 20.5.5 Vormarschieren
      6. 20.5.6 Um Armeslänge
    6. 20.6 Designentscheidungen
      1. 20.6.1 Ist die Aufteilung hierarchisch oder gleichmäßig?
      2. 20.6.2 Hängt die Zellengröße von der Verteilung der Objekte ab?
      3. 20.6.3 Werden die Objekte nur in den Zellen gespeichert?
    7. 20.7 Siehe auch ...