VUE+Canvasは、インゴットを受け取る富の神のゲームを実装します

VUE+Canvasは、インゴットを受け取る富の神のゲームを実装します

前回のキャンバス ゲーム シリーズへようこそ:

《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 を応援してください。

以下もご興味があるかもしれません:
  • VueはCanvasを使用してランダムなサイズで重なり合わない円を生成します
  • Vueはキャンバスを使用して画像圧縮アップロードを実現します
  • vue+canvasでタイムラインを描く方法
  • VUE+CanvasはシンプルなGobangゲームの全プロセスを実現します
  • VUE と Canvas を使用して Thunder Fighter タイピング ゲームを実装する方法
  • VUE+Canvasはデスクトップピンボールブロック破壊ゲームのサンプルコードを実装します
  • Vueはマウスを使ってキャンバス上に四角形を描きます
  • Vueはキャンバスを使用してモバイル手書き署名を実装します
  • Vue+canvasでパズルゲームを実現
  • Vueはキャンバスの手書き入力を使用して中国語を認識します

<<:  MySQLクエリステートメント内のユーザー変数のコード分析

>>:  VMware での Linux CentOS6.9 インストール グラフィック チュートリアル

推薦する

CentOS7.5 MySQLのインストールチュートリアル

1. まずシステムにmysqlがインストールされているかどうかを確認します rpm -qa | gr...

HTML の基本的な使用法には、リンク、スタイルシート、span、div などが含まれます。

1. リンクハイパーテキスト リンクは HTML において非常に重要です。基本的な形式は次のとおりで...

SQL における distinct と row_number() over() の違いと使い方

1 はじめにデータベース内のデータを操作するための SQL 文を記述するときに、いくつかの不快な問題...

Clickhouse Docker クラスターの展開と構成を例を使って説明します

目次前面に書かれた環境の展開Zookeeper クラスタの展開Clickhouse クラスターの展開...

HTML でスクロールバーを使用する際のヒントを共有する

今日、牛南ニュースリリースシステムについて学んでいたとき、牛南先生はスクロールバーに関するいくつかの...

負荷分散と動的・静的分離を実現するNginx+Tomcatの原理の分析

1. Nginx ロードバランシングの実装原理1. Nginxはリバースプロキシを通じて負荷分散を実...

Vue の nextTick について話す

データが変更されても、DOM ビューはすぐには更新されません。変更直後にノードまたはその値を取得しよ...

MySql への新しいユーザーの追加、ユーザー用のデータベースの作成、ユーザーへの権限の割り当ての概要

1. 新しいユーザーを追加するローカルIPアクセスのみを許可する '123456' ...

Javascript デザインパターン プロトタイプ モードの詳細

目次1. プロトタイプモード例1例2例3 2. オブザーバーパターン1. プロトタイプモードプロトタ...

Jsモジュールパッケージのエクスポートの使用法と違いにはインポートが必要

目次1. Commonjsのエクスポートとrequireの使用1.1 CommonJS エクスポート...

MySQL で中国語の文字をピンインでソートする簡単な例

名前を格納するフィールドが GBK 文字セットを使用している場合、GBK 内部コード自体がエンコード...

燃える炎効果の英語フォント16種類をシェアする

私たちは視覚の世界に住んでおり、多くの視覚効果に囲まれています。コンピューターの前にいても、屋外にい...

ウェブページの HTML コード: スクロールテキストの作成

このセクションでは、Web ページ内のテキストをスクロールしたり、スクロール プロパティを制御できる...

CSS のオーバーフロー:hidden エラーの解決方法

失敗の原因今日、カルーセルを書いていたときに、overflow;hidden; が失敗する可能性があ...

Centos8.3、dockerデプロイメントspringbootプロジェクトの実際のケース分析

導入現在、k8s は非常に人気があり、それについて学ぶために本を購入しました。しかし、k8s では数...