onlyme0349 onlyme0349 - 4 months ago 50
Javascript Question

Tetris 2d array logic

I'm trying to write tetris in JS with matrixes instead of sprites.
Basically to be better at visualising 2d arrays.

I rotate a block by transposing its matrix data and then reversing the rows.
But because the block's width and height doesn't completely fill this 4x4 matrix
the rotating results in the block moving, instead of rotating in place.

I can't see it, i've already spent more than two days with trying to get such a simple game as tetris working, restarting from scratch a couple of times..
I need help, i really want to be able to program games, and the only thing i got working was tic tac toe. Which i spent more time on than i should.

Here's the full js code. Clicking the canvas rotates the piece.



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>





Please ignore the little quirks in my code, i learned programming by myself.
Thanks in advance :)

Answer

I think your issue is that you are always assuming your piece is 4 tiles wide. You may want to shrink wrap your matrix to the smallest space that is still a square. For your Z/S blocks, it would be 3x3. Then the center of your rotation would act correctly.

Your issue right now is that the rotation is kind of working correctly, but the center of your brick is at cell (2, 2) rather than (1, 1) (assuming base 0). C is the reference frame around which your rotation is being applied.

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

If you could shrink wrap your shape, you could apply your rotation and acheive the following:

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