Introdução
Este projeto, o "jQuery Flip Puzzle Game", proporciona uma experiência prática em desenvolvimento web, com foco em JavaScript, jQuery e Bootstrap. Ele envolve programação orientada a objetos em JavaScript e aborda a questão comum da ligação de "this" no contexto do desenvolvimento web. O jogo é implementado usando jQuery e Bootstrap 3 para a interface do usuário. Embora a familiaridade com Bootstrap seja útil, a lógica principal do projeto é construída com jQuery e JavaScript.
No jogo, os jogadores começam com uma grade de blocos laranja. Cada bloco tem um lado laranja e um lado azul. Quando um jogador clica em um bloco, sua cor se inverte, e as cores dos blocos adjacentes também mudam. O objetivo é transformar todos os blocos em azul para completar o jogo.
👀 Pré-visualização

🎯 Tarefas
Neste projeto, você aprenderá:
- Como implementar programação orientada a objetos em JavaScript e abordar a questão da ligação de "this".
- Como construir a lógica principal do jogo usando jQuery e JavaScript.
- Como criar um jogo de quebra-cabeça interativo onde os jogadores invertem as cores dos blocos para vencer.
🏆 Conquistas
Após concluir este projeto, você será capaz de:
- Aplicar princípios de programação orientada a objetos em JavaScript.
- Lidar com a ligação de "this" em JavaScript para tratamento de eventos e métodos de objetos.
- Desenvolver jogos web interativos usando jQuery.
- Utilizar Bootstrap 3 para criar interfaces visualmente atraentes e fáceis de usar.
Estrutura HTML Básica
De acordo com a imagem de pré-visualização, é criado um layout preliminar da página web. No Bootstrap, existe um diálogo Modal semelhante à janela pop-up alert, e o estilo do Modal é mais estético em comparação.
Precisamos incluir os estilos CSS do Bootstrap, nossos estilos CSS personalizados, o arquivo jQuery, o arquivo JavaScript do Bootstrap e o arquivo JavaScript principal do jogo no projeto. Escreva o seguinte código na tag head da página HTML:
<head>
<meta charset="utf-8" />
<title>Blue Puzzle</title>
<!-- Include Bootstrap CSS -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
/>
<!-- Include custom CSS -->
<link rel="stylesheet" href="style.css" />
<!-- Include jQuery and Bootstrap JavaScript -->
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
<!-- Include game main JavaScript -->
<script src="game.js"></script>
</head>
Configuração da Área do Jogo
Para configurar a área do jogo, incluindo os botões para reiniciar o jogo e outras funções, insira o seguinte código na tag body:
<div class="container">
<div class="heading">
<h1 class="title">jQuery Flip Puzzle Game</h1>
<div class="scoresContainer">
<!-- Display current game level -->
<div class="currLevel">Current level: <b>1</b></div>
</div>
</div>
<div class="aboveGame">
<!-- Game buttons -->
<a
class="instruct btn btn-primary"
data-toggle="modal"
data-target="#instructions"
>Game Instructions</a
>
<a
class="newgame btn btn-primary"
data-toggle="modal"
data-target="#newGame"
>Restart</a
>
<a
class="reset btn btn-primary"
data-toggle="modal"
data-target="#restartLevel"
>Reset Level</a
>
</div>
<div class="board">
<!-- Game area -->
<div class="gamerow">
<div class="gamesquare coord0q0"></div>
</div>
</div>
</div>
Layout do Popup de Jogabilidade
Edite o conteúdo do popup correspondente ao botão "Edit Game Instructions". Escreva o seguinte código abaixo do código da área do jogo:
<!-- Gameplay Modal -->
<div
class="modal fade"
id="instructions"
tabindex="-1"
role="dialog"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Gameplay</h4>
</div>
<div class="modal-body">
<p>How to win: Make all puzzle pieces turn blue.</p>
<p>
Gameplay: Each square has one orange side and one blue side. When you
click on a square, its color will flip, and the colors of the squares
adjacent to it will also flip.
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">
Start Game
</button>
</div>
</div>
</div>
</div>
Layout para o Novo Modal do Jogo
Edite o conteúdo do modal correspondente ao botão "Restart". Escreva o seguinte código abaixo do código da lógica do jogo:
<!-- New Game modal -->
<div
class="modal fade"
id="newGame"
tabindex="-1"
role="dialog"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Restart</h4>
</div>
<div class="modal-body">
<p>Are you sure you want to restart?</p>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-primary"
id="newGameConfirm"
data-dismiss="modal"
>
Start Game
</button>
</div>
</div>
</div>
</div>
Layout do Modal de Confirmação de Reset do Nível
Modifique o conteúdo do popup correspondente ao botão "Reset Level". Adicione o seguinte código abaixo do código "Restart Level":
<!-- Reset Level Confirmation Modal -->
<div
class="modal fade"
id="restartLevel"
tabindex="-1"
role="dialog"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Reset Level Confirmation</h4>
</div>
<div class="modal-body">
<p>Are you sure you want to reset the level?</p>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-primary"
id="resetLevelConfirm"
data-dismiss="modal"
>
Reset
</button>
</div>
</div>
</div>
</div>
Estilos CSS
Os estilos CSS do jogo são relativamente simples. O código em style.css é mostrado abaixo:
.container {
width: 600px;
margin: 0 auto;
}
/* Game level */
.scoresContainer {
float: right;
text-align: right;
font-size: 18px;
}
/* Game buttons */
.aboveGame:after {
display: block;
margin: 20px 0;
content: "";
clear: both;
}
/* Game area */
.board {
position: absolute;
background-color: #5f5f5f;
border-radius: 4px;
}
.gamesquare {
float: left;
margin-right: 15px;
border-radius: 3px;
}
Configurando a Cena do Jogo
As peças no painel do jogo são armazenadas como um array bidimensional, onde cada elemento tem um valor de 0 (definido para laranja) ou 1 (definido para azul). Inicialmente, todos os valores são definidos como 0. Quando uma peça é clicada, sua cor é invertida, e as coordenadas das peças adjacentes são determinadas para inverter suas cores também, enquanto também se alteram os valores no array bidimensional. O jogo é concluído quando todos os valores no array se tornam 1 (ou seja, todas as peças são azuis).
Lógica principal:
A relação entre o tamanho da cena do jogo, o nível de dificuldade e o tamanho e número de peças.
Clicar em uma peça e mudar o estado das peças adjacentes.
Verificar se todos os estados das peças são
1.
function SetStyle() {}
SetStyle.prototype.setGridSize = function (level) {
var margin = this.getMargin(level);
var res = ($(".container").width() - margin * level) / level;
// Set the size and spacing of the tiles
$(".gamesquare").css("margin-right", margin);
$(".gamesquare").css("width", res);
$(".gamesquare").css("height", res);
// Set the height, right margin, and bottom margin of each row
$(".gamerow").css("height", res);
$(".gamerow").css("margin-right", margin * -1);
$(".gamerow").css("margin-bottom", margin);
// Set the padding of the game area
$(".board").css("padding", margin);
$(".board").css("padding-bottom", 0);
};
SetStyle.prototype.getMargin = function (level) {
if (level <= 6) return 15;
if (level > 15) return 5;
return 20 - level;
};
Criar Construtor do Jogo
// Game constructor
function Game() {
// Game level
this.level = 1;
// Create objects for controlling the game
this.gb;
this.sh = new SetStyle();
}
O construtor Game tem como objetivo criar instâncias de um jogo com propriedades para rastrear o estado do jogo e métodos para lidar com funcionalidades do jogo, como iniciar o jogo, atualizar seu estado e renderizar visuais. No entanto, a lógica real para essas funcionalidades (dentro dos métodos start, update e render) não é fornecida atualmente, e espaços reservados estão no lugar para implementação futura.
Configurando Detalhes do Jogo
Defina os detalhes do jogo nos métodos prototype da classe Game:
// Prototype method of the Game class, controlling the specific game logic, make sure to reset the 'this' reference
Game.prototype = {
processClick: function (w, h) {
this.gb.processClick(w, h);
this.updateCounts();
if (this.gb.isGameWin()) {
this.gameEnd();
}
},
// Start the game
beginGame: function () {
this.setupLevel();
},
// Game end
gameEnd: function () {
this.level++;
this.resetGame();
},
// Reset the game, redirect 'this' using bind
resetGame: function () {
$("#levelDescriptor").html("Enter Level " + this.level);
setTimeout(
function () {
this.setupLevel(); // When 'this' is not reset, it refers to the window object
}.bind(this),
500
); // Use bind to redirect 'this' from window to the instance
},
// Set the difficulty level
setupLevel: function () {
this.gb = new GameBoard(this.level, this.level);
$(".board").html(""); // Clear game board
this.gb.populate(); // Reset all tiles to orange color
this.gb.renderBoard(); // Render game board and create tiles
this.sh.setGridSize(this.level); // Control tile size in game area
this.updateCounts(); // Update current level display
this.applyBindings(); // Flip the colors of tiles around the clicked tile
},
// Update current level display
updateCounts: function () {
$(".currLevel").html("Current Level: <b>" + this.level + "</b>");
},
applyBindings: function () {
var that = this; // Save 'this' as a variable before the DOM event callback for easy reference
$(".gamesquare").click(function () {
// Get the position of the clicked tile
var cname = $(this).attr("class").split(" ")[1];
var coord = cname.substring(5).split("q");
var height = parseInt(coord[1]);
var width = parseInt(coord[0]);
that.processClick(width, height);
});
},
onNewGameClick: function () {
this.level = 1;
this.setupLevel();
}
};
Este código estende a funcionalidade do construtor Game adicionando métodos prototype. Esses métodos definem a lógica principal do jogo e as interações.
Definindo as Coordenadas dos Blocos
Este código define uma função construtora chamada GameBoard que é usada para criar objetos de tabuleiro de jogo.
// xPos, yPos are the coordinates of the block
function GameBoard(xPos, yPos) {
// Game board
// Tile coordinates
this.high = yPos - 1; // Index starts from 0
this.wide = xPos - 1; // Index starts from 0
this.count = 0;
// The horizontal coordinate is wide, and the vertical coordinate is high
// [0][0] | [0][1]
// - - - - - - - - - - - -
// [1][0] | |[1][1]
// Create a two-dimensional array of tiles
this.board = new Array(xPos);
for (var i = 0; i <= this.wide; i++) {
this.board[i] = new Array(yPos);
}
}
Definindo as Regras do Jogo
O trecho de código fornecido estende a funcionalidade do construtor GameBoard adicionando métodos prototype que definem as regras principais do jogo e a lógica de renderização.
// Implementation of game rules
GameBoard.prototype = {
renderBoard: function () {
var htmlString = ""; // Structure of game squares
for (var j = 0; j <= this.high; j++) {
htmlString += "<div class='gamerow'>";
for (var i = 0; i <= this.wide; i++) {
htmlString += "<div class='gamesquare coord" + i + "q" + j + "'></div>";
}
htmlString += "</div>";
}
$(".board").html(htmlString);
for (var i = 0; i <= this.wide; i++) {
for (var j = 0; j <= this.high; j++) {
this.processClickView(i, j);
}
}
},
processClick: function (w, h) {
//
// Flip the colors of the blocks surrounding the clicked block
//
// Find the surrounding blocks that need to be flipped
var lowx = w - 1;
var highx = w + 1;
var lowy = h - 1;
var highy = h + 1;
// Check if the clicked block is an edge block
if (w == 0) lowx = 0;
if (w == this.wide) highx = this.wide;
if (h == 0) lowy = 0;
if (h == this.high) highy = this.high;
// Flip the vertically adjacent blocks of the clicked block
for (var i = lowy; i <= highy; i++) {
if (this.board[w][i] == 0) {
this.board[w][i] = 1;
this.count++;
} else {
this.board[w][i] = 0;
this.count--;
}
this.processClickView(w, i);
}
// Flip the horizontally adjacent blocks of the clicked block
for (var i = lowx; i <= highx; i++) {
if (i == w) continue;
if (this.board[i][h] == 0) {
this.board[i][h] = 1;
this.count++;
} else {
this.board[i][h] = 0;
this.count--;
}
this.processClickView(i, h);
}
},
// Flip the color of a block
processClickView: function (w, h) {
var coord = ".coord" + w + "q" + h;
if (this.board[w][h] == 0) {
$(coord).css("background-color", "#e8BB39");
} else {
$(coord).css("background-color", "#6060e0");
}
},
// Reset all blocks to orange color
populate: function () {
for (var i = 0; i <= this.wide; i++) {
for (var j = 0; j <= this.high; j++) {
this.board[i][j] = 0;
}
}
},
// Game win condition
isGameWin: function () {
return this.count == (this.wide + 1) * (this.high + 1);
}
};
Inicializando o Jogo
Este código configura o jogo quando o documento está pronto. Ele inicializa o jogo, inicia o primeiro nível e também configura os ouvintes de eventos para reiniciar o nível atual ou iniciar um novo jogo.
// Initialize the game
$(document).ready(function () {
// Create the game
var game = new Game();
// Begin the game
game.beginGame();
// Reset the level tiles
$("#resetLevelConfirm").click(function () {
game.setupLevel();
});
// Start a new game
$("#newGameConfirm").click(function () {
game.onNewGameClick();
});
});
Executando o Aplicativo
- Abra
index.htmlem um navegador web.
- O efeito da página é o seguinte:

Resumo
Do desenvolvimento deste jogo, encontramos:
- Métodos orientados a objetos em JavaScript
- Referência interna
thise redirecionamento em JavaScript - Como manipular o DOM com jQuery
- Questões de relação matricial
Na verdade, não precisamos implementar essa lógica, mas precisamos aprender a mentalidade. Para resolver um problema, precisamos primeiro analisar o problema e esclarecer as relações lógicas envolvidas. Essa é a chave para a resolução de problemas.



