テトリスは非常に古典的な小さなゲームで、私もそれを書いてみました。しかし、できるだけ簡潔で論理的なコードで実装したいと思っています。落下するブロックのモデルを記録したり、落下する各ブロックの 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 を応援していただければ幸いです。 以下もご興味があるかもしれません:
|
<<: Docker ベースの MySQL マスタースレーブレプリケーション環境を構築するための実装手順
>>: win2008 で mysql8.0.11 を mysql8.0.17 にアップグレードする詳細な手順
目次ブール型数値型文字列型文字列と数値を連結する未定義およびnull配列型タプル型列挙型あらゆるタイ...
Linux には、マウントされたハードディスクとマウントされていないハードディスクの 2 種類のハー...
1. this.$router.push() 1. ビュー <テンプレート> <d...
目次解決: 1. 無視する2. 交換する3. 重複キーの更新についてデータを挿入するときに、重複した...
HTMLに触れた当初はレイアウトにいつもテーブルを使っていましたが、とても面倒で見た目も悪かったの...
昨年、この公開書簡は大ヒットし、羅永浩氏を驚かせた。今日、著者が新しい章を発表するとは思ってもみなか...
Redux はシンプルな状態マネージャーです。その歴史をたどることはしません。使用法の観点から見ると...
目次1. 索引1.1 コンセプト1.2 機能1.3 索引作成の原則1.3.1 ディスクアクセス回数を...
LOFTER のコンテストで、ログイン ボックスを再設計できると言及されているのを見ました。過去 2...
関連する知識ポイント親コンポーネントから子コンポーネントに値を渡す子コンポーネントから親コンポーネン...
MySQL でメタデータ ロックがブロックされている場所を確認する方法手順: 1. セッション1の実...
この記事の例では、ふるい抽選を実装するためのミニプログラムの具体的なコードを参考までに共有しています...
記録として、将来使用される可能性があり、困っている友人も使用できます。 BBはもうやめて、まずはレン...
現在、CentOS の最新バージョンは CentOS 8 です。次に、CentOS Linux 8....
ドロップダウン メニューも実生活では非常に一般的です。実装に使用される js コードは、タブ選択やア...