Tetris en JavaScript – Open source

En este post te mostraré el juego de Tetris programado en JavaScript puro, totalmente gratuito y open source.

Este juego de bloques está programado con JavaScript y utiliza canvas para pintar el juego. También utilizo Bootstrap para el diseño de los botones y la página en general, con un poco de SweetAlert para las ventanas.

Aunque se vea sencillo de hacer, es uno de los trabajos que más me ha costado realizar y del cual me siento más orgulloso. Fue complejo (para mí) comprender toda la lógica para las colisiones, rotaciones, eliminación de filas, movimiento de piezas, límites, etcétera.

Entre las características del juego encontramos:

  1. Sonidos: música de fondo, sonido cuando la pieza no se puede rotar, cuando se hace una fila completa y cuando el tetrominó toca el suelo
  2. Colores: cada pieza tiene un color aleatorio elegido en tiempo de ejecución
  3. Rotaciones: las piezas se pueden rotar para acomodarlas y acumular puntos
  4. Compatible con móviles: debido a que es web, he agregado unos botones para poder jugarlo en móviles, pero también se puede jugar con el teclado
  5. Código abierto: puedes modificar el juego, el tablero, la longitud, velocidad, piezas, rotaciones, etcétera.
  6. Port de tetris: se comporta como cualquier juego de tetris normal
  7. Pausa del juego: el juego se puede pausar o reanudar en cualquier momento

Veamos entonces los detalles de este juego programado en JS. A lo largo del post te mostraré cómo es que este juego está programado, también te dejaré una demostración y el código completo.

Nota: figura, pieza y tetrominó serán usados como sinónimos en este post.

Algoritmo general del juego de Tetris

El algoritmo es sencillo. Tenemos un plano cartesiano en donde existen las coordenadas X e Y. Tenemos 3 cosas:

  1. Tablero de juego: el tablero en donde se dibujará o mostrará todo
  2. Piezas ya existentes: los puntos o piezas que ya han caído antes; es decir, las figuras que se quedaron ahí
  3. Pieza actual: la pieza que va bajando actualmente y que el jugador puede mover o rotar

Ahora hacemos lo siguiente: dibujamos el tablero del juego (vacío), luego sobreponemos las piezas existentes y finalmente colocamos la pieza actual (la que va bajando).

En cada movimiento o intento de rotación, verificamos si la pieza no colapsa con la pared o con otra figura abajo. Cuando la pieza se rota, hacemos una simulación para ver si los puntos, después de haber sido rotados, no colapsarán con otra pieza.

Además, cuando se detecta que la pieza ha llegado al suelo, se inicia un temporizador que bajará la siguiente pieza en determinados milisegundos (de este modo el jugador tiene tiempo para mover la pieza).

Antes de mostrar otra figura, se mueven los puntos de la figura actual a las piezas existentes.

Lo demás son colisiones y trabajos con arreglos. Por ejemplo, para verificar si una fila está llena recorremos cada punto del arreglo en determina posición de Y y verificamos si está tomado.

Todo el dibujo del juego lo hacemos en un requestAnimationFrame y dibujamos una matriz sobre Canvas usando JavaScript.

Música del juego

El juego tiene varios sonidos. Todos los sonidos son inyectados de manera invisible. Se inician así:

En este caso el sonido de fondo es reproducido en loop, para que se repita infinitamente. Luego, lo reproducimos así (línea 1):

Clases ayudantes

Punto

Un punto tiene dos cosas: coordenadas X e Y. Y un Tetrominó tiene varios puntos que lo conforman.

Tetrominó

Como lo dije, una figura de tetris se compone de varios puntos. Además, tiene varias rotaciones. La Z, por ejemplo, tiene solo 2, pero la J tiene 4. Las rotaciones se definen igualmente como un Tetrominó, y se intercambian al rotar.

Para llevar la cuenta de la rotación en la que la figura se encuentra, se lleva un índice. Las rotaciones no son más que un arreglo que tiene varios Tetrominós, mismo que representa todas las rotaciones posibles.

Como puedes ver, el color se elige en la línea 6. Al momento de elegir la figura, cada punto de cada rotación de la misma es coloreado con el color aleatorio.

Funciones útiles

Antes de continuar veamos las funciones útiles. Entre ellas tenemos la función que carga el sonido, la que elige un color aleatorio o la que elige un número aleatorio para saber cuál figura elegir:

Por ejemplo, la función getRandomColor elige un color aleatorio del arreglo estático de la clase Game que veremos a continuación. Y esta función reutiliza la función llamada getRandomNumberInRange que devuelve un número en determinado rango.

Funcionamiento del juego

Tetris en JavaScript – Bienvenida al juego

Comencemos viendo las constantes del juego, como lo son el tamaño del tablero, los colores, la puntuación que se da al usuario cuando hace una fila de puntos o los colores aleatorios para elegir:

El arreglo de colores puede ser modificado a tu gusto, ya sea cambiando los colores o agregando más, para agregar aleatoridad.

También tenemos ciertos parámetros interesantes como el tamaño de cada cuadro en pixeles (esto afecta al tamaño del tablero) o los milisegundos para indicar la velocidad a la que la pieza baja, la duración de la animación o el tiempo que tiene el jugador para mover la pieza si la misma ha tocado el suelo.

Función init del juego

Todo comienza en la función init, pero también es importante el constructor en donde definimos varias cosas:

El juego recibe el id del canvas en donde se va a dibujar. De este modo podríamos hacer que sean dos tableros de juego de Tetris, usando el mismo código.

También tenemos varias banderas, la definición del tablero, los sonidos, etcétera. Ahora veamos el init y el reinicio de este juego de tetris open source:

Aquí hay que notar una cosa importante y es la función syncExistingPiecesWithBoard. Lo que hace esta función es limpiar el tablero y colocar sobre el mismo (es decir, modificar los índices del arreglo) las piezas existentes.

Dibujar sobre canvas

La función que dibuja todo el juego de tetris en el canvas es la siguiente. La misma se estará invocando cada 17 milisegundos usando requestAnimationFrame:

Esta función es la que puedes modificar si quieres dibujar el juego en otro lugar; por ejemplo en una tabla, con SVG, en la consola, etcétera.

Obtener figura aleatoria

Tenemos la función en donde definimos las figuras y sus rotaciones. Este método devolverá un Tetrominó aleatorio en cada invocación:

Justo aquí es en donde estamos usando la clase Point y la clase Tetromino. Recuerda que cada Tetrominó recibirá un arreglo de todas las rotaciones posibles. Y cada rotación es a su vez un arreglo de puntos que tienen distintas coordenadas.

Estas coordenadas no se modifican internamente en el punto, sino que son colocadas a partir de un X e Y globales del tablero.

Si tú quieres definir otras figuras o modificar las rotaciones, justo aquí es en donde tienes que realizar los cambios.

Colisiones y movimientos

Sé que existen motores para el desarrollo de videojuegos pero en este caso quise hacerlo todo a mano. Por lo tanto he creado mis propias funciones para saber si un punto está fuera de los límites, si un punto es válido, etcétera.

Primero veamos las funciones de colisión de puntos que verifican el tablero y las piezas existentes:

Estamos usando las coordenadas globales de X y también las de Y, pues recuerda que cada punto de la figura es independiente.

Ahora veamos las funciones para mover o rotar la figura:

Lo que hacemos es simular el movimiento y verificar si cada punto sigue siendo válido. También reproducimos un sonido en el caso de que la figura no se pueda rotar.

Eliminar filas

Eliminar filas llenas en juego de bloques con JavaScript

Esta es una de las funciones que más trabajo me tomó programar. Lo que hace es verificar y eliminar las filas llenas. Queda así:

Debemos obtener la coordenada Y de todas las filas que ya están llenas. Por cada una, verificamos si podemos mover todos los puntos hacia abajo. En caso de que sí, los bajamos, pero no los bajamos más allá de la cantidad de filas eliminadas.

Además, esta función aumenta el puntaje. La función que lo refresca es:

El puntaje se calcula de acuerdo a la cantidad de puntos que se eliminaron multiplicados por el puntaje por cuadro eliminado.

Loop: ciclo del juego

Ahora veamos el ciclo del juego. Según el intervalo en milisegundos definido anteriormente vamos bajando la pieza, mientras se pueda. En caso de que ya no se pueda mover la pieza, se inicia un temporizador para darle oportunidad al jugador de mover la pieza.

Cuando se acaba el temporizador, si la pieza sigue sin poder moverse, agregamos la pieza actual a las piezas existentes y luego seleccionamos otra figura:

También es en este ciclo en donde comprobamos si el jugador pierde.

Juego de bloques terminado (jugador pierde)

Debo admitir que esa función debe ser mejorada, pues actualmente verifica si hay piezas en la segunda fila, pero debería ser más inteligente. Se me ocurre que puede verificar si puede colocar una figura aleatoria.

Controles para jugar bloques en JavaScript

El juego de bloques o tetris en JavaScript que he programado se puede jugar con el teclado o con los botones. Es buen momento para mostrar el código HTML del juego, en donde vemos al canvas y los botones:

Cada botón tiene un id, que luego recupero dentro del juego usando querySelector:

Ahora veamos los controles, tanto del teclado como de los botones. Cada uno invoca a las funciones “intentar mover a la derecha” y a todas las demás posiciones:

Aquí puedes ver que usamos la bandera canPlay, misma que desactivamos o activamos según nuestra conveniencia. Por ejemplo, no se puede jugar mientras el juego está en pausa o mientras se está reproduciendo la animación de la eliminación de las filas.

Poniendo todo junto

Jugando Tetris en JavaScript (juego open source)

No puedo colocar ni explicar todo el código aquí. Recuerda que lo único que necesitamos es un canvas en donde dibujar todo el juego de bloques. Lo demás se encuentra en el código, sobre todo en la clase Game. Eres libre de explorarlo.

Realmente me llevó bastante tiempo y esfuerzo hacer este juego; puedes ver toda su evolución a través de los commits.

Te dejo un vídeo de YouTube para la demostración:

El código completo y open source está en mi GitHub.

Puedes probar la demostración aquí: https://parzibyte.github.io/tetris-javascript/

También aprovecho para invitarte a leer más sobre JavaScript y Videojuegos en mi blog.

Encantado de ayudarte


Estoy disponible para trabajar en tu proyecto, modificar el programa del post o realizar tu tarea pendiente, no dudes en ponerte en contacto conmigo.

No te pierdas ninguno de mis posts

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

2 comentarios en “Tetris en JavaScript – Open source”

Dejar un comentario