Juego web de 2048 utilizando jQuery

JavaScriptJavaScriptBeginner
Practicar Ahora

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

2048 es un juego extremadamente popular y fácil de aprender que ha tomado el mundo por la tormenta. Si aún no lo has jugado, puedes descargarlo en tu teléfono móvil para probarlo. Este proyecto te guiará en el uso de HTML, CSS, JavaScript y jQuery para crear una versión web del juego 2048.

  • Aprender el proceso de desarrollo de una aplicación web
  • Explorar cómo hacer que la aplicación sea responsive en dispositivos móviles para adaptarse a pantallas de varios tamaños y manejar el diseño y la inicialización
  • Utilizar JavaScript y jQuery para escribir la lógica del juego, implementar el movimiento de bloques y determinar los resultados del juego.

👀 Vista previa

Animación de vista previa del juego 2048

🎯 Tareas

En este proyecto, aprenderás:

  • Cómo crear el diseño de página de un juego web 2048 utilizando HTML y CSS
  • Cómo implementar la lógica del juego en JavaScript y jQuery
  • Cómo manejar el movimiento de bloques y la fusión de bloques
  • Cómo probar y ejecutar el juego web en un navegador web

🏆 Logros

Después de completar este proyecto, podrás:

  • Desarrollar una aplicación web responsive para el juego 2048
  • Utilizar JavaScript y jQuery para escribir la lógica y la funcionalidad del juego
  • Implementar el movimiento y la fusión de bloques en el juego
  • Probar y ejecutar un juego web en un navegador web

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL javascript(("JavaScript")) -.-> javascript/BasicConceptsGroup(["Basic Concepts"]) javascript(("JavaScript")) -.-> javascript/DOMManipulationGroup(["DOM Manipulation"]) javascript/BasicConceptsGroup -.-> javascript/cond_stmts("Conditional Statements") javascript/BasicConceptsGroup -.-> javascript/switch_stmts("Switch Statements") javascript/BasicConceptsGroup -.-> javascript/loops("Loops") javascript/BasicConceptsGroup -.-> javascript/array_methods("Array Methods") javascript/BasicConceptsGroup -.-> javascript/obj_manip("Object Manipulation") javascript/DOMManipulationGroup -.-> javascript/dom_select("DOM Selection") javascript/DOMManipulationGroup -.-> javascript/dom_manip("DOM Manipulation") javascript/DOMManipulationGroup -.-> javascript/event_handle("Event Handling") javascript/DOMManipulationGroup -.-> javascript/dom_traverse("DOM Traversal") subgraph Lab Skills javascript/cond_stmts -.-> lab-445688{{"Juego web de 2048 utilizando jQuery"}} javascript/switch_stmts -.-> lab-445688{{"Juego web de 2048 utilizando jQuery"}} javascript/loops -.-> lab-445688{{"Juego web de 2048 utilizando jQuery"}} javascript/array_methods -.-> lab-445688{{"Juego web de 2048 utilizando jQuery"}} javascript/obj_manip -.-> lab-445688{{"Juego web de 2048 utilizando jQuery"}} javascript/dom_select -.-> lab-445688{{"Juego web de 2048 utilizando jQuery"}} javascript/dom_manip -.-> lab-445688{{"Juego web de 2048 utilizando jQuery"}} javascript/event_handle -.-> lab-445688{{"Juego web de 2048 utilizando jQuery"}} javascript/dom_traverse -.-> lab-445688{{"Juego web de 2048 utilizando jQuery"}} end

Preparación para el desarrollo

Dejando a un lado el estilo de página, el juego 2048 se puede abstraer como una matriz bidimensional. En el estado inicial, se deben generar dos números al azar. Los números generados al azar solo pueden ser 2 o 4. En la implementación siguiente, haremos que la probabilidad de aparición de 2 y 4 sea igual. Por supuesto, también puedes hacer que la probabilidad de aparición de 4 sea menor.

0 0 0 0
2 0 0 0
0 0 2 0

Luego, cuando presiono una tecla direccional, los números se moverán en esa dirección y las celdas adyacentes con el mismo número se fusionarán. Luego, se generará otro número al azar. Por ejemplo, si presionamos Arriba → Izquierda → Arriba, la interfaz puede quedar así:

2 0 2 0
0 0 0 0
0 0 0 0
4 0 0 0
4 0 0 0
0 0 0 0
0 0 2 0
4 0 0 0
8 0 2 0
0 0 0 0
0 4 0 0

De esta manera, seguimos moviendo y fusionando números hasta que ya no se puedan fusionar o hasta que aparezca 2048, terminando el juego. Como puedes ver, el núcleo del juego es manipular esta matriz bidimensional.

Estructura de archivos del proyecto

Primero, debemos crear la siguiente estructura de archivos en el camino ~/proyecto:

~/proyecto
 |__ index.html
 |__ main.js
 |__ support.js
 |__ showanimation.js
 |__ style.css

jquery.min.js ya se encuentra en el camino ~/proyecto, por lo que se puede utilizar directamente.

Ahora, ¡comencemos oficialmente con nuestras tareas de codificación! Empezaremos con el diseño de página y gradualmente completaremos módulos como la inicialización del tablero de ajedrez y el movimiento de los bloques de números.

Diseño de página

Como es probable que hayas observado, el juego 2048 se construye sobre 16 cuadrados. A continuación, usaremos div + css para dibujar estas celdas de 4X4. Agregue el siguiente código al archivo index.html:

<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
    />
    <title>Juego 2048</title>
    <link rel="stylesheet" href="style.css" />
    <script type="text/javascript" src="jquery.min.js"></script>
    <script type="text/javascript" src="main.js"></script>
    <script type="text/javascript" src="showanimation.js"></script>
    <script type="text/javascript" src="support.js"></script>
  </head>
  <body>
    <header>
      <h1>Juego 2048</h1>
      <a href="javascript:new_game();" id="new_game_button">Nuevo Juego</a>
      <p>puntuación: <span id="score">0</span></p>
    </header>
    <div id="grid_container">
      <div class="grid_cell" id="grid_cell_0_0"></div>
      <div class="grid_cell" id="grid_cell_0_1"></div>
      <div class="grid_cell" id="grid_cell_0_2"></div>
      <div class="grid_cell" id="grid_cell_0_3"></div>

      <div class="grid_cell" id="grid_cell_1_0"></div>
      <div class="grid_cell" id="grid_cell_1_1"></div>
      <div class="grid_cell" id="grid_cell_1_2"></div>
      <div class="grid_cell" id="grid_cell_1_3"></div>

      <div class="grid_cell" id="grid_cell_2_0"></div>
      <div class="grid_cell" id="grid_cell_2_1"></div>
      <div class="grid_cell" id="grid_cell_2_2"></div>
      <div class="grid_cell" id="grid_cell_2_3"></div>

      <div class="grid_cell" id="grid_cell_3_0"></div>
      <div class="grid_cell" id="grid_cell_3_1"></div>
      <div class="grid_cell" id="grid_cell_3_2"></div>
      <div class="grid_cell" id="grid_cell_3_3"></div>
    </div>
  </body>
</html>

A continuación, necesitamos agregar estilos a la página y a cada celda. Agregue el siguiente código al archivo style.css:

body {
  padding: 50px 0px;
}

header {
  display: block;
  margin: 0 auto;
  width: 100%;
  text-align: center;
}

header h1 {
  font-family: Arial;
  font-size: 40px;
  font-weight: bold;
  margin: 0 auto;
  color: #776e65;
  padding: 20px 0px;
}

header #new_game_button {
  display: block;
  margin: 0px auto;
  width: 100px;
  padding: 10px 10px;
  background-color: #8f7a66;
  font-family: Arial;
  color: white;
  border-radius: 10px;
  text-decoration: none;
}

header #new_game_button:hover {
  background-color: #9f8b77;
}

header p {
  font-family: Arial;
  font-size: 25px;
  margin: 5px auto;
}

#grid_container {
  width: 460px;
  height: 460px;
  padding: 20px;
  margin: 0px auto;
  background-color: #bbada0;
  border-radius: 10px;
  position: relative;
}

.grid_cell {
  width: 100px;
  height: 100px;
  border-radius: 6px;
  background-color: #ccc0b3;
  position: absolute;
}

.number_cell {
  border-radius: 6px;
  font-family: Arial;
  font-weight: bold;
  font-size: 60px;
  line-height: 100px;
  text-align: center;
  position: absolute;
}

Después de completar este paso, abra el archivo index.html usando Vista previa,

Código HTML del juego 2048

y deberíamos ver el siguiente resultado:

Diseño de cuadrícula del juego 2048
✨ Revisar Solución y Practicar

Inicialización del tablero de ajedrez

Con la creciente popularidad de los dispositivos móviles, necesitamos manejar la adaptabilidad a varios tamaños de pantalla.

Al comienzo del juego, necesitamos generar dos números aleatorios en el tablero de ajedrez. Esto se logra a través de código JavaScript.

En main.js, agregue lo siguiente:

var board = new Array(); // Los números en cada celda
var score = 0; // La puntuación
var has_conflicted = new Array(); // Bandera para resolver eliminaciones consecutivas
var startx = 0; // Coordenada x del punto de inicio al tocar la pantalla móvil
var starty = 0; // Coordenada y del punto de inicio al tocar la pantalla móvil
var endx = 0; // Coordenada x del punto final al tocar la pantalla móvil
var endy = 0; // Coordenada y del punto final al tocar la pantalla móvil
var success_string = "Success";
var gameover_string = "GameOver";

// Inicializar el tablero de ajedrez después de que se haya cargado el documento HTML
$(document).ready(function () {
  // Manejar la adaptabilidad
  prepare_for_mobile();
  new_game();
});

// Iniciar un nuevo juego
function new_game() {
  // Inicializar el tablero de ajedrez
  init();
  // Generar números en dos celdas aleatorias
  generate_one_number();
}

// Inicializar
function init() {
  for (var i = 0; i < 4; i++) {
    for (var j = 0; j < 4; j++) {
      var grid_cell = $("#grid_cell_" + i + "_" + j);
      grid_cell.css("top", get_pos_top(i, j));
      grid_cell.css("left", get_pos_left(i, j));
    }
  }
  for (var i = 0; i < 4; i++) {
    board[i] = new Array();
    has_conflicted[i] = new Array();
    for (var j = 0; j < 4; j++) {
      board[i][j] = 0;
      has_conflicted[i][j] = false;
    }
  }
  update_board_view();
  score = 0;
  update_score(score);
}

// Actualizar la vista del tablero de ajedrez
function update_board_view() {
  $(".number_cell").remove();
  for (var i = 0; i < 4; i++) {
    for (var j = 0; j < 4; j++) {
      $("#grid_container").append(
        '<div class="number_cell" id="number_cell_' + i + "_" + j + '"></div>'
      );
      var number_cell = $("#number_cell_" + i + "_" + j);
      if (board[i][j] == 0) {
        number_cell.css("width", "0px");
        number_cell.css("height", "0px");
        number_cell.css("top", get_pos_top(i, j) + cell_side_length / 2);
        number_cell.css("left", get_pos_left(i, j) + cell_side_length / 2);
      } else {
        number_cell.css("width", cell_side_length);
        number_cell.css("height", cell_side_length);
        number_cell.css("top", get_pos_top(i, j));
        number_cell.css("left", get_pos_left(i, j));
        number_cell.css(
          "background-color",
          get_number_background_color(board[i][j])
        );
        number_cell.css("color", get_number_color(board[i][j]));
        number_cell.text(board[i][j]);
      }
      has_conflicted[i][j] = false;
    }
  }
  $(".number_cell").css("line-height", cell_side_length + "px");
  $(".number_cell").css("font-size", 0.6 * cell_side_length + "px");
}

// Generar un número en una celda aleatoria
function generate_one_number() {
  if (nospace(board)) {
    return false;
  }
  // Posición aleatoria
  var randx = parseInt(Math.floor(Math.random() * 4));
  var randy = parseInt(Math.floor(Math.random() * 4));
  var time = 0;
  while (time < 50) {
    if (board[randx][randy] == 0) {
      break;
    }
    randx = parseInt(Math.floor(Math.random() * 4));
    randy = parseInt(Math.floor(Math.random() * 4));
    time++;
  }
  if (time == 50) {
    for (var i = 0; i < 4; i++) {
      for (var j = 0; j < 4; j++) {
        if (board[i][j] == 0) {
          randx = i;
          randy = j;
        }
      }
    }
  }
  // Número aleatorio
  var rand_number = Math.random() < 0.5 ? 2 : 4;
  // Mostrar el número aleatorio en la posición aleatoria
  board[randx][randy] = rand_number;
  show_number_with_animation(randx, randy, rand_number);
  return true;
}

// Manejar la adaptabilidad
function prepare_for_mobile() {
  if (document_width > 500) {
    grid_container_width = 500;
    cell_side_length = 100;
    cell_space = 20;
  }
  $("#grid_container").css("width", grid_container_width - 2 * cell_space);
  $("#grid_container").css("height", grid_container_width - 2 * cell_space);
  $("#grid_container").css("padding", cell_space);
  $("#grid_container").css("border-radius", 0.02 * grid_container_width);
  $(".grid_cell").css("width", cell_side_length);
  $(".grid_cell").css("height", cell_side_length);
  $(".grid_cell").css("border-radius", 0.02 * grid_container_width);
}
✨ Revisar Solución y Practicar

Mejora de la lógica del juego

A continuación, necesitamos mejorar la lógica del juego, incluyendo el movimiento de las fichas numéricas y la comprobación de si el juego ha terminado. Complete el siguiente código en support.js:

document_width = window.screen.availWidth; // El ancho de la pantalla
grid_container_width = 0.92 * document_width; // El ancho del tablero de juego
cell_side_length = 0.18 * document_width; // El tamaño de cada celda del grid
cell_space = 0.04 * document_width; // El espacio entre cada celda del grid

// Obtener la distancia de la celda del grid correspondiente desde la parte superior del tablero de juego
function get_pos_top(i, j) {
  return cell_space + i * (cell_space + cell_side_length);
}

// Obtener la distancia de la celda del grid correspondiente desde el lado izquierdo del tablero de juego
function get_pos_left(i, j) {
  return cell_space + j * (cell_space + cell_side_length);
}

// Obtener el color de fondo del número correspondiente
function get_number_background_color(number) {
  switch (number) {
    case 2:
      return "#eee4da";
      break;
    case 4:
      return "#ede0c8";
      break;
    case 8:
      return "#f2b179";
      break;
    case 16:
      return "#f59563";
      break;
    case 32:
      return "#f67c5f";
      break;
    case 64:
      return "#f65e3b";
      break;
    case 128:
      return "#edcf72";
      break;
    case 256:
      return "#edcc61";
      break;
    case 512:
      return "#9c0";
      break;
    case 1024:
      return "#33b5e5";
      break;
    case 2048:
      return "#09c";
      break;
    case 4096:
      return "#a6c";
      break;
    case 8192:
      return "#93c";
      break;
  }
  return "black";
}

// Obtener el color del número correspondiente
function get_number_color(number) {
  if (number <= 4) return "#776e65";
  return "white";
}

// Comprobar si hay alguna celda del grid vacía en el tablero de juego
function nospace(board) {
  for (var i = 0; i < 4; i++) {
    for (var j = 0; j < 4; j++) {
      if (board[i][j] == 0) {
        return false;
      }
    }
  }
  return true;
}
✨ Revisar Solución y Practicar

Mejora de los efectos de animación

A continuación, necesitamos mejorar los efectos de animación, incluyendo la visualización de las fichas numéricas y la actualización de la puntuación. Todo este código se encuentra en showanimation.js:

// Animación para mostrar las fichas numéricas
function show_number_with_animation(i, j, rand_number) {
  var number_cell = $("#number_cell_" + i + "_" + j);
  number_cell.css("background-color", get_number_background_color(rand_number));
  number_cell.css("color", get_number_color(rand_number));
  number_cell.text(rand_number);
  number_cell.animate(
    {
      width: cell_side_length,
      height: cell_side_length,
      top: get_pos_top(i, j),
      left: get_pos_left(i, j)
    },
    50
  );
}

// Actualización de la puntuación
function update_score(score) {
  $("#score").text(score);
}
✨ Revisar Solución y Practicar

Mover las fichas numéricas

Después de completar el diseño y la inicialización, ahora implementaremos la funcionalidad para mover y eliminar las fichas numéricas hasta que el juego tenga éxito o fracase.

Agregue el siguiente código a main.js:

// Escuchar los movimientos de las teclas de flecha del teclado
$(document).keydown(function (event) {
  if ($("#score").text() == success_string) {
    new_game();
    return;
  }
  switch (event.keyCode) {
    case 37: // Izquierda
      event.preventDefault();
      if (move_left()) {
        setTimeout("generate_one_number()", 210);
        setTimeout("is_gameover()", 300);
      }
      break;
    case 38: // Arriba
      event.preventDefault();
      if (move_up()) {
        setTimeout("generate_one_number()", 210);
        setTimeout("is_gameover()", 300);
      }
      break;
    case 39: // Derecha
      event.preventDefault();
      if (move_right()) {
        setTimeout("generate_one_number()", 210);
        setTimeout("is_gameover()", 300);
      }
      break;
    case 40: // Abajo
      event.preventDefault();
      if (move_down()) {
        setTimeout("generate_one_number()", 210);
        setTimeout("is_gameover()", 300);
      }
      break;
    default:
      break;
  }
});

// Escuchar el evento touchstart en dispositivos móviles
document.addEventListener("touchstart", function (event) {
  startx = event.touches[0].pageX;
  starty = event.touches[0].pageY;
});

// Escuchar el evento touchmove en dispositivos móviles
document.addEventListener("touchmove", function (event) {
  event.preventDefault();
});

// Escuchar el evento touchend en dispositivos móviles
document.addEventListener("touchend", function (event) {
  endx = event.changedTouches[0].pageX;
  endy = event.changedTouches[0].pageY;

  var deltax = endx - startx;
  var deltay = endy - starty;
  if (
    Math.abs(deltax) < 0.3 * document_width &&
    Math.abs(deltay) < 0.3 * document_width
  ) {
    return;
  }
  if ($("#score").text() == success_string) {
    new_game();
    return;
  }
  // Movimiento en el eje x
  if (Math.abs(deltax) >= Math.abs(deltay)) {
    if (deltax > 0) {
      // Mover hacia la derecha
      if (move_right()) {
        setTimeout("generate_one_number()", 210);
        setTimeout("is_gameover()", 300);
      }
    } else {
      // Mover hacia la izquierda
      if (move_left()) {
        setTimeout("generate_one_number()", 210);
        setTimeout("is_gameover()", 300);
      }
    }
  } else {
    // Movimiento en el eje y
    if (deltay > 0) {
      // Mover hacia abajo
      if (move_down()) {
        setTimeout("generate_one_number()", 210);
        setTimeout("is_gameover()", 300);
      }
    } else {
      // Mover hacia arriba
      if (move_up()) {
        setTimeout("generate_one_number()", 210);
        setTimeout("is_gameover()", 300);
      }
    }
  }
});

// Mover hacia la izquierda
function move_left() {
  if (!can_move_left(board)) {
    return false;
  }
  // Mover hacia la izquierda
  for (var i = 0; i < 4; i++) {
    for (var j = 1; j < 4; j++) {
      if (board[i][j] != 0) {
        for (var k = 0; k < j; k++) {
          if (board[i][k] == 0 && no_block_horizontal(i, k, j, board)) {
            show_move_animation(i, j, i, k);
            board[i][k] = board[i][j];
            board[i][j] = 0;
            break;
          } else if (
            board[i][k] == board[i][j] &&
            no_block_horizontal(i, k, j, board) &&
            !has_conflicted[i][k]
          ) {
            show_move_animation(i, j, i, k);
            board[i][k] += board[i][j];
            board[i][j] = 0;
            // Sumar puntuación
            score += board[i][k];
            update_score(score);
            has_conflicted[i][k] = true;
            break;
          }
        }
      }
    }
  }
  setTimeout("update_board_view()", 200);
  return true;
}

// Mover hacia la derecha
function move_right() {
  if (!can_move_right(board)) {
    return false;
  }
  // Mover hacia la derecha
  for (var i = 0; i < 4; i++) {
    for (var j = 2; j >= 0; j--) {
      if (board[i][j] != 0) {
        for (var k = 3; k > j; k--) {
          if (board[i][k] == 0 && no_block_horizontal(i, j, k, board)) {
            show_move_animation(i, j, i, k);
            board[i][k] = board[i][j];
            board[i][j] = 0;
            break;
          } else if (
            board[i][k] == board[i][j] &&
            no_block_horizontal(i, j, k, board) &&
            !has_conflicted[i][k]
          ) {
            show_move_animation(i, j, i, k);
            board[i][k] += board[i][j];
            board[i][j] = 0;
            // Sumar puntuación
            score += board[i][k];
            update_score(score);
            has_conflicted[i][k] = true;
            break;
          }
        }
      }
    }
  }
  setTimeout("update_board_view()", 200);
  return true;
}

// Mover hacia arriba
function move_up() {
  if (!can_move_up(board)) {
    return false;
  }
  // Mover hacia arriba
  for (var j = 0; j < 4; j++) {
    for (var i = 1; i < 4; i++) {
      if (board[i][j] != 0) {
        for (var k = 0; k < i; k++) {
          if (board[k][j] == 0 && no_block_vertical(j, k, i, board)) {
            show_move_animation(i, j, k, j);
            board[k][j] = board[i][j];
            board[i][j] = 0;
            break;
          } else if (
            board[k][j] == board[i][j] &&
            no_block_vertical(j, k, i, board) &&
            !has_conflicted[k][j]
          ) {
            show_move_animation(i, j, k, j);
            board[k][j] += board[i][j];
            board[i][j] = 0;
            // Sumar puntuación
            score += board[k][j];
            update_score(score);
            has_conflicted[k][j] = true;
            break;
          }
        }
      }
    }
  }
  setTimeout("update_board_view()", 200);
  return true;
}

// Mover hacia abajo
function move_down() {
  if (!can_move_down(board)) {
    return false;
  }
  // Mover hacia abajo
  for (var j = 0; j < 4; j++) {
    for (var i = 2; i >= 0; i--) {
      if (board[i][j] != 0) {
        for (var k = 3; k > i; k--) {
          if (board[k][j] == 0 && no_block_vertical(j, i, k, board)) {
            show_move_animation(i, j, k, j);
            board[k][j] = board[i][j];
            board[i][j] = 0;
            break;
          } else if (
            board[k][j] == board[i][j] &&
            no_block_vertical(j, i, k, board) &&
            !has_conflicted[k][j]
          ) {
            show_move_animation(i, j, k, j);
            board[k][j] += board[i][j];
            board[i][j] = 0;
            // Sumar puntuación
            score += board[k][j];
            update_score(score);
            has_conflicted[k][j] = true;
            break;
          }
        }
      }
    }
  }
  setTimeout("update_board_view()", 200);
  return true;
}

// Comprobar si el juego ha tenido éxito o fracasado
function is_gameover() {
  for (var i = 0; i < 4; i++) {
    for (var j = 0; j < 4; j++) {
      if (board[i][j] == 2048) {
        update_score(success_string);
        return;
      }
    }
  }
  if (nospace(board) && nomove(board)) {
    gameover();
  }
}

// Actualizar el texto de fin de juego cuando el juego termina
function gameover() {
  update_score(gameover_string);
}
✨ Revisar Solución y Practicar

Mejora de support.js

A continuación, necesitamos mejorar el código en support.js, incluyendo la comprobación de si se puede mover o todavía se puede mover.

// Comprobar si se puede mover hacia la izquierda
function can_move_left(board) {
  for (var i = 0; i < 4; i++) {
    for (var j = 1; j < 4; j++) {
      if (board[i][j] != 0) {
        if (board[i][j - 1] == 0 || board[i][j] == board[i][j - 1]) {
          return true;
        }
      }
    }
  }
  return false;
}

// Comprobar si se puede mover hacia la derecha
function can_move_right(board) {
  for (var i = 0; i < 4; i++) {
    for (var j = 2; j >= 0; j--) {
      if (board[i][j] != 0) {
        if (board[i][j + 1] == 0 || board[i][j] == board[i][j + 1]) {
          return true;
        }
      }
    }
  }
  return false;
}

// Comprobar si se puede mover hacia arriba
function can_move_up(board) {
  for (var j = 0; j < 4; j++) {
    for (var i = 1; i < 4; i++) {
      if (board[i][j] != 0) {
        if (board[i - 1][j] == 0 || board[i - 1][j] == board[i][j]) {
          return true;
        }
      }
    }
  }
  return false;
}

// Comprobar si se puede mover hacia abajo
function can_move_down(board) {
  for (var j = 0; j < 4; j++) {
    for (var i = 2; i >= 0; i--) {
      if (board[i][j] != 0) {
        if (board[i + 1][j] == 0 || board[i + 1][j] == board[i][j]) {
          return true;
        }
      }
    }
  }
  return false;
}

// Comprobar si no hay bloques en la dirección horizontal
function no_block_horizontal(row, col1, col2, board) {
  for (var i = col1 + 1; i < col2; i++) {
    if (board[row][i] != 0) {
      return false;
    }
  }
  return true;
}

// Comprobar si no hay bloques en la dirección vertical
function no_block_vertical(col, row1, row2, board) {
  for (var i = row1 + 1; i < row2; i++) {
    if (board[i][col] != 0) {
      return false;
    }
  }
  return true;
}

// Comprobar si todavía se puede mover
function nomove(board) {
  if (
    can_move_down(board) ||
    can_move_up(board) ||
    can_move_right(board) ||
    can_move_left(board)
  ) {
    return false;
  }
  return true;
}
✨ Revisar Solución y Practicar

Completar el juego

Finalmente, necesitamos completar el código en showanimation.js, incluyendo la visualización de la animación de movimiento y la animación de fusión.

// Efecto de animación cuando una celda del grid se mueve
function show_move_animation(fromx, fromy, tox, toy) {
  var number_cell = $("#number_cell_" + fromx + "_" + fromy);
  number_cell.animate(
    {
      top: get_pos_top(tox, toy),
      left: get_pos_left(tox, toy)
    },
    200
  );
}

Con esto, nuestra versión web de 2048 está completa.

✨ Revisar Solución y Practicar

Ejecución y prueba

Abra index.html en un navegador web.

Web browser displaying index html

Para ver los siguientes efectos, haga clic en el botón Go Live en la esquina inferior derecha de WebIDE y cambie a la pestaña "Web 8080".

Live preview demonstration
✨ Revisar Solución y Practicar

Resumen

En este proyecto, hemos implementado una versión web del juego 2048 utilizando HTML, CSS, JavaScript y jQuery. También hemos aprendido cómo hacerlo compatible con dispositivos móviles. Se cree que a través de este proyecto, puede profundizar su comprensión de la tecnología front-end y mejorar sus habilidades de aplicación integral.