2016-07-26 9 views
4

私はスプライトではなく行列でテトリスをJSに書き込もうとしています。 基本的には、2次元配列を視覚化する方がよいでしょう。テトリス2次元配列ロジック

ブロックを回転させるには、行列データを転置してから行を反転させます。 ブロックの幅と高さがこの4x4行列を完全に埋めるわけではないので、ブロック内の回転結果は、代わりに回転する代わりに移動します。

私はそれを見ることができません、私はすでにテトリスのような単純なゲームを得るために2日以上を過ごしました。何度か最初から再開します。 私は本当にしたいですゲームをプログラムすることができて、私が働いていたのはチックタックでした。私はそれよりも多くの時間を費やしました。

ここには完全なjsコードがあります。キャンバスをクリックすると、その部分が回転します。

var canvas = document.getElementById('c'); 
 
var ctx = canvas.getContext('2d'); 
 
canvas.width = 400; 
 
canvas.height = 600; 
 

 
// game object 
 
var G = {}; 
 
var current = 0; 
 
var x = 0; 
 
var y = 0; 
 

 
//GRID 
 
G.grid = []; 
 
G.gridColumns = 10; 
 
G.gridRows = 15; 
 
for (var i = 0; i < G.gridColumns; i++) { 
 
    G.grid[i] = []; 
 
    for (var j = 0; j < G.gridRows; j++) { 
 
    G.grid[i][j] = 0; 
 
    } 
 
} 
 

 
// Array with all different blocks 
 
G.blocks = []; 
 
//block constructor 
 
function block() {}; 
 
G.blocks[0] = new block(); 
 
G.blocks[0].matrix = [ 
 
    [1, 0, 0, 0], 
 
    [1, 1, 0, 0], 
 
    [0, 1, 0, 0], 
 
    [0, 0, 0, 0] 
 
]; 
 
G.blocks[0].width = 2; 
 
G.blocks[0].height = 3; 
 

 
function transpose(m) { 
 
    // dont understand this completely, but works because j<i 
 
    for (var i = 0; i < m.matrix.length; i++) { 
 
    for (var j = 0; j < i; j++) { 
 
     var temp = m.matrix[i][j]; 
 
     m.matrix[i][j] = m.matrix[j][i]; 
 
     m.matrix[j][i] = temp; 
 
    } 
 
    } 
 
} 
 

 
function reverseRows(m) { 
 
    for (var i = 0; i < m.matrix.length; i++) { 
 
    m.matrix[i].reverse(); 
 
    } 
 
} 
 

 
function rotate(m) { 
 
    transpose(m); 
 
    reverseRows(m); 
 
} 
 

 
function add(m1, m2) { 
 
    for (var i = 0; i < m1.matrix.length; i++) { 
 
    for (var j = 0; j < m1.matrix[i].length; j++) { 
 
     m2[i + x][j + y] = m1.matrix[i][j]; 
 
    } 
 
    } 
 
} 
 

 
function draw(matrix) { 
 
    for (var i = 0; i < matrix.length; i++) { 
 
    for (var j = 0; j < matrix[i].length; j++) { 
 
     if (matrix[i][j] === 1) { 
 
     ctx.fillRect(j * 20, i * 20, 19, 19); 
 
     } 
 
    } 
 
    } 
 
    ctx.strokeRect(0, 0, G.gridColumns * 20, G.gridRows * 20); 
 
} 
 

 

 
window.addEventListener("click", function(e) { 
 
    rotate(G.blocks[current]); 
 
}); 
 

 
function tick() { 
 
    ctx.clearRect(0, 0, canvas.width, canvas.height); 
 
    add(G.blocks[current], G.grid); 
 
    draw(G.grid); 
 
} 
 
setInterval(tick, 1000/30);
<canvas id="c"></canvas>

私のコードに少し癖を無視してください、私は自分でプログラミングを学びました。 ありがとうございます。

+0

正確にどのような** **は動作しませんか? – zero298

+0

なぜ4x4の代わりに3x3の行列を使用しないのですか? – Vanojx1

+2

@ Vanojx1 Tetrixの一部はおそらく4つのセルを長さ/幅にすることができます。 – zero298

答えて

2

あなたの問題は、あなたの作品が常に4タイル幅であると仮定していると思います。行列をまだ正方形である最小の空間に縮小することができます。 Z/Sブロックの場合、3x3になります。あなたの回転のの中心は正しく動作します。

あなたの問題は、ローテーションが正常に機能していることですが、ブリックの中心は(1,1)(底辺0を仮定)ではなくセル(2,2)にあります。 Cは、回転が適用される参照フレームです。

[x][ ][ ][ ][ ]  [ ][ ][X][X][ ] 
[X][X][ ][ ][ ]  [ ][X][X][ ][ ] 
[ ][X][C][ ][ ] => [ ][ ][C][ ][ ] 
[ ][ ][ ][ ][ ]  [ ][ ][ ][ ][ ] 
[ ][ ][ ][ ][ ]  [ ][ ][ ][ ][ ] 

あなたの形状をラップシュリンクことができれば、あなたはあなたの回転を適用すると、次のacheiveできます。実際の回転に

[x][ ][ ]  [ ][X][X] 
[X][C][ ] => [X][C][ ] 
[ ][X][ ]  [ ][ ][ ] 
+0

この素晴らしい概要ありがとうございました:) 私はすべての行列を最大のテトリスの大きさに保つと考えましたが、その論理は明らかにここには適用されません.. Doあなたはこのようなテトリスゲームでどのように私が衝突を使用するのか知っている、私はすでに回転を試みる前にそれですでに苦労している。 – onlyme0349

2

ローテーション

一つの問題は、それらのいくつかが進んでいないということです行列の幅が考慮されていても、それをすべて見てください。ゲームプレイの観点から

. X . .  . . . .  . . X .  . . . . 
. X . . => X X X X => . . X . => . . . . 
. X . .  . . . .  . . X .  X X X X 
. X . .  . . . .  . . X .  . . . . 

、あなたは3番目と4番目の形状が第一と第二のものと同一であることが期待される:さんは「I」形状の回転と何が起こるか見てみましょう。しかし、それはジェネリックローテーションアルゴリズムで起こることではありません。上記の問題に非正方行列(5x4)を使用して対処するかもしれませんが、アルゴリズムは当初想定していたより複雑になります。

実際には、ほとんどのテトリスの実装では、回転をプログラム的に気にせず、ローテーションを「公平」に見せるように、テトミノのさまざまな形状をハードコードするだけです' できるだけ。それについての素晴らしいことは、あなたが彼らのサイズについてもう心配する必要がないということです。それらをすべて4x4として保存することができます。

ここでは、これを非常にコンパクトなフォーマットで行うことができます。

あなたの努力は賞賛され、私の要点は、あなたの現在の解決策を働かせることを妨げるものではありません。まったく反対。私はちょうどあなたが後で実験したいかもしれない別のアプローチを提案したいと思います。ビットマスク

として

エンコーディングtetrominoesテトロミノは、基本的に「オン」または「オフ」のいずれかとすることができる「大きな画素」の設定されているため、なく、ビットマスクとしてそれを表現するために非常に適しかつ効率的です整数の行列

は、我々は「S」形状の二つの異なる回転をエンコードすることができる方法を見てみましょう:

X . . .  1 0 0 0 
X X . . = 1 1 0 0 = 1000110001000000 (in binary) = 0x8C40 (in hexadecimal) 
. X . .  0 1 0 0 
. . . .  0 0 0 0 

. X X .  0 1 1 0 
X X . . = 1 1 0 0 = 0110110000000000 (in binary) = 0x6C00 (in hexadecimal) 
. . . .  0 0 0 0 
. . . .  0 0 0 0 

他の二つの回転がこの1のために同じです。だから、我々は完全に私たちの「S」形状を定義することができます。

各形状についても同じことと、各回転を行う
[ 0x8C40, 0x6C00, 0x8C40, 0x6C00 ] 

、我々のようなもので終わる:

var shape = [ 
    [ 0x4640, 0x0E40, 0x4C40, 0x4E00 ], // 'T' 
    [ 0x8C40, 0x6C00, 0x8C40, 0x6C00 ], // 'S' 
    [ 0x4C80, 0xC600, 0x4C80, 0xC600 ], // 'Z' 
    [ 0x4444, 0x0F00, 0x4444, 0x0F00 ], // 'I' 
    [ 0x44C0, 0x8E00, 0xC880, 0xE200 ], // 'J' 
    [ 0x88C0, 0xE800, 0xC440, 0x2E00 ], // 'L' 
    [ 0xCC00, 0xCC00, 0xCC00, 0xCC00 ] // 'O' 
]; 

それらを描きます

今、この新しいフォーマットのテトロミノをどのように描こうとしていますか?むしろmatrix[y][x]で行列の値にアクセスするよりも、私たちはビットマスクに関連するビットをテストするつもりだ:

以下

for (var y = 0; y < 4; y++) { 
    for (var x = 0; x < 4; x++) { 
    if (shape[s][r] & (0x8000 >> (y * 4 + x))) { 
     ctx.fillRect(x * 20, y * 20, 19, 19); 
    } 
    } 
} 

デモは、このメソッドを使用して、いくつかのデモコードです。

var canvas = document.getElementById('c'); 
 
var ctx = canvas.getContext('2d'); 
 
canvas.width = 100; 
 
canvas.height = 100; 
 

 
var shape = [ 
 
    [ 0x4640, 0x0E40, 0x4C40, 0x4E00 ], // 'T' 
 
    [ 0x8C40, 0x6C00, 0x8C40, 0x6C00 ], // 'S' 
 
    [ 0x4C80, 0xC600, 0x4C80, 0xC600 ], // 'Z' 
 
    [ 0x4444, 0x0F00, 0x4444, 0x0F00 ], // 'I' 
 
    [ 0x44C0, 0x8E00, 0xC880, 0xE200 ], // 'J' 
 
    [ 0x88C0, 0xE800, 0xC440, 0x2E00 ], // 'L' 
 
    [ 0xCC00, 0xCC00, 0xCC00, 0xCC00 ] // 'O' 
 
]; 
 

 
var curShape = 0, curRotation = 0; 
 
draw(curShape, curRotation); 
 

 
function draw(s, r) { 
 
    ctx.fillStyle = 'white'; 
 
    ctx.fillRect(0, 0, 100, 100); 
 
    ctx.fillStyle = 'black'; 
 

 
    for (var y = 0; y < 4; y++) { 
 
    for (var x = 0; x < 4; x++) { 
 
     if (shape[s][r] & (0x8000 >> (y * 4 + x))) { 
 
     ctx.fillRect(x * 20, y * 20, 19, 19); 
 
     } 
 
    } 
 
    } 
 
} 
 

 
function next() { 
 
    curShape = (curShape + 1) % 7; 
 
    draw(curShape, curRotation); 
 
} 
 

 
function rotate() { 
 
    curRotation = (curRotation + 1) % 4; 
 
    draw(curShape, curRotation); 
 
}
<canvas id="c"></canvas> 
 
<button onclick="rotate()">Rotate</button> 
 
<button onclick="next()">Next shape</button>

+1

まず、ボタンタグのonclickパラメータが私のために機能しないのはなぜですか? 私は常にjsコードでeventlistenerを使用しなければなりませんでした。 第2に、この "(0x8000 >>(y * 4 + x))"コードが何をしているのか教えていただけますか?私はJavascriptでその演算子を見たことさえありません。 ありがとう、私は前にビットマスクのことを聞いたことがない、それらを使用することを学ぶことはおそらく非常に便利です。 – onlyme0349

+1

@ onlyme0349演算子は「ビット単位の右シフト演算子」です。ビット演算子については、[ここ](http://code.tutsplus.com/articles/understanding-bitwise-operators--active-11301)を参照してください。 – Mark

+0

@マークそれでも、何が起こっているのかを理解するのは本当に難しいです。おかげさまで、私は今それが何を呼んでいるか知っています。 :) – onlyme0349