So verwenden Sie VUE und Canvas, um ein Thunder Fighter-Tippspiel zu implementieren

So verwenden Sie VUE und Canvas, um ein Thunder Fighter-Tippspiel zu implementieren

Heute werden wir ein Thunder Fighter-Tippspiel implementieren. Das Gameplay ist sehr einfach. Jeder „Feind“ besteht aus einigen englischen Wörtern. Wenn Sie die Buchstaben des Wortes richtig auf der Tastatur eingeben, feuert das Flugzeug nacheinander Kugeln ab, um den „Feind“ zu vernichten. Sie müssen den aktuellen „Feind“ töten, bevor Sie den nächsten töten können. Es ist ein Spiel, das die Handgeschwindigkeit und Wortgewandtheit testet.

Schauen wir uns zunächst den Endeffekt an:

emmmmmmmmmmmmm, die Benutzeroberfläche ist sehr einfach. Implementieren Sie zuerst die Grundfunktionen und denken Sie dann über die erweiterte Benutzeroberfläche nach.

Lassen Sie uns zunächst die Schnittstellenzusammensetzung analysieren:

(1) Die Ebene wird in der Mitte des unteren Bildes fixiert.

(2) Feinde (Wörter), die zufällig aus dem oberen Bildschirmbereich generiert werden;

(3) Eine Kugel, die aus der Vorderseite des Flugzeugs abgefeuert wird und direkt auf den Feind zusteuert;

(4) Spielstandanzeige nach Spielende.

Im Vergleich zu den Vorgängerspielen scheint der Sportteil dieses Mal zahlreicher und komplizierter zu sein. Obwohl sich bei Flappy Bird das Rohr bewegt, bleiben die x-Koordinate des Vogels sowie der Abstand und die Breite des Rohrs unverändert, sodass die Grenze leichter zu berechnen ist. Beim Flipper- und Ziegelspiel sind die Holzbretter und Ziegel relativ einfache bzw. feste Koordinaten, sodass Sie nur die Grenze des Flipperspiels und die Kontaktfläche der Ziegel bestimmen müssen. Egal, ob es sich beim Worteliminierungsspiel „Thunder Fighter“ um das landende Zielwort oder die fliegende Kugel handelt, sie haben alle ihre eigene Bewegungsbahn. Die Kugeln müssen jedoch dem Ziel folgen, sodass eine Flugbahnberechnung in Echtzeit erfolgt.

Ein hohes Gebäude beginnt am Boden. Nachdem wir so viel gesagt haben, beginnen wir mit dem einfachsten!

1. Das Flugzeug in der Mitte des unteren Bildschirmrands fixiert

Das ist sehr einfach und es gibt nicht viel zu sagen. Hier beträgt die Standardbreite und -höhe des Flugzeugs 40 Pixel, und dann wird das Flugzeug unten in der Mitte des Bildschirms gezeichnet:

zeichneEbene() {
      lass _this = dies;
      _this.ctx.speichern();
      _dieses.ctx.drawImage(
        _dieses.planeImg,
        _this.clientWidth / 2 - 20,
        _this.clientHeight – 20 – 40,
        40,
        40
      );
      _this.ctx.restore();
},

2. Feinde werden zufällig vom oberen Bildschirmrand generiert

Hier werden standardmäßig nur 3 Wortziele gleichzeitig auf dem Bildschirm angezeigt, die Bewegungsgeschwindigkeit des Ziels auf der Y-Achse beträgt 1,3 und der Radius des Ziels beträgt 10:

const _MAX_TARGET = 3; // Die maximale Anzahl von Zielen, die gleichzeitig auf dem Bildschirm erscheinen const _TARGET_CONFIG = {
  // Feste Parameter der Zielgeschwindigkeit: 1,3,

  Radius: 10

};

Dann nehmen wir zunächst zufällig _MAX_TARGET nicht wiederkehrende Wörter aus dem Wortbibliothek-Array heraus und fügen die verbleibenden Wörter in die kreisförmige Wortbibliothek this.wordsPool ein:

Wortgenerierung(Zahl) {
      // Wähle zufällig ein Wort aus dem Pool, das sich nicht mit den angezeigten Wörtern überschneidet. let arr = [];
      für (sei i = 0; i < Zahl; i++) {
        lass random = Math.floor(Math.random() * this.wordsPool.length);
        arr.push(diesen.wordsPool[random]);
        dies.wordsPool.splice(random, 1);
      }
      Rückflug an;
},
Ziel generieren() {
      // Ziele zufällig generieren let _this = this;
      lass Länge = _this.targetArr.length;
      wenn (Länge < _MAX_TARGET) {
        let txtArr = _this.generateWord(_MAX_TARGET - Länge);
        für (lass i = 0; i < _MAX_TARGET - Länge; i++) {
          _diese.targetArr.push({
            x: _this.getRandomInt(
              _TARGET_CONFIG.radius,
              _this.clientWidth - _TARGET_CONFIG.radius
            ),
            y: _TARGET_CONFIG.radius * 2,
            txt: txtArr[i],
            TypIndex: -1,
            TrefferIndex: -1,
            dx: (_TARGET_CONFIG.speed * Math.random().toFixed(1)) / 2,
            dy: _TARGET_CONFIG.speed * Math.random().toFixed(1),
            drehen: 0
          });
        }
      }
}

Es ist ersichtlich, dass this.targetArr ein Array ist, das das Zielobjekt speichert:

Bei einem anfänglichen Ziel ist x zufällig über die Breite des Bildschirms verteilt.

Der Wert auf der Y-Achse ist der Durchmesser;

txt zeichnet die durch das Ziel dargestellten Wörter auf;

typeIndex zeichnet den Indexindex des Zeichens auf, das eingegeben wird, wenn das Wort „bombing“ eingegeben wird (wird verwendet, um eingegebene Zeichen von nicht eingegebenen Zeichen zu trennen);

hitIndex zeichnet den Index der Kugel auf, die das Wort „Bombing“ bombardiert (da die Kugel das Ziel tatsächlich bombardiert, nachdem sie das Wort getroffen hat, hat die Kugel schließlich eine Flugzeit, sodass hitIndex verwendet wird, um zu bestimmen, wann die Kugel zersplittert und verschwindet);

dx ist der Versatzabstand des Ziels auf der X-Achse pro Frame;

dy ist der Versatzabstand des Ziels auf der Y-Achse pro Frame;

Drehen legt den Drehwinkel des Ziels fest.

OK, da wir nun drei Ziele generiert haben, verschieben wir sie von oben nach unten:

zeichneZiel() {
      // Das Ziel Bild für Bild zeichnen let _this = this;
      _this.targetArr.forEach((Element, Index) => {
        _this.ctx.speichern();
        _this.ctx.translate(item.x, item.y); //Mittelpunkt der Rotation festlegen_this.ctx.beginPath();
        _this.ctx.font = "14px Arial";
        Wenn (
          index === _dieser.aktuellerIndex ||
          item.typIndex === item.txt.länge - 1
        ) {
          _dieser.drawText(
            item.txt.substring(0, item.typeIndex + 1),
            -item.txt.Länge * 3,
            _TARGET_CONFIG.radius * 2,
            "grau"
          );
          lass Breite = _this.ctx.measureText(
            item.txt.substring(0, item.typeIndex + 1)
          ).width; // Breite des angetippten Textes abrufen_this.drawText(
            item.txt.substring(item.typeIndex + 1, item.txt.length),
            -item.txt.Länge * 3 + Breite,
            _TARGET_CONFIG.radius * 2,
            "Rot"
          );
        } anders {
          _dieser.drawText(
            Artikel.txt,
            -item.txt.Länge * 3,
            _TARGET_CONFIG.radius * 2,
            "Gelb"
          );
        }
 
        _this.ctx.closePath();
        _this.ctx.rotate((item.rotate * Math.PI) / 180);
        _dieses.ctx.drawImage(
          _dieses.targetImg,
          -1 * _TARGET_CONFIG.radius,
          -1 * _TARGET_CONFIG.radius,
          _TARGET_CONFIG.radius * 2,
          _TARGET_CONFIG.radius * 2
        );
        _this.ctx.restore();
        Element.y += Element.dy;
        Artikel.x += Artikel.dx;
        wenn (item.x < 0 || item.x > _this.clientWidth) {
          Artikel.dx *= -1;
        }
        wenn (item.y > _this.clientHeight - _TARGET_CONFIG.radius * 2) {
          //Den Boden erreichen_this.gameOver = true;
        }
        // Element drehen.rotate++;
      });
}

Das Zeichnen des Ziels ist in diesem Schritt nichts Besonderes. Wir erhöhen einfach zufällig dx und dy und prallen ab, wenn es die linken und rechten Kanten trifft. Der Hauptpunkt ist das Zeichnen von Wörtern. Das Wort wird durch typeIndex in zwei Teile geteilt, die angetippten Zeichen werden auf Grau gesetzt, und dann wird die Breite der angetippten Zeichen durch measureText ermittelt, um den X-Achsen-Versatz der nicht angetippten Zeichen festzulegen, und die nicht angetippten Zeichen werden auf Rot gesetzt, um den Spieler darauf hinzuweisen, dass dieses Wort ein angegriffenes Ziel ist.

3. Die Kugel wird von der Vorderseite des Flugzeugs abgefeuert und geht direkt auf den Feind zu.

Aufzählungszeichen sind ein zentraler Bestandteil dieses Spiels. Welche Aspekte sollten beim Zeichnen von Aufzählungszeichen berücksichtigt werden?

(1) Das Ziel bewegt sich ständig, und die abgefeuerte Kugel muss das Ziel ständig „verfolgen“, so dass sich ihre Flugbahn dynamisch ändert.

(2) Um ein Ziel zu zerstören, ist eine bestimmte Anzahl an Kugeln erforderlich. Wann werden die Kugeln vom Bildschirm gelöscht?

(3) Wenn ein Zielwort getroffen wird, wird die nächste Kugelsalve auf das nächste Ziel abgefeuert, so dass die Flugbahn der Kugel eindeutig ist.

(4) Wie zeichnet man den Aufzählungseffekt?

(5) Wenn das Zielwort gesperrt ist, muss der Spieler das aktuelle Wort zu Ende tippen, bevor er das nächste Wort anklicken kann.

Hier sind einige festzulegende Variablen:

bulletArr: [], //Bullet-Objekte speichern

currentIndex: -1 //Der Index des aktuell gesperrten Ziels in targetArr

Schreiben wir zunächst die Funktion, die beim Drücken der Tastatur ausgelöst werden soll:

handleKeyPress(Taste) {
      //Tastatur gedrückt, bestimme das aktuelle Ziel let _this = this;
      wenn (_this.currentIndex === -1) {
        // Momentan wird auf kein Ziel geschossen let index = _this.targetArr.findIndex(item => {
          gibt item.txt.indexOf(Schlüssel) === 0 zurück;
        });
        wenn (Index !== -1) {
          _this.currentIndex = Index;
          _this.targetArr[index].typeIndex = 0;
          _this.createBullet(index);
        }
      } anders {
        // Auf ein Ziel wird bereits geschossen, wenn (
          Schlüssel ===
          _this.targetArr[_this.currentIndex].txt.split("")[
            _this.targetArr[_this.currentIndex].typeIndex + 1
          ]
        ) {
          // Holen Sie sich das Zielobjekt_this.targetArr[_this.currentIndex].typeIndex++;
          _this.createBullet(_this.currentIndex);
 
          Wenn (
            _this.targetArr[_this.currentIndex].typeIndex ===
            _this.targetArr[_this.currentIndex].txt.length - 1
          ) {
            // Auf dieses Ziel wurde bereits geschossen_this.currentIndex = -1;
          }
        }
      }
},
// Eine Kugel abfeuern createBullet(index) {
      lass _this = dies;
      dies.bulletArr.push({
        dx: 1,
        d: 4,
        x: _this.clientWidth / 2,
        y: _this.clientHeight - 60,
        Zielindex: Index
      });
}

Was diese Funktion macht, ist sehr klar. Sie ruft das aktuell auf der Tastatur gedrückte Zeichen ab. Wenn currentIndex === -1 ist, beweist dies, dass kein Ziel angegriffen wird. Sie sucht also im Zielarray nach, bei welchem ​​Wort der erste Buchstabe mit dem Zeichen übereinstimmt, setzt currentIndex auf den Index des Wortes und feuert eine Kugel ab. Wenn bereits ein Ziel angegriffen wird, prüft sie, ob der erste Buchstabe des nicht getroffenen Wortes übereinstimmt. Wenn ja, erhöht sie den typeIndex des Zielobjekts und feuert eine Kugel ab. Wenn das aktuelle Ziel getroffen wurde, setzt sie currentIndex auf -1 zurück.

Als nächstes wird die Kugel gezeichnet:

zeichneBullet() {
      // Aufzählungszeichen Bild für Bild zeichnen let _this = this;
      // Bestimmen Sie, ob die Kugel das Ziel getroffen hat, wenn (_this.bulletArr.length === 0) {
        zurückkehren;
      }
      _this.bulletArr = _this.bulletArr.filter(_this.firedTarget);
      _this.bulletArr.forEach(item => {
        Lassen Sie targetX = _this.targetArr[item.targetIndex].x;
        sei targetY = _this.targetArr[item.targetIndex].y;
        sei k =
          (_this.clientHeight - 60 - ZielY) /
          (_this.clientWidth / 2 - targetX); // Neigung des Flugzeugkopfes und des Ziels let b = targetY - k * targetX; // Konstante b
        item.y = item.y – bullet.dy; // y-Achse um eine Einheit verschoben item.x = (item.y – b) / k;
        für (sei i = 0; i < 15; i++) {
          // Den abschließenden Effekt zeichnen_this.ctx.beginPath();
          _diese.ctx.arc(
            (Punkt y + i * 1,8 - b) / k,
            Artikel.y + i * 1,8,
            4 - 0,2 * ich,
            0,
            2 * Math.PI
          );
          _this.ctx.fillStyle = `rgba(193,255,255,${1 - 0.08 * i})`;
          _this.ctx.fill();
          _this.ctx.closePath();
        }
      });
},
abgefeuertesZiel(Element) {
      // Bestimmen, ob das Ziel getroffen wurde let _this = this;
      Wenn (
        item.x > _this.targetArr[item.targetIndex].x - _TARGET_CONFIG.radius &&
        Element.x < _this.targetArr[Element.targetIndex].x + _TARGET_CONFIG.radius &&
        item.y > _this.targetArr[item.targetIndex].y - _TARGET_CONFIG.radius &&
        Element.y < _this.targetArr[item.targetIndex].y + _TARGET_CONFIG.radius
      ) {
        // Die Kugel hat das Ziel getroffen let arrIndex = item.targetIndex;
        _this.targetArr[arrIndex].hitIndex++;
        Wenn (
          _this.targetArr[arrIndex].txt.length - 1 ===
          _this.targetArr[arrIndex].hitIndex
        ) {
          // Alle Kugeln treffen das Ziel let word = _this.targetArr[arrIndex].txt;
          _this.targetArr[arrIndex] = {
            // Erzeuge ein neues Ziel x: _this.getRandomInt(
              _TARGET_CONFIG.radius,
              _this.clientWidth - _TARGET_CONFIG.radius
            ),
            y: _TARGET_CONFIG.radius * 2,
            txt: _this.generateWord(1)[0],
            TypIndex: -1,
            TrefferIndex: -1,
            dx: (_TARGET_CONFIG.speed * Math.random().toFixed(1)) / 2,
            dy: _TARGET_CONFIG.speed * Math.random().toFixed(1),
            drehen: 0
          };
          _this.wordsPool.push(word); // Das getroffene Zielwort kehrt zum Pool zurück_this.score++;
        }
        gibt false zurück;
      } anders {
        gibt true zurück;
      }
}

Tatsächlich ist es auch sehr einfach. Wir verwenden targetIndex im Bullet-Objekt, um den Zielindex aufzuzeichnen, der von der Kugel angegriffen wird. Dann lösen wir die Gleichung y = kx + b, um die Umlaufbahnfunktion des Flugzeugkopfes (der Startpunkt der Kugel) und des Ziels zu erhalten. Wir berechnen die Bewegungskoordinaten jeder Kugel in jedem Frame und können dann die Kugel zeichnen.

Der Trailing-Effekt wird durch das Zeichnen einer Anzahl von Kreisen mit allmählich abnehmender Transparenz und Radius entlang der Wachstumsrichtung der Y-Achse der Spur erzielt.

In der Funktion firedTarget () wird es verwendet, um die Kugeln herauszufiltern, die das Ziel getroffen haben. Um den Index anderer Ziele, die in targetArr noch angegriffen werden, nicht zu beeinträchtigen, wird keine Spleißlöschung verwendet, sondern der Wert des zerstörten Ziels wird direkt zurückgesetzt, ein neues Wort wird aus wordPool ausgewählt und das aktuell defekte Wort wird zurück in den Pool geworfen, um sicherzustellen, dass im Bild keine doppelten Ziele erscheinen.

4. Punktetexteffekt nach Spielende

Das Spiel endet, wenn das Ziel den Boden berührt.

Das ist eigentlich ein Easter Egg. Wie können wir Canvas verwenden, um diese Art von blinkendem und mit Heiligenschein versehenem Text zu zeichnen? Wechseln Sie einfach die Farbe und stapeln Sie den Buff, nein, stapeln Sie nur den Strich.

zeichneGameOver() {
      lass _this = dies;
      //Den Status des Kontexts speichern object_this.ctx.save();
      _this.ctx.font = "34px Arial";
      _this.ctx.strokeStyle = _this.colors[0];
      _this.ctx.Linienbreite = 2;
      //Halo_this.ctx.shadowColor = "#FFFFE0";
      let txt = "Spiel vorbei, Ergebnis: " + _this.score;
      Lassen Sie Breite = _this.ctx.measureText(txt).width;
      für (sei i = 60; i > 3; i -= 2) {
        _this.ctx.shadowBlur = i;
        _this.ctx.strokeText(txt, _this.clientWidth / 2 - Breite / 2, 300);
      }
      _this.ctx.restore();
      _diese.Farben.umkehren();
}

Okay, okay, wir haben bis jetzt ein ziemlich vollständiges Spiel, aber die Benutzeroberfläche ist etwas grob. Wenn Sie die coolen Explosionseffekte wie beim echten Thunder Fighter erzielen möchten, benötigen Sie eine Menge Materialien und Leinwandzeichnungen.

Canvas ist sehr leistungsstark und macht Spaß. Solange Sie genügend Fantasie haben, können Sie auf dieser Leinwand zeichnen, was Sie wollen.

Wie üblich ist hier der vollständige Code von Vue zu Ihrer Information:

<Vorlage>
  <div Klasse="Typ-Spiel">
    <canvas id="Typ" Breite="400" Höhe="600"></canvas>
  </div>
</Vorlage>
 
<Skript>
const _MAX_TARGET = 3; // Die maximale Anzahl von Zielen, die gleichzeitig auf dem Bildschirm erscheinen const _TARGET_CONFIG = {
  // Feste Parameter der Zielgeschwindigkeit: 1,3,
  Radius: 10
};
const _DICTIONARY = ["Apfel", "orange", "blau", "grün", "rot", "aktuell"];
Standard exportieren {
  Name: "TypSpiel",
  Daten() {
    zurückkehren {
      ctx: null,
      Clientbreite: 0,
      Clienthöhe: 0,
      bulletArr: [], // Das Bullet auf dem Bildschirm targetArr: [], // Das aktuelle Ziel speichern targetImg: null,
      planeImg: null,
      aktuellerIndex: -1,
      WörterPool: [],
      Punktzahl: 0,
      gameOver: falsch,
      Farben: ["#FFFF00", "#FF6666"]
    };
  },
  montiert() {
    lass _this = dies;
    _this.wordsPool = _DICTIONARY.concat([]);
    let container = document.getElementById("Typ");
    _this.clientWidth = Containerbreite;
    _this.clientHeight = Containerhöhe;
    _this.ctx = container.getContext("2d");
    _this.targetImg = neues Bild();
    _this.targetImg.src = erfordern("@/assets/img/target.png");
 
    _this.planeImg = neues Bild();
    _this.planeImg.src = erfordern("@/assets/img/plane.png");
 
    Dokument.onkeydown = Funktion(e) {
      let key = window.event.keyCode;
      wenn (Schlüssel >= 65 und Schlüssel <= 90) {
        _this.handleKeyPress(String.fromCharCode(key).toLowerCase());
      }
    };
 
    _this.targetImg.onload = Funktion() {
      _this.generateTarget();
      (Funktion animloop() {
        wenn (!_this.gameOver) {
          _this.drawAll();
        } anders {
          _this.drawGameOver();
        }
        Fenster.requestAnimationFrame(animloop);
      })();
    };
  },
  Methoden: {
    zeichneGameOver() {
      lass _this = dies;
      //Den Status des Kontexts speichern object_this.ctx.save();
      _this.ctx.font = "34px Arial";
      _this.ctx.strokeStyle = _this.colors[0];
      _this.ctx.Linienbreite = 2;
      //Halo_this.ctx.shadowColor = "#FFFFE0";
      let txt = "Spiel vorbei, Ergebnis: " + _this.score;
      Lassen Sie Breite = _this.ctx.measureText(txt).width;
      für (sei i = 60; i > 3; i -= 2) {
        _this.ctx.shadowBlur = i;
        _this.ctx.strokeText(txt, _this.clientWidth / 2 - Breite / 2, 300);
      }
      _this.ctx.restore();
      _diese.Farben.umkehren();
    },
    zeichneAlles() {
      lass _this = dies;
      _this.ctx.clearRect(0, 0, _this.clientWidth, _this.clientHeight);
      _this.drawPlane(0);
      _this.drawBullet();
      _this.drawTarget();
      _this.drawScore();
    },
    zeichneEbene() {
      lass _this = dies;
      _this.ctx.speichern();
      _dieses.ctx.drawImage(
        _dieses.planeImg,
        _this.clientWidth / 2 - 20,
        _this.clientHeight – 20 – 40,
        40,
        40
      );
      _this.ctx.restore();
    },
    Wortgenerierung(Zahl) {
      // Wähle zufällig ein Wort aus dem Pool, das sich nicht mit den angezeigten Wörtern überschneidet. let arr = [];
      für (sei i = 0; i < Zahl; i++) {
        lass random = Math.floor(Math.random() * this.wordsPool.length);
        arr.push(diesen.wordsPool[random]);
        dies.wordsPool.splice(random, 1);
      }
      Rückflug an;
    },
    Ziel generieren() {
      // Ziele zufällig generieren let _this = this;
      lass Länge = _this.targetArr.length;
      wenn (Länge < _MAX_TARGET) {
        let txtArr = _this.generateWord(_MAX_TARGET - Länge);
        für (lass i = 0; i < _MAX_TARGET - Länge; i++) {
          _diese.targetArr.push({
            x: _this.getRandomInt(
              _TARGET_CONFIG.radius,
              _this.clientWidth - _TARGET_CONFIG.radius
            ),
            y: _TARGET_CONFIG.radius * 2,
            txt: txtArr[i],
            TypIndex: -1,
            TrefferIndex: -1,
            dx: (_TARGET_CONFIG.speed * Math.random().toFixed(1)) / 2,
            dy: _TARGET_CONFIG.speed * Math.random().toFixed(1),
            drehen: 0
          });
        }
      }
    },
    getRandomInt(n, m) {
      gibt Math.floor(Math.random() * (m - n + 1)) + n zurück;
    },
    zeichneText(txt, x, y, Farbe) {
      lass _this = dies;
      _this.ctx.fillStyle = Farbe;
      _this.ctx.fillText(txt, x, y);
    },
    Punktestand zeichnen() {
      // Punktzahl this.drawText("Punktzahl: " + this.score, 10, this.clientHeight - 10, "#fff");
    },
    zeichneZiel() {
      // Das Ziel Bild für Bild zeichnen let _this = this;
      _this.targetArr.forEach((Element, Index) => {
        _this.ctx.speichern();
        _this.ctx.translate(item.x, item.y); //Mittelpunkt der Rotation festlegen_this.ctx.beginPath();
        _this.ctx.font = "14px Arial";
        Wenn (
          index === _dieser.aktuellerIndex ||
          item.typIndex === item.txt.länge - 1
        ) {
          _dieser.drawText(
            item.txt.substring(0, item.typeIndex + 1),
            -item.txt.Länge * 3,
            _TARGET_CONFIG.radius * 2,
            "grau"
          );
          lass Breite = _this.ctx.measureText(
            item.txt.substring(0, item.typeIndex + 1)
          ).width; // Breite des angetippten Textes abrufen_this.drawText(
            item.txt.substring(item.typeIndex + 1, item.txt.length),
            -item.txt.Länge * 3 + Breite,
            _TARGET_CONFIG.radius * 2,
            "Rot"
          );
        } anders {
          _dieser.drawText(
            Artikel.txt,
            -item.txt.Länge * 3,
            _TARGET_CONFIG.radius * 2,
            "Gelb"
          );
        }
 
        _this.ctx.closePath();
        _this.ctx.rotate((item.rotate * Math.PI) / 180);
        _dieses.ctx.drawImage(
          _dieses.targetImg,
          -1 * _TARGET_CONFIG.radius,
          -1 * _TARGET_CONFIG.radius,
          _TARGET_CONFIG.radius * 2,
          _TARGET_CONFIG.radius * 2
        );
        _this.ctx.restore();
        Element.y += Element.dy;
        Artikel.x += Artikel.dx;
        wenn (item.x < 0 || item.x > _this.clientWidth) {
          Artikel.dx *= -1;
        }
        wenn (item.y > _this.clientHeight - _TARGET_CONFIG.radius * 2) {
          //Den Boden erreichen_this.gameOver = true;
        }
        // Element drehen.rotate++;
      });
    },
    handleKeyPress(Taste) {
      //Tastatur gedrückt, bestimme das aktuelle Ziel let _this = this;
      wenn (_this.currentIndex === -1) {
        // Momentan wird auf kein Ziel geschossen let index = _this.targetArr.findIndex(item => {
          gibt item.txt.indexOf(Schlüssel) === 0 zurück;
        });
        wenn (Index !== -1) {
          _this.currentIndex = Index;
          _this.targetArr[index].typeIndex = 0;
          _this.createBullet(index);
        }
      } anders {
        // Auf ein Ziel wird bereits geschossen, wenn (
          Schlüssel ===
          _this.targetArr[_this.currentIndex].txt.split("")[
            _this.targetArr[_this.currentIndex].typeIndex + 1
          ]
        ) {
          // Holen Sie sich das Zielobjekt_this.targetArr[_this.currentIndex].typeIndex++;
          _this.createBullet(_this.currentIndex);
 
          Wenn (
            _this.targetArr[_this.currentIndex].typeIndex ===
            _this.targetArr[_this.currentIndex].txt.length - 1
          ) {
            // Auf dieses Ziel wurde bereits geschossen_this.currentIndex = -1;
          }
        }
      }
    },
    // Eine Kugel abfeuern createBullet(index) {
      lass _this = dies;
      dies.bulletArr.push({
        dx: 1,
        d: 4,
        x: _this.clientWidth / 2,
        y: _this.clientHeight - 60,
        Zielindex: Index
      });
    },
    abgefeuertesZiel(Element) {
      // Bestimmen, ob das Ziel getroffen wurde let _this = this;
      Wenn (
        item.x > _this.targetArr[item.targetIndex].x - _TARGET_CONFIG.radius &&
        Element.x < _this.targetArr[Element.targetIndex].x + _TARGET_CONFIG.radius &&
        item.y > _this.targetArr[item.targetIndex].y - _TARGET_CONFIG.radius &&
        Element.y < _this.targetArr[item.targetIndex].y + _TARGET_CONFIG.radius
      ) {
        // Die Kugel hat das Ziel getroffen let arrIndex = item.targetIndex;
        _this.targetArr[arrIndex].hitIndex++;
        Wenn (
          _this.targetArr[arrIndex].txt.length - 1 ===
          _this.targetArr[arrIndex].hitIndex
        ) {
          // Alle Kugeln treffen das Ziel let word = _this.targetArr[arrIndex].txt;
          _this.targetArr[arrIndex] = {
            // Erzeuge ein neues Ziel x: _this.getRandomInt(
              _TARGET_CONFIG.radius,
              _this.clientWidth - _TARGET_CONFIG.radius
            ),
            y: _TARGET_CONFIG.radius * 2,
            txt: _this.generateWord(1)[0],
            TypIndex: -1,
            TrefferIndex: -1,
            dx: (_TARGET_CONFIG.speed * Math.random().toFixed(1)) / 2,
            dy: _TARGET_CONFIG.speed * Math.random().toFixed(1),
            drehen: 0
          };
          _this.wordsPool.push(word); // Das getroffene Zielwort kehrt zum Pool zurück_this.score++;
        }
        gibt false zurück;
      } anders {
        gibt true zurück;
      }
    },
    zeichneBullet() {
      // Aufzählungszeichen Bild für Bild zeichnen let _this = this;
      // Bestimmen Sie, ob die Kugel das Ziel getroffen hat, wenn (_this.bulletArr.length === 0) {
        zurückkehren;
      }
      _this.bulletArr = _this.bulletArr.filter(_this.firedTarget);
      _this.bulletArr.forEach(item => {
        Lassen Sie targetX = _this.targetArr[item.targetIndex].x;
        sei targetY = _this.targetArr[item.targetIndex].y;
        sei k =
          (_this.clientHeight - 60 - ZielY) /
          (_this.clientWidth / 2 - targetX); // Neigung des Flugzeugkopfes und des Ziels let b = targetY - k * targetX; // Konstante b
        item.y = item.y - 4; // y-Achse um eine Einheit verschoben item.x = (item.y - b) / k;
        für (sei i = 0; i < 15; i++) {
          // Den abschließenden Effekt zeichnen_this.ctx.beginPath();
          _diese.ctx.arc(
            (Punkt y + i * 1,8 - b) / k,
            Artikel.y + i * 1,8,
            4 - 0,2 * ich,
            0,
            2 * Math.PI
          );
          _this.ctx.fillStyle = `rgba(193,255,255,${1 - 0.08 * i})`;
          _this.ctx.fill();
          _this.ctx.closePath();
        }
      });
    }
  }
};
</Skript>
 
<!-- Fügen Sie das Attribut „scoped“ hinzu, um CSS nur auf diese Komponente zu beschränken -->
<style scoped lang="scss">
.Typ-Spiel {
  #Typ {
    Hintergrund: #2a4546;
  }
}
</Stil>

Oben finden Sie Einzelheiten zur Verwendung von VUE und Canvas zur Implementierung des Thunder Fighter-Tippspiels. Weitere Informationen zum VUE Thunder Fighter-Spiel finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

Das könnte Sie auch interessieren:
  • Vue verwendet Canvas, um Kreise zufälliger Größe und ohne Überlappung zu erzeugen
  • Vue verwendet Canvas, um den Bildkomprimierungs-Upload zu realisieren
  • So zeichnen Sie die Zeitleiste mit Vue+Canvas
  • VUE+Canvas realisiert den gesamten Prozess eines einfachen Gobang-Spiels
  • VUE+Canvas implementiert das Spiel God of Wealth und erhält Barren
  • VUE+Canvas implementiert den Beispielcode des Desktop-Flipper-Brick-Breaking-Spiels
  • Vue verwendet die Maus, um ein Rechteck auf Canvas zu zeichnen
  • Vue nutzt Canvas zur Implementierung mobiler handschriftlicher Signaturen
  • Vue+Canvas realisiert Puzzlespiel
  • Vue verwendet Canvas-Handschrifteingabe, um Chinesisch zu erkennen

<<:  Die wichtigsten Unterschiede zwischen MySQL 4.1/5.0/5.1/5.5/5.6

>>:  Einführung in das Batch-Cache-Löschskript von nginx proxy_cache

Artikel empfehlen

Verwendung des Linux-Befehls sed

1. Funktionseinführung sed (Stream EDitor) ist ei...

Eine kurze Analyse des Zustandsverständnisses von React

Wie definiert man komplexe Komponenten (Klassenko...

IIS 7.5 verwendet das URL-Rewrite-Modul, um eine Webseitenumleitung zu erreichen

Wir alle wissen, dass Apache in der Konfiguration...

Lösung für das Problem, dass sich der mysql8.0.11-Client nicht anmelden kann

In diesem Artikel erfahren Sie, wie Sie das Probl...

So überwachen Sie den Linux-Serverstatus

Wir, insbesondere Linux-Ingenieure, haben täglich...

Detaillierte Erklärung des Nginx Reverse-Proxy-Beispiels

1. Reverse-Proxy-Beispiel 1 1. Erzielen Sie den E...

So installieren und konfigurieren Sie den Apache-Webserver

Erfahren Sie, wie Sie Ihre eigene Website auf Apa...

Verwenden Sie thead, tfoot und tbody, um eine Tabelle zu erstellen

Manche Leute verwenden diese drei Tags auf pervers...

mysql Backup-Skript und halten Sie es für 7 Tage

Skriptanforderungen: Sichern Sie die MySQL-Datenb...

Einführung und Installation von vue-cli

Inhaltsverzeichnis 1. Einleitung 2. Einführung in...