En la anterior entrega, explicamos cómo podríamos representar las piezas: básicamente, utilizando matrices con ceros y unos, de manera que un uno representará un cuadrado pintado en pantalla, mientras que un cero representará un hueco vacío. Por ejemplo:
class PieceL extends Piece {
constructor()
{
super( [ [ 1, 0 ],
[ 1, 0 ],
[ 1, 0 ],
[ 1, 1 ] ],
"orange" );
}
}
La clase Piece tiene una matriz shape en la que se va a guardar la matriz que representará a esa "L". De acuerdo, pero... ¿cómo podemos rotar las piezas?
Las piezas rotarán en el sentido de las agujas del reloj. En realidad, no hay tantas formas distintas por cada pieza: de hecho, la que tendrá más formas distintas serán precisamente la "L" y la "L" inversa.
Hay dos formas de conseguir esto:
La genérica: para cada matriz, cambiar filas por columnas. Utiliza poca memoria, aunque necesita mayor complejidad de procesamiento cada vez que se rota.
La simple: para cada pieza, guardar las posibles formas que adquiere al rotar. Es necesario guardar un selector con la forma que se está empleando en cada momento. Utiliza más memoria, pero es muy rápido.
1 | 2 | 3 | 4 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | ||||||
1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | ||||||
1 | 1 | 0 | 1 |
En la tabla anterior, podemos ver las distintas formas para la "L" (a partir de la forma 4, se vuelve a la 1). Es la pieza (junto con la "L" inversa) que tiene más formas, cuatro en total. La pieza que tiene menos formas es el cuadrado, que solo tiene una. La "barra" solo tiene dos. A continuación, vemos cómo se definen la "barra" y la "L".
class PieceBar extends Piece {
constructor()
{
super( [
[ [ 1 ],
[ 1 ],
[ 1 ],
[ 1 ] ],
[ [ 1, 1, 1, 1 ] ],
],
"darkcyan" ); // color
}
}
class PieceL extends Piece {
constructor()
{
super( [
[ [ 1, 0 ],
[ 1, 0 ],
[ 1, 1 ] ],
[ [ 1, 1, 1 ],
[ 1, 0, 0 ] ],
[ [ 1, 1 ],
[ 0, 1 ],
[ 0, 1 ] ],
[ [ 0, 0, 1 ],
[ 1, 1, 1 ] ],
],
"orange" ); // color
}
}
En lugar de crear una matriz para una sola forma, crearemos un vector de matrices con las diferentes formas rotando la pieza. A continuación, vemos la clase pieza con el soporte para las distintas formas.
class Piece {
#_shape = null;
#_color = "black";
#_height = 1;
#_width = 1;
#_row = 0;
#_col = 0;
#_shapeNum = 0;
constructor(shapes, color)
{
this._row = 0;
this._col = 0;
this._height = shapes[ 0 ].length;
this._width = shapes[ 0 ][ 0 ].length;
this._shapeNum = 0;
if ( color != null ) {
this._color = color;
}
}
get shape()
{
return this._shapes[ this._shapeNum ];
}
reset(board_width)
{
this._row = 0;
this._col = parseInt( ( board_width / 2 ) - 1 );
this._shapeNum = 0;
this._height = this._shapes[ 0 ].length;
this._width = this,_shapes[ 0 ][ 0 ].length;
}
rotate()
{
this._shapeNum = ( this._shapeNum + 1 ) % this._shapes.length;
this._height = this._shapes[ this._shapeNum ].length;
this._width = this._shapes[ this._shapeNum ][ 0 ].length;
}
Antes teníamos _shape.length para calcular la altura de la pieza, y _shape[ 0 ].length para calcular el ancho de la misma. Como ahora tenemos una matriz con la secuencia de formas, pasamos a hacer lo mismo, pero con la primera forma: respectivamente _shape[ 0 ].length y _shape[ 0 ][ 0 ].length. A medida que vamos rotando la pieza (_shapeNum), calculamos el alto y el ancho de la forma en concreto en la que estamos, como se puede ver en el método rotate().
En la próxima entrega, veremos cómo representar el tablero del juego.
Top comments (0)