Introduction
2048 est un jeu extrêmement populaire et facile à apprendre qui a fait sensation dans le monde. Si vous ne l'avez pas encore joué, vous pouvez le télécharger sur votre téléphone mobile pour l'essayer. Ce projet vous guidera dans l'utilisation de HTML, CSS, JavaScript et jQuery pour créer une version web du jeu 2048.
- Apprendre le processus de développement d'une application web
- Explorer la manière de rendre l'application responsive sur les appareils mobiles pour s'adapter à des écrans de diverses tailles et gérer la mise en page et l'initialisation
- Utiliser JavaScript et jQuery pour écrire la logique du jeu, implémenter le déplacement des blocs et déterminer les résultats du jeu.
👀 Aperçu

🎯 Tâches
Dans ce projet, vous allez apprendre :
- Comment créer la mise en page de la page web du jeu 2048 à l'aide de HTML et CSS
- Comment implémenter la logique du jeu en JavaScript et jQuery
- Comment gérer le déplacement des blocs et la fusion des blocs
- Comment tester et exécuter le jeu web dans un navigateur web
🏆 Réalisations
Après avoir terminé ce projet, vous serez capable de :
- Développer une application web responsive pour le jeu 2048
- Utiliser JavaScript et jQuery pour écrire la logique et la fonctionnalité du jeu
- Implémenter le déplacement et la fusion des blocs dans le jeu
- Tester et exécuter un jeu web dans un navigateur web
Préparation du développement
Mettons de côté le style de la page, le jeu 2048 peut être abstrait comme un tableau à deux dimensions. Dans l'état initial, deux nombres doivent être générés aléatoirement. Les nombres générés aléatoirement ne peuvent être que 2 ou 4. Dans la mise en œuvre suivante, nous ferons en sorte que la probabilité d'apparition de 2 et 4 soit égale. Bien sûr, vous pouvez également rendre la probabilité d'apparition de 4 plus faible.
0 0 0 0
2 0 0 0
0 0 2 0
Ensuite, lorsque je presse une flèche directionnelle, les nombres se déplacent dans cette direction et les cellules adjacentes avec le même nombre sont fusionnées. Ensuite, un autre nombre est généré aléatoirement. Par exemple, si nous appuyons sur Haut → Gauche → Haut, l'interface peut devenir :
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 cette manière, nous déplaçons et fusionnons continuellement les nombres jusqu'à ce que les nombres ne puissent plus être fusionnés ou jusqu'à ce que 2048 apparaisse, mettant fin au jeu. Comme vous pouvez le voir, le cœur du jeu est la manipulation de ce tableau à deux dimensions.
Structure du fichier du projet
Tout d'abord, nous devons créer la structure de fichier suivante sous le chemin ~/projet :
~/projet
|__ index.html
|__ main.js
|__ support.js
|__ showanimation.js
|__ style.css
jquery.min.js est déjà placé sous le chemin ~/projet, vous pouvez donc l'utiliser directement.
Maintenant, commençons officiellement nos tâches de codage! Nous allons commencer par la mise en page de la page et compléter progressivement des modules tels que l'initialisation du plateau d'échecs et le déplacement des blocs de nombres.
Mise en page de la page
Comme vous avez peut-être remarqué, le jeu 2048 est construit sur 16 carrés. Plus bas, nous allons utiliser div + css pour dessiner ces cellules 4X4. Veuillez ajouter le code suivant au fichier 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>Jeu 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>Jeu 2048</h1>
<a href="javascript:new_game();" id="new_game_button">Nouvelle partie</a>
<p>score : <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>
Ensuite, nous devons ajouter des styles à la page et à chaque cellule. Veuillez ajouter le code suivant au fichier 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;
}
Après avoir terminé cette étape, ouvrez le fichier index.html à l'aide d'Aperçu,

et nous devrions voir le résultat suivant :

Initialisation du plateau d'échecs
Avec la popularité croissante des appareils mobiles, nous devons gérer l'adaptabilité à diverses tailles d'écran.
Au début du jeu, nous devons générer deux nombres aléatoires sur le plateau d'échecs. Cela est réalisé grâce au code JavaScript.
Dans main.js, ajoutez le code suivant :
var board = new Array(); // Les nombres dans chaque cellule
var score = 0; // Le score
var has_conflicted = new Array(); // Drapeau pour résoudre les éliminations consécutives
var startx = 0; // Coordonnée x du point de départ lors du toucher de l'écran mobile
var starty = 0; // Coordonnée y du point de départ lors du toucher de l'écran mobile
var endx = 0; // Coordonnée x du point d'arrivée lors du toucher de l'écran mobile
var endy = 0; // Coordonnée y du point d'arrivée lors du toucher de l'écran mobile
var success_string = "Succès";
var gameover_string = "Partie terminée";
// Initialiser le plateau d'échecs après le chargement du document HTML
$(document).ready(function () {
// Gérer l'adaptabilité
prepare_for_mobile();
new_game();
});
// Démarrer une nouvelle partie
function new_game() {
// Initialiser le plateau d'échecs
init();
// Générer des nombres dans deux cellules aléatoires
generate_one_number();
}
// Initialiser
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);
}
// Mettre à jour l'affichage du plateau d'échecs
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");
}
// Générer un nombre dans une cellule aléatoire
function generate_one_number() {
if (nospace(board)) {
return false;
}
// Position aléatoire
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;
}
}
}
}
// Nombre aléatoire
var rand_number = Math.random() < 0.5 ? 2 : 4;
// Afficher le nombre aléatoire dans la position aléatoire
board[randx][randy] = rand_number;
show_number_with_animation(randx, randy, rand_number);
return true;
}
// Gérer l'adaptabilité
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);
}
Améliorer la logique du jeu
Ensuite, nous devons améliorer la logique du jeu, y compris le déplacement des tuiles de nombres et la vérification si la partie est terminée. Complétez le code suivant dans support.js :
document_width = window.screen.availWidth; // La largeur de l'écran
grid_container_width = 0.92 * document_width; // La largeur du plateau de jeu
cell_side_length = 0.18 * document_width; // La taille de chaque cellule de grille
cell_space = 0.04 * document_width; // L'espace entre chaque cellule de grille
// Obtenir la distance de la cellule de grille correspondante depuis le haut du plateau de jeu
function get_pos_top(i, j) {
return cell_space + i * (cell_space + cell_side_length);
}
// Obtenir la distance de la cellule de grille correspondante depuis le côté gauche du plateau de jeu
function get_pos_left(i, j) {
return cell_space + j * (cell_space + cell_side_length);
}
// Obtenir la couleur d'arrière-plan du nombre correspondant
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";
}
// Obtenir la couleur du nombre correspondant
function get_number_color(number) {
if (number <= 4) return "#776e65";
return "white";
}
// Vérifier s'il y a des cellules de grille vides sur le plateau de jeu
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;
}
Amélioration des effets d'animation
Ensuite, nous devons améliorer les effets d'animation, y compris l'affichage des tuiles de nombres et la mise à jour du score. Ce code se trouve tout entier dans showanimation.js :
// Animation pour l'affichage des tuiles de nombres
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
);
}
// Mise à jour du score
function update_score(score) {
$("#score").text(score);
}
Déplacer les tuiles numériques
Après avoir terminé la mise en page et l'initialisation, nous allons maintenant implémenter la fonctionnalité de déplacement et d'élimination des tuiles de nombres jusqu'à ce que la partie réussisse ou échoue.
Ajoutez le code suivant à main.js :
// Écouter les mouvements des flèches du clavier
$(document).keydown(function (event) {
if ($("#score").text() == success_string) {
new_game();
return;
}
switch (event.keyCode) {
case 37: // Gauche
event.preventDefault();
if (move_left()) {
setTimeout("generate_one_number()", 210);
setTimeout("is_gameover()", 300);
}
break;
case 38: // Haut
event.preventDefault();
if (move_up()) {
setTimeout("generate_one_number()", 210);
setTimeout("is_gameover()", 300);
}
break;
case 39: // Droite
event.preventDefault();
if (move_right()) {
setTimeout("generate_one_number()", 210);
setTimeout("is_gameover()", 300);
}
break;
case 40: // Bas
event.preventDefault();
if (move_down()) {
setTimeout("generate_one_number()", 210);
setTimeout("is_gameover()", 300);
}
break;
default:
break;
}
});
// Écouter l'événement touchstart sur les appareils mobiles
document.addEventListener("touchstart", function (event) {
startx = event.touches[0].pageX;
starty = event.touches[0].pageY;
});
// Écouter l'événement touchmove sur les appareils mobiles
document.addEventListener("touchmove", function (event) {
event.preventDefault();
});
// Écouter l'événement touchend sur les appareils mobiles
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;
}
// Mouvement sur l'axe x
if (Math.abs(deltax) >= Math.abs(deltay)) {
if (deltax > 0) {
// Déplacer vers la droite
if (move_right()) {
setTimeout("generate_one_number()", 210);
setTimeout("is_gameover()", 300);
}
} else {
// Déplacer vers la gauche
if (move_left()) {
setTimeout("generate_one_number()", 210);
setTimeout("is_gameover()", 300);
}
}
} else {
// Mouvement sur l'axe y
if (deltay > 0) {
// Déplacer vers le bas
if (move_down()) {
setTimeout("generate_one_number()", 210);
setTimeout("is_gameover()", 300);
}
} else {
// Déplacer vers le haut
if (move_up()) {
setTimeout("generate_one_number()", 210);
setTimeout("is_gameover()", 300);
}
}
}
});
// Déplacer vers la gauche
function move_left() {
if (!can_move_left(board)) {
return false;
}
// Déplacer vers la gauche
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;
// Ajouter le score
score += board[i][k];
update_score(score);
has_conflicted[i][k] = true;
break;
}
}
}
}
}
setTimeout("update_board_view()", 200);
return true;
}
// Déplacer vers la droite
function move_right() {
if (!can_move_right(board)) {
return false;
}
// Déplacer vers la droite
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;
// Ajouter le score
score += board[i][k];
update_score(score);
has_conflicted[i][k] = true;
break;
}
}
}
}
}
setTimeout("update_board_view()", 200);
return true;
}
// Déplacer vers le haut
function move_up() {
if (!can_move_up(board)) {
return false;
}
// Déplacer vers le haut
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;
// Ajouter le score
score += board[k][j];
update_score(score);
has_conflicted[k][j] = true;
break;
}
}
}
}
}
setTimeout("update_board_view()", 200);
return true;
}
// Déplacer vers le bas
function move_down() {
if (!can_move_down(board)) {
return false;
}
// Déplacer vers le bas
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;
// Ajouter le score
score += board[k][j];
update_score(score);
has_conflicted[k][j] = true;
break;
}
}
}
}
}
setTimeout("update_board_view()", 200);
return true;
}
// Vérifier si la partie est réussie ou échouée
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();
}
}
// Mettre à jour le texte de fin de partie lorsque la partie se termine
function gameover() {
update_score(gameover_string);
}
Améliorer support.js
Ensuite, nous devons améliorer le code dans support.js, y compris la vérification de s'il est possible de déplacer ou si il est encore possible de déplacer.
// Vérifier si il est possible de déplacer vers la gauche
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;
}
// Vérifier si il est possible de déplacer vers la droite
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;
}
// Vérifier si il est possible de déplacer vers le haut
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;
}
// Vérifier si il est possible de déplacer vers le bas
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;
}
// Vérifier s'il n'y a pas de blocs dans la direction horizontale
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;
}
// Vérifier s'il n'y a pas de blocs dans la direction verticale
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;
}
// Vérifier s'il est encore possible de déplacer
function nomove(board) {
if (
can_move_down(board) ||
can_move_up(board) ||
can_move_right(board) ||
can_move_left(board)
) {
return false;
}
return true;
}
Terminer le jeu
Enfin, nous devons terminer le code dans showanimation.js, y compris l'affichage de l'animation de déplacement et de fusion.
// Effet d'animation lorsqu'une cellule de grille se déplace
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
);
}
Avec cela, notre version web de 2048 est terminée.
Exécution et test
Ouvrez index.html dans un navigateur web.

Pour voir les effets suivants, cliquez sur le bouton Go Live dans le coin inférieur droit de WebIDE, et basculez vers l'onglet "Web 8080".

Résumé
Dans ce projet, nous avons implémenté une version web du jeu 2048 à l'aide de HTML, CSS, JavaScript et jQuery. Nous avons également appris à le rendre compatible avec les appareils mobiles. Il est à espérer que grâce à ce projet, vous pourrez approfondir votre compréhension des technologies front-end et améliorer vos compétences d'application globale.



