JSはスネークゲームを実装する

JSはスネークゲームを実装する

ページ効果:

Snake ゲームは、メディエーター モデルを使用して開発されます。Snake のケースは、以前のように 1 つの HTML ファイルに記述されるのではなく、クラスに分割されます。個別の js が各クラスを表し、メディエーター クラスは Game クラスです。

1. 初期化構造

まず、ページを初期化する必要があります。初期化レイアウトはHTMLタグに直接記述されるのではなく、ゲームノードツリーを通じて初期化されます。

行を表すために this.row を使用し、列を表すために this.col を使用して、20 行 20 列のテーブルを設定します。

Games.prototype.init = 関数(){
    this.dom = document.createElement('table');
    var tr、td;
    //行と列のツリーをトラバースする for (var i = 0; i < this.row; i++) {
        // 行を走査してノード上にツリーを作成します tr = document.createElement('tr');
 
        (var j = 0; j < this.col; j++) の場合 {
            // 列をトラバースしてノード上にツリーを作成します td = document.createElement('td');
            // ツリーにノードを追加します tr.appendChild(td);
 
 
            // ツリーにノードを追加します this.dom.appendChild(tr);
 
        }
    }
    // テーブル上のツリー document.getElementById('app').appendChild(this.dom);
}

結果:

2. 蛇の色のレンダリング

スネークをレンダリングするためのロジック: スネーク クラスは、Game クラスの setColor メソッドを呼び出します。これは、本質的にはテーブルの色をレンダリングするためです。テーブルは Game クラスが初期化されるときに作成されるため、Game に色をレンダリングするためのメソッドを設定させるのは合理的です。

// 色を設定するメソッド Games.prototype.setColor = function (row, col, color) {
    // テーブルの行と列の色を設定します。this.dom.getElementsByTagName('tr')[row].getElementsByTagName('td')[col].style.backgroundColor = color;
}

この時点で、SnakeクラスはgameのsetColorメソッドを呼び出すようになります。

Snake.prototype.render = 関数 () {
    // ヘビのレンダリング game.setColor(this.body[0].row, this.body[0].col, 'pink');
    // スネークボディ for (var i = 1; i < this.body.length; i++) {
        game.setColor(this.body[i].row, this.body[i].col, 'skyblue');
    }
}

この時点で、誰が Snake のレンダリングを呼び出すのかという疑問が生じます。 Snakeのコンストラクタでゲームを呼び出すことはできません。Gameクラスの4つのステップがまだ実行されていないため、現在は未定義です。

解決策はタイマーを呼び出すことです。タイマーは非同期なので、Game クラスの 4 つのステップの実行を妨げることはありません。

    this.timer = setInterval(関数() {
        // タイマーの核はゲーム レンダリングの本質、つまり画面のクリア - 更新 - レンダリングです // スネークをレンダリングします game.snake.render();
    }, 20);

結果:

3. ヘビの動き

ヘビの動きは、実際にはボディ配列の更新です。本質は、ボディ配列の尾を削除し、頭を追加して、ヘビが新しい状態をレンダリングすることです。

Snake.prototype.update = 関数(){
 
    // 現在の方向はwilldirectionを受け取ります
    this.direction = this.willDirection;
    スイッチ(this.direction) {
        ケース 'R':
            this.body.unshift({ '行': this.body[0].row, '列': this.body[0].col + 1 });
            壊す;
        ケース 'D':
            this.body.unshift({ '行': this.body[0].row + 1, '列': this.body[0].col });
            壊す;
        ケース 'L':
            this.body.unshift({ '行': this.body[0].row, '列': this.body[0].col - 1 });
            壊す;
        ケース 'T':
            this.body.unshift({ '行': this.body[0].row - 1, '列': this.body[0].col });
            壊す;
    }

この時点で、蛇はどんどん長くなっていることがわかります

スネークに色のレンダリング方法を伝えたので、以前のレンダリングを消去する必要があります。

ゲームの画面を消去する方法を設定しました

// 画面をクリアする Games.prototype.clear = function () {
    (var i = 0; i < this.row; i++) の場合 {
        (var j = 0; j < this.col; j++) の場合 {
            this.dom.getElementsByTagName('tr')[i].getElementsByTagName('td')[j].style.backgroundColor = '#fff';
            this.dom.getElementsByTagName('tr')[i].getElementsByTagName('td')[j].innerHTML = '';
        }
    }
}

次に、タイマーでゲームの3つのステップを実行します。画面のクリア、更新、レンダリングです。

 // 画面をクリアします game.clear();
        // スネークの動き/更新 // スネークの更新速度 スネーク側が長いほど速度が上がります var during = game.snake.body.length < 30 ? 30 - game.snake.body.length : 1;
        // Snake 更新 game.f % during == 0 && game.snake.update();
        // ヘビをレンダリングします game.snake.render();

ヘビはさまざまな方向に移動します。Game の bindEvent イベントを設定すると、キーボード イベントを監視し、さまざまな方向を変更し、ヘビの頭が下に移動したときに上キーが押せないことを判断できます。

Games.prototype.bindEvent = 関数(){
    var self = this;
    //キーボードイベント document.onkeydown = function (even) {
        スイッチ (even.keyCode) {
            ケース37:
                // まず、現在の方向が右に移動している場合、この時点で左ボタンを押すことはできません。 if (self.snake.direction == 'R') return;
                方向をLに変更します。
                壊す;
            ケース38:
                // まず、現在の方向が下向きであるかどうかを判断し、この時点で上キーを押すことはできません。 if (self.snake.direction == 'D') return;
                方向を変更します。
                壊す;
            ケース39:
                // まず、現在の方向が左に移動している場合、この時点では右ボタンを押すことはできません。 if (self.snake.direction == 'L') return;
                方向を変更します。
                壊す;
            ケース40:
                // まず、現在の方向が上向きの場合、この時点ではキーを押すことができません。 if (self.snake.direction == 'T') return;
                方向変更('D')
                壊す;
        }
    }
}

このとき、Snake クラスにも対応する方向の一致が必要です。Snake を初期化するときに this.direction='R' を設定します。

Snake.prototype.update = 関数(){
 
    // 現在の方向はwilldirectionを受け取ります
    this.direction = this.willDirection;
    スイッチ(this.direction) {
        ケース 'R':
            this.body.unshift({ '行': this.body[0].row, '列': this.body[0].col + 1 });
            壊す;
        ケース 'D':
            this.body.unshift({ '行': this.body[0].row + 1, '列': this.body[0].col });
            壊す;
        ケース 'L':
            this.body.unshift({ '行': this.body[0].row, '列': this.body[0].col - 1 });
            壊す;
        ケース 'T':
            this.body.unshift({ '行': this.body[0].row - 1, '列': this.body[0].col });
            壊す;
    }

4. ヘビの死を判定する方法 ヘビの死を判定する方法は2つあります

1つ目は、蛇自体がテーブル部分を超えていることです

 // テーブルの端を超える部分 if (this.body[0].col > game.col - 1 || this.body[0].row > game.row - 1 || this.body[0].col < 0 || this.body[0].row < 0) {
        alert('ゲームオーバー、現在のスコアは ' + game.score です);
        ゲームのタイマーをクリアします。
        this.body.shift();
        ゲームのタイマーをクリアします。
    }

2つ目は、蛇自体が体の一部と重なっていることです。

  // 自身をヒット for (var i = 1; i < this.body.length; i++) {
        this.body[0].col == this.body[i].col && this.body[0].row == this.body[i].row)の場合{
            alert('ゲームオーバー、現在のスコアは ' + game.score です);
            this.body.shift();
            ゲームのタイマーをクリアします。
        }
    }

5. 食品の創造

この時点で、食べ物を生産するためのFoodクラスを作成し、Gameでインスタンス化し、タイマーでレンダリングします。

食べ物の列と行をランダムに生成するときは、まずそれがヘビの上にあるかどうかを確認します。

関数 Food(gameSnake) {
    var self = this;
    // 食べ物の場所 // do-while ループ ステートメントは、最初に行と列を作成し、次に行と列がヘビの上にあるかどうかを判断します。do {
        this.row = parseInt(Math.random() * gameSnake.row);
        this.col = parseInt(Math.random() * gameSnake.col);
    } while ((関数 () {
        // ヘビの行と列を走査し、それらを新しくランダムに生成された食品の行と列と比較して、それらが重複しているかどうかを確認します for (var i = 0; i < gameSnake.snake.body.length; i++) {
            gameSnake.snake.body[i].row == self.row && gameSnake.snake.body[i].col == self.col) の場合 {
                true を返します。
            }
 
        }
        false を返します。
    })())
 
    コンソールにログ出力します。
}
 
Food.prototype.render = 関数(){
    game.setHTML(this.row, this.col, '♥');
}

6. ヘビが食べる餌の長さ

ヘビが移動すると、配列本体の先頭に要素が追加され、尾の要素が削除されます。したがって、ヘビの頭が餌に触れた後は、尾をそのままにしておけばよいだけです。

   this.body[0].row == game.food.row && this.body[0].col == game.food.col) の場合 {
        // 新しい食べ物を作成します。game.food = new Food(game);
        // フレーム番号を0に戻す
        // スコアを追加 game.score++;
        ゲーム.f = 0;
    } それ以外 {
        this.body.pop();
    }

ヘビは餌を早く食べる

餌に当たるまで増加するフレーム番号を設定し、ヘビの長さが長くなるにつれてヘビの更新速度を速めます。

         0 を返します。
        ゲーム.f++;
       // ヘビの速度を更新します。ヘビの側面が長くなると、速度が上がります。var during = game.snake.body.length < 30 ? 30 - game.snake.body.length : 1;
        // Snake 更新 game.f % during == 0 && game.snake.update();
        // ヘビをレンダリングする

7. ゲーム開始機能

HTML でボタンを記述し、位置決めによって適切な場所に配置し、クリック イベントを与えるだけで、開始ボタンをクリックした後にのみ Game 内のコードが実行されます。

 <div id="アプリ"></div>
    <div class="startgame"><img src="images/btn1.gif" alt=""></div>
    <div class="stopgame"><img src="images/btn4.png" alt=""></div>
    <スクリプト>
        var ゲーム = null;
        var btnstart = document.querySelector('.startgame');
        var btnstop = document.querySelector('.stopgame')
        btnstart.addEventListener('click', 関数() {
            btnstart.style.display = 'なし';
            ゲーム = 新しいゲーム();
            // コンソールログ(テーブル);
            var テーブル = document.querySelector('テーブル');
            table.addEventListener('click', 関数() {
                ゲームのタイマーをクリアします。
                btnstop.style.display = 'ブロック';
            })

8. ゲームの一時停止/再開機能

一時停止ボタンとテーブルの両方にクリック イベントを設定します。テーブルをクリックすると、停止ボタンが表示され、ゲーム内のタイマーが停止します。一時停止ボタンをクリックすると、タイマーが開始して非表示になります。

     btnstop.addEventListener('click', 関数() {
                btnstop.style.display = 'なし';
                game.timer = setInterval(関数() {
                    // タイマーの核はゲーム レンダリングの本質です。画面をクリア - 更新 - レンダリング game.f++;
                    // document.getElementById('f').innerHTML = 'フレーム番号:' + game.f;
                    // // スコアをレンダリングします // document.getElementById('score').innerHTML = 'Score:' + game.score;
                    // 画面をクリアします game.clear();
                    // スネークの動き/更新 // スネークの更新速度 スネーク側が長いほど速度が上がります var during = game.snake.body.length < 30 ? 30 - game.snake.body.length : 1;
                    // Snake 更新 game.f % during == 0 && game.snake.update();
                    // ヘビをレンダリングします game.snake.render();
                    // 食べ物をレンダリングする game.food.render();
                }, 10);
            })

これで、JS で Snake ゲームを実装する方法に関するこの記事は終了です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援して頂ければ幸いです。

以下もご興味があるかもしれません:
  • JavaScript の絶妙なスネーク実装プロセス
  • スネークゲームのアイデアを実現するためのJavaScript
  • 古典的なスネークゲームの JavaScript 実装
  • JS 実用的なオブジェクト指向スネークゲームの例

<<:  LeetCode の SQL 実装 (178. スコアランキング)

>>:  Docker に ElasticSearch をインストールする方法を 1 つの記事で解説

推薦する

MysqlクエリJSON結果に関連する関数の概要

JSON 形式のフィールドは、MySQL 5.7 で追加された新しい属性ですが、基本的には文字列とし...

MySQL プロジェクトでトランザクション分離レベルを選択する方法

導入コンテンツから始めましょう。誰もが次のような面接のシナリオに遭遇したことがあると思います。インタ...

mysql-8.0.19-winx64 をインストールしてログインするための初心者向けチュートリアル (初心者必読)

目次1. インストールパッケージ(64ビット)をダウンロードする2. MySQLデータベースをインス...

JavaScript 配列 sort() メソッドの基本的な使い方と落とし穴

序文日常のコード開発では、配列のソートに関連する操作が多数あります。JavaScript では、so...

CSS を使用して画像の下の空白を数ピクセル消去する方法の詳細な説明

最近、友人が私に質問をしました。ページをレイアウトすると、画像の下に 1 ~ 2 ピクセルの空白があ...

JavaScript の基礎: スコープ

目次範囲グローバルスコープ関数のスコープもし、スイッチ、のために、その間ブロックスコープスコープチェ...

CSSの固定位置属性の詳細な説明

モバイル アプリを開発する場合、Web サイトが特定の高さまでスクロールしたときにコンテンツの一部を...

HTML でマウスが停止したときに行全体の色 (tr) を変更する方法

純粋な CSS を使用して、マウスが行の上を通過するときに行の背景色を変更し、その行にフォーカスがあ...

Deepin Linuxでカーネルを手動でアップグレードする方法

deepinとUbuntuどちらもdebianをベースにしたディストリビューションであり、ここではU...

MySQLデータベースのロック機構の分析

同時アクセスの場合、非反復読み取りやその他の読み取り現象が発生する可能性があります。高い同時実行性に...

JavaScript でシンプルなクリスマス ゲームを実装する

目次序文成果を達成するコードCSSコードJSコードHTMLコードデモンストレーションのプロセス序文ク...

Dockerを使用してphabricatorをインストールする方法

ここでは Ubuntu 16.04 システムを使用しています。 dockerを使用したインストールh...