Se você está procurando aprender como criar um jogo básico de plataforma com HTML5 e JavaScript, este post é para você! Vamos explorar um jogo estilo runner, onde o objetivo é controlar um bloco que precisa pular para evitar obstáculos.
O que vamos construir:
- Um bloco (representado por um quadrado) que pode pular (pode ser um dinossauro aqui).
- Obstáculos que aparecem do lado direito e vão em direção ao bloco (que podem ser as árvores).
- Detecção de colisões.
- Contagem de pontos.
Estrutura do código
Vamos dividir o código em duas partes principais:
- HTML: Para estruturar a tela e criar a área de jogo.
- JavaScript: Para adicionar a lógica do jogo, movimento do bloco, obstáculos, colisões e o loop de jogo.
Passo 1: Estrutura HTML
Primeiro, criamos um arquivo simples de HTML com uma tag <canvas>
, onde o jogo será renderizado. O <canvas>
é a área onde desenharemos o bloco e os obstáculos. O arquivo HTML ficará assim:
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bloco Runner DEVDATA</title>
</head>
<body>
<canvas id="game" width="800" height="400"></canvas>
<script>
// Aqui vai o código JavaScript
</script>
</body>
</html>
Passo 2: Configuração do Canvas e Contexto
Agora, no script JavaScript, começamos pegando o elemento <canvas>
e criando o contexto de desenho (ctx
). Este contexto nos permite desenhar o bloco e os obstáculos na tela.
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
Passo 3: Definição do Bloco (o carinha que pula)
Vamos criar um objeto dino
(representando nosso bloco) que pode pular e é controlado pela gravidade. O bloco começará em uma posição fixa no eixo Y, mas vai cair de volta quando não estiver pulando.
const dino = {
x: 50,
y: 150,
width: 40,
height: 40,
vy: 0,
jumping: false,
draw() {
ctx.fillStyle = "#000";
ctx.fillRect(this.x, this.y, this.width, this.height);
},
update() {
if (this.jumping) {
this.vy += gravity;
this.y += this.vy;
if (this.y >= 150) {
this.y = 150;
this.vy = 0;
this.jumping = false;
}
}
},
jump() {
if (!this.jumping) {
this.jumping = true;
this.vy = -12;
}
}
};
Passo 4: Criando os Obstáculos
Agora, precisamos criar obstáculos que aparecem aleatoriamente na tela e vão da direita para a esquerda. Esses obstáculos têm uma largura e altura aleatória e, quando saem da tela, são removidos.
class Obstacle {
constructor() {
this.width = 20 + Math.random() * 20;
this.height = 30 + Math.random() * 40;
this.x = canvas.width;
this.y = 200 - this.height;
}
draw() {
ctx.fillStyle = "#666";
ctx.fillRect(this.x, this.y, this.width, this.height);
}
update() {
this.x -= gameSpeed;
}
}
Passo 5: Lógica do Jogo
O loop do jogo é o coração do processo. Aqui, o bloco será desenhado e atualizado a cada frame, assim como os obstáculos. Além disso, a pontuação será atualizada à medida que o jogo avança.
let obstacles = [];
let spawnTimer = 0;
let score = 0;
let gameOver = false;
function resetGame() {
obstacles = [];
spawnTimer = 0;
score = 0;
gameSpeed = 6;
dino.y = 150;
dino.vy = 0;
dino.jumping = false;
gameOver = false;
loop();
}
function loop() {
if (gameOver) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
dino.update();
dino.draw();
if (spawnTimer <= 0) {
obstacles.push(new Obstacle());
spawnTimer = 60 + Math.random() * 40;
} else {
spawnTimer--;
}
for (let i = 0; i < obstacles.length; i++) {
const o = obstacles[i];
o.update();
o.draw();
// Colisão
if (
dino.x < o.x + o.width &&
dino.x + dino.width > o.x &&
dino.y < o.y + o.height &&
dino.y + dino.height > o.y
) {
gameOver = true;
alert("Game Over! Score: " + Math.floor(score));
resetGame();
return;
}
// Remove obstáculos fora da tela
if (o.x + o.width < 0) {
obstacles.splice(i, 1);
i--;
}
}
score += 0.1;
gameSpeed += 0.001;
// Desenha o chão
ctx.fillStyle = "#888";
ctx.fillRect(0, 190, canvas.width, 2);
// Exibe a pontuação
ctx.fillStyle = "#000";
ctx.font = "16px monospace";
ctx.fillText("Score: " + Math.floor(score), 10, 20);
requestAnimationFrame(loop);
}
document.addEventListener("keydown", (e) => {
if (e.code === "Space" || e.code === "ArrowUp") dino.jump();
});
loop();
Passo 6: Detecção de Teclas
Adicionamos um evento keydown
para que, quando o usuário pressionar a tecla de espaço ou a seta para cima, o bloco execute o pulo.
Passo 7: Testando o Jogo
Agora, você pode testar o jogo localmente, abrindo o arquivo HTML em seu navegador. O bloco começará correndo e você precisará pular para evitar os obstáculos. A pontuação será mostrada no topo da tela e aumentará à medida que o jogo avança.
O que aprendemos aqui?
- Como usar o
<canvas>
para desenhar objetos dinâmicos. - Como controlar o movimento de um personagem (neste caso, o bloco) com a física básica de gravidade.
- Como criar obstáculos que surgem de forma aleatória e interagem com o personagem.
- Como configurar o loop do jogo para manter tudo em movimento e atualizando.
Conclusão
Este jogo simples foi construído apenas com HTML5 e JavaScript, e você pode personalizá-lo conforme desejar. Desde modificar o estilo do bloco até adicionar novos elementos no jogo, as possibilidades são infinitas!
Agora é só fazer o download do código HTML e jogar! Se você tiver alguma dúvida ou quiser melhorar o jogo, fique à vontade para compartilhar suas ideias!
EXEMPLO FUNCIONAL COMPLETO:
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BLock Runner Devdata</title>
</head>
<body>
<canvas id="game" width="800" height="400"></canvas>
<script>
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
const gravity = 0.6;
let gameSpeed = 6;
const dino = {
x: 50,
y: 150,
width: 40,
height: 40,
vy: 0,
jumping: false,
draw() {
ctx.fillStyle = "#000";
ctx.fillRect(this.x, this.y, this.width, this.height);
},
update() {
if (this.jumping) {
this.vy += gravity;
this.y += this.vy;
if (this.y >= 150) {
this.y = 150;
this.vy = 0;
this.jumping = false;
}
}
},
jump() {
if (!this.jumping) {
this.jumping = true;
this.vy = -12;
}
}
};
class Obstacle {
constructor() {
this.width = 20 + Math.random() * 20;
this.height = 30 + Math.random() * 40;
this.x = canvas.width;
this.y = 200 - this.height;
}
draw() {
ctx.fillStyle = "#666";
ctx.fillRect(this.x, this.y, this.width, this.height);
}
update() {
this.x -= gameSpeed;
}
}
let obstacles = [];
let spawnTimer = 0;
let score = 0;
let gameOver = false;
function resetGame() {
obstacles = [];
spawnTimer = 0;
score = 0;
gameSpeed = 6;
dino.y = 150;
dino.vy = 0;
dino.jumping = false;
gameOver = false;
loop();
}
function loop() {
if (gameOver) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
dino.update();
dino.draw();
if (spawnTimer <= 0) {
obstacles.push(new Obstacle());
spawnTimer = 60 + Math.random() * 40;
} else {
spawnTimer--;
}
for (let i = 0; i < obstacles.length; i++) {
const o = obstacles[i];
o.update();
o.draw();
// colisão
if (
dino.x < o.x + o.width &&
dino.x + dino.width > o.x &&
dino.y < o.y + o.height &&
dino.y + dino.height > o.y
) {
gameOver = true;
alert("Game Over! Score: " + Math.floor(score));
resetGame();
return;
}
// remove obstáculos fora da tela
if (o.x + o.width < 0) {
obstacles.splice(i, 1);
i--;
}
}
score += 0.1;
gameSpeed += 0.001;
// desenha o chão
ctx.fillStyle = "#888";
ctx.fillRect(0, 190, canvas.width, 2);
// score
ctx.fillStyle = "#000";
ctx.font = "16px monospace";
ctx.fillText("Score: " + Math.floor(score), 10, 20);
requestAnimationFrame(loop);
}
document.addEventListener("keydown", (e) => {
if (e.code === "Space" || e.code === "ArrowUp") dino.jump();
});
loop();
</script>
</body>
</html>
