Tetris in Javascript
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Tetríssimus © (by Joan Alba Maldonado)</title>
<!-- (c) Tetrissimus - Programa realizado por Joan Alba Maldonado (granvino@granvino.com). Prohibido publicar, reproducir o modificar sin citar expresamente al autor original.
Tetrissimus
by Joan Alba Maldonado (100% DHTML).
granvino@granvino.com
Prohibited to publish, reproduce or modify without maintain author's name.
Approximate date: 7 of March 2006 (fixes beyond 16 of August 2006).
Dedicated to Yasmina Llaveria del Castillo.
-->
<script language="JavaScript1.2" type="text/javascript">
<!--
//(c) Tetrissimus - Programa realizado por Joan Alba Maldonado (granvino@granvino.com). Prohibido publicar, reproducir o modificar sin citar expresamente al autor original.
//Variable que activa el mapa modo debug:
var mostrar_mapa_debug = false;
//Variable que guarda el primer evento del teclado, por razones de compatibilidad:
var primer_evento = "";
//Se dibuja el mapa en una varialbe tipo string:
var mapa = "000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000" +
"000000000000";
//Se declara la matriz para guardar el mapa:
var mapa_matriz = new Array();
//El numero de columnas del mapa:
var numero_columnas = 12;
//El numero de filas del mapa:
var numero_filas = 22;
//Variable que contiene el ancho de cada celda (tile o panel):
var panel_width = 20;
//Varialbe que contiene el alto de cada celda (tile o panel):
var panel_height = 20;
//Velocidad de caida de las piezas (entre menor, mas rapido):
var velocidad_inicial = 1500; //Velocidad inicial.
var velocidad = velocidad_inicial; //Velocidad que ira incrementandose (al decrementar la variable).
//Pizels de desplazamiento en la caida de las piezas:
var desplazamiento_inicial = panel_height * 1; //Desplazamiento inicial.
var desplazamiento = desplazamiento_inicial; //Desplazamiento que ira incrementandose.
//Se realiza un bucle para guardar el mapa en la matriz:
for (x=0; x<mapa.length; x++) { mapa_matriz[x] = mapa.substring(x, x+1); }
//Variable que guarda el numero de la pieza actual:
var numero_pieza = 0;
//Variable que guarda el numero de la pieza siguiente:
var numero_pieza_siguiente = 0;
//Matriz que contiene la coleccion de piezas, con su ancho, alto y color:
var pieza = new Array();
//Varialbe para saber si una pieza se ha elevado verticalmente al ser rotada:
var al_rotar_se_ha_elevado = false;
//Variable donde se guardara el Interval del movimiento de la pieza cayendo:
var movimiento_pieza = setInterval("", 1);
//Variable donde se guardara el Timeout que hara que el mensaje del centro de la pantalla se oculte:
var ocultar_mensaje = setTimeout("", 1);
//Variable donde se guarda el numero de piezas:
var numero_piezas = 0;
//Variable que indica si se ha acabado el juego o todavia no:
var game_over = false; //Todavia no se ha acabado el juego.
//Variable que define las lineas necesarias para cambiar de nivel:
var lineas_necesarias = 6;
//Variable que cuenta cuantas lineas se han realizado en el nivel actual:
var lineas_nivel_actual = 0;
//Variable donde se guarda la puntuacion:
var puntuacion = 0;
//Variable donde se guada el nivel:
var nivel = 1;
//Contador de niveles, que cuando llega a 10 se sube el desplazamiento de las piezas (se desplazan mas espcio hacia abajo, para hacerlo mas dificil):
var contador_niveles_desplazamiento = 0;
//Variable que impide el Game Over, cuando ya ha ocurrido:
var impedir_game_over = false;
//Matriz vacia que se utilizara para cuando se llame a mostrar_mapa:
var guardar_mapa_anterior = new Array();
//Funcion que crea las piezas, con su ancho, alto y color:
function crear_piezas()
{
//Pieza 1:
pieza[1] = new Array();
pieza[1]["forma"] = "1" +
"1" +
"1" +
"1";
pieza[1]["width"] = 1;
pieza[1]["height"] = 4;
pieza[1]["color"] = "#aaffdd";
//Pieza 2:
pieza[2] = new Array();
pieza[2]["forma"] = "22" +
"22";
pieza[2]["width"] = 2;
pieza[2]["height"] = 2;
pieza[2]["color"] = "#ffffdd";
//Pieza 3:
pieza[3] = new Array();
pieza[3]["forma"] = "33" +
"03" +
"03";
pieza[3]["width"] = 2;
pieza[3]["height"] = 3;
pieza[3]["color"] = "#ddaaff";
//Pieza 4:
pieza[4] = new Array();
pieza[4]["forma"] = "44" +
"40" +
"40";
pieza[4]["width"] = 2;
pieza[4]["height"] = 3;
pieza[4]["color"] = "#ffaadd";
//Pieza 5:
pieza[5] = new Array();
pieza[5]["forma"] = "055" +
"550";
pieza[5]["width"] = 3;
pieza[5]["height"] = 2;
pieza[5]["color"] = "#ffddff";
//Pieza 6:
pieza[6] = new Array();
pieza[6]["forma"] = "660" +
"066";
pieza[6]["width"] = 3;
pieza[6]["height"] = 2;
pieza[6]["color"] = "#aaddff";
//Pieza 7:
pieza[7] = new Array();
pieza[7]["forma"] = "070" +
"777";
pieza[7]["width"] = 3;
pieza[7]["height"] = 2;
pieza[7]["color"] = "#ffddaa";
//Pieza 8:
// pieza[8] = new Array();
// pieza[8]["forma"] = "808" +
// "080" +
// "080";
// pieza[8]["width"] = 3;
// pieza[8]["height"] = 3;
// pieza[8]["color"] = "orange";
//Se guarda el numero de piezas:
numero_piezas = pieza.length - 1;
}
//Funcion que inicia el juego:
function iniciar_juego()
{
//Se setea que aun no se ha acabado el juego:
game_over = false;
//Desbloquea el impedir game over:
impedir_game_over = false;
//Se crean las piezas:
crear_piezas();
//Se setea la velocidad a la inicial:
velocidad = velocidad_inicial;
//Se setea el desplazamiento al inicial:
desplazamiento = desplazamiento_inicial;
//Se deifne el contador de niveles que incrementa el desplazamiento, a 0:
contador_niveles_desplazamiento = 0;
//Se definen las lineas del nivel actual a 0;
lineas_nivel_actual = 0;
//Se define el marcador de puntuacio a 0:
puntuacion = 0;
//Se define el nivel a 1:
nivel = 1;
//Se define el numero de pieza actual a 0 (ninguno):
var numero_pieza = 0;
//Se define el numero de pieza siguiente a 0 (ninguno):
var numero_pieza_siguiente = 0;
//Vaciar mapa (recorre la matriz, cambiando todo por 0):
for (x=0; x<mapa_matriz.length; x++) { mapa_matriz[x] = "0"; }
//Se recoge el mapa en una matriz, para calcular las diferencias con este y el posterior:
mapa_matriz_anterior = guardar_mapa_anterior;
//Se muestra el mapa:
mostrar_mapa(mapa_matriz, mapa_matriz_anterior);
//Se actualiza el marcador:
actualizar_marcador();
//Se muestra el mensaje de "Comienza el juego":
mostrar_mensaje("The game begins");
//Sacamos una pieza:
sacar_pieza();
}
//Funcion que actualiza la matriz del mapa:
function actualizar_mapa(numero_pieza)
{
//Si se ha enviado como pieza el cero, es que no hay piezas:
if (numero_pieza == 0)
{
//Recorre la matriz, cambiando todo lo que no sea 0 ni X por 0:
for (x=0; x<mapa_matriz.length; x++)
{
//Si no es 0 ni X, lo cambia a 0:
if (mapa_matriz[x] != "0" && mapa_matriz[x] != "X") { mapa_matriz[x] = "0"; }
}
}
//Pero si se ha enviado otro numero, mayor que cero:
else if (numero_pieza > 0)
{
//Se borra la pieza del mapa:
actualizar_mapa(0);
//Se calcula en que posicion de la matriz comienza la pieza:
matriz_posicion_x = numero_columnas - (parseInt(document.getElementById("pieza").style.left) / panel_width);
matriz_posicion_y = parseInt(document.getElementById("pieza").style.top) / panel_height + 1;
//Esta es la posicion inicial (la clave de la matriz) donde comienza la pieza:
matriz_posicion_inicial = (numero_columnas * matriz_posicion_y) - matriz_posicion_x;
//Se actualiza la matriz pintando la pieza en ella, segun la posicion:
// for (x=0; x<mapa_matriz.length; x++)
for (x=matriz_posicion_inicial; x<matriz_posicion_inicial+pieza[numero_pieza]["forma"].length; x++)
{
//Si estamos en el indice donde comienza la pieza:
if (x == matriz_posicion_inicial)
{
//El contador de columnas:
contador_columnas = 0;
//La variable que se suma para saltar una fila:
saltar_fila = 0;
for (y=0; y<pieza[numero_pieza]["forma"].length; y++)
{
//Se toma como posicion de la matriz la posicion inicial y se le suma la variable que hace saltar filas:
posicion_matriz_actual = x + saltar_fila;
//Si la posicion actual de la pieza no es un cero, se graba en la matriz:
if (pieza[numero_pieza]["forma"].substring(y, y+1) != "0") {mapa_matriz[posicion_matriz_actual] = pieza[numero_pieza]["forma"].substring(y, y+1); } //Se pinta la pieza.
//Se incrementa el contador de columnas:
contador_columnas++;
//Se incrementa la variable para saltar filas:
saltar_fila++;
//Si el contador de columnas es mayor al ancho de la pieza, se salta una fila:
if (contador_columnas >= pieza[numero_pieza]["width"]) { contador_columnas = 0; saltar_fila += numero_columnas - pieza[numero_pieza]["width"]; }
}
}
}
}
}
//Funcion que activa/desactiva la visualizacion del mapa en modo debug:
function activar_desactivar_mapa_debug(modo)
{
//Si no se ha enviado alternar, no se alterna el estado:
if (modo != "alternar") { var alternar_estado = mostrar_mapa_debug; }
//...pero si se ha enviado alternar, se alterna:
else { var alternar_estado = mostrar_mapa_debug ? false: true; }
//Si se ha desactivado, setea para que no se muestre el mapa y esconde el mapa:
if (!alternar_estado) { mostrar_mapa_debug = false; document.getElementById("mapa_debug").style.visibility = "hidden"; document.formulario.casilla.checked = false; }
//Si no (se ha activado), lo vuelve a activar y a hacer visible:
else { mostrar_mapa_debug = true; document.getElementById("mapa_debug").style.visibility = "visible"; document.formulario.casilla.checked = true; mapa_matriz_anterior = guardar_mapa_anterior; mostrar_mapa(mapa_matriz, mapa_matriz_anterior); }
}
//Funcion que muestra el mapa en modo debug:
function mostrar_mapa(mapa_matriz, mapa_matriz_anterior)
{
//Si se ha enviado la misma matriz actual que la anterior, sale de la funcion (no hay nada que actualizar):
if (mapa_matriz == mapa_matriz_anterior) { return; }
//Se setea el contador de columnas a cero:
var columnas_contador = 0;
//Se setea el contador de filas a cero:
var filas_contador = 0;
//Variable que guardara el color a utilizar en cada celda (tile o panel):
var color_panel;
//Se borra el mapa:
// document.getElementById("mapa").innerHTML = "";
// if (mostrar_mapa_debug) { document.getElementById("mapa_debug").innerHTML = ""; } //Si esta en modo debug, tambien se borra el mapa debug.
//Se crean las variables que guardaran la informacion del mapa:
var mapa_bucle_temp = "";
var mapa_debug_bucle_temp = "";
//Se realiza un bucle para mostrar el contenido de la matriz en el espacio de debug:
for (x=0; x<mapa_matriz.length; x++)
{
//Se calcula que color utilizar, segun el caracter de celda (tile o panel):
if (mapa_matriz[x] == "X") { color_panel = "#555555"; } //Color gris oscuro (caracter X, piezas ya colocadas).
else if (mapa_matriz[x] != 0) { color_panel = pieza[mapa_matriz[x]]["color"]; } //Color de la pieza segun su numero.
//Calcular la posicion de la celda (tile o panel):
panel_x = columnas_contador * panel_width; //Posicion horizontal.
panel_y = filas_contador * panel_height; //Posicion vertical.
//Se muestra la imagen en la celda, siempre que no este vacia (0) y que haya habido un cambio desde la anterior:
if (mapa_matriz[x] != 0 && mapa_matriz[x] != mapa_matriz_anterior[x]) { mapa_bucle_temp += '<div style="background:'+color_panel+'; top:'+panel_y+'px; left:'+panel_x+'px; width:'+panel_width+'px; height:'+panel_height+'px; position:absolute; padding:0px; font-size:1px; filter:alpha(opacity=80); opacity:0.8; -moz-opacity:0.8; z-index:5000;"></div>'; }
//Si esta activado el mapa debug, se escribe en el:
if (mostrar_mapa_debug) { mapa_debug_bucle_temp += mapa_matriz[x]; }
//Se incrementa el contador de columnas:
columnas_contador++;
//Si se alcanza el numero maximo de columnas, se baja una fila y se setea otra vez el contador a cero y se incrementa el contador de filas (si esta el mapa en modo debug, se baja una linea en este):
if (columnas_contador == numero_columnas) { columnas_contador = 0; filas_contador++; if (mostrar_mapa_debug) { mapa_debug_bucle_temp += "<br>"; } }
}
//Se vuelcan las variables en el mapa:
document.getElementById("mapa").innerHTML = mapa_bucle_temp;
if (mostrar_mapa_debug) { document.getElementById("mapa_debug").innerHTML = mapa_debug_bucle_temp; } //Si esta en modo debug, tambien se vuelca el mapa en modo debug.
}
//Funcion que saca una pieza al escenario:
function sacar_pieza()
{
//Si ya ha habido game over, se sale de la funcion:
if (impedir_game_over) { return; }
//Si aun no seh a escogido ninguna pieza, se escoge una aleatoriamente:
if (numero_pieza == 0) { numero_pieza = elegir_pieza(); }
//Si antes ya se habia escogido alguna, se setea la actual como la siguiente:
else { numero_pieza = numero_pieza_siguiente; }
//Ponemos el numero de la pieza siguiente, escogido aleatoriamente, en una variable:
numero_pieza_siguiente = elegir_pieza();
//Se muestra la pieza siguiente:
mostrar_pieza_siguiente(numero_pieza_siguiente);
//Setear conforme todavia no se ha elevado verticalmente la pieza al ser rotada:
al_rotar_se_ha_elevado = false;
//Borrar esto:
//numero_pieza = 1;
//Devolver las piezas a su estado inicial:
crear_piezas();
//Se recoge el mapa en una matriz, para calcular las diferencias con este y el posterior:
mapa_matriz_anterior = guardar_mapa_anterior;
//Calcular ancho y alto de la pieza, segun el numero enviado:
pieza_width = pieza[numero_pieza]["width"];
pieza_height = pieza[numero_pieza]["height"];
//Se situa horizontalmente en el centro:
//document.getElementById("pieza").style.left = parseInt( (numero_columnas * panel_width) / 2 - pieza_width * panel_width) + "px";
document.getElementById("pieza").style.left = "0px";
//Se situa verticalmente arriba:
document.getElementById("pieza").style.top = "0px";
mover_pieza(0, 0);
//Se actualiza el mapa:
//actualizar_mapa(numero_pieza);mostrar_mapa_debug(mapa_matriz);
//Se muestra el mapa:
mostrar_mapa(mapa_matriz, mapa_matriz_anterior);
//Elimina el movimiento de la pieza cayendo, por si aun existia:
clearInterval(movimiento_pieza);
//Crea el movimiento de la pieza cayendo:
movimiento_pieza = setInterval("mapa_matriz_anterior = guardar_mapa_anterior; mover_pieza('mantener', parseInt(document.getElementById('pieza').style.top) + desplazamiento); mostrar_mapa(mapa_matriz, mapa_matriz_anterior);", velocidad);
}
//Funcion que elige una pieza aleatoriamente:
function elegir_pieza()
{
//Variable que escoge un numero aleatorio entre 1 y 8:
var numero_aleatorio = parseInt(Math.random() * numero_piezas) + 1;
//Retorna el numero escogido de la pieza:
return numero_aleatorio;
}
//Funcion que mueve la pieza segun las coordenadas enviadas:
function mover_pieza(posicion_x, posicion_y)
{
//Si ya ha habido game over, se sale de la funcion:
if (impedir_game_over) { return; }
//Si se ha enviado mantener posicion horizontal, no mover la pieza (conservar la X de esta):
if (posicion_x == "mantener") { posicion_x = parseInt(document.getElementById("pieza").style.left); }
//Variable para saber si la pieza ha tocado fondo:
var ha_tocado_fondo = false;
//Si la pieza esta en el limite de abajo, situa la pieza lo maximo posible hacia abajo y se setea la variable ha_tocado_fondo a true:
if (posicion_y > panel_height * numero_filas - pieza[numero_pieza]["height"] * panel_height) { posicion_y = panel_height * numero_filas - pieza[numero_pieza]["height"] * panel_height; ha_tocado_fondo = true; }
//Si la pieza esta en el limite izquierdo, situa la pieza lo maximo posible hacia la izquierda:
if (posicion_x <= 0) { posicion_x = 0; }
//Si la pieza esta en el limite derecho, situa la pieza lo maximo posible hacia la derecha:
if (posicion_x + panel_width * pieza[numero_pieza]["width"] > panel_width * numero_columnas) { posicion_x = panel_width * numero_columnas - pieza[numero_pieza]["width"] * panel_width; }
//Variables que impiden el movimiento horizontal si a la izquierda o a la derecha de la pieza hay otra ya colocada:
impedir_movimiento_derecho = false;
impedir_movimiento_izquierdo = false;
//Realizar un bucle en la matriz:
for (x=0; x<mapa_matriz.length; x++)
{
//Si la posicion actual de la matriz contiene un caracter que no es 0 ni X, contiene una pieza:
if (mapa_matriz[x] != "0" && mapa_matriz[x] != "X")
{
//Si existe un caracter a la derecha del actual (no excede el tama??e la matriz):
if (x + 1 <= mapa_matriz.length)
{
//Si el caracter que hay a la derecha es una X, impedir movimiento horizontal:
if (mapa_matriz[x+1] == "X") { impedir_movimiento_derecho = true; } //Se impide movimiento horizontal hacia la derecha.
}
//Si existe un caracter a la izquierda del actual (no es menor a 0):
if (x - 1 >= 0)
{
//Si el caracter que hay a la izquierda es una X, impedir movimiento horizontal:
if (mapa_matriz[x-1] == "X") { impedir_movimiento_izquierdo = true; } //Se impide movimiento horizontal hacia la izquierda.
}
}
}
//Si la posicion horizontal es hacia la izquierda y no esta impedida o es a la derecha y tampoco esta impedida, mueve la pieza horizontalmente:
posicion_x_actual = parseInt(document.getElementById("pieza").style.left);
if (posicion_x_actual > posicion_x && !impedir_movimiento_izquierdo || posicion_x_actual < posicion_x && !impedir_movimiento_derecho)
{
document.getElementById("pieza").style.left = posicion_x + "px"; //Se situa la pieza en la posicion horizontal dada.
}
//Se situa la pieza en la posicion vertical dada:
document.getElementById("pieza").style.top = posicion_y + "px";
//Se actualiza el mapa con la nueva posicion de la pieza:
actualizar_mapa(numero_pieza);
//Calcular colision:
var ha_colisionado = calcular_colision();
//Si la posicion vertical de la pieza la situa abajo del todo, se convierte todo el mapa que no sea 0 a X:
if (ha_tocado_fondo || ha_colisionado)
{
//Elimina el movimiento de la pieza cayendo, por si existia anteriormente:
//clearInterval(movimiento_pieza);
//Da 1 punto:
puntuacion += 1;
//Se setea todo lo que haya en el mapa como X (ya colocado):
for (x=0; x<mapa_matriz.length; x++) { if (mapa_matriz[x] != "0") { mapa_matriz[x] = "X"; } }
//Se hace bajar la pieza un panel, para que quede bien al pausar el juego:
document.getElementById("pieza").style.top = parseInt(document.getElementById("pieza").style.top) + panel_height + "px";
actualizar_mapa();
mostrar_mapa(mapa_matriz, mapa_matriz_anterior);
//Calculamos si se ha llegado arriba del todo y se acaba el juego:
hay_game_over = calcular_game_over();
//Se saca una pieza:
if (!hay_game_over) { sacar_pieza(); }
}
//Calcular si se ha hecho linea:
calcular_linea();
//Se muestra el mapa:
// mostrar_mapa(mapa_matriz);
// mostrar_mapa(mapa_matriz, mapa_matriz_anterior);
}
//Funcion que calcula si una pieza ha chocado con otra (poniendose encima):
function calcular_colision()
{
//Variable que calcula si ha colisionado o no:
var ha_colisionado = false;
//Realizar bucle en la matriz, buscar caracteres que no sean 0 ni X y calcular si justo debajo tienen una X:
for (x=0; x<mapa_matriz.length; x++)
{
//Si la posicion actual de la matriz contiene un caracter que no es 0 ni X, contiene una pieza:
if (mapa_matriz[x] != "0" && mapa_matriz[x] != "X")
{
//Si existe un caracter debajo del actual (no excede el tama??e la matriz):
if (x + numero_columnas <= mapa_matriz.length)
{
//Si el caracter que hay debajo es una X, ha colisionado:
if (mapa_matriz[x+numero_columnas] == "X") { ha_colisionado = true; break; } //Ha habido colision y sale del bucle.
}
}
}
//Si ha colisionado:
if (ha_colisionado)
{
//Retorna true:
return true;
}
//...y si no:
else { return false; } //Retorna false;
}
//Funcion que calcula si ha habido linea:
function calcular_linea()
{
//Calcular si ha habido linea y calcular cuantas:
var columnas_contador = 0;
if (!numero_de_lineas) { var numero_de_lineas = 0; }
var ha_habido_linea = false;
var hay_linea = true;
for (var x=0; x<mapa_matriz.length; x++)
{
columnas_contador++;
if (mapa_matriz[x] != "X") { hay_linea = false; }
if (columnas_contador == numero_columnas)
{
if (hay_linea)
{
//Cambiar las X de la linea por 0:
for (var y=x-numero_columnas+1; y<=x; y++)
{
mapa_matriz[y] = "0";
}
//Bajar lineas:
se_ha_bajado_linea = hacer_caer_cuadros();
//Volver a llamar a la funcion recursivamente si se ha bajado alguna linea, para ver si al bajar las piezas colocadas ha habido mas lineas:
// if (se_ha_bajado_linea) { calcular_linea(); }
//calcular_linea();
//Incrementar el contador de lineas:
numero_de_lineas++;
ha_habido_linea = true;
}
columnas_contador = 0;
hay_linea = true;
}
//actualizar_mapa(numero_pieza);
}
//Si ha habido linea, dar puntos segun cuantas lineas ha haya habido:
dar_puntos(numero_de_lineas);
}
//Funcion que hace caer los cuadros (X) cuando debajo no tienen nada (0):
function hacer_caer_cuadros(posicion_final)
{
//Todavia no se ha bajado ninguna linea:
se_ha_bajado_linea = false;
//Calcula si la linea esta en el aire o no:
var esta_en_el_aire = true;
//Bucle que va de arriba a abajo, haciendo caer las piezas:
// for (z=mapa_matriz.length-numero_columnas; z>=numero_columnas+1; z-=numero_columnas)
for (z=mapa_matriz.length-numero_columnas; z>=numero_columnas; z-=numero_columnas)
{
// alert(z);
//Calcula si la linea esta en el aire o no:
esta_en_el_aire = true;
//Comprueba que la linea este en el aire:
for (k=z; k<=z+numero_columnas-1; k++) { if (k > mapa_matriz.length || mapa_matriz[k] != "0" || z > numero_columnas && mapa_matriz[k-numero_columnas] != "X" && mapa_matriz[k-numero_columnas] != "0") { esta_en_el_aire = false; } }
//Si esta en el aire, se baja la linea:
if (esta_en_el_aire)
{
// alert(z);
for (k=z; k<=z+numero_columnas-1; k++)
{
//Se replica la pieza en el cuadro de abajo:
mapa_matriz[k] = mapa_matriz[k-numero_columnas];
//Se borra la pieza en el cuadro actual:
mapa_matriz[k-numero_columnas] = "0";
//Setear conforme se ha bajado una linea:
se_ha_bajado_linea = true;
// mostrar_mapa(mapa_matriz, mapa_matriz_anterior);
}
//Se setea como que ya no estan en el aire:
esta_en_el_aire = false;
}
}
if (se_ha_bajado_linea) { return true; }
else { return false; }
}
//Funcion que rota la pieza:
function rotar_pieza(direccion)
{
//Se inviert el ancho y el alto de la pieza:
var width_original = pieza[numero_pieza]["width"]; //El width anterior.
var height_original = pieza[numero_pieza]["height"]; //El height anterior.
pieza[numero_pieza]["width"] = height_original; //El nuevo width es el height.
pieza[numero_pieza]["height"] = width_original; //El numero height es el width anterior.
//Se setea la matriz donde se guardara la nueva pieza:
var nueva_pieza_matriz = new Array(); //Se declara la matriz.
//Variables que serviran para realizar los bucles:
var contador1 = 0;
var contador2 = height_original;
var contador3 = width_original;
//Si se ha de rotar la pieza a la derecha:
if (direccion == "derecha")
{
//Se realiza un bucle por la pieza actual, y se guarda rotada a la derecha en la nueva pieza:
for (x=0; x<pieza[numero_pieza]["forma"].length; x++)
{
//Formula que yo mismo descubri, despues de mucho pensar x):
var formula = (contador1 * height_original) + (contador2 - 1);
nueva_pieza_matriz[formula] = pieza[numero_pieza]["forma"].substring(x,x+1);
contador1++;
contador3--;
if (contador3 == 0) { contador3 = width_original; contador1 = 0; contador2--; }
}
}
//...O si se ha de rotar la pieza hacia la izquierda (o tres veces hacia la derecha):
else if (direccion == "izquierda")
{
//Se realiza un bucle por la pieza actual, y se guarda rotada a la derecha en la nueva pieza:
for (x=pieza[numero_pieza]["forma"].length; x>0; x--)
{
//Formula que yo mismo descubri, despues de mucho pensar x):
var formula = (contador1 * height_original) + (contador2 - 1);
nueva_pieza_matriz[formula] = pieza[numero_pieza]["forma"].substring(x-1,x);
contador1++;
contador3--;
if (contador3 == 0) { contador3 = width_original; contador1 = 0; contador2--; }
}
}
//Posicion vertical de la pieza
posicion_y = parseInt(document.getElementById("pieza").style.top);
//Calcular si al rotarse la pieza va a estar encima de alguna X, entonces moverla a un lugar cercano (hasta en posicion horizontal - ancho pieza, posicion horizontal + ancho pieza, posicion vertical + alto pieza o en posicion vertical - alto pieza) con 0.
//Calcular si la pieza va a chocar al rotarse con alguna pieza inferior o lateral:
//* Si hay piezas debajo, elevar la pieza un cuadro.
//* Si hay piezas al lado, mover la pieza al lado contrario.
//* Si la nueva posicion calculada no es posible (hay X en lo que va a ocupar), no rotar la pieza y salir de la funcion.
//Si la pieza va a estar demasiado cerca del borde inferior (abajo) o de alguna pieza inferior, se sube un poco hacia arriba:
if (posicion_y + pieza[numero_pieza]["height"] * panel_height >= numero_filas * panel_height) { posicion_y -= parseInt(pieza[numero_pieza]["height"] / 2 + 1) * panel_height; al_rotar_se_ha_elevado = true; }
//...y si no, y ya ha sido elevada anteriormente al rotarse, se vuelve a bajar:
else if (al_rotar_se_ha_elevado) { posicion_y += parseInt(pieza[numero_pieza]["width"] / 2 + 1) * panel_height; }
//Variable donde se guardara la forma de la nueva pieza rotada:
var nueva_pieza = "";
//Se realiza un bucle para introducir lo que hay en la matriz en una variable de texto plano:
for (x = 0; x<nueva_pieza_matriz.length; x++)
{
nueva_pieza += nueva_pieza_matriz[x];
}
//Se setea la forma de la pieza actual a la nueva pieza que hemos rotado:
pieza[numero_pieza]["forma"] = nueva_pieza;
//Retorna la posicion vertical de la pieza:
return posicion_y;
}
//Funcion que da puntos, segun un numero de lineas enviado:
function dar_puntos (numero_lineas)
{
//Variable donde se guardara el mensaje a mostrar, si es necesario:
var mensaje = "";
//Dar puntos, segun las lineas:
if (numero_lineas == 4) { puntuacion += 400; mensaje = "Tetris"; } //Se han hecho 4 lineas (tetris).
else if (numero_lineas == 3) { puntuacion += 300; mensaje = "Triple"; } //Se han hecho 3 lineas (triple).
else if (numero_lineas == 2) { puntuacion += 200; mensaje = "Double"; } //Se han hecho 2 lineas (doble).
else if (numero_lineas == 1) { puntuacion += 100; mensaje = "Single"; } //Se ha hecho 1 linea (simple).
//Mostrar en medio de la pantalla cuantas lineas se han hecho, siempre que se haya hecho alguna, y suma al contador de lineas:
if (mensaje != "") { mostrar_mensaje(mensaje); lineas_nivel_actual++; }
//Si elas lineas del nivel actual alcanza o supera las necesarias para pasar de nivel, se llama a la funcion de pasar de nivel:
if (lineas_nivel_actual >= lineas_necesarias)
{
pasar_nivel();
}
//Actualizar marcador:
actualizar_marcador();
}
//Funcion que pasa de nivel cada X lineas:
function pasar_nivel()
{
//Si esta habiendo game over, salir de la funcion:
if (impedir_game_over) { return; }
//Calcular si el numero de lineas realizadas en el nivel actual es igual o supera a lineas_necesarias, y entonces cambia de nivel:
if (lineas_nivel_actual >= lineas_necesarias)
{
//Se define el contador de lineas de cada nivel a cero:
lineas_nivel_actual = 0;
//Se incrementa el contador de niveles, que al llegar a 10 incrementa el desplazamiento de la pieza:
contador_niveles_desplazamiento++;
//Se suma un nivel:
nivel++;
//Se sube la velocidad inicial (ahora la pieza tardara 50 milisegundos menos en caer hacia abajo en cada movimiento):
if (velocidad_inicial - 25 >= 0) { velocidad -= 25; }
//Si el contador de niveles llega a 10, se sube el desplazamiento de la pieza (ahora la pieza se desplazara mas en cada caida):
if (contador_niveles_desplazamiento >= 10 && desplazamiento_inicial <= panel_height * numero_filas) { desplazamiento += panel_height; contador_niveles_desplazamiento = 0; }
//Se dan 1000 puntos:
puntuacion += 1000;
}
//Mostrar en pantalla que se ha pasado de nivel:
mostrar_mensaje("Welcome to level "+nivel);
//Actualizar marcador:
actualizar_marcador();
}
//Funcion que actualiza el marcador:
function actualizar_marcador()
{
//Actualiza el marcador (barra de estado):
document.getElementById("estado").innerHTML = " Level: "+nivel+" | Score: "+puntuacion;
if (game_over) { document.getElementById("estado").innerHTML += " | [Game Over]"; }
}
//Funcion que muestra la pieza siguiente:
function mostrar_pieza_siguiente(numero_pieza_siguiente)
{
//Variable que contendra la pieza siguiente pintada (los div):
var pieza_pintada = "";
//Posicion de la pieza en el cuadro de "pieza siguiente":
posicion_y = panel_height; //Posicion vertical inicial.
posicion_x = panel_width; //Posicion horizontal inicial.
//Contador de columnas, para saber cuando bajar la celda:
var contador_columnas = 0;
//Se realiza un bucle hasta cumplir el numero de celdas que tenga la pieza:
for (x=0; x<pieza[numero_pieza_siguiente]["forma"].length; x++)
{
//Se coge el color de la pieza:
color_pieza = pieza[numero_pieza_siguiente]["color"];
//Si la celda actual no esta vacia (0), se pinta (se crea un div con las posiciones correspondientes):
if (pieza[numero_pieza_siguiente]["forma"].substring(x,x+1) != "0") { pieza_pintada += '<div style="background:'+color_pieza+'; left:'+posicion_x+'; top:'+posicion_y+'; width:'+panel_width+'; height:'+panel_height+'; font-size:1px; position:absolute; z-index:5001;"></div>'; }
//Se incrementa la posicion horizontal:
posicion_x += panel_width;
//Se incrementa una columna:
contador_columnas++;
//Si se ha llegado al fin de las columnas, se baja una fila y se setea las columnas a 0:
if (contador_columnas >= pieza[numero_pieza_siguiente]["width"]) { contador_columnas = 0; posicion_y += panel_height; posicion_x = panel_width; }
}
//Se muestra la ficha que hemos "pintado":
document.getElementById("pieza_siguiente").innerHTML = "Next piece: "+pieza_pintada;
}
//Funcion que muestra un mensaje en medio de la pantalla, durante un tiempo:
function mostrar_mensaje(mensaje)
{
//Se borra el Timeout anterior por si ya existia de antes:
clearTimeout(ocultar_mensaje);
//Se pone el teto en el recuadro:
document.getElementById("mensaje").innerHTML = mensaje;
//Se hace visible el recuadro:
document.getElementById("mensaje").style.visibility = "visible";
//Se esconde el recuadro a los 1500 milisegundos (un segundo y medio):
ocultar_mensaje = setTimeout("document.getElementById('mensaje').style.visibility = 'hidden';", 1500);
}
//Funcion que calcula si se ha llegado al tope de la pantalla, y si es asi da GameOver:
function calcular_game_over()
{
//Si ya se ha ejecutado game over, sale de la funcion:
if (impedir_game_over) { return; }
//Variable que definira si se ha llegado arriba del todo o no:
var se_ha_llegado_arriba = false;
//Calcular si se ha llegado al fin del mapa, con un bucle:
for (x=0; x<numero_columnas; x++)
{
//Si arriba del mapa hay otra cosa que no es un 0, se ha llegado arriba:
if (mapa_matriz[x] != "0") { se_ha_llegado_arriba = true; }
}
//Si ha llegado arriba del todo, hace el game over y luego inicia otro juego nuevo:
if (se_ha_llegado_arriba)
{
//Setea el game over:
game_over = true;
//Actualizar marcador:
actualizar_marcador();
//Se muestra el mensaje:
mostrar_mensaje("Game Over");
//Impedir Game Over:
impedir_game_over = true;
//Se alerta:
alert("Game Over");
//Se comienza el juego en 2 segundos:
setTimeout("iniciar_juego();", 2000);
return true;
}
else { return false; } //No ha habido game over.
}
//Funcion que recoge el mapa en la variable mapa_matriz_anterior()
function guardar_mapa_anterior()
{
var mapa_matriz_anterior = new Array();
for (x=0; x<mapa_matriz.length; x++)
{
mapa_matriz_anterior[x] = mapa_matriz[x];
}
return mapa_matriz_anterior;
}
//Funcion que captura la tecla pulsada y realiza la funcion necesaria:
function pulsar_tecla(e, evento_actual)
{
//Si esta en pausa el juego, se sale de la funcion:
if (!movimiento_pieza) { return; }
//Se recoge el mapa en una matriz, para calcular las diferencias con este y el posterior:
mapa_matriz_anterior = guardar_mapa_anterior;
//Si el primer evento esta vacio, se le introduce como valor el evento actual (el que ha llamado a esta funcion):
if (primer_evento == "") { primer_evento = evento_actual; }
//Si el primer evento no es igual al evento actual (el que ha llamado a esta funcion), se vacia el primer evento (para que a la proxima llamada entre en la funcion) y se sale de la funcion:
if (primer_evento != evento_actual) { primer_evento = ""; return; }
//Capturamos la tacla pulsada, segun navegador:
if (e.keyCode) { var unicode = e.keyCode; }
//else if (event.keyCode) { var unicode = event.keyCode; }
else if (window.Event && e.which) { var unicode = e.which; }
else { var unicode = 40; } //Si no existe, por defecto se utiliza la flecha hacia abajo.
//Se obtiene la posicion actual de la pieza:
posicion_x = parseInt(document.getElementById("pieza").style.left); //Posicion horizontal.
posicion_y = parseInt(document.getElementById("pieza").style.top); //Posicion vertical.
//Si se pulsa la flecha hacia abajo, se suman 20 pixels verticales:
if (unicode == 40) { posicion_y += 20; }
//...y si se pulsa la flecha hacia la derecha, se suman 20 pixels horizontales:
else if (unicode == 39) { posicion_x += 20; }
//...y si se pulsa la flecha hacia la izquierda, se restan 20 pixels horizontales:
else if (unicode == 37) { posicion_x -= 20; }
//...y si se pulsa flecha arriba (38), control (17), intro (13) o . (190), se rota la pieza hacia la derecha:
else if (unicode == 38 || unicode == 17 || unicode == 13 || unicode == 190) { posicion_y = rotar_pieza("derecha"); }
//...y si se pulsa shift (16), espacio (32), 0 (96) o insert (45), se rota la pieza hacia la izquierda:
else if (unicode == 16 || unicode == 32 || unicode == 96 || unicode == 45) { posicion_y = rotar_pieza("izquierda"); }
//Se mueve la pieza:
mover_pieza(posicion_x, posicion_y);
//Se muestra el mapa:
mostrar_mapa(mapa_matriz, mapa_matriz_anterior);
}
//Funcion que pausa o reanuda el juego:
function pausar_reanudar_juego()
{
//Si la pieza no esta moviendose, se reanuda:
if (!movimiento_pieza) { movimiento_pieza = setInterval("mapa_matriz_anterior = guardar_mapa_anterior; mover_pieza('mantener', parseInt(document.getElementById('pieza').style.top) + desplazamiento); mostrar_mapa(mapa_matriz, mapa_matriz_anterior);", velocidad); mostrar_mensaje("Game resumed"); document.getElementById("pausar").innerHTML = "[ Pause ]"; document.getElementById("pausar").title = "Click here to pause game"; }
//...pero si ya esta moviendose, se pausa:
else { clearInterval(movimiento_pieza); movimiento_pieza = false; document.getElementById("mensaje").innerHTML = "Game paused"; document.getElementById("mensaje").style.visibility = "visible"; setTimeout('document.getElementById("mensaje").innerHTML = "Game paused"; document.getElementById("mensaje").style.visibility = "visible";', 1500); document.getElementById("pausar").innerHTML = "[ Resume ]"; document.getElementById("pausar").title = "Click here to resume game"; }
}
//-->
</script>
</head>
<body onLoad="javascript:activar_desactivar_mapa_debug('mantener'); iniciar_juego();" onKeyDown="javascript:pulsar_tecla(event, 'onkeypress');" onKeyPress="javascript:pulsar_tecla(event, 'onkeydown');" bgcolor="#eeeeff" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
<!-- Zona de juego: -->
<div id="zona_juego" style="background:#555555; color:#555555; visibility:visible; top:10px; left:20px; width:244px; height:442px; position:absolute; padding:0px; border:0px; font-size:1px; z-index:1;">
<!-- Mapa: -->
<div id="mapa" style="background:url('fondo.gif'); color:#000000; visibility:visible; top:0px; left:2px; width:242px; height:442px; position:absolute; padding:0px; border:0px; font-size:1px; z-index:2;"></div>
<!-- Fin de Mapa. -->
<!-- Pieza: -->
<div id="pieza" style="background:transparent; color:#ffffff; visibility:hidden; position:absolute; left:0px; top:0px; font-size:1px; z-index:3;"></div>
<!-- Fin de Pieza. -->
<!-- Mensaje: -->
<div id="mensaje" style="background:#cc0000; color:#ffffff; visibility:visible; top:210px; left:11px; width:225px; height:20px; position:absolute; padding:0px; border:0px; font-size:12px; line-height:14px; font-family:verdana; font-weight:bold; filter:alpha(opacity=80); opacity:0.8; -moz-opacity:0.8; text-align:center; z-index:4;">
Loading...
</div>
<!-- Fin de Mensaje. -->
</div>
<!-- Fin de Zona de juego. -->
<!-- Pieza siguiente: -->
<div id="pieza_siguiente" style="background:#102020; color:#ffffff; visibility:visible; top:10px; left:270px; width:120px; height:120px; position:absolute; padding:0px; border:0px; font-size:12px; font-weight:bold; text-align:center; z-index:5;">
Loading...
</div>
<!-- Fin de Pieza siguiente. -->
<!-- Barra de estado: -->
<div id="estado" style="background:#000077; color:#ffffff; visibility:visible; top:453px; left:20px; width:244px; height:20px; position:absolute; padding:0px; border:0px; font-size:10px; line-height:18px; font-family:verdana; font-weight:bold; z-index:6;">
Loading...
</div>
<div id="autor" style="background:transparent; color:#aa0000; visibility:visible; top:473px; left:20px; width:244px; height:20px; position:absolute; padding:0px; border:0px; font-size:9px; line-height:15px; font-family:verdana; font-weight:bold; text-align:center; z-index:7;">
Tetríssimus© by Joan Alba Maldonado
</div>
<!-- Fin de Barra de estado. -->
<!-- Mapa en modo debug: -->
<div id="mapa_debug" style="top:135px; left:270px; background:cyan; visibility:hidden; color:#000066; position:absolute; padding:4px; border:0px; text-align:center; font-family:arial; font-size:12px; z-index:8;">
</div>
<div id="opcion_debug" style="visibility:visible; top:470px; left:270px; padding:0px; background:cyan; color:#000066; position:absolute; padding:4px; border:0px; text-align:center; font-weight:bold; font-family:arial; font-size:12px; line-height:20px; z-index:9;">
<form name="formulario" id="formulario" style="display:inline;">
<label for="casilla" title="Shows map on debug mode (text)" accesskey="m">
<input type="checkbox" name="casilla" id="casilla" onClick="javascript:activar_desactivar_mapa_debug('alternar');" checked> Show debug mode <u>m</u>ap
</label>
</form>
</div>
<!-- Fin de Mapa en modo debug. -->
<!-- Boton de Pausa: -->
<div id="pausar" style="top:450px; left:360px; background:transparent; visibility:visible; color:#660000; position:absolute; padding:4px; border:0px; text-align:center; font-family:arial; font-size:12px; cursor: pointer; cursor: hand; z-index:8;" onClick="javascript:pausar_reanudar_juego();" title="Click here to pause game">
[ Pause ]
</div>
<!-- Fin de Boton de Pausa. -->
<!-- Informacion: -->
<div style="left:400px; top:10px; height:0px; position:absolute; border:0px; padding:0px; background:transparent; color:#333333; text-align:left; line-height:20px; text-decoration:none; font-family:verdana; font-size:12px; z-index:10;">
© <b>Tetríssimus</b> 0.15a
<br>
by <i>Joan Alba Maldonado</i> (<a href="mailto:granvino@granvino.com;">granvino@granvino.com</a>) <sup>(100% DHTML)</sup>
<br> - Prohibited to publish, reproduce or modify without maintain author's name.
<br>
<tt>* Use the keyboard arrow to move, and up arrow (also spacebar, control,
<br>
shift or return) to rotate piece. Under Opera, leave the mouse cursor
<br>
over game zone.</tt>
<br>
<i>Dedicated to Yasmina Llaveria del Castillo</i>
<!-- Fin de Informacion. -->
</body>
</html>
Related examples in the same category