Baue ein animiertes Physikspiel mit JavaScript | Frank Dvorak | Skillshare

Playback-Geschwindigkeit


1.0x


  • 0.5x
  • 0.75x
  • 1x (normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Baue ein animiertes Physikspiel mit JavaScript

teacher avatar Frank Dvorak, Creative Coding

Schau dir diesen Kurs und Tausende anderer Kurse an

Erhalte unbegrenzten Zugang zu allen Kursen
Lerne von Branchenführern, Ikonen und erfahrenen Experten
Wähle aus einer Vielzahl von Themen, wie Illustration, Design, Fotografie, Animation und mehr

Schau dir diesen Kurs und Tausende anderer Kurse an

Erhalte unbegrenzten Zugang zu allen Kursen
Lerne von Branchenführern, Ikonen und erfahrenen Experten
Wähle aus einer Vielzahl von Themen, wie Illustration, Design, Fotografie, Animation und mehr

Einheiten dieses Kurses

    • 1.

      Einführung

      0:46

    • 2.

      Grundlegende Einrichtung

      3:51

    • 3.

      Objektorientierte Programmierung in JavaScript

      4:21

    • 4.

      Den Spieler zeichnen

      7:10

    • 5.

      Maussteuerungen

      5:59

    • 6.

      Den Spieler bewegen

      7:39

    • 7.

      Hindernisse schaffen

      6:33

    • 8.

      Nicht überlappende Hindernisse

      6:35

    • 9.

      Zufällige Bilder aus einem Sprite-Sheet

      5:14

    • 10.

      Positionierungsregeln

      5:59

    • 11.

      Wiederverwendbare Kollisionserkennungsmethode

      4:04

    • 12.

      Physik

      8:07

    • 13.

      8 direktionale Sprite-Animation

      4:13

    • 14.

      Animationswinkel

      7:05

    • 15.

      Debug-Modus

      3:33

    • 16.

      Bewegungsgrenzen der Spieler

      2:56

    • 17.

      FPS

      9:39

    • 18.

      Eierkurs

      4:53

    • 19.

      Regelmäßig neue Eier hinzufügen

      6:59

    • 20.

      Eierphysik

      5:34

    • 21.

      Reihenfolge zeichnen

      8:17

    • 22.

      Feind-Kurs

      11:19

    • 23.

      Larvenkurs

      3:26

    • 24.

      Eierbrüten

      9:58

    • 25.

      Larvensprites und Kollisionen

      4:37

    • 26.

      Partitur

      2:40

    • 27.

      Partikeleffekte

      8:55

    • 28.

      Partikelbewegung

      7:04

    • 29.

      Zufällige Feind-Skins

      4:24

    • 30.

      Zustand gewinnen und verlieren

      10:31

    • 31.

      Spiel neu starten

      6:32

    • 32.

      Kurs des Feindes erweitern

      5:55

    • 33.

      Einfacher Vollbildmodus

      3:07

    • 34.

      Player Sprite Sheet vollständige Animation

      2:36

    • 35.

      Larva Sprite Sheet vollständige Animation

      1:43

    • 36.

      Enemies Sprite Sheet vollständige Animation

      6:38

    • 37.

      Bonusprojekt (optional)

      0:46

    • 38.

      Bonusprojekteinrichtung

      1:36

    • 39.

      Spielwelten verbessern

      6:56

    • 40.

      JavaScript-Einrichtung

      5:52

    • 41.

      Tastatursteuerungen

      7:27

    • 42.

      Spielercharakter

      11:21

    • 43.

      4 direktionale Sprite-Sheets

      12:00

    • 44.

      So steuerst du FPS

      9:02

    • 45.

      Zufällig positionierte Spielobjekte

      8:19

    • 46.

      Layering und Zeichenfolge in 2D-Spielen

      5:33

  • --
  • Anfänger-Niveau
  • Fortgeschrittenes Niveau
  • Fortgeschrittenes Niveau
  • Jedes Niveau

Von der Community generiert

Das Niveau wird anhand der mehrheitlichen Meinung der Teilnehmer:innen bestimmt, die diesen Kurs bewertet haben. Bis das Feedback von mindestens 5 Teilnehmer:innen eingegangen ist, wird die Empfehlung der Kursleiter:innen angezeigt.

171

Teilnehmer:innen

1

Projekte

Über diesen Kurs

Was macht ein großartiges Spiel aus? Geht es um schöne, ausgefeilte Visuals oder um ein Gameplay, das sich gut und reaktionsfreudig anfühlt? Geht es um einzigartige Ideen oder vielleicht sind es die kleinen Details, die besonderen Geheimnisse und die Ostereier? Was sind die Zutaten für ein perfektes Rezept für die Spieleentwicklung?

 

In diesem Kurs tauchen wir tief in die Sprite-Animation, Interaktivität und 2D-Physik ein. Wir lernen 10 wichtige Techniken kennen, die jeder Spieleentwickler kennen muss, und wir werden sie in einem echten Projekt anwenden. 

 

Die Teilnehmer dieses Kurses erhalten kostenlos eine Menge professioneller 2D-Spielekunst mit hoher Auflösung. Ich biete Umwelt- und Charakterkunst-Assets in Form von gebrauchsfertigen Sprite-Sheets sowie Quelldateien mit separaten Teilen für diejenigen unter euch, die die Farben bearbeiten, deine eigenen Pilze und Kreaturen zusammenstellen oder deine eigenen Animationen manipulieren möchten. 

 

Heute erfahren wir:

- So zeichne du mit der integrierten drawImage-Methode zufällige Spielumgebungen und animierte Charaktere aus einem Sprite-Sheet

- Wie du den FPS unseres Spiels kontrollierst und wie du die Zeit messst, um periodische Ereignisse auszulösen

- So startest du das Spiel mit einem Knopfdruck

- Wie man die Kollisionserkennung anwendet, Kollisionen auflöst und dies zur Simulation der Physik verwendet

- Wie man eine sehr einfache KI implementiert, um die Kreaturen lebendig fühlen zu lassen

- So kannst du die Mausposition erfassen und ein Sprite-Sheet mit 8 Richtungen animieren, basierend auf der relativen Position zwischen Maus und Spielercharakter

- Wie man HTML5, CSS3 und einfaches Vanille-JavaScript verwendet, um ein Spiel von Grund auf zu bauen. Wir werden jede Codezeile schreiben und verstehen, wir verlassen uns nicht auf externe Frameworks oder Bibliotheken

... und vieles mehr

 

Das Tempo und die Techniken in diesem Kurs sind anfängerfreundlich. Um den Kurs zu absolvieren, sind bereits vorhandene Kenntnisse in HTML, CSS und JavaScript erforderlich. Wenn du die Grundlagen von JavaScript verstehst und weißt, was Funktionen für Loops und Arrays sind, kannst du den maximalen Wert aus diesem Kurs herausholen.

 

Viel Spaß! :)

Triff deine:n Kursleiter:in

Teacher Profile Image

Frank Dvorak

Creative Coding

Kursleiter:in

Hello, I'm Frank. I'm a front-end web developer, owner of Frank's Laboratory YouTube channel. Come explore creative coding, game development and generative art with me.

Vollständiges Profil ansehen

Level: Beginner

Kursbewertung

Erwartungen erfüllt?
    Voll und ganz!
  • 0%
  • Ja
  • 0%
  • Teils teils
  • 0%
  • Eher nicht
  • 0%

Warum lohnt sich eine Mitgliedschaft bei Skillshare?

Nimm an prämierten Skillshare Original-Kursen teil

Jeder Kurs setzt sich aus kurzen Einheiten und praktischen Übungsprojekten zusammen

Mit deiner Mitgliedschaft unterstützt du die Kursleiter:innen auf Skillshare

Lerne von überall aus

Ob auf dem Weg zur Arbeit, zur Uni oder im Flieger - streame oder lade Kurse herunter mit der Skillshare-App und lerne, wo auch immer du möchtest.

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