Este artículo es la segunda parte de mi tutorial para hacer un pequeño juego con Javascript. Realizando tu primer juego en JavaScript – Primera parte.
In diesem zweiten Teil werden wir den Betrieb unseres Spiels starten und ihm mehr Animation, Vielseitigkeit und Bewegung verleihen. Beginnen wir mit diesem zweiten Teil, ohne mehr zu sagen!
Lass uns das nachholen
Como ya sabrás, tenemos mucho adelantado de este tutorial. Sigue el siguiente Verknüpfung y Siehe den vollständigen Quellcode dieses Tutorials . Absolutamente todo lo conseguirás siguiendo esa Url. Así que no esperes mas y continuemos con nuestro tutorial.
Erstellen Sie unser erstaunliches Raumschiff
Jetzt, da der Hintergrund fertig ist, können wir endlich anfangen, unser Raumschiff zusammenzubauen!
Lassen Sie uns eine Datei erstellen Player.js und füge es hinzu Index.html als Skript (Genau wie bei CloudManager).
Hier ist ein (schönes) Raumschiff, das in wenigen Minuten entworfen wurde und das Sie Ihrem hinzufügen können Assets-Ordner und in der Laderfunktion von main.js:
Grundsätzlich möchten wir, dass dieses Schiff am linken Bildschirmrand angezeigt wird. Wir brauchen auch seinen Anker (Objektpositionspunkt), um in der Mitte des Sprites zu sein, und da er vielleicht zu groß ist, können wir ihn neu skalieren, wie ich Ihnen unten zeige:
class Player {constructor () {this.sprite = new PIXI.Sprite (PIXI.loader.resources ["Assets / Spaceship.png"]. Textur); this.sprite.interactive = true; this.sprite.anchor.set (0,5, 0,5); this.sprite.position.set (renderer.width * 0.2, renderer.height * 0.4); this.sprite.scale.set (0,4, 0,4); stage.addChild (this.sprite); }}
Natürlich müssen wir dieses Objekt als deklarieren Globale Variable aus der Datei main.js, so kann es im Spiel instanziiert werden:
var stage = new PIXI.Container (); var cloudManager; var player; ...
… und in der Init-Funktion aus derselben Datei (direkt danach CloudManager):
Spieler = neuer Spieler ();
Jetzt sollten Sie das glänzende Raumschiff segeln sehen.
Wenn Sie jedoch einige Sekunden warten, sollten Sie einige Probleme haben:
Das Raumschiff fliegt hinter den Wolken!
Ja, da sich das zuletzt erstellte Objekt tatsächlich hinter dem vorherigen bewegt. Die Wolken erscheinen, nachdem das Raumschiff instanziiert wurde. Daher muss der Cloud-Manager am Ende der Objektliste Wolken generieren. Dazu müssen wir nur die aktualisieren addChild der Klasse CloudManager:
stage.addChildAt (this.cloud, 0);
Mit addChildAt können wir einen zweiten Parameter übergeben, nämlich die Position in der Liste der Objekte auf der Bühne. Je weiter Sie entfernt sind, desto weiter entfernt befindet sich das Sprite auf dem Bildschirm.
"0" bedeutet den ersten Index in der Objektliste. Jedes Mal, wenn wir eine neue Cloud erstellen, fügen wir sie oben in die Liste ein, um sicherzustellen, dass sie hinter dem Raumschiff angezeigt wird.
Nachdem dies erledigt ist, können wir die Raumschiffsteuerung starten.
Bewegen Sie das Raumschiff
Kehren wir zur Klasse von zurück Player.js und fügen wir einige Zeilen in den Konstruktor ein:
window.addEventListener ('keydown', this.onKeyDown.bind (this)); window.addEventListener ('keyup', this.onKeyUp.bind (this));
Dadurch kann das Spiel Tastaturereignisse erkennen (wenn eine Taste gedrückt und losgelassen wird). Wenn eines dieser Ereignisse eintritt, wird die Methode am Ende jeder Zeile ausgeführt.
Hinweis: Durch Hinzufügen von ".bind (this)" am Ende der Funktion wird der Kontext des Objekts übergeben. Dies bedeutet, dass wir weiterhin auf seine Eigenschaften zugreifen können, indem wir "this" aufrufen. Wenn wir es nicht so schreiben, kann die Rückruffunktion nicht bestimmen, mit welchem Objekt wir arbeiten. Denken Sie daran, dass Sie Ihr Objekt möglicherweise auf diese Weise binden müssen, wenn eine Ihrer Rückruffunktionen den Fehler "undefined this" erhält.
Wir werden 2 leere Methoden in derselben Klasse definieren (wir werden sie ein wenig ausfüllen):
onKeyDown (Schlüssel) = {}; onKeyUp (Schlüssel) = {};
Wir brauchen auch 3 Variablen, um das Raumschiff zu bewegen: seine horizontale und vertikale Richtung (X und Y) und die Geschwindigkeit (alle im Konstruktor):
this.directionX = 0; this.directionY = 0; this.speed = 8;
this.keyCodes = {37: -1, 38: -1, 39: 1, 40: 1};
Dieses Objekt ist im Grunde eine Zuordnung von Schlüsselcodes und Adresswerten:
- 37 ist die linke Pfeiltaste, Um unser Raumschiff nach links zu bewegen, müssen wir seine Position in X verringern.
- 38 ist die Aufwärtspfeiltaste, Um unser Raumschiff nach oben zu bewegen, müssen wir seine Position in Y verringern.
- 39 ist die rechte Pfeiltaste, Um unser Raumschiff nach rechts zu bewegen, müssen wir seine Position in X erhöhen.
- 40 ist die Abwärtspfeiltaste, Um unser Raumschiff in den Hintergrund zu rücken, müssen wir seine Position in Y erhöhen.
Bei jedem Tastendruck wird die entsprechende Adresse abgerufen:
onKeyDown (key) {if (key.keyCode == 37 || key.keyCode == 39) this.directionX = this.keyCodes [key.keyCode]; sonst wenn (key.keyCode == 38 || key.keyCode == 40) this.directionY = this.keyCodes [key.keyCode]; }}
Es sieht ziemlich seltsam aus, aber lassen Sie uns das erklären: Wenn der Schlüsselcode 37 oder 39 ist (was bedeutet, dass die linke oder rechte Pfeiltaste bedeutet), legen wir einfach die Richtung des X fest. Wenn es 38 oder 40 ist, können Sie erraten, was passiert (Ja, es ist eigentlich die vertikale Richtung). Das ist alles!
Fügen wir die Player-Aktualisierungsmethode hinzu (wie die Cloud Manager, merken?):
update () {this.sprite.position.x + = this.directionX * this.speed; this.sprite.position.y + = this.directionY * this.speed; }}
... und vergessen Sie natürlich nicht, es in der Schleifenfunktion von main.js aufzurufen
player.update ();
Wenn Sie das Spiel speichern und neu laden, funktioniert es einwandfrei, außer das Schiff bewegt sich weiter, wenn wir die Pfeiltasten loslassen. Es ist offensichtlich, dass wir die onKeyUp-Funktion, die den gerade freigegebenen Schlüssel erfasst, noch nicht abgeschlossen haben. Auf diese Weise können wir es stoppen, indem wir Richtung X oder Richtung Y auf 0 setzen.
Es gibt nur ein kleines Problem: Was passiert, wenn wir die Adresse auf 0 setzen, weil wir die linke Taste losgelassen haben, aber die rechte Taste noch gedrückt ist?
Ja, das Raumschiff wird anhalten und wir müssten die rechte Taste erneut drücken, um uns zu bewegen, was nicht sehr logisch ist.
Warum also nicht prüfen, ob die rechte oder linke Taste noch gedrückt ist, damit wir die Adresse auf diese zuvor gedrückte Taste einstellen können?
Das werden wir tun. Und dafür müssen wir den Status jeder Taste in einem Booleschen Wert speichern, gedrückt oder losgelassen (wahr oder falsch). Lassen Sie uns all diese Zustände in eine Objektvariable im Player-Konstruktor einfügen:
this.keyState = {37: false, 38: false, 39: false, 40: false};
Wenn eine Taste (identifiziert durch ihren eigenen Code) gedrückt wird, ändern wir einfach ihren Status in true, und wenn sie losgelassen wird, setzen wir sie auf false. Einfach richtig?
Fügen wir diese Zeile am Anfang von onKeyDown hinzu:
this.keyState [key.keyCode] = true;
... und das in onKeyUp:
this.keyState [key.keyCode] = false;
Jetzt können wir mit der Logik fortfahren onKeyUp: Wenn eine der horizontalen oder vertikalen Tasten losgelassen wird, die gegenüberliegende jedoch weiterhin gedrückt wird, ändern wir die Richtung zur letzten. Wenn beide freigegeben werden, stoppen wir das Schiff:
if (! this.keyState [37] && this.keyState [39]) this.directionX = this.keyCodes [39]; sonst wenn (this.keyState [37] &&! this.keyState [39]) this.directionX = this.keyCodes [37]; sonst this.directionX = 0; if (! this.keyState [38] && this.keyState [40]) this.directionY = this.keyCodes [40]; sonst wenn (this.keyState [38] &&! this.keyState [40]) this.directionY = this.keyCodes [38]; sonst this.directionY = 0;
Hinweis: Es gibt mehrere Möglichkeiten, mit der Bewegung des Raumfahrzeugs umzugehen. Dies ist sicherlich nicht die sauberste, aber ich denke, es ist eine der am einfachsten zu verstehenden.
Wir sind bereit, speichern und neu laden und genießen!
Aktualisierung: Das Raumschiff kann den Bildschirm verlassen! Versuchen Sie, Ihre Position zu überprüfen, bevor Sie sie aktualisieren. Das Ergebnis können Sie hier überprüfen.
Raketenstart
Jetzt, da wir das Schiff kontrollieren können, wollen wir, dass es Raketen abfeuert.
Beginnen wir mit dem Hinzufügen des Sprites im Assets-Ordner:
PIXI.loader.add (["Assets / Cloud_1.png", "Assets / Cloud_2.png", "Assets / Raumschiff.png", "Assets / Rocket.png"]). Load (init);
Erstellen Sie eine neue Datei mit dem Namen Rocket.js auf der src Ordner und füge es hinzu index.html mit den anderen Typen:
<script src="../src/lib/pixi.min.js"></script> <script src="../src/Player.js"></script> <script src="../src/CloudManager.js"></script> <script src="../src/Rocket.js"></script> <script src=“../src/main.js"></script>
Volvamos a la clase de Jugadores. Queremos que Sein capaz de disparar un cohete si pulsa el botón de la barra espaciadora. La onKeyDown-Funktion Diese Ereignisse werden bereits abgefangen, sodass wir nur eine Bedingung mit dem gewünschten Schlüsselcode erstellen müssen (in diesem Beispiel die Leertaste):
onKeyDown (Schlüssel) {this.keyState [key.keyCode] = true; if (key.keyCode == 32) {let rocket = new Rocket (this.sprite.position.x, this.sprite.position.y); } if (key.keyCode == 37 || key.keyCode == 39) this.directionX = this.keyCodes [key.keyCode]; sonst wenn (key.keyCode == 38 || key.keyCode == 40) this.directionY = this.keyCodes [key.keyCode]; }}
Wir geben die Position des Raumschiffs im Raketenkonstrukteur an, also fixieren wir im Inneren nur seine Position auf die des Raumschiffs (mit einem Versatz, so dass es vor dem Schiff statt in der Mitte erscheint).
Also los, initialisiere Rocket.js mit dem Konstruktor:
Klasse Rocket {Konstruktor (x, y) {this.sprite = new PIXI.Sprite (PIXI.loader.resources ["Assets / Rocket.png"]. Textur); this.sprite.anchor.set (0,5, 0,5); this.sprite.position.set (x + 40, y); stage.addChild (this.sprite); }}
Okay, wenn Sie speichern und neu laden, können Sie Raketen (statisch) abfeuern, indem Sie die Leertaste drücken!
Damit sie sich bewegen können, müssen wir eine Array-Variable erstellen, die alle im Spiel vorhandenen Raketen enthält (wir wissen nicht, wie viele von ihnen sich auf der Bühne befinden):
let _list = new Array (); Klasse Rocket {static get list () {return _list; } statische Mengenliste (Wert) {_list = Wert; } ...
Die Variable _Liste Es befindet sich außerhalb der Klasse, da es statisch ist. Dies bedeutet, dass sein Wert eindeutig ist und nicht nur die Eigenschaft eines Objekts ist (im Gegensatz dazu). Wir können es jedoch abrufen und konfigurieren, wie wir wollen (mit den ersten beiden Zeilen der Klasse).
Wir können das aktuelle Objekt in diese Liste (innerhalb des Konstruktors) verschieben und gleichzeitig die Geschwindigkeitsvariable deklarieren:
this.speed = 20; Rocket.list.push (dies)
…. und fügen Sie auch die Aktualisierungsmethode hinzu:
update () {this.sprite.position.x + = this.speed; if (this.sprite.position.x> renderer.width * 1.1) {this.sprite.destroy (); Rocket.list.splice (Rocket.list.indexOf (this), 1); }}
Dies ist im Grunde das gleiche wie zuvor, wir aktualisieren die Position x der Rakete (und nicht der y weil es sich nicht vertikal bewegt) und genau wie Wolken entfernen wir es, wenn es außerhalb der Bildschirmgrenzen liegt, außer diesmal ist es der rechte Rand.
Danach in der Schleife main.js, Wir müssen nur die Raketenliste analysieren und die Aktualisierungsfunktion für jedes Element aufrufen:
Funktionsschleife () {cloudManager.update (); player.update (); Rocket.list.map ((element) => {element.update ();}); requestAnimationFrame (Schleife); renderer.render (Bühne); }}
Jetzt speichern, neu laden und testen!
Es feuert, aber es ist nicht automatisch. Sie müssen die Taste für jede Rakete drücken und wenn Sie sich nicht bewegen, ist es etwas seltsam, weil es so schnell feuert. Wir möchten in der Lage sein, automatisch zu schießen, wenn die Taste gedrückt gehalten wird, mit einer einstellbaren Geschwindigkeit.
Wir werden zwei neue Variablen im Player-Konstruktor definieren: die Feuerrate (die geändert werden kann) und die Abklingzeit, die der Wert des Timers ist:
this.fireSpeed = 10; this.fireCooldown = 0;
Wir müssen auch aktualisieren keyState um die Leertaste hinzuzufügen, weil wir wissen wollen, ob sie gedrückt ist oder nicht:
this.keyState = {32: false, 37: false, 38: false, 39: false, 40: false};
Dies ist die Funktion, die wir zum Feuern verwenden (wir müssen sie im Player-Update aufrufen):
updateFire () {if (this.fireCooldown <this.fireSpeed) this.fireCooldown ++; if (this.keyState [32] && this.fireCooldown> = this.fireSpeed) {let rocket = new Rocket (this.sprite.position.x, this.sprite.position.y); this.fireCooldown = 0; }}
Es ist ganz einfach: Wir erhöhen einfach den Timer von 0 auf die von uns eingestellte Feuerrate. Wenn die Taste gedrückt wird und der Timer den Wert erreicht hat, erzeugen wir eine Rakete und setzen den Timer auf 0 zurück.
Diese Funktion wird permanent in der Player-Update-Schleife ausgeführt:
update () {this.sprite.position.x + = this.directionX * this.speed; this.sprite.position.y + = this.directionY * this.speed; this.updateFire (); }}
Arbeit erledigt! Wenn Sie es schneller haben möchten, verringern Sie einfach die Aufnahmegeschwindigkeit (und erhöhen Sie sie für eine langsamere Geschwindigkeit).