前回のキャンバス ゲーム シリーズへようこそ: 《VUEがFlappy Birdを実装しました〜〜〜》 単語当てゲーム 《VUE+Canvas がデスクトップ ピンボール ブロック崩しゲームを実現》 《VUE+Canvasでサンダーファイターのタイピングゲームを実装》 タイトルの通り、誰もがプレイしたことがある、どこでも見かけるゲームです。左右の方向キーを使って富の神の動きをコントロールし、空から落ちてくる金塊をキャッチします。時間切れになるとゲームは終了します。まずは効果を見てみましょう: 弾丸を発射して飛び交う前回のサンダーファイターと比べると、今回のエレメントの移動軌跡は非常にシンプルで、宝石は垂直に、富の神は水平に動きます。前回のコードと同様に、重要な手順は次のとおりです。 1. キーボード操作で富の神が水平方向に移動する これは非常にシンプルで、「デスクトップ ピンボール ブロック除去ゲームを実現する VUE+Canvas」のスライダーの制御に似ています。 描画カイシェン() { _this = this とします。 _this.ctx.save(); _this.ctx.drawImage( _this.caishenImg、 _this.caishen.x, _this.caishen.y、 120, 120 ); _this.ctx.restore(); }, 移動Caishen() { this.caishen.x += this.caishen.dx; if (this.caishen.x > this.clientWidth - 120) { this.caishen.x = this.clientWidth - 120; } それ以外の場合 (this.caishen.x < 0) { this.caishen.x = 0; } } 2. 空から降ってくる宝石 これも非常にシンプルですが、宝石の初期 x 値を 0 から clientWidth までランダムに取ることはできないことに注意してください。宝石が重なり合ってゲームのプレイアビリティに影響を与える可能性があるためです。そのため、宝石は異なるトラックに散在させるのが最適です。ここでは、キャンバスの幅を 5 つのトラックに分割します。宝石が最初に描画されるときに、トラックに散在させ、y 値を一定の高さにランダムに設定して、ずらした外観を作成します。次に、新しく生成された宝石は、宝石が密集しないように、トラックの分布に従って生成されます。 宝物を生成する() { _this = this とします。 _this.treasureArr.length < MaxNum の場合 { ランダム = Math.floor(Math.random() * TreasureNames.length); チャンネルを_this.getRandomArbitrary(1, 5);とします。 _this.treasureArr.push({ x: _this.channelWidth * (1 / 2 + (チャンネル - 1)) - 30, y: 0, 名前: TreasureNames[ランダム], 速度: _this.getRandomArbitrary(2, 4) }); } }, フィルター宝物(アイテム) { _this = this とします。 もし ( item.x <= _this.caishen.x + 110 && item.x >= _this.caishen.x && アイテム.y > _this.caishen.y ){ // 富の神との接触範囲を決定する_this.score += _this.treasureObj[item.name].score; false を返します。 } if (item.y >= _this.clientHeight) { false を返します。 } true を返します。 }, 宝物を描く() { _this = this とします。 _this.treasureArr = _this.treasureArr.filter(_this.filterTreasure); _this.treasureArr.forEach(item => { _this.ctx.drawImage( _this.treasureObj[アイテム名].src, アイテム.x、 アイテム.y、 60, 60 ); アイテムのy + = アイテムの速度; }); }, getRandomArbitrary(最小値, 最大値) { Math.random() * (max - min) + min を返します。 } ここでは、フィルター関数を使用して、消えるはずの宝石をフィルターします。for+splice+i-- メソッドを使用すると、ジッターが発生します。 そして、各宝石にランダムな移動速度を与え、宝石が富神の画像範囲に入ると、対応するスコアが蓄積されます。 3. カウントダウンリング カウントダウンを 30 秒に設定します。次に、requestAnimationFrame コールバックで、現在の時刻と最後のタイムスタンプの差が 1000 ミリ秒より大きいかどうかを計算して秒数を計算します。次に、別のタイムスタンプを取得して進行状況を累積し、リングのスムーズな動きを実現します。 描画カウントダウン() { // 進捗リングを描画します。let _this = this; _this.progress += Date.now() - _this.timeTag2; _this.timeTag2 = Date.now(); _this.ctx.beginPath(); _this.ctx.moveTo(50, 50); _this.ctx.arc( 50, 50, 40, 数学.PI * 1.5、 Math.PI * (1.5 + 2 * (_this.progress / (countDownInit * 1000)))、 間違い ); _this.ctx.closePath(); _this.ctx.fillStyle = "黄色"; _this.ctx.fill(); // 塗りつぶされた円を描画します_this.ctx.beginPath(); _this.ctx.arc(50, 50, 30, 0, Math.PI * 2); _this.ctx.closePath(); _this.ctx.fillStyle = "#fff"; _this.ctx.fill(); // 入力 text_this.ctx.font = "bold 16px Microsoft YaHei"; _this.ctx.fillStyle = "#333"; _this.ctx.textAlign = "center"; _this.ctx.textBaseline = "中央"; _this.ctx.moveTo(50, 50); _this.ctx.fillText(_this.countDown + "s", 50, 50); } (関数animloop() { _this.ctx.clearRect(0, 0, _this.clientWidth, _this.clientHeight); _this.loop(); アニメーションID = window.requestAnimationFrame(animloop); _this.countDown === 0 の場合 _this.gameOver = true; window.cancelAnimationFrame(アニメーションID); } Date.now() - _this.timeTag >= 1000 の場合 { _this.countDown--; _this.timeTag = Date.now(); } })(); この時点で、富の神が金塊をキャッチするという非常に単純なゲームが完成しました。もちろん、難易度を上げるために、爆弾を連続して落とすセグメントを設定することもできます。原理は宝石の動きと同じです。 以下に参考用の完全なコードを示します。 <テンプレート> <div class="caishen"> <canvas id="caishen" width="1200" height="750"></canvas> <div class="container" v-if="ゲームオーバー"> <div class="ダイアログ"> <p class="once-again">おめでとうございます! </p> <p class="once-again">このラウンドの宝物: {{ score }} ポイント</p> </div> </div> </div> </テンプレート> <スクリプト> 定数TreasureNames = [ 「元宝」、 「トンチアン」、 「ジンティアオ」、 "shuijin_red", "shuijin_blue", 「ふだい」 ]; アニメーションIDをnullにします。 countDownInit = 0 とします。 定数MaxNum = 5; エクスポートデフォルト{ 名前:「CaiShen」、 データ() { 戻る { スコア: 0, ctx: null、 caishenImg: null、 クライアント幅: 0, クライアントの高さ: 0, チャネル幅: 0, 財神: x: 0, y: 0, 速度: 8, 度: 0 }, 進捗: 0, カウントダウン: 30, 時間タグ: Date.now(), timeTag2: Date.now(), treasureArr: [], ゲームオーバー: false、 宝物オブジェクト: { 元宝: スコア: 5, ソース: null }, トンチェン: スコア: 2, ソース: null }, ジンティアオ: スコア: 10, ソース: null }, shuijin_red: スコア: 20, ソース: null }, shuijin_blue: { スコア: 15, ソース: null }, 府代: スコア: 8, ソース: null } } }; }, マウント() { _this = this とします。 コンテナを document.getElementById("caishen"); _this.ctx = コンテナ.getContext("2d"); _this.clientWidth = コンテナの幅; _this.clientHeight = コンテナの高さ; _this.channelWidth = Math.floor(_this.clientWidth / 5); _this.caishenImg = 新しい画像(); _this.caishenImg.src = require("@/assets/img/caishen/财神爷.png"); _this.initTreasures(); countDownInit = _this.countDown; _this.caishen.x = _this.clientWidth / 2 - 60; _this.caishen.y = _this.clientHeight - 120; document.onkeydown = 関数(e) { キーを window.event.keyCode とします。 (キー === 37) の場合 { //左 button_this.caishen.dx = -_this.caishen.speed; } そうでない場合 (キー === 39) { //右ボタン_this.caishen.dx = _this.caishen.speed; } }; document.onkeyup = 関数(e) { _this.caishen.dx = 0; }; _this.caishenImg.onload = 関数() { (関数animloop() { _this.ctx.clearRect(0, 0, _this.clientWidth, _this.clientHeight); _this.loop(); アニメーションID = window.requestAnimationFrame(animloop); _this.countDown === 0 の場合 _this.gameOver = true; window.cancelAnimationFrame(アニメーションID); } Date.now() - _this.timeTag >= 1000 の場合 { _this.countDown--; _this.timeTag = Date.now(); } })(); }; }, メソッド: { 宝物を初期化する() { _this = this とします。 Object.keys(_this.treasureObj).forEach(キー => { _this.treasureObj[キー].src = 新しいイメージ(); _this.treasureObj[ 鍵 ].src.src = require(`@/assets/img/caishen/${key}.png`); }); (i = 0; i < MaxNum; i++) の場合 { ランダム = Math.floor(Math.random() * TreasureNames.length); _this.treasureArr.push({ x: _this.channelWidth * (1 / 2 + i) - 30, y: _this.getRandomArbitrary(0, 20)、 名前: TreasureNames[ランダム], 速度: _this.getRandomArbitrary(2, 4) }); } }, ループ() { _this = this とします。 _this.drawCountDown(); _this.drawCaishen(); _this.moveCaishen(); _this.generateTreasure(); _this.drawTreasure(); _this.drawScore(); }, 描画カイシェン() { _this = this とします。 _this.ctx.save(); _this.ctx.drawImage( _this.caishenImg、 _this.caishen.x, _this.caishen.y、 120, 120 ); _this.ctx.restore(); }, 移動Caishen() { this.caishen.x += this.caishen.dx; if (this.caishen.x > this.clientWidth - 120) { this.caishen.x = this.clientWidth - 120; } それ以外の場合 (this.caishen.x < 0) { this.caishen.x = 0; } }, スコアを描画する() { _this = this とします。 _this.ctx.beginPath(); _this.ctx.fillStyle = "#fff"; _this.ctx.textAlign = "center"; _this.ctx.textBaseline = "中央"; _this.ctx.fillText(_this.score + "分", 30, _this.clientHeight - 10); _this.ctx.closePath(); }, 描画カウントダウン() { // 進捗リングを描画します。let _this = this; _this.progress += Date.now() - _this.timeTag2; _this.timeTag2 = Date.now(); _this.ctx.beginPath(); _this.ctx.moveTo(50, 50); _this.ctx.arc( 50, 50, 40, 数学.PI * 1.5、 Math.PI * (1.5 + 2 * (_this.progress / (countDownInit * 1000)))、 間違い ); _this.ctx.closePath(); _this.ctx.fillStyle = "黄色"; _this.ctx.fill(); // 塗りつぶされた円を描画します_this.ctx.beginPath(); _this.ctx.arc(50, 50, 30, 0, Math.PI * 2); _this.ctx.closePath(); _this.ctx.fillStyle = "#fff"; _this.ctx.fill(); // 入力 text_this.ctx.font = "bold 16px Microsoft YaHei"; _this.ctx.fillStyle = "#333"; _this.ctx.textAlign = "center"; _this.ctx.textBaseline = "中央"; _this.ctx.moveTo(50, 50); _this.ctx.fillText(_this.countDown + "s", 50, 50); }, フィルター宝物(アイテム) { _this = this とします。 もし ( item.x <= _this.caishen.x + 110 && item.x >= _this.caishen.x && アイテム.y > _this.caishen.y ){ // 富の神との接触範囲を決定する_this.score += _this.treasureObj[item.name].score; false を返します。 } if (item.y >= _this.clientHeight) { false を返します。 } true を返します。 }, 宝物を描く() { _this = this とします。 _this.treasureArr = _this.treasureArr.filter(_this.filterTreasure); _this.treasureArr.forEach(item => { _this.ctx.drawImage( _this.treasureObj[アイテム名].src, アイテム.x、 アイテム.y、 60, 60 ); アイテムのy + = アイテムの速度; }); }, ランダムに取得(最小値, 最大値) { Math.random() * (max - min) + min を返します。 }, 宝物を生成する() { _this = this とします。 _this.treasureArr.length < MaxNum の場合 { ランダム = Math.floor(Math.random() * TreasureNames.length); チャンネルを_this.getRandomArbitrary(1, 5);とします。 _this.treasureArr.push({ x: _this.channelWidth * (1 / 2 + (チャンネル - 1)) - 30, y: 0, 名前: TreasureNames[ランダム], 速度: _this.getRandomArbitrary(2, 4) }); } } } }; </スクリプト> <!-- CSS をこのコンポーネントのみに制限するために "scoped" 属性を追加します --> <スタイル スコープ lang="scss"> #財神 背景色: #b00600; 背景画像: url("~assets/img/caishen/brick-wall.png"); } 。容器 { 位置: 絶対; 上: 0; 右: 0; 下部: 0; 左: 0; 背景色: rgba(0, 0, 0, 0.3); テキスト配置: 中央; フォントサイズ: 0; 空白: ラップなし; オーバーフロー:自動; } .コンテナ:後{ コンテンツ: ""; 表示: インラインブロック; 高さ: 100%; 垂直位置合わせ: 中央; } .ダイアログ{ 幅: 400ピクセル; 高さ: 300px; 背景: rgba(255, 255, 255, 0.5); ボックスの影: 3px 3px 6px 3px rgba(0, 0, 0, 0.3); 表示: インラインブロック; 垂直位置合わせ: 中央; テキスト配置: 左; フォントサイズ: 28px; 色: #fff; フォントの太さ: 600; 境界線の半径: 10px; 空白: 通常; テキスト配置: 中央; .もう一度-btn { 背景: #1f9a9a; 境界線: なし; 色: #fff; } } </スタイル> これで、VUE+Canvas で富神インゴット獲得ゲームを実現した記事は終了です。Vue インゴット獲得ゲームの関連コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM を応援してください。 以下もご興味があるかもしれません:
|
<<: MySQLクエリステートメント内のユーザー変数のコード分析
>>: VMware での Linux CentOS6.9 インストール グラフィック チュートリアル
この記事では、テキスト中央の両側に水平線を引く効果を実現する CSS のサンプルコードを紹介し、皆さ...
以下は、B+ ツリーのデータ構造と実験結果からの推測に基づいた私の判断です。間違いがあればご指摘くだ...
この記事では、スライディングスコアリングを実装するためのuniappの具体的なコードを参考までに共有...
reduceメソッドは配列の反復メソッドです。 mapやfilterとは異なり、 reduceメソッ...
目次パーティションテーブルとはパーティションテーブルの適用シナリオパーティションテーブルの制限パーテ...
先週、先生が私に数字当てゲームをするちょっとした宿題を出しました。とても面白いと思ったので、適当に書...
目次1. はじめに2. 本文2.1 Where句の位置2.2 演算子2.3 NULL値1. はじめに...
目次非同期を理解するフェッチ(url)レスポンス.json() asyncとawaitを組み合わせる...
この記事の目的は、これらの概念とその機能の関係を明らかにすることです。 Mysql がトランザクショ...
Linux は現在最も広く使用されているサーバー オペレーティング システムです。Unix をベー...
目次1. ツールの紹介2. ワークフロー3. 操作インターフェースとパラメータ設定(1)監視と再起動...
この記事では、例を使用して、MySQL ストアド プロシージャでの case ステートメントの使用方...
1. dhtmlxツリー dHTMLxTree は機能豊富なツリー メニュー コントロールです。豊...
MySQL で使用される自動インクリメント ID には多くの種類があり、各自動インクリメント ID ...
バックエンドからフロントエンドまで、なんと悲劇なのでしょう。他の人の CSS を自分の jsp We...