Tetris in Javascript : Game « Page Components « JavaScript DHTML






Tetris in Javascript



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>Tetr&iacute;ssimus &copy; (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 = "&nbsp; 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;">
            &nbsp; 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&iacute;ssimus&copy; 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 &nbsp;
                </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;">
            &copy; <b>Tetr&iacute;ssimus</b> 0.15a
            <br>
            &nbsp;&nbsp;by <i>Joan Alba Maldonado</i> (<a href="mailto:granvino@granvino.com;">granvino@granvino.com</a>) &nbsp;<sup>(100% DHTML)</sup>
            <br>&nbsp;&nbsp;- Prohibited to publish, reproduce or modify without maintain author's name.
            <br>
            &nbsp;&nbsp;<tt>* Use the keyboard arrow to move, and up arrow (also spacebar, control,
            <br>
            &nbsp;&nbsp;  shift or return) to rotate piece. Under Opera, leave the mouse cursor
            <br>
            &nbsp;&nbsp;  over game zone.</tt>
            <br>
            &nbsp;&nbsp;<i>Dedicated to Yasmina Llaveria del Castillo</i>
        <!-- Fin de Informacion. -->
    </body>
</html>

           
       








Related examples in the same category

1.Chess: Draughts
2.Mine game
3.Word search game
4.Ranisima english
5.Yasminuroban (by Joan Alba Maldonado)
6.Level editor for Yasminuroban by Joan Alba Maldonado
7.js mine sweeper
8.Another tictactoe
9.Marbles
10.Jigsaw
11.Game sudoku
12.Game PunkPong
13.Arrange Game
14.Guess Number
15.Tic tac toe
16.Count Game
17. A JavaScript Hangman Game
18.Game library
19.Type Tutor
20.Game: Place It (IE only)
21.HylZee