Herausforderung: Neue Funktionen zu unserem Bouncing Balls Demo hinzufügen
In dieser Herausforderung sollen Sie das Bouncing Balls Demo aus dem vorherigen Artikel als Ausgangspunkt verwenden und einige neue und interessante Funktionen hinzufügen.
Ausgangspunkt
Um mit dieser Herausforderung zu beginnen, erstellen Sie eine lokale Kopie von index-finished.html, style.css und main-finished.js aus unserem letzten Artikel in einem neuen Verzeichnis auf Ihrem lokalen Computer.
Alternativ können Sie einen Online-Editor wie CodePen, JSFiddle oder Glitch verwenden. Sie könnten das HTML, CSS und JavaScript in einen dieser Online-Editoren einfügen. Sollte der von Ihnen verwendete Online-Editor kein separates JavaScript-Panel haben, können Sie es in einem <script>
-Element innerhalb der HTML-Seite einfügen.
Hinweis: Wenn Sie nicht weiterkommen, können Sie sich über einen unserer Kommunikationskanäle an uns wenden.
Hinweise und Tipps
Ein paar Hinweise, bevor Sie beginnen.
- Diese Herausforderung ist ziemlich schwierig. Lesen Sie alle Anweisungen, bevor Sie anfangen zu programmieren, und gehen Sie jeden Schritt langsam und sorgfältig an.
- Es könnte eine gute Idee sein, eine separate Kopie des Demos zu speichern, nachdem Sie jede Stufe funktionierend haben, sodass Sie darauf zurückgreifen können, wenn Sie später in Schwierigkeiten geraten.
Projektbeschreibung
Unser Bouncy Balls Demo macht Spaß, aber jetzt möchten wir es ein wenig interaktiver gestalten, indem wir einen benutzerkontrollierten bösen Kreis hinzufügen, der die Bälle auffrisst, wenn er sie fängt. Außerdem möchten wir Ihre Objektaufbaufähigkeiten testen, indem wir ein generisches Shape()
-Objekt erstellen, von dem unsere Bälle und der böse Kreis erben können. Schließlich möchten wir einen Zähler hinzufügen, um die Anzahl der verbleibenden Bälle zu verfolgen.
Der folgende Screenshot gibt Ihnen eine Vorstellung davon, wie das fertige Programm aussehen sollte:
Um Ihnen eine bessere Vorstellung zu geben, werfen Sie einen Blick auf das fertige Beispiel (nicht den Quellcode ansehen!)
Schritte zur Fertigstellung
Die folgenden Abschnitte beschreiben, was Sie tun müssen.
Erstellen einer Shape-Klasse
Zuerst einmal erstellen Sie eine neue Shape
-Klasse. Diese hat nur einen Konstruktor. Der Shape
-Konstruktor sollte die Eigenschaften x
, y
, velX
und velY
auf dieselbe Weise definieren, wie es der Ball()
-Konstruktor ursprünglich tat, jedoch nicht die Eigenschaften color
und size
.
Die Ball
-Klasse sollte von Shape
mit extends
abgeleitet werden. Der Konstruktor für Ball
sollte:
- dieselben Argumente wie zuvor übernehmen:
x
,y
,velX
,velY
,size
undcolor
- den
Shape
-Konstruktor mitsuper()
aufrufen und die Argumentex
,y
,velX
undvelY
übergeben - seine eigenen
color
undsize
Eigenschaften aus den ihm gegebenen Parametern initialisieren.
Hinweis:
Stellen Sie sicher, dass die Shape
-Klasse oberhalb der bestehenden Ball
-Klasse erstellt wird, ansonsten erhalten Sie möglicherweise einen Fehler wie: "Uncaught ReferenceError: Cannot access 'Shape' before initialization"
Der Ball
-Konstruktor sollte eine neue Eigenschaft namens exists
definieren, die verwendet wird, um zu verfolgen, ob die Bälle im Programm existieren (nicht vom bösen Kreis gefressen wurden). Dies sollte ein boolescher Wert (true
/false
) sein, der im Konstruktor auf true
gesetzt wird.
Die collisionDetect()
-Methode der Ball
-Klasse benötigt eine kleine Aktualisierung. Ein Ball muss nur für die Kollisionsdetektion berücksichtigt werden, wenn die Eigenschaft exists
true
ist. Ersetzen Sie also den vorhandenen collisionDetect()
-Code durch den folgenden Code:
class Ball {
// …
collisionDetect() {
for (const ball of balls) {
if (!(this === ball) && ball.exists) {
const dx = this.x - ball.x;
const dy = this.y - ball.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < this.size + ball.size) {
ball.color = this.color = randomRGB();
}
}
}
}
// …
}
Wie oben besprochen, ist die einzige Ergänzung, zu prüfen, ob der Ball existiert — indem ball.exists
im if
bedingten Ausdruck verwendet wird.
Die Definitionen der Methoden draw()
und update()
des Balls sollten genau so bleiben können, wie sie zuvor waren.
An diesem Punkt versuchen Sie, den Code erneut zu laden — er sollte genauso funktionieren wie zuvor, mit unseren überarbeiteten Objekten.
Definition von EvilCircle
Jetzt ist es Zeit, den Bösewicht kennenzulernen — das EvilCircle()
! Unser Spiel wird nur einen bösen Kreis enthalten, aber wir werden ihn trotzdem mit einem Konstruktor definieren, der von Shape()
erbt, um Ihnen etwas Übung zu geben. Vielleicht möchten Sie später noch einen weiteren Kreis zur App hinzufügen, der von einem weiteren Spieler kontrolliert werden kann, oder mehrere computerkontrollierte böse Kreise haben. Sie werden die Welt wahrscheinlich nicht mit einem einzelnen bösen Kreis erobern, aber für diese Herausforderung reicht es.
Erstellen Sie eine Definition für eine EvilCircle
-Klasse. Sie sollte von Shape
mit extends
erben.
EvilCircle Konstruktor
Der Konstruktor für EvilCircle
sollte:
- nur
x
,y
-Argumente erhalten - die
x
,y
-Argumente an dieShape
-Superclass weitergeben, zusammen mit Werten fürvelX
undvelY
, die fest auf 20 gesetzt sind. Dies sollten Sie mit Code wiesuper(x, y, 20, 20);
tun color
aufwhite
undsize
auf10
setzen.
Schließlich sollte der Konstruktor den Code einrichten, der es dem Benutzer ermöglicht, den bösen Kreis auf dem Bildschirm zu bewegen:
window.addEventListener("keydown", (e) => {
switch (e.key) {
case "a":
this.x -= this.velX;
break;
case "d":
this.x += this.velX;
break;
case "w":
this.y -= this.velY;
break;
case "s":
this.y += this.velY;
break;
}
});
Dies fügt dem window
-Objekt einen keydown
-Ereignislistener hinzu, sodass bei jedem Drücken einer Taste die key
-Eigenschaft des Ereignisobjekts konsultiert wird, um zu sehen, welche Taste gedrückt wurde. Wenn es eine der vier angegebenen Tasten ist, bewegt sich der böse Kreis nach links/rechts/oben/unten.
Definition von Methoden für EvilCircle
Die EvilCircle
-Klasse sollte drei Methoden haben, wie unten beschrieben.
draw()
Diese Methode hat den gleichen Zweck wie die draw()
-Methode für Ball
: Sie zeichnet die Objektinstanz auf der Leinwand. Die draw()
-Methode für EvilCircle
funktioniert sehr ähnlich, daher können Sie mit dem Kopieren der draw()
-Methode für Ball
beginnen. Sie sollten dann die folgenden Änderungen vornehmen:
- Wir möchten, dass der böse Kreis nicht ausgefüllt ist, sondern nur eine äußere Linie (Stroke) hat. Sie können dies erreichen, indem Sie
fillStyle
undfill()
instrokeStyle
undstroke()
aktualisieren. - Wir möchten auch, dass die Linie ein wenig dicker ist, damit Sie den bösen Kreis etwas leichter sehen können. Dies kann erreicht werden, indem Sie einen Wert für
lineWidth
irgendwo nach dembeginPath()
-Aufruf setzen (3 wäre in Ordnung).
checkBounds()
Diese Methode wird das Gleiche tun wie der erste Teil der update()
-Methode für Ball
— schauen Sie, ob der böse Kreis den Bildschirmrand verlässt, und verhindern Sie, dass er dies tut. Auch hier können Sie größtenteils die update()
-Methode für Ball
kopieren, aber es gibt ein paar Änderungen, die Sie vornehmen sollten:
- Entfernen Sie die letzten beiden Zeilen — wir möchten die Position des bösen Kreises nicht in jedem Frame automatisch aktualisieren, da wir ihn auf eine andere Weise bewegen, wie Sie weiter unten sehen werden.
- Innerhalb der
if ()
-Anweisungen, wenn die Teststrue
zurückgeben, möchten wirvelX
/velY
nicht aktualisieren; stattdessen möchten wir den Wert vonx
/y
ändern, sodass der böse Kreis nur geringfügig auf den Bildschirm zurückprallt. Das Hinzufügen oder Subtrahieren (je nachdem) dersize
-Eigenschaft des bösen Kreises würde Sinn machen.
collisionDetect()
Diese Methode wird auf sehr ähnliche Weise wie die collisionDetect()
-Methode für Ball
-Methoden funktionieren, sodass Sie eine Kopie davon als Grundlage für diese neue Methode verwenden können. Es gibt jedoch einige Unterschiede:
- In der äußeren
if
-Anweisung müssen Sie nicht mehr überprüfen, ob der aktuelle Ball in der Iteration derselbe ist wie der Ball, der die Überprüfung durchführt — denn es ist kein Ball mehr, es ist der böse Kreis! Stattdessen müssen Sie eine Prüfung durchführen, um zu sehen, ob der Ball, der überprüft wird, existiert (mit welcher Eigenschaft könnten Sie das tun?). Wenn er nicht existiert, wurde er bereits vom bösen Kreis gefressen, sodass es keinen Bedarf gibt, ihn erneut zu überprüfen. - In der inneren
if
-Anweisung möchten Sie nicht mehr, dass die Objekte ihre Farbe ändern, wenn eine Kollision erkannt wird — stattdessen sollen Sie alle Bälle, die mit dem bösen Kreis kollidieren, dazu bringen, nicht mehr zu existieren (wie denken Sie, würden Sie das tun?).
Den bösen Kreis ins Programm bringen
Jetzt, da wir den bösen Kreis definiert haben, müssen wir ihn tatsächlich in unserer Szene erscheinen lassen. Dazu müssen Sie einige Änderungen an der loop()
-Funktion vornehmen.
- Zuerst erstellen Sie eine neue Objektinstanz des bösen Kreises (Angabe der notwendigen Parameter). Dies müssen Sie nur einmal tun, nicht bei jeder Iteration der Schleife.
- An dem Punkt, an dem Sie durch jeden Ball schleifen und die
draw()
,update()
undcollisionDetect()
-Funktionen für jeden aufrufen, sorgen Sie dafür, dass diese Funktionen nur aufgerufen werden, wenn der aktuelle Ball existiert. - Rufen Sie bei jeder Iteration der Schleife die
draw()
,checkBounds()
undcollisionDetect()
-Methoden der bösen Kreis-Instanz auf.
Den Zähler implementieren
Um den Zähler zu implementieren, führen Sie die folgenden Schritte aus:
-
Fügen Sie in Ihrer HTML-Datei ein
<p>
-Element direkt unter dem h1-Element hinzu, das den Text "Ball count: " enthält. -
Fügen Sie in Ihrer CSS-Datei die folgende Regel am unteren Rand hinzu:
cssp { position: absolute; margin: 0; top: 35px; right: 5px; color: #aaa; }
-
In Ihrem JavaScript machen Sie die folgenden Aktualisierungen:
- Erstellen Sie eine Variable, die eine Referenz auf den Absatz speichert.
- Halten Sie in irgendeiner Weise die Anzahl der Bälle auf dem Bildschirm fest.
- Erhöhen Sie die Zählung und zeigen Sie die aktualisierte Anzahl an Bällen jedes Mal an, wenn ein Ball zur Szene hinzugefügt wird.
- Verringern Sie die Zählung und zeigen Sie die aktualisierte Anzahl an Bällen jedes Mal an, wenn der böse Kreis einen Ball auffrisst (ihn dazu bringt, nicht mehr zu existieren).