Jeder hat schon Flipper und Ziegelsteinzertrümmerungsspiele gespielt. Verwenden Sie die linke und rechte Taste, um die Bewegung eines kleinen Holzbretts unten zu steuern, um den fallenden Ball aufzufangen, und lassen Sie den Ball dann nach oben springen, um den Ziegelsteinhaufen oben auf dem Bildschirm zu beseitigen. Wie lässt sich dies also mit VUE+Canvas erreichen? Die Idee ist ganz einfach. Lassen Sie uns zunächst den Inhalt aufteilen, der auf der Leinwand gezeichnet werden soll: (1) Verwenden Sie die linke und rechte Taste auf der Tastatur, um die Verschiebung des Holzbretts zu steuern. (2) Ein kleiner Ball, der auf der Leinwand herumspringt; (3) Ein Stapel Ziegel, der am oberen Bildschirmrand fixiert ist und verschwindet, wenn er vom Ball getroffen wird. Die oben genannten drei Objekte können mit der Funktion requestAnimationFrame() übersetzt und mit verschiedenen Kollisionsprüfungen kombiniert werden, um das Endergebnis zu erhalten. Schauen wir uns zunächst den Endeffekt an: 1. Das Holzbrett, das sich horizontal bewegtDas Holzbrett unten ist der einfachste Teil, da die Y-Koordinate des Bretts fest ist. Wir legen die Anfangsparameter des Bretts fest, einschließlich Breite, Höhe, Translationsgeschwindigkeit usw., und implementieren dann die Funktion zum Zeichnen des Bretts: Panel: { x: 0, y: 0, Höhe: 8, Breite: 100, Geschwindigkeit: 8, dx: 0 }, .... Zeichenpanel() { dies.drawRoundRect( dieses.panel.x, dieses.panel.y, diese.Panelbreite, diese.Panelhöhe, 5 ); }, drawRoundRect(x, y, width, height, radius) { // Zeichne ein abgerundetes Rechteck this.ctx.beginPath(); this.ctx.arc(x + Radius, y + Radius, Radius, Math.PI, (Math.PI * 3) / 2); this.ctx.lineTo(Breite - Radius + x, y); dies.ctx.arc( Breite - Radius + x, Radius + y, Radius, (Math.PI * 3) / 2, Math.PI * 2 ); this.ctx.lineTo(Breite + x, Höhe + y - Radius); dies.ctx.arc( Breite - Radius + x, Höhe - Radius + y, Radius, 0, (Math.PI * 1) / 2 ); dies.ctx.lineTo(Radius + x, Höhe + y); dies.ctx.arc( Radius + x, Höhe - Radius + y, Radius, (Math.PI * 1) / 2, Mathe.PI ); dies.ctx.fillStyle = "#008b8b"; dies.ctx.fill(); dies.ctx.closePath(); } Wenn das Programm initialisiert wird, werden die linken und rechten Pfeiltasten auf der Tastatur überwacht, um das Brett zu bewegen, und die Länge wird verwendet, um zu bestimmen, ob es sich bis zur linken oder rechten Grenze bewegt hat, sodass es sich nicht weiter aus dem Bildschirm hinaus bewegen kann: Dokument.onkeydown = Funktion(e) { let key = window.event.keyCode; wenn (Schlüssel === 37) { //Linke Taste_this.pannel.dx = -_this.pannel.speed; } sonst wenn (Schlüssel === 39) { //Rechte Taste_this.pannel.dx = _this.pannel.speed; } }; Dokument.onkeyup = Funktion(e) { _this.panel.dx = 0; }; .... VerschiebePanel() { dieses.panel.x += dieses.panel.dx; wenn (this.pannel.x > this.clientWidth - this.pannel.width) { dieses.pannel.x = diese.Clientbreite - diese.pannel.width; } sonst wenn (this.panel.x < 0) { dieses.panel.x = 0; } }, 2. Sprungball- und KollisionserkennungDie Bewegung des Balls ähnelt der des Bretts, mit der Ausnahme, dass es nicht nur einen dx-Versatz, sondern auch einen dy-Versatz gibt. Und es muss eine Kollisionserkennung geben: (1) Beim Aufprall auf die obere, rechte oder linke Wand sowie auf Holzbretter prallt es zurück. (2) Erfolgt der Zusammenstoß mit der unteren Begrenzung außerhalb des Bretts, ist das Spiel verloren; (3) Wenn der Ball mit einem Ziegelstein kollidiert, verschwindet der Ziegelstein, die Punktzahl erhöht sich um 1 und der Ball prallt zurück. Daher ist der Ballteil, genau wie das Holzbrett, in die Ballzeichenfunktion drawBall() und die Ballbewegungsfunktion moveBall() unterteilt: zeichneBall() { dies.ctx.beginPath(); dies.ctx.arc(dieser.ball.x, dieser.ball.y, dieser.ball.r, 0, 2 * Math.PI); dies.ctx.fillStyle = "#008b8b"; dies.ctx.fill(); dies.ctx.closePath(); }, bewegeBall() { dieser.ball.x += dieser.ball.dx; dieser.ball.y += dieser.ball.dy; dies.breaksHandle(); dies.edgeHandle(); }, brichtHandle() { // Brick-Touch-Erkennung this.breaks.forEach(item => { wenn (Artikel.anzeigen) { Wenn ( dieser.ball.x + dieser.ball.r > item.x && dieser.ball.x - dieser.ball.r < item.x + diese.breaksConfig.width && dieser.ball.y + dieser.ball.r > item.y && dieser.ball.y - dieser.ball.r < item.y + diese.breaksConfig.height ) { item.show = falsch; dieser.ball.dy *= -1; dies.score++; wenn (this.showBreaksCount === 0) { dies.gameOver = wahr; } } } }); }, Kantengriff() { // Kantenerkennung // Abprallen wenn es die Spitze erreicht if (this.ball.y - this.ball.r < 0) { dieser.ball.dy = -dieser.ball.dy; } Wenn ( //Triff die linke und rechte Wand this.ball.x - this.ball.r < 0 || dieser.ball.x + dieser.ball.r > diese.clientWidth ) { dieser.ball.dx = -dieser.ball.dx; } Wenn ( dieser.ball.x >= dieses.pannel.x && dieser.ball.x <= dieses.pannel.x + dieses.pannel.width && dieser.ball.y + dieser.ball.r >= diese.clientHeight - diese.pannel.height ) { // Die x-Linie des Balls liegt innerhalb der Reichweite des Bretts und berührt das Brett this.ball.dy *= -1; } sonst wenn ( (dieser.ball.x < dieses.panel.x || dieser.ball.x > dieses.pannel.x + dieses.pannel.width) && dieser.ball.y + dieser.ball.r >= diese.clientHeight ) { // Der Ball trifft die Unterkante this.gameOver = true; dies.getCurshBreaks(); } } 3. ZiegelgenerationAuch die Generierung von Bricks ist relativ einfach. Hier initialisieren wir einige Daten: unterbrichtKonfiguration: Zeile: 6, // Anzahl der Zeilen Höhe: 25, // Ziegelhöhe Breite: 130, // Ziegelbreite Radius: 5, // Rundung der Rechteckecken Space: 0, // Abstand Spalte: 6 // Anzahl der Spalten } Basierend auf diesen Konfigurationselementen und der Leinwandbreite können wir den horizontalen Abstand zwischen den einzelnen Steinen berechnen: // Berechne die Breite der Ziegellücke this.breaksConfig.space = Math.floor( (this.clientWidth - diese.breaksConfig.width * diese.breaksConfig.colunm) / (diese.breaksConfig.colunm + 1) ); So können wir die x- und y-Koordinaten jedes Steins auf der Leinwand ermitteln (bezogen auf die Koordinaten der oberen linken Ecke des Steins). für (lass i = 0; i < _this.breaksConfig.row; i++) { für (let j = 0; j < _this.breaksConfig.colunm; j++) { _dies.bricht.push({ x: diese.breaksConfig.space * (j + 1) + diese.breaksConfig.width * j, y: 10 * (i + 1) + this.breaksConfig.height * i, zeigen: wahr }); } } Plus die Funktion zum Zeichnen von Bausteinen: drawBreaks() { lass _this = dies; _this.breaks.forEach(item => { wenn (Artikel.anzeigen) { _this.drawRoundRect( item.x, Artikel.y, _this.breaksConfig.width, _this.breaksConfig.height, _this.breaksConfig.radius ); } }); } 4. Bewegen Sie die drei oben genannten Teile(Funktion animloop() { wenn (!_this.gameOver) { _this.movePanel(); _this.Ball bewegen(); _this.drawAll(); } anders { _this.drawCrushBreaks(); } Fenster.requestAnimationFrame(animloop); })(); .... zeichneAlles() { this.ctx.clearRect(0, 0, this.clientWidth, this.clientHeight); dies.drawPanel(); dies.drawBall(); dies.drawScore(); dies.drawBreaks(); } 5. Auswirkungen nach SpielendeIm ersten animierten Bild können Sie sehen, dass die Steine nach dem Ende des Spiels in mehrere kleine Bälle zersplittern, die herunterfallen. Dies ähnelt tatsächlich dem Zeichnen einzelner kleiner Bälle. Die Idee besteht darin, an den Mittelpunktskoordinaten der verbleibenden Steine eine Reihe kleiner Bälle unterschiedlicher Größe, Bewegungsbahnen und Farben zu erzeugen und dann die Animation fortzusetzen. getCurshBreaks() { lass _this = dies; dies.breaks.forEach(item => { wenn (Artikel.anzeigen) { item.show = falsch; for (let i = 0; i < 8; i++) { // Jeder Stein wird in 8 kleine Kugeln zerbrochen this.crushBalls.push({ x: Element.x + this.breaksConfig.width / 2, y: item.y + this.breaksConfig.height / 2, dx: _this.getRandomArbitrary(-6, 6), dy: _this.getRandomArbitrary(-6, 6), r: _this.getRandomArbitrary(1, 4), Farbe: _this.getRandomColor() }); } } }); }, zeichneCrushBreaks() { this.ctx.clearRect(0, 0, this.clientWidth, this.clientHeight); dies.crushBalls.forEach(item => { dies.ctx.beginPath(); dies.ctx.arc(Element.x, Element.y, Element.r, 0, 2 * Math.PI); dies.ctx.fillStyle = Element.Farbe; dies.ctx.fill(); dies.ctx.closePath(); Artikel.x += Artikel.dx; Element.y += Element.dy; Wenn ( // Triff die linke und rechte Wand item.x - item.r < 0 || item.x + item.r > this.clientWidth ) { Artikel.dx = -Artikel.dx; } Wenn ( // Schlagen gegen die obere und untere Wand item.y - item.r < 0 || item.y + item.r > diese.Clienthöhe ) { Artikel.dy = -Artikel.dy; } }); }, Oben ist die Implementierungsidee und ein Teil des Codes für das Desktop-Flipper-Brick-Breaking-Spiel. Die Implementierung ist sehr einfach und dieses Spiel kann mit zwei- oder dreihundert Codezeilen realisiert werden. Die Bewegung des Balles lässt sich dabei kontinuierlich optimieren und auch die Schwierigkeitsstufen können gesteigert werden. Hängen Sie abschließend alle Vue-Dateicodes zu Ihrer Information an: <Vorlage> <div Klasse="Breakball"> <canvas id="breakBall" width="900" height="600"></canvas> <div Klasse="Container" v-if="gameOver"> <div Klasse="Dialog"> <p class="once-again">Punktzahl dieser Runde: {{score}} Punkte</p> <p class="once-again">Es macht so viel Spaß! </p> <p class="once-again">Noch einmal~~</p> <el-button class="once-again-btn" @click="init">Starten</el-button> </div> </div> </div> </Vorlage> <Skript> const zufälligeFarbe = [ "#FF95CA", "#00E3E3", "#00E3E3", "#6F00D2", "#6F00D2", "#C2C287", "#ECFFFF", "#FFDC35", "#93FF93", „#d0d0d0“ ]; Standard exportieren { Name: "BreakBall", Daten() { zurückkehren { Clientbreite: 0, Clienthöhe: 0, ctx: null, zerquetschenBälle: [], Panel: { x: 0, y: 0, Höhe: 8, Breite: 100, Geschwindigkeit: 8, dx: 0 }, Ball: x: 0, y: 0, r: 8, dx: -4, dy: -4 }, Punktzahl: 0, gameOver: falsch, Pausen: [], unterbrichtKonfiguration: Zeile: 6, // Anzahl der Zeilen Höhe: 25, // Ziegelhöhe Breite: 130, // Ziegelbreite Radius: 5, // Rundung der Rechteckecken Space: 0, // Abstand Spalte: 6 // Anzahl der Spalten } }; }, montiert() { lass _this = dies; let container = document.getElementById("breakBall"); dies.ctx = container.getContext("2d"); this.clientHeight = Containerhöhe; this.clientWidth = Containerbreite; _this.init(); Dokument.onkeydown = Funktion(e) { let key = window.event.keyCode; wenn (Schlüssel === 37) { //Linke Taste_this.pannel.dx = -_this.pannel.speed; } sonst wenn (Schlüssel === 39) { //Rechte Taste_this.pannel.dx = _this.pannel.speed; } }; Dokument.onkeyup = Funktion(e) { _this.panel.dx = 0; }; (Funktion animloop() { wenn (!_this.gameOver) { _this.movePanel(); _this.Ball bewegen(); _this.drawAll(); } anders { _this.drawCrushBreaks(); } Fenster.requestAnimationFrame(animloop); })(); }, berechnet:{ zeigeBreaksCount(){ gib diesen.breaks.filter zurück(item=>{ Artikel zurückgeben.show; }).Länge; } }, Methoden: { init() { lass _this = dies; _this.gameOver = falsch; this.pannel.y = this.clientHeight - this.pannel.height; this.pannel.x = this.clientWidth / 2 – this.pannel.width / 2; dieser.ball.y = diese.clientHeight / 2; dieser.ball.x = diese.clientWidth / 2; dieser.Score = 0; dieser.ball.dx = [-1,1][Math.floor(Math.random() * 2)]*4; dieser.ball.dy = [-1,1][Math.floor(Math.random() * 2)]*4; dies.crushBalls = []; dies.breaks = []; // Berechne die Breite der Ziegellücke this.breaksConfig.space = Math.floor( (this.clientWidth - diese.breaksConfig.width * diese.breaksConfig.colunm) / (diese.breaksConfig.colunm + 1) ); für (lass i = 0; i < _this.breaksConfig.row; i++) { für (let j = 0; j < _this.breaksConfig.colunm; j++) { _dies.bricht.push({ x: diese.breaksConfig.space * (j + 1) + diese.breaksConfig.width * j, y: 10 * (i + 1) + this.breaksConfig.height * i, zeigen: wahr }); } } }, zeichneAlles() { this.ctx.clearRect(0, 0, this.clientWidth, this.clientHeight); dies.drawPanel(); dies.drawBall(); dies.drawScore(); dies.drawBreaks(); }, VerschiebePanel() { dieses.panel.x += dieses.panel.dx; wenn (this.pannel.x > this.clientWidth - this.pannel.width) { dieses.pannel.x = diese.Clientbreite - diese.pannel.width; } sonst wenn (this.panel.x < 0) { dieses.panel.x = 0; } }, bewegeBall() { dieser.ball.x += dieser.ball.dx; dieser.ball.y += dieser.ball.dy; dies.breaksHandle(); dies.edgeHandle(); }, brichtHandle() { // Brick-Touch-Erkennung this.breaks.forEach(item => { wenn (Artikel.anzeigen) { Wenn ( dieser.ball.x + dieser.ball.r > item.x && dieser.ball.x - dieser.ball.r < item.x + diese.breaksConfig.width && dieser.ball.y + dieser.ball.r > item.y && dieser.ball.y - dieser.ball.r < item.y + diese.breaksConfig.height ) { item.show = falsch; dieser.ball.dy *= -1; dies.score++; wenn (this.showBreaksCount === 0) { dies.gameOver = wahr; } } } }); }, Kantengriff() { // Kantenerkennung // Abprallen wenn es die Spitze erreicht if (this.ball.y - this.ball.r < 0) { dieser.ball.dy = -dieser.ball.dy; } Wenn ( //Triff die linke und rechte Wand this.ball.x - this.ball.r < 0 || dieser.ball.x + dieser.ball.r > diese.clientWidth ) { dieser.ball.dx = -dieser.ball.dx; } Wenn ( dieser.ball.x >= dieses.pannel.x && dieser.ball.x <= dieses.pannel.x + dieses.pannel.width && dieser.ball.y + dieser.ball.r >= diese.clientHeight - diese.pannel.height ) { // Die x-Achse des Balls liegt innerhalb der Reichweite des Bretts und berührt das Brett this.ball.dy *= -1; } sonst wenn ( (dieser.ball.x < dieses.panel.x || dieser.ball.x > dieses.pannel.x + dieses.pannel.width) && dieser.ball.y + dieser.ball.r >= diese.clientHeight ) { // Der Ball trifft die Unterkante this.gameOver = true; dies.getCurshBreaks(); } }, Punktestand zeichnen(){ dies.ctx.beginPath(); diese.ctx.font="14px Arial"; dies.ctx.fillStyle = "#FFF"; this.ctx.fillText("Punktzahl: "+this.score,10,this.clientHeight-14); dies.ctx.closePath(); }, zeichneCrushBreaks() { this.ctx.clearRect(0, 0, this.clientWidth, this.clientHeight); dies.crushBalls.forEach(item => { dies.ctx.beginPath(); dies.ctx.arc(Element.x, Element.y, Element.r, 0, 2 * Math.PI); dies.ctx.fillStyle = Element.Farbe; dies.ctx.fill(); dies.ctx.closePath(); Artikel.x += Artikel.dx; Element.y += Element.dy; Wenn ( // Triff die linke und rechte Wand item.x - item.r < 0 || item.x + item.r > this.clientWidth ) { Artikel.dx = -Artikel.dx; } Wenn ( // Schlagen gegen die obere und untere Wand item.y - item.r < 0 || item.y + item.r > diese.Clienthöhe ) { Artikel.dy = -Artikel.dy; } }); }, getRandomColor() { returniere Zufallsfarbe[Math.floor(Math.random() * Zufallsfarbe.length)]; }, getRandomArbitrary(min, max) { gibt Math.random() * (max - min) + min zurück; }, getCurshBreaks() { lass _this = dies; dies.breaks.forEach(item => { wenn (Artikel.anzeigen) { item.show = falsch; für (sei i = 0; i < 8; i++) { dies.crushBalls.push({ x: Element.x + this.breaksConfig.width / 2, y: item.y + this.breaksConfig.height / 2, dx: _this.getRandomArbitrary(-6, 6), dy: _this.getRandomArbitrary(-6, 6), r: _this.getRandomArbitrary(1, 4), Farbe: _this.getRandomColor() }); } } }); }, zeichneBall() { dies.ctx.beginPath(); dies.ctx.arc(dieser.ball.x, dieser.ball.y, dieser.ball.r, 0, 2 * Math.PI); dies.ctx.fillStyle = "#008b8b"; dies.ctx.fill(); dies.ctx.closePath(); }, Zeichenpanel() { dies.drawRoundRect( dieses.panel.x, dieses.panel.y, diese.Panelbreite, diese.Panelhöhe, 5 ); }, drawRoundRect(x, y, Breite, Höhe, Radius) { dies.ctx.beginPath(); this.ctx.arc(x + Radius, y + Radius, Radius, Math.PI, (Math.PI * 3) / 2); this.ctx.lineTo(Breite - Radius + x, y); dies.ctx.arc( Breite - Radius + x, Radius + y, Radius, (Math.PI * 3) / 2, Math.PI * 2 ); this.ctx.lineTo(Breite + x, Höhe + y - Radius); dies.ctx.arc( Breite - Radius + x, Höhe - Radius + y, Radius, 0, (Math.PI * 1) / 2 ); dies.ctx.lineTo(Radius + x, Höhe + y); dies.ctx.arc( Radius + x, Höhe - Radius + y, Radius, (Math.PI * 1) / 2, Mathe.PI ); dies.ctx.fillStyle = "#008b8b"; dies.ctx.fill(); dies.ctx.closePath(); }, drawBreaks() { lass _this = dies; _this.breaks.forEach(item => { wenn (Artikel.anzeigen) { _this.drawRoundRect( item.x, Artikel.y, _this.breaksConfig.width, _this.breaksConfig.height, _this.breaksConfig.radius ); } }); } } }; </Skript> <!-- Fügen Sie das Attribut „scoped“ hinzu, um CSS nur auf diese Komponente zu beschränken --> <style scoped lang="scss"> .Breakball { Breite: 900px; Höhe: 600px; Position: relativ; #breakBall { Hintergrund: #2a4546; } .container { Position: absolut; oben: 0; rechts: 0; unten: 0; links: 0; Hintergrundfarbe: rgba(0, 0, 0, 0,3); Textausrichtung: zentriert; Schriftgröße: 0; Leerzeichen: Nowrap; Überlauf: automatisch; } .container:nach { Inhalt: ""; Anzeige: Inline-Block; Höhe: 100%; vertikale Ausrichtung: Mitte; } .dialog { Breite: 400px; Höhe: 300px; Hintergrund: rgba(255, 255, 255, 0,5); Kastenschatten: 3px 3px 6px 3px rgba (0, 0, 0, 0,3); Anzeige: Inline-Block; vertikale Ausrichtung: Mitte; Textausrichtung: links; Schriftgröße: 28px; Farbe: #fff; Schriftstärke: 600; Rahmenradius: 10px; Leerzeichen: normal; Textausrichtung: zentriert; .noch einmal-btn { Hintergrund: #1f9a9a; Rand: keiner; Farbe: #fff; } } } </Stil> Dies ist das Ende dieses Artikels über VUE+Canvas zur Realisierung des Desktop-Flipper- und Brick-Breaking-Spiels. Weitere verwandte Inhalte zu VUE-Flipper- und Brick-Breaking-Spielen finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! Das könnte Sie auch interessieren:
|
<<: Detaillierte Erläuterung der FTP-Umgebungskonfigurationslösung (vsftpd)
>>: So ändern Sie MySQL, um Remoteverbindungen zuzulassen
Ich habe immer das Gefühl, dass Designer die sens...
Ein einfacher cooler Effekt, der mit CSS3-Animati...
FEHLER 1290 (HY000) : Der MySQL-Server wird mit d...
Ich habe zuvor die Verwendung des asynchronen Lad...
Speicherort der MySQL-Datenbank: 1. Wenn MySQL di...
Inhaltsverzeichnis 1. Ressourcendateien 2. Instal...
1. Stoppen Sie zuerst den mysqld.exe-Prozess 2. Ö...
In diesem Artikel wird die Installations- und Kon...
Die weltberühmte virtuelle Maschinensoftware VMwa...
Fügen Sie den erforderlichen Links Inline-Stile hi...
mysql-5.7.17.msi Installation, folgen Sie den Scr...
Bei der normalen Entwicklung verwenden wir normal...
Wir alle wissen, dass die in der Front-End-Entwic...
1. Übersicht Ich habe viel online gesucht und fes...
Zusammenfassung: HBase verfügt über zahlreiche Be...