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

推薦する

TypeScriptの基本型の詳細な説明

目次ブール型数値型文字列型文字列と数値を連結する未定義およびnull配列型タプル型列挙型あらゆるタイ...

Linux でハードディスクのサイズを確認し、ハードディスクをマウントする方法

Linux には、マウントされたハードディスクとマウントされていないハードディスクの 2 種類のハー...

Vueページジャンプの実装方法

1. this.$router.push() 1. ビュー <テンプレート> <d...

MySQLの主キーとユニークキーの重複挿入の解決策の詳細な説明

目次解決: 1. 無視する2. 交換する3. 重複キーの更新についてデータを挿入するときに、重複した...

HTML と CSS に関する基本的なメモ (フロントエンドでは必読)

HTMLに触れた当初はレイアウトにいつもテーブルを使っていましたが、とても面倒で見た目も悪かったの...

デザイナーが再びハマーの公式サイトに不満を述べる

昨年、この公開書簡は大ヒットし、羅永浩氏を驚かせた。今日、著者が新しい章を発表するとは思ってもみなか...

react+reduxを使用してカウンター機能を実装すると発生する問題

Redux はシンプルな状態マネージャーです。その歴史をたどることはしません。使用法の観点から見ると...

MySQL データベースのインデックスとトランザクション

目次1. 索引1.1 コンセプト1.2 機能1.3 索引作成の原則1.3.1 ディスクアクセス回数を...

163 メールボックスログインボックスインタラクティブデザインの改善体験と共有

LOFTER のコンテストで、ログイン ボックスを再設計できると言及されているのを見ました。過去 2...

Vue コンポーネント化の一般的な方法: コンポーネント値の転送と通信

関連する知識ポイント親コンポーネントから子コンポーネントに値を渡す子コンポーネントから親コンポーネン...

MySQL でメタデータ ロックがブロックされている場所を確認する方法

MySQL でメタデータ ロックがブロックされている場所を確認する方法手順: 1. セッション1の実...

ふるい抽選を実施するミニプログラム

この記事の例では、ふるい抽選を実装するためのミニプログラムの具体的なコードを参考までに共有しています...

HTML+CSS を使用して、画像の右上隅に削除の十字と画像削除ボタンを追加します。

記録として、将来使用される可能性があり、困っている友人も使用できます。 BBはもうやめて、まずはレン...

CentOS8 Linux 8.0.1905 のインストール手順(図解)

現在、CentOS の最新バージョンは CentOS 8 です。次に、CentOS Linux 8....

ドロップダウンメニューを実装するためのネイティブ js

ドロップダウン メニューも実生活では非常に一般的です。実装に使用される js コードは、タブ選択やア...