JavaScript キャンバス テトリス ゲーム

JavaScript キャンバス テトリス ゲーム

テトリスは非常に古典的な小さなゲームで、私もそれを書いてみました。しかし、できるだけ簡潔で論理的なコードで実装したいと思っています。落下するブロックのモデルを記録したり、落下する各ブロックの x と y を記録したりするのに、あまり多くのコードは必要ありません。次のようなアイデアについて考えてみたところ、このように書くのが非常に簡潔であることがわかりました。

テトリスには 7 つの基本モデルがあります。

これらのモデルを記録する方法は、相対位置の記録、各ブロックの x、y 座標の記録など、多数あります。これら 7 つのモデルを記録するというアイデアを思いつきました。左シフト、右シフト、回転関数を記述するときに非常に簡潔で使いやすいです。次の配列はこれらのモデルを記録します。

var cubeArr=[[6,7,12,13],[7,8,11,12],[6,7,11,12],[7,12,17,8],[7,12,16,17],[7,12,17,22],[7,11,12,13]];

アイデア:

0 から始まる番号が付けられた 5*5 のテーブル。 12番の点が中心点です。各モデルはラベルとともに記録されます。たとえば、最初のモデルは [6,7,12,13] です。

表の左上隅を参照点とすると、次のような規則があります。表内の数字を値とすると、値を 5 で割った余りが参照点に対する点の x オフセットとなり、値を 5 で割った整数部分が参照点に対する点の y オフセットとなります。回転もとても簡単です。中心の12を中心に回転することで、いくつかのパターンを見つけることもできます。

var movex=cubeNow[i]%5;
var movey=Math.floor(cubeNow[i]/5);

ループ付きのモデルを描く

関数drawEle(color)
    {
        ctx.fillStyle=色;
        ctx.strokeStyle='#fff';
        (var i=0;i<4;i++) の場合
        {
            var movex=downInfor.cubeNow[i]%5;
            var movey=Math.floor(downInfor.cubeNow[i]/5);
            ctx.fillRect(cubeW*(downInfor.point[0]+movex),cubeW*(downInfor.point[1]+movey),cubeW,cubeW);
            ctx.strokeRect(cubeW*(downInfor.point[0]+movex),cubeW*(downInfor.point[1]+movey),cubeW,cubeW)
        }
} 

モデルを回転します。

この配列を通じて、モデルを回転させることにより、現在の位置と次の回転位置の関係を簡単に実現できます。たとえば、位置が 0 で時計回りに回転する場合、次の位置は 4 になります。位置番号が 6 の場合、次の位置は 8 です。次の配列は、前の位置から次の位置を見つけることができます。

var rotateArr=[4,9,14,19,24,3,8,13,18,23,2,7,12,17,22,1,6,11,16,21,0,5,10,15,20];

コード:

<!DOCTYPE html>
<html lang="ja">
<ヘッド>
    <メタ文字セット="UTF-8">
    <title>テトリス</title>
</head>
<本文>
<div>
    <div style="display:inline-block">
     <canvas id="can" height="480" width="300" style="border:3px solid black;"></canvas>
    </div>
    <div id="info" style="display:inline-block;height:600px;vertical-align: top;font-family: tmb; font-size:14pt; color:green;">
    <span>スコア:</span><span id="score">0</span>
     </div>
</div>
<script type="text/javascript">
    var キューブW = 20;
    var cubeArr=[[6,7,12,13],[7,8,11,12],[6,7,11,12],[7,12,17,8],[7,12,16,17],[7,12,17,22],[7,11,12,13]];
    var colorArr=['#ffc0cb','#dda0dd','#9370db','#6495ed','#fa8072','#ff8c00','#008000'];
    var rotateArr=[4,9,14,19,24,3,8,13,18,23,2,7,12,17,22,1,6,11,16,21,0,5,10,15,20];
    var キャンバス = document.getElementById('can');
    var ctx = canvas.getContext('2d');
    var スコア = document.getElementById('スコア');
    var canWidth=canvas.width;
    var canHeight=canvas.height;
    var downInfor = {}、staticCube = [];
    var myinter;
    window.initialize = function() //初期化{
        線を引く();
        (var i=0;i<(canWidth/cubeW);i++) の場合
        {
            静的キューブ[i] = [];
            (var j=0;j<(canHeight/cubeW);j++) の場合
            {
                静的キューブ[i][j] = 0;
            }
        }
        Cube を初期化します。
        myinter=setInterval('movedown()',200); //最初のパラメータは引用符で囲む必要があります}
    関数drawline()
    {
        ctx.lineWidth=1;
        ctx.strokeStyle='#ddd';
        (var i=0;i<(canWidth/cubeW);i++) の場合
        {
          ctx.moveTo(キューブW*i,0);
          ctx.lineTo(cubeW*i,canHeight);
        }
        ctx.stroke();
        (var j=0;j<(canHeight/cubeW);j++) の場合
        {
            ctx.moveTo(0,cubeW*j);
            ctx.lineTo(canHeight,cubeW*j);
        }
        ctx.stroke();
    }
    関数 initCube()
    {
           var index=Math.floor(Math.random()*cubeArr.length);//ランダムに生成 downInfor.cubeNow=cubeArr[index].concat();
            downInfor.index=インデックス;
            downInfor.prepoint=[5,-1];
            ダウンインフォメーションポイント=[5,-1];
            要素を描画します(colorArr[downInfor.index]);
    }
    関数movedown()
    {
        //次の位置が妥当かどうかを判断しますvar length,isempty=true,px,py,movex,movey,max=0;
        (var i=0;i<4;i++) の場合
        {
            最大値<downInfor.cubeNow[i]の場合
                最大値 = downInfor.cubeNow[i];
        }
        長さ=Math.ceil(max/5);
        (var i=0;i<4;i++) の場合
        {
            px=downInfor.point[0]+downInfor.cubeNow[i]%5;
            py=downInfor.point[1]+1+Math.floor(downInfor.cubeNow[i]/5);
            静的キューブ[px][py]==1の場合
            {
                isempty=false;
                壊す;
            }
        }
        if((downInfor.point[1]+length)<(canHeight/cubeW)&&isempty)
        {
            downInfor.prepoint=downInfor.point.concat(); //参照型に注意してください downInfor.point[1]=downInfor.point[1]+1;
            クリアエレメント();
            要素を描画します(colorArr[downInfor.index]);
        }
        else // 移動できない場合 {
            (var i=0;i<4;i++) の場合
            {
                px=downInfor.point[0]+downInfor.cubeNow[i]%5;
                py=downInfor.point[1]+Math.floor(downInfor.cubeNow[i]/5);
                静的キューブ[px][py]=1;
            }
            描画エレメント('#555')
            チェックフルライン();
        }
 
    }
    関数moveLeft()
    {
        var leftroom=4,isempty=true,px,py,movex,movey;
        (var i=0;i<4;i++) の場合
        {
            px=downInfor.point[0]-1+downInfor.cubeNow[i]%5;
            py=downInfor.point[1]+Math.floor(downInfor.cubeNow[i]/5);
            if((downInfor.cubeNow[i]%5)<leftroom)
                左の部屋=downInfor.cubeNow[i]%5;
            静的キューブ[px][py]==1の場合
            {
                isempty=false;
                壊す;
            }
        }
        if((downInfor.point[0]+leftroom)>=0&&isempty)
        {
            downInfor.prepoint=downInfor.point.concat();
            ダウンインフォメーションポイント[0]=ダウンインフォメーションポイント[0]-1;
            クリアエレメント();
            要素を描画します(colorArr[downInfor.index]);
        }
    }
    関数moveRight()
    {
        var rightroom=0,isempty=true,px,py,movex,movey;
        (var i=0;i<4;i++) の場合
        {
            px=downInfor.point[0]+1+downInfor.cubeNow[i]%5;
            py=downInfor.point[1]+Math.floor(downInfor.cubeNow[i]/5);
            if((downInfor.cubeNow[i]%5)>右の部屋)
                右の部屋=downInfor.cubeNow[i]%5;
            静的キューブ[px][py]==1の場合
            {
                isempty=false;
                壊す;
            }
        }
        if((downInfor.point[0]+rightroom+1)<(canWidth/cubeW)&&isempty)
        {
            downInfor.prepoint=downInfor.point.concat();
            ダウンインフォメーションポイント[0]=ダウンインフォメーションポイント[0]+1;
            クリアエレメント();
            要素を描画します(colorArr[downInfor.index]);
        }
    }
    function moverotate()//回転処理 {
        var isempty=true,px,py,movex,movey, tempRotate=[0,0,0,0];
        (var i=0;i<4;i++) の場合
        {
            tempRotate[i] = rotateArr[downInfor.cubeNow[i]];
        }
        (var i=0;i<4;i++) の場合
        {
            px=downInfor.point[0]+tempRotate[i]%3;
            py=downInfor.point[1]+Math.floor(tempRotate[i]/3);
            静的キューブ[px][py]==1の場合
            {
                isempty=false;
                壊す;
            }
        }
        if(空)
        {
            downInfor.prepoint=downInfor.point.concat();
            クリアエレメント();
            downInfor.cubeNow = tempRotate.concat();
            要素を描画します(colorArr[downInfor.index]);
        }
 
    }
    関数drawEle(color)
    {
        ctx.fillStyle=色;
        ctx.strokeStyle='#fff';
        (var i=0;i<4;i++) の場合
        {
            var movex=downInfor.cubeNow[i]%5;
            var movey=Math.floor(downInfor.cubeNow[i]/5);
            ctx.fillRect(cubeW*(downInfor.point[0]+movex),cubeW*(downInfor.point[1]+movey),cubeW,cubeW);
            ctx.strokeRect(cubeW*(downInfor.point[0]+movex),cubeW*(downInfor.point[1]+movey),cubeW,cubeW)
        }
    }
    関数 clearEle()
    {
        ctx.lineWidth=1;
        ctx.strokeStyle='#ddd';
        (var i=0;i<4;i++) の場合
        {
            var movex=downInfor.cubeNow[i]%5;
            var movey=Math.floor(downInfor.cubeNow[i]/5);
            ctx.clearRect(cubeW*(downInfor.prepoint[0]+movex),cubeW*(downInfor.prepoint[1]+movey),cubeW,cubeW);
            ctx.strokeRect(cubeW*(downInfor.prepoint[0]+movex),cubeW*(downInfor.prepoint[1]+movey),cubeW,cubeW)
        }
    }
    function checkfullLine()// 行が完全かどうかをチェックする {
        var isFullLine=true、index=0、changeScore=false;
        for(var i=0;i<canWidth/cubeW;i++)
        {
            静的キューブ[i][0]==1の場合
            {
                alert('ゲームオーバー!');
                クリア間隔(myinterval);
                戻る;
            }
        }
        (var i=canHeight/cubeW-1;i>=0;i--) の場合
        {
            フルラインかどうかをチェックします。
            (var j=0;j<(canWidth/cubeW);j++) の場合
            {
                静的キューブ[j][i]==0の場合
                {
                    isFullLine = false;
                }
            }
            if(isFullLine)// 1点追加 {
                score.innerHTML = parseInt(score.innerText) + 1;
                スコアを変更します。
                (var s=i;s>=0;s--) {
                    (var j = 0; j < (canWidth / cubeW); j++) {
                        (s- 1) >= 0 ? staticCube[j][s] = staticCube[j][s - 1] : staticCube[j][s] = 0;
                    }
                }
            }
        }
        if(スコア変更)
        {
            ctx.clearRect(0,0,canWidth,canHeight);
            線を引く();
            ctx.fillStyle='555';
            ctx.strokeStyle='#fff';
            (var i=0;i<(canWidth/cubeW);i++) の場合
            {
                (var j=0;j<(canHeight/cubeW);j++) の場合
                {
                    静的キューブ[i][j]==1の場合
                    {
                        ctx.fillRect(cubeW*i,cubeW*j,cubeW,cubeW);
                        ctx.strokeRect(cubeW*i,cubeW*j,cubeW,cubeW);
                    }
                }
            }
        }
        Cube を初期化します。
    }
    window.onkeydown=関数 (evt)
    {
       スイッチ(evt.keyCode)
       {
           ケース 37: //leftmoveLeft();
               壊す;
           ケース 38: //moverotate();
               壊す;
           ケース 39: //右へ moveRight();
               壊す;
           ケース 40: //movedown();
               壊す;
       }
    }
</スクリプト>
</本文>
</html>

効果:

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • JavaScript でテトリス ゲームを実装するためのアイデアと方法
  • JS テトリス、完全なデザインコンセプトを含む
  • JS テトリスの完璧にコメントされたコード
  • テトリスのウェブ版を書くための JAVASCRIPT コード
  • テトリスを実装するための 60 行の js コード
  • JSコードを使用してテトリスゲームを実装する
  • JavaScript で簡単なテトリスの完全な例を実装する
  • JavaScript で実装されたテトリス ゲームの分析とソースコードの共有
  • JS+Canvas で実装されたテトリス ゲームの完全な例
  • js html5 css テトリス ゲームの再登場

<<:  Docker ベースの MySQL マスタースレーブレプリケーション環境を構築するための実装手順

>>:  win2008 で mysql8.0.11 を mysql8.0.17 にアップグレードする詳細な手順

推薦する

HTML テーブルタグチュートリアル (12): 境界線スタイル属性 FRAME

FRAME プロパティを使用して、表の境界線のスタイル タイプを制御します。基本的な構文<T...

クロスドメインの問題を解決するためのNginxの実用的な方法

フロントエンドとバックエンドを分離し、nginxを使用してクロスドメインの問題を解決するフロントエン...

Vue の長いリストをすばやく読み込む方法

目次背景メインコンテンツ1. コンポーネントの比較2. 実装のアイデア3. キーメソッドソースコード...

ウェブサイトデザインの経験 ウェブサイト構築におけるよくある間違いのまとめ

注意: 計画、設計、開発のいずれの場合でも、これらの間違いは避けなければなりません。 1. ナビゲー...

MySql 5.7.21 無料インストール バージョンの構成方法 (Win10 の場合)

1.インストールしたい場所に解凍し、my.iniファイルを作成します。 my.iniの内容は次のと...

JavaScriptの構文とコード構造に関する深い理解

目次概要機能性と読みやすさ空白括弧セミコロンインデント身元大文字と小文字を区別予約キーワード概要すべ...

Ubuntu 20.04 では、隠し録音ノイズ低減機能が有効になります (推奨)

最近、 Ubuntu 20.04でkazamを使用して録音しているときに、問題が見つかりました。シス...

JavaScript のよりエレガントなエラー処理方法 async await

目次背景なぜエラー処理が必要なのでしょうか? async await より適切なエラー処理まとめ要約...

重複したMySQLレコードを現場でチェックし、処理する実践的な記録

目次序文分析するデータ合計繰り返し率どこにあるかと持っているかの違い要約する序文私はソフトウェアの導...

IDEA が MySQL データベースに接続できない問題の 6 つの解決策

この記事では、IDEA が MySQL データベースに接続できない問題に対する 6 つの解決策を主に...

シンプルなウェブデザインコンセプトのカラーマッチング

(I)ウェブページのカラーマッチングの基本概念(1)白黒の言葉は永遠のテーマです。誰もそれを悪く言う...

フロートをクリアするための CSS メソッドの概要

フロートはWebページのレイアウトでよく使用されますが、フローティングブロックレベル要素は標準のドキ...

Linux システム構成 (サービス制御) の詳細な紹介

目次序文1. システムサービス制御1. システムctl 2. ターゲット3. 共通システムサービス4...

Windows7 での Mysql5.7 my.ini ファイルの読み込みパスとデータの場所の変更方法

更新: MySQL の公式 Web サイトにアクセスして MySQL インストーラーをインストールし...

CentOS7 での PostgreSQL 11 の詳細なインストールと設定のチュートリアル

1. 公式ウェブサイトアドレス公式サイトではインストールの参考手順が紹介されています。公式サイトを見...