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

推薦する

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

Centos6.4 で mysql5.7.18 をインストールするための具体的な手順が全員に共有され...

Docker+K8S クラスタ環境構築と分散アプリケーション展開

1. Dockerをインストールする yumでdockerをインストール #サービスを開始する sy...

Vue3+Vantコンポーネントを使用してアプリの検索履歴機能を実装する(サンプルコード)

現在、新しいアプリプロジェクトを開発中です。私にとっても初めてのアプリ開発です。チームで調査と検討を...

WeChat アプレット uniapp は左スワイプによる削除効果を実現します (完全なコード)

WeChatアプレットuniappは左スワイプで削除効果を実現成果を達成する1. スワイプしてリス...

良い広告にはどのような特徴が必要ですか?

広告業は人間であることに似ていると言う人がいます。これは本当です。優れた広告には、優れた人間と同じよ...

CentOS に Nginx をインストールする方法

公式ドキュメント: https://nginx.org/en/linux_packages.html...

Centos6でgitlabを構築する方法

序文元のプロジェクトは、パブリックネットワークgitlabに配置されていました。セキュリティ上の理由...

MySQL における UNION と UNION ALL の基本的な使い方

データベースでは、UNION キーワードと UNION ALL キーワードの両方が 2 つの結果セッ...

CSS3は光る境界線効果を実現します

操作効果: html <!-- この要素は表示されません。DOM は JavaScript に...

MySQL の if 関数の正しい使い方の詳細な説明

今日私が書こうとしている内容では、プログラムは 7 時間近く実行され、データベースに 1,000 万...

アクセス速度を上げるためにウェブサイトを最適化する方法の更新

最近、同社はitpubを皮切りに、コーポレートウェブサイト傘下の全サイトの評価を開始した。そのために...

CentOS での mysql5.7 の詳細なインストールと設定のチュートリアル

インストールユーザーにインストール権限があることを確認してくださいルートスイッチなしsuルート(su...

nginx-ingress-controller ログ永続化ソリューションのソリューション

最近、nginx-ingress-controller のアプリケーションについて説明した公開アカウ...

ZabbixはSNMPに基づいてLinuxホストを監視します

序文: Linux ホストは、エージェント プログラムをインストールする場合でも、SNMP を使用す...

変数が空かどうかを判定するシェルの方法の概要

シェルで変数が空かどうかを判断する方法シェルプログラミングでは、パラメータのエラーチェック項目に、変...