Students Save 30%! Learn & create with unlimited courses & creative assets Students Save 30%! Save Now
Advertisement
  1. Game Development
  2. Programming
Gamedevelopment

Erstelle ein einfaches Asteroiden-Spiel mit komponentenbasierten Entitäten

by
Difficulty:IntermediateLength:LongLanguages:

German (Deutsch) translation by Władysław Łucyszyn (you can also view the original English article)

Im vorherigen Lernprogramm haben wir ein bodennahes komponentenbasiertes Entity-System erstellt.  Jetzt werden wir dieses System verwenden, um ein einfaches Asteroids-Spiel zu erstellen. 


Finale Ergebnisvorschau


Hier ist das einfache Asteroids-Spiel, das wir in diesem Tutorial erstellen werden.  Es ist mit Flash und AS3 geschrieben, aber die allgemeinen Konzepte gelten für die meisten Sprachen. 

Der vollständige Quellcode ist auf GitHub verfügbar. 


Klassenübersicht

Es gibt sechs Klassen: 

  • AsteroidsGame, das die Basis-Spielklasse erweitert und die für unser Space-Shoot-Em-Up spezifische Logik hinzufügt. 
  • Schiff, das ist die Sache, die du kontrollierst. 
  • Asteroid, auf das du schießt. 
  • Bullet, das ist die Sache, die Sie feuern.   
  • Pistole, die diese Kugeln erzeugt.   
  • EnemyShip, ein wandernder Alien, der nur dazu da ist, dem Spiel ein bisschen Abwechslung zu geben. 
  • Lassen Sie uns nacheinander diese Entitätstypen durchgehen.


    Die Schiffsklasse 

    Wir beginnen mit dem Spielerschiff:

Es gibt eine ganze Reihe von Implementierungsdetails hier, aber die Hauptsache ist, dass wir im Konstruktor Körper-, Physik-, Gesundheits-, Sicht- und Waffenkomponenten instanziieren und konfigurieren.  (Die Waffenkomponente ist tatsächlich eine Instanz von Gun und nicht die Waffenbasisklasse.) 

Ich verwende die Flash-Grafik-Zeichnungs-APIs, um mein Schiff zu erstellen (Zeilen 29-32), aber wir könnten genauso gut ein Bitmap-Bild verwenden.  Ich erstelle auch eine Instanz meiner Gamepad-Klasse - dies ist eine Open-Source-Bibliothek, die ich vor ein paar Jahren geschrieben habe, um die Tastatureingabe in Flash zu vereinfachen. 

Ich habe auch die Update-Funktion von der Basisklasse überschrieben, um ein benutzerdefiniertes Verhalten hinzuzufügen: Nach dem Auslösen des gesamten Standardverhaltens mit super.update ()  rotieren wir das Schiff basierend auf der Tastatureingabe und feuern die Waffe, wenn der Feuerschlüssel ist gedrückt. 

Wenn wir dem abgestorbenen Signal der Gesundheitskomponente zuhören, lösen wir die onDied-Funktion aus, wenn dem Spieler die Trefferpunkte ausgehen.  Wenn das passiert, sagen wir dem Schiff, dass es sich selbst zerstören soll.


Die Waffenklasse 

Als nächstes lass uns den Gun-Kurs starten:

Das ist ein schöner kurzer!  Wir überschreiben einfach die Funktion fire (), um einen neuen Bullet zu erstellen, wann immer der Spieler feuert.  Nachdem wir die Position und Rotation des Geschosses auf das Schiff abgestimmt und in die richtige Richtung verschoben haben, entsenden wir die EntityCreated, so dass sie dem Spiel hinzugefügt werden kann.

Eine tolle Sache an dieser Gun-Klasse ist, dass sie sowohl vom Spieler als auch von gegnerischen Schiffen benutzt wird. 


Die Bullet-Klasse 

Eine Waffe erstellt eine Instanz dieser Bullet-Klasse:

Der Konstruktor instanziiert und konfiguriert den Körper, die Physik und die Ansicht.  In der Update-Funktion können Sie jetzt sehen, dass die Liste der Ziele nützlich ist, da wir alle Dinge, die wir treffen wollen, durchgehen und sehen, ob einer von ihnen das Geschoss schneidet. 

Dieses Kollisionssystem würde nicht auf Tausende von Kugeln skalieren, aber für die meisten Gelegenheitsspiele ist es in Ordnung. 

Wenn das Geschoss mehr als 20 Frames alt ist, fangen wir an, es auszublenden, und wenn es älter als 25 Frames ist, zerstören wir es.  Wie bei der Waffe wird die Kugel sowohl vom Spieler als auch vom Gegner benutzt - die Instanzen haben nur eine andere Zielliste. 

Apropos ...


Die feindliche Schiffsklasse 

Sehen wir uns nun dieses feindliche Schiff an:

Wie Sie sehen können, ist es ziemlich ähnlich der Klasse des Spielerschiffs.  Der einzige wirkliche Unterschied ist, dass wir in der update () - Funktion, anstatt die Kontrolle des Spielers über die Tastatur zu haben, etwas "künstliche Dummheit" haben, um das Schiff wandern zu lassen und zufällig zu feuern. 


Die Asteroidenklasse

Der andere Entitätstyp, auf den der Spieler schießen kann, ist der Asteroid selbst:

Hoffentlich werden Sie sich daran gewöhnen, wie diese Entitätsklassen jetzt aussehen.

Im Konstruktor initialisieren wir unsere Komponenten und randomisieren die Position und Geschwindigkeit.

 In der update () - Funktion überprüfen wir auf Kollisionen mit unserer Zielliste - die in diesem Beispiel nur einen einzigen Gegenstand hat - dem Schiff des Spielers.  Wenn wir eine Kollision finden, beschädigen wir das Ziel und zerstören dann den Asteroiden.  Auf der anderen Seite, wenn der Asteroid selbst beschädigt ist (d. H. Er wird von einer Kugel eines Spielers getroffen), schrumpfen wir ihn und erzeugen einen zweiten Asteroiden, was die Illusion erzeugt, dass er in zwei Teile gesprengt wurde.  Wir wissen, wann dies zu tun ist, indem wir das "weh" -Signal der Gesundheitskomponente hören.


 Die AsteroidsGame-Klasse 

Sehen wir uns schließlich die AsteroidsGame-Klasse an, die die gesamte Show steuert:

Diese Klasse ist ziemlich lang (gut, mehr als 100 Zeilen!), Weil es eine Menge Dinge tut.

In startGame () erstellt und konfiguriert es 10 Asteroiden, das Schiff und das feindliche Schiff, und erstellt auch die "CLICK TO START" -Meldung. 

Die Funktion start () pausiert das Spiel und entfernt die Nachricht, während die Funktion gameOver das Spiel erneut pausiert und die Nachricht wiederherstellt.  Die restart () Funktion wartet auf einen Mausklick auf den Game Over Bildschirm - wenn dies passiert, stoppt das Spiel und startet es erneut.

Die update () -Funktion durchläuft alle Feinde und krümmt alle, die vom Bildschirm verschwunden sind, sowie die Win-Bedingung, die besagt, dass keine Feinde mehr in der Liste der Feinde sind. 


Nimm es weiter

Dies ist eine ziemlich nackte Knochenmaschine und ein einfaches Spiel, also lasst uns jetzt darüber nachdenken, wie wir es erweitern könnten. 

  • Wir könnten für jede Entität einen Prioritätswert hinzufügen und die Liste vor jeder Aktualisierung sortieren, sodass wir sicherstellen können, dass einige Entitätstypen immer nach anderen Typen aktualisiert werden. 
  • Wir könnten das Objekt-Pooling verwenden, so dass wir tote Objekte (z. B. Kugeln) wiederverwenden, anstatt nur Hunderte neuer Objekte zu erstellen.
  • Wir könnten ein Kamerasystem hinzufügen, damit wir die Szene scrollen und zoomen können.  Wir könnten die Body- und Physics-Komponenten erweitern, um Unterstützung für Box2D oder eine andere Physik-Engine hinzuzufügen. 
  • Wir könnten eine Inventarkomponente erstellen, sodass Entitäten Elemente transportieren können. 

Neben der Erweiterung der einzelnen Komponenten müssen wir manchmal die IEntity-Schnittstelle erweitern, um spezielle Arten von Entitäten mit speziellen Komponenten zu erstellen.

Zum Beispiel, wenn wir ein Plattform-Spiel machen, und wir haben eine neue Komponente, die all die spezifischen Dinge behandelt, die eine Plattform-Spiel-Figur braucht - sind sie auf dem Boden, berühren sie eine Mauer, wie lange waren sie schon in der Luft, können sie doppelt springen usw. - andere Entitäten müssen möglicherweise ebenfalls auf diese Informationen zugreifen.  Aber es ist nicht Teil der Kern-Entity-API, die absichtlich sehr allgemein gehalten wird.  Daher müssen wir eine neue Schnittstelle definieren, die Zugriff auf alle standardmäßigen Entitätskomponenten bietet, aber den Zugriff auf die PlatformController-Komponente hinzufügt.

Dafür würden wir etwas tun wie: 

Jede Entität, die "Plattformfunktionalität" benötigt, implementiert diese Schnittstelle und ermöglicht anderen Entitäten die Interaktion mit der PlatformController-Komponente.


Schlussfolgerungen 

Ich wage sogar, über die Spielarchitektur zu schreiben, ich fürchte, ich rühre ein Hornissennest der Meinung auf - aber das ist (meistens) immer eine gute Sache, und ich hoffe zumindest, dass ich dich darüber nachdenken lasse, wie du dich organisierst Code. 

Letztendlich glaube ich nicht, dass Sie sich zu sehr darauf festlegen sollten, wie Sie die Dinge strukturieren. Was immer für dich funktioniert, um dein Spiel zu machen, ist die beste Strategie.  Ich weiß, dass es weit fortgeschrittenere Systeme gibt, die ich hier umreiße, die eine Reihe von Problemen lösen, die über die besprochenen hinausgehen, aber sie können dazu neigen, sehr ungewohnt zu erscheinen, wenn Sie an eine traditionelle vererbungsbasierte Architektur gewöhnt sind.

Ich mag den Ansatz, den ich hier vorgeschlagen habe, weil er es ermöglicht, Code nach Zweck, in kleinen fokussierten Klassen zu organisieren, während er eine statisch typisierte, erweiterbare Schnittstelle bereitstellt und sich nicht auf dynamische Sprachfunktionen oder String-Lookups verlässt.  Wenn Sie das Verhalten einer bestimmten Komponente ändern möchten, können Sie diese Komponente erweitern und die Methoden überschreiben, die Sie ändern möchten.  Die Klassen bleiben meist sehr kurz, so dass ich nie durch Tausende von Zeilen scrollen muss, um den Code zu finden, nach dem ich suche.

Das Beste von allem, ich bin in der Lage, eine einzige Engine zu haben, die flexibel genug ist, um alle Spiele, die ich mache, zu verwenden, was mir eine Menge Zeit spart.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.