Transkripte
1. Einführung: Was macht ein perfektes Spiel aus? Detaillierte, handgefertigte Grafiken,
Fantasy-Umgebungen und eine Vielzahl von
animierten Charakteren? Oder geht es eher um
die Spielmechanik, Physik für Interaktionen und die
KI, damit sich die
Kreaturen lebendig fühlen. Was ist die besondere Zutat im Rezept für die Spieleentwicklung? In diesem Kurs werden wir
tief in die Geheimnisse
von JavaScript,
Webanimation und
Frontend-Webentwicklung eintauchen tief in die Geheimnisse
von JavaScript, . Versuchen wir herauszufinden, was
ein großartiges Spiel ausmacht und wie
wir es von
Anfang bis Ende erstellen können , indem nur unseren eigenen
JavaScript-Code
ohne Frameworks und Bibliotheken verwenden. Dieser Kurs richtet sich an Anfänger, sind
jedoch einige Grundkenntnisse der Frontend-Webentwicklung
erforderlich , um
den größtmöglichen Nutzen daraus zu ziehen. Lass uns gehen.
2. Grundlegende Einrichtung: Ich verschenke in diesem
Kurs
jede Menge kostenlose Spielgrafiken, ich werde es mögen. Wir werden den blauen Ball kontrollieren. Ihre Aufgabe ist es,
Bruteier vor Wellen
hungriger Feinde zu schützen . Der Spieler kann
alle Spielobjekte positionieren indem er sie herumschiebt. Wir können das X und die
Jungtiere in Sicherheit bringen, oder wir können die
Feinde aus
dem Weg räumen, während wir
dieses Projekt bauen.
Ich werde Ihnen zeigen, wie
Sie HTML, CSS
und einfaches
JavaScript verwenden, um
viele wichtige Webanimations
- und Spielentwicklungstechniken zu implementieren viele wichtige Webanimations , wir werden Physik anwenden, um die Objekte eines
Spiels miteinander
interagieren zu lassen . Wir werden lernen, wie man
unser Spiel durch Drücken einer Taste neu startet , wie man den FBS
des gesamten Spiels steuert wie man periodische Ereignisse auslöst. Wir werden die meisten Kontrollen anwenden. Erfahren Sie, wie Sie
Richtungstabellen verwalten und animieren. Wir lösen Partikel aus und
animieren wenn ein bestimmtes Ereignis
eintritt, und vieles mehr. Gehen wir Schritt
für Schritt vor, um
sicherzustellen , dass wir den Code wirklich
verstehen. Und am Ende dieses Kurses wirst
du über alle
Fähigkeiten verfügen, die du benötigst, um
deine eigenen Spiele und
Animationsprojekte zu erstellen . Ich erstelle ein IMG-Element
mit der ID Overlay. Die Quelle wird
Overlay-Dot-PNG sein. Sie können alle Projektdateien herunterladen , darunter
die
Ressourcen im Abschnitt Ressourcen, es gibt einzelne Bilder und Sprites, da ich
sie in dieser Klasse verwende, sowie einen Bonus-Ordner mit Quelldateien, in denen
jedes Spielobjekt Gmb, aufgeteilt in
hochauflösende Teile. Sie können bearbeiten und animieren. Also, wenn du willst,
kannst du sie kombinieren und mit
Kunst
kombinieren, die ich dir für
andere Kurse gegeben habe , in denen wir dieses
Pilzwald-Thema
verwenden. Und Sie können Ihre eigenen
einzigartigen Spielumgebungen erstellen. Die gesamte Kunst in diesem
Kurs ist urheberrechtlich geschützt. Sie können
sie jederzeit herunterladen, ändern und in Ihren eigenen
Projekten wiederverwenden, wie Sie möchten. Ich gebe
dir bereits alle Kunst,
die du für diesen Kurs benötigst. Aber für diejenigen von Ihnen möchte
ich noch einen Schritt weiter gehen. Wenn Sie einen Grafikeditor
wie Photoshop haben , können Sie z. B. die Bilder
farblich verschieben, um noch mehr visuelle Abwechslung zu schaffen. Charakter-Quelldateien können
auch vergewaltigt und
in 2D-Sprite-Tools wie
Drachenknochen oder Wirbelsäule animiert in 2D-Sprite-Tools wie
Drachenknochen oder Wirbelsäule Schauen Sie sich die Quelldateien an und
verwenden Sie sie, wie Sie möchten. Es ist mein Geschenk an dich als Dankeschön dafür, dass du
deine Zeit mit mir verbracht hast. Wir haben also ein Basis-Setup in
index.HTML und stylen CSS. Gammas ist standardmäßig auf diese geringe
Größe von 300, 150 Pixeln eingestellt. Wenn ich seine Größe mit CSS festlegen würde, würde
ich
nur die Elementgröße festlegen. Und das würde meine
Zeichnungen überfordern. Html Canvas hat
eigentlich zwei Größen. Elementgröße, die
Größe der
Zeichnungsfläche , die unabhängig
eingestellt werden kann. Ich möchte, dass beide Größen
gleich sind , um Verzerrungen zu vermeiden. Also werde ich hier meine Leinwand
mit dem JavaScript dimensionieren. Ich packe alles in Load Event Listener ein, weil wir viele Kunst-Assets verwenden werden. Und ich wollte sicherstellen, dass
alle meine Bilder vollständig
geladen und verfügbar sind ,
bevor JavaScript-Code ausgeführt wird. Zuerst müssen wir
JavaScript mit
get element by ID auf
unser Canvas-Element lenken. Wir speichern diese Referenz in dieser benutzerdefinierten Variablen, die
ich zB Canvas nenne. Dann nehme ich diese
Variable und
rufe daraus die integrierte getContext-Methode auf und
übergebe sie als
Kontexttypargument an D. Dadurch wird ein
integriertes Objekt initialisiert, das alle Canvas-Eigenschaften
und Zeichenmethoden
enthält. Wir können sie jetzt
von dieser CD x-Variablen aus aufrufen. Wie ich bereits sagte, möchte
ich die Leinwandgröße,
sowohl die Größe der Elemente als auch die Größe der
Zeichnungsfläche,
auf den gleichen Wert setzen sowohl die Größe der Elemente als auch die Größe . Wir können das so machen. Die Breite der Leinwandpunkte beträgt 1.280 Pixel und die
Höhe der Leinwand beträgt 720 Pixel. Jetzt ist das vollständige
Hintergrundbild, das ich für Sie
vorbereitet habe , perfekt
sichtbar.
3. Objektorientierte Programmierung in JavaScript: Ich wollte dieses Spiel als
objektorientierte Codebasis schreiben ,
um es modularer zu gestalten Wir werden eine Klasse
für Spieler und eine
weitere Klasse für das Spiel haben , um die gesamte Spiellogik zu
verwalten. Das Hauptgehirn
dieser Codebasis. Wir benötigen außerdem eine
Animationsschleife, um
unser Spiel immer wieder zu zeichnen und zu aktualisieren , um die Illusion von Bewegung zu
erzeugen. Spieleklassenkonstruktor
erwartet einen Verweis auf das
Canvas-Element als Argument wie dieses. Im Inneren wandeln wir es in eine Klasseneigenschaft um und
müssen die Eigenschaft breiter machen. Und der Wert ist dieser
Punkt Canvas aus Zeile 15, Punktbreite. So wie das. Dadurch erhalten wir 1.280 Pixel, wie wir
es online einrichten Dasselbe tun
wir
für diese Punkthöhe. Wir nehmen einen Verweis auf das
Canvas-Element und
stellen die Breite und Höhe unseres Spiels so ein, dass sie der Breite und
Höhe von Canvas entsprechen. Wir werden dieses
Setup beenden, indem wir
dieses Canvas-Argument
etwas später mit dieser
Canvas-Variablen verbinden dieses Canvas-Argument
etwas später mit dieser
Canvas-Variablen . Wenn wir eine Instanz
unserer Spielklasse mit
dem Schlüsselwort new
erstellen unserer Spielklasse mit ,
werden wir früher dort sein. Ich zeig's dir. Bevor wir das tun,
muss der Spieler
auch Zugriff auf die
Breiten- und Höheneigenschaften
unseres Spiels haben Breiten- und Höheneigenschaften
unseres , da der
Spieler beispielsweise wissen muss wann er sich außerhalb
des Spielbereichs bewegt und so weiter. Ich werde ihm Zugriff auf
die gesamte Spielklasse und
all ihre Eigenschaften
und Methoden geben die gesamte Spielklasse und , indem ihm eine Referenz
auf diese Spielklasse als
Argument
übergebe ich ihm eine Referenz
auf diese Spielklasse als
Argument
übergebe. Im Inneren konvertieren
wir es in
eine Klasseneigenschaft. Denken Sie daran, dass ich keine Kopie von
Game Object
erstelle, wenn ich Spielerobjekte in
JavaScript
erstelle . Es handelt sich um sogenannte
Referenzdatentypen. Dieses Punktspiel hier auf Zeile
neun erstellt also keine Kopie. Es zeigt nur auf ein
Feld im Speicher dem unser
Hauptspielobjekt gespeichert ist. Der Code in einem
Klassenkonstruktor. Es wird ausgelöst, wenn wir
eine Instanz einer Klasse
mit dem Schlüsselwort new erstellen eine Instanz einer Klasse
mit dem Schlüsselwort new Das werden
wir in einer Minute tun. Ich möchte, dass unsere Codebasis
automatisch einen Spieler erstellt wenn wir eine Instanz
unseres Hauptspielobjekts erstellen. Also kann ich das
im Klassenkonstruktor machen. Ich erstelle eine Eigenschaft
namens This Dot Player und setze sie wie folgt auf
einen neuen Player. Ich kann mir vorstellen, dass
der Spielerklassenkonstruktor Online Aid
das Spiel als Argument erwartet. Also übergebe ich es mit diesem Schlüsselwort, da wir uns hier
in dieser Spielklasse befinden. Dieses Schlüsselwort bezieht sich hier
auf das gesamte Spielobjekt. Hier in Zeile 18
erstellen wir eine Instanz der Spielerklasse und
speichern sie als diesen Punkt Player-Eigenschaft der Spielklassenstruktur in unserem Code. Dadurch wird
automatisch ein Spieler erstellt. Wenn wir ein Spiel erstellen, erstellen
wir eine Instanz
eines Spielobjekts wie diese benutzerdefinierte
Variable, die ich zB
game nenne , und ich
setze sie auf new game. Zeile 14 kann ich sehen, dass der Spielklassenkonstruktor Canvas als Argument
erwartet. Also übergebe ich die
Canvas-Variable von der Zeile an diese Variable
wird in eine Klasseneigenschaft umgewandelt und
die Breite und Höhe des Spielbereichs werden wie geplant
daraus extrahiert. Lassen Sie uns überprüfen, ob
alles funktioniert hat, indem diese
Spielvariable
konsolidieren. Toll, ich kann die richtigen
Breiten-
und Höheneigenschaften sehen und wir haben dort auch eine Instanz der
Spielerklasse. Dies ist eine der Möglichkeiten, wie
Sie
Ihre Objekte in einer
objektorientierten JavaScript-Codebasis organisieren und verbinden können. Sie daran, dass die Reihenfolge, in wir
die
Klassen definieren, wichtig ist. Javascript-Datei wird zeilenweise
von oben nach unten gelesen. Javascript-Klassen werden zwar gehisst, aber sie werden
erst initialisiert , wenn diese bestimmte
Zeile stimmt. Spielerklasse muss also
definiert werden, bevor sie verwendet wird. Eine sehr gute Idee wäre, unser JavaScript in
einzelne Module
aufzuteilen und unsere Klassen nach Bedarf
zwischen Dateien zu importieren
und zu exportieren . Für dieses Projekt werde ich den gesamten Code in
einer einzigen JavaScript-Datei
schreiben einer einzigen JavaScript-Datei um ihn so
anfängerfreundlich wie möglich zu halten. Die
Verwendung von
JavaScript-Modulen würde erfordern, Verwendung von
JavaScript-Modulen würde erfordern wir diesen Code
über einen lokalen Server ausführen. Es würde den
Code nicht mehr ausführen, indem Sie einfach
eine Index-HTML-Datei in
einem Webbrowser öffnen mehr ausführen, indem Sie einfach
eine Index-HTML-Datei in
einem Webbrowser Wenn Sie mehr Erfahrung haben, wird
es für Sie
sehr einfach sein das Projekt mit mir abzuschließen. Und wenn Sie möchten, können
Sie einzelne Klassen selbst
in separate Module aufteilen . Dieser Kurs richtet sich an Anfänger Konzentrieren wir uns
also auf
objektorientierte Prinzipien und
Animationstechniken.
4. Den Spieler zeichnen: Die Funktion, die sich auf einem
Objekt befindet, wird Methode genannt. Der Spieler muss die
Zeichenmethode verwenden, um zu zeichnen und zu animieren. Es wird erwarten, dass der Kontext
als Argument dient, um zu spezifizieren, auf welche Art von
uns wir zurückgreifen wollen. Wir werden dieses
Kontextargument
ab Zeile drei mit unserer CTX-Variablen verbinden ab Zeile drei mit unserer CTX-Variablen Wenn wir diese Draw-Methode
etwas später aufrufen , werde
ich es Ihnen zeigen. Ich wollte
zuerst einen
einfachen Kreis zeichnen , der unseren Spieler darstellt. Um einen Kreis auf Canvas zu zeichnen, nehmen
wir Kontexte und rufen begin path auf, um JavaScript
mitzuteilen, dass
wir mit dem
Zeichnen einer neuen Form beginnen möchten. Wir wollen die vorherige Form schließen. Wenn es welche gibt,
rufen wir die eingebaute Arc-Methode auf, die
mindestens fünf Argumente erwartet. Es erwartet X- und
Y-Koordinaten des
Mittelpunkts des Kreises. Sein Radius-Startwinkel
in Bogenmaß, gemessen von der positiven X-Achse, und einem
Winkel, in dem der Bogen endet, wiederum in Bogenmaß, gemessen
von der positiven X-Achse. Es gibt ein optionales sechstes
Argument für gegen den Uhrzeigersinn. Wenn wir ihn nicht definieren, wird er standardmäßig auf false gesetzt,
was bedeutet, dass der Bogen im Uhrzeigersinn gezeichnet
wird. Startwinkel ist also 0 rad und der Endwinkel ist Math.Pi mal
zwei, es ist ein voller Kreis. Jetzt können wir wählen, ob wir Füllung aufrufen, um die Form mit Farbe zu füllen,
Strich, nur um die Form zu
umreißen. Oder wir könnten beide benutzen. werden wir bald tun. Wie zeichnen wir
den Spieler eigentlich auf Leinwand? In der Spielklasse erstelle
ich nun eine Methode, die ich zB
Render nenne . Diese Methode zeichnet und
aktualisiert alle Objekte in unserem Spiel. Es erwartet Kontexte
als Argument. Darin nehme ich diesen Punkt Spieler
aus Zeile 23 und über diese Referenz
greifen wir
auf die Ziehmethode für die Spielerklasse zu, die wir gerade ab Zeile 11
definiert haben. Diese Methode enthält
den Code zum Zeichnen eines Kreises,
der den Spieler darstellt. Ich kann mir vorstellen, dass es
Kontexte als Argument erwartet, also gebe ich es an diesen Kontext weiter, wir an die Render-Methode übergeben haben. Jetzt kann ich diese
Spielvariable nehmen, die eine Instanz
der gesamten Spielklasse
enthält. Und von dort rufe ich Render und übergebe es an CTX. Ab Zeile drei
wird diesem CTX hier ein
Variablennamenskontext zugewiesen und er wird an die
Zeichenmethode der Spielerklasse weitergegeben . Schön, wir zeichnen einen schwarzen Kreis,
der den Spieler darstellt, der hier ist. Vielleicht kannst du es nicht sehen. Geben wir ihm also verschiedene X - und Y-Koordinaten, um ihn zu bewegen. Anstatt
all diese Werte fest zu codieren, möchte
ich, dass Sie Eigenschaften
für die Player-Klasse erstellen. Dann benutze die hier. Wir benötigen X- und Y-Koordinaten
für die Spielerposition. Aber weil wir in diesem Kurs über
Positions- und Hitboxen
und Charakterbilder
lernen , die sehr unterschiedliche
Formen und Größen
haben können . Ich muss eine Eigenschaft für die
X- und Y-Position
des Spieler-ID-Feldes
erstellen . Und ich benötige
eine andere X- und
Y-Eigenschaft für das
Spieler-Spritesheet-Bild. Es wird mehr
Sinn machen, wenn wir es bauen. Ich möchte
meine Variablennamen sehr explizit angeben, um absolut klar zu
machen , welcher Wert die Position
des Kollisionsfeldes und welcher Wert die
Position einer Tabelle ist. Anstatt diese
Eigenschaften also nur x und y zu benennen, ich sie Kollision
x und College sowie Y-, X- und Y-Position
der
Kollisions-Hitbox des Mittelpunkts
des Kollisionskreises. Alle Objekte in unserem heutigen
Spiel werden kreisförmige
Trefferfelder
haben, weil ich euch zeigen
wollte , wie
man sie auf
der Startposition
des Spielers aneinander entlang
schieben und gleiten lässt, sodass sie sich genau in der Mitte
des Spielbereichs befinden. Kollision x wird also dieses
Punktspiel ab Zeile neun sein. Und aus dieser Eigenschaft werde
ich die
Breite aus Zeile 23 extrahieren. Und in der Mitte, also mal 0,5 Kollision,
wird y gleich sein. Dieser Punkt spielt mit der
Höhe mal 0,5. Jetzt kann ich diese
Werte als X- und
Y-Argumente für die
Canvas-Arc-Methode wie diese verwenden . Jetzt können wir den
Spieler bewegen, indem wir die
Werte für Kollision
und Kollision ändern . Warum Immobilien? Wir benötigen außerdem eine Eigenschaft
namens Kollisionsradius, die die Größe
dieses kreisförmigen
Spielers definiert . Er hatte Bücher. Ich verwende es auch hier innerhalb
der Arc-Methode. Standardfüllfarbe
ist immer schwarz. Ich kann die
FillStyle-Eigenschaft
auf Weiß so überschreiben,
indem ich bestimmte Arten von uns verwende. Anstatt
die Form mit Farbe zu füllen, könnten
wir sie auch einfach streichen. Schon wieder. Standardmäßig beträgt die Linienbreite des Strichs ein Pixel und
die Farbe ist schwarz. Ich habe die Linienbreite auf
drei Pixel eingestellt und
Strichstil auf Weiß gesetzt. Beachten Sie, dass ich
diese Canvas-Eigenschaften
außerhalb einer Klasse oder Methode definiere . Ich mache das mit Absicht,
weil dieser Code beim
ersten Laden der Seite
nur einmal ausgeführt wird . nicht immer möglich
, wenn Sie
mehrere Objekte mit
unterschiedlichen Feldern,
Stilen und Strichfarben haben mehrere Objekte mit
unterschiedlichen Feldern, . In diesem Fall
müssen Sie diese Eigenschaften
innerhalb der Zeichenmethode definieren und immer wieder zwischen ihnen
wechseln. Das Problem dabei
ist, dass die Draw-Methode 60
Mal pro Sekunde aufgerufen
wird. Und Veränderungen in einem
solchen Zustand könnten die
Leistung teuer werden. Es ist eine gute Idee, den Code so zu
strukturieren dass Sie einen Zustand so
wenig wie möglich ändern. Und wenn ich Canvas-Status sage, meine
ich alles, von Transformationen bis hin zu wechselnden Farben von
FillStyle und Strichstil. Deshalb habe ich diesen Code hier eingefügt anstatt
ihn direkt in
die Zeichenmethode zu integrieren, damit er so wenig wie möglich
ausgeführt gleichzeitig die Farben
und Einstellungen nach Bedarf angewendet werden. Ich kann Fill auch hier anrufen. Jetzt
füllen und streichen wir denselben Pfad, der mit der Arc-Methode definiert
ist. Ich möchte, dass die Füllung weiß ist, aber ich wollte
leicht transparent sein. Kind of us hat eine globale
Alpha-Eigenschaft, mit der die
Opazität der Formen, die
wir zeichnen, festgelegt werden. Das Problem ist, dass, wenn ich
globales Alpha mit einem
anderen Wert sagte ,
alles, was danach gezeichnet
wird, halbtransparent sein wird. Ich möchte, dass die Transparenz nur für die Füllfarbe des
Spielerkollisionskreises gilt , um
bestimmte Einstellungen
nur auf bestimmte Draw-Calls zu beschränken . Wir können diesen
Zeichnungscode zwischen den integrierten Canvas-Methoden
Safe und Restore umschließen. Wenn ich dann
Globales Alpha auf 0,5 setzen würde, wirkt sich das nur auf diese
spezifische Zeichenaktion aus. In unserem Fall
wirkt sich dies nur auf die Füllung dieses Kreises aus. Methode save erstellt also eine
Momentaufnahme des aktuellen Zustands, einschließlich des FillStyle-Zustands, der Opazität der
Linienbreite sowie der
Transformationen und Skalierung. Wenn wir das tun, kann ich an dem Zustand
, den ich will, ändern. In diesem Fall habe ich die Opazität einfach auf 0,5
gesetzt. Diese Füllfarbe wird durch diese
Änderung der Opazität
beeinflusst. Und dann rufen wir Restore auf und stellen
alle Arten von
Einstellungen auf das zurück, was sie waren als wir die
zugehörige Speichermethode zum ersten Mal aufgerufen haben. Aus diesem Grund wird der Strich durch
eine verringerte Opazität
nicht beeinträchtigt. Methoden
zum Speichern und Wiederherstellen können wir bestimmte
Zeichnungseinstellungen
nur zur Auswahl der
Formen anwenden , ohne dass sich dies auf die übrigen
Canvas-Zeichnungen auswirkt.
5. Maussteuerung: Ich möchte den Spieler mit der Maus
bewegen. Wir wissen bereits, dass der
Code im
Spielklassenkonstruktor an
dem Punkt
ausgeführt wird , an dem wir
mit dem Schlüsselwort new
eine Instanz dieser Klasse erstellen . Wir
nutzen Daten, indem automatisch eine
Instanz der Spielerklasse erstellen.
Wir können hier tatsächlich jeden
JavaScript-Code ausführen. Ich kann sogar
Event-Listener hier platzieren , um sicherzustellen, dass sie
automatisch angewendet werden. Wenn ich eine
Instanz der Spielklasse erstelle, erstelle
ich einen Event-Listener
für das Mousedown-Ereignis. Wenn die Maustaste angeklickt wird, wird
der Code in dieser
Callback-Funktion ausgeführt. Ich habe getestet, indem ich einfach das Wort Maus auf der Konsole
protokolliert habe. Wenn ich Änderungen speichere
, weil ich diese
Klasse bereits online für D6
instanziiere. D7-Listener wird
automatisch angewendet. Wenn ich jetzt auf Canvas klicke, löst das
Konsolenprotokoll nette Callback-Funktion
auf EventListener Generiert automatisch ein
Ereignisobjekt, das
alle Arten von Informationen über
das gerade stattgefundene Ereignis enthält alle Arten von Informationen über . Um Zugriff auf dieses Objekt zu erhalten, müssen
wir
ihm nur einen Variablennamen geben. Du kannst es nennen,
wie du willst. Aber die Konvention
ist normalerweise Event oder E. Lassen Sie uns dieses Ereignis auf der Konsole protokollieren. Ich klicke auf Canvas
und sehe es hier. Ich habe es inspiziert. Sie können
sehen, dass es
viele Informationen über diesen Mausklick enthält, z. B. sehen
wir hier die X- und
Y-Koordinaten dieses Klicks. Es gibt viele andere
Eigenschaften, die uns sagen, welche Maustaste gedrückt wurde
und viele andere Dinge. Ich möchte, dass du die
Koordinaten des Klicks nimmst und sie als Eigenschaften
auf dem Hauptspielobjekt speicherst. Und von dort aus können
wir auch von unserem
Spielerobjekt aus
auf sie zugreifen. Ich erstelle eine neue Eigenschaft in der Spielklasse namens
diese Punktmaus. Es wird ein Objekt
mit der Eigenschaft x sein, wobei Standardwert dieser
Punktbreite mal 0,5 ist. Und y wird diese
Punkthöhe mal 0,5 sein. Also die Mitte der Leinwand,
horizontal und vertikal. Wir werden auch überwachen
wollen, wann die Maustaste gedrückt
wird. Anfänglich
wird es auf false gesetzt. Wenn ich die Punkte X und Y in der Konsole löse, können
Sie sehen,
dass wir X- und
Y-Koordinaten erhalten , wenn wir um uns herum
klicken. Das Problem ist, dass die
Koordinaten von den oberen linken Rändern
des Browserfensters stammen. Ich möchte stattdessen
die Clip-Koordinaten von
der oberen linken Ecke
von Canvas aus messen . Wenn wir also hier
in der oberen linken
Ecke der Leinwand klicken , erhalten
wir x und y Null Null. Dafür können wir für
dieses automatisch generierte
Ereignisobjekt eine
andere Eigenschaft namens Offset x verwenden , die uns die
horizontale Koordinate
des Klicks auf den Zielknoten gibt. In unserem Fall
ist der Zielknoten, das Ziel des Klicks, quasi ein Element. Jetzt können Sie sehen, wie die
Werte sehr nahe an
Null gehen , wenn ich in die
Nähe des Randes von Canvas klicke. Ich könnte den
Event-Listener auch
dem Canvas-Element selbst hinzufügen und nicht dem gesamten
Browserfensterobjekt. Wenn ich näher an
die obere linke Ecke klicke, erhalten
wir
Werte nahe 00. Perfekt. Wahrscheinlich
wäre es sinnvoll, wenn ich stattdessen diese Punkt-Canvas-Eigenschaft
hier ab Zeile 31
verwende, da wir uns in
einer Klasse befinden und die Referenz auf
Canvas hier verfügbar ist. Jetzt erhalten wir die Koordinaten
des Klicks, gemessen in Pixelabstand von der
oberen linken Ecke von Canvas. Selbst wenn wir
die Größe des Browserfensters ändern, funktioniert
das gut. Ich möchte, dass Sie die
zyklischen Koordinaten in der
Mauseigenschaft
unseres Kunden speichern , damit sie für andere
Objekte in unserer Codebasis
verfügbar sind , z. B. für den Player im
Maus-Down-Event-Listener. Ich nehme die Eigenschaft
Punkt x der Hundemaus aus Zeile 36 und setze sie gleich
dem E-Punkt-Offset x. Dieser Punkt Maus-Punkt y
wird der E-Punkt-Offset sein. Warum? Ich erstelle
ein weiteres Konsolenprotokoll und werde mir diese neu
aktualisierten Mauseigenschaften ansehen. Wenn ich auf Canvas klicke, erhalten
wir eine Fehlermeldung, die besagt, dass Eigenschaften
für ein undefiniertes bestimmtes
x online für D3
nicht festgelegt werden können. Sie sagt mir, dass ich die
X-Eigenschaft für etwas
, das undefiniert ist, nicht festlegen kann. Aus irgendeinem Grund ist
diese Punktmaus
undefiniert, wenn sie
vom Event Listener aus aufgerufen wird. liegt daran, dass
diese Callback-Funktion
bei der Ausführung des Event-Listeners vergessen hat, dass sie
ursprünglich
in diesem
Spielklassenkonstruktor definiert wurde. Es vergisst, wofür dieses
Schlüsselwort steht. Dadurch wird erwartet, dass sich der Event-Listener daran erinnert,
wo es zuerst definiert wurde wo es sich im lexikalischen
Umfang unserer Codebasis befindet. Wir können hier stattdessen einfach die
ES6-Pfeilfunktion verwenden. Eine der Besonderheiten der ES6-Pfeilfunktionen besteht darin
, dass sie den Verweis auf
dieses Schlüsselwort automatisch aus dem übergeordneten
Bereich
übernommen haben, in dem alle Funktionen enthalten sind. Denken Sie daran, wo in der Codebasis sie ursprünglich lexikalisch
deklariert wurden. Und sie passen
ihr Schreibtischschlüsselwort an, dass es auf das richtige Objekt
verweist, auf das übergeordnete Objekt. Jetzt wurden dieser Mauspunkt x und dieser Look-Mauspunkt y
korrekt
auf die neuen Werte aktualisiert,
sodass die aktuellen
Mauskoordinaten
überall in unserer Codebasis verfügbar sind korrekt
auf die neuen Werte aktualisiert, sodass die aktuellen
Mauskoordinaten
überall in unserer Codebasis verfügbar ,
wann immer sie benötigt werden. Später lösche ich
die Konsolenprotokolle. Wenn das Mauszeigereignis passiert. Ich sagte, der Preis liegt bei
Zeile 38 bis wahr. Ich habe diesen Event-Listener kopiert. Dieser wird
für das Mouse-Up-Event sein. Wenn die
Maustaste losgelassen wird, bleibt hier
alles beim Alten
und die Brust
wird auf falsch zurückgesetzt. Ich erstelle auch einen Event-Listener
für Mausbewegungsereignisse. Lassen Sie uns nachfragen, um das zu überprüfen. Ja, das funktioniert. Lass uns den Spieler bewegen.
6. Den Spieler bewegen: Erstellen Sie eine benutzerdefinierte
Methode, die ich update nenne. Drinnen sagte ich
Kollision x von Zeile 14 bis zur aktuellen X-Position der
Maus. Und Kollision y wird die aktuelle
Y-Position der Maus sein, so wie hier. Um diesen Code auszuführen,
müssen wir tatsächlich die Update-Methode aufrufen. Ich nenne es von
innen Render hier unten. Ich lösche dieses Konsolenprotokoll. Wenn wir eine Bewegung
sehen wollten, müssen
wir immer wieder
Render anrufen. Also lass es uns hier in
die Animationsschleife legen. Ich nenne den integrierten Request
Animation Frame eine Methode, die sich auf dem
Browserfensterobjekt befindet, aber wir können ihn auch
direkt so aufrufen. Wenn wir wollen. Ich übergebe es, animiere den Namen der übergeordneten Funktion, um
eine endlose Animationsschleife zu erstellen. Jetzt muss ich animate aufrufen , um die Animation tatsächlich zu starten. Wenn ich die Maus über
uns bewege, bekommen wir Spuren. Ich wollte nur die
aktuellen Animationsbilder sehen. Also verwende
ich zwischen jeder Schleife die eingebaute durchsichtige
rechteckige Methode , um die alte Farbe zu entfernen. Ich wollte den
gesamten Leinwandbereich von der
Koordinate Null bis zur
Leinwandbreite und Leinwandhöhe löschen . Jetzt bewegt der Spieler
die Maus, während wir sie durch
Cannabis bewegen, perfekt. Ich wollte eine Linie
zwischen Maus und Spieler um deutlich zu zeigen,
in welche Richtung sich der Spieler bewegen wird. In der Draw-Methode in
der Spielerklasse beginnen
wir eine neue Form
von Colin Begin Bath. Move-to-Methode definiert die Start-X- und
Y-Koordinaten der Linie. In diesem Fall
wollte ich, dass die Linie von den Koordinaten
des Spielerobjekts ausgeht. Zeile zwei Methoden, wir legen das Ende in den X- und
Y-Koordinaten der Linie fest. In diesem Fall sind es die X - und Y-Koordinaten der Maus. Dann rufen wir Strike auf, um die Grenze
tatsächlich zu ziehen. Das funktioniert, aber
da der Spieler den Mauszeiger
immer so schnell
einholen kann, können
wir die Linie kaum sehen. Geben wir dem Spieler Geschwindigkeit, Geschwindigkeit X horizontale Geschwindigkeit. Anfangs habe ich
es auf Nullgeschwindigkeit eingestellt. Warum die Vertikalgeschwindigkeit sie auch
zunächst auf Null gesetzt hat. In der Aktualisierungsmethode berechnen
wir die Geschwindigkeit x. Zuerst setze ich sie auf codiert ein Pixel
pro Animationsbild. Und ich erhöhe die
Spielerexposition um die horizontale Geschwindigkeit. Das hat funktioniert. Ich mache es auch
für die vertikale Position. Es gibt zwei Möglichkeiten, wie wir den Spieler
dazu bringen können, der Maus zu folgen. Eine Möglichkeit wäre, einfach den
Unterschied zwischen
der aktuellen Mausposition und der Spielerposition auf
der horizontalen X-Achse zu ermitteln. Und stellen Sie diesen Unterschied
als horizontale Geschwindigkeit ein. Und das tun wir auch
für vertikale Bewegungen. Jetzt korrigiert
die Spielerposition
den Unterschied um
die gesamte Entfernung. So wird die
Bewegung sofort ausgeführt. Was ist, wenn ich es nur um
das Fünfundzwanzigste
des Unterschieds zwischen
Spieler- und Mausposition
für das
horizontale Animationsbild bewegen das Fünfundzwanzigste
des Unterschieds zwischen Spieler- und Mausposition lasse? Und auch vertikal. Ich erstelle eine
Klasseneigenschaft für dx, Abstand zwischen
Maus und Spieler horizontal und
vertikal. Ich ersetze diese Werte hier. Es ist einfacher, es so zu lesen. Ich möchte nicht, dass der Spieler
ständig folgt,
wenn wir die Maus über Canvas bewegen. Ich will nur, wenn wir irgendwo
klicken oder wenn wir die
Maustaste gedrückt halten und uns bewegen. Im
Mausbewegungs-Event-Listener
sage ich , dass nur die X- und
Y-Mausposition aktualisiert werden. Wenn die Maus gedrückt ist. Jetzt kann ich herumklicken, um den Spieler
zu dieser Position zu bewegen, oder ich kann diesen Punkt verschieben, während ich die
Maus gedrückt halte. Perfekt. Das Problem bei dieser
Technik ist, dass die Geschwindigkeit nicht konstant ist. Bewegt sich anfangs sehr schnell, denn ein Zwanzigstel
der Entfernung ist zunächst ein großer Brocken,
wenn sie weit voneinander entfernt sind. Aber je näher sie kommen, desto wird
ein
Zwanzigstel dieser Entfernung kleiner wird
ein
Zwanzigstel dieser Entfernung und die Anzahl der Pixel, die
pro Animationsframe zurückgelegt werden müssen, verringert. Vielleicht wünschst du dir diese besondere
Emotion für dein Projekt, aber für das Spiel, das
wir heute entwickeln, wollte
ich, dass sich der Spieler mit einer konstanten Geschwindigkeit
bewegt. Wir müssen die
zweite Technik für
diese Methode zur Aktualisierung von Erkenntnissen verwenden . Ich habe die Entfernung berechnet. Wir haben bereits dx, den horizontalen Abstand zwischen Maus
und Spieler. Wir haben auch d, den vertikalen Abstand zwischen Maus und
Spieler. Wir wollen
den Abstand zwischen
diesen beiden Punkten berechnen . können wir tun, indem wir die Hypotenuse
berechnen, die längste Seite dieses
imaginären rechtwinkligen Dreiecks. Wir können
die Formel des Satzes von Pythagoras verwenden, oder in JavaScript haben wir diese integrierte mathematische
Punkthypotenuse-Methode. Diese Methode berechnet die Länge der
längsten Seite für uns, wenn wir sie als Argumente an
andere Seiten des
Dreiecks übergeben . Denken
Sie daran, dass sie d-,
dy- und dx-Sekunden erwartet , was etwas unerwartet sein könnte wenn Sie das noch nie gesehen haben. horizontale Geschwindigkeit ist
das Verhältnis zwischen dx, der
horizontalen Entfernung zwischen
Maus und Spieler und der tatsächlichen Entfernung.
Sandwich-Geschwindigkeit. Warum? Dies ist das Verhältnis
zwischen dem Abstand auf vertikalen Y-Achse und
dem tatsächlichen Abstand zwischen den beiden Punkten. Als Backup, wenn einige
dieser Werte
zunächst undefiniert sind , sagen wir oder
Null. So werden
wir in horizontale
und vertikale Distanzen unterteilt,
diese Seiten durch die
tatsächliche Entfernung, die durch die längste
Seite eines rechtwinkligen Dreiecks
dargestellt wird. Dx und DY sind immer eine
kleinere Zahl als der Abstand, da
der Abstand die
Hypotenuse ist , die längste Seite. Aus diesem Grund liegen
die Werte, die wir für Geschwindigkeit x und Geschwindigkeit y
erhalten , irgendwo zwischen 0-1. Das gibt uns die
richtige
Bewegungsrichtung bei konstanter Geschwindigkeit. dieser Technik gibt es noch viel mehr zu
sagen. Aber im Moment ist das
alles, was wir wissen müssen. Ich komme darauf zurück. Jetzt. Der Spieler bewegt sich mit konstanter Geschwindigkeit
auf die Maus zu. Ich kann einen Geschwindigkeitsmodifikator haben. Ich setze es auf fünf, z. B. I. Benutze es hier unten und ich
multipliziere Geschwindigkeit x und Geschwindigkeit. Warum durch diesen Modifikator, nachdem wir den Geschwindigkeitsmodifikator hinzugefügt haben, wird
der Spielerkreis eigentlich
nie mehr still stehen. Es wird hin und
her schwingt, in diesem Fall um
50 Pixel, weil der Geschwindigkeitsmodifikator es in beide Richtungen
zu weit drückt. Ich kann das beheben, indem ich sage, bewege den Spieler
nur, wenn
der Abstand zwischen Maus und Spieler
größer als der Geschwindigkeitsmodifikator ist. Else sagte Geschwindigkeit x zu Null
und Geschwindigkeit y auch zu Null. Das funktioniert perfekt. Deshalb haben wir eine einfache und
eine fortgeschrittenere Technik behandelt , um den Spieler
dazu zu bringen, sich der Maus
zuzubewegen. Jetzt ist es an der Zeit, solide,
zufällige, sich
nicht überlappende Hindernisse hinzuzufügen .
7. Hindernisse erstellen: Ich erstelle eine Klasse, die
ich Hindernis nenne. Konstruktor wird
das Spiel als Argument erwarten. Und drinnen habe ich
diese Referenz
wie zuvor in
eine Klasseneigenschaft umgewandelt . Es wird auf
das Hauptspielobjekt zeigen. Und das haben wir gebraucht
, weil wir über diese Referenz
Zugriff auf Spielbreite und -höhe, Mauspositionen und
einige andere Eigenschaften haben. Wir werden später hinzugefügt. Wir werden über
diese.name-Referenz
ab Zeile 54 Zugriff auf
all diese Werte innerhalb der Hindernisklasse haben. Wie ich bereits erklärt habe, den Objekten in unserem Spiel eine kreisförmige, werden
wir bei
den Objekten in unserem Spiel eine kreisförmige,
kollisionsbeheizte Box
und eine separate
rechteckige Tabelle haben . Aus diesem Grund werde
ich diese Eigenschaften mit sehr
aussagekräftigen Namen benennen, um
sicherzustellen , dass klar ist,
was passiert, wenn
wir später
alles bewegen und animieren. Kollision x, der zentrale
Punkt des Kollisionskreises jedes Hindernisses, ist ein zufälliger Wert zwischen Null und der
Breite des Spiels. Diese Breite stammt hier
von Zeile 62. Und wir greifen über
diese Punktspielreferenz darauf zu, die
wir in Zeile 54 erstellt haben. Wir werden auch eine Kollision brauchen. Warum vertikaler Mittelpunkt
des Kollisionsbereichskreises. Es wird ein zufälliger Wert
zwischen Null und Spielhöhe sein. Dieser Wert für den
Kollisionsradius beträgt 60. Wir müssen auch eine Methode
zeichnen, die Kontexte als Argument
erwartet. Ich möchte, dass der Kreis, der einen Trefferbereich
jedes Hindernisses
darstellt , genauso aussieht wie der Kreis, der den Spieler
darstellt. Also nehme ich den
Zeichencode von hier oben, nur für den Kreis. Also diesen Codeblock, ich kopiere ihn und
füge ihn hier ein. Dieser Code funktioniert hier,
weil genau wie bei dem Spieler,
den wir
unsere Hinderniseigenschaften
gegeben haben , Kollisions-X, Kollisionsradius und
Kollisionsradius genannt werden. Wir benötigen auch
denselben Namen all diese Eigenschaften zwischen
verschiedenen Objekttypen. Falls wir
eine wiederverwendbare
Kollisionserkennungsfunktion haben möchten . Ich werde dir später zeigen, wie man das
benutzt. Es ist ganz einfach. Wie dem auch sei, hier haben wir einen
Code zum Zeichnen eines Kreises mit einem Radius von 60 Pixeln
mit 50% Opazität, weißer Füllung und weißem, vollständig sichtbarem Strich mit voller
Opazität. Diese Hindernisklasse
hier ist eine Blaupause. Wir werden es verwenden, um
individuelle Hindernisobjekte zu erstellen. Die eigentliche Logik zum
Erstellen und Verwalten dieser Objekte wird sich
hier unten in der Hauptspielklasse befinden, die das Hauptgehirn
unserer Codebasis darstellt. Ich erstelle eine Eigenschaft namens
This Dot Obstacles. Es wird ein Array sein, das
alle derzeit aktiven
Hindernisobjekte enthält . Es beginnt zunächst als
leeres Feld, die Anzahl der Hindernisse
beträgt z. B. fünf. Ich erstelle eine benutzerdefinierte Methode für
unsere Spielklasse, ich rufe sie z. B.
in der IT auf , initialisiere ihre Aufgabe. Ihre Aufgabe besteht
vorerst darin,
fünf zufällige
Hindernisobjekte zu erstellen und
sie in die
Hindernisanordnung zu legen , die wir gerade definiert haben. Im Inneren erstelle ich eine For-Schleife. Es wird
fünfmal fahren, weil wir auf Linie 76 die
Anzahl der Hindernisse auf
fünf erhöht haben. Jedes Mal, wenn es ausgeführt wird, nimmt es dieses Punkt-Hindernis-Array
aus Zeile 77 und ruft
darauf die eingebaute
Array-Push-Methode auf, um Methode als ein
oder mehrere Elemente an das Ende eines Arrays
zu
pushen , und es gibt die neue
Länge des Arrays zurück. Ich werde ein neues
Hindernis wie dieses überwinden. Das neue Schlüsselwort sucht nach einer Klasse mit dem Namen Hindernis, und es wird seinen
Klassenkonstruktor online auslösen 53,
ich kann mir vorstellen, dass der
Hindernisklassenkonstruktor Spiel als Argument
erwartet. Hier unten befindet sich die Methode init
innerhalb dieser Spielklasse, also übergebe ich ihr das Schlüsselwort, this, das hier
das gesamte Spielobjekt
mit all seinen Eigenschaften
und zugehörigen Methoden darstellt mit all seinen Eigenschaften
und zugehörigen Methoden all diese innerhalb der Hindernisklasse verfügbar
macht. Jetzt spiele ich
das Spiel auf der Konsole und
sehe , dass das Hindernis-Array komplett leer
ist. Um es zu füllen, muss
ich nur die Init-Methode aufrufen. Wir haben einfach so geschrieben. Jetzt kann ich sehen, dass das Array fünf Hindernisobjekte
enthält. Ich überprüfe noch einmal, ob
alle Eigenschaften Werte haben. Wenn Sie
in einem dieser Elemente undefined sehen, bedeutet
dies, dass in Ihrer Codebasis ein
Problem vorliegt. Alles ist gut hier. So wie ich hier
ein Update zeichne und der Spieler aus dem
Spiel rendert, möchte
ich alle fünf
Hindernisobjekte auf Leinwand zeichnen. Ich nehme die Hindernisreihe von -77. Wir wissen bereits, dass es
fünf Objekte enthält und dass jedes
dieser Objekte mit
unserer benutzerdefinierten
Hindernisklasse von Ich bin 52 erstellt wurde . Sie alle haben Zugriff auf diese Ziehmethode, die wir in Zeile 59
definiert haben. Also hier beim Rendern nehme
ich das Hindernis-Array, ich rufe das eingebaute Array
für jede Methode auf, die forEach-Methode führt eine bereitgestellte Funktion einmal
für jedes Array-Element aus. Zuerst müssen wir
einen Variablennamen definieren, der in
dieser forEach-Methode verwendet
wird ,
um auf einzelne Objekte
in diesem Array zu verweisen . Ich nenne jedes
Objekt Hindernis. Also für jedes
Hindernisobjekt in Obstacles Array nenne
ich die zugehörige
Draw-Methode von 1959 online 59, ich kann sehen, dass es
eine Referenz auf den Kontext als
Argument erwartet , um zu spezifizieren , auf welche Art von Us-Element
wir zeichnen wollen. Ich gebe einfach
diesen Kontext weiter, der an die übergeordnete Rendermethode übergeben
wurde. Nett. Wir zeichnen
einen Spieler und 12345 zufällig
positionierte Hindernisse. Ich gehe hier hoch und mache die
Hindernisse etwas größer. Jedes Mal, wenn ich das
Browserfenster aktualisiere, werden
sie zufällig
irgendwo im Canvas-Bereich positioniert irgendwo im Canvas-Bereich ,
weil wir so
ihre Position in den Zeilen 55.56 definieren . Was wäre, wenn ich sicherstellen möchte
, dass sich die Hindernisse niemals so
überschneiden und vielleicht sogar noch weiter
gehen wollen,
da es sich um solide
Hindernisse handelt, die der Spieler nicht überwinden
kann und die er umgehen
muss. Ich möchte auch, dass
zwischen ihnen und auch zwischen den Rändern
des Spielbereichs ein Mindestabstand besteht . Nur um sicherzugehen, dass all
die Kreaturen, die bald
hier kriechen werden, nicht
stecken bleiben und sich irgendwann automatisch an jedem Hindernis
orientieren können . Es ist tatsächlich einfacher, all das zu implementieren, als
Sie vielleicht denken, aber wir müssen Schritt für Schritt
vorgehen und ein paar Tricks
erklären wir hier anwenden können, um das zu erreichen.
8. Nicht überlappende Hindernisse: In der Init-Methode fügen
wir einfach fünf zufällig
positionierte Hindernisse
hinzu. Richtig? Jetzt. Ich muss das löschen. Wir werden brauchen, dass diese Struktur hier etwas anders
heißt. Also wollte ich zuerst sicherstellen, dass sich die Hindernisse nicht berühren, dass sie
sich nicht so überschneiden. Wir könnten auch
die Anzahl der
Hindernisse so anpassen , dass die
maximale Anzahl von
Kreisen in
einen bestimmten Bereich passt , ohne dass sich
zwei von ihnen überlappen. Manchmal nennen wir
das Circle Packing. Schreiben wir hier also einen
sehr einfachen Kreis zurück in den Algorithmus. Ich werde die grundlegende
Technik anwenden, bei der Sie einfach
versuchen , viele Male Kreise an zufälligen
Positionen zu spielen. Und nur diejenigen, die
nicht mit
bereits existierenden Kreisen kollidieren ,
werden tatsächlich in
Hindernisobjekte
umgewandelt und gezeichnet. Dies wird auch als
Brute-Force-Algorithmus bezeichnet. Es ist nicht sehr schlau, es versucht es
einfach viele, viele Male. Ich werde eine
Hauptvariable namens Versuche erstellen. Das wird meine Sicherheitsmaßnahme sein. Wir werden zählen, wie
oft wir versucht haben,
einen Kreis zu zeichnen , und
nach einer bestimmten
Anzahl von Versuchen geben wir auf. wird davon ausgegangen, dass
es bereits genügend Möglichkeiten
gegeben haben muss , um die Hindernisse zu legen. Ich werde einen While-Loop verwenden. Mit diesem musst du vorsichtig sein. Wenn Sie eine
unendliche While-Schleife erstellen, wird
Ihr Browser langsamer und Sie müssen ihn neu starten. Sehr alte Computer könnten sogar einfrieren, wenn Sie
while loop Rome verwenden, neue Browser kommen
normalerweise damit zurecht. Mein Ziel hier ist es, Kreise immer wieder nach dem Zufallsprinzip zu
platzieren. Und bevor wir
diesen Kreis tatsächlich in
ein Hindernisobjekt verwandeln , prüfen
wir, ob er sich
mit Existenzkreisen überschneidet. Wenn es sich nicht überlappt, haben wir es dem
Hindernis-Array hinzugefügt. Ich möchte, dass diese Ganzschleife läuft solange die
Länge der Hindernisanordnung kleiner als,
Anzahl der Hindernisse,
weniger als fünf ist . Wir haben dieses Array hier definiert und die Anzahl der Hindernisse
wurde hier definiert. Als Backup habe ich auch
eine sekundäre Bedingung gesetzt, diese While-Schleife
nur weiterlaufen zu lassen,
solange die Anzahl der Versuche weniger als 500
beträgt. Das ist wichtig,
denn wenn ich sagen würde, dass der
Radius eines Hindernisses eine sehr große Zahl ist, oder wenn ich die Anzahl der Hindernisse
so groß setze, dass sie physisch nicht
in den verfügbaren Bereich passen, sie physisch nicht
in den verfügbaren Bereich passen, würden
wir eine
Endlosschleife erhalten. Aber wenn die sekundäre
Bedingung JavaScript ist, versuchen
wir es einfach 500 mal. Und wenn
sie bis dahin nicht für
alle
Hindernisse einen Platz finden , wird es aufgeben. Ich denke, 500 Versuche
sind mehr als genug. Jedes Mal, wenn die Runde läuft, müssen
wir die Anzahl der
Versuche
um einen erhöhen , damit unser
Sicherheitsplan funktioniert. Jedes Mal, wenn diese währende Schleife läuft, erstellen
wir ein temporäres
Objekt, das ich z. B.
Testhindernis nenne . Es wird
dem neuen Hindernis entsprechen und ich übergebe es als Spiel, dieses Schlüsselwort als
Argument, wie wir es zuvor getan haben. Lassen Sie uns
dieses Testhindernis auf der Konsole protokollieren. Nett. Wir haben 500
Testhindernisse in der Konsole. Jetzt können Sie sehen,
dass sie die Eigenschaften Kollision,
Kollisions-Y und
Kollisionsradius haben Kollisions-Y und
Kollisionsradius ,
wie sie sollten. Mein Ziel ist es nun, dieses temporäre
Testhindernisobjekt vergleichen allen anderen Hindernissen
in der Hindernisanordnung zu
vergleichen. Natürlich ist
dieses Array zunächst leer, daher sollte das erste Hindernis immer ohne Probleme platziert werden. Das zweite Testhindernis vergleicht
sich mit dem ersten, das sich bereits
im Array befindet, und so weiter. Also werde ich für jedes Hindernis, jedes
Hindernisarray,
eine Formel
zur Erkennung von Kreiskollisionen ausführen . Erkennung von Kreiskollisionen in
JavaScript ist recht einfach. Wir müssen im Grunde den Abstand
zwischen den beiden
Mittelpunkten dieser beiden Kreise
berechnen . Dann vergleichen wir den
Abstand zwischen zwei Mittelpunkten mit
der Summe der Radien. Wenn der Abstand kleiner ist
als der Radius des ersten Kreises plus der Radius des Kreises
, überlappen sie sich. Wenn es genau dasselbe ist, berühren sich
die Kreise. Die Entfernung ist mehr
als die Summe der Radien. Es gibt keine Kollision. Das haben wir bereits gemacht, als die Entfernung
zwischen Spieler und Maus
gemessen haben. Dieses Mal sind die beiden Punkte, an denen
wir
die Entfernung
dazwischen messen wollen , der Mittelpunkt
des Hinderniskreises eins. Und auch der zentrale Punkt der
Hindernisse kreist. Also erstellen wir wieder
dieses imaginäre rechtwinklige Dreieck , wobei dx der Unterschied
zwischen zwei horizontalen Punkten ist . D ist der vertikale Unterschied zwischen
den beiden Punkten. Und die tatsächliche Entfernung ist die Hypotenuse dieses Dreiecks. Also verwenden wir hier
die Formel des Satzes von Pythagoras oder eine eingebaute mathematische
Punkt-Hypotenuse-Methode, indem wir ihr zuerst ein DY
und dann ein zweites Mal übergeben. Jetzt wissen wir, wie groß der Abstand zwischen
den beiden Mittelpunkten ist. Summe über ADI ist der
Radius des ersten Kreises, in diesem Fall
der Radius des Testhindernisses. Und der zweite
ist der Radius eines beliebigen Hindernisobjekts
innerhalb der Hindernisanordnung, wir sind derzeit im Zyklus und darüber. Wie gesagt, wenn der
Abstand kleiner als die Summe
der Radien ist , wie mache ich das? Außerhalb der für jede Methode erstelle
ich eine
Flag-Längenvariable, die ich Overlap nenne, und setze sie zunächst auf false. Die Entfernung ist kleiner
als die Summe der Radien. Wir setzen die Überlappung auf True
, da
für jede Methode eine Kollision außerhalb der
erkannt wurde . Wenn die Überlappung immer noch
falsch ist, nachdem wir Schreibtischhindernis
erstellt haben
und nachdem wir es mithilfe der Formel
zur Kollisionserkennung
mit allen anderen vorhandenen
Hindernissen in der Reihe
verglichen haben es mithilfe der Formel
zur Kollisionserkennung
mit allen anderen vorhandenen
Hindernissen in der Reihe
verglichen . Wenn es
mit keinem von ihnen kollidiert. Und die Überlappungsvariable
ist immer noch falsch. Nach all diesen Prüfungen nehmen wir das
Hindernis-Array und schieben
dieses Testhindernis, das
unsere Prüfungen bestanden hat, in das Array. Wenn ich das Spiel aktualisiere, werden
fünf Hindernisse nach dem Zufallsprinzip positioniert und sie werden
sich
nicht überlappen, da diejenigen, die sich überschneiden, weggeworfen werden. Und es werden nur sich nicht überlappende
Kreise verwendet. Weil ich meine
Sicherheitsmaßnahme hier auf der Linie 10008 habe
und wir
diese While-Schleife immer beenden, und wir
diese While-Schleife immer beenden wenn
wir 500 Versuche erreichen, kann
ich tatsächlich hier hochgehen
und die Anzahl der
Hindernisse auf eine große Zahl setzen, von denen
ich weiß, dass sie niemals in unseren Code passen werden. Wir werden einfach so
viele Hindernisse wie
möglich platzieren und dann
wird es aufhören, es zu versuchen. Wir wissen, dass das
funktioniert, denn wenn ich mein
Projekt
immer wieder aktualisiere, sehen
wir nie
überlappende Kreise. Ich meine, keine Hindernisse
überschneiden sich. Spieler können sich an dieser
Stelle mit Hindernissen überschneiden. uns momentan egal. Ich habe eine Reihe von
Hindernissen gegen zehn genannt.
9. Randomisierte Bilder aus einem sprite: Lassen Sie mich Ihnen nun zeigen, wie
wir
Bilder an die kreisförmigen
Kollisionstrefferkästen anbringen und wie Sie das Bild
im Verhältnis zum
Kopfkasten positionieren , sodass es visuell Sinn
macht und die
Illusion entsteht , dass dies keine flache Leinwand
ist, sondern eine dreidimensionale
Umgebung, in der der Spieler diese Hindernisse tatsächlich
umgehen kann. Sie können
alle Projekte herunterladen.
Die Ressourcen finden Sie im Abschnitt
Ressourcen unten. In index.HTML erstelle ich ein weiteres
Bildelement mit einer ID von Hindernissen und die Quelle
wird Hindernispunkt-PNG sein. Dieses Bild ist ein Spritesheet. Wir werden für jedes
Hindernisobjekt nach dem Zufallsprinzip einen
dieser Frames herausschneiden . Ich möchte
das eigentliche Bildelement nicht wirklich zeichnen, also verstecke ich es mit CSS im
Hindernisklassenkonstruktor, ich erstelle eine neue Eigenschaft, ich nenne dieses Punktbild. Ich habe auf diese
Hindernistabelle hingewiesen, indem ich das Element nach der ID wie folgt verwendet habe. Lassen Sie uns die Anzahl der
Hindernisse vorerst auf eins setzen. Innerhalb der Zeichnungsmethode in
der Hindernisklasse nenne
ich die integrierte Leinwand-Methode zum
Zeichnen von Bildern. Diese Methode benötigt
mindestens drei Argumente, das Bild, das wir zeichnen wollen. Also dieses Punktbild aus Zeile 58 und den X- und Y-Koordinaten,
wo soll es gezeichnet werden? Ich werde es bei
dieser Punktkollision x
und dieser Punktkollision zeichnen . Warum? Zuerst zeichnen wir einfach das
gesamte Bild-Spritesheet. Und die obere linke Ecke
dieser Tabelle
beginnt am
Mittelpunkt des Hinderniskreises, da
Bilder und Kreise standardmäßig auf der HTML-Leinwand
gezeichnet werden. Wenn ich das Projekt aktualisiere oder ein
neues Hindernis
zufällig irgendwo auf Canvas positioniert wird, habe ich diese
Tabelle für Sie erstellt. Ich weiß also, dass einzelne
Frames 250 Pixel breit sind. Ich speichere diesen Wert als Sprite mit variabler Sprite-Höhe
, der ebenfalls 250 Pixel beträgt. Wenn Sie eine
andere Tabelle verwenden, können
Sie die Breite ermitteln, indem Sie die Breite
der gesamten Tabelle durch
die Anzahl der Spalten
dividieren . Und die Höhe ist die Höhe
des Spritesheets geteilt durch die Anzahl der Zeilen, falls wir eine Skalierung hinzufügen
möchten. Und später werde ich auch
unabhängige Breiten- und
Höheneigenschaften erstellen . Vorerst werden die
Sprite-Breite und
Sprite-Höhe gleich sein , da ich
die Sprite-Frames so dimensioniert die Sprite-Frames habe dass sie im Spiel
gezeichnet werden sollen. Draw image kann auch
optionale vierte und
fünfte Argumente akzeptieren optionale vierte und
fünfte Argumente die in Breite und Höhe
definiert sind. Das gesamte Bild
wird auf den Bereich gequetscht oder gestreckt, den wir durch diese Werte
definiert haben. Es wird so aussehen. Was ich eigentlich tun
möchte, ist,
eines dieser 12
Hindernisse aufzudecken und
nur dieses in der Größe
von 250 mal 250 Pixeln zu zeichnen . Dafür muss ich die längste Version
der
Draw-Image-Methode verwenden , die neun Argumente
erwartet. Diese neun Argumente
sind das Bild, das wir zeichnen
wollten, Quelle x, y, Quelle mit Quellhöhe
des Bereichs, den wir aus dem Quellbild
herausschneiden möchten. Und Ziel x, Ziel. Warum Ziel mit und Zielhöhe,
um zu definieren, wo am Ziel wir das
ausgeschnittene Bild
platzieren möchten . Also, wenn ich ihm eine Null als
Quelle x und Null
als Quellhöhe übergebe . Sprite mit einer solchen Sprite-Höhe als Quellbreite und -höhe muss
ich richtig buchstabieren. Jetzt zeichnen wir den oberen linken Rahmen
in unserer Tabelle. Wie ich bereits sagte, werde
ich separate X- und
Y-Positionen für die Tabelle festlegen. Dafür gibt es mehrere
verschiedene Möglichkeiten. Ich kann
das Bild einfach direkt über
der Kollision x positionieren , was der Mittelpunkt
des Kollisionskreises ist, abzüglich der Breite
des Bildes mal 0,5. Dadurch wird das Bild horizontal exakt über
dem Kollisionskreis zentriert. Um dies tatsächlich anzuwenden, muss
ich Sprite X als
Ziel-X-Eigenschaft verwenden , die hier
an die Draw-Image-Methode übergeben wird.
Seien Sie vorsichtig, wenn Sie
Argumente an die Draw-Image-Methode übergeben. Die Reihenfolge, in der Sie
diese Argumente übergeben , ist
sehr wichtig. Okay, wenn ich die Seite aktualisiere, kann
ich sehen, dass sie horizontal korrekt
zentriert wurde. Ich mache dasselbe
für Sprite y und verwende es als Ziel. Warum die Eigenschaft
an die Draw-Image-Methode übergeben wurde. Jetzt befindet sich die Tabelle direkt über
dem Kollisionskreis. Ich sagte Kollisionsradius
auf einen kleineren Wert. Ich möchte, dass dieser kleine
Kollisionsbereich
am Fuß der Pflanze positioniert wird ,
wo sich der Stein befindet. Denn das wird der
feste Bereich sein, der
den Boden berührt , in dem die Spielcharaktere herumlaufen
müssen. Da unsere Sprites eine Größe
von 250 mal 250 Pixeln festlegen, kann
ich hier tatsächlich einen
fest codierten Wert verwenden. Plus 40 wird es nach oben bringen. -40, -50 -60 -70. Ja, das scheint in Ordnung zu sein. Ich sagte, die Zahl
der Hindernisse beträgt zehn.
10. Positionierungsregeln: Was wäre, wenn ich sicherstellen
möchte, dass nicht nur die Hindernisse
nicht überlappen,
sondern auch, dass zwischen den Hindernissen
ein zusätzlicher Abstand von mindestens 100
Pixeln besteht . Das heißt, sie sind
gleichmäßiger über den
verfügbaren Spielbereich verteilt den
verfügbaren Spielbereich und bieten
genügend Platz zwischen
den Hindernissen. Die Spielfiguren können
leicht um sie herumlaufen. Ich erstelle eine
Hilfsvariable, die ich zB
distanzpuffer nenne , und setze
sie so auf 100 Pixel. Dann habe ich hier in einige
Radien einen
Abstandspuffer eingefügt, um diesen
Puffer zwischen Hindernissen anzuwenden , wenn
wir sie platzieren. Nett. Um sicherzustellen, dass das funktioniert, erhöhe ich den
Abstandspuffer um 250 Pixel. Das sollte es
noch offensichtlicher machen. Ja, so können wir Abstand zwischen Hindernissen
einfach kontrollieren. Ich möchte auch
sicherstellen, dass die
Sprite-Bilder von Hindernissen vollständig
innerhalb des Spielbereichs gezeichnet werden und nicht teilweise
hinter den Rändern versteckt sind. Ich hätte diesen
Insight-Hindernisklassenkonstruktor als ich diese
Werte anfänglich definiert habe. Oder ich kann es auch einfach hier machen, da wir nicht so viele Hindernisse zeichnen
und ihre Positionen sowieso nur
einmal beim Laden der ersten
Seite
berechnet werden , achte
ich darauf, dass der linke Rand der Hindernistabelle mehr als Null
ist, damit er nicht hinter
dem linken Rand von Canvas versteckt ist. Gleichzeitig achte ich
darauf, dass der rechte
Rand nicht versteckt wird. Sprite X muss also
kleiner sein als die Breite
des Spielbereichs abzüglich der
Breite des Hindernisses. Nett. Wenn ich die Seite aktualisiere, kann
ich horizontal sehen, Hindernisse sind immer
vollständig sichtbar. Für die vertikale Position
möchte ich überprüfen, ob das Bild, Mittelpunkt
des Kollisionskreises, der vertikal über Null liegt, nicht
ausreicht. Ich möchte einen Bereich definieren, der für dieses
Hintergrundkunstwerk
reserviert ist . Ich möchte nicht, dass Hindernisse über diesem Bereich auftauchen. Ich erstelle eine Eigenschaft
namens Top Margin. Ich schätze, in diesem oberen Bereich ist es
etwa 260 Pixel hoch. Lass uns hier nachschauen. Ja, 2.6D sieht in Ordnung aus, weil ich
sicherstellen wollte, dass sich die Basis
der Hindernisse nicht mit diesem oberen Bereich
überlappt, aber es macht mir nichts aus, wenn sich die Oberseite
der Hindernistabellen so
überlappt, weil das so
aussieht, als würde die Hindernispflanze vor dem
Hintergrund
stehen, damit wir sie sehen können. Das ist also in Ordnung. Ich werde auch überprüfen, ob
der Mittelpunkt des Kreises der Hinderniskollusionsfläche
kleiner als die Höhe
des Spielbereichs ist . Ich will ein paar Margen. Ich kann zB eine
Hilfsvariable erstellen, die dem
Kollisionsradius des
Testhindernisses mal zwei entspricht . Ich ersetze diesen fest
codierten Wert durch
diese gepunktete Eigenschaft am oberen Rand, die wir definiert haben. Außerdem möchte ich ihm einen zusätzlichen oberen Rand geben ,
damit Charaktere und insbesondere Feinde sich zwischen
Hindernissen
hindurchquetschen und Grenzen überwinden können . über das Spielfeld gehen Horizontal von rechts nach links über das Spielfeld gehen. Ich werde auch
den Rand vom
unteren Rand des Spielbereichs berücksichtigen ,
um dort etwas Platz zu schaffen. Wir haben Code geschrieben, der unserer Spielwelt automatisch Hindernisse
setzt. Diese Hindernisse überschneiden sich nie und ihre
Korrelationsbereiche sind so platziert , dass genügend
Abstand zwischen ihnen bleibt. Dadurch wird der nächste
Schritt viel einfacher da wir Feinde
und freundliche NPCs benötigen um
sie mithilfe sehr einfacher
künstlicher Intelligenz automatisch
umgehen zu können . Wir haben verschiedene
Bilder für Hindernisse, aber im Moment zeichnen wir nur das erste Bild oben links
an der Koordinate Null. Wir können aus
der Hindernis-Tabelle auf
verschiedene Bereiche zuschneiden ,
horizontale Zuschneidefläche. Wir beginnen hier an der
Position, die wir als Quell-X-Argument übergeben, um die Bildmethode zu
zeichnen, Null mal Sprite mit
ist dieser Frame. Eins. Sprite-Breite wird diesem Rahmen entsprechen. Zwei ist diese 13, ist diese eine. Zurück auf Null. Um auszuwählen
, aus welcher Zeile wir zuschneiden, verwenden
wir das Argument source Warum hier? Auch hier multiplizieren wir die
Regelzahl mit der tatsächlichen Höhe der
einzelnen Bright Frames, Null mal Sprite-Höhe ist dieser eine Begriff,
Sprite-Höhe ist dieser eine Begriff. Jetzt sind wir bei
zwei abgerollt und es gibt keine dritte Zeile, weil wir bei Zeile Null
beginnen. Die Bilder werden von oben gezeichnet und
beschnitten. Anstatt
diese Werte, die
derzeit auf 00 gesetzt sind, fest zu codieren , sollten wir sie der Übersichtlichkeit halber in
Klasseneigenschaften umwandeln. Und ist eine Kontrolle. Dieser Look Frame x bestimmt , in welcher Spalte wir uns in
unserer Hindernis-Tabelle befinden. Wenn ich eine Zufallszahl 0-4 mache, funktioniert
das nicht. Es gibt keine Spalte 1.74, z. B. brauchen
wir ganze Zahlen, Zahlen
ohne Dezimalpunkte. Also wickle ich es in
Math.floor ein, um den von
Math.Random generierten zufälligen Wert auf die
nächste niedrigere Ganzzahl zu runden von
Math.Random generierten zufälligen Wert . Dieser Code gibt mir
entweder Null oder Eins, oder zwei oder drei. also in einer unserer Sprite-Spalten Wenn wir also in einer unserer Sprite-Spalten
diese ganzen Zahlen mit
der Breite eines
einzelnen Sprite-Frames multiplizieren der Breite eines
einzelnen Sprite-Frames und diesen Wert
als Quellargument an die Methode
draw image übergeben , definieren
wir die horizontale
Schnittkoordinate. Das hat perfekt funktioniert. Ich werde dasselbe für Frame y tun, der die Sprite-Zeile bestimmt. Wir haben nur drei Rollen. Diese Codezeile
gibt mir ganze Zahlen, entweder Null oder Eins oder
zwei, was
der Anzahl der Zeilen entspricht , die wir in unserer
Hindernistabelle
zur Verfügung haben . Jetzt können wir diese fest
codierte Null durch
diesen Punktrahmen y ersetzen . Argument source Why but asked to draw
image method ist dieses Punktrahmen y mal
diese Punktrahmenhöhe. Das mache ich in einer Sekunde. Kombination von zufälligen Werten in Frame X
und Frame why erhalten wir ein zufälliges Bild aus diesen 12
verfügbaren Hindernissen Jedem Hindernisobjekt wird zufälliges Bild aus dieser
Tabelle zugewiesen. Ich werde das etwas später beenden.
11. Physik: Für das Fernstrahlobjekt erstelle
ich eine Methode, die ich Check Collision
nenne. Ich möchte,
dass dies eine
wiederverwendbare Hilfsmethode ist, die Objekt A und Objekt B verwendet und
sie vergleicht und prüft, ob
sie kollidieren oder nicht. Wir werden dies in der
gesamten Codebasis
überall dort verwenden können , wo eine
Kollisionserkennung zwischen zwei Kreisen erforderlich ist. So wie ich mein Spiel baue, werden
alle Charaktere und Objekte einen kreisförmigen Kollisionsbereich
haben, eine solide Basis
darstellt, durch
die nichts
hindurchgehen kann und alles reagiert und
um alles herumläuft. Damit können wir auch Dinge
verschieben. Ich werde Ihnen zeigen, ob die
Kollision zwischen zwei Kreisen überprüft wird. Wir haben Kreis a
und Kreis B. Hier. Wir müssen zuerst dx überprüfen, den Abstand zwischen dem
Mittelpunkt von Kreis a und dem Mittelpunkt von Kreis B auf der
horizontalen X-Achse. Diese wiederverwendbaren Methoden
funktionieren nur, wenn alle
beteiligten Objekte Eigenschaften mit
derselben Namenskonvention haben. Also werden wir sicherstellen, dass wir
die X- und Y-Positionen auf jedem Objekt als Kollision
x und Kollision warum? Ich verwende diese übermäßig
beschreibenden Eigenschaftsnamen ,
damit sehr
klar ist, wann sich die X- und
Y-Koordinaten auf den Kreis der
Kollisionsfläche und wann auf die Positionen von
Bild-Spritesheets beziehen. Dies ist ein Tutorial, daher möchte ich, dass die Dinge sehr
klar und leicht zu verstehen sind. Wir benötigen auch ein D, warum der Unterschied zwischen dem
Mittelpunkt von Kreis a und dem Mittelpunkt von Kreis B auf der vertikalen Y-Achse. Dann wollen wir
den Abstand zwischen
diesen beiden Mittelpunkten wissen . Also Hypotenuse, die längste Seite dieses imaginären
rechtwinkligen Dreiecks,
rechter Winkel von 90 Grad, ist hier. Und das ist die
Entfernung, mit der ein Dolch einen
Satz hat , eine Formel oder alternativ eine eingebaute
mathematische Hypotenusenmethode. Und wir übergeben ihm zuerst das Dui und das x als
zweites Argument. Um festzustellen, ob eine Kollision vorliegt oder
nicht, vergleichen
wir den Abstand zwischen
diesen beiden Mittelpunkten mit dem Radius von Kreis a
plus Radius von Kreis B. Ich werde diesen Wert
als benutzerdefinierte Variable speichern, ich nenne z. B. einige der Radien. Wenn die Entfernung also kleiner ist
als die Summe der Radien, kennen
wir die Zirkuskollision. Wenn der Abstand
der Summe
über ADI entspricht , berühren sich die Kreise. Wenn der Abstand mehr
als die Summe der Radien ist, wissen
wir, dass es keine Kollision gibt. Diese Funktion gibt einfach true
zurück, wenn eine
Kollision vorliegt , und false, wenn
keine Kollision vorliegt. Lassen Sie uns unsere benutzerdefinierte
Kollisionsfunktion verwenden. Hier oben in der
Update-Methode für die Spielerklasse überprüfen
wir, ob Spieler und Hindernisse
miteinander kollidieren. Wir haben ein Ein-Spieler-Objekt und mehrere Hindernisobjekte. alle zu vergleichen, rufen
wir für jedes Objekt ein Hindernis-Array
auf, das alle derzeit
aktiven Hindernisobjekte enthält. Ich werde jedes Objekt
im Array mit einem
Hilfsvariablennamen, einem
Hindernis und
unserer gerade definierten
Kollisionsmethode zur Überprüfung des Konsolenprotokolls aufrufen im Array mit einem
Hilfsvariablennamen, einem Hindernis und . Wir wissen, dass es kreisförmige
Objekte a und Objekt B als
Argumente erwartet , um
den Abstand
ihrer Mittelpunkte mit
der Summe der Radien zu vergleichen . Also übergebe ich
das, was bedeutet, dass dieses Spielerobjekt, Kreis und das Hindernis, das
wir gerade mit dieser
forEach-Methode
überfahren, als Kreis B. Denken Sie daran, dass diese wiederverwendbare
Check-Kollisionsmethode nur Objekte
vergleichen
kann, deren Kollisions-X, Kollision und
Kollisionsradius in ihrem
Klassenkonstruktor definiert sind. Deshalb werde ich sicherstellen, dass ich für
alle Objekte im Spiel,
die
wir heute bauen, die gleichen Namenskonventionen einhalte für
alle Objekte im Spiel,
die
wir heute bauen, die gleichen Namenskonventionen einhalte . sich der Spieler bewegt,
werden in der Konsole „ Falsch“ und „Wahr“ angezeigt. Scheint, als ob das funktioniert. Lassen Sie uns das Wort Kollision eigentlich nur auf der Konsole
protokollieren wenn eine Kollision zwischen Spieler
und Hindernis stattfindet. Jetzt ist es noch einfacher zu sehen
, dass unser Code funktioniert. Perfekt.
12. Wiederverwendbare collision: In der Rendermethode zeichne ich
zuerst Hindernisse, also hinten und danach den Spieler, sodass sie oben gezeichnet werden. Was ist, wenn ich auch unsere Kollisionen
lösen möchte? Was ich meine ist, wenn sie
mit einem Hindernis kollidieren, möchte
ich nicht, dass es so
hindurchgehen kann. Ich möchte, dass der
Spielerkreis
ein Pixel vom
Hinderniskreis weg in
die Richtung verschoben ein Pixel vom
Hinderniskreis weg wird, die
direkt vom
Mittelpunkt des Hindernisses wegzeigt . Diese einfache Sache, wir werden die Hindernisse solide
machen. Der Spieler rutscht
tatsächlich um
die Hindernisse herum und es
entsteht eine schöne Physik. Lass es mich dir zeigen. Ich habe bereits alles
berechnet, was ich für diesen Einblick
benötige, unsere benutzerdefinierte
Prüfkollisionsmethode, aber diese Funktion
gibt derzeit nur wahr oder falsch zurück. Ich benötige diese wiederverwendbare Methode,
um mehr Werte zurückzugeben ,
damit wir sie
innerhalb der Spielerklasse verwenden können, um die Kollisionsauflösung
von Vektorfunktionen zu berechnen und Methoden in JavaScript können einen Wert wie diesen
zurückgeben, aber sie können auch
ein Array zurückgeben , das
mehrere Werte enthält. Ich möchte den Kollisionsstatus wahr oder
falsch als
erstes Element
im Array-Element mit
einem Index von Null zurückgeben erstes Element
im . Wir wollen auch die Entfernung
zurückgeben wir in Zeile 127 berechnen. Wir benötigen auch einige
Radien aus Linie 128. Und wir benötigen DX und
DY aus den Zeilen 100.2526. Unsere benutzerdefinierte
Kollisionsmethode überprüft jetzt nicht nur, ob
eine Kollision vorliegt oder nicht, sondern gibt uns auch
andere Werte aus Berechnungen, die während der Kollision
stattgefunden haben. Es ist wichtig, dass wir uns
die Reihenfolge merken , in der wir in diesen Werten
zurückgegeben werden. Element mit einem Index von Null ist Kollisionsstatus wahr oder falsch? Element mit einem Index
von Eins ist die Entfernung. Ein Teil der Radien ist indexiert für. Dx ist Index drei und d y ist indexiert für. Ich werde einfach das Array kopieren
, das hier zurückgegeben wird. Und ich habe es nur kommentiert, damit ich es als
Hilfsreferenz sehen kann. Jetzt möchte ich jeden
dieser Werte nehmen und sie als
separate Variablen speichern, damit
wir sie verwenden können, um die
Kollisionsauflösung
hier zu berechnen und
zwei Spieler in die
richtige Richtung von dem Hindernis
wegzuschieben zwei Spieler in die
richtige Richtung von dem , in dem es
gerade kollidiert, und in der Breite Ich verwende eine sogenannte
Restrukturierungszuweisung. Lass es uns einfach schreiben und ich werde es
erklären, wenn wir das Ganze
sehen. Ich sage, let variable
ist dieses Array. Und es ist gleichbedeutend, die Kollision zwischen
diesem Spielerobjekt und
dem Hindernis zu
überprüfen diesem Spielerobjekt und , das für jede Methode
gerade überwunden wird. Ich muss
diesen ersten Ausdruck
durch einen Variablennamen ersetzen . Ich wollte es Kollision nennen, ich möchte es Kollision nennen. wird es der richtige oder falsche Wert Je nach Abstand
zwischen dem Mittelpunkt des Kreises wird es der richtige oder falsche Wert sein. Wenn das stimmt,
liegt eine Kollision vor. Wenn das falsch ist, liegt
keine Kollision vor. Diese Struktur- und
Zuweisungssyntax ist ein JavaScript-Ausdruck
, der es ermöglicht Werte aus Arrays oder
Eigenschaften von Objekten
in verschiedene Variablen zu
entpacken . Im Grunde genommen sage ich hier, erstelle
fünf Variablen für mich. Die erste Variable
namens Kollision ist das Array, das zurückgegeben wird, wenn wir Check-Kollisionsmethode zwischen
diesem Spieler und dem
Hindernisindex Null
aufrufen . Die Entfernungsvariable ist der
Array-Index eins und so weiter. Diese Struktur und
Zuweisung erledigt dies automatisch
hinter den Kulissen. Es erstellt diese fünf
Variablen und kombiniert sie. Die Werte, die sich
an diesen Indizes in dem von der
Check-Kollisionsmethode zurückgegebenen Array befinden. Das könnte
etwas seltsam sein, wenn Sie noch nie zuvor mit JavaScript gesehen haben. Es ist eine gute
Sache, sich mit
dieser Strukturierung vertraut zu machen. Moderne Frameworks verwenden
es häufig und nehmen im Grunde nur das Array, das
von der Check-Kollisionsmethode zurückgegeben wird. Und ich weise jeden Wert
seinen separaten Variablennamen zu ,
damit ich sie hier verwenden kann. Also hier sind wir in der
Update-Methode für die Spielerklasse. Wir radeln durch die
Hindernisanordnung vergleichen den Spieler mit
jedem Hindernisobjekt. Wenn es zu einer Kollision
zwischen Spieler und Hindernis Kollisionsvariable wahr ist, Protokoll AAA auf der Konsole gespeichert. Das funktioniert. Ich
wollte einen Vektor erstellen, eine
Art kleine Linie Länge von
0-1 Pixeln. Linie zeigt in die
Richtung, in die der Spieler geschoben werden soll, um die Kreiskollision zu
lösen, um sicherzustellen, dass der Spieler
kollidiert und Spieler und Hindernis sich gegenseitig abstoßen, sodass der Spieler am Radius
des Hindernisses entlang
rutscht, anstatt es direkt zu Diese Linie zeigt in die
Richtung, in die
der Spieler geschoben werden soll, um die Kreiskollision zu
lösen,
um sicherzustellen, dass der Spieler
kollidiert und Spieler und
Hindernis sich gegenseitig abstoßen,
sodass der Spieler am Radius
des Hindernisses entlang
rutscht, anstatt es direkt zu durchqueren. horizontale Vektor
ist das Verhältnis zwischen Dx, dem
Abstand zwischen dem Spieler und dem Mittelpunkt des
Hindernisses auf der horizontalen X-Achse
und der tatsächlichen Entfernung
zwischen diesen beiden Punkten, und der tatsächlichen Entfernung
zwischen diesen beiden Punkten wir vor der
Check-Kollisionsmethode berechnet haben. Weil dx immer
kleiner ist als Entfernung,
weil Entfernung ist
Hypotenuse immer die längste Seite des
imaginären rechtwinkligen Dreiecks. Einheit x hat
immer einen Wert von 0-1, da wir einen kleineren
Wert durch einen größeren Wert dividieren. Einheit y ist das
Verhältnis zwischen Dui, dem Abstand zwischen
Mittelpunkten auf der vertikalen Y-Achse, und dem tatsächlichen Abstand
zwischen den beiden Mittelpunkten. Auch hier wird es ein
Wert irgendwo 0-1 sein. Dies können auch
negative Werte sein je nachdem, wie unsere Objekte zueinander
stehen auf der horizontalen und vertikalen Achse zueinander
stehen. Also sind Einheit x
und Einheit y tatsächlich
ein Wert zwischen minus
eins und plus eins. Wenn ich
Einheit x und Einheit auf der Konsole protokolliere, warum wir diese Werte sehen können, die Kombination
dieser beiden Werte, die zur
horizontalen und vertikalen Position des Spielers
für jedes Animationsbild hinzugefügt
wird horizontalen und vertikalen Position für jedes Animationsbild hinzugefügt
wird bewegt sich
die Kombination
dieser beiden Werte, die zur
horizontalen und vertikalen Position des Spielers
für jedes Animationsbild hinzugefügt
wird
, in eine
bestimmte Richtung und mit einer bestimmten Geschwindigkeit vom
Mittelpunkt des Hindernisses weg. Ich mache das, indem ich die
Kollisionsexposition des Spielers, den Mittelpunkt des Kollisionskreises des
Spielers, ihn aus dem Radius
des Hindernisses herausschiebe , mit dem er
kollidiert. Ich bewege es horizontal
zur Position des Mittelpunkts des
Hinderniskreises plus der Summe der Radien des Spielerkreises und des Hinderniskreises plus einem zusätzlichen Pixel
außerhalb der Terme
, dem Verhältnis von Einheit x, um ihm
die richtige Richtung
vom
Mittelpunkt des Hindernisses zu geben die richtige Richtung
vom . Wir machen dasselbe vertikal. Mittelpunkt des
Kollisionskreises des Spielers wird an
die Position des
Kollisionsmittelpunkts des Hinderniskreises
plus der Summe der Radien von Hindernis
und Spielerkreis plus der Einheit
Y der Stadt um
ein Pixel verschoben die Position des
Kollisionsmittelpunkts des Hinderniskreises plus der Summe der Radien von Hindernis
und Spielerkreis plus Einheit
Y der Stadt um
ein Pixel , um ihm die richtige
Richtung des Stoßens zu geben. Ich versuche das
auf eine sehr anfängerfreundliche Art zu erklären , aber mach dir keine Sorgen, wenn es
noch etwas unklar ist. Dies ist eine wichtige Technik
und jedes Mal, wenn Sie sie anwenden, werden
Sie sich mit diesem Mantel immer
vertrauter fühlen. Irgendwann wird es
für Sie klicken, wie es funktioniert. Alles, was Sie hier
verstehen müssen, ist, dass dieser Code
den Spieler ein Pixel
außerhalb des Kollisionsradius
des Hindernisses in Richtung
vom Mittelpunkt verschiebt außerhalb des Kollisionsradius
des Hindernisses in Richtung . Und so erstellen Sie eine sehr einfache, aber sehr effektive Physiksimulation in Ihrem Spiel. Versuche den Spieler zu bewegen. Das fühlt sich sehr
gut an, nicht wahr? Plötzlich
verwandelten sich unsere Hinderniskreise in feste,
unmögliche Objekte. Gut gemacht, wenn Sie den ganzen Weg hierher
verfolgt haben.
Dies ist der Haupttrick, den wir heute für
unser Physikspiel
verwenden. Ich stelle den Geschwindigkeitsmodifikator
auf einen kleineren Wert ein. Wir haben gelernt, wie man
den Spieler dazu bringt, sich auf
eine Maus oder auf einen bestimmten
Punkt in einem 2D-Raum zu bewegen , und wie man ihn dazu
bringt, sich automatisch um
feste Hindernisse zu bewegen. Dies ist eine leistungsstarke
Technik, mit der Sie mehr machen
können,
als Sie sich vorstellen können. Wir werden heute
einiges davon untersuchen. Hoffe du hast Spaß.
13. 8 direktionale sprite: habe ich ein
spezielles
Spieler-Spritesheet mit Hilfsmitteln vorbereitet Für diesen Kurs habe ich ein
spezielles
Spieler-Spritesheet mit Hilfsmitteln vorbereitet. Sie können es unten im
Ressourcenbereich herunterladen. Ich werde einige
alternative Farben hinzufügen. Wahrscheinlich ist meins zu
blau für Pilze
in meiner Spielkunst. Ich werde es hier mit CSS verstecken. Interner Spielerklassenkonstruktor. Ich erstelle einen Verweis auf dieses Bild mit
get element by ID und speichere es als diese
Punktbildeigenschaft. In unserer benutzerdefinierten Zeichenmethode verwende ich Kontexte und
nenne die integrierte
Leinwand-Methode zum Zeichnen von Bildern
, die wir bereits zuvor verwendet haben. Wir haben bereits gesagt, dass die Methode zum Zeichnen von Bildern
mindestens drei Argumente benötigt. Das Bild, das wir zeichnen wollen
und x und y sollten es zeichnen. Dadurch wird nur die
gesamte Tabelle gezeichnet. Wir können ihm Breite
und Höhe übergeben, um
die gesamte Tabelle
in den angegebenen Bereich zu komprimieren. Wir haben
diese Eigenschaften eigentlich nicht definiert. Sprite mit der Breite
eines einzelnen Frames beträgt
255 Pixel. Sprite-Höhe beträgt ebenfalls 255. Dann erstellen wir separate
Breiten- und Höheneigenschaften , um das Potenzial zu nutzen,
falls wir es später
einführen möchten. Jetzt komprimieren wir
die gesamte Tabelle in den Bereich
eines Sprite-Frames. Sie
wissen wahrscheinlich bereits, dass wir
die längste Version der
Draw-Image-Methode benötigen die längste Version der ,
bei der wir Quell-X,
Y, Quellbreite und -höhe hinzufügen . Mit diesen Werten wird zunächst ein Teil des Bildes
ausgeschnitten, in unserem Fall ein
einzelnes Sprite-Frame. Danach zeichnen wir diesen Rahmen, die Position, die durch
die letzten vier Argumente definiert wird. den oberen linken Rahmen
an der Koordinate
Null Null zu zeichnen Es ist einfach, den oberen linken Rahmen
an der Koordinate
Null Null zu zeichnen. Wir haben es einfach mit der
Hindernistabelle gemacht, Quelle x, y, z,
Null, um den Beginn des
Zuschneidens eines Rechtecks zu definieren. Und Sprite mit und
Sprite-Höhe als Quellbreite- und
Quellhöhenargumente , um seine Größe zu definieren. Jetzt sehen wir nur noch einen Frame. Ich werde die Position des
Tabellenbildes im Verhältnis
zu den Kollisions- und
Kollisions-Y-Koordinaten des Spielers berechnen Tabellenbildes im Verhältnis . Er würde diese beiden
separaten Grundstücke nur der Übersichtlichkeit halber einpacken. Denken Sie also daran, dass
diese Eigenschaften den Mittelpunkt des Kollisionskreises des
Spielers
definieren. Mit diesen beiden Eigenschaften
definieren wir die obere linke Ecke des Tabellenrahmenbilds, das wir
gerade zeichnen , um den Spieler
darzustellen. Auf uns. Sphärische Koordinaten
r vom Mittelpunkt, Rechteck- und
Bildkoordinaten aus der oberen linken Ecke. Und Bild und Rechteck
gehen von dort aus
je nach Breite
und Höhe nach rechts unten . Wir müssen dies berücksichtigen, wenn wir den folgenden Code
schreiben. Sprite X wird relativ zum Kollisionsbereich positioniert . Es wird Kollision x sein, der Mittelpunkt des
Kollisionskreises minus der
halben Breite des
Spielerrahmens. So. Ich muss hier Sprite X in
der Auslosung als
Ziel-X-Argument verwenden . Damit dies funktioniert,
müssen wir
diesen Wert jedes Mal neu berechnen , wenn
eine Kollision x aktualisiert wird. Also muss ich das hier in
die Aktualisierungsmethode einfügen. Und ich mache das auch für Sprite y, das ist Kollisions-Y minus die halbe Spielergröße. Ich kann es hier löschen. Und ich benutze Sprite.
Warum die Eigenschaft hier als Ziel-Y-Argument
an die Draw-Image-Methode übergeben wurde. Jetzt ist es oben positioniert. Ich möchte eigentlich, dass dieser
Kollisionskreis so
genau wie möglich zu
dem kleinen Schatten
auf
dem Boden unter dem Spieler passt dem kleinen Schatten
auf
dem Boden unter , denn das ist der
Kontaktpunkt, den wir verwenden werden wenn wir mit
anderen Objekten in unserem Spiel interagieren. Da der Player eine
feste Pixelgröße hat, kann
ich ihn durch
einen fest codierten Wert ausgleichen. Wenn wir unsere
Charaktere in diesem Spiel skalieren würden, würde
ich hier einen
relativen Wert verwenden. -100 verschiebt das Spielerbild nach oben. Das ist vorerst in Ordnung.
14. Animation: So wie wir es mit der
Hindernis-Tabelle gemacht haben. Ich wollte in
unserer Tabelle navigieren , indem ich
von Frame zu Frame wechselte. horizontale Navigation
erfolgt, indem Sprite mit
einer Ganzzahl
multipliziert wird ,
die die Spalte in
der Vergangenheit der Tabelle
als Quellargument darstellt . Wenn wir das durchgespielt
haben, animieren wir
einzelne Richtungen,
einzelne Animationsschleifen, um zwischen den Richtungen
in der Tabelle zu wechseln, so wie unsere spezifische
Tabelle heute organisiert ist,
wir müssen
die Sprite-Höhe mit
einer Ganzzahl multiplizieren , die die
Sprite-Rolle darstellt Sie können eine Reihe sehen, Null ist der
Spieler, der nach oben zeigt, von uns
weg. Rho ist oben rechts oder schaut
der Spieler nach rechts? Drei ist unten rechts für zeigt nach unten
in Richtung Kamera. Reihe fünf in unserer Tabelle zeigt
das Spielerbild unten links, sechs zeigt nach links. Ich denke, du verstehst die Idee. Ich habe diese ganzen Zahlen
in Klasseneigenschaften eingegeben. Frame x für horizontale
Spread-Navigation. Rahmen. Warum für vertikal ersetze
ich diese fest codierten
Werte durch meine neuen Variablen, und jetzt kann ich ändern welchen Frame wir gerade aus
dem Player-Spritesheet
herausschneiden , indem Frame x und Frame warum unterschiedliche Werte gebe? Ich wollte den Frame ändern, weshalb die Zeile, die wir gerade
vom Spritesheet aus animieren, das bestimmt, wohin
der Spieler blickt. Ich möchte, dass das vom aktuellen Winkel
zwischen Maus und
Spieler abhängt aktuellen Winkel
zwischen Maus und und von der
Position, an der sie sich gerade im
Verhältnis zueinander befinden. Dafür haben wir eine eingebaute
Methode namens Math dot eta. Und für Martha gibt atan2 einen Winkel
im Bogenmaß zwischen
der positiven X-Achse und einer Linie zurück der positiven X-Achse und einer Linie von Null
auf einen bestimmten Punkt
projiziert wird. Wir werden es verwenden, um
den Winkel zwischen dem Spieler
und dem Mauszeiger zu berechnen . Und basierend auf diesem Winkel wählen
wir aus, welche Zeile in der Tabelle wir animieren
möchten, sodass der Spieler immer in die Richtung
schaut, in die
er sich bewegt. In Richtung des Mauszeigers. Wir werden DX und DY brauchen. Also habe ich sie hierher gebracht. Diese Werte berechneten also
den Abstand zwischen
dem Spieler und dem Mauszeiger
horizontal und vertikal. Denken Sie daran, dass es einen Unterschied
macht, ob Sie zuerst die Maus
oder zuerst den Spieler verwenden. In dieser Berechnung habe ich diesen
Code hier
schon einmal geschrieben. Ohne nachzudenken,
würden wir es dafür verwenden, also müssen wir uns vielleicht ein bisschen darauf
einstellen. Ich werde dir
genau zeigen, was ich meine. Martha-Daten erwarten dy, dy und dx als
zweites Argument. Ich werde den Winkel, den wir
berechnen, konsultieren und ich kann
sehen, dass er sich ändert. Und die Werte reichen von
-3,14 minus Pi bis
plus 3,14 plus Pi. Das funktioniert, weil wir wissen , dass der volle Kreis zwei Pi ist, also ungefähr 6,28 rad, was
in 360 Grad umgerechnet wird. Ich werde diese Methode wiederholen. Atan2 gibt einen Winkel
im Bogenmaß zwischen
der positiven X-Achse und der Ausrichtung zurück der positiven X-Achse und der Ausrichtung von Null
auf einen bestimmten Punkt
projiziert wird. Da ich zuerst die Maus
und dann die Spielerposition verwende , bei der Berechnung von DX und DY erhalte
ich
bei der Berechnung von DX und DY Werte aus
Stammdaten und um zu lernen, entspricht
die aktuelle Mausposition 0,00 und Spielerposition ist der Punkt, auf den
wir eine Linie projizieren. Für die Zwecke
einer schönen Grafik würde
es viel besser funktionieren, wenn
Player die statischen Nullen,
Nullen, Eins wichtig wäre , aber
ich lasse es so wie es ist. Und anhand der Werte, die ich
in der Konsole erhalte, erstelle
ich dieses Diagramm
mit Breakpoints im Bogenmaß. Es war eigentlich einfach
zu erstellen, weil ich nur einen
Wert als Anker benötigte. Und ich wusste, dass der gesamte Bereich
von -3,14 ist, zwei plus 3,14. Und wir haben acht
Spieleranweisungen. Jede Scheibe war also 6,20 8/8. Wie dem auch sei, du
musst das
alles nicht unbedingt verstehen, oder? Jetzt, wo wir den vollständigen Code haben, können
Sie mit den
Werten spielen, was
hoffentlich für mehr Klarheit sorgt. habe eine Weile gebraucht, um Mathe zu benutzen , aber atan2, bis ich es
vollständig verstanden habe. Wenn Sie es also
zum ersten Mal sehen, üben Sie nicht zu viel
Druck auf sich aus. Wenn ich den Bildschirm pausiere, ist
dies die 0,00,
das ist die Linie, die
auf einen anderen Punkt projiziert wird. Und Martha-Daten und zwei
geben uns einen Winkel im Bogenmaß zwischen dieser positiven
X-Achse und dieser Linie. Also, indem ich dieses
Konsolenprotokoll verwende, um
einen Ankerpunkt zu erhalten , damit ich
sehen kann , welche Winkelwerte
wir erhalten. Ich habe dieses
Hilfsbild erstellt, das ich nun verwenden werde,
um die Zeilen
in unserer Tabelle korrekt zu vertauschen in unserer Tabelle korrekt zu der Spieler immer der Maus
zugewandt ist. Wenn der Winkel kleiner als -1,17 ist, setzen Sie Frame y auf Null. Ich werde das ein paar Mal kopieren. -0,2, 39 ist ein Rahmen y eins
plus 0,39 ist ein Rahmen. Strahlkraft von Y bis 1,17 ist eingerahmt. Y3, 1,96 ist Rahmen Y4. Lass uns sehen. Bisher funktioniert
das super. Ich glaube, wir haben es. Ich
kann die Konsole löschen. Log 2.74 ist Frame fünf. Dieser Bereich ist etwas seltsam, da
der Kreis endet und beginnt. Ich muss sagen, ob der
Winkel kleiner als
-2,74 ist oder ob der Winkel
mehr als plus 274 ist. Ich möchte Frameworks Six verwenden. Wenn der Winkel kleiner als -1,96 ist, ist
Frame y sieben. Achten Sie hier auf Klammern, minus n Pluswerte und die Operatoren
kleiner als. Wenn Sie ein
unerwartetes Verhalten feststellen, stellen Sie sicher, dass der gesamte
Code mit meinem identisch ist. Es ist leicht,
hier
einen kleinen Fehler zu machen und Ihren
Code versehentlich zu beschädigen. Damit das
für alle Richtungen funktioniert, muss
ich es
ein bisschen anpassen. Ich kann zum Beispiel diese Folien
nehmen und sie
hier platzieren , weil es bei der
else-if-Anweisung
darauf ankommt, welche zuerst überprüft
wird. Manchmal habe ich den Tempo-Modifikator
für
Spieler auf drei reduziert , damit wir
deutlich sehen können, wie er sich dreht. Während Destin. Jetzt können wir den Spieler in
alle acht Richtungen drehen. Perfekt. Wir werden später in der Klasse mehr
über Sprite-Animationen erfahren. Im Moment bin ich damit zufrieden.
15. Debug-Modus: Da dies ein
Physikspiel ist, bei dem wir Kollisionsbereiche an
der Basis jedes Objekts
platzieren. Wir wollen in der Lage sein, schnell zwischen der Ansicht,
in der diese Kollisionsbereiche sichtbar
sind, und der unsichtbaren Ansicht zu
wechseln . Es wird uns helfen,
die Physik und die
Gameplay-Elemente zu optimieren , während wir
sie entwickeln , und gleichzeitig eine einfache Möglichkeit bieten zu überprüfen, wie die Änderungen, die wir gerade vorgenommen haben, für
den Spieler sichtbar sind, der diese Boxen
nicht sehen wird. Ich möchte einen Debug-Modus erstellen ,
indem ich den Buchstaben
D auf der Tastatur drücke Wir schalten alle
Helfer-Kollisionselemente der
Hauptspielklasse ein und aus, ich erstelle eine Eigenschaft
namens diese zum Debuggen. Und zunächst habe ich es hier unten, wo wir unsere Event-Listener
platziert haben, auf
true gesetzt , ich erstelle einen weiteren. Wir werden uns das
Keydown-Event anhören. Lassen Sie uns einfach das
Konsolenereignisobjekt protokollieren. Wenn ich Canvas auswähle,
indem ich darauf klicke, und dann
eine beliebige Tastaturtaste drücke, erhalten
wir dieses automatisch generierte
Tastaturereignisobjekt. Im Inneren haben wir eine
Immobilie namens Key. Sie können sehen, dass ich
den Buchstaben R drücke, also
befindet sich die Taste, für die der Preis angegeben wurde, innerhalb der E-Punkt-Tasteneigenschaft. Ich sage, wenn der E-Punktschlüssel D ist, setzen Sie die Debug-Eigenschaft von Zeile
123 auf den entgegengesetzten Wert. Wenn es also derzeit wahr ist, setzen Sie es auf Falsch. Wenn es falsch ist, setzen Sie es auf wahr. auf diese Weise
den gleichen Schlüsselbuchstaben D angeben, wird der
Debug-Modus ein- und ausgeschaltet. Ich habe es mit Console
Login Test oder Debug getestet. Ich drücke das D immer wieder. Und in der Konsole sehe ich, dass es
zwischen wahr und falsch wechselt. Perfekt. Ich entferne
das Konsolenprotokoll und in der
Zeichnungsmethode für die Hindernisklasse
angezeigt. Ich sage, wenn dieser Hund gekommen ist, um in einem Diner zu
debuggen, zeichne den Kreis im Kollisionsbereich. Jetzt kann ich
den Buchstaben D drücken, sie anzeigen und ausblenden. Das funktioniert gut. Ich möchte
dasselbe für den Spieler tun. Wenn dieses Spiel zum Debuggen
in einem Diner zutrifft, zeichne den Kollisionskreis und auch die Linie zwischen dem
Spieler und der Maus. In diesem Fall sind Position und Größe der Kopfkästen
noch nicht perfekt, aber wir haben jetzt die gesamte Logik
im Griff, gute Arbeit. Ich kann den
Kollisionsradius jedes Hindernisses verkleinern, um ihn besser an
den Teil anzupassen , an dem es den Boden
berührt. Wir haben hier verschiedene
Hindernistypen. Der Pilz und diese große
fleischfressende Pflanze sollten wahrscheinlich unterschiedliche
Kollisionskreise haben , was leicht zu bewerkstelligen ist. Aber im Moment bin ich
damit zufrieden. Sie können sehen, dass die
Kollisionsformel wir zuvor geschrieben haben, alles ist,
was wir brauchen, um dem Spieler eine sehr
einfache Fähigkeit zur Pfadfindung zu geben. Es wird einfach automatisch um
Hindernisse herumlaufen. Und da wir Hindernisse so platziert haben , dass sie
immer Zwischenräume sind, ist
es unwahrscheinlich, dass der
Spieler stecken bleibt. Ich kann auch sehen, dass ich nur die ersten vier Hindernisbilder erhalte, was mich
daran erinnert, hier zu Zeile
10008 zu gehen und den zufälligen
Frame-Y-Wert als Quelle anzugeben. Warum Argument in der Methode zum
Zeichnen von Hindernissen. Jetzt erhalte ich nach dem Zufallsprinzip
eines aller 12. Hindernisbilder. Sie können damit und mit Position
und Größe spielen. In Ihrem Handbuch steht
etwas anderes, wenn Sie möchten. Ich bin zufrieden mit dem, was
wir bisher gemacht haben.
16. Player: Ich wollte sichergehen, dass
der Spieler nicht so
hoch gehen kann , dass er sich über diesem Bereich mit Grafiken
im Hintergrund befindet. Lassen Sie uns einige
horizontale Grenzen erstellen. Zuerst. Wenn der Mittelpunkt des
Spielerkollisionskreises kleiner als die
X-Koordinate Null plus
Kollisionsradius ist , setzen Sie ihn auf Null plus
Kollisionsradius. Wenn also der linke
Rand des Kreises den linken
Rand des Leinwandbereichs berührt, lassen Sie ihn
nicht weiter
nach links gehen. Ich möchte
dasselbe für den rechten Rand tun. Natürlich können wir dieses
Nullplus hier und hier löschen. Wenn der Mittelpunkt des Spieler-Kollisionskreises mehr als
die Breite des Spiels abzüglich des Radius
des
Spieler-Kollisionskreises ist die Breite des Spiels abzüglich des . Stellen Sie sicher, dass es nicht weiter gehen
kann, oder? Nett. Vertikale Grenzen. Wenn die Kollision y kleiner als die
vertikale Koordinate
Null plus oberer Rand ist , haben wir einen Abstand von 260 Pixeln
von der Oberseite plus
Kollisionsradius definiert . Achte darauf, dass der Spieler nicht mehr hochgehen
kann. Das funktioniert gut. Ja, das wollte ich. Auch hier und hier können wir
Null plus löschen. Untere Grenze. Das ist ganz einfach. Wenn die Kollision y
größer ist als die Höhe des Spiels abzüglich des
Kollisionsradius, Sie sicher, dass sie
dort auf diese Weise stoppt. Das funktioniert, wenn ich den
Kollisionsradius des Spielers kleiner als
den
Hindernisradius mache , da wir beim
Positionieren von Hindernissen einen Abstand festgelegt haben.
Es wird immer einen Platz geben, Es wird immer einen Platz an dem sich
ein Spieler
zwischen Hindernissen quetschen kann. Die Ränder des Spielbereichs. Das gibt es nicht. Also hier unten erhöhe ich diese
Marge. Sie sollten es tun. Sie können Ihren Code mit dem
Quellcode vergleichen ,
den ich
im
Laufe unseres Projekts an
mehreren Stellen in diesem Kurs
zum Herunterladen in den Projektabschnitt aufnehmen werde im
Laufe unseres Projekts an
mehreren Stellen in diesem Kurs
zum Herunterladen in den Projektabschnitt Laufe unseres Projekts an
mehreren Stellen in diesem Kurs .
17. FPS: Ich kann sehen, dass
der untere Teil der Tabelle in den unteren Reihen abgeschnitten
wird . Das liegt daran, dass die Höhe
eines einzelnen Frames tatsächlich 256 Pixel
beträgt. Jetzt ist es behoben. Im Visual Studio Code-Editor wähle
ich den
Zeilenumbruch anzeigen aus, um einen
Codeumbruch in eine andere
Zeile zu machen , falls er nicht passt. Wenn es zu lang ist. Ich
wollte FBS für das gesamte Spiel einstellen, weil
bei meinen vorherigen Projekten viele von euch erwähnt haben,
dass Spiele auf Bildschirmen mit hoher
Bildwiederholfrequenz zu
schnell laufen , Animationsframes
anfordern oder die
Methode, die wir hier verwenden,
sich
automatisch an die Bildschirmaktualisierungsrate Animationsframes
anfordern oder die
Methode, die wir hier verwenden anpasst. Für normale Bildschirme sind
das also etwa
60 Bilder pro Sekunde. Aber auf einigen der neuen
Gaming-Bildschirme, die die Leute verwenden, wäre
diese Geschwindigkeit doppelt oder vielleicht nicht gerade
doppelt so hoch, aber viel schneller. Wir berechnen
die Deltazeit, die Anzahl der
Millisekunden, die
zwischen den einzelnen Zielen des Animationsframes der
Anfrage vergangen sind . Und wir werden zulassen, dass
das Spiel
das nächste Animationsbild erst anzeigt, wenn eine bestimmte Anzahl von
Millisekunden vergangen ist. Wir können
die Delta-Zeit
hier unten in unserer benutzerdefinierten
Animationsfunktion berechnen . Zuerst habe ich das letzte
Mal außerhalb der
Funktion so definiert . Anfangs habe ich es auf Null gesetzt. Diese Variable enthält immer
eine Referenz des
Zeitstempels aus der vorherigen
Animationsschleife, sodass wir ihn mit dem
aktuellen Zeitstempel
vergleichen können . Und der Unterschied zwischen
ihnen wird die Deltazeit sein. Der Animationsframe von Request
weist zwei Besonderheiten auf. Wie gesagt, es wird
automatisch versuchen, sich
an die Bildwiederholfrequenz des
Bildschirms anzupassen, in den meisten Fällen 60
Bilder pro Sekunde. Es generiert auch
automatisch einen Zeitstempel für uns
, den wir verwenden können. Und es übergibt
diesen Zeitstempel als Argument
an die
aufgerufene Funktion. In unserem Fall animieren. Stellen Sie sich vor, es übergibt diesen
Zeitstempel hier so. Automatisch, es
wird automatisch generiert. Alles, was wir tun müssen,
um es zu verwenden, ist, ihm hier einen Variablennamen zuzuweisen. Ich nenne es einen Zeitstempel, so
buchstabiert, achte auf
Klein- und Großbuchstaben, wenn du deine Variablennamen
in JavaScript
definierst, das ist wichtig. Lassen Sie uns eine Konsolenprotokollierung dieser automatisch generierten temporären
Stamps-Variablen erstellen, die uns das
Animationsbild gegeben hat nur um zu sehen, welches Format
es ist n. Sie können die uns das
Animationsbild gegeben hat,
nur um zu sehen, welches Format
es ist n. Sie können
sehen, dass es uns Millisekunden gibt,
seit die erste Animation aufgerufen
wurde. 1 s ist
1.000 Millisekunden. Hier kann ich also buchstäblich
sehen, dass das Spiel vor 13 Sekunden vor
9101112 gestartet wurde. Ich lösche dieses Konsolenprotokoll. Wir wissen, dass wir Zugriff auf
den aktuellen Zeitstempel haben. Verwenden wir ihn
also, um die Delta-Zeit zu
berechnen. Es wird der Unterschied
zwischen dem Zeitstempel dieser Animationsschleife und dem Zeitstempel der
vorherigen Animationsschleife sein. Deltazeit ist die Anzahl
der Millisekunden, die
unser Computer für die Bereitstellung des
nächsten Animationsbildes benötigte . Nachdem wir das letzte Mal verwendet haben, um die Deltazeit zu
berechnen, weisen
wir sie dem
aktuellen Zeitstempel zu. Auf diese Weise kann der aktuelle
Zeitstempel in
der nächsten Animationsschleife
als alter Zeitstempel verwendet werden . Für die allererste
Animationsschleife letzte Mal
Null, aber
danach wird immer der Wert des
Zeitstempels aus dem
vorherigen Animationsbild gespeichert ,
sodass wir
ihn mit dem Wert des
Zeitstempels aus diesem aktuell
laufenden Animationsframe vergleichen können . Und der Unterschied zwischen
ihnen ist die Deltazeit. Lassen Sie uns also die
Deltazeit auf der Konsole protokollieren, um zu sehen, ob es funktioniert hat. Meine Deltazeit beträgt etwa
16,6 Millisekunden. Tausend Millisekunden
geteilt durch 60 sind 16,6. Das stimmt also. Ich frage mich, wie viele
von Ihnen dieselbe Delta-Zeit und wie viele von
Ihnen eine andere Nummer bekommen haben. Wenn Sie einen Bildschirm mit hoher
Bildwiederholrate haben, wird
Ihre Deltazeit
eine viel geringere Zahl sein. Wenn du einen alten Computer hast, Schwierigkeiten hat, unser Spiel zu
animieren, könnte
deine Delta-Zeit viel
höher sein , wenn du hier eine
Sekunde Zeit hast, Delta-Zeit in den Kommentaren. Wir wissen also, dass, wenn
die meisten Menschen dieselben oder sehr
unterschiedliche Werte haben als ich, das mir helfen wird, meine zukünftigen Kurse besser zu
optimieren. Wenn ich
die Konsole bis zum allerersten Zeitstempel hochscrolle, können
Sie sehen, dass die
ersten beiden Werte der Delta-Time keine Zahl sind
. liegt daran, dass der
allererste Zeitstempel
undefiniert ist , da
dieser Zeitstempelwert erst
in der zweiten Schleife automatisch vom Animationsframe der
Anfrage generiert wird . Die erste Schleife wird nicht durch den
Animationsframe der Anfrage ausgelöst, sondern durch diese Zeile. Wenn
wir also am Anfang sagen, dass die Deltazeit
undefiniert minus Null ist , erhalten
wir hier keine, keine Zahl. Es repariert
sich automatisch, wenn die Schleife läuft. Aber diese beiden anfänglichen Werte
ohne Zahl könnten Ihren Code beschädigen. Das hängt von der
Delta-Zeit ab, es sei denn, Sie berücksichtigen dies mit
einer mündlichen Aussage.
Der einfachste Weg, dies zu beheben, besteht darin, hier Null
als Zeitstempel für die
erste Animationsschleife zu übergeben . Ab der zweiten Schleife wird
der Wert zum
automatisch generierten Tau-Stempel. Denn danach wird
Animate per
Anforderungs-Animationsframe
aufgerufen . Wie Sie sehen,
erhalten wir hier Zahlen und es gibt keine
Nichtwerte mehr. Perfekt. Ich lösche
dieses Konsolenprotokoll. Verwenden wir Delta Time, um
die Bildrate unseres Spiels festzulegen. Wir benötigen einige
Hilfsvariablen. Fps, Bilder pro
Sekunde werden z. B. 20 sein. Der Timer zählt
immer wieder von Null an. Auf dem Weg zu einem bestimmten Wert. Wenn dieser Wert erreicht
ist, wird das
nächste Animationsbild ausgelöst und es wird auf Null zurückgesetzt. Das Intervall ist der
Breakpoint-Wert , bei dessen Erreichen der Timer zurückgesetzt
wird. Es werden tausend
Millisekunden sein, 1 s geteilt durch FBS. Dies gibt uns die
Menge an Millisekunden benötigt werden, um
diesen spezifischen FBS zu erreichen. Wir werden diese
Frame-Handling-Logik hier unten in der
Render-Methode verwalten . Wenn der Timer mehr als ein
Intervall ist, tun Sie etwas. gleichzeitig den Timer
immer wieder
um den Wert der
Delta-Zeit. Wenn der Timer
genügend Deltazeit angesammelt hat, so viele Millisekunden, dass sein
Wert größer als das Intervall ist. Wir werden das nächste Bild animieren. Wir werden den Timer auch
wieder auf Nullen zurücksetzen,
damit er für
das zukünftige Frame-Update wieder zählen kann. Ich nehme den ganzen
Code und füge ihn in die if-Anweisung ein. So wie das. Wir verwenden den
Delta-Zeitwert in Zeile 173. Der Punktwert wird hier oben als Argument
an die
Rendermethode übergeben . Und innerhalb der Animationsschleife berechnen
wir
hier die Deltazeit und werden
sie so übergeben, um zu rendern. Okay, es passiert also etwas. Der Grund, warum alles
blinkt
, ist , dass wir ständig
alte Farben löschen, unser Spiel
aber nur neu zeichnen wenn der Timer das Intervall erreicht. Ich habe dieses durchsichtige
Rechteck von hier. Jetzt sind wir mit alter Farbe überhaupt nicht klar
. Und alles wird mit 20 Bildern pro Sekunde animiert
. Und alles
hinterlässt Spuren. Und ich werde
alte Farben erst entfernen, wenn wir bereit sind,
den nächsten aktualisierten A-Frame für
das Spiel hier neu zu zeichnen . Also Kontext, löschen Sie das Rechteck von Koordinaten Null Null
bis zu dieser Punktbreite, diese Punkthöhe, um
den gesamten Spielbereich zu löschen, eine Optimierung
wäre, unser Spiel auf
mehrere
Cannabis-Elemente zu zeichnen und nur
die Cannabisportionen zu löschen , die es tatsächlich aktualisieren. Auf diese Weise müssten wir nicht ständig alles neu zeichnen. Im Moment wird das gut funktionieren. Sie sollten eine Verlangsamung der Geschwindigkeit der
Spielanimationen
feststellen können ,
da wir die FPS hier auf 20
setzen. Um es noch deutlicher zu machen, möchte ich
vielleicht nur
fünf Bilder pro Sekunde animieren. 30405060. Ich bin mir sicher, dass FBS
60 Bilder pro Sekunde erreicht, aber wir
animieren unser Spiel nicht wirklich 60 FPS, denn jedes Mal, wenn ich den Timer auf Null
zurücksetze, bleibt etwas Deltatime
übrig ich nicht berücksichtige. Also obwohl ich 60 sage, ist
die tatsächliche FPS etwas niedriger. Ich kann runtergehen und die verbleibende
Delta-Zeit abrechnen. Aber vielleicht möchte ich
diese Codebasis einfach halten. Vielleicht möchte ich kein JavaScript
erstellen, um immer
wieder mehr Berechnungen durchzuführen. das also im Hinterkopf behalte, werde
ich wissen, dass
ich FBS hier auf
einen etwas höheren Wert setzen muss, um
tatsächlich
etwa 60 FPS zu erreichen werde
ich wissen, dass
ich FBS hier auf
einen etwas höheren Wert setzen muss, um . Wenn ich den Wert auf 70 setze,
kommen wir meiner Meinung nach flüssig
genug voran und lassen JavaScript
nicht die übrig gebliebene Delta-Tan
berechnen, was die
Leistungsanforderung
in unserem Spiel leicht
erhöhen würde . Ich habe gerade darüber nachgedacht, ich bin mir nicht sicher, was eine bessere Lösung ist. Ich werde meinen Code vorerst
so belassen, aber ich denke, die richtige
Lösung hängt von den
persönlichen Vorlieben jedes Einzelnen ab. Also drei, um
das in den Kommentaren zu besprechen. Ich werde Ihr Feedback in
meinen zukünftigen Projekten berücksichtigen ,
da wir wissen, wie
wir die Animationsgeschwindigkeit
unseres Spiels mithilfe von Delta-Time steuern Das Spiel wird auf allen Maschinen mit einer ähnlichen
Geschwindigkeit laufen, auch für diejenigen von uns, die Bildschirme
mit hoher Bildwiederholfrequenz verwenden.
18. Egg: Ich wollte Eier hinzufügen
, die
herumgeschoben werden können , um noch
mehr Physik in unser Spiel Aus diesen X schlüpfen nach einer bestimmten
Zeit oder wenn sie vergangen ist, zu
Kreaturen. Und die Aufgabe der Spieler wird es sein,
die Kreaturen von Hodge zu schützen. Das X kann von Feinden
herumgeschoben werden, aber sie werden nicht zerstört. Die Herausforderung für den
Spieler besteht darin, dass
Feinde die Jungtiere fressen, wenn sie schlüpfen . Aufgabe der Spieler in unserem Spiel
wird es also sein, das X zu positionieren , es zu
beschützen oder Gegner
vom Weg der
frisch geschlüpften Kreaturen
wegzudrängen . Die Larve, die aus jedem Ei
kommt , versucht immer,
sich in Sicherheit zu und sich in den Büschen
im
Pilzwald oben zu verstecken . Dadurch werden
viele Wahlmöglichkeiten der Spieler und ihre Optionen in unser Spiel eingeführt,
während
wir die von uns implementierte Physik nutzen Ich hatte eine Idee für diese
Spielmechanik eine
Naturdokumentation
angesehen habe, in der
kleine Babyschildkröten am Strand
schlüpfen und versuchen, aus Sicherheitsgründen ans Meer zu
gelangen. In unserem Spiel
kontrollieren wir den blauen Ball. Ihre Aufgabe ist es, die
Jungtiere zu schützen, indem sie X,
Laven und Feinde herumschubsen . In diesem Spiel dreht sich alles um
Physik und Positionierung. Ich werde eine benutzerdefinierte
Klasse haben, die ich zB anrufe. Konstruktor
erwartet wie gewohnt einen Verweis auf das
Hauptobjekt des Spiels, um sicherzustellen, dass die
Ec-Klasse Zugriff auf
viele wichtige
Eigenschaften des Spielobjekts hat . X wird Teil
der Spielphysik sein. Ich muss also sicherstellen, dass ich
separate X- und
Y-Koordinaten für den Mittelpunkt des
Kollisionskreises definiere separate X- und
Y-Koordinaten . Und für das Sprite Sheet. Beginnen wir mit der Eigenschaft
Kollision x. Es wird ein zufälliger
Wert zwischen Null und der Breite
des Spielbereichs sein. Kollision y liegt zwischen
Null und Spielhöhe, also Kollisionsradius, z. B. 40 Pixel. Dieses Ladebild wird ein
Dokument mit einem Punkt sein, das Element anhand der ID abgerufen wird, und die ID befindet sich in index.HTML. Ich muss
dieses Bildelement tatsächlich erstellen. Wie immer können Bilder im Abschnitt
Ressourcen unten
heruntergeladen werden . Ich verstecke es hier mit CSS. Ich halte für meine Objekte dieselben
Namenskonventionen ein. Es ist eine gute Praxis. Sprite-Breite beträgt also 110 Pixel und die
Sprite-Höhe 135. Breite und Höhe werden auf dieselben Werte
gesetzt. In unserem Spiel hat jedes Objekt
Kollision x und Kollision. Warum Eigenschaften, die
den Mittelpunkt des
Kollisionsbereichs darstellen ,
sogar Spieler und Hindernisse haben die Eigenschaften
so benannt, sodass wir eine wiederverwendbare Methode zur
Kollisionserkennung
verwenden können wiederverwendbare Methode zur
Kollisionserkennung
verwenden um unsere
Physik auf alles zu implementieren. Das Gleiche gilt für Sprite
x und Sprite. Warum Immobilien? Diese stellen die Position in der
oberen linken Ecke ,
von der aus das
Bild des Objekts gezeichnet wird. Sprite X des Bildes
entspricht Kollision x plus der halben
Breite des Bildes. Um das Bild horizontal über dem
Kollisionskreis zu zentrieren. Sprite y entspricht Kollisions-Y
plus der halben Bildhöhe. Möglicherweise müssen wir das
etwas später anpassen , da
wir wollen, dass sich der
Kollisionsbereich an der Basis des Halses befindet,
nicht in der Mitte. Dazu kommen wir bald. Die Draw-Methode erwartet den
Kontext als Argument. Wie üblich rufen wir draw image auf, und diesmal
benötigen wir nur drei Argumente. Das Bild, das wir zeichnen möchten, und die X- und Y-Koordinaten
, wo es gezeichnet werden soll. Wenn wir skalieren würden, würden
wir auch
optionale Breiten - und
Höhenargumente wie diese hinzufügen. Aber ich gebe dir alle
Bilder in der gleichen Größe. Wir zeichnen sie im Spiel. Es ist also eigentlich nicht notwendig. Wie bei allen Spielobjekten zeichnen
wir nicht nur
das Bild, zeichnen
wir nicht nur das
das Objekt darstellt, wir zeichnen auch Kollisionskreis, wenn der
Debug-Modus aktiv ist .
Da wir in unserer
gesamten Codebasis
dieselben Benennungskonventionen
für Eigenschaften beibehalten , erleichtern
wir uns das Leben. Ich kann einfach diesen gesamten
Codeblock kopieren und hier verwenden. Wir zeichnen also x MHz
und wenn der Debug-Modus aktiviert ist, zeichnen
wir den Kollisionsbereich. Ja, wahrscheinlich ist es
eine gute Idee diesen Code in
wiederverwendbare Methoden umzuwandeln, da wir
denselben Code verwenden, um Kollisionskreise
für alles zu zeichnen. Das mache ich vielleicht später. Vorerst wollte ich eine Methode
entwickeln, die unserem Spiel
regelmäßig ein neues
Ei hinzufügt. In der Spielklasse werden wir ein Array
haben, das alle
derzeit
aktiven Eierobjekte enthält. Ich werde auch eine andere
Eigenschaft namens Anzahl der Eier haben. Oder ein max x beschreibt
es noch besser. Wir fügen dem Spiel nur
neue hinzu, bis die Summe kleiner oder
gleich dem maximalen X-Wert ist.
19. Regelmäßig neue Eier hinzufügen: In der Rendermethode werden wir uns
hier mit der Logik befassen, x regelmäßig hinzuzufügen. Wir haben es schon gemacht. Wir haben in
dieser Codebasis ein periodisches Ereignis durchgeführt, bei dem
wir die Delta-Zeit verwenden und einen neuen Spielframe
nur ausgelöst haben, wenn ein bestimmter
Intervallwert erreicht wurde. Wir werden hier tatsächlich
dasselbe tun. Dafür benötigen wir einige
Hilfsvariablen. Eieruhr wechselt von
Null auf den Intervallwert X. Dann wird ein neues Ei hinzugefügt und es wird zurückgesetzt
, sodass es zählen kann. Schon wieder. Wir arbeiten mit
Deltazeit, also Millisekunden, ich möchte ein neues Ei hinzufügen, sagen
wir alle
500 Millisekunden. Hier unten werde ich überprüfen, ob Eieruhr länger
als das x-Intervall ist. Wir fügen ein neues Ei hinzu, indem wir
diese Methode von Zeile 220 aus aufrufen. Da drin
nehme ich einfach das Eiers-Array, ich nenne die eingebaute
Array-Push-Methode. Ich werde dort eine neue Instanz unserer Kunden,
zB eine Klasse, reinstellen. Wie immer wissen wir, dass die Eiergläser das
Spiel als Argument erwarten. Also übergebe ich ihm dieses Schlüsselwort, weil wir uns hier
in diesem Spielobjekt befinden. Wenn die Eieruhr also
mehr als das x-Intervall beträgt, rufen
wir Ei hinzufügen auf. Wir werden den
Timer auch wieder auf Nullen zurücksetzen ,
damit er beim
nächsten Ei wieder zählen kann. Andernfalls erhöhen wir die
Eieruhr immer weiter um die Deltazeit, was wir
hier bereits zur
Rendermethode von zuvor verwenden. Ich protokolliere diesen Punkt x in der Konsole, um zu sehen, ob die Objekte hinzugefügt
werden. Entschuldigung, das wird nur
ein endlos wachsendes Array erzeugen. Ich muss hier eine
zusätzliche Bedingung erstellen, füge
nur neues x hinzu,
solange die Länge des x-Arrays kleiner als
max x ist. Das ist besser. Ich untersuche eines der Objekte. Ich muss sicherstellen, dass
alle Eigenschaften Werte
haben. Wenn z. B. ich undefined als
Kollisions-X-Koordinate hätte, würde
mein X nicht
auf Canvas gezeichnet werden, weil JavaScript nicht wüsste,
wo es gezeichnet werden soll. Ich sehe Werte in allem.
Das sieht toll aus. In der Rendermethode möchte ich
auch mein X zeichnen. Ich kopiere einfach diese Linie und habe für jedes
Element im Röntgenbild
angepasst, wir nennen es z. Wir werden die
Draw-Methode darauf aufrufen. Perfekt. Jetzt bekommen wir einige Grafiken
, die es uns noch
einfacher machen werden , die
Details zu optimieren und zu verbessern. Das Erste, was mir auffällt, ist, dass alle Eier
fast sofort hinzugefügt werden, obwohl ich gesagt habe, ich möchte alle 500 Millisekunden
ein Ei. Wenn ich das
x-Intervall hier auf 1 s erhöhe, kann
ich sehen, dass mit meinem Code etwas nicht
stimmt. Ich weiß, dass das Problem
in diesem Codeblock liegen muss. Und weil die Eieruhr
mehr als ein Intervall ist und
erst dann ein neues Ei hinzugefügt wird, müssen
wir hier diesen
Vergleichsoperator verwenden. Das mit dem Tippfehler tut mir leid. Sie haben es wahrscheinlich
schon einmal bemerkt. Jetzt funktioniert es. Wir bekommen alle 1 s ein neues Ei
hinzugefügt, solange wir
weniger als zehn x haben. Ich kann auch sehen, dass
die Bilder außerhalb der
Kollisionskreise
positioniert sind . Ich ändere dieses Plus
hier und auch hier auf Minus .
Das ist jetzt besser. Ich möchte
die Tabelle im Verhältnis
zu ihrem Kollisionskreis anpassen . Plus 35 wird es um -35 nach oben bewegen, wir bewegen es um -30 nach unten. Ich wollte den unteren
Bildrand so
genau wie möglich angleichen , aber ich möchte auch nicht der Kollisionskreis zu
groß ist, weil ich möchte, dass der Spieler hinter dem Ei
laufen kann,
ohne es zu schieben, um
die Illusion zu haben, dass unser Spielbereich in 3D
ist und dass
er eine gewisse Tiefe hat, obwohl
es in Wirklichkeit nur eine ebene Fläche ist. Wir werden gleich mehr tun, um dies
durchzusetzen. Jetzt möchte ich
einen Rand erstellen, um sicherzustellen, dass das X einen bestimmten
Mindestabstand zu den Rändern des Spielbereichs hat, damit
wir den Spieler
zwischen das Ei und den Rand bringen können ,
um es an eine beliebige Stelle zu schieben. Ich möchte, dass der Abstand, sagen
wir, Kollisionsradius
zur anfänglichen x-Position des Kollisionskreises ein zufälliger Wert ist, der von links
beginnt. Ausgehend von diesem
Margenwert, den wir gerade definiert spielen wir mit minus dieser Marge. Hier unten habe ich das Intervall von
200 Millisekunden eingestellt. Ich will 50 x. Nur um eine bessere Vorstellung zu bekommen, wo sie möglicherweise in unserem Spiel
spawnen können. Wir haben den linken
Rand, den ich wollte, aber ich kann sehen, dass das X oder
zu weit am rechten Rand ist. Also hier erhöhe ich den
rechten Rand so. Ja, damit bin ich zufrieden. Dx sind jetzt horizontal immer vollständig
sichtbar, mit etwas zusätzlichem Abstand links und rechts zwischen den Altersstufen
des Spielbereichs. Vertikal werde ich
etwas Ähnliches machen. Die zufällige Position
muss unterhalb
des oberen Randbereichs beginnen , den
wir zuvor definiert haben. Ich möchte kein X vor
diesem Hintergrundkunstwerk haben. So wie Math.random funktioniert, habe ich den Bereich einfach
von hier nach hier verschoben. Ich muss
den Bereich auch eingrenzen, indem ich die Spanne der
zufälligen Werte, die wir erhalten,
reduziere. Also Spielhöhe minus oberer Rand. Jetzt kann x
von hier nach hier erscheinen. Ich werde den zufälligen
Wert um einen Rand verkleinern, um
ihm etwas Platz am
unteren Rand zu geben, so wie hier. Perfekt. Wenn Sie ein Anfänger sind, kann
Math.random nicht intuitiv sein. Es ist eigentlich sehr einfach. Es kann nur etwas Übung erfordern. Also hier sage ich
Set Collision. Warum eine Eigenschaft auf einen zufälligen Wert der hier am oberen Rand
beginnt? Weil wir von oben gehen und
der Bereich der zufälligen Werte die
Spielhöhe abzüglich dieser Marge
abzüglich dieser anderen Marge ist . X kann also irgendwo zwischen
hier und hier erscheinen . Vertikal. Ich setze das Intervall auf 500
Millisekunden und max. x auf z. B. zehn. Im Moment bedeutet das, dass
wir jede halbe Sekunde ein Ei
erscheinen lassen,
bis die Gesamtzahl zehn beträgt. ein Physikspiel handelt, Da es sich um ein Physikspiel handelt, wollten wir, dass der Spieler die Eier
herumschieben
kann, um sie aus dem Weg zu bringen, um ankommenden
Feinden aus dem Weg zu gehen, oder sie
strategisch zu positionieren , um
der Larve, die daraus
schlüpft, die beste Überlebenschance in diesem Spiel zu geben .
Ich entscheide mich dafür, dass x unzerstörbar ist. Gegner schieben
das X einfach aus dem Weg,
wenn sie kollidieren, aber die Larve, die schlüpft,
wird gefressen, wenn der Feind sie fängt. Daher ist es sehr wichtig,
das X zu positionieren und zu verschieben . Lassen Sie uns dem X etwas Physik geben.
20. Egg: Ich gebe jedes Ei und jede
Update-Methode darin an, wir werden ein
temporäres Helper-Array
namens Kollisionsobjekt erstellen . Dies wird alle Objekte in
unserem Spiel enthalten , mit denen x interagieren
wird. Wir werden prüfen, ob
jedes Ei mit diesen Objekten kollidiert. Also brauchen wir hier einen Spieler, dieses Punktspiel,
einen Punktspieler wie diesen. Und natürlich brauchen wir hier die
soliden Hindernisse. Ich möchte, dass all diese Elemente
auf dem gleichen Niveau sind. Im Kollisionsobjekt-Array. Wir haben hier ein Spielerobjekt. Und wir werden das
Hindernis-Array mit dem Spread-Operator in ein
Kollisionsobjekt-Array
verteilen. So wie das. Der Spread-Operator ermöglicht es
uns,
Elemente in einem Array schnell in ein anderes Array
zu erweitern . Ich werde dieses
Kollisionsobjekt tatsächlich mit Eis nennen. Ich rufe nach jedem darauf, für jedes dieser Objekte. In diesem Fall möchte
ich also
für den Spieler und alle einzelnen
Hindernisse, die wir hier haben, diese
Check-Kollisionsmethode verwenden wir in Zeile 225 definiert haben. Wenn Sie sich erinnern, werden Objekt a und Objekt B als Argumente verwendet. Und es gibt ein Array zurück
, das uns wahr oder falsch für den Kollisionsabstand zwischen zwei
Kollisionskreismittelpunkten, einige ihrer Radien
und den horizontalen und vertikalen Abstand zwischen
den beiden Mittelpunkten angibt. Ich kopiere dieses Array. Ich füge es hier ein. Und wieder werden wir diese
Struktur verwenden, um diese fünf Variablen schnell mit einer einzigen Codezeile zu
definieren Ich benötige hier einen Variablennamen, also nenne ich die erste
Kollision wahr oder falsch,
unabhängig davon, ob sie mit einem Spieler oder einem Hindernis kollidiert. Das haben wir schon einmal gemacht. Ich möchte, dass dies die
Hauptvariablen sind und sie werden diesem Punktspiel entsprechen. Überprüfen Sie nicht die Kollision zwischen
diesem Ei, da wir uns in der Aktualisierungsmethode der Ec-Klasse und einem der Objekte im Array der
Kollisionsobjekte befinden. Während die forEach-Methode ausgeführt wird, führen
wir die
Check-Kollisionsmethode zwischen diesem Ei und jedem
Element in diesem Array aus. Und wir erhalten
fünf Variablen , die uns mehr Details über Position und Kollision dieser beiden Objekte, die
wir vergleichen, mitteilen. Wenn eine Kollision erkannt wird, verwenden
wir all
diese Werte, um zu berechnen, wie weit und in welche Richtung
wir das Ei schieben wollen. Die horizontale Richtung
des Schubs das Verhältnis zwischen dem X, dem horizontalen Abstand
zwischen den beiden Mittelpunkten
und der Entfernungshypotenuse und der Entfernungshypotenuse dieses imaginären
rechtwinkligen Dreiecks. Da dx eine Stelle
dieses Dreiecks ist und der
Abstand die Hypotenuse,
die längste Seite, ist , werden
wir durch einen größeren Wert in
kleinere Werte geteilt . Aufgrund dieser Einheit wird
x etwas zwischen
minus eins und plus eins sein. D x kann positiv
oder negativ sein. Einheit y. vertikale Schubrichtung ist
das Verhältnis zwischen
D und Entfernung. Jetzt benutzen wir das,
um das Ei zu bewegen. Wir befinden uns in einem Codeblock
, der nur ausgeführt wird, wenn x mit dem Spieler
oder einem der Hindernisse kollidiert. Wenn also eine Kollision auftritt, nehmen
wir die Kollision x
des Eies und verschieben es um ein Pixel außerhalb
des Radius des Objekts. Es ist Kollision und Breite. Also Kollision x des
Objekts, der Mittelpunkt, plus ein zusätzliches Pixel, um
das Ei außerhalb des
Kollisionsbereichs zu bewegen . So weit und die
horizontale Richtung dieser Bewegung wird also definiert
, indem sie mit der Einheit x
multipliziert wird, die, wie gesagt, positiv oder negativ sein
kann. Wir müssen die
Kollision und das Ei auch vertikal bewegen. Kollisionsmittelpunkt y des Eies wird die Kollision
y des Objekts sein. Es kollidiert mit dem
Radius des Eies plus dem Radius des Objekts
plus einem zusätzlichen Pixel. In der nächsten Schleife ist die
Bedingung also falsch. Begriffe vertikale Richtung,
definiert durch Einheit Y. Beachten Sie, dass
wir hier eine
Kollision erkennen und ich bewege Kollision und Kollision, warum
des Eies, basierend auf der
Position des Hindernisses? Das ist nur meine Entscheidung
und wenn ich das mache bewegt sich
das Ei und all diese Elemente werden in dieser Interaktion
solide sein. Wenn eine Interaktion stattfindet,
bewegen wir den Spieler und
die Hindernisse bleiben stabil. Sie lassen sich nicht vom Ei
schubsen. Hier unten nennen wir Draw
Method für jedes Ei. Wir möchten auch
diese neue
Aktualisierungsmethode nennen , die wir gerade geschrieben haben. Lass uns das testen. Wir verschieben den
Kollisionskreis dieses Eies. Ich muss sicherstellen,
dass der Kollisionsbereich und Sprite zusammenhalten. Der einfachste Weg
wäre,
diesen Code so zu verwenden, dass
Sprite X und Sprite positioniert werden. Warum in Bezug auf
Kollision und Kollision y und ich werde es
Insight Update Method nennen. Ich kann die Werte hier entfernen und jetzt können wir Dx mit dem Player drücken, und sie werden auch
kollidieren und
um unsere Pilze und Pflanzen herumrutschen , um die festen Hindernisse herum. Dx
interagieren nicht miteinander. Das ist nur meine Wahl. Ich möchte
, dass sich die X überlappen,
sodass ein erfahrener Spieler mehrere Eier schieben, sie quasi zusammen verletzen
und sie
alle gleichzeitig schieben
kann , sie quasi zusammen verletzen . diese Wahl wird
unser Code auch einfacher, weil
wir lernen.
21. Bestellung zeichnen: Wir zeichnen alles
auf einem einzigen Leinwandelement. Die Zeichenreihenfolge
unserer Spielobjekte,
was die Drohne
hinter und was im
Vordergrund ist, hängt also was die Drohne
hinter und was im
Vordergrund ist von der Reihenfolge in der wir die Zeichnungsmethoden für
jedes Objekt innerhalb
der Rendermethode hier aufrufen ab,
in der wir die Zeichnungsmethoden für
jedes Objekt innerhalb
der Rendermethode hier aufrufen. Im Moment habe ich Hindernisse gezeichnet, also Pilze und Pflanzen. Dann zeichne ich x. Also werden x auf Hindernisse
gezeichnet, wie du hier sehen kannst. Und dann zeichnen wir den Spieler. Der Spieler wird über
alles andere gezogen. Wenn ich das X nehme und
es zuerst
ziehe, wird hinter
den Hindernissen hinter dem Spieler immer
eines gezogen . Und hier können wir sehen, dass es visuell
nicht wirklich
Sinn macht. Ich wollte eine
Illusion von Tiefe erzeugen, künstliches 3D oder vielleicht
zweieinhalb D. Objekte, die niedrig sind,
sollten im Vordergrund stehen. Wenn wir uns nach oben bewegen,
sollten Objekte,
die auf dieser vertikalen Grundlinie gezeichnet sind, nach hinten gezeichnet
werden, z. B. sollte
dieses Ei vor dieser Pflanze gezeichnet werden, nicht dahinter. können wir nicht wirklich erreichen. Wenn wir alle x zeichnen,
dann alle Hindernisse und dann den Spieler, müssen
wir unseren
Code ein wenig anpassen. Ich muss all diese
Objekte in ein einziges Array zusammenfassen und dieses Array
anhand der vertikalen Koordinaten sortieren. Lass mich dir zeigen, was ich meine. Ich erstelle eine neue Eigenschaft
für die Hauptspielklasse. Ich nenne es Spielobjekte. Zunächst wird dies ein leeres Array
sein. Zufallsmethode nehme ich ein Spielobjekt und verwende den
Spread-Operator , um
das gesamte Array darin zu erweitern. Ich werde hier auch die gesamte
Hindernisliste erweitern. Und ich füge den Spieler hinzu. Jetzt halten wir alle Spielobjekte
in einem einzigen Array. Dieses Array wird jedes Mal
neu erstellt Rendermethode
verwendet. Ein guter
Optimierungstipp wäre, diese Operation nur
durchzuführen eine vertikale Koordinate
eines Elements ändert. Oder wenn wir ein Ei hinzufügen oder entfernen, werde
ich
diesen Codeblock wiederverwenden. Anstatt
jede Methode im Array aufzurufen, werde
ich sie für dieses
neue Spielobjekt-Array aufrufen. Für jedes Element im Array werde
ich ihm einen temporären
Variablennamen zuweisen, z. B. Objekt für jedes Objekt
im
Spielobjekt-Array , das die zugehörigen
Draw- und Update-Methoden aufruft. Damit dies funktioniert, ist
es wichtig, dass für alle Objekte, die wir in Zeile
217 zum
Spielobjekt-Array
hinzufügen , in ihren Klassen Draw- und
Update-Methoden definiert
sind . Andernfalls
würde der Code kaputt gehen, weil JavaScript diese Methode nicht finden könnte. Also rufen wir Draw und
Update für alle Spielobjekte
auf, auf allen X, auf allen Hindernissen
und auf den Spieler. Das heißt, ich kann
diese Codezeilen jetzt löschen. Tippfehler hier, ich habe
Spielobjekte mit S buchstabiert. Jetzt zeichnen wir das erste Hindernis
und dann bekommen wir eine Fehlermeldung. Wir rufen die Auslosung
des ersten Hindernisses aus. Und als wir versuchten, Update darauf
aufzurufen, erhalten
wir einen Typfehler, der besagt, dass Object Dot Update keine Funktion
ist. Ich gehe zu meinem Hinderniskurs
und du kannst sehen, wie gesagt, wir haben hier die Draw-Methode, aber es gibt keine Aktualisierungsmethode. Wir bitten JavaScript,
eine Methode aufzurufen , die für dieses Objekt nicht
existiert Ich werde hier eine
Aktualisierungsmethode erstellen. Innerhalb dieser Methode könnten wir z. B. Tabellen
mit diesen Pflanzen und
Pilzen
animieren , wenn der Spieler mit ihnen
kollidiert oder so,
vielleicht füge ich später einige
interaktive Hindernisse hinzu mit ihnen
kollidiert oder so, . Vorerst lassen wir
diese Methode leer. Jetzt funktioniert es und wir rufen Draw und
Update auf allen X,
allen Hindernissen und auf den Spieler auf. Alternativ hätte ich das Fehlen einer
Update-Methode für Hindernisse
auch durch
irgendeine Art von
Wenn-selt-Statements hier unten lösen Update-Methode für Hindernisse
auch durch können, es gibt immer mehrere
Möglichkeiten, etwas zu tun. Besprechen Sie gerne, wie Sie das anders angehen würden. Vielleicht bekommen wir in
den Kommentaren
bessere Lösungen , die ich in zukünftigen Kursen
verwenden könnte. Ich freue mich, wenn Sie mir Feedback zu
meinem Code
geben und Verbesserungen
vorschlagen. Okay, jetzt
rufen wir Draw und Update auf, während wir
durch die Spielobjekte wechseln, was bedeutet, dass X zuerst gezeichnet werden, was bedeutet, dass X zuerst gezeichnet werden,
Hindernisse über X und der Spieler über
allem gezeichnet wird. Wenn ich hier die Reihenfolge
dieser Elemente ändere, wird
der Spieler jetzt
hinter
X zurückgezogen und Hindernisse sind
über allem. Jetzt können wir verstehen,
wie das Layering funktioniert. Es hängt von der Reihenfolge ab
, in der wir die Zeichenmethode für
jedes Objekt aufrufen , um
unsere Spielobjekte in der Reihenfolge zu zeichnen , die visuell Sinn macht. Ich kann jetzt die Anordnung der
Spielobjekte
anhand der
vertikalen Position jedes Objekts sortieren . Ich nehme das Array der Spielobjekte und rufe die eingebaute
Array-Sortiermethode auf. Diese Methode sortiert die
Elemente in einem Array und gibt
dasselbe Array zurück, das jetzt sortiert ist. Wenn wir es aufrufen,
ohne Argumente zu übergeben,
werden standardmäßig nur
Array-Elemente in Zeichenketten umgewandelt. Und es sortiert sie
anhand ihrer Unicode-Werte. Das wollen wir nicht wirklich, also werden wir es als Argument weiterleiten. Dieses optionale Argument, das
wir an die
Array-Sortiermethode übergeben können , ist
eine Vergleichsfunktion, eine benutzerdefinierte Funktion, die eine gewisse Logik
definiert. Es definiert
eine bestimmte Sortierreihenfolge, die wir wollen. Diese spezielle Funktion
benötigt zwei Argumente, Element a und Element sind
alle Elemente im Array. In unserem Fall
wird das Array in
Spielobjekten durch
dieses A und B dargestellt, wird das Array in
Spielobjekten durch
dieses A und B dargestellt das in dieser
Logik verwendet wird, die wir hier definieren Ich kann die Rückgabe so machen, und ich möchte die
Elemente in aufsteigender
Reihenfolge basierend auf dem Wert
jeder Objektkollision sortieren . Warum Eigentum?
Wir sortieren also anhand des vertikalen Mittelpunkts
der Kollisionskreisfläche. Alternativ könnten wir auch nach dem unteren Rand
des Sprite-Bildes sortieren, was nach dem Wert
von
Sprite y plus Sprite-Höhe sortiert wäre . Sortiermethode kann für Anfänger kompliziert zu verstehen sein.
Alles, was Sie
hier verstehen müssen, ist, dass ich
alle meine Elemente in das Array der
Spielobjekte einfüge. Dann habe ich die eingebaute
Sortiermethode von Colin für dieses Array. Und ich organisiere
diese Elemente anhand ihrer
vertikalen Position. Es funktioniert jetzt nicht,
weil ich
ein Array erstelle , das ich zeichne,
und dann sortiere ich. Ich muss die Elemente sortieren,
nachdem ich das Array erstellt habe, aber bevor ich sie zeichne. Also so. Perfekt. Das wird nun vor
der Pflanze gezeichnet, aber wenn ich es mit dem
Spieler nach oben schiebe, wird
die vertikale
Position der Eier kleiner als die vertikale
Position der Pflanze. Jetzt wird das Ei
hinter die Pflanze gezogen. Dies ist eine einfache
Möglichkeit, Elemente in
einem 2D-Spiel visuell sinnvoller zu zeichnen . Es ist eine sehr leistungsstarke Technik , die Sie Ihrem Coding-Toolkit hinzufügen können. Hast du irgendwelche Fragen?
Hinterlassen Sie einen Kommentar. Du musst nicht das
Folgende tun, was ich jetzt tun werde. Ich setze das Intervall auf 20 Millisekunden
und max. x wird 150 sein. Ich teste nur, ob es irgendwelche
Probleme gibt, die wir lösen müssen. Wenn ich sie durchgehe, scheint
die Physik sehr gut zu sein. Es funktioniert alles gut. so viele Eier zum
Testen habe, habe ich auch eine ziemlich gute Vorstellung davon, wo sie
möglicherweise laichen könnten. Sie erscheinen in dem von uns angegebenen
Bereich mit einem großen oberen Rand und kleineren Rand von
links, unten und rechts. Wir haben x, nette Jobcoder. Ich sagte Intervall
2000 Millisekunden, ein Ei pro Sekunde und max. x wird 20 sein. Da wir diese
Kollisionsformel haben, wird sie, wenn sie über einem
Hindernis oder dem Spieler erscheint, automatisch aus ihrem Kollisionsradius geschoben . Ich entferne dieses
Konsolenprotokoll in Zeile 237. Wir haben unsere Spielwelt. Wir haben
solide Hindernisse randomisiert. Wir haben einen mausgesteuerten
Spielercharakter , der sich in eine Richtung bewegen kann. Und wir haben x, das
in einem bestimmten Intervall spawnt. Obendrein
kollidiert alles und reagiert
auf alles. Wir können damit so viele
verschiedene Spiele
machen Lass uns Feinde hinzufügen.
22. Enemy: Ich erstelle eine benutzerdefinierte
Klasse, die ich zB
Feind nenne . Wie üblich verwendet der Konstruktor
ein Spiel als Argument und wir konvertieren diese Referenz
in eine Klasseneigenschaft. Wir tun das, um durch diese Hundespielreferenz einen einfachen Zugang zu allen Immobilien der gegnerischen Klasse zu erhalten, die
sich in der Hauptspielklasse zu allen Immobilien
innerhalb
der gegnerischen Klasse zu erhalten, die
sich in der Hauptspielklasse befinden. Wir müssen hier dieselben
Namenskonventionen einhalten. Der Kollisionsradius 30 Pixel,
Kollisions-X und der Mittelpunkt des
Kollisionskreises sind also Kollisions-X und der Mittelpunkt des der rechte Rand von Canvas. Dieses Punktspiel hat eine Punktbreite. Kollision y ist ein
zufälliger Wert zwischen Null und dem Wert für die Spielhöhe, der von hier
kommt. Geschwindigkeit X horizontale Geschwindigkeit ist ein zufälliger Wert
zwischen 0,5 und 3,5. Sie können das Feindbild
in der Videobeschreibung herunterladen. Zunächst beginnen wir mit
dem statischen Einzelbild. Die ID wird abgeschleppt, Quelle wird der Punkt PNG mitgeteilt. Ich verstecke es mit CSS,
weil wir es so
zeichnen wollen , dass das
JavaScript auf Canvas, diese Punktbild-Eigenschaft, das Element nach ID abrufen
wird. Und der Ausweis, den wir ihm gegeben haben, wurde abgeschleppt. Sprite mit, in diesem Fall 140 Pixeln, und die
Sprite-Höhe beträgt 260. Ich werde auch Breiten
- und Höheneigenschaften erstellen. Und wir definieren die Sprite-X
- und Sprite-Y-Positionen
des Tabellenbilds, die im
Verhältnis zur
Kollisionskreiskoordinate positioniert
werden . Die Draw-Methode verwendet den Kontext als Argument, die integrierte Methode zum
Zeichnen von Bildern. Und weil die
Bilddatei, die ich verwende bereits die gleiche
Auflösung wie die Größe hat. Ich möchte, dass
es im Spiel angezeigt wird. Ich muss
ihm nur drei Argumente übergeben. Das Bild, das ich zeichnen wollte
und x und y sollten es zeichnen. Ich werde auch das
Kollisionskreis-Visual kopieren, das nur
angezeigt wird , wenn die
Debug-Modus-Eigenschaft auf true gesetzt ist. Nur wenn der Debug-Modus aktiv ist. Ich kopiere es einfach und füge es hier ein. Da dieser Code für
alle unsere Objekte derselbe ist . Methode aktualisieren. Darin möchte ich, dass sich die Gegner
auf der
horizontalen X-Achse mit
der Geschwindigkeit x,
einem Wert, den wir in Zeile 179 definiert haben, in Minusrichtung nach links bewegen auf der
horizontalen X-Achse mit
der Geschwindigkeit x,
einem Wert, den wir in Zeile 179 definiert haben, in Minusrichtung nach . Wir verschieben also
Gegner nach links, wenn der rechte Rand
der Tabelle hinter dem linken
Rand von Cannabis
versteckt ist . Wir können seine
X-Position wieder auf die
Spielbreite setzen , sodass es wieder nach links über
den Bildschirm
laufen kann . Wir werden auch die vertikale Y-Position nach dem Zufallsprinzip anordnen, damit die Gegner
auf verschiedenen Bahnen laufen. Ich werde also Feinde haben
, die von rechts
nach links gehen und dann
zurücksetzen und wieder gehen. Alternativ hätte ich
auch immer wieder neue animierte
Objekte erstellen und sie zerstören
und
wegwerfen können, wenn
sie sich vom Bildschirm bewegen. Der Code wäre
einfach, aber
Objekte wiederzuverwenden , indem
ihre Position zurückgesetzt wird,
anstatt neue zu erstellen
und sie
später zu verwerfen , ist eine gute
Optimierungstechnik. Lassen Sie uns Ihre Objekte wiederverwenden und ihre
Positionen zurücksetzen, wenn Sie können Anstatt neue zu erstellen, ist die
Verwendung des Schlüsselworts new zum
Erstellen eines neuen Objekts teurer als das
Zurücksetzen eines vorhandenen Objekts. In der Hauptspielklasse erstelle ich
eine benutzerdefinierte Methode, die ich z. B.
at, NME aufrufe . Hier oben haben
wir ein
Array, das
alle derzeit aktiven
animierten Objekte enthält. Immer wenn ein Feind rennt, schiebt
es ein neues
Tierobjekt in die feindliche Reihe. Online 174, ich kann mir vorstellen, dass feindliche Klassenkonstruktor das Spiel als Argument
erwartet. Also übergebe ich es mit diesem Schlüsselwort, denn hier sind
wir in dieser Spielklasse. Dabei übergebe ich nur
eine Referenz, die auf einen Bereich im Speicher
verweist , in dem
ein Spielobjekt gespeichert ist. Ich erstelle keine
Kopie des Spielobjekts. Jedes Mal erschaffe ich mir einen neuen Feind. Die Init-Methode wird ausgeführt. Ich möchte nur
unser Spiel initialisieren und
alles darin einrichten. Wir
schaffen bereits Hindernisse. Wir werden in
dieser FOR-Schleife auch Gegner erstellen , die, sagen
wir, dreimal ausgeführt werden . Und jedes Mal, wenn es läuft, wird
es rufen. Und dann die Methode, die
wir gerade definiert haben, kann
ich diese Punktfeinde auswählen. Und wie erwartet enthält es
drei animierte Objekte. Ich untersuche einen von ihnen, um sicherzugehen, dass nichts undefiniert ist, was ein Problem sein könnte. Alles ist gut hier. Ich kann das Konsolenprotokoll
löschen. Es ist eine gute Idee,
Ihre Objekte und Arrays immer
mit Konsolenprotokollen zu überprüfen Ihre Objekte und Arrays immer
mit Konsolenprotokollen während Sie Ihre
Projekte Schritt für Schritt erstellen,
um mögliche Fehler
und Tippfehler rechtzeitig zu erkennen. Um Gegner zu zeichnen und zu aktualisieren, muss
ich nur die
Feindesliste mit
dem Spread-Operator zu einem
Spielobjekt erweitern . Das haben wir schon einmal gemacht. Ich sehe nur Kollisions-Trefffelder, ich muss Sprite
X und Sprite Y einige
Werte geben , damit das JavaScript weiß, wo
die Bildposition des
Sprites gezeichnet werden soll. Wir werden umziehen. Wenn sich Kollisionskreise bewegen. Also habe ich diesen Code
in die Aktualisierungsmethode eingefügt. Lassen Sie uns zuerst den Schwerpunkt und
dann den Offset verwenden. Sprite X ist Kollision
x minus die Hälfte von Sprite mit einem Sprite wie diesem. Warum ist Kollision y
minus halbe Höhe? Ich möchte, dass die Kollisionskreise
dem Schatten auf
dem Boden unter den
schwebenden Feinden so
nah wie möglich entsprechen dem Boden unter . Wir müssen die
Bildpositionen vertikal anpassen. -40 -60. Was ist mit
Minushöhe? Plus 40? Ich kann den
Debug-Modus aktivieren und deaktivieren , um Trefferfelder ein
- und auszublenden, indem Buchstaben d
drücke.
Wir haben Gegner von rechts nach
links
kommen und dann zurücksetzen. Ich möchte, dass sie bis hinter
den rechten Rand zurückgesetzt werden, damit wir nicht sehen wie
sie einfach auftauchen. Also setzen wir sie auf die Breite des
Spielpunktes plus die Breite des Feindes zurück. Und obendrein
noch ein Spiel mit dem Begriff
0,5, um jedem Spiel eine
andere zufällige Verzögerung zu geben. Warum ist das hier? Das lösche ich. Nur zum Testen. Erhöhen wir die Geschwindigkeit. Zurücksetzen mit zufälligem Versatz hinter dem rechten
Rand funktioniert gut, vielleicht ist das ein bisschen zu schnell. Ich muss ihre
vertikalen Positionen einschränken. Nehmen wir an, wir beginnen
am oberen Rand. Und von dort aus ein
zufälliger Bereich zwischen Null und Spielhöhe
abzüglich des oberen Randes. Ich kopiere diesen Wert, um ihn als erste Kollisions-X-Position
innerhalb des Konstruktors zu verwenden. Und ich nehme diese neue Kollision, warum ich sie in der
Rezeptor-Check-In-Aktualisierungsmethode verwende. Das wird nicht funktionieren, weil
ich hier
oben in Zeile 176 diese Punktbreite verwende, aber sie wird erst
später hier in Zeile 183 definiert. Die Reihenfolge hier ist wichtig. Ich nehme einfach diese beiden
Zeilen und füge sie hier ein. Jetzt haben wir Gegner, die in
einem korrekten Korridor
von rechts nach links laufen und
sich hinter dem rechten Rand zurücksetzen. Auf diese Weise können wir
dieselben Gegner
immer wieder wiederverwenden , es sei denn,
ich entscheide, dass wir einige andere Funktionen
hinzufügen möchten ,
z. B. das
Zerstören von Feinden durch Spieler oder
ähnliches. Wir werden sehen. Auch hier müssen
Sie diesen Teil nicht tun. Ich teste nur unseren Code. Also erschaffe ich mir 30 Gegner. Wenn ich so viele Feinde habe, kann
ich mir eine bessere Vorstellung davon machen, wie sie zurückgesetzt werden, und ich kann
potenzielle Probleme schneller erkennen. Alles scheint gut zu
funktionieren. Das wäre ein sehr
gefährlicher Wald. Zum Glück für unsere
Jungtiere wird es
im letzten Spiel keine solchen Schwärme von Feinden
geben, es sei denn du willst eine periodische
Welle von Feinden wie diese erzeugen. Als Teil des Spiels und der
Mechanik
muss sich der Spieler darauf vorbereiten und es vermeiden. Wir können hier so viele Dinge in
Bezug auf das Gamedesign tun, ich gebe
dir nur die Tools und Techniken und zeige
dir einige meiner Ideen. Fühlen Sie sich frei, dieses Spiel
mit Ihren kreativen Ideen zu erweitern. Wenn der Kurs beendet ist, kehren
wir zu drei Feinden zurück. Gerade jetzt. Die Feinde
fliegen einfach durch den Wald, ohne mit irgendetwas zu
interagieren. Zunächst möchte ich, dass sie auf
solide Hindernisse reagieren und der Spieler, wir haben bereits Code, der diese Methode zur Aktualisierung von Erkenntnissen in der EKG-Klasse durchführt. Ich kann buchstäblich
denselben Codeblock verwenden und
ihn in die
Aktualisierungsmethode für die feindliche Klasse einfügen. Dadurch werden Gegner, Hindernisse
und Spieler zu soliden, und Spieler zu soliden, unmöglichen Objekten gemacht und sie
werden um sie herumrutschen. Wir befinden uns in der
Update-Methode für die feindliche Klasse, und wir passieren den
Feind als Objekt A, Spieler und die Hindernisse
als Objekt B. Und hier sagen wir, passen Sie Position von A
an die Position von B Spieler
und Hindernisse
werden in
dieser Interaktion solide und dominant sein
und Feinde werden um sie herum
geschoben. Dieser einfache
Kollisions-Check-in wird auch zu einer sehr grundlegenden
künstlichen Intelligenz führen. Wie Sie sehen können, laufen die
Gegner von rechts nach links
durch das Spielfeld. Und sie rutschen
automatisch hinein
und weichen Hindernissen
und dem Spieler aus,
weil sie
dem Spieler auf diese Weise ausgewichen sind und weichen Hindernissen
und dem Spieler aus, , können
wir den Spieler
auch benutzen, um Feinde herumzustoßen, genauso wie wir das X
herumschieben können. Ich passe die Geschwindigkeit des Feindes an. Wenn ich x zur Reihe der
Kollisionsobjekte der gegnerischen Klasse hinzufüge, wird
x auch zu soliden, unmöglichen Hindernissen
für die Feinde. Und Feinde
müssen sie umgehen. Das könnte eine gute
Sache sein,
je nachdem , wie du dein Spiel
gestaltest. Übrigens, ich will, dass
mein Spiel wird, ich wollte eigentlich das X von hier
entfernen. Stattdessen gehe ich zur Klasse
und füge innerhalb der Aktualisierungsmethode Feinde zu
Kollisionsobjekten hinzu. Hier. Dadurch wird das Objekt Eier zu einem Pfad zur Methode zur
Überprüfung von Kollisionen. Und die Gegner werden solide sein, unmögliche Gegner
werden das X herumschieben. Wenn ich das so mache, haben wir
viele Funktionen implementiert. Daher werde ich den
Quellcode aus
dieser Phase im Abschnitt
Ressourcen unten belassen dieser Phase im Abschnitt
Ressourcen unten Sie können ihn herunterladen und mit Ihren Dateien
vergleichen. Wenn Sie alleine programmieren.
Hoffe du hast Spaß.
23. Larva: Hier unten zwischen Egg
- und Feindklassen. Und ich erstelle eine neue
Klasse, die ich zB
Larva nenne . Ich möchte, dass x einen versteckten Timer hat und nach
einem bestimmten Zeitintervall schlüpfen aus
jedem Ei kleinere Larven. Diese Larve wird versuchen, sich im Wald zu
verstecken. Und unsere Aufgabe als Spieler ist es, es
zu schützen, indem wir es näher an die Sicherheitszone oder indem wir Gegner von
ihr wegstoßen. Der Konstruktor für
die Larvenklasse wird ein bisschen
anders sein, da ich möchte, dass jede Larve an
derselben Position erscheint wie
das geschlüpfte Ei. Also geben wir ihm wie gewohnt einen Verweis auf das
Hauptspielobjekt, aber wir übergeben ihm auch die
X- und Y-Koordinaten. Jetzt wandle ich all diese
Argumente in Klasseneigenschaften um. Ich muss diese
X- und Y-Koordinaten,
Kollision und Kollision, benennen , warum diese Variablen an der Kollisionserkennung
beteiligt sein werden. Wir müssen sie
also genauso benennen wie andere Objekte in unserem
Physikspiel, damit wir auch hier unsere wiederverwendbare
Check-Kollisionsmethode verwenden
und diese
Larvenschlüpfer
in den Game of Physics-Loop einbeziehen
können wiederverwendbare
Check-Kollisionsmethode und diese
Larvenschlüpfer
in den Game of Physics-Loop einbeziehen . Wir benötigen hier auch einen
Kollisionsradius, sagen
wir vorerst 30 Pixel. Sie können das Larvenbild
in der Videobeschreibung herunterladen. Ich habe hier mit einer ID von
Larva und Quelllarve Punkt PNG hinzugefügt . Es ist eine Tabelle
mit zwei Frames. In dieser Rolle
haben wir eine mutige Larve und diese hat etwas
Flaum hinter dem Hals, nur um ihr etwas
visuelle Abwechslung zu verleihen. Der Flaum macht mehr
Sinn, wenn Sie wissen, was diesen Jungtieren wird,
wenn sie ausgewachsen sind. Ich bringe das
Larvenbild
mit get element
by ID wie folgt in das Projekt . Breite und Höhe
eines einzelnen Rahmens. Jetzt beträgt Sprite mit 150 Pixeln, Sprite-Höhe ebenfalls
150 Pixel. Wenn Sie ein Anfänger sind, empfehle
ich Ihnen dringend meinen Code genau zu
befolgen
und dieselben Bilder zu verwenden. Amüsant. Wenn das
Projekt abgeschlossen ist, wird
es einfacher sein,
Ihre eigenen benutzerdefinierten Änderungen vorzunehmen. den Code zu ändern, während
Sie
diesem Tutorial folgen ist keine
gute Idee, den Code zu ändern, während
Sie
diesem Tutorial folgen, es sei denn, Sie sind ein erfahrener
JavaScript-Entwickler
, der Ihre eigenen Änderungen vornimmt, bevor
das Projekt abgeschlossen ist Wir werden das Debuggen erschweren. Wir benötigen auch die
Sprite-X- und
Sprite-Y-Koordinaten des
Tabellenbilds. Jede Larve muss die Methoden zeichnen und aktualisieren. Wie immer. Die Draw-Methode
verwendet Kontexte als Argument. In der Site nennen wir Built In a Drawer Image und wir übergeben ihm das Bild, das wir zeichnen wollen, und die
X- und Y-Koordinaten,
wo es gezeichnet werden soll. Ich möchte, dass
sich jede Larve
in
den sicheren Pilzwald bewegt . Dieses offene Gebiet ist voller Feinde und es ist sehr gefährlich. Geschwindigkeit, warum die vertikale
Geschwindigkeit ein zufälliger Wert ist, 1-2, z. B. haben wir Sprite X und Sprite definiert. Warum Eigenschaften, die bestimmen, wo das
Spritesheet gezeichnet wird. Aber da sie sich jedes Mal
bewegen müssen , wenn sich die Larve bewegt, muss
ich
sie immer wieder Update-Methode aus aktualisieren. Sprite X ist Kollision
x minus die halbe Breite. Sprite y ist Kollision
y minus die halbe Höhe. Ich verstecke dieses Bild mit CSS. Wir haben ihm eine Larven-ID gegeben.
24. Egg: Wir haben also eine Klasse, die wir als Bauplan
verwenden können, um jedes
Mal, wenn ein Ei schlüpft, eine Larve zu erzeugen Lassen Sie uns das Eierschlüpfen logisch schreiben, wir müssen unseren Variablen
helfen. Hatch-Timer wechselt von
Null auf das Schraffurintervall. Es wird Millisekunden zählen. Nehmen wir an, ich möchte, dass
das Ei
nach fünf Millisekunden nach 5
s schlüpft nach fünf Millisekunden nach 5 . In der Update-Methode behandeln
wir Kollisionen
in diesem Bereich. Und hier unten
kümmern wir uns um das Schlüpfen. Wenn der gerade
definierte Hatch-Timer mehr als das
Schraffurintervall ist, machen
wir etwas anderes. Wir erhöhen den
Hatch-Timer ständig um die Deltazeit. Zählen und Akkumulieren
in Millisekunden. Der Delta-Term wird an die
Aktualisierungsmethode
hier oben in Zeile 159 übergeben . Diese Aktualisierungsmethode
wird es hier erhalten. Inneres Rendern. Wir haben den Delta-Zeitwert
vor der Animationsschleife berechnet vor der Animationsschleife Die
Delta-Zeit enthält die
Anzahl der Millisekunden, die
zwischen diesem Animationsbild und dem vorherigen
Animationsbild vergangen sind. Hatch Timer sammelt also diese Deltazeit in Millisekunden
zwischen den Frames. Wenn der Schlupftimer länger
als das Schlupfintervall ist, löschen
wir das Ei und ersetzen
es durch eine Larve. Hier oben erstelle ich eine Eigenschaft
namens Marked for delete. Hier unten setzen wir markiert
zum Löschen auf true. Ich kann einchecken und diese zum
Löschen markierten Objekte für jedes
Animationsbild
entfernen . Es könnte etwas
effizienter sein, unser Löschen nur
neu zu strukturieren, wenn etwas tatsächlich markiert wird. Also hier werden wir
eine benutzerdefinierte Methode aufrufen. Ich rufe z.B.
entferne ein Spiel Objekte auf. Hier unten in der
Hauptspielklasse werde
ich diese Methode definieren. Bisher
markieren wir nur X zum Löschen. Wann immer diese Methode ausgeführt wird, nehme
ich das gesamte Array und rufe die eingebaute
Array-Filtermethode dafür auf. Oder eine Filtermethode
erstellt einfach eine Kopie dieses Arrays. neue gefilterte Array
enthält jedoch nur Elemente , die die
in der Callback-Funktion angegebene Prüfung bestehen. In diesem Fall wird geprüft, ob
ich nur möchte, dass das
X-Array Elemente
enthält deren
Eigenschaft zum Löschen markiert auf Falsch gesetzt ist. Wenn etwas, das
zum Löschen markiert wurde, auf true gesetzt
ist, wird es aus dem Array
herausgefiltert. Dies ist die sogenannte
ES6-Pfeilfunktionssyntax. Ich sage, nimm die Elemente
im Array eins nach dem anderen und weise jedem
ein temporäres
Variablennamensobjekt zu. Und
überprüfen Sie bei jedem dieser Objekte, ob die Eigenschaft „Zum
Löschen markiert“ den Wert „Falsch“ hat. Ausrufezeichen bedeutet falsch. Wenn
auf diesem Ei die Option zum Löschen markiert ist, wird
dieses Ei aus diesem neuen Array
herausgefiltert. Und dieses neue gefilterte
Array wird
dem ursprünglichen Röntgenstrahl zugewiesen und überschreibt ihn. Erkläre ich zu viel? Und noch einmal, lassen Sie uns dieses Punktspiel Punkt
X auf der Konsole
protokollieren , um zu sehen, ob x
entfernt und hinzugefügt wird. Ja, das funktioniert perfekt. Wenn wir uns im Debug-Modus befinden, möchte
ich, dass der Hajj-Timer als Zahl
sichtbar ist, die über
jedem Ei
schwebt .
In der Draw-Methode nenne ich die eingebaute FiltText-Methode. Diese Methode benötigt
mindestens drei Argumente, den
Text, den wir zeichnen möchten X
- und Y-Koordinaten,
an denen er gezeichnet werden soll. Die Schriftgröße ändern, anstatt die
Schriftgröße jedes
Mal zu ändern , wenn die Zeichenmethode auf jedem Ei
ausgeführt wird, werde
ich sie hier in Zeile
zehn beim Laden der ersten Seite einrichten. Dies ist eine leistungsstarke
Optimierungstechnik. Die Schrift ist Teil eines Zustands, und häufige Änderungen an einem Status
können die Leistung beeinträchtigen. Definierte Canvas-Eigenschaften
wie FillStyle, Linienstärke, Strichstil und Telefonieren in einem Codeblock, der
so wenig wie möglich ausgeführt wird. Idealerweise sollten Sie dies nicht
in einer Methode tun, die 60
Mal pro Sekunde auf mehreren
Objekten gleichzeitig ausgeführt wird. In einigen Fällen kann
dies jedoch unvermeidlich sein. Ich sage hier nur, wenn Sie die Canvas-Eigenschaften
auf der ersten Seite
festlegen und so
laden können Canvas-Eigenschaften
auf der ersten Seite
festlegen , wird der ganze
Code nur einmal ausgeführt. Ich sagte, ich
mag 40 Pixel. Helvetika. Ich hätte hier
in dieser Zeichenmethode auch eine Canvas-Schrift
definieren können. Aber wie gesagt, diese
Codezeile würde
60 Mal pro Sekunde
auf jedem aktiven Ei ausgeführt . Das sind viele
Operationen, die
leicht vermieden werden können, wenn Sie das tun,
was ich gerade gesagt habe. Ij Dimer ist diese
lächerliche Zahl mit so vielen Ziffern hinter
dem Komma. Lass uns das aufräumen. Ich erstelle eine Hilfsvariable
namens Display Timer. Hier werden wir diese Zahl ein
wenig
formatieren, bevor wir
sie zeichnen. Ich kann zum Beispiel den Hatch Timer nehmen und die
eingebaute bis feste Methode aufrufen. Methode Javascript to fixed
konvertiert eine Zahl eine Zeichenfolge und rundet die Zeichenfolge auf eine angegebene
Anzahl von Dezimalstellen. Ich will eigentlich
die Nulldezimalzahlen. Ich will nur
die Millisekunden sehen. Ich verwende die
Display-Timer-Variable hier, um sie tatsächlich zu zeichnen. Ich kann die vertikale
Position des Textes anpassen, vielleicht durch einen solchen
Kollisionsradius. Hier oben setze ich die
Textzeile in die Mitte. Dadurch werden die Timer
und x horizontal ausgerichtet. Nett. Ich wollte die Timer noch
weiter nach oben über die Eier schieben . Vielleicht sogar mehr.
Lass uns mit 2,5 beginnen. Statt Millisekunden möchte ich
nur die Sekunden sehen. Also schließe ich den Hatch Timer in Klammern und multipliziere
ihn mit 0,001. Das ist jetzt besser lesbar. Wir können die Anzahl der
Sekunden über jedem Ei sehen. Lass uns jedes Ei nach 3 s
schlüpfen lassen. Schön. Wenn das Ei schlüpft, wird
es durch
die Filtermethode entfernt. In der Hauptspielklasse erstelle
ich eine Eigenschaft
namens Hatchlings und setze sie zunächst
auf ein leeres Array. Immer wenn ein Ei schlüpft, schieben
wir neue Larven
in dieses Array. Hier oben auf Zeile 190 kann
ich sehen, dass die Larve
Wild- und X- und Y-Koordinaten erwartet . Wenn also ein Ei schlüpft, nehme
ich es mit zum Game Dot Hatchlings Array und
schiebe neue Larven hinein. Ich gebe es weiter, um das Spiel zu verzerren. Und ich übergebe ihm die X- und
Y-Koordinaten dieser
Eier, die
daraus geschlüpft sind. Ich entferne dieses Konsolenprotokoll. Innerhalb der Render-Methode verwende
ich den Spread-Operator oder um Schraffuren
zu Spielobjekten,
Arrays, zu erweitern , sodass sie
sortiert, gezeichnet und aktualisiert werden können. Perfekt, wir machen Fortschritte. Jetzt, wo wir sehen können, wie
unsere Jungtiere aussehen, können
wir in die
Larvenklasse gehen und das aufräumen. Zuerst prüfen wir, ob sich
die Larve in Sicherheit gebracht hat. Sie sind in Sicherheit,
sobald sie
dieses Pilz- und
Buschgebiet erreichen , in dem sie sich verstecken können. Wenn also die Kollision y kleiner
als der obere Rand des
Punktspiels ist als der obere Rand des
Punktspiels Larve diesen Punkt überschritten hat, können
wir die Markierung für das
Löschen auf wahr setzen. Wir werden diese Larve löschen , weil wir sie nicht mehr zeichnen
wollen. Und wir nennen remove game objects online 350 insight, remove game object's method. Ich mache dasselbe, was
wir für x gemacht haben, filtere das Hatchlings-Array. Und wenn für ein Larva-Objekt
in diesem Array Eigenschaft Zum Löschen
markiert
auf true gesetzt ist , filtern Sie es heraus. Nur um die Spielobjekte in unserem
Konsolenprotokoll zu überprüfen. Jedes Mal, wenn wir ein Ei
oder eine Larve entfernen, erhalte ich eine Fehlermeldung. Und das liegt daran, dass dies dieses Punktspiel
sein muss , das
Spielobjekte entfernen muss, weil diese Methode unserer Hauptspielklasse enthalten ist. Ich möchte, dass du
Kollisionskreise auf Jungtiere zeichnest. Ich kopiere diesen Codeblock
aus der feindlichen Klasse. Und ich habe es nur hier eingefügt, weil unsere Klassen
die gleichen Namenskonventionen
für ihre Eigenschaften haben . Es ist einfach, solchen
Code wiederzuverwenden. Moment zeichnen wir die gesamte Tabelle
für jede Larve. Ich wollte
nur ein einzelnes Bild
von der Koordinate Null Null zwei herausschneiden . Das sieht hell aus in der Breite und
dieser Punkt in der Sprite-Höhe. Und wir wollen
das ausgeschnittene
Bild an der Position
Sprite, Sprite y zeichnen . Und wir müssen ihm eine
Breite und Höhe wie folgt geben. Neun Argumente. Ich wollte das
Larven-Tabellenbild
im Verhältnis zu seinem
Kollisionskreis positionieren . Ich versuche -50. Ja, das wird funktionieren. Ich möchte, dass der Kollisionskreis an der
Unterseite seines Körpers
ausgerichtet ist. Ich denke, das wird visuell
am sinnvollsten sein, wenn man mit
Spielumgebungen und Charakteren
interagiert. Ich entferne dieses
Konsolenprotokoll in Zeile 362.
25. Larva sprites und Kollisionen: Larva-Tabelle
hat zwei Rahmen, aber wir zeichnen
nur den oberen. Lassen Sie uns diesen Frame randomisieren. Y wird ein zufälliger Wert 0-2 sein. Und da es
keine Zeile 1.5 gibt, brauchen
wir z.B. ganze Zahlen, ganze Zahlen
ohne Dezimalstellen. Also wickle ich das in Math.floor ein. Diese Codezeile gibt
uns entweder Null oder Eins, da Math.floor
den Wert auf die nächste
niedrigere Ganzzahl
herunterrundet. Frame X wird immer
Null sein , bis
ich dir später
in der Klasse eine
Tabelle für Fortgeschrittene gebe. Zur Animation. Wir werden Frame x
mal Sprite verwenden, wobei hier als Quell-X-Argument
an die Draw-Image-Methode übergeben wird. Und wir müssen auch eine Quelle
definieren. Warum die Kombination der X- und
Y-Koordinaten der Quelle bestimmt, welcher Bereich
der Tabelle, den
wir aus
Quelle Y zuschneiden , mit
Y mal Sprite-Höhe eingerahmt wird. Nett. Da Frame Why
nach dem Zufallsprinzip entweder Null oder Eins ist. Einige Jungtiere verwenden das
Sprite-Bild aus Zeile Null, und andere verwenden das andere
aus Zeile eins. Kollisionen zwischen Jungtieren und Wildobjekten
werden hier behandelt. Ich gehe hier in die
Update-Methode eine Klasse und kopiere
diesen Codeblock, wir werden einige Änderungen daran vornehmen, aber das meiste davon wird dasselbe sein. Also könnten wir es genauso gut kopieren damit wir das alles nicht
schreiben müssen. Schon wieder. Ich füge es hier in die
Aktualisierungsmethode der Larva-Klasse ein. Ich werde Gegner
von Kollisionsobjekten entfernen , da Gegner
eine andere Art der Interaktion haben werden . Larve weicht also automatisch
Spielern und Hindernissen aus. Und wir können
den Spieler auch benutzen, um
Larven auf diese Weise herumzuschieben , was eine
wichtige Spielmechanik sein wird. Kollisionen mit Feinden
werden hier unten geregelt. Ich stelle die Feinde auf und
rufe sie alle an. Für jedes feindliche Objekt nenne
ich sie Feind, z.B. für jedes von ihnen diese
Callback-Funktion auf. Im Grunde möchte ich sagen, ob diese Larve und dieser Feind, den wir
gerade mit
dieser forEach-Methode überfahren, kollidieren. Eine Möglichkeit, auf einfache Weise zu überprüfen,
ob Objekte im Spiel kollidieren, besteht darin, unsere benutzerdefinierte
Kollisionsmethode zu verwenden. Auch hier möchte ich die
Kollision zwischen dieser Larve überprüfen. Wir gehören zur Klasse der Larven
und zu jedem einzelnen Feind. Da dies für jede Methode ausgeführt wird, wissen
wir, dass unsere benutzerdefinierte
Prüfkollisionsmethode ein Array von Werten
zurückgibt. Es gibt uns den Kollisionsabstand
einiger Radien, DX und DY. Hier will ich nur das
erste Argument, Kollagen, das wahr oder
falsch sein wird, je nachdem ob diese Larve
und dieser Feind kollidieren oder nicht. Check collision
gibt ein Array zurück und ich möchte den Kollisionsstatus
wahr oder falsch. Ich möchte das erste Element
im Array-Index Null haben, so. Hier verwenden wir also
die Strukturierung, um alle fünf
einzelnen Variablen
aus der Check-Kollisionsmethode zu extrahieren . Hier greife ich direkt
nur auf den ersten Wert mit dem Index Null zu, weil ich die anderen nicht
benötige. Der Grund, warum ich
diese anderen Werte nicht benötige ,
wenn Larve und Feind kollidieren, ist, dass
es kein
Herumschubsen und keine Physik geben wird . Die Larve wird einfach gefressen. Also sagte ich, auf dieser Larve zum
Löschen markiert. Objekt gegen wahr. Ich werde auch
Remove Game Objects aufrufen, um diese Larve aus dem Array
der Schlüpflinge
herauszufiltern. Ich werde auch verfolgen,
wie viele Jungtiere wir ekelhaft und variabel verloren
haben. Dieses Punktspiel, bei dem
Jungtiere verloren haben , wird
um eins erhöht. Und hier, wo wir
überprüfen, ob
Florida die Sicherheit
des Pilzwaldes verbessert, erhöhen
wir die Punktzahl um eins. Also wenn wir Larven
nach Position und x schützen, indem Feinde
wegdrängen oder indem wir
Larven in Richtung Wald schieben . Wenn die Larve erfolgreich
im Gebüsch aufsteigt, erhalten
wir einen Punktepunkt. Wenn Larven gefressen werden, erhöht sich die Variable
für
verlorene Schlüpflinge um eins. Hier unten in unserer Hauptspielklasse erstellen
wir diese Eigenschaften. Die Punktzahl wird
zunächst auf Null gesetzt und auch für verlorene Jungtiere wird
zunächst auf Null gesetzt.
26. Punktzahl gewinnen: Ich kann Konsolenprotokolle
oder ähnliches verwenden , um zu überprüfen, ob der Code, den
wir gerade geschrieben haben, funktioniert, aber der Text musste dem Spieler trotzdem
angezeigt werden. Also hier unten werden wir den Spielstatustext
zeichnen. Schon wieder. Wir werden die eingebaute
Cannabis-Fülltextmethode verwenden
, bei der der
Text, den wir
zeichnen möchten, und die X- und Y-Koordinaten,
wo er gezeichnet werden soll, erwartet . Ich möchte die Wortpunktzahl an den
Koordinaten 25 horizontal
und vertikal zeichnen . Das Problem, das wir
derzeit haben, ist, dass ich möchte, dass dieser Text linksbündig ist. Und wenn Sie sich an
den Text über x erinnern, dass der Timer mittig ausgerichtet ist, muss
ich diesen aufgerufenen
FiltText isolieren, indem ich
ihn zwischen den
integrierten Canvas-Methoden safe und restore umwickle . Dann kann ich die
Textausrichtung auf links setzen. Und ich rufe eine Wiederherstellung an. Die Methoden Speichern und Wiederherstellen funktionieren zusammen und wir verwenden
sie, wenn wir bestimmte Einstellungen nur auf
einen bestimmten Draw-Call auf der
Leinwand
anwenden möchten Einstellungen nur auf
einen bestimmten Draw-Call auf der
Leinwand
anwenden einen bestimmten Draw-Call auf , ohne
den Rest unseres Projekts zu beeinflussen. Ich speichere den Canvas-Status. Ich habe die Textausrichtung auf links gesetzt, was sich nur auf
diesen FiltText-Aufruf auswirkt bei dem wir Punkte ziehen und dann die Wiederherstellungsmethode
alle möglichen Einstellungen
auf das zurücksetzt , was sie waren. Safe wurde gerufen. In diesem Fall kehrt es
nur zur X-Linie zurück von links zur Mitte
zurück. Das ergibt Sinn. Dies ist eine sehr nützliche Technik, insbesondere wenn Sie Ihre Leinwandzeichnungen skalieren
und drehen möchten . Das mache ich in einigen
anderen Klassen, z.B. in meiner
Fraktalklasse Creative Coding, falls du
mehr darüber wissen willst. Jetzt ist die Punktzahl linksbündig und Timer über den Eiern
sind mittig ausgerichtet. Perfekt. Ich habe den Text so angepasst, dass er gezeichnet Ich möchte sagen
, Punkte in Anführungszeichen plus diese
Punktezahl, um ihn dynamisch zu gestalten. Jetzt, wo sich die Jungtiere in
Sicherheit bringen und sich im Wald verstecken, können
wir sehen, wie unsere Punktzahl im Debug-Modus
steigt. Ich möchte auch verlorene Jungtiere sehen können
. Also, wenn dieses
zu debuggende Spiel wahr ist, kopiere
ich diese Codezeile. Im Text steht Lost plus dieser Punkt Lost
Hatchlings Variable. Eigentlich sind wir hier im
Spielunterricht, also muss ich
nur diesen Punkt-Debug sagen. Ja, ich ändere hier die vertikale
Koordinate. Und jetzt, im Debug-Modus, verfolgen
wir auch,
wie viele Schlüpflinge gefressen wurden und
wie viele Schlüpflinge mit Feinden
kollidiert sind wie viele Schlüpflinge gefressen wurden .
27. Partikeleffekte: Manchmal schlüpft die Larve schnell und
frisst zu schnell, oder manchmal
verschwindet die Larve sehr nahe am oberen Rand, während der
Feind in der Nähe ist. Es ist also möglicherweise nicht zu
100% klar,
ob es in
Sicherheit gekommen ist oder ob es gegessen wurde. Ich möchte einen
zusätzlichen visuellen Effekt hinzufügen, der uns
hilft, unser
Spiel klar und leicht lesbar zu gestalten. Ich wollte zwei Arten
von Partikeleffekten hinzufügen. Wenn sich die Larve
im Gebüsch befindet, wird ein Schwarm
Glühwürmchen, die auf den Ästen
saßen, unterbrochen und
sie fliegen in die Luft. Ein Spieler sieht diese Glühwürmchen. Sie wissen, dass Larven sicher sind. Wenn Florida gefressen wird, werde
ich versuchen
, mir eine andere, sehr deutliche Partikelbewegung auszudenken. Wenn sich also viele
Spielobjekte in derselben Gegend befinden, können
wir immer noch erkennen, was vor sich
geht, indem wir sehen welche Art von Partikeln
von dort aus fliegen. Ich werde diese
Gelegenheit auch nutzen, um
über die Unterklassifizierung in JavaScript zu sprechen , um
über die Unterklassifizierung in JavaScript Wir werden eine übergeordnete
Partikelklasse haben, die
alle Eigenschaften und Methoden enthält alle Eigenschaften und Methoden allen
Partikeltypen
gemeinsam sind. Dies ist eine sogenannte
Elternklasse, auch Oberklassenklasse genannt. Firefly erweitert diese
Partikelklasse. Dies ist eine untergeordnete Klasse, auch Unterklasse genannt. Wir werden auch eine
Klasse haben, die ich Spark nenne und die die Partikelklasse wie diese
erweitert. Wir haben eine Elternklasse
und zwei Kinderklassen. Untergeordnete Klassen erben
automatisch Eigenschaften und Methoden
von der übergeordneten Klasse, was uns
einige kalte Wiederholungen erspart. Lassen Sie uns den Code schreiben und im Laufe der Zeit ein bisschen mehr
darüber sprechen . Der übergeordnete
Partikelklassenkonstruktor
erwartet die X- und
Y-Position des Spiels, da Glühwürmchen und Funken
immer an der Position
herausfliegen , an
der die Larve verschwunden ist. Und fügen wir hier
noch eine Farbe hinzu, z. B. Vielleicht möchte ich, dass ein
Partikeltyp gold und ein anderer blau ist,
je nachdem, wo in unserer Codebasis dieser
Partikel erstellt wurde. Ich zeige dir, was ich meine. Ich wandle all diese Argumente wie gewohnt
in Klasseneigenschaften um. Ich sage, nimm die Farbe, die hier als Argument
übergeben wurde und speichere sie als skalare Eigenschaft diese Instanz
der Partikelklasse. Sie wissen inzwischen, wie das funktioniert, Radius wird ein
zufälliger Wert von 5-15 sein. Aber ich verpacke es in Math.floor,
um nur ganze Zahlen zuzulassen, also keine Dezimalpunkte. Wenn wir
viele Partikel erzeugen, werden
Sie einen großen
Leistungsunterschied feststellen wenn wir solche zufälligen
Werte verwenden, im Vergleich dazu,
den Anfangsradius
auf einen festen Wert von beispielsweise
zehn Pixeln
für alle Partikel festzulegen auf einen festen Wert von beispielsweise . Randomisierung von
Objektwerten bei der Erstellung vieler Objekte ist sehr
leistungsaufwändig. Du kannst die
Leistung deines Spiels verbessern, indem du versuchst, Math.random so
weit wie möglich zu
vermeiden. Wenn Sie das wissen,
werden Sie
viele Kopien dieses
bestimmten Objekts erstellen . Ich weiß, dass wir viele Partikel
erzeugen werden. Wir haben nur ein Spielerobjekt, da ist es
also nicht
wirklich wichtig. Es wird einmal erstellt. Aber im Laufe unseres Spiels werden
wir wahrscheinlich
Tausende von Partikeln erzeugen. Eine Möglichkeit, dies zu vermeiden, wäre eine Technik namens
Object Pooling. Sie erstellen einen Pool von
Partikelobjekten und zeichnen und
verwenden sie
nur, wenn sie benötigt werden. Wenn es um die Leistung geht, wird
das viel
besser sein, als ständig neue
zu erstellen
und sie zu löschen. Geschwindigkeit x ist ein zufälliger Wert zwischen minus drei
und plus drei. Das bedeutet, dass sich einige Partikel
auf
der horizontalen X-Achse in
positiver Richtung nach rechts bewegen, andere Partikel
bewegen sich nach links, wenn ihre Geschwindigkeit x
ein negativer Wert ist. Für die vertikale Geschwindigkeit
wird ein zufälliger Wert zwischen 0,5 und 2,5 Pixeln
pro Animationsframe verwendet. Ich möchte ein bisschen
Trigonometrie verwenden , um
die Partikel rotieren,
schweben und herumwirbeln zu lassen . Wir benötigen also zunächst einen
Winkelwert, ich setze ihn auf Null. V. Die Geschwindigkeit des Winkels
bestimmt ,
wie schnell der
Winkelwert ansteigt. Ich werde Ihnen in einer
Minute genau zeigen, wie Sie das benutzen. Mach dir keine Sorgen. Das a wird ein zufälliger Wert zwischen diesen beiden
sehr kleinen Zahlen sein. Wir werden Partikel löschen
, die sich vom Bildschirm bewegen. Anfangs habe ich gesagt, dass sie für
falsche Dramen zum Löschen
markiert sind , die auch in der übergeordneten
Partikelklasse enthalten
sein werden . Es wird also für alle
Fireflies und alle Sparks geteilt. Ich möchte sicherstellen, dass
Änderungen an einem Zustand, den wir hier
vornehmen, auf
dieses bestimmte Teilchen beschränkt bleiben. Also habe ich den
Zeichnungscode zwischen den
integrierten Canvas-Methoden
Safe und Restore umwickelt . Wir haben FillStyle zu dieser
Punktfarbe aus Zeile 3/3 gesagt. Ich rufe Begin Path an
, um eine neue Form zu beginnen. integrierte Bogenmethode
verwendet Horizontal, Mittelpunkt, Vertikal,
Mittelpunkt, Radius, Startwinkel und Endwinkel. Ich möchte, dass du
einen vollen Kreis zeichnest. Also von Null zu Math.Pi
mal zu Math.Pi mal zwei ist ein Wert im Bogenmaß und er
wird in 360 Grad umgerechnet. Es ist ein geschlossener Kreis. Wir müssen
hier Werte im Bogenmaß verwenden , wenn wir
sie an die Bogenmethode übergeben. Dann rufe ich fill auf, um
die Pfadbreitenfarbe zu füllen. Und ich werde
es auch streicheln, denn in unserem Spiel hat
alles diesen
Vektorkunststil mit schwarzen Konturen. Ich möchte, dass die Partikel
dazu passen. Außerdem enthält Firefly
nur die Aktualisierungsmethode. Gleiche gilt für Spark später, wenn wir Draw-Methode
in der Firefly-Klasse
aufrufen. Da diese Klasse Partikel
erweitert, sucht JavaScript
automatisch nach Draw-Methode und nach dem
Konstruktor für die
übergeordnete Partikelklasse. Dadurch sparen wir
uns Code-Wiederholungen. Ich muss den
Konstruktor und die Draw-Methode nicht
zweimal definieren , wenn sie für
Glühwürmchen und für Funken gemeinsam genutzt Wir können sie nur einmal für
die übergeordnete Klasse definieren werden.
Wir können sie nur einmal für
die übergeordnete Klasse definieren und das
JavaScript findet sie, sie wird vererbt. Glühwürmchen werden eine
einzigartige Bewegung haben, ich denke, sie schweben hoch
und schwanken und links und rechts, was sehr einfach zu implementieren ist. Zunächst
erhöhen wir den Winkel für
jedes Animationsbild um VA, die
Winkelgeschwindigkeit. Dann erhöhen wir die
Kollision x um die Geschwindigkeit x. Da Geschwindigkeit x
positiv oder negativ sein kann, können
sie nach dem
Zufallsprinzip nach links oder rechts
fahren . Kollision y ist minus gleich Geschwindigkeit.
Warum? Weil ich möchte, dass sie
auf
der vertikalen Y-Achse in negativer Richtung nach oben schweben . Wenn sich ein Glühwürmchen
ganz nach oben bewegt und es über dem
oberen Rand des Spielbereichs versteckt ist. Wenn es sich also um eine Kollision handelt, ist der
Y-Mittelpunkt kleiner als Null abzüglich seines Radius. Wir haben gesagt, dass es
zum Löschen markiert ist, auf true gesetzt, und wir werden Spielobjekte
entfernen nennen. Die Hauptspielklasse, die ich erstelle,
ist eine Eigenschaft namens Partikel. Es wird ein Array sein und es wird alle aktuell
aktiven Partikelobjekte
enthalten. Ich erweitere Partikel in
Spielobjekte, sodass sie sortiert,
gezeichnet und aktualisiert werden können. Unter Spielobjekte entfernen füge
ich eine weitere Codezeile hinzu, füge
ich eine weitere Codezeile um Partikelobjekte
herauszufiltern deren Eigenschaft zum Löschen markiert wie folgt auf true gesetzt
ist. Versuchen wir,
einige Partikel zu erzeugen. Ich werde sie
hier im Larvenunterricht erstellen. In diesem Codeblock, der läuft, wenn Larven
im Wald hochkommen, erhalten
wir einen Punktepunkt. Ich möchte, dass ein Schwarm Glühwürmchen
aus den Büschen fliegt. Ich nehme dieses Particle-Array im
Top-Game-Look und schiebe einen neuen
Firefly hinein. Ich erinnere mich, dass der
Partikelklassenkonstruktor für Argumente wie gewohnt
einen Verweis auf das
Hauptspielobjekt
erwartet . Also gebe ich es einfach
zusammen
mit Larva Constructor an dieses Punktspiel weiter. anfänglichen X- und
Y-Startpositionen dieses Partikels
sind die letzten X- und
Y-Positionen der Larve, die wir gerade gelöscht haben, und die Farbe
wird rot sein, z. B. nur um es zu testen. Schön, wir haben rote Partikel
mit weißen Konturen. Wenn ich mehr als einen will, habe ich einfach einen For-Loop erstellt. Nehmen wir an, ich möchte jedes Mal drei
Glühwürmchen. Ich werde die Farbe auf Gelb ändern. Mal sehen, wie das aussieht. Schöne Partikel
brauchen einen schwarzen Strich. Ich kann es innerhalb der
Zeichenmethode für jedes Partikel festlegen. Aber in diesem Projekt verwende
ich bei vielen anderen Dingen keinen Strich. Ich kann den
Strich hier in Zeile neun einfach
global auf Schwarz setzen , das wird
leistungseffizienter sein. Es wird auch
schwarze Striche für
Kollisionskreise geben , während
wir uns im Debug-Modus befinden. Aber ich
glaube nicht, dass es wirklich ein Problem ist. könnte es noch
besser aussehen.
28. Partikelbewegung: Glühwürmchen haben eine sehr einfache Aufwärtsbewegung nach links und rechts. Wir verwenden diesen Blickwinkel nicht. Wir nehmen auf der Linie 327
endlos zu. Eine einfache Möglichkeit,
etwas
hin und her wechseln zu lassen , besteht darin, jede Erhöhung des
Winkelwerts an die
Masdar-Sinus- oder Kosinusmethode weiterzuleiten . Wenn Ihr Code so ist, va, um wie viel Winkel sich für
jedes Animationsbild erhöht ,
bestimmt die Geschwindigkeit des Schwankens. Und diese Punktgeschwindigkeit x
bestimmt die Kurve, den Radius, wie weit, links und rechts, die Bewegung geht. Perfekt. Immer wenn eine
Larve erfolgreich im Wald aufsteigt, erhalten
wir einen Punktepunkt und wir erhalten Bestätigung, indem wir
diesen Glühwürmchen-Effekt sehen. Ich möchte, dass Funken
anders aussehen, sodass
man, falls Larve und Feind hinter
Hindernissen oder so
verdeckt sind , Larve und Feind hinter
Hindernissen oder so
verdeckt sind,
anhand des
Partikeleffekts,
der dort stattfindet, immer noch erkennen kann, dass die Larve gefressen wurde . Hier werde ich
eine andere Aktualisierungsmethode
mit unterschiedlichem Code definieren . Firefly und Spark sind also
beide untergeordnete Klassen
des übergeordneten Partikels
und beide erben Code im
Partikelklassenkonstruktor, und beide teilen
sich die Zeichnungsmethode, aber jede hat eine eigene Aktualisierungsmethode,
bei der wir Bewegung behandeln. Ich werde den Winkel erneut um die
Winkelgeschwindigkeit VA erhöhen, aber ich werde ihn verlangsamen. Also mal 0,5 horizontale Position
minus gleich dem gemasterten Kosinus. Wir geben diesen
ständig steigenden
Winkelwert weiter, um ihn entlang
einer Kosinuskurve abzubilden. Und wir definieren den
Radius dieser Kurve mit Geschwindigkeit x.
Kollision y minus gleich
Methodenzeichen und ich übergebe ihr den gleichen Winkelwert und der
Radius der Kurve
ist der Geschwindigkeits-y-Wert. Wir gehen wieder in die Larvenklasse. Und hier löschen wir es, wenn Florida
mit einem Feind kollidiert . Und ich wollte
einen Wirbel aus Partikeln erzeugen. Ich kopiere einfach diesen
Codeblock, mit dem wir drei Glühwürmchen erstellt haben,
und kopiere ihn hier. In diesem Fall wollen wir
drei Funken erzeugen und die
Farbe wird blau sein. Wie mache ich das? Jetzt muss ich die
Larve vor ein MA schieben, um zu
sehen, was passiert,
wenn sie gefressen wird. Toll, wir bekommen blaue Funken und eine Art
kreisförmige Bewegung. Nur zu Testzwecken werde
ich Funken erzeugen, auch wenn Larven in Sicherheit sind, sodass die Animation
öfter
automatisch abläuft , ohne dass ich ihnen hinterherjagen
muss. Ich muss es sehen, damit ich die Bewegung anpassen
kann. Was können wir mit
diesen Olivenpartikeln machen? Sie können so einfach so viele verschiedene
Bewegungsmuster ausführen. Lassen Sie uns sie z. B. schrumpfen lassen. Wenn Sie versuchen,
einen Kreis mit der
Bogenmethode zu zeichnen , dessen
Radius kleiner als Null ist, erhalten
Sie eine Fehlermeldung. Also müssen wir hier
sehr vorsichtig sein. Ich sage, wenn der Radius mehr als 0,1
ist, reduzieren
Sie den Radius weiter
um einen kleinen Wert. Dieser Wert muss unter
0,1 liegen , um sicherzustellen, dass
wir nicht unter Null kommen. Wenn Sie sich erinnern, entfernen
wir auch alte
Partikel nur, wenn sie sich über
den oberen Rand von Canvas bewegen den oberen Rand von Canvas und die wirbelnden
Partikel tun dies nie. Also brauche ich hier eine andere
Bedingung. Wenn der Radius kleiner als
0,2 ist, wird
er sicherheitshalber zum Löschen auf
true gesetzt und die Methode zum Entfernen von
Spielobjekten aufgerufen. Toll, das sieht interessant aus. Ich möchte, dass sie auf beiden Seiten irgendwie
erkundet werden. Ich habe es noch nie erwähnt,
da es für diesen Kurs nicht erforderlich ist, die
Trigonometrie vollständig
zu verstehen. Sinus und Kosinus und
bilden zusammen eine kreisförmige Bahn ab. Wenn wir ihnen die gleichen Werte geben,
schauen Sie, was passiert, wenn ich Sinus und Kosinus
vertausche. Alles, was Sie
für Animationszwecke
über Sinus und Kosinus wissen müssen
, ist, dass, wenn Sie sie bestehen, der Winkelwert
immer erhöht wird. Und wenn Sie
diese Werte den
vertikalen und horizontalen
Positionen Ihres Objekts zuordnen , erhalten
Sie eine
kreisförmige Bewegung. Der beste Weg, um
Klarheit zu gewinnen, besteht darin, mit den Werten zu spielen, die
versucht wurden, es zu
knacken, den Code anzupassen und zu
sehen, was passiert. Sie sich heute keine Gedanken darüber, die Trigonometrie vollständig zu
verstehen, sie kann für
Anfänger kompliziert sein und es dauert
eine Weile, sie zu beherrschen. Ich zeichne hier 30
Partikel, um mir
eine bessere Vorstellung von der
Bewegung zu geben , die passiert. Und wenn wir irgendwelche Randfälle
bekommen , die berücksichtigt
werden müssen. Du musst das nicht tun. empfehle ich,
pro Begriff
nur drei Partikel zu verwenden Aus
Leistungsgründen empfehle ich,
pro Begriff
nur drei Partikel zu verwenden.
Sie können sehen, dass es sich
bei den Funken wirbelnde
Explosionen handelt. Ich mag es. Die Bewegung
unterscheidet sich stark von Glühwürmchen. Ich gebe ihnen hier gelbe Farbe und werde wieder
Glühwürmchen verwenden. Mal sehen, wie das aussieht. Damit wir wissen, wie man die
JavaScript-Klasse erweitert , um Code-Wiederholungen zu
vermeiden, haben wir eine übergeordnete
Partikelklasse und eine untergeordnete Klasse,
Firefly, erstellt ,
die dem Spieler anzeigt , dass die Larve
es geschafft hat, sich im
Wald zu verstecken , indem sie einen Schwarm
wachsender Käfer, die nach oben
schweben,
gestört hat. Und wenn die Larve von einem Feind
gefressen wird, verwandelt
sie sich in einen Strudel
magischer Funken, die langsam
schrumpfen und verschwinden. Ich werde hier auf drei
Glühwürmchen zurückkommen. Und hier unten. Lass uns drei
Funken erzeugen, oder vielleicht fünf, weil sie so
schnell schrumpfen und oft von Hindernissen
und anderen Spielobjekten
verdeckt werden . Wir möchten sicherstellen, dass sie
auffallen, wenn sie auftauchen. Ich möchte
dem Spieler auch ermöglichen, die Xs in den Wald
zu bewegen , um sofort
Punkte zu erhalten.
Ich möchte, dass X sofort
schlüpft, wenn wir sie hoch genug
in den sicheren Bereich
drücken sie hoch genug
in den sicheren Bereich
drücken. Dieses Ei wird
automatisch Larven und sofort zu
Glühwürmchen. Und wir werden einen Punktestand bekommen. Ich kann das hier oben auf
Zeile 179 machen, wo wir überprüfen, ob Hodge-Timer länger als das
Hutch-Intervall ist , um sich
wieder in eine Larve zu verwandeln.
Ich möchte, dass dieser
Codeblock auch läuft, wenn das Ei in die Sicherheitszone geschoben
wurde. Wenn eine vertikale
Positionskollision y kleiner als dieses
Punktspiel
ist, ist der obere Rand gepunktet. Um es zu testen, sollte ich vielleicht das Schlupfintervall
erhöhen. Sonst
schlüpfen diese Eier zu schnell. Ich sehe hier ein Ei, nein hier, und ich schiebe
es ins Mark. Okay, jetzt los geht's. Es ist sofort
geschlüpft, obwohl der Schlupftimer nur
7 s lang war . Ich versuche es noch einmal mit diesem Ei, und ja, das funktioniert und wir bekommen
auch Punkte
dafür. Perfekt.
29. Randomisierte feindliche Skins: Ich peptidiere viele verschiedene
Feinde für dich. Sie wissen, dass wir
eine einzige Bilddatei mit mehreren Hindernistypen haben. Ich habe auch viele
verschiedene Krötengewinne für
euch vorbereitet , die in unserem Spiel die Rolle
von Feinden spielen werden. Ich hatte viel Spaß daran,
verschiedene Variationen zu machen und mir vorzustellen , welche Arten von
Spezialfähigkeiten und Spezialbewegungen
sie haben könnten. Nehmen wir an, aus
Leistungsgründen wollen
wir nur eine Reihe
statischer Bilder für Feinde verwenden. Wir werden sie später auch
animieren, falls du
das in der endgültigen
Version des Spiels möchtest Alles wird animiert. Alle Projektbilder können im Abschnitt
Ressourcen unten
heruntergeladen werden . Wie immer gebe ich dir all diese
Premium-Spielgrafiken kostenlos. Dieser Kurs ist darauf ausgelegt,
Ihnen den größtmöglichen Nutzen zu bieten. Sie können
diese Kunstressourcen gerne
für Ihre eigenen Projekte verwenden ,
wenn Sie möchten. Deshalb bringe ich diese Tabelle mit vier Frames für
Feindtypen in das Projekt ein. Die ID ist Kröten und die Quelle
steht für den Punkt PNG. Ich verstecke es wie immer mit CSS. In script.js innerhalb des
gegnerischen Klassenkonstruktors erstellen
wir zwei Hilfsvariablen, erstellen
wir zwei Hilfsvariablen die uns helfen, in
der Tabelle zu
navigieren , und schneiden für jedes
gegnerische Objekt
einen zufälligen Frame aus, Frame x. Wir navigieren horizontal durch die
Tabelle. Und es wird zunächst auf Null
gesetzt, damit MY vertikal navigiert und
auch bei Null beginnt. Ich benötige die
längste Version der Methode zum
Zeichnen von Bildern, um zu definieren welches Bild ich zeichnen möchte
, Quell-X, Y, Quellbreite und
-höhe, um anzugeben welchen rechteckigen Bereich
ich
aus dem Quellbild
und dem Ziel ausschneiden möchte . Reiseziel. Warum
Zielbreite und Zielhöhe, um zu definieren, warum wir
dieses
ausgeschnittene Bild auf der
Zielleinwand platzieren . Insgesamt neun Argumente. Bild zum Zeichnen der Schnittfläche. Und wo soll ich
das beschnittene Bild hinstellen? Lassen Sie uns damit beginnen,
nur den oberen linken Rahmen zuzuschneiden. Also schneiden wir von der
Koordinate Null Null ab, zwei Koordinaten, Sprite
mit Sprite Hide. Diese Tabelle hat
nur eine Spalte, sodass Frame x auf Null bleibt. Ich möchte einen
vertikalen Rahmen nach dem Zufallsprinzip ausschneiden. Quelle für
den Schnittbereich
wird also die Sprite-Höhe sein der Anfang des
Schnittbereichs hier verschoben wird. Wenn wir uns diesen Rahmen
geben, muss
ich das neue
Bild mit einer ID von Kröten verwenden, um ihn tatsächlich zu sehen . Um es klar zu sagen, Null mal Sprite-Höhe
ergibt uns diesen Frame. Zweifache der Sprite-Höhe
wird dieser Frame ausgeschnitten. Der Wert, den wir an eine Quelle übergeben. Methode, warum wir ein Bild zeichnen, bestimmt , wo wir
von einer Vertikalen aus mit dem Zuschneiden beginnen. Anstelle dieses
fest codierten Werts können
wir Frame verwenden. Warum? Nun, wenn ich Frame gebe, warum ein anderer Wert? Es gibt uns verschiedene
Feindtypen. Ich möchte, dass jedes feindliche Objekt
nach dem Zufallsprinzip
einem dieser Bilder zugewiesen wird
, wenn es erstellt wird. Wir haben also vier Zeilen,
Math.random mal vier. Und wenn ich es in Math.floor
frame einwickle , ist y
entweder Null oder Eins oder zwei oder drei. Ich werde auch Quelle X
durch einen Disk-Punktrahmen x mal
Sprite ersetzen durch einen Disk-Punktrahmen x mal , damit dies
etwas später relevant
wird , wenn ich
Ihnen die nächste Tabelle gebe. Lassen wir
Frame x vorerst auf Null stehen. Es wäre auch schön,
das Bild jedes Mal
nach dem Zufallsprinzip neu zuzuweisen und es dann vom Bildschirm zu
bewegen und zurückzusetzen. Also verwenden wir alle
verfügbaren Bilder. Ich randomisiere Frame Y hier einfach
so, um das zu erreichen. Um dies schnell zu testen oder gegnerische Geschwindigkeit
auf einen zufälligen Wert zu
erhöhen, 5-8 Pixel pro Animationsbild. Gegner werden zurückgesetzt
und die Bilder ändern sich bei
jedem Reset
zufällig. Perfekt. Gehen wir zurück
zu einer niedrigeren Geschwindigkeit. Ich habe x auf fünf gesetzt, da wir derzeit statische Bilder
für Gegner verwenden . zu
zeichnen ist von der Leistung her sehr billig
, vielleicht könnte ich
die Anzahl der
Gegner auch auf fünf erhöhen . Das
sieht langsam richtig gut aus.
30. Gewinnen und verlieren Zustand: Ich wollte
eine Gewinn- und
Verlustmeldung in
der Hauptklasse des Spiels anzeigen .
Ich habe eine Eigenschaft erstellt, die ich z. B. Gewinnpunktzahl
nenne. Zu Testzwecken
habe ich es auf fünf gesetzt. Wir werden hier unten die Gewinner- und
Verliererbotschaften ziehen. Wenn das Ergebnis mehr oder
gleich dem Gewinnergebnis ist, packe ich es in einen Safe
und stelle es wieder her, um
einige
Ziehungseinstellungen einzuschränken . Wir verwenden jetzt nur noch zwei, die die Nachricht
gewinnen oder verlieren. Ich möchte eine
halbtransparente Ebene zeichnen um anzuzeigen, dass das Spiel vorbei ist, und um die Botschaft vom
Hintergrund
kontrastreicher zu machen . Also sagte ich FillStyle,
um Nullen,
Nullen, 0,0, 0,5 Opazität zu blockieren . Dann zeichnen wir dieses schwarze halbtransparente
Rechteck über die gesamte Leinwand
von der Koordinate 00 bis zur Breite und
Höhe des Spielbereichs. Lassen Sie uns diesen Code ausführen, um ihn zu testen. Wenn wir drei Punkte erreichen, sollten
wir die niederländische
halbtransparente Schicht bekommen. Ja. Nachdem das Rechteck gezeichnet wurde, ändere
ich fillStyle
in Weiß, um sicherzustellen, dass der Text einen Kontrast
zum dunklen Hintergrund bildet. Ich habe die Textausrichtung auf die Mitte gesetzt. Wir werden eine
Hauptnachricht in großen Buchstaben und eine Nebennachricht
in kleinerer Schrift haben. Ich werde sie einfach
so als Hauptvariablen definieren. Und der Wert, den
diese Nachrichten
erhalten , hängt davon ab, wie
gut wir gespielt haben. In jedem Fall
wird diese Meldung erst angezeigt, Punktzahl höher oder gleich
der Gewinnpunktzahl ist. Aber nehmen wir an, wenn
wir gut gespielt
haben und nur fünf
oder weniger Jungtiere verloren
haben, erhalten wir eine Gewinnnachricht. Wenn wir mehr als fünf verlieren, erhalten
wir eine Verlustmeldung. Das Ziel des Spiels ist es, Eier, Brutglieder
und Gegner durch die Gegend
zu
schieben, um sicherzustellen, dass wir so viele wie möglich
schützen. Wenn wir also gut spielen, wird
Message One sagen, lasst uns ein bisschen mit Worten spielen. Sie können hier alles schreiben, was Sie wollen als Gewinn- und
Verlustnachricht. Wenn wir also die Hauptbotschaft
in großen Buchstaben
auf dem Bildschirm gewinnen , sagen
wir Bullauge und
einige Ausrufezeichen. Die sekundäre, kleinere
Botschaft lautet:
Ihr erschießt die Tyrannen. Wenn wir verlieren, lautet die
Hauptbotschaft, Borlaugs sekundäre, kleinere
Botschaft lautet, dass Sie verloren haben. Außerdem werden wir dynamischen Variablenwert anzeigen, um zu zeigen wie viele Jungtiere gefressen wurden. Und das Koma der Jungtiere. Sei kein Schwächling. In diesem Physikspiel geht es darum
, Dinge zu verschieben. Wir müssen lernen, besser zu pushen. Ich verwende eine gute alte
Zeichenkettenverkettung um diese
dynamische Nachricht zu erstellen.
Noch besser wäre es, hier Vorlagenliterale zu verwenden
, wenn Sie mit der
modernen JavaScript-Syntax vertraut sind. Jetzt wollen wir diese Botschaften tatsächlich
zeichnen. Die große Nachricht
wird z. B.
130 Pixel groß sein . Helvetika. Die Filttext-Methode
verwendet den Text, den wir für die erste Nachricht
zeichnen möchten, und die X
- und Y-Koordinaten befinden sich horizontal
und vertikal in
der Mitte der
Leinwand , so wie hier. Die zweite Nachricht wird für die Pixel
kleiner sein. Helvetika. Filttext wird auch mitten im Thema Cannabis
die zweite
Botschaft zeichnen. Noch ein
FiltText-Tor, das wir mit einem Leerzeichen für die
Endergebnisse angeben Leerzeichen für die
Endergebnisse ,
plus Punkt, um den Satz zu
beenden. Und in einem anderen Satz heißt es, drücke R, um erneut gegen die Köpfe zu stoßen. Ich möchte Ihnen zeigen,
wie Sie
eine sehr einfache
Neustartfunktion implementieren . Immer wenn wir den
Buchstaben R auf der Tastatur drücken, zeichne
ich ihn auch
in
der Mitte , also vertikal
und horizontal. Jetzt muss ich
diese Nachrichten
mit Abstand damit sie nicht
übereinander gezeichnet werden. Ich passe die
vertikale Position der Nachricht um -20 Pixel an und
bewege sie
auf
der vertikalen Y-Achse in negativer Richtung nach oben . Nachricht zwei wird plus
30 sein, wenn Sie es nach unten verschieben. Nachricht drei wird plus 80 sein. Mal sehen, wie das aussieht. Ja, dieser Raum und
es ist viel besser. Wir haben unsere Erfolgsbotschaft. Wenn die Punktzahl mehr ist
als die Gewinnpunktzahl, haben wir gesagt, dass das Spiel vorbei ist. Im Hauptspielobjekt definiere
ich die Game-Over-Eigenschaft und setze sie zunächst auf False. Das Einfachste, was wir hier tun
könnten, ist die
Animation einzufrieren , wenn Game Over
passiert. Ich kann das z.B. hier
unten machen , ich sage, nur
den nächsten Animationsframe servieren. Wenn Gameover falsch ist und GameOver auf True gesetzt wird, friert
das Spiel ein. Ich sagte, das Gewinnergebnis zu
eins, nur zum Testen. Und es wird eine
Gewinn- oder Verlustmeldung angezeigt. Und es wird so einfrieren. Ich gehe zu Zeile 519
und lösche diesen Teil. Ich möchte, dass das Spiel
weiterläuft, aber wir werden dafür sorgen, dass kein neues X mehr erscheint und ich werde
verhindern, dass Gegner zurückgesetzt werden. Und so schweben sie einfach vom
Bildschirm und bleiben dort. Wann immer das Spiel vorbei ist, die Objekte, die sich
bereits im Spielbereich befinden, beenden
wir
die Objekte, die sich
bereits im Spielbereich befinden, einfach die
Aktion, die sie gerade ausführen, aber es erscheinen keine neuen Objekte
mehr im Spiel, wir beenden das Spiel einfach hinter der Gewinn
- oder Verlustmeldung, aber das neue X
erscheint nicht mehr und die Gegner
halten an, kommen rein. Der Spieler wird weiterhin
interaktiv sein und wir können ihn
immer noch in
der leeren Spielwelt bewegen. Wie setzen wir
das um? Es ist ganz einfach. Nehmen wir zunächst an, es erscheint
eine
Gewinn- oder Verlustmeldung und wir haben immer noch einige Klassen, in denen Eier
schlüpfen Wir werden sicherstellen, dass wir nur
Punkte erhalten , wenn
das Spiel vorbei falsch ist. Wenn das Spiel vorbei ist, erscheinen immer noch
Jungtiere
aus den verbleibenden X, aber was auch immer
passiert, hat keinen Einfluss mehr auf unsere Punktezahl.
In der feindlichen Klasse. Ich möchte nur, dass die Gegner zurückgesetzt wenn GameOver so falsch ist, wenn GameOver passiert,
und dann wird ihre
Bewegung durch das Spielfeld
beendet, aber sie werden nicht mehr nach rechts
zurückgesetzt. werden also keine neuen Feinde mehr kommen. Hier unten
wollen wir dem Spiel nur dann ein neues X
hinzufügen, wenn
Game-Over falsch ist, Gewinn- oder Verlustmeldung
erscheint, das bestehende x, wir werden trotzdem mit dem Schraffieren fertig sein, aber das neue X wird nicht mehr erscheinen. Lass es uns testen. Ich habe eine gewinnbringende Nachricht. Ich habe noch einige Eier übrig, aber diese Schlüpflinge erhöhen unsere Punktzahl
nicht mehr. Wir haben noch einige Gegner übrig, aber sie entfernen sich langsam vom Bildschirm und
kommen nicht wieder. Der Spieler bleibt interaktiv und wir können ihn immer noch bewegen. Perfekt. Ich wollte
die Locker-Nachricht testen, anstatt die
Jungtiere
absichtlich vor die
Feinde zu schieben , um gefressen zu werden.
Ich
setze die verschollenen Schlüpflinge einfach manuell, die zehn hier auf Zeile 380. Ja, wir bekommen, dass wir die Botschaft verlieren. Das ist großartig. Ich sagte plus Touch
Links zurück auf Null. Das Hinzufügen einer benutzerdefinierten Schrift ist einfach. Sie können eine beliebige
Schriftart wählen. Ich gehe zu Google Fonts. Sie haben dort Tausende von
Schriftarten zur Verfügung. Ich möchte diese von Comics
inspirierte Schrift namens Bankers verwenden . Ich klicke hier, um die Schriftart auszuwählen, und ich klicke hier, wodurch
ein Code generiert wird, den ich verwenden kann , um diese
Schrift in mein Projekt aufzunehmen. Ich kopiere diese drei Link-Tags
und füge sie hier in den Kopfstock
meiner Index-HTML-Datei ein, verzögere vor meinen
benutzerdefinierten Stylesheets, sodass die Schrift von dort aus
verfügbar ist. Dann kopiere ich die CSS-Regel. Ich benutze es hier. Im Fall dieses Projekts kann
ich diese
Schriftfamilie einfach auf alle Elemente anwenden. Vielleicht möchten Sie
spezifischer sein und nur auf das
Canvas-Element anwenden, z. B. jetzt ist die Schrift in unserem Projekt
verfügbar. Also hier oben in Zeile zehn sagte
ich Canvas Fond to
40 Pixel Bankers. Dies wirkt sich auf den
Text aus, in dem
Punkte und Timer
über Bruteiern angezeigt werden. Wir wollen hier und hier auch
Banker setzen, wenn wir das
für Game-Over-Nachrichten verwenden wollen, lasst uns schnell, wenn das Spiel ja ist. Das sieht besser aus, oder? Weil wir Safe and Restore verwenden. Ich höre, dass alles, was ich in
diesem Bereich mache, auf
Game-Over-Nachricht
beschränkt bleibt , ist Canvas. Schatten sind
leistungsintensiv und einige Browser kommen
damit nicht gut zurecht, aber wenn ich sie auf
diesen Text beschränke, wird es
uns gut gehen. Lass es uns versuchen. Wir müssen den
horizontalen Abstand
zwischen Form und Schatten definieren . Es kann ein positiver oder ein
negativer Wert sein, je nachdem ob der Schatten links oder rechts sein
soll. Schattenversatz y
kann auch positiv oder negativ sein. Es bestimmt die
vertikale Position
des Schattens im Verhältnis
zu seiner Elternform. Die Schattenfarbe wird schwarz sein. Wir können auch
Schattenunschärfe definieren, wenn wir wollen. Das ist optional,
also belasse ich es auf der Standardeinstellung Null, was edler
bedeutet. Denken Sie daran, dass
Schatten nur dann gezeichnet werden wenn die Schattenfarbe auf
einen nicht transparenten Wert gesetzt ist. Und wenn mindestens eine der
Eigenschaften Shadow Blur,
Shadow Offset X oder Shadow Offset y auf einen Wert ungleich Null gesetzt ist. Schatten geben dem
Text ein schönes Highlight und heben ihn etwas mehr
vom Hintergrund ab. Ich sagte, ich habe wieder Jungtiere
vor zehn verloren, nur um die lockere Botschaft zu sehen. Wie es mit
neuer Schrift und Schatten aussieht. Toll, das sieht toll aus. Ich sagte, die
Jungtiere wurden mit Zahnseide auf Null gebracht.
31. Spiel neu starten: Wir haben
hier diese Meldung, die besagt, dass du R
drückst, um erneut gegeneinander anzutreten,
was bedeutet, dass du R drückst,
um das Spiel neu zu starten. Was ich Ihnen gleich zeigen werde,
ist die einfachste Art, wie Sie die
Funktion zum Neustarten eines Spiels in der Spielerklasse
implementieren können . Ich erstelle eine benutzerdefinierte
Methode, die ich zB
restart nenne . Darin möchte ich die Spielereigenschaften auf das setzen, was sie sind, wenn ein neues Spiel beginnt. Schauen wir uns kurz an,
was wir hier haben. Ich möchte, dass der Spieler
zur Ausgangsposition wechselt. Wir werden Kollision
x zurücksetzen und Kollision warum? Wir werden auch sicherstellen, dass sich das Sprite-Bild zusammen
mit dem Kollisionskreis bewegt. Also benötige ich diese
beiden Codezeilen. Methode zum Neustart des Spiels
verschiebt also Kollisionsbereich des
Spielers und das Spieler-Spritesheet
zurück in die Ausgangsposition. Wir gehen hier runter
zur Hauptspielklasse und hier im Key
Down Event Listener, ich sage, wenn die gedrückte Taste
unsere Methode
zum Neustarten der Spielklasse wie diese ist . Ich definiere diese Methode hier unten. Und hier werden wir
alle Eigenschaften auf
ihren Anfangszustand setzen . Das wird
von Projekt zu Projekt unterschiedlich sein. Wir haben diese Codebasis gerade geschrieben damit wir damit
vertraut sind und verstehen, was geändert werden muss
, um das Spiel wieder in seinen ursprünglichen Zustand
zu versetzen. Zuerst rufen wir die
Restart-Methode auf, die
wir gerade für
die Spielerklasse definiert haben. Lass es uns testen. Ich bewege den Spieler und wenn ich den Buchstaben
R auf der Tastatur drücke, bewegt sich der
Spieler zurück in seine Ausgangsposition.
So weit so gut. Wir können eine ähnliche
Technik verwenden, um
dem Spieler die Möglichkeit
zu geben , die Zeit zurückzuspulen. ZB setzen wir einfach Zustand und Position auf x und n ist n Schlüpflinge
auf das,
was sie vor 5 s waren . Das könnte uns ein
interessantes Gameplay bescheren. Wie dem auch sei, wir wollten das Spiel
neu starten. Also hier oben im Konstruktor überprüfe
ich, was geändert werden muss. Ich weiß, dass ich
den Inhalt meiner Arrays zurücksetzen muss. Ich nehme Hindernisse, X, Feinde, Jungtiere
und Partikel. Und ich habe das alles
auf leere Arrays wie dieses zurückgeführt. Ich teste es. Okay, also wenn ich R drücke, passiert das
jetzt und ich
muss die Init-Methode
erneut ausführen , um Feinde und
Hindernisse neu zu erstellen , seit wir sie gelöscht haben. Ja, jetzt, wenn ich neu starte, werden
Hindernisse an
zufälligen Positionen regeneriert und wir generieren
auch neue Feinde. Ich kann sehen, dass ich auch die aktuelle
Mausposition
zurücksetzen muss . Ich nehme diese
Punktmaus und setze sie tatsächlich
auf diese
Startwerte, also kann ich das einfach kopieren. Ich habe auch den Punktestand auf
Null zurückgesetzt und auch Jungtiere verloren. Ich muss das Spiel
auch auf False setzen, um
sicherzustellen, dass X weiterhin erscheint und die
Gegner immer wieder zurückgesetzt werden. Lass es uns testen. Ich spiele. Ich gewinne das Spiel. Ich drücke auf die Arterienseite. Ich spiele. Wenn ich die Größe ändere, spiele
ich, ich gewinne, es scheint
zu funktionieren. In Ordnung. Ich sagte, das
Gewinnspiel ist zu 30. Okay, ich verbringe einige Zeit damit,
das Gameplay zu testen , und es gibt noch
ein paar
Dinge, die wir anpassen können. Wie Sie wissen, können wir den Debug-Modus aktivieren und deaktivieren, indem wir den
Buchstaben D drücken . Ich bin hier in
unserer benutzerdefinierten Larva-Klasse. Ich möchte, dass unsere
Larven-Hatch-Links mit der Methode x in der
Aktualisierungsmethode der
Larvenklasse
interagieren . Ich habe den
Spread-Operator verwendet, um x in das Array für
Kollisionsobjekte zu erweitern. Dadurch wird der X solide, unmögliche Hindernisse
und die Jungtiere müssen um sie herumkriechen. Dadurch wird das
Spiel etwas schwieriger und der Spieler
muss sich mehr
engagieren, um das X
aus dem Weg zu räumen und
sicherzustellen , dass die Jungtiere so schnell wie möglich
einen sicheren Bereich erreichen. Manchmal
können Schlüpflinge sogar zwischen mehreren
Eiern und Hindernissen
stecken bleiben. Und wenn wir uns nicht rechtzeitig befreien, werden
sie von Feinden gefressen. Alternativ kann ich X von hier
entfernen. Ich gehe zur Methode Eierkurs
und Insight Update über. In einer Klasse werde ich
Schlüpflinge zu einem Array von
Kollisionsobjekten erweitern . Dies wiederum
wird das Spiel einfacher machen, da
die Jungtiere nicht nur das X aus dem Weg
schieben können. Manchmal platzieren sie das X auch näher
an der Sicherheitszone
vor sich. Sie können selbst wählen, was Sie hier tun
möchten,
je nachdem, ob Sie
möchten, dass Ihr Spiel zu diesem
Zeitpunkt
einfach oder anspruchsvoller Sie kennen das
Codebasiert gut genug. Wenn Sie möchten, können Sie sich also
etwas Freiheit nehmen und das
Gameplay nach Belieben anpassen. Ich möchte auch, dass die
Kollisionskreise bei Jungtieren besser zum Spritesheet
passen.
-40 hier wird gut funktionieren, ich denke, um den Boden der
Kollisionskreise besser
an
der Unterseite der Körper der Jungtiere auszurichten Kollisionskreise besser
an
der Unterseite . Ich möchte, dass diese
Kollisionsbereiche so
genau wie möglich mit
dem Kunstwerk übereinstimmen . Wir befinden uns jetzt im Debug-Modus, aber denken Sie daran, dass
das Spiel mit versteckten
Kollisionskreisen gespielt werden soll . Wenn der Debug-Modus ausgeschaltet ist. Du kannst
dieselbe Technik verwenden, um Kollisionskreise auf
Gegner
besser auszurichten , wobei der kleine Schatten auf dem Boden unter jedem Feind liegt. Ich werde das in
einer Minute machen, weil wir uns in
der nächsten Lektion darauf
konzentrieren werden, neue Feindtypen hinzuzufügen. Ich werde dir auch Tabellen mit allen
Charakteren geben und wir werden diesem Projekt viele
Animationen hinzufügen. Ich hatte so viel Spaß daran,
diese Kreaturen zu entwerfen und
sie in Bewegung zu bringen. Ich hoffe es gefällt dir. Mir ist ein kleiner
Vorteil aufgefallen,
als wir eine
Game-Over-Nachricht bekommen und übrig gebliebene Gegner ein paar
übrig gebliebene Jungtiere fressen. Variablen für verlorene Schlüpflinge
nehmen immer noch zu. Wir müssen sicherstellen, dass der Wert für
verlorene Jungtiere gleich
bleibt, nachdem die
Game-Over-Meldung angezeigt wird. Also werde ich diesen
Codeblock nur ausführen, wenn Game Over falsch ist. Dadurch werden
die Jungtiere auch unter dem
Spielbildschirm
verwundbar. Wenn Sie das nicht möchten, können
Sie diese
if-Anweisung nur auf
eine Codezeile anwenden , die die Anzahl der verlorenen Jungtiere
erhöht. Wenn Game Over falsch ist, verlorene Jungtiere plus, plus.
32. Extending: Okay, mehrere Feindtypen. Ich möchte zwei
Kinderklassen erstellen, die sich erweitern. Feindliche Elternklasse. Die abgebildete Haut wird
diese schleimige grüne sein, Bark Scan wird der
hohle Holzrest
mit Geweih,
Stacheln und Blättern sein . Wir machen ein magisches
Waldthema. Ich hatte also Spaß mit dem
Kreaturendesign in diesem Fall. Also erweitern wir auch hier die
JavaScript-Klasse. Wir tun das, um
kalte Wiederholungen zu vermeiden. Alle Eigenschaften und
Methoden, die von
allen Feindtypen gemeinsam genutzt werden, gehören
zur übergeordneten endemischen Klasse. Nur die Eigenschaften
, die für
einzelne Feindtypen spezifisch sind ,
werden den untergeordneten Klassen zugewiesen. Sie können all
diese Premium- oder Assets
im folgenden
Projektbereich herunterladen . Wir werden damit beginnen,
acht verschiedene Rindenscans hinzuzufügen. Was hältst du zu sehr von
meinen Designs? Ich wollte, dass dieser aus Holz ist und innen hohl ist, aber Licht
aus Augen und Mund kommt, bisschen wie ein Halloween-Kürbis. Ich verstecke das Bild mit CSS. Ich habe auch das
Krötenbild ersetzt. Wir hatten zuerst vier Charaktere
drauf. Jetzt gibt es acht
verschiedene Versionen. Jede Menge Worte, Schleim,
Augen und Tentakel. Hier oben bei der feindlichen Hauptklasse sehe
ich, dass der Konstruktor
das Spiel als Argument erwartet. Ich möchte den Konstruktor
auf der übergeordneten Feindklasse ausführen und ihm
aus der TO-Skin-Klasse etwas hinzufügen. Hauptsächlich die Eigenschaften
, die
nur für den Feindtyp der Krötenhaut spezifisch sind. Im Konstruktor der untergeordneten
Klasse erwarten
wir also das
Spiel als Argument. Und dann müssen wir zuerst den
Konstruktor für die
übergeordnete Feindklasse ausführen , auch als Superklasse bezeichnet wird. Wir nennen Superclass Constructor. Und wir geben die Referenz, das Hauptspielobjekt,
weiter, weil wir wissen, was
hier oben auf Zeile 264 erwartet wird. All diese Eigenschaften
gelten nur für NMAI, da
das Bild anders sein wird. Größe der Sprites sowie Breite
und Höhe
hängen ebenfalls von dieser Sprite-Größe ab. Und Kollision x verwendet
Breite und ihre Formel. Also habe ich all diese herausgeschnitten und sie auf der
Grundlage der
Kinderklasse hier erstellt. Diese Eigenschaften haben also für
jede untergeordnete Klasse
einen anderen Wert. Sie werden nicht geteilt. Ich werde diesen Codeblock kopieren
und auf Rindenhaut legen. Hier müssen wir die Werte
anpassen. Sprite-Breite beträgt hier 183 Pixel. Sprite-Höhe beträgt 280, Breite und Höhe
eines einzelnen Frames. Dieser Feind wird größer sein. Dieses Punktbild
wird die ID von Barack sein. Haben wir ihm ein Index-HTML gegeben? Das sind also die Eigenschaften, die allen gegnerischen Klassen
gemeinsam sind. Sie werden auch diese
Schublade und diese Aktualisierungsmethode teilen. Eigenschaften der untergeordneten Klassen werden für
jeden Feindtyp einzigartig sein, wir haben zwei Feindtypen. Ich möchte nach dem Zufallsprinzip das eine oder andere
hinzufügen. Ich kümmere mich um das Hinzufügen von
Feinden
hier unten in der Add-Enema-Methode
zur Domain-Spielklasse. Hier kann ich sagen, wenn
Math.Random kleiner als 0,5 ist, Math.Random alleine
so aufgerufen wird
Math.Random alleine
so aufgerufen,
eine Zufallszahl zurück , die größer oder gleich
Null und kleiner als eins ist. Wir können also sagen, dass
es weniger als
0,5 und rund 50
Prozent der Fälle sein werden . Liegt der Wert unter 0,5, werden
wir die Haut
unserer Gegner mit neuer Kröte aufnehmen. Andernfalls werden
wir in den anderen 50
Prozent der Fälle auf neues Hirschleder setzen. Nett. Jetzt fügen
wir nach dem Zufallsprinzip beide Feindtypen hinzu. Frame x ist auf Null gesetzt, sodass wir nur die
Frames aus der ersten Spalte erhalten. Ich möchte, dass es Null oder Eins ist. Also Math.random mal zwei so
in Math.floor verpackt. Jetzt bekommen wir alle Frames. Ich werde euch auch zeigen, wie man diese Tabellen
animiert, aber das wird die Leistung des
Spiels verteuern, da die Charaktergrafiken, die
ich für
dieses Projekt verwendet habe, sehr detailliert sind und die Bilder ziemlich groß
sind. Es gibt
Optimierungstechniken, die für
Sprite-Animationen verwendet werden
können, aber das würde den Rahmen
dieses anfängerfreundlichen Kurses sprengen . Wir werden bald etwas mehr
darüber sprechen. Wenn Gegner zurückgesetzt werden, werden wir randomisiert und Frame
y, aber nicht Frame x. Kopieren wir dazu Zeile 270
und fügen sie hier in
diesen if-Anweisungsblock ein. Jetzt sind wir im Bild vollständig randomisiert , wenn
die Gegner ihre Position
zurücksetzen.
Ich kann diese Zeilen, die Frame
X und Frame Y randomisiert haben, in die
gemeinsame Aktualisierungsmethode einfügen. Weil meine beiden
Feindtypen die gleiche Anzahl an
Frames für Zeilen und zwei Spalten haben . Wenn jedes gegnerische Spritesheet eine andere
Anzahl von Frames
hätte, müsste
ich
diese Aktualisierungsmethode erweitern. In jeder NMS-Unterklasse fügen
wir Objekte
wie Partikel,
Schraffuren und x hinzu und
löschen sie. Es ist immer gut, unsere Objekte zu überprüfen , um sicherzustellen, dass
die alten Objekte korrekt entfernt wurden und wir nicht ein endlos
wachsendes Array haben. Ich könnte es in
meiner Aktualisierungsmethode auf der Konsole protokollieren, aber ein solches
Konsolenprotokoll
60 Mal pro Sekunde auszuführen, ist sehr
leistungsaufwändig. Wir könnten einfach
R-Objekte auf Anfrage auf der Konsole protokollieren, wann immer wir eine Taste in unserem
Key Down Event Listener
drücken.
Ich sage, wenn wir
C auf der Tastatur drücken, nur dann protokolliert die Konsole
diese Punktspielobjekte. Jetzt kann ich das Spiel spielen und gelegentlich drücke ich
C, um zu überprüfen, ob das
Spielobjekt-Array nur
die richtigen Objekte enthält , die gerade im Spiel
aktiv
sind. Wenn Sie z. B. feststellen
, dass es endlos zunimmt und
immer mehr Partikel enthält. Wir wissen, dass wir
die alten
Partikelobjekte nicht korrekt entfernen . In diesem Fall scheint alles gut zu sein.
33. Einfacher Vollbildmodus: In unserem Spiel können
wir also den Buchstaben
D drücken, um den Debug-Modus zu aktivieren und zu
deaktivieren, den Buchstaben
R, um das Spiel neu zu starten,
C, um ein benutzerdefiniertes Konsolenprotokoll auszuführen. Und ich zeige
Ihnen auch, wie Sie einen sehr einfachen
Vollbildmodus ein- und ausschalten können, indem Buchstaben F
drücken. Wir
besprechen die Methode, z. B. Vollbild
umschalten. Wir werden es hier unten in
der Hauptspielklasse definieren. Javascript hat eine native
Vollbildfunktion. Diese integrierte API enthält eine Reihe von Methoden
, mit denen wir ein bestimmtes Element und
alle seine Nachkommen im
Vollbildmodus
darstellen können, wobei alle Elemente der
Browser-Benutzeroberfläche
und andere Anwendungen
vom Bildschirm entfernt werden. Wenn ich das Document
Dot-Vollbildelement wie dieses aufrufe, wird das Element zurückgegeben gerade
im Vollbildmodus dargestellt wird. Wenn es Null zurückgibt, bedeutet dies, dass der
Vollbildmodus derzeit nicht verwendet wird. Also hier sage ich, wenn wir auf dieser Seite gerade nicht im
Vollbildmodus verwendet werden , möchte
ich in den
Vollbildmodus wechseln. Methode „Vollbild anfordern“ zeigt das Element, für das es aufgerufen wurde, im Vollbildmodus
an. In diesem Fall wollte ich die gesamte Webseite
anzeigen. Also Dokument, das das DOD-Dokumentelement
der Webseite
darstellt, das das
Stammelement des Dokuments darstellt, in diesem Fall das HTML-Tag. Ich möchte, dass
die gesamte Webseite ab
ihrem Root-Elementcode im Vollbildmodus angezeigt wird,
um den Vollbildmodus zu verlassen. Das ist einfach, also sagen wir
einfach anders, wenn Dokument Punkt den Vollbildmodus beendet, Ausführen, Dokument, das den
Vollbildmodus beendet. Es ist ein bisschen komisch,
aber es wird funktionieren. Währenddessen wird
die gesamte Webseite umgedreht. Fullscreen Canvas
nimmt nicht die gesamte Bildschirmbreite ein. Wir bewegen den
Spieler mit der Maus, also müssen wir vorsichtig sein,
wie wir die Größe von Canvas in diesem Projekt ändern, da die
Mauskoordinaten eine bestimmte Weise berechnet
werden. Wenn ich Canvas mit CSS eine
dynamische Breite
gebe, werden
uns falsche Koordinaten angezeigt. Im Google Chrome-Browser. Wenn ich auf diese Weise in den Vollbildmodus gehe und hineinzoome, um das
Spiel im Vollbildmodus abzudecken, werden die Mauskoordinaten
immer noch
korrekt berechnet und der Gain
ist spielbar. Sie können es
selbst testen, indem Sie F drücken um den Vollbildmodus aufzurufen,
und dann die Strg-Taste
gedrückt halten und auf die Plus- oder
Minustasten tippen , um die Ansicht
zu vergrößern und zu verkleinern. Auf dem Mac verwenden wir stattdessen die
Befehlstaste. Wir sind dabei,
die Tabellen zu animieren. Diese Bilder sind
groß und es wird die
Computerleistung
etwas belasten , wenn wir anfangen,
diese Bilder bei jedem aktiven
animierten Objekt sehr
schnell zu durchsuchen . Vielleicht möchten
Sie
die Codebasis so speichern, wie sie
gerade ist , und in einer Kopie
dieses Ordners
fortfahren , damit Sie statische und
vollständig animierte Codebasen behalten
und sie
Seite an Seite vergleichen
können vollständig animierte Codebasen behalten
und sie
Seite an Seite vergleichen in Bezug auf
Leistung auf Ihrer Maschine. Es liegt an dir. Ich werde auch den vollständigen
Quellcode aus dieser Phase
des Projekts im Abschnitt
Ressourcen unten zum
Download zur Verfügung im Abschnitt
Ressourcen unten zum
Download Der Ordner mit dem vollständigen
Quellcode aus dieser Phase heißt
Quellcodeversion fünf.
34. Spieler sprite Blatt volle Animation: Zeit, das
Spieler-Spritesheet vollständig zu animieren. Wir verwenden bereits
das Spritesheet, schneiden
aber nur
das erste Bild jeder Reihe zu, um den Spieler
in verschiedene Richtungen zu lenken. Wir haben hier Hilfsvariablen, bei denen ein Frame x in
derselben Zeile von links nach rechts über und über eine Schleife in
dieser bestimmten Animation wechselt. Und Frame y bestimmt
, welche Zeile wir animieren. Beim
Spieler-Sprite Sheet verschiedenen Reihen
derselbe
Spielercharakter in verschiedene Richtungen. Wir verwenden die Zeichenmethode, um diese Tabelle auf Canvas zu zeichnen. Wir verwenden die
längste Version mit einem Bild mit neun Argumenten, das
wir zeichnen möchten. Dann definieren wir den Schnittbereich mit den folgenden vier Argumenten. Quelle x, y,
Quellbreite und Quellhöhe. Und die letzten vier Argumente und Definition, wo am
Ziel-Cannabis, platzieren
wir das ausgeschnittene Bild auf Ziel x, Ziel. Warum Zielbreite
und Zielhöhe? Ich habe das
in diesem Kurs ein paar Mal erklärt , weil
es wirklich wichtig , zu verstehen, ob Sie das Draw-Bild für
eine Sprite-Animation
verwenden möchten . Wir haben bereits eine Funktion
, die Frame Y in
eine andere Zeile tauscht , je nachdem, in Richtung der Spieler schauen soll. Alles, was ich jetzt tun muss, um
vollständig animiert zu sein, ist Frame X
immer wieder zwischen Frame Null und maximalem Frame zu wechseln. Wir werden die Sprite-Animation hier
unten innerhalb der Aktualisierungsmethode behandeln . Und wir werden diesen Code auch
für andere Objekte wiederverwenden. Wir benötigen eine weitere
Hilfseigenschaft namens Max Frame. Spritesheet hat
58 Bilder pro Zeile. Es ist ein riesiges
Tabellenbild. Wir werden es durchfliegen und verschiedene
Bilder
ausschneiden, um
eine Illusion von Bewegung
und Animation zu erzeugen . Lass es mich dir zeigen. Es ist einfach. Wenn Frame x kleiner als der maximale Frame
ist, möchte
ich, dass Frame x um
eins erhöht wird , wenn die Aktualisierungsmethode immer wieder
ausgeführt wird. Dadurch wird die Animationszeile
von links nach rechts durchquert. Wenn das Endbild erreicht ist, ist
x nicht mehr kleiner
als der maximale Frame. Sonst wird die Anweisung ausgeführt. Frame x wird wieder auf
Nullen zurückgesetzt , sodass der Zyklus erneut gestartet
werden kann. Das war's. Wir
animieren den Spieler. Ich versuche herumzulaufen, den Spieler in alle
möglichen Richtungen
zu
drehen, den Spieler in alle
möglichen Richtungen
zu
drehen um zu sehen, ob alles in Ordnung ist. Jetzt ist unser Spieler
richtig am Leben. Wenn du
deine Tabelle vorbereitest und du Spielgrafiken richtig machst, so wie ich sie für dich vorbereitet habe. Es mit
Code zu animieren ist sehr einfach. Alles was Sie brauchen ist dieser
einfache Codeblock.
35. Larva Sprite Blatt volle Animation: Ich kopiere diesen Codeblock. Ich werde es im Larvenunterricht wiederverwenden. Ich gehe zum Larvenunterricht. Hier. Wir benötigen auch
Max Frame Helper Property. In diesem Fall beträgt der maximale Frame 38. Larva-Tabelle hat
38 Bilder pro Zeile. Wie gewohnt können Sie
alle Tabellen
im Bereich Ressourcen herunterladen . Ich lege es in meinen Projektordner und bringe es hier in
das Projekt. Die ID wird Larve
Underscores Sprite sein und die
Quelle wird dasselbe
Larva Sprite Dot PNG sein. In script.js verweise ich diese
Punktbildeigenschaft auf diese neue ID. Es hat 38 Bilder pro Reihe. Und wieder möchte ich zwischen Frame Zero
und Max Frame wechseln. Ich habe die
Sprite-Animation namens
Blog von der Aktualisierungsmethode
auf die Spielerklasse kopiert Blog von der Aktualisierungsmethode
auf die Spielerklasse und füge sie hier ein. Es ist sehr einfach, sodass Sie
keine Änderungen vornehmen müssen. Wenn Frame x kleiner
als der maximale Frame ist, erhöhen
Sie Frame x weiter um eins. Andernfalls setzen Sie Frame x wieder auf
Null zurück , damit der Zyklus erneut gestartet werden kann. Alle Tabellen sind so
eingerichtet, dass das letzte Bild
und das erste Bild in einer kontinuierlichen Animationsschleife miteinander verbunden sind. Sie sie also immer wieder
auf diese Weise durchspielen entsteht eine nahtlose
Animationssequenz. Jetzt können Sie sehen, wie unsere Jungtiere mit ihrem Antonio kriechen, und ab
wackeln, und
ihre matschigen Körper bewegen sich während sie in die Sicherheit eines
Pilzwaldes kriechen. Perfekt.
36. Feinde sprite Blatt volle Animation: Ich habe auch
Animationstabellen für die Feinde vorbereitet. Ich gebe ihm eine ID von Bark Skin und die
ID lautet Bark Skin Dot PNG. Der grüne Schleim.
Eine wird die ID der Haut
für Erwachsene sein und die Quelle
teilte Skin PNG mit. Ich habe Hyde Park Skin mit CSS. Auch Skin erzählt. Und das Larven-Sprite. Wir werden
diesen Codeblock erneut kopieren. Es ist wichtig zu beachten, wie die
Tabellen
dieser Feinde organisiert sind . Wir müssen berücksichtigen, dass wir
beim Schreiben unseres Codes, wie
ich sehe, vier Arten von
Kröten und vier Typen
für dunkle Haut haben , wobei jeder Typ in einer separaten Zeile steht. In diesem Fall wissen wir,
dass Frame y steuert, welcher
Feindtyp angezeigt wird. Bild x
durchläuft erneut diese Animationsreihe und erweckt die Kreatur zum Leben. Es ist auch wichtig
zu beachten, dass ich für tote als auch für
dunkelhäutige Sprites dieselbe Struktur sowohl für tote als auch für
dunkelhäutige Sprites dieselbe Struktur habe. Beide haben vier Reihen, 38 Bilder pro Reihe. So kann ich die Animation für
die übergeordnete feindliche Klasse übernehmen ,
da die Logik für beide
Animus-Unterklassen gemeinsam genutzt
wird . Ich habe hier Frame x auf Null gesetzt. Erläutern Sie, warum wir
nach dem Zufallsprinzip einen
der vier verfügbaren
Gegner für die Animation auswählen . Der maximale Frame wird 38 sein. In der Aktualisierungsmethode habe ich die
Sprite-Animation hier oben bearbeitet den kopierten Codeblock eingefügt. Zuallererst wollte ich
hier die Tabelle mit der Krötenhaut
verwenden und die Rindenhaut
hier so. Wenn Sie den
Animationsfehler wie diesen sehen, bedeutet
das normalerweise, dass die von uns definierte
Bildgröße falsch ist. Die Rahmen sind also quasi
einschiebbar. Dunkle Skins werden korrekt
animiert. Ich überprüfe die Rahmengröße bei unzähligen Skins und sehe, dass der einzelne
Frame in der Tabelle
154 Pixel breit und
238 Pixel hoch ist . Sie erhalten die Breite eines einzelnen
Frames, indem Sie die Breite
der gesamten Tabelle
durch die Anzahl der Spalten und
durch die Anzahl der Frames pro Zeile dividieren der gesamten Tabelle
durch die Anzahl der Spalten . Und Sie erhalten die Höhe
eines einzelnen Frames, indem Sie
die Höhe der
gesamten Tabelle
durch die Anzahl der Zeilen dividieren die Höhe der
gesamten Tabelle . Perfekt, wir animieren die Spielerschlüpflinge und
acht verschiedene Feindtypen. Wir sehen Bereiche mit kollagenen
Kreisen, aber das Spiel
soll
mit deaktiviertem Debug-Modus gespielt werden . Wir müssen sicherstellen
, dass die Kollisionsbereiche den kleinen Schatten
unter unserem Schwebekörper und unseren Feinden
passen, da ich möchte, dass sie hier pixelgenau sind. Und Kröten,
Stöcke und Hirschhäute haben
unterschiedliche Sprites-Größen. Ich kann
Sprite X und Sprite nicht gegeneinander abstimmen. Warum hier in der
Shared-Update-Methode um einen bestimmten Wert und richten beide von
derselben Stelle aus aus aus aus. In einer solchen Situation möchte
ich diese Zeile kommentieren
und
diese Aktualisierungsmethode für
jede Unterklasse erweitern , um ihr
für jeden Elementtyp
leicht unterschiedliche Werte zu geben . Um es so einfach zu machen. Bei unerlaubten Handlungen kann eine Unterklasse
, die die übergeordnete
NME-Superklassenklasse erweitert , nennen wir Update. Wenn ich
Update einfach so definiere, hätte
diese Methode Vorrang
und würde die Methode mit dem gleichen Namen in
der
übergeordneten Klasse vollständig überschreiben . will ich nicht wirklich. Ich möchte, dass der Code innerhalb Aktualisierungsmethode für die
feindliche Klasse ausgeführt wird. Und ich wollte hier unten in dieser
Aktualisierungsmethode für
eine untergeordnete Klasse benutzerdefinierten Code hinzufügen , der nur für
die Skinklasse von
Toad spezifisch , der nur für
die Skinklasse von
Toad ist. Ich mache das, indem ich
das Super-Schlüsselwort verwende , das den Elternteil
darstellt. Und dann meine Klasse. Hier
sage ich, führe den gesamten Code innerhalb der Aktualisierungsmethode auf der übergeordneten Klasse und dann der
Klasse auf der Superklasse aus. Dann möchte ich
diese Codezeile nehmen, und in dieser Zeile werden nur vier Zehenscans
ausgeführt. Ich versuche es mit plus 50. Mein Ziel ist es,
den
Kollisionskreis
so nah wie möglich an
dem kleinen Schatten auf
dem Boden unter den schwebenden Feinden auszurichten den
Kollisionskreis
so nah wie möglich an
dem kleinen Schatten auf dem Boden unter den schwebenden Feinden so nah wie möglich Wir haben Barkenskins kaputt gemacht,
weil ihr Sprite-Y-Wert jetzt
nicht aktualisiert wird.
Wir werden das in einer Minute beheben. Zuerst möchte ich mich darauf ausrichten, ich werde eine Körpergröße von -100 machen. Okay, wie wäre es mit der Größe des
Feindes geteilt durch zwei -100? Das kommt dem,
was ich will, näher. Vielleicht -90. Ja. Wenn ich das D drücke, um den Debug-Modus zu aktivieren
und zu deaktivieren, kann
ich sehen, dass kleine
Grundschatten-Unterton-Skins sehr genau auf den
Kollisionskreisbereich
abgestimmt sind. Perfekt. Ich kopiere diesen Codeblock und lege ihn hier auf unsere Rindenfelle. Hier mache ich -100. So erweitern Sie also
eine Methode, die in
einer übergeordneten Klasse existiert, wie diese
Aktualisierungsmethode, die wir hier haben. Und für jede Unterklasse rufen
wir zuerst den Code innerhalb der Update-Methode für die übergeordnete
Klasse ab Zeile 302 auf. Und dann können wir
zusätzlichen Code hinzufügen
, der nur für
diese bestimmte Unterklasse einzigartig ist. Mit dieser Technik kann
jedem Feindtyp ein
anderes Bewegungsmuster, anderes Verhalten,
unterschiedliche Angriffe, verschiedene Animationen usw. verliehen werden. Sie können den
endgültigen Quellcodeordner, den
ich
Quellcodeversion sechs genannt habe,
im Abschnitt Ressourcen
unten herunterladen ich
Quellcodeversion sechs genannt habe,
im und ihn mit
Ihrem eigenen Code vergleichen , falls Sie
Probleme haben. Jetzt ist es an der Zeit, dass Sie
einige zusätzliche Funktionen hinzufügen. Vielleicht versuche ich, in meinen anderen
Kursen zur
Spieleentwicklung nachzuschauen , in denen wir Sounds oder State Management
anwenden und verwende es für dieses Spiel. Schauen Sie sich die
Bonus-Kunstsammlung , die im Abschnitt
Ressourcen unten
verfügbar Ich werde eine Menge Kunst
in verschiedenen Formaten mit
separaten Stücken hinterlassen , sodass
Sie sie
kombinieren und Spaß
damit haben können , wenn Sie möchten. Danke, dass du
deine Zeit mit mir verbracht hast. Ich hoffe, du hast
heute viel Wert. Gut gemacht, dass Sie das
Projekt abgeschlossen haben. Wir sehen uns später.
37. Bonusprojekt (optional): Erstelle animierte
Spielumgebungen per Tastatur
gesteuerten Charakteren, zufällig positionierten Hindernissen und Kunstwerken aus der Umgebung. Lasst uns Spiele
mit HTML-CSS und einfachem Vanilla-Javascript ohne Frameworks und Bibliotheken erstellen. Wie immer kann das
Layern von Elementen eine Herausforderung sein, wenn ich
all meine interaktiven Elemente
auf einer einzigen Leinwand zeichne einzigen Leinwand kann das
Layern von Elementen eine Herausforderung sein, wenn ich
all meine interaktiven Elemente
auf einer Wir können die eingebaute
Array-Sortiermethode verwenden, um
Spielobjekte anhand
ihrer vertikalen Y-Koordinate neu zu organisieren Spielobjekte anhand und sie in dieser Reihenfolge zu zeichnen Mit diesem einfachen Trick können
wir einen
Spielercharakter haben, der Hindernisse
auf visuell sinnvolle
Weise umgeht Hindernisse
auf visuell sinnvolle
Weise umgeht Lassen Sie uns ein Spiel von
Grund auf neu erstellen und etwas über Front
- und Y-Entwicklung und
objektorientierte Programmierung lernen .
38. Bonusprojekteinrichtung: Wir werden mit drei
Dateien im Index-HTML arbeiten. Ich erstelle eine generische
einfache Webseite und gebe ihr einen Titel. Ich verlinke ein CSS-Stylesheet, ich erstelle ein
HTML-Five-Canvas-Element mit der ID Canvas One und ich verlinke die GS-Datei des Skripts. Ich erstelle einen Dip mit der ID
eines Wrappers und
lege die Leinwand hinein Ich erstelle ein Bild-Tag
mit Source-Overlay,
Alt-Overlay und ID-Overlay Du kannst
alle Grafikdateien in
der Videobeschreibung im
Bereich Projektdateien herunterladen der Videobeschreibung im
Bereich Projektdateien Ich gebe dir auch
alle einzelnen Teile in hoher Auflösung, damit
du
deine eigenen einzigartigen
Hintergrundbilder zusammenstellen kannst . Wenn Sie Optimierungstipp
Nummer eins wollen, verwenden Sie einfaches CSS. Bei großen Hintergrundbildern kann
ich
alles auf Leinwänden zeichnen und animieren. Normalerweise mache ich das heute. Ich möchte Ihnen zeigen, wie
Sie CSS und die
Canvas-Draw-Bildmethode kombinieren können , um die Leistung zu maximieren. Dadurch entfällt die Notwendigkeit, diese großen Bilder bei
jedem Animations-Tick immer wieder auf die
Leinwand zu
zeichnen jedem Animations-Tick immer wieder auf die
Leinwand zu Und es wird die
Leistung unserer Spiele verbessern. CSS-Transformationen verwenden GPU. Sie sind schneller und
haben ein einfacheres Markup, da CSS viele
integrierte Schlüsselwörter hat , was animierte
Übergänge erheblich erleichtert Vielleicht musst du für dein Spiel alles auf
Leinwand zeichnen Aber heute werde ich
es mit etwas CSS kombinieren, um die
Tools und Techniken, die die
Frontend-Webentwicklungsumgebung bietet,
voll auszunutzen .
39. Spielwelten verbessern: Intalsien. Ich gebe Canvas ein
Hintergrundbild, du kannst es in
der Videobeschreibung herunterladen oder du kannst
deinen eigenen Hintergrund aus
den einzelnen Stücken zusammenstellen , die
ich zur Verfügung stelle. Wie du siehst, haben wir zwei Ebenen
erstellt Hintergrundgrafiken, auf die unser Charakter gezeichnet
wird, und einige Overlay-Bilder, Blätter und Gras, die vor unserer Waldszene zu sehen
sein werden vor unserer Waldszene zu sehen
sein Der Spielercharakter wird sich hinter ihnen verstecken
können. Sofern wir die
Breite und Höhe der Leinwand nicht festlegen, wird
sie standardmäßig immer
auf 300 mal 150 Pixel eingestellt. Wir werden es in
einer Minute mit dem Java-Skript auf die richtige
Größe einstellen, um die
vollständige Hintergrundgrafik zu enthüllen. Ich hätte
dieses Hintergrundbild auch
auf das Wrapper-Element legen dieses Hintergrundbild auch
auf das Wrapper-Element Ich gebe dem
Haupt-Wrapper-Element einen gewissen Rand. Mein Browser ist verkleinert, sodass ich alles auf dem Bildschirm unterbringen kann Die Bilder, die ich Ihnen
heute gebe, sind für eine Auflösung von
1.280 mal 720
Pixeln optimiert 1.280 mal 720
Pixeln Das Spiel, das wir gerade entwickeln,
ist ziemlich umfangreich. Sie können die
Größen anpassen, wenn Sie möchten. Wenn Sie ein
Anfänger sind, ist es vielleicht eine gute Idee,
meinem Code genau zu folgen, dieselbe Größe
und dieselben Bilder zu
verwenden
und Änderungen erst vorzunehmen, wenn wir das gesamte
Projekt zum Laufen gebracht haben. Ich möchte den Container zentrieren, also gebe ich ihm eine absolute Position. Sie können sehen, dass der Wrapper nicht in
der oberen linken Ecke beginnt Es gibt einige
Standardränder und -abstände, um sicherzustellen, dass unsere Seite in allen
Browsern gleich aussieht . Ich werde einen globalen Reset für
alle Elemente auf der Seite durchführen und den Rand auf Null,
den Innenabstand auf Null und die
Feldgröße auf das Rahmenfeld setzen und die
Feldgröße auf das Rahmenfeld Um sicherzustellen, dass die
Elemente Innenabstand und Rahmen in der
Gesamtbreite und -höhe enthalten sind, möchte
ich das
Rapid vertikal
und horizontal in der Mitte
der Seite zentrieren Ich habe ihm bereits die absolute
Position gegeben. Jetzt kann ich die obere Hälfte links auf 50% setzen und die Transformation auf
-50%
-50% transformieren . Außerdem muss ich das Overlay an
diesem Bild ausrichten Ich gebe die Position
absolut oben 50% links 50% -50% transformieren
-50% -50% Dadurch wird es exakt
über dem Wrapper ausgerichtet Es gibt noch viel mehr
Dinge, die wir hier tun können. Lassen Sie uns zum Beispiel zwei
weitere Bilder
in das Projekt einbringen . Ich erstelle ein Bild mit dem Namen
leaves underscore left. Ich gebe ihm dasselbe
alte Attribut und dieselbe ID. Sie können
all diese Bilder
in der Videobeschreibung herunterladen in der Videobeschreibung Ich erstelle ein anderes Bild namens Leaves Underscore,
oder? So wie das Diese
hätten nur ein Teil des Haupt-Overlay-Bildes sein können,
aber ich möchte, dass sie
animiert und interaktiv Wie gesagt, CSS-Transformationen
werden von der GPU verarbeitet. Lassen Sie uns das nutzen
, damit sich unsere Spielwelt ein bisschen
lebendiger und interaktiver anfühlt CSS erledigen etwas Arbeit für uns. Nicht alles muss
auf Leinwand gezeichnet werden. Es wird alles sehr
gut
zusammenpassen und unser Spiel
wird großartig aussehen. Ich passe Blätter links
oben auf
50 Pixel an, linke Position
auf -100 Blätter rechts werden
-150 Pixel hinter dem
rechten Rand hier oben
auf dem Haupt-Wrapper positioniert rechten Rand hier oben
auf dem Haupt-Wrapper Setze Overflow auf versteckt,
um
alles, was sich
außerhalb des Hauptspielcontainers befindet, abzuschneiden und zu verstecken außerhalb Wir können jetzt so viele
Dinge damit machen. Wir können zum Beispiel dafür sorgen, dass die
Blätter aus dem Weg geräumt werden. Wenn wir mit der Maus über die Leinwand fahren, sind
wir nur ein stiller Beobachter, der
sich im Gebüsch versteckt Lassen Sie uns die Blätter ein wenig aus dem Weg räumen,
damit wir sehen können Wenn ich mit der Maus über die Leinwand fahre, möchte
ich etwas
CSS auf die verbleibenden Blätter anwenden Ich werde ihre
linke Position ändern und sie
um plus 15 Grad drehen Diese CSS-Deklaration
wird nicht funktionieren. Es würde funktionieren, wenn leaves left
ein untergeordnetes Element des
Canvas-Elements wäre, aber das ist es nicht. Wenn wir hier nachschauen, können wir sehen
, dass sie Geschwister sind. Sie befinden sich in Element
drei auf derselben
Ebene und beide teilen sich den
Wrapper als Elternteil Um etwas auf die verbleibenden Blätter anzuwenden, müssen
wir, wenn der Mauszeiger darüber bewegt wird, wenn der Mauszeiger darüber bewegt wird, etwas verwenden,
das als allgemeine Geschwisterauswahl bezeichnet wird das als allgemeine Geschwisterauswahl allgemeine Geschwisterauswahl
wählt alle Elemente , die die nächsten Geschwister
eines bestimmten Elements sind Wenn ich mir unsere
Elementstruktur ansehe, haben
wir ein
Leinwand-Element-Overlay-Bild direkt darüber
liegt Es verhindert tatsächlich, dass
das Hover-Ereignis auf der Leinwand ausgelöst Ich möchte, dass das
Overlay-Bild oben angezeigt wird, aber ich möchte, dass es
für alle Mausinteraktionen unsichtbar Damit ich mit der
Leinwand interagieren kann, die sich darunter befindet. Ich kann das tun, indem ich die
Zeigerereigniseigenschaft Overlay so
auf non setze Moment befindet sich die Leinwand nur
in diesem kleinen Bereich, aber bald werden wir die
Größe ändern, um
den gesamten Container auszufüllen, um das
Hover-Ereignis zu testen Im Moment muss ich
meine Maus über den
kleinen Leinwandbereich bewegen meine Maus über den
kleinen Leinwandbereich Hier funktioniert es beim Hover, ich habe die linke Position
auf -150 Pixel gesetzt Ich gebe den Blättern
etwas Übergangszeit ,
damit sie tatsächlich Versuchen wir es mit 0,3 Sekunden. Nett. Ich mache das
Gleiche mit Blättern, oder? Ich gebe ihm auch einen gewissen Übergang, vielleicht nur 0,2 Sekunden. Sie sind also nicht
vollständig synchronisiert. Wir können so viele Dinge tun. Wenden Sie beispielsweise
Keyframe-Animationen an damit es so aussieht, als würden
sich die Blätter vom Wind bewegen. Ich nenne es Wobble. Bei 0%
beginnt es bei den oberen 50 Pixeln. Wir werden einen
Breakpoint von 50% bei 55 Pixeln haben. Und bei 100% wird es wieder auf 50
gehen. Wir können es anwenden, indem wir den
Blättern die Animationseigenschaft geben. Wir nennen es Wackeln. Das Timing wird sich lockern. Die Dauer der
Animationsschleife beträgt 1,5 Sekunden. So, so, es läuft nur einmal, aber ich möchte eine Endlosschleife,
ich sehe keine Bewegung. Stellen wir das auf
65 Pixel ein, oder? Ich muss sicherstellen, dass ich die
richtige Syntax für Keyframes habe . Dieses Semikolon muss
da sein, wir haben Blätter, die
sich im Wind bewegen Versuchen wir es mit 56 Pixeln. Ich kopiere diese Linie und wende
sie auch auf Blätter an, oder? Ich möchte sie desynchronisieren. Loop
dauert hier 1,6 Sekunden, genau wie bei Overlay. Ich muss die Zeigerereignisse
auf beiden Blättern auf „Keine“ setzen , um
sicherzustellen , dass sie Mausereignisse
auf der darunterliegenden Leinwand nicht
blockieren auf der darunterliegenden Leinwand So können wir einen Teil
deiner
Spielwelt-Szene mit CSS
zeichnen und verbessern . Es ist eine gute Praxis, wenn
es um Leistung geht. Wenn Ihr Projekt dies zulässt, Sie es
gerne öfter verwenden.
40. JavaScript-Einrichtung: Wir werden auch einige
Bilder mit Javascript zeichnen, hauptsächlich unseren animierten,
tastaturgesteuerten Alber-Charakter Wenn wir mit
Bildern in Javascript arbeiten, müssen
wir immer sicherstellen, dass
das Bild vollständig geladen und
verfügbar ist , bevor der Code ausgeführt wird, der von diesem
Bild
abhängt Andernfalls erhalten wir eine Fehlermeldung. Es gibt viele Möglichkeiten, dies zu tun. Wir können Versprechen verwenden oder
eine sehr einfache Möglichkeit besteht darin gesamten Javascript-Code
in den Load Event Listener
einzubinden Ladeereignis wird ausgelöst, wenn
die gesamte Seite geladen wurde, einschließlich aller
abhängigen Ressourcen wie Stylesheets und Bilder Auf diese Weise kann ich meine Tabelle einfach
als normales IMG-Element
in Index-HTML
einfügen , und Javascript
wartet, bis das Bild in der anonymen
Callback-Funktion
geladen wird der anonymen
Callback-Funktion
geladen Hier habe ich meine Leinwand eingerichtet. Wir benötigen einen Verweis auf
das Canvas-Element, eine konstante Variable, die ich
Canvas nenne, und ich möchte
Javascript auf
dieses Canvas-Element verweisen , das wir in Zeile
12 im Index HGML
erstellt Wir haben ihm die ID von Canvas One gegeben Wir müssen hier nicht wirklich
Get Element by ID verwenden, da alle Browser
automatisch
Javascript-Variablen für
alle Elemente mit einer ID erstellen Javascript-Variablen für
alle Elemente mit einer ID Dieser automatische Variablenname
ist immer derselbe wie ID. Es ist gut für den Bug in, aber da Browser
all diese Variablen in
den globalen Namespace stellen , diese Variablen leicht
versehentlich überschrieben werden Es ist besser, wenn wir Get
Element by ID verwenden, so wie hier. Ctx-Kontext ist Canvas Dot Get Context Two D, um
eine Instanz der integrierten
Canvas-Two-D-API zu generieren , die den
Canvas-Status und alle
beiden Zeichenmethoden enthält Canvas-Status und alle
beiden Zeichenmethoden Das übergeordnete
Wrapper-Element wurde auf
1.280 mal 720 Pixel gesetzt 1.280 mal Stellen wir sicher, dass das
Canvas-Element dieselbe Größe hat. Dadurch wird das
gesamte Hintergrundbild angezeigt. Was denkst du darüber? Wie gesagt, ich werde auch
einzelne Stücke in hoher Auflösung mit
Ihnen teilen . Ihr könnt
sie mischen und kombinieren und
eure eigenen, einzigartigen
Spielumgebungen kreieren , wenn ihr wollt. Alle Kunstgegenstände, die ich in
diesem Video teile , sind urheberrechtlich frei. Sie wurden
von mir oder von Künstlern, die ich engagiert habe, entworfen und gezeichnet. Sie können sie ändern und
verwenden, wie Sie möchten. Ich werde
CSS-Animationen in den Zeilen
39.31 auskommentieren . Ich denke, das wird weniger ablenkend
sein Wir müssen
jetzt einige
Java-Skript-Codierungen durchführen, um unseren animierten
Charakter zum Leben zu erwecken Lassen Sie uns heute den Prinzipien der
objektorientierten
Programmierung folgen und unseren Code in
einzelne Klassen
aufteilen. Jede Klasse wird unterschiedliche
Aufgaben haben und wir werden
sie dazu bringen , miteinander zu kommunizieren und
zusammenzuarbeiten , um
das Endprodukt zu entwickeln. Eine benutzerdefinierte Klasse, die ich zum Beispiel nenne, Eingabehandler
verarbeitet Tastatureingaben. Wenn eine Taste
auf einer Tastatur gedrückt wird, verarbeitet
diese Klasse sie und transformiert und speichert diesen Wert, sodass er von anderen Klassen verwendet werden kann. Class Owl Bear wird unsere animierte
Hauptfigur sein. Der Spieler kann es mit der Tastatur
steuern. Das Klassenobjekt wird
als Blaupause verwendet, um
zufällig generierte
Bäume, Büsche und Gras zu erstellen zufällig generierte
Bäume, Büsche und Gras Sobald wir sie
in der Spielwelt platziert
haben, werden wir lernen, sie so zu
organisieren, dass sie vor
und hinter dem Spieler gezeichnet werden,
je nachdem, wo der Spieler gerade
steht Das ist sehr wichtig, denn
ohne das wäre es in einem Spiel wie diesem visuell nicht
sinnvoll, den Spieler über
alles zu ziehen diesem visuell nicht
sinnvoll, den Spieler über
alles zu ziehen. Wir brauchen etwas Logik, damit
der Spieler
diese beiden D-Hindernisse umgehen kann , und ich werde dir einen
einfachen Weg zeigen, wie das geht. Schließlich brauchen wir
eine Klasse, die ich Spiel nenne. Hier
kommt die gesamte Logik aller Klassen zusammen. Dies wird das
Haupthirn unserer Codebasis sein. Klassenkonstruktor
erstellt für uns eine Instanz
einer Klasse auf der Grundlage eines
Entwurfs, den wir darin definieren Lassen Sie uns einen Entwurf
für unsere Hauptspielklasse definieren. Ich möchte, dass diese Klassen
eigenständig und modular sind. Wir werden es
zusammen mit der Höhe
des Spielfeldes als
Argumente wie dieses weitergeben . Wir konvertieren sie in
Klasseneigenschaften. Wir nehmen Breite und Höhe als Argument für den
Klassenkonstruktor und konvertieren sie in Eigenschaften für
Breite und Höhe dieser Instanz der Spielklasse Um eine Instanz
einer Spielklasse zu erstellen, erstelle
ich eine konstante Variable Ich nenne zum Beispiel Game und verwende das neue Schlüsselwort. Das neue Schlüsselwort in
Java-Skript wird verwendet, um
eine Instanz eines Objekts zu erstellen , das eine Konstruktorfunktion
hat Das neue Schlüsselwort
sucht nach einer Klasse mit diesem Namen und
löst ihren Konstruktor Der Konstruktor erstellt ein
neues leeres Java-Script-Objekt und stellt
seinen Prototyp automatisch hinter den Kulissen Es bindet dieses Schlüsselwort so, dass es
auf dieses neu
erstellte Objekt zeigt, und weist dem Objekt
alle Eigenschaften und Werte zu, wie wir sie hier
im Blueprint definieren Bisher
wird unser Spielobjekt nur die Eigenschaften Breite
und Höhe haben In diesem Fall kann ich sehen,
dass diese Eigenschaften als Werte
erwartet
werden , die von außen weitergegeben werden. Wir tun dies, um unsere Klassen
eigenständig und modular zu halten . Ich übergebe die
Leinwandbreite ab Zeile vier. Wie bei der Leinwandhöhe
ab Zeile fünf als Höhe. Da ich möchte,
dass das Spiel die gleiche Größe wie die Leinwand hat, möchte
ich, dass der Spielbereich das gesamte Leinwandelement verbraucht. So
erstellen Sie eine Klasse in Java-Skript und wie Sie
eine Instanz dieser Klasse erstellen. So verwenden Sie diese Klasse, um
ein Objekt auf der Grundlage
des Klassen-Blueprints zu erstellen ein Objekt auf der Grundlage
des Klassen-Blueprints Lassen Sie uns die
Spielvariable aus Zeile 26 übernehmen, um zu
überprüfen, ob in der Konsole alles gut
gelaufen Ich kann sehen, dass die
Spielvariable
eine Referenz speichert , die auf
ein Spielobjekt zeigt , wobei die
Eigenschaften für
Höhe und Breite auf die
richtigen Werte perfekt eingestellt Wenn Sie beim
Schreiben Ihrer
objektorientierten Codebasis Fehler bekommen , können
Sie
Ihre Objekte jederzeit auf diese Weise konsolidieren und überprüfen, ob all diese
Eigenschaften Werte haben Wenn Sie hier undefined sehen, wissen
Sie, dass in
Ihrem Code ein Problem vorliegt , und Sie können
diesen Wert in Ihrer
Codebasis nachverfolgen , um das Problem zu finden
41. Tastatursteuerungen: Input-Handler-Klasse dient
dazu, den Überblick über die
Tastaturtasten zu behalten , während sie vom Benutzer gedrückt
und losgelassen werden. Und sie konvertiert sie in
Werte, die von
anderen Objekten in unserer
Codebasis verwendet werden können , und speichert sie. Ich gebe ihm auch einen Konstruktor. So werden wir
unsere Objekte miteinander
kommunizieren lassen unsere Objekte miteinander
kommunizieren Eingabe-Handler erwartet eine Referenz,
die auf das Hauptspielobjekt zeigt als Argument
eine Referenz,
die auf das Hauptspielobjekt zeigt. Dieses gesamte Objekt, in dem wir diese Referenz
in eine Klasseneigenschaft
umwandeln, so wie dieses Spiel, das als Argument übergeben wurde, in
eine Spieleigenschaft umgewandelt
wird. In dieser Instanz
des Eingabehandlers sind
Klassenobjekte in Java-Skript Referenzdatentypen. Ich erstelle hier keine Kopie
des Spielobjekts, ich erstelle nur eine
Variable, die auf
einen Bereich im Speicher verweist, in dem das
Hauptspielobjekt gespeichert ist. Das ist großartig, denn wenn die
Werte des Spielobjekts aktualisiert werden, sind
diese Änderungen sofort dieser
Punktspielreferenz
sichtbar. Hier in der Hauptspielklasse erstelle
ich eine Eigenschaft
namens „Punkt
letzte Taste“. Diese Klasse aktualisiert diesen Wert in der Spielklasse, wenn Tasten gedrückt und losgelassen
werden. Anfangs habe ich
es zu undefiniert gesagt. Heute werden wir etwas über die
Tastatursteuerung lernen und nur die letzte Taste, die
gedrückt oder losgelassen wurde, im Speicher
gedrückt Das ist alles, was wir kontrollieren müssen, vier Richtungen auf
den Charakter. Wenn ich mehrere Tastendrücke verfolgen
wollte, würde
ich stattdessen hier ein
Array erstellen. Und ich würde dort Schlüssel hinzufügen und
entfernen. Ich habe es schon einmal gemacht und
vielleicht mache ich es später
in dieser Serie. Je nachdem, wie komplex und präzise
Tastatursteuerungen wir benötigen werden. Ich möchte auch automatisch
eine Instanz des Eingabehandlers
erstellen, wenn ich das Spielobjekt erstelle. Lassen Sie uns hier ein Consolo einfügen
, das besagt, dass der Eingabehandler im
Spielklassenkonstruktor
erstellt wurde Ich erstelle eine Eigenschaft
namens diese Eingabe. Ich habe es einem neuen
Eingabe-Handler wie diesem gleichgestellt. Zeile acht kann ich sehen, dass Klassenkonstruktor des
Eingabehandlers einen Verweis auf
das Hauptspielobjekt
erwartet Hier erstelle ich eine
Input-Handler-Instanz innerhalb dieser Spielklasse Ich übergebe ihm dieses Schlüsselwort. Dieses
innerhalb der Spielklasse verwendete Schlüsselwort verweist auf die gesamte
Spielklasse selbst. Es steht für das Objekt
, in dem es definiert wurde. Nett, weil ich diesen Code in den Game Class
Constructor eingefügt habe, wenn ich eine Instanz von
Game Class in Zeile 31 erstelle.
Außerdem wird
automatisch eine Instanz der
Input-Handler-Klasse für mich Es wird als
Punkteingabeeigenschaft in
der Hauptspielklasse selbst gespeichert der Hauptspielklasse selbst Ich kann bestätigen, dass der
Eingabe-Handler erstellt wurde , da ich diese
Konsole hier sehe. Perfekt. Dies ist eine einfache Methode,
wie du
deine Klassen miteinander verbinden und sie
zusammenarbeiten lassen kannst deine Klassen miteinander verbinden und sie
zusammenarbeiten lassen , um ein vollständiges Spiel zu
erstellen. Es ist außerdem sehr modular aufgebaut, sodass du
deinem Spiel später weitere Funktionen
und mehr Klassen
hinzufügen kannst, wenn du möchtest. Wie wir bei diesem Consolo sehen, wird der
gesamte Code innerhalb des
Klassenkonstruktors automatisch ausgeführt,
wenn eine Instanz dieser Klasse erstellt wird Dieser Code muss nicht immer nur in
Klasseneigenschaften definiert
werden Wir können hier jeden beliebigen Code einfügen. In diesem Fall möchte ich Event-Listener
automatisch
anwenden Wenn eine Instanz der
Input-Handle-Klasse erstellt wird, füge
ich sie einfach hier Wir werden
in
der Callback-Funktion auf das Key-Down-Ereignis in
der Callback-Funktion Ich werde eine
Consolo-Callback-Funktion für den Event-Listener in
Javascript ausführen , der Zugriff
auf ein
automatisch generiertes Ereignisobjekt hat, das alle Details zu dem Ereignis
enthält, das Ich kann ihm hier einen
Variablennamen zuweisen, Konvention besteht normalerweise aus
einem Ich habe das schon einmal gemacht, also weiß ich dass dieses automatisch generierte
Event-Objekt eine Eigenschaft namens key
hat, die uns den Namen der
Taste
gibt, die gedrückt wurde Ich consolo key, ich muss auf Canvas klicken,
um sicherzugehen, dass es ausgewählt ist Und wenn ich
etwas auf der Tastatur drücke, werden
die Namen der Tasten in der Konsole gedruckt Heute werden wir uns auf die
Richtungspfeiltasten konzentrieren. Also Pfeil links, Pfeil rechts, Pfeil runter und Pfeil hoch. Ich möchte diese
Schlüsselwerte in der
letzten Schlüsseleigenschaft aus Zeile
28 des Hauptspielobjekts speichern . Wir haben
hier in
Zeile neun einen Verweis auf das Hauptspielobjekt . Aber wenn ich
dieses Spiel aus dem Event-Listener heraus
konsologiere , stellen
wir fest, dass die Referenz undefined
zurückgibt. Das liegt daran, dass diese
Callback-Funktion vergisst, dass sie ursprünglich hier in der
Konstruktormethode der
Eingabehandler-Klasse definiert wurde hier in der
Konstruktormethode der
Eingabehandler-Klasse definiert vergisst, dass sie ursprünglich hier in der
Konstruktormethode der
Eingabehandler-Klasse definiert wurde. Ich möchte, dass sich die Funktion daran erinnert, ich möchte ihren Geltungsbereich so binden, dass ein Verweis auf dieses Schlüsselwort, das
in diesem Fall
dieses
Eingabehandler-Objekt darstellt , sowie Zugriff auf diese
Spieleigenschaft innerhalb dieser
Callback-Funktion auf
dem
Key-down-Event-Listener verfügbar sind,
wann immer dieser
Event-Listener später ausgeführt wird innerhalb dieser
Callback-Funktion auf
dem
Key-down-Event-Listener verfügbar sind,
wann immer dieser Event-Listener später ausgeführt Ich möchte sicherstellen, dass diese
Funktion nie vergisst, dass sie ursprünglich innerhalb eines Objekts definiert wurde
. Ich kann dazu die
Javascript-Bindungsmethode verwenden, oder ich kann einfach die
ES-Sechs-Pfeil-Funktion verwenden Funktionen mit sechs Pfeilen binden sich
nicht selbst, sondern erben die Funktion
aus dem übergeordneten Bereich Wir nennen das lexikalisches Scoping. Der Umfang der Pfeilfunktion hängt immer davon ab, wo sie in unserer Codebasis ursprünglich in ihrem ursprünglichen
lexikalischen Geltungsbereich
definiert wurde ihrem ursprünglichen
lexikalischen Geltungsbereich
definiert In unserem Fall wurde er
hier innerhalb dieser
Konstruktormethode definiert hier innerhalb dieser
Konstruktormethode Es wird also immer
Zugriff auf diese Punktspieleigenschaft
und alle anderen Eigenschaften haben , die wir in
diesem Konstruktor definieren
könnten Später, wenn ich
diese Callback-Funktion in eine schmale Funktion
umgestalte , können
wir das Spiel im Alleingang überprüfen. Und wir sehen, dass sie
auf das Hauptspielobjekt zeigt. Und alle seine Eigenschaften sind dort
sichtbar,
einschließlich des letzten Schlüssels Wenn ich den letzten
Schlüsselwert aus Zeile 28 bestätige, ist er
zunächst auf
undefiniert gesetzt Wir nehmen die Schlüsseleigenschaft aus dem Event-Objekt und ich weise
sie ihr so zu Jetzt zeichnet die letzte Tasteneigenschaft der Hauptspielklasse
immer die
letzte Taste
auf , die gedrückt wurde. Ich muss auch wissen, wann
die letzte Taste losgelassen wurde. Ich erstelle einen weiteren Event-Listener, diesmal für das Key-Up-Event Jetzt speichern wir den Namen der letzten Taste,
die
gedrückt oder losgelassen wurde Das Problem ist, dass es nur den Namen der Taste
registriert. Ich muss wissen, ob diese Taste gedrückt oder losgelassen
wurde. Ich werde den
Großbuchstaben P innerhalb
des Tasten-Down-Ereignisses verketten , um anzugeben, dass die Taste mit diesem
Namen gedrückt wurde Ich werde dann den Großbuchstaben R vor
den Namen der Taste innerhalb des Keyup-Ereignisses damit wir wissen, dass die Jetzt bekommen wir diese
Werte in der Konsole, Sie können den Wert
dieses Punktgamets sehen Die letzte wichtige Eigenschaft ändert sich. Wir drücken hier die Pfeiltaste und
hier lassen wir die
Pfeiltaste los. Ich kann die Konsole entfernen. Okay. Jetzt, da wir wissen, dass es dem Hauptspielobjekt
funktioniert, haben wir die letzte
Schlüsseleigenschaft definiert und eine Instanz der
Input-Handler-Klasse
erstellt. Input-Handler-Klasse initialisiert
wird, wenden
wir Event-Listener mit Tasten nach unten und
Tasten nach oben Dadurch wird
die letzte Tasteneigenschaft dynamisch aktualisiert , sodass unser Spielobjekt und alle damit verbundenen
Objekte immer wissen, welche Taste
gedrückt oder losgelassen wurde Wir werden diese Werte verwenden, um den Spielercharakter,
den Eulenbären, zu
steuern .
Definieren wir es hier.
42. Spielercharakter: Zuerst müssen wir
es mit dem Hauptspielobjekt verbinden. Wir stellen sicher, dass es einen Verweis auf
das Spielobjekt
als Argumenteinsicht
erwartet , wir konvertieren es wie gewohnt in eine
Klasseneigenschaft. Beginnen wir damit, ihm eine Breite
und Höhe von 100 Pixeln zu geben. Die Anfangsposition
wird 200 Pixel vom linken Rand und
200 Pixel vom oberen Rand entfernt sein. Ich gebe ihm eine Zeichenmethode
, um es auf Leinwand zu zeichnen. Es wird den Kontext
als Argument erwarten, um anzugeben, auf welches
Leinwandelement wir zeichnen möchten. Nimm diese Kontextvariable und ich rufe die eingebaute
Phil-Rectangle-Methode auf. Phil Rectangle erwartet X-, Y-Breite und -Höhe. Also übergebe ich ihm Eigenschaften
vom Owl Bear Constructor. Wir wollen zunächst ein
schwarzes Rechteck zeichnen , das den
Eulenbären
darstellt,
genau wie wir es mit der Input-Handler-Klasse getan haben Ich möchte automatisch eine Instanz des
Owl Bear-Objekts erstellen Owl Bear-Objekts Wenn ich eine Instanz
der Hauptspielklasse erstelle, habe ich
sie hier im Klassenkonstruktor instanziiert und einer
Klasseneigenschaft zugewiesen Ich nenne diese Eule in Zeile 20
Bär, ich sehe, dass sie
Spiel als Argument erwartet Ich gebe ihm dieses Schlüsselwort, weil wir in dieser Spielklasse sind Spielklasse wird eine spezielle
Methode haben, die ich render nenne, um alle
Spielobjekte zu aktualisieren und auf der Leinwand zu zeichnen. Ich nehme Oil Bear aus Zeile 42 und rufe die zugehörige
Ziehmethode aus Zeile 27 auf. Diese Methode erwartet
Kontext als Argument, nämlich diese CTX
aus Zeile drei Ich muss es weitergeben. Ich nenne es trotzdem Kontext. Es wird von der
Haupt-Render-Methode als
Argument erwartet , wir geben es an die
Draw-Methode auf Owl Bear weiter Ich nehme ein Spiel, rufe seine
Render-Methode ab Zeile 44 und übergebe es CTX aus Zeile
drei als Argument, dem ein Variablennamenkontext zugewiesen
und bei Bedarf weitergegeben
wird und bei Bedarf weitergegeben Perfekt. Wir
zeichnen unseren Eulenbären Es sieht aus wie ein
einfaches schwarzes Quadrat ,
weil
wir das hier
in der Draw-Methode der
Eulenbär-Klasse definiert haben . Lass uns es bewegen Ich gebe ihm eine benutzerdefinierte Aktualisierungsmethode für jeden Animationsframe. Ich möchte, dass X um eins zunimmt, sodass es sich nach rechts bewegt. Wir müssen diese Methode tatsächlich innerhalb
von Render in
der Spielklasse
aufrufen . Hier lösche ich diese Konsole,
um die Bewegung tatsächlich zu sehen Wir müssen diese
Aktualisierungsmethode immer wieder aufrufen. Sie es vom
Rendern aus nur einmal beim Laden
der ersten Seite aufrufen , wie wir es hier tun, wird nichts
animiert Wir werden eine Animationsschleife benötigen. Ich erstelle eine benutzerdefinierte Funktion. Ich nenne zum Beispiel
Animate Inside. Ich habe diesen Renderaufruf getätigt. Um es in eine Schleife zu versetzen, rufe ich die eingebaute
Request-Animationsframe-Methode auf. Diese Methode aktualisiert
unsere Webseite vor
dem nächsten Repaint, indem sie
einen Code in einer Funktion ausführt Wir übergeben ihn als Argument Wenn ich der Animation den
Namen der übergeordneten Funktion übergebe, wird eine
endlose Animationsschleife erzeugt Animate wird aufgerufen. Es ruft render auf, um unsere Eulenbär-Anfrage zu zeichnen und zu
aktualisieren. Der Animationsframe
löst die Animation erneut aus, sodass sich der Zyklus wiederholt Anforderungsanimationsframe befindet sich auf dem Fensterobjekt,
das das Browserfenster darstellt Es kann aber auch
direkt so aufgerufen werden. Ohne
Fenster davor zu stellen. Es ist besser, den
Anforderungsanimationsrahmen für
die Animation zu verwenden, als die Anfrage mit
festgelegtem Intervall zu verwenden Der Animationsframe passt die
Bilder pro Sekunde an Ihre Bildschirmaktualisierungsrate an und generiert
außerdem automatisch
einen Zeitstempel für uns Möglicherweise benötigen wir ihn später, um die Animation
auszulösen. Ich rufe einfach animate auf, als ob dieser nette Spieler sich nach rechts
bewegt,
er hinterlässt Spuren Wir müssen sicherstellen, dass wir
alle Leinwandzeichnungen zwischen den
einzelnen Animationsschleifen löschen alle Leinwandzeichnungen zwischen den
einzelnen Animationsschleifen Ich mache das, indem ich die eingebaute Methode Clear
Rectangle aufrufe. Ich möchte die gesamte
Leinwand aus der Koordinate 002, der
Leinwandbreite und der Leinwandhöhe löschen . Jetzt haben wir ein
sich bewegendes schwarzes Quadrat , das den
Spielercharakter darstellt. Perfekt. Es bewegt sich
nach rechts, weil hier in der
Update-Methode der Alber-Klasse
, wir
hier in der
Update-Methode der Alber-Klasse
, unserem Player, die
horizontale X-Position
für jeden Animationsframe um eins erhöhen horizontale X-Position
für jeden Animationsframe um eins Ich gebe ihr eine Eigenschaft, die
ich Geschwindigkeit X nenne. Anfangs setze ich sie auf Null Wir benötigen auch Geschwindigkeit Y, vertikale Geschwindigkeit für Auf
- und Abwärtsbewegungen. Denken Sie daran, dass wir
einen Charakter bauen , der über
die Tastatur gesteuert wird und sich in
vier Richtungen bewegen kann. Ich werde diesen Punkt x um den aktuellen Wert
von Geschwindigkeit x erhöhen . So
wie diese vertikale
Y-Koordinate
des Eulenbären wird um den Wert der Geschwindigkeit
Y erhöht.
Das ist großartig, weil
ich ihr
einen positiven Wert geben kann, um sich nach rechts zu
bewegen, und
einen negativen Wert, um sich nach links zu
bewegen Ich kann es
schneller bewegen, indem ich
ihm einen größeren Wert
pro Animationsframe Hier bedeutet diese Zahl
Pixel pro Animationsframe. Ein positiver Wert für Geschwindigkeit Y
lässt den Spieler nach unten gehen. Ein negativer Wert
lässt ihn aufsteigen. Ein positiver Wert in X und Y lässt ihn nach unten bewegen, oder? Wir könnten das problemlos für Bewegungen in
acht Richtungen verwenden. Wie Sie
hier in Zeile 7 sehen können, haben
wir eine Input-Handle-Klasse
, die Tastatureingaben erfasst. Sie wandelt die
Standardtastennamen so um,
dass sie angeben, ob die Taste gedrückt oder losgelassen
wurde Indem dem
eigentlichen Namen der Taste ein Pending oder R vorangestellt wird Es speichert den Wert
der letzten Taste, die hier in Zeile 46 gedrückt oder losgelassen
wurde. Innerhalb dieses Punktes befindet sich die letzte
Schlüsseleigenschaft der Hauptspielklasse. Weil ich
einen Verweis auf
diese gesamte Spielklasse übergebe , wenn
ich Alber in Zeile 48 erstelle Alber-Objekt hat über
diese Punktspielreferenz
hier in Zeile 21 Zugriff auf den
letzten Schlüsselwert auf Ich kann sagen, wenn dieses Spiel funktioniert, ist die
letzte Taste der Pfeil nach links Wenn der Linkspfeil gedrückt wurde, setze Geschwindigkeit x auf minus eins,
damit sich der Charakter auf
der horizontalen X-Achse in negativer
Richtung nach links bewegt . Wenn ich auf die Leinwand klicke und die linke Pfeiltaste
drücke, bewegen
wir uns perfekt. Wenn ich die Taste loslasse, hört der
Spieler hier nicht auf. Ich kann sehen, dass wir
den Wert für Presse und Pressemitteilung erfassen . Ich kann L sagen,
Geschwindigkeit x auf Null setzen, jetzt können wir uns nach links bewegen
und wir können anhalten. Ich könnte auch
eine Methode mit festgelegter Geschwindigkeit erstellen ,
die bei jedem Aufruf Geschwindigkeit x und Geschwindigkeit Y festlegt. Diese werden ihr als Argumente
übergeben Wir nehmen diese Argumente und aktualisieren die
Klasseneigenschaften aus Zeile 26.27 Jetzt kann ich diese
Zeile durch diese eingestellte Geschwindigkeit ersetzen Und ich übergebe sie minus eins als
Geschwindigkeit x und Null als Geschwindigkeit y. In der L-Anweisung setze ich sowohl die horizontale als auch die
vertikale Geschwindigkeit auf Null Es ist besser, eine
globale maximale Geschwindigkeitsvariable
zu haben als
eine fest zu codieren und hier minus eins. Falls diese Geschwindigkeit dynamisch sein
muss, kann der
Spieler eine
vorübergehende Geschwindigkeitssteigerung vornehmen. Oder vielleicht bewegt sich der Spieler beim Krabbeln
und Herumstreifen
langsamer. Um das zu erreichen, definieren wir die Eigenschaft
Max Speed. Wir setzen es auf drei Pixel
pro Animationsframe und ersetzen es hier. Lassen Sie uns diese Aussage erweitern. Ich werde auch
L überprüfen, ob die
letzte Taste mit dem Punkt R nach rechts gedrückt wird, so wie hier. In diesem Fall setzen wir Geschwindigkeit x auf plus Höchstgeschwindigkeit Geschwindigkeit y auf Null. Jetzt können wir uns
nach links und rechts bewegen und wir hören auf, uns zu bewegen, wenn die
RO-Taste losgelassen wird. Perfektioniere einen weiteren L-if-Block. Seien Sie vorsichtig mit der
Syntax und den Klammern. Es ist sehr einfach, eine Klammer zu
übersehen und dabei die gesamte
Codebasis zu
beschädigen. Wenn wir die Taste R drücken, rufen
wir Set Speed auf. Wir setzen die Geschwindigkeit x auf Null
und die Geschwindigkeit Y auf minus Höchstgeschwindigkeit, weil wir uns
auf der vertikalen Y-Achse
in negativer Richtung nach oben bewegen
wollen . Wir machen noch ein L, wenn wir blockieren, wenn letzte Taste die
Pfeiltaste nach unten ist. Wir setzen Geschwindigkeit x auf Null und
Geschwindigkeit y auf plus Höchstgeschwindigkeit. Wir können uns auch nach links,
rechts, oben und unten bewegen . Ich möchte sichergehen, dass der
Spieler die Leinwand nicht verlassen kann. Ich muss einige
horizontale Grenzen setzen. Wenn die horizontale
X-Position des Spielers kleiner als Null ist, setze sie wieder auf Null, das ist die linke Grenze. Andernfalls, wenn die horizontale
Position der Spieler
größer ist als dieses Spiel mit der
Breite des Spielfeldes, kommt
dieses Spiel von hier. Von dort aus navigieren wir
zu dieser Immobilie. Zeile 64 ist die
aktuelle Position des Spielers größer als die Breite
des Spiels abzüglich der Breite
des Spielers
, die wir in Zeile 22 definiert haben bedeutet, dass der rechte Rand des Spielerrechtecks
den rechten Rand der Leinwand berührt. Stellen Sie sicher, dass sich der Spieler nicht mehr weiter nach
rechts
bewegen kann . Auf diese Weise werde ich die Spielergeschwindigkeit auf zehn
Pixel pro Animationsframe erhöhen. Sie können sich jetzt nach links und rechts bewegen , um die horizontalen
Grenzen zu testen. Vertikale Grenzen
werden etwas anders sein, da
in unserer Spielwelt der Boden hier endet. Ich möchte nicht, dass der Spieler über
dieses Gebiet läuft, es sei denn, es handelt sich um
eine fliegende Kreatur. Ich glaube, dieser Eulenbär ist
definitiv zu schwer zum Fliegen. Ich frage mich, ob es
seltene Arten von fliegenden Eulenbären gibt Vielleicht suchen
wir
später in der Serie nach ihnen Wir haben diesen Bereich oben, in dem ich nicht möchte
, dass der Spieler laufen kann Ich erstelle eine Klasseneigenschaft
namens Top Margin. Anfangs habe ich
es auf 200 Pixel eingestellt. Lass es uns hier hinstellen. Hier oben werden
wir
vertikale Grenzen definieren. Sagen wir, wenn dieser Punkt y kleiner als Null
ist, ist
y gleich Null. Dadurch wird hier
eine Grenze geschaffen. Der Spieler kann nicht über
den oberen Rand der Leinwand hinaus nach oben gehen. Ich möchte eigentlich, dass
die Grenze
niedriger ist , wegen all
dieser Umgebungsgrafiken, ich sage Null plus dieser
Spiel-Dop-Marge wie dieser Ich kann hier Null plus löschen. Natürlich ist jetzt die obere
Grenze hier, 200 Pixel vom oberen Rand entfernt. Wir können herumlaufen, aber wir
können hier nicht mehr laufen. Perfekt, es macht visuell
mehr Sinn wenn der Spieler eine
echte animierte Figur ist, nicht nur ein schwarzes Quadrat, wir sind schnell da. untere Grenze ist einfach,
wenn die vertikale
Y-Position des Spielers größer ist als die Höhe des Spiels minus der
Körpergröße des Spielers. bedeutet, dass die Unterseite des Spielerrechtecks
den unteren Rand der Leinwand berührt. Lass nicht zu, dass es so
weiter nach unten geht. Lass es uns testen. Ja, wir
haben alle vier Grenzen. Perfekt. Lassen Sie uns dieses
einfache schwarze Rechteck in eine animierte Tabelle mit vier direktionalen
Zeichen umwandeln
43. 4 direktionale Sprite-Sheets: Ich beginne damit, ein
Tabellenkalkulationsbild wie folgt zum
Index-HTML hinzuzufügen Tabellenkalkulationsbild wie folgt zum
Index-HTML Wir machen das so, weil unser
gesamtes Javascript
im Load Event Listener befindet Wenn ich meine Tabelle hier platziere, wartet
Javascript, bis
diese Bilder vollständig
geladen und verfügbar sind, bevor
sie animiert werden Sie können alle
Projektgrafiken
im
Abschnitt Projektressourcen unten herunterladen im
Abschnitt Projektressourcen unten Ich habe es mir vorgestellt, lassen Sie es uns so aus
der Hülle herausbringen Sie können sehen, dass wir acht
Animationszeilen in
der Tabelle haben , Vier Richtungen,
und jede Richtung hat Leerlauf und Laufschleife Wir werden uns das
in einer Minute genauer ansehen und das Bild
selbst mit CSS ausblenden Wir wollen es mit
dem Java-Skript auf Leinwand zeichnen. Sie können sehen, dass sich der gesamte Code im Load Event Listener
befindet gesamte darin enthaltene Code
wird nur ausgeführt wenn Owl Bear und alle
anderen Bilder hier
im Konstruktor der Alber-Klasse, unserer
Spieler-Kontrollfigur,
vollständig geladen wurden hier
im Konstruktor der Alber-Klasse, unserer
Spieler-Kontrollfigur,
vollständig geladen Alber-Klasse, unserer
Spieler-Kontrollfigur, Wir werden eine
Referenz hinzufügen,
die auf dieses Tabellenbild
als Klasseneigenschaft verweist die auf dieses Tabellenbild
als Ich nenne es dieses Bild und setze es einer
Variablen namens al bear gleich Diese Variable wurde
nicht von uns deklariert, aber alle Browser
erstellen automatisch Verweise, automatisch generierte
globale Variablen auf alle Elemente mit einer ID Dieses Element hat eine ID. Wir wissen also, dass unser Browser automatisch eine
globale Variable dafür generiert hat. Normalerweise würden wir Get Element by
ID hier in Zeile 29
verwenden ,
aber das müssen wir nicht. Das einzige Problem ist, dass es
sich um eine globale Variable handelt. Da wir jetzt
globale Variablen in unsere Klassen aufnehmen, besteht die
ständige Gefahr, dass diese Variable versehentlich überschrieben wird Lass uns einfach testen, ob es funktioniert. Wie auch immer, ich nehme den Kontext sich auf die CTX-Variable bezieht,
aus Zeile drei Ich rufe die integrierte
Canvas-Draw-Image-Methode auf. Draw Image erwartet
mindestens drei Argumente. Ich übergebe ihm diese automatisch generierte
globale Variable, die aus der
Element-ID erstellt wurde , als
das Bild, das wir zeichnen möchten. Und ich übergebe ihm diesen Punkt x aus
Zeile 24 und diesen Punkt y aus Zeile 25, um dem
Java-Skript mitzuteilen , wo auf der Leinwand
wir das Bild zeichnen wollen. Jetzt zeichnen wir die
gesamte Tabelle
an diesen X- und Y-Koordinaten. Wir können uns mit den
Pfeiltasten bewegen. Aufgrund der Logik, die
wir zuvor geschrieben haben, ist
es sicherer, hier Get
Element by ID zu verwenden. Also lass es uns tun. Ich verwende
dieses Punktbild hier. Okay, das funktioniert immer noch. nett, eine Tabelle zu
animieren Wir müssen die Abmessungen
eines einzelnen Animationsframes
innerhalb dieser Tabelle kennen eines einzelnen Animationsframes
innerhalb dieser Tabelle kennen Ich werde diese in
separate Variablen einfügen. Ich nenne den
ersten Sprite Breite und setze ihn auf 200 Pixel Die Sprite-Höhe wird
ebenfalls 200 Pixel betragen. Wenn Sie ein
anderes Spritesheet verwenden, können
Sie die
Spritebreite berechnen, indem Sie die Breite
des gesamten
Spritesheets durch die Anzahl der
Spalten dividieren Sprite-Höhe ist die Höhe
des gesamten Spritesheet-Bilds geteilt durch In diesem Fall entsprechen die Eigenschaften Breite und
Höhe den
Eigenschaften der
Sprite-Breite und Sprite-Höhe könnte jedoch sinnvoll sein
, sie
getrennt zu halten , da
wir dann hier die
Skalierung verwenden oder
die Größen nach dem Zufallsprinzip anordnen können , ohne dass
sich dies auf diese Werte auswirkt, die
immer gleich bleiben müssen Um
einzelne Frames korrekt aus
dem Spritesheet auszuschneiden , gibt es drei Versionen von
Draw-Image Die erste Version
erwartet drei Argumente, das
haben wir gerade
hier in Zeile 35 gemacht Die zweite Version
benötigt fünf Argumente, optional
definieren das vierte und
fünfte Argument die Breite und Höhe des und
das Bild wird gestreckt oder zusammengedrückt, um es an diese Abmessungen
anzupassen Jetzt drücke ich die
gesamte riesige Tabelle eine Fläche von 200
mal 200
Pixeln Die dritte Version der Methode Draw
Image erwartet, dass neun Argumente uns
die größtmögliche Kontrolle über das
Bild geben , das wir zeichnen möchten Das ist die Version, die wir
verwenden müssen, um unsere Tabelle zu animieren Diese neun Argumente sind
das Bild, das wir zeichnen wollen. Quelle x, Quelle
Y, Quellbreite und Quellhöhe, der Bereich wir
aus dem Quellbild ausschneiden möchten. Die letzten vier Argumente nennen
wir Ziel X, Ziel Y,
Zielbreite und Zielhöhe. Dadurch wird definiert,
auf welche Stelle auf der Leinwand wir das
ausgeschnittene Bild zeichnen möchten das
ausgeschnittene Bild zeichnen Nehmen wir an, ich möchte nur den oberen
linken Eckrahmen
ausschneiden Ich werde von der
Koordinate 00 auf die Sprite-Breite zuschneiden. Und die
Sprite-Höhenwerte haben wir so eingestellt, dass sie exakt der Größe eines einzelnen Frames in
unserer Tabelle entsprechen, in diesem Fall 200 mal 200
Pixel Schön, wir verwenden die
Draw-Image-Methode , um einen einzelnen Frame auszuschneiden Ich kann die
Sprite-Breite hier auch mit
einer Zahl und die
Sprite-Höhe multiplizieren . Jetzt habe ich eine Möglichkeit, auf
dem Spritesheet von
Frame zu Frame 00 zu Ist das 1100? Ist das
1200? Ist das ein Rahmen? Diese Nummer navigiert
horizontal. Diese andere Zahl bestimmt , in welcher Zeile des
Spritesheets wir uns befinden Sie können sehen, dass wir
jedes Mal, wenn ich diese Zahl ändere, zu
einer anderen Animationszeile springen können einer anderen Animationszeile jedes Mal, wenn ich diese Zahl ändere Ich werde diese Werte in die
Klasseneigenschaften einfügen . Frame X
kümmert sich um die horizontale
Sprite-Navigation Frame Y ist für die
vertikale Sprite-Navigation vorgesehen. Auch hier gilt: Wenn Frame X
und Frame Y den Wert 00
haben, wird der
obere linke Frame angezeigt Ich kann diese Werte ändern, um in der Tabelle zu
springen. Jetzt, wo wir verstehen, wie
diese Argumente an die Methode
zum Zeichnen von Bildern übergeben wurden , einzelne Frames
ausschneiden, können
wir
unsere Tabelle animieren und diesen mächtigen
Eulenbären
wirklich zum Leben erwecken Beginnen wir damit, nur
eine einzelne Zeile für jeden
Animationsframe eine einzelne Zeile für jeden Wenn Frame X kleiner
als Max Frame ist, entspricht Max Frame in diesem Fall der Anzahl der
Frames pro Zeile, 30. Wenn Frame X kleiner als 30 ist, erhöhen
Sie
Frame X immer wieder um ein L,
was bedeutet, dass es gleich
oder mehr als 30 ist Setzen Sie Frame X wieder auf Null zurück,
damit es erneut wiederholt werden kann. Gut, wir animieren diese Zeile, weil wir hier
Frame Y auf drei setzen Wenn ich ihn auf Null setze, animieren
wir diese Zeile Ändere ich diese Zahl, animieren
wir verschiedene Zeilen Wir wollen diese
Animationszeilen in Abhängigkeit von zwei Dingen austauschen Animationszeilen in Abhängigkeit von zwei Dingen In welche Richtung geht
der Spieler und geht der Spieler
oder steht er einfach? Wenn wir einen komplexen Charakter
mit mehreren
Angriffszügen usw. hätten , würde
ich vorschlagen, hier
ein State-Design-Muster zu erstellen, wie ich es in der
Endless Runner-Klasse getan habe. In diesem Fall ist die Bewegungs
- und Animationslogik einfach genug, um
hier innerhalb der Aktualisierungsmethode behandelt zu werden. Wir können es später jederzeit auf
ein State-Entwurfsmuster erweitern , wenn wir beschließen,
weitere Spielerzüge hinzuzufügen. Lassen Sie mich Ihnen zeigen,
dass wir hier die
Spielergeschwindigkeit danach einstellen , welche der vier Pfeiltasten nach links, rechts, oben oder unten
gedrückt wurde . Lass uns diesen Codeblock kopieren. Seien Sie hier sehr
vorsichtig mit Klammern, es ist leicht, eine zu übersehen
und Ihren Code zu beschädigen. Wenn Sie sich erinnern,
verfolgen wir
hier oben die Tasten, die
gedrückt und losgelassen wurden. Gedrückte Tasten beginnen
mit Großbuchstaben P, losgelassene Tasten beginnen
mit Großbuchstaben R. Wie machen wir das? Ich
denke, das sollte funktionieren. Wenn wir die linke Pfeiltaste drücken, möchten
wir diese Zeile animieren Dieser Punktrahmen Y entspricht
drei bewegten linken
Animationszeilen Wenn wir den Pfeil
nach links auf diese Weise loslassen, setzen
wir Frame y22 Wir wollen einfach untätig
links stehen. Lass es uns testen. Ich muss die Geschwindigkeit auf
00 setzen, wenn wir hier veröffentlichen. Das ist besser, wenn wir die Pfeiltaste
drücken, oder? Ich möchte das
Gehen animieren, richtig,
diese Reihe, dieser
Punktrahmen ist fünf Ich kopiere dieses LF,
vorsichtig mit Klammern. Wir wechseln hier zu R, wenn wir die Pfeiltaste und die rechte Taste
loslassen. Wir setzen die Geschwindigkeit auf 00. Und wir stellen Frame
Y24, Idle, richtig ein. Animation. Perfekt. Wir haben einen Charakter, der nach links und rechts
gehen kann,
und die Logik, die wir gerade geschrieben sich
korrekt in
der Tabelle Wir gehen und
wir stehen. Der Player ist animiert
und
reagiert korrekt auf
Tastatureingaben. Gute Arbeit. Lassen Sie uns das auch für
vertikale Bewegungen, Aufwärts- und Abwärtsbewegungen tun. Wenn wir die Pfeiltaste nach oben drücken, soll der Spieler
um sieben
vom Kamerarahmen weggehen . Ich kopiere diesen Codeblock. Wenn wir den Aufwärtspfeil loslassen, animieren wir Frame Y 6 und setzen die Geschwindigkeit auf 00 Wir können nach links gehen, gleich hier oben. Wenn wir die Pfeiltaste nach unten drücken, möchten
wir Bild Y eins animieren Ich kopiere diesen Codeblock. Wenn wir den Pfeil nach unten loslassen, animieren
wir Frame Y auf Null
und setzen die Geschwindigkeit auf Null Wir laufen und animieren
in vier Richtungen. Wir wechseln für
jede dieser Richtungen korrekt
zwischen Steh- und Gehanimation Tolle Arbeit, um
eine Vorstellung von Tiefe
zu erzeugen , sodass es sich
anfühlt, als würde der Spieler
weggehen und sich der Kamera
nähern Wenn ich auf und ab gehe, werde
ich dafür sorgen, dass es sich auf dieser Achse
etwas langsamer bewegt. Schau, wie viel
Unterschied das macht. Es fühlt sich an, als ob
es mehr Tiefe gibt, ob der Hintergrund weiter
von der Kamera entfernt ist als
der Vordergrund. Wir laufen mit normaler
Geschwindigkeit, links, rechts? Aber auf und ab
gehen wir etwas langsamer. Lassen Sie uns die Höchstgeschwindigkeit auf fünf ändern. Das ist eine große, schwere Kreatur. Es sollte sich langsamer bewegen. Ich kommentiere das schwarze Rechteck
aus, wir brauchen es momentan nicht. Das gefällt mir wirklich. Wir haben eine Basis für so viele
verschiedene Spiele. Jetzt brauchst du nur noch
deine kreativen Ideen. Damit können wir so viele verschiedene
Dinge machen. Je mehr Sie über
Java Script Canvas
und die Spieleentwicklung erfahren , desto einfacher wird
es, diese Ideen tatsächlich in eine
funktionierende Codebasis umzusetzen. Lass mich dir mehr zeigen. Ich hoffe, Sie
profitieren heute davon. Lass mich in den Kommentaren wissen,
wenn du etwas
Neues lernst , denn wir verwenden nur die letzte Taste, die
gedrückt oder losgelassen wurde, um den Spielercharakter zu
steuern. Es gibt ein
häufiges Problem : Wenn wir
in eine Richtung gehen, sagen
wir, ich gehe nach rechts, drücke
ich die linke Pfeiltaste. Der Spieler dreht sich nach links und erst dann lasse ich die rechte Pfeiltaste los. Die letzte Taste wird nach rechts losgelassen.
Dadurch
hält der Spieler kurz an, bevor kontinuierliches Halten
der linken Taste er durch
kontinuierliches Halten
der linken Taste wieder nach links läuft. Du kannst es versuchen und du wirst
feststellen, dass wir
dieses Problem in jeder
Richtung haben werden , geh irgendwohin. Und wenn Sie eine
andere Richtungstaste drücken bevor Sie
die vorherige
loslassen, hält der Spieler
eine Weile an, bevor er sich weiter in
diese neue Richtung bewegt. Das zu beheben ist einfach. Wenn wir den Pfeil nach links loslassen. Wir möchten, dass dieser Code nur ausgeführt wird, wenn Geschwindigkeit der
Spieler unter Null liegt. Stoppen Sie den Player nur dann und
lassen Sie ihn im Leerlauf nach
links animieren , wenn die
Geschwindigkeit des aktuellen Spielers kleiner als Null ist, wenn sich der Spieler gerade nach links
bewegt Auf diese Weise können wir nur aus dem Zustand
Gehen
nach links in den Leerlauf wechseln Wenn wir die rechte Pfeiltaste loslassen, wollen
wir nur die
Bewegungsgeschwindigkeit stoppen und den Leerlauf
animieren, oder? Wenn sich der Spieler gerade
nach rechts bewegt, wenn seine Geschwindigkeit x größer
als Null ist Ich muss auch
diese L-Anweisung hier entfernen. Und jetzt beheben wir das Problem
für Links- und Rechtsbewegungen. Lassen Sie uns dasselbe
für Auf- und Abwärtsbewegungen tun. Führen Sie diesen Code nur aus, wenn
wir den Aufwärtspfeil loslassen und gleichzeitig die Bewegungsgeschwindigkeit Y des
Spielers
kleiner als Null ist , wenn wir den Pfeil nach unten
loslassen. Führe diesen Code nur aus, wenn gleichzeitig Geschwindigkeit
Y größer als Null ist. Nur wenn der Spieler zur Kamera
hinuntergeht. Jetzt bewegen wir uns und die Panne ist
weg. Gut gemacht.
44. So steuerst du FPS: Wenn ich die Höchstgeschwindigkeit auf
zwei setze, bewegt sich der Spieler langsam, aber die
Sprite-Animation zeigt Frames an, so schnell sind, dass der Spieler im Mondlauf
ist. Die Füße werden auf
eine Weise animiert, die nicht Bewegungsgeschwindigkeit
entspricht,
und das sieht sehr schlecht aus Eine Möglichkeit,
dieses Problem zu lösen, besteht darin, manuell zu steuern, wie schnell das
Spritesheet Im Moment stellen wir nur einen neuen
Animationsframe pro Bei jeder Anfrage wird ein
Animationsframe aufgerufen. Lassen Sie uns eine Funktion erstellen
, mit der wir
FPS-Frames pro Sekunde manuell
für die Animationsgeschwindigkeit
unseres Spritesheets festlegen FPS-Frames pro Sekunde für die Animationsgeschwindigkeit
unseres Spritesheets Das kann
global gemacht werden und wir können FPS für das gesamte Spiel
einstellen Oder wie ich Ihnen jetzt zeigen werde, können
Sie FPS individuell
für das Spielerobjekt einstellen. Vielleicht werden wir
später einige Gegner haben , die
unterschiedliche Spritesheets haben werden Und wir möchten vielleicht
, dass diese Spritesheets mit
unterschiedlicher Geschwindigkeit animiert werden Standardmäßig passt sich der
Animationsframe der Anfrage an
die Bildschirmaktualisierung
an Bewerten. Unser Spiel
läuft schneller bei Bildschirmen mit hoher
Bildwiederholfrequenz, wie den neuen Gaming-Bildschirmen. Wenn
wir möchten
,
dass ein Animationsframe
eine spezielle Funktion hat, bei der er bei jedem Aufruf der Animationsfunktion einen
Zeitstempel
generiert
und diesen Zeitstempel als Argument
an die aufgerufene Wenn
wir möchten
,
dass Animationsframe
eine spezielle Funktion hat, bei der er bei jedem Aufruf der Animationsfunktion einen
Zeitstempel
generiert Aufruf der Animationsfunktion einen
Zeitstempel Animationsfunktion weitergibt Animationsfunktion Verwenden wir es, um
Millisekunden zwischen Frames zu zählen,
sodass wir unsere eigenen
FBS-Frames pro Sekunde einstellen können Ich erstelle eine Variable, die
ich beim letzten Mal aufgerufen habe. Sie befindet
sich außerhalb der
Animationsschleife sich außerhalb der
Animationsschleife Anfangs habe ich es auf Null gesetzt. Es wird den Wert des
Zeitstempels aus der
vorherigen Animationsschleife enthalten Zeitstempels aus der
vorherigen Animationsschleife Damit wir
aktuelle und alte Zeitstempel vergleichen
und feststellen können , wie viele
Millisekunden Der Wert wird Deltazeit genannt. Deltazeit ist die Anzahl der Millisekunden, die zwischen
dem Zeitstempel
dieser Animationsschleife
und dem Zeitstempel der
vorherigen Animationsschleife vergangen dem Zeitstempel
dieser Animationsschleife
und dem Zeitstempel der
vorherigen Animationsschleife und dem Zeitstempel der
vorherigen berechnen Wir wissen, dass wir diese Zeitstempel
vergleichen müssen, um die Deltazeit zu Zeitstempel der
vorherigen Schleife wird
hier in der Variablen für die letzte Zeit gespeichert Zunächst setzen wir ihn auf Null, bevor wir mit der
Generierung von Zeitstempeln beginnen Wie gesagt, der
Anforderungsanimationsframe übergibt das automatisch generierte
Zeitstempelargument an
die aufgerufene Funktion Wenn Sie ein Anfänger sind,
stellen Sie sich vor,
dass es generiert und hier so
übergeben An dem Punkt, an dem der
Anforderungsanimationsframe diese Funktion
auslöst, weisen
wir dem automatisch generierten
Zeitstempel einen Variablennamen Hier nenne ich es einfach
Zeitstempel, geschrieben mit einem Großbuchstaben S. Lassen Sie uns das
auskommentieren und den Zeitstempel konsoloc Nur damit ich sehen kann, welches
Format wir bekommen, können
Sie sehen, dass
es Millisekunden sind können
Sie sehen, dass
es Millisekunden Der erste Wert ist buchstäblich
die Anzahl der Sekunden seit dem Start
der Schleife Das ist der Zeitstempel, den ich lösche. Die Consolo-Delta-Zeit
ist der Zeitstempel dieser Animationsschleife abzüglich des
letzten Zeitstempels aus Zeile 113, die immer
einen Wert für Zeitstempel der
vorherigen Animationsschleife enthält Nachdem wir die Deltazeit berechnet
haben, setzen wir beim letzten Mal den Zeitstempel Damit dieser neue Zeitstempel
aus dieser Schleife als
alter Zeitstempelwert in der
nächsten folgenden Animationsschleife verwendet werden kann alter Zeitstempelwert in der
nächsten folgenden Animationsschleife Jetzt haben wir Delta-Zeit. Sie sagt uns, wie viele
Millisekunden
unser Computer benötigt , um
einen Animationsframe bereitzustellen Mein Bildschirm wird mit
etwa 60 Bildern pro Sekunde aktualisiert. Meine Deltazeit liegt bei etwa
16,6 Millisekunden. Das ist perfekt. Bekommen Sie dieselbe Delta-Zeit oder
erhalten Sie einen völlig
anderen Wert? Lass es mich in einem Kommentar wissen. Dies hängt von
der Bildwiederholfrequenz
Ihres Bildschirms und teilweise auch von der Leistung
Ihres Geräts ab. Schwächere Maschinen
haben eine höhere Deltazeit. Sie können sehen, dass hier die ersten Deltazeitwerte keine
sind, keine Zahl. Da wir Animate
hier in der ersten Schleife zuerst ausführen, ist
dieser Zeitstempel undefiniert Bisher wurde kein
Animationsframe-Aufruf
zur automatischen Generierung angefordert Animationsframe-Aufruf
zur automatischen Damit wir das beheben können, muss
ich sicherstellen, dass
ich ihm den ersten
Zeitstempel übergebe, nur um zu vermeiden, in der Anfangsschleife
kein Wert, kein Zahlenwert ist. Andernfalls könnte es später
zu Problemen kommen je nachdem, wie Sie Ihre Delta-Zeitwerte
verwenden möchten. Der anfängliche Zeitstempel wird Null sein. Sie können sehen, dass die Werte zunächst
überall sind, aber dann
pendeln sie sich schnell bei etwa 16,6 ein, während unsere
Animationsschleife immer wieder läuft Das ist ideal. Ich
lösche die Konsole und übergebe diesen Delta-Zeitwert an die Render-Methode der Spielklasse Ich stelle sicher, dass der Wert hier erwartet
wird und ich kann ihn
überall in unserem Spiel weitergeben Jetzt wo immer wir ihn brauchen. Ich übergebe es an die Update-Methode der
Alber-Klasse , weil
wir die
Deltazeit verwenden wollen, um
FPS-Frames pro Sekunde
der Sprite-Animation zu steuern FPS-Frames pro Sekunde
der Sprite-Animation Dort übergebe ich die
Deltazeit an die
Aktualisierungsmethode und muss
sicherstellen, dass sie erwartet wird Hier in Zeile 44
befinden wir uns
jetzt in der Alber-Klasse und wir können den
Delta-Zeitwert
hier für so viele
verschiedene Dinge verwenden hier für so viele
verschiedene Dinge Um die FPS der
Sprite-Animation zu kontrollieren, erstelle
ich drei
Hilfsvariablen,
Klasseneigenschaften, FPS wird 30 sein Lassen Sie uns versuchen, 30 Bilder
pro Sekunde zu animieren und zu sehen,
wie das aussieht Das Frame-Intervall beträgt 1.000
Millisekunden geteilt durch 30. Dies bestimmt, wie viele
Millisekunden vergehen müssen bevor wir zum nächsten
Bild im Spritesheet wechseln Der Frame-Timer wird der Zähler sein. Delta-Zeit Während unsere
Animationsschleife läuft, sammelt er immer wieder Wenn der Wert
und das Frame-Intervall erreicht sind und genügend Millisekunden angesammelt
haben, lösen
wir In diesem Fall werden wir
den nächsten Animationsframe bereitstellen. Dieselbe Technik kann auch
verwendet werden , um dem Spiel einen neuen
Feind
oder ein anderes Ereignis hinzuzufügen , das in einem
bestimmten Intervall
stattfinden soll . Das ist eine wichtige
Technik, die es zu verstehen gilt. Lassen Sie uns die Logik schreiben und sie
erklären, wenn wir den Code sehen. Es sind nur ein paar kurze Zeilen. Ich möchte nur
diesen Code ausführen, der
zwischen Sprite-Frames wechselt, wenn
genügend Millisekunden vergangen Wenn der Frame-Timer länger
als das Frame-Intervall ist, animieren Sie das
Spritesheet erst dann Andernfalls erhöhen Sie den
Frame-Timer immer weiter um die Delta-Zeit. Dieser Code animiert die
Tabelle von hier aus. Wenn dies ausgelöst wird, setzen
wir auch Frame-Timer auf Null zurück,
sodass er
wieder bis zum
nächsten periodischen Ereignis
in der Animationsschleife zählen kann wieder bis zum
nächsten periodischen Ereignis
in der Animationsschleife Wir berechnen die Deltazeit, die Differenz zwischen dem
Zeitstempel der
aktuellen und der vorherigen
Animationsschleife Deltazeit ist die Anzahl
der Millisekunden, die
unser Computer benötigt , um
einen Animationsframe bereitzustellen Der Frame-Timer beginnt
bei Null und fügt immer mehr
Deltazeit hinzu, während die Animationsschleife läuft, bis das Frame-Intervall überschritten
wird Frameintervall
ist der Grenzwert,
dessen Erreichen unser periodisches Ereignis auslöst Wenn wir ihn erreichen, kümmern wir uns um Sprite-Animation und
setzen den Frame-Timer wieder auf
Null zurück , sodass er wieder für den nächsten regelmäßig
ausgegebenen Animationsframe gezählt werden kann den nächsten regelmäßig
ausgegebenen Animationsframe Ich weiß, das war viel, aber diese Technik
ist sehr wichtig Es wird
leicht zu verstehen , wenn Sie es häufiger verwenden. Vertrauen Sie mir jetzt, der Charakter
animiert langsamer, nur das Tauschen der Sprites und nicht die tatsächliche
Bewegungsgeschwindigkeit auf der Sie können wirklich sehen
, dass, wenn ich FPS auf zwei Bilder pro Sekunde setze, es bei 60 FPS immer noch reibungslos über die
Leinwand gleitet Aber wir drosseln, wie schnell die nächsten Frames in
Spritesheets bereitgestellt werden Hoffe, das macht den Unterschied deutlich
. Ich kann andere Werte als FPS ausprobieren. Ich muss hier
ein bisschen experimentieren und den richtigen Wert
finden
, damit sich der Lex mit der Geschwindigkeit
bewegt, die sich
natürlich anfühlt, wenn sich der Spieler
über das Grasgelände bewegt. 50 rutscht immer noch etwas ab. 60, wir berücksichtigen eigentlich
nicht
jedes Mal, wenn wir
unser periodisches Ereignis auslösen,
übrig gebliebene Werte der Delta-Zeit wenn wir
unser periodisches Ereignis auslösen,
übrig gebliebene Werte der Delta-Zeit Obwohl ich 60 FPS gesagt habe, wären
die tatsächlichen FPS weniger als Für die Zwecke eines
solchen Projekts ist das völlig in Ordnung. Wir haben einen Wert, den wir erhöhen
und verringern können , um die
Sprite-Animation zu steuern Es erfüllt seinen Zweck gut. Ich kann diese
Codezeile vereinfachen und den
ternären Operator verwenden , um all
dies in eine einzige Zeile zu schreiben Lass mich dir zeigen, dass es einfach ist. ternäre Operator ist der einzige Java-Script-Operator
mit drei Operanden Wir werden ihn als
einfache einzeilige
L-Anweisung verwenden, wenn wir eine Bedingung zur Auswertung haben Wir prüfen, ob Frame X
kleiner als der maximale Frame ist. Wenn es ein Fragezeichen ist, erhöhen Sie Frame X um eins, L setzt Frame X wieder auf Null zurück. Jetzt macht diese einzelne
Codezeile dasselbe wie diese
mehrzeilige L if-Anweisung. Sie können beide Syntaxen verwenden.
Ich wollte es dir nur zeigen.
45. Zufällig positionierte Spielobjekte: Lassen Sie uns einige
Objekte erstellen und
sie nach dem Zufallsprinzip in
der Spielwelt verteilen . Ich erstelle eine Klasse, ich nenne sie Objekt. Wie üblich erwartet sie einen Verweis auf das
Hauptspielobjekt aus Zeile 111 als Argument dafür , dass wir Zugriff auf
alle wichtigen Eigenschaften haben. Von dort aus konvertieren wir diese
Referenz in eine Klasseneigenschaft. So wie wir es zuvor getan haben. Draw-Methode, wir erwarten
Kontext als Argument. Im Inneren rufen wir die eingebaute
Draw-Image-Methode auf. Ich möchte Ihnen zeigen, wie Sie
Klassen erweitern und die
Vorteile der Vererbung nutzen können, die eines der
Hauptprinzipien
der objektorientierten Programmierung ist . Wie wir es verwenden können, um die Wiederholung von Codes zu
reduzieren. Ich erstelle eine Klasse
namens Busch, die die Objektklasse
ab Zeile 102
erweitert Sie wird auch einen
Konstruktor haben. Ich erstelle eine weitere Klasse. Ich nenne Pflanze
noch eins, ich nenne Gras. Wir haben die Hauptobjektklasse. Wir haben drei Klassen, Bush, Plant und Grass, die diese Objektklasse
erweitern. Das Objekt ist eine sogenannte
Elternklasse, auch Superklasse genannt Bush, Plant und Grass
sind untergeordnete Klassen, auch Unterklassen genannt Wenn ich eine Eigenschaft oder Methode
innerhalb einer dieser
untergeordneten Klassen verwende , ist
diese Eigenschaft in dieser Unterklasse nicht
definiert Java-Skript
sucht automatisch übergeordneten Klasse,
im Objekt, danach Auf diese Weise kann ich
diese Draw-Methode nur auf einmal definieren. Und alle untergeordneten
Klassen, die
diese übergeordnete Klasse erweitern , haben
automatisch Zugriff darauf, sie erben diese Methode Wir können etwas Ähnliches
mit Eigenschaften innerhalb des
Konstruktors tun , indem wir das Super-Schlüsselwort verwenden das
ich Ihnen gleich zeigen werde Objektklasse enthält
alle Eigenschaften und Methoden, die von
allen untergeordneten Klassen gemeinsam genutzt Busch, Plant und Grass
werden Eigenschaften enthalten , die nur für
diese bestimmte Unterklasse spezifisch sind Beispielsweise hat jede Unterklasse
ein anderes Bild, aber alle geben dieses
unterschiedliche Bild
ab 907 an dieselbe Zeichenmethode weiter. Lass es uns machen Bevor ich
dieses Schlüsselwort im Konstruktor der
untergeordneten Klasse verwenden kann , muss der Konstruktor für
seine übergeordnete Klasse
ausgelöst Wenn ich hier super sage, bedeutet das, dass ich
einen Konstruktor der
übergeordneten Klasse ausführen möchte einen Konstruktor der
übergeordneten Klasse Die übergeordnete Klasse wird auch
als Superklasse bezeichnet. Zeile einhundert drei kann
ich sehen, dass der
Objektklassenkonstruktor Spiel als Argument
erwartet Ich gebe diese Referenz
weiter, während
ich sie gleichzeitig in eine
Klasseneigenschaft der Bush-Klasse umwandle. So übergebe ich in der Shared Draw
Image-Methode die Befehle did image didot x und dis.yi kann ihr auch
distwidth und distot height geben Wenn ich die
Bilder so skalieren möchte, wie Sie sehen können, keines davon in dieser Klasse vorhanden Ich möchte, dass jede Unterklasse ein anderes Bild
hat, und wir müssen die Größe
dieses Bildes kennen , um
seine zufällige Position zu berechnen Ich muss
all diese Eigenschaften jeder Unterklasse
separat Fangen wir mit
Bush an. Bei diesem Punktbild wird das Dokument nach der ID nach Punkt
abgerufen. Hier in Index-HTML muss
ich dieses
Bildelement wie gewohnt erstellen Sie können die Bilder im
Abschnitt
Projektressourcen unten herunterladen . Ich lege es hier hin, die ID wird Bush sein, eine
andere mit
einer Pflanzen-ID wie dieser. Das letzte wird
Gras im Stil von CSS sein. Ich verwende ihre IDs, um diese Bilder zu
verstecken. Wir wollen sie auf Leinwand zeichnen, nicht als tatsächliche
Bildelemente auf der Webseite. Die ID ist Bush. Ich dupliziere diese Code-ID. Hier wird geplant
und hier Gras. Ich versuche, die
Benennung einfach und sauber zu halten. Ich
möchte die Bilder nicht wirklich skalieren,
aber wenn wir die Option zum Skalieren offen lassen wollen, ist es
vielleicht besser, wenn ich die
Bildbreite und die
Eigenschaften zum Ausblenden von Bildern getrennt definiere . Auch wenn sie zu diesem Zeitpunkt den gleichen Wert haben
werden. Ich habe die Bilder bereits so dimensioniert, dass dieselbe Größe haben, wie wir sie auf Leinwand
zeichnen werden, was eine gute Praxis ist. Das Bush-Bild hat 216.100 Pixel. Ich könnte
diese Eigenschaften auch in
einer Zeile wie dieser definieren .
Es liegt an dir. horizontale Position ist ein zufälliger Wert zwischen Null und der Breite des Spielbereichs abzüglich der Breite
des Bildes selbst. Dies wird wahrscheinlich
einige Anpassungen erfordern. Mal sehen, die vertikale Y-Position
beginnt nicht bei Null, sondern am oberen Rand. Und von dort aus ein zufälliger Wert zwischen Null und der Höhe des
Spielbereichs abzüglich der Höhe des
Bildes abzüglich des oberen Randes. Ich denke, wenn wir
anfangen, sie zu zeichnen werden
wir sehen, ob ich hier Anpassungen
vornehmen muss. Lass es uns testen.
In der Hauptspielklasse erstelle
ich eine Eigenschaft
namens Number of Plants. Lassen Sie uns zehn zufällig
positionierte Pflanzenobjekte erstellen. Ich erstelle eine initialisierte Methode
, die beim Laden
der ersten Seite nur einmal ausgeführt wird und die Objekte
zufällig darin positioniert Ich erstelle eine Viererschleife. Es wird zehnmal laufen. Jedes Mal, wenn es läuft, erstellen
wir eine Pflanze. Ich erstelle hier ein leeres
Array, das alle Pflanzenobjekte aufnehmen
wird. Jedes Mal, wenn die vier Schleifen laufen, nehme
ich dieses Plants-Array, ich, neue Bush-Objekt
in Zeile 111, und
ich kann sehen, dass der
Bush-Klassenkonstruktor ein Spiel als Argument
erwartet Ich gebe ihm dieses Schlüsselwort, weil wir uns hier in dieser
Spieleklasse befinden Nachdem ich eine Instanz
der Spieleklasse 160 erstellt
habe, kann ich diese Init-Methode aufrufen Sie läuft und füllt
das Plants-Array mit zehn zufälligen
Instanzen der Bush-Klasse Wenn ich
sie auf Leinwand anzeigen möchte, muss
ich
ihre Draw-Methode aufrufen Ich werde es innerhalb von Render machen. Ich nehme Pflanzen und rufe für jedes
Pflanzenobjekt innerhalb des Arrays die zugehörige
Zeichenmethode aus Zeile 106 auf. Diese Methode erwartet Kontext. Ich gebe es diese
Kontextreferenz weiter. Toll, ich zeichne zehn
zufällig positionierte Büsche. Ich gehe hier hoch und kopiere
all diese Eigenschaften, die für die Bush-Klasse spezifisch
sind, und ich kopiere sie hier
in die Pflanzenklasse. Ich überprüfe, ob die Breite des Bildes
212 Pixel und die Höhe 118 Pixel beträgt. Ich kopiere es erneut und die
Grasbreite 103 und die
Höhe 183 Pixel. Gut, wir haben eine
übergeordnete Objektklasse definiert in der wir alle gemeinsamen
Eigenschaften und Methoden platzieren können, und drei Unterklassen namens Bush Plant und Grass, die die übergeordnete Klasse
erweitern Um schnell zu überprüfen, ob
diese Klassen funktionieren, kann
ich einfach den
Klassennamen hier in Zeile 168 austauschen Gras arbeitet,
Plant arbeitet. Wie können wir
sie randomisieren und kontrollieren , welcher Teil dieser zehn zufällig generierten
Pflanzen Busch-,
Gras- oder Pflanzenobjekte sein wird Gras- oder Pflanzenobjekte Eine einfache Möglichkeit, dies zu tun,
besteht darin, eine Variable zu erstellen. Hier nenne ich zum
Beispiel Randomize. Es wird
Mathodtrandom entsprechen. Wir wissen, dass ein
Zufallscode wie dieser für sich genommen einen Zufallswert
0-1
zurückgibt. Nehmen wir an , ich möchte ungefähr 30% dieser Objekte
Instanzen der Klasse Plant sind dieser für sich genommen einen Zufallswert
0-1
zurückgibt. Nehmen wir an, ich möchte, dass
ungefähr 30% dieser Objekte
Instanzen der Klasse Plant sind. Ich sage, wenn zufällige Größe kleiner als 0,3 L
ist, wenn Randomize kleiner als
0,6 ist , wenn die Mathematik nach dem
Zufallsprinzip zwischen
0,3 und 0,6 rollt , erzeugen wir eine
Instanz der Bush-Klasse L, das
heißt, wenn Maat
random zwischen 0,6 und eins würfelt, Das funktioniert nicht,
weil das innerhalb der
Vierer-Schleife
sein muss , weil wir jedes Mal rollen
wollen , wenn wir ein neues Objekt
erstellen, nicht nur einmal
für alle zehn Objekte rollen
46. Layering und Zeichenfolge in 2D-Spielen: Perfekt. Wir erweitern
eine Klasse, um drei verschiedene zufällig
positionierte Spielobjekte zu erstellen. Gute Arbeit. Wie Sie sehen können, ergibt die Art und Weise, wie diese Objekte positioniert
werden und wie das Spiel die Schichten überlagert, visuell nicht wirklich
Sinn Eulenbär wird zuerst
auf Linie 162 gezeichnet und dann werden
alle Pflanzen gezogen, nachdem Pflanzen immer
auf einem Bären Wenn ich das vertausche, dann sind die Pflanzen immer
hinter dem Bären Da wir alles
auf demselben Leinwandelement zeichnen , liegt das, was
zuerst gezeichnet wird, dahinter, und was danach gezeichnet wurde,
ist davor oben. Ich möchte Objekte in
einer bestimmten Reihenfolge zeichnen , die auf
ihren vertikalen Positionen basiert. Genauer gesagt, basierend auf der vertikalen Position
ihrer Unterkante. Weil jedes Objekt
eine andere Höhe hat , um sicherzustellen, dass sie logisch und visuell sinnvoll ausgerichtet
sind. Und damit unser Charakter um
sie herum laufen und sich vor
und hinter den Objekten befinden
kann . Gegebenenfalls versuchen
wir, eine virtuelle Welt zu simulieren , in der Pflanzen
aus dem Boden wachsen. Und wo dieser
Eulenbär jederzeit
auf festem Boden läuft , auch wenn er auf und ab geht Die Schichtung muss optisch dazu
passen. Es ist eigentlich sehr
einfach, das zu erreichen. Ich muss nur sicherstellen
, dass sich all diese Objekte, also alle Bären- und alle
Pflanzenobjekte, in derselben Anordnung
befinden. Damit ich sie nach
ihrer vertikalen Position sortieren kann. Ich erstelle ein weiteres Array, das als Spielobjekte
bezeichnet wird. Jedes Mal, wenn die Render-Methode ausgeführt wird, füge
ich das Alber-Objekt ein. Ich verteile alle Objekte von den gesamten Pflanzen in diesen
Array-Spread-Operator ihn so verwenden, können wir ein Array
in ein anderes
erweitern. In diesem Fall macht es
wenig Sinn, dies jedes
Mal zu tun, wenn die Rendermethode
für jeden Animationsframe aktiviert wird. Da wir nur Alber
und zehn statische Pflanzen haben, hätten
wir diese Methode
intern init Es wäre einfach
sinnvoll, dies
regelmäßig zu tun, um
dieses Array immer wieder zu erstellen Wenn wir mehr Objekte haben, die wieder hinzugefügt und
entfernt werden, zum Beispiel Feinde oder
Power-Ups, die kommen und gehen. Jetzt haben wir Alber, alle zehn Pflanzen auf derselben
Ebene innerhalb derselben Reihe Ich kann dieses Array für jedes Objekt in der Objekt-Reihe
des Spiels verwenden Ich nenne ihre Draw-Methode. Wenn wir das tun und
verschiedene Objekttypen zu einem
einzigen Array kombinieren , müssen
wir sicherstellen, dass für
all diese Objekte tatsächlich Zeichenmethoden in ihren Klassen
definiert sind. Vorsicht bei Klammern
Hier kann ich diesen Code löschen. Ich muss die
Update-Methode aufrufen und ihr die Delta-Time übergeben. Sonst werde ich es ertragen,
mich nicht bewegen oder beleben. Wenn ich Update so aufrufe, zeichnen und aktualisieren
wir alle Bären Wenn ich versuche, die erste von
zehn Pflanzen zu zeichnen und zu
aktualisieren, wird
sie gezeichnet, aber es gibt keine Aktualisierungsmethode,
sodass wir eine Fehlermeldung erhalten. Ich muss der
Objektklasse eine Update-Methode hinzufügen , damit
dieser Code ausgeführt werden kann. Wir
aktualisieren die Objekte nicht wirklich, aber hier können wir
einige Animationen haben. Zum Beispiel können sich Büsche und Gras bewegen, wenn der
Spieler sie berührt Dieser Code würde
innerhalb dieser Aktualisierungsmethode behandelt. Ich lasse es vorerst leer. Jetzt haben wir das
Gleiche wie zuvor, aber alle Elemente, die dynamisch geschichtet
werden müssen, werden aus dem Objektfeld
des Spiels gezogen und aktualisiert. Alle Bären stehen an erster Stelle in der Reihe. Deshalb wird es vor Pflanzen
gezogen. Pflanzen werden darauf gemalt. Wenn ich sie vertausche, sind die
Pflanzen hinten und ein Aulber
wird als letztes oben drauf gezogen Weil das die
Reihenfolge ist, in der für
jede Methode die Objektgruppe des
Spiels durchläuft. Um ihre Zeichenmethoden aufzurufen, wollen
wir Alber und
alle zehn Pflanzen in diesem Array
nach ihrer
vertikalen Y-Koordinate sortieren alle zehn Pflanzen in diesem Array , aber nicht nach ihrer oberen,
sondern nach ihrer unteren Grenze Da wir Objekte
mit unterschiedlichen Höhen haben, können
wir dies mit der integrierten
Array-Sortiermethode tun Die Sortiermethode sortiert die
Elemente eines Arrays an der richtigen Stelle und gibt den
Verweis auf dasselbe Array zurück. Jetzt sortiert, benötigt sie
ein optionales Argument. Wir rufen eine Vergleichsfunktion auf, in der wir Logik definieren können, die die Sortierreihenfolge
beschreibt. Wenn wir keine
Sortierbedingung definieren, werden
standardmäßig alle Array-Elemente einfach in
Zeichenketten umgewandelt und nach
Zeichen, Unicode-Werten, sortiert. A ist das erste Vergleichselement
, B steht für das zweite
Element. Zum Vergleich vergleicht die
Sortiermethode
automatisch jedes Element im Array
mit jedem anderen Element. Um sie nach unseren Anforderungen
zu sortieren. Wir möchten, dass die
Sortierbedingung
die untere Grenze jedes auf der Leinwand gezeichneten
Elements vergleicht . Es ist also die vertikale Y-Position
plus ihre Höhe. So wie das hier. Ich sage, sortiere alle Elemente in aufsteigender Reihenfolge basierend auf ihrer vertikalen Position
plus ihrer Höhe Sobald das Array sortiert ist, zeichnen
wir Pflanzen und Eulenbären
in dieser Reihenfolge auf die Leinwand Und jetzt
macht alles visuell Sinn. Wir können Hindernisse umgehen und sehen, dass der
Spielercharakter und Pflanzen jetzt immer korrekt vorne oder hinten
gezeichnet sind. Du kannst dieses Spiel
auf viele verschiedene Arten erweitern und Pilze
erschaffen, die im
spielbaren Bereich wachsen , damit der
Eulenbär wächst, wenn er sie frisst Oder du kannst es dazu bringen,
gefährlichen Feinden auszuweichen oder stachelige Hindernisse zu
umgehen Ich schlage vor, dass Sie eine Kopie
dieser Codebasis erstellen und sie als Grundlage für
verschiedene Gameplay-Experimente verwenden
können