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 にアップグレードする詳細な手順

推薦する

Windows 10 システムで Mysql8.0.13 のルート パスワードを忘れる方法

1. まずmysqlサービスを停止します管理者としてCMDを開いて閉じるか、Windowsサービスペ...

MySQL シリーズ 10 同時実行制御を実装するための MySQL トランザクション分離

目次1.同時アクセス制御2. 取引1. トランザクションは ACID 原則に従います。 2. トラン...

HTML のスクロールバーについて/スクロールバーの削除

1. xhtmlの下のスクロールバーの色元の HTML では、ページ全体のスクロール バーを次のよう...

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

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

CSS を使用して正方形の div を実装する 2 つの方法

目標: 辺の長さが等しい正方形を作成する方法 1: 単位 vw を使用する (ps これが最も簡単な...

jsはシンプルなショッピングカートモジュールを実装します

この記事の例では、参考までに、シンプルなショッピングカートモジュールを実装するためのjsの具体的なコ...

MySQL マスター スレーブ データが矛盾しています。プロンプト: Slave_SQL_Running: 解決策はありません

この記事では、MySQL マスターとスレーブ データ間の不一致の解決方法と、プロンプト「Slave_...

MySQL 8.0.12 のインストールと設定方法のグラフィックチュートリアル

MySQL 8.0.12のインストールと設定方法を記録してみんなで共有します。 1. インストール1...

親要素を基準にCSSの位置を絶対的に設定する方法についての簡単な説明

ご存知のとおり、CSS の絶対位置はデフォルトでドキュメントに応じて設定されます。たとえば、posi...

Nginx で同じドメイン名を持つ複数のプロジェクトを構成する方法

Nginx を使用して同じドメイン名で複数のプロジェクトを構成するには、次の 2 つの方法があります...

Typescriptを使用してWeChatミニプログラムを開発するための詳細な手順

Typescript の利点については詳しく説明する必要はありません。ご興味があれば、(https:...

MySQL から Excel にテーブルデータをエクスポートする際の日時形式に関する簡単な説明

最近、MySQL を使用してテーブル データを Excel ファイルにエクスポートしました。MySQ...

MySQLはinit-connectを使用してアクセス監査機能の実装を増やします

まず init-connect を通じて mysql 接続を初期化し、次にインスタンスに接続する必要...

pagodaを使用してionCube拡張機能をインストールする方法

1. まずパゴダを設置するインストール要件: Python バージョン: 2.6/2.7 (Pago...

React Stateの状態とライフサイクルの実装方法

1. コンポーネントの実装方法:組件名稱首字母必須大寫1. JS関数を通じてコン​​ポーネントを実装...