SnakePong es una emocionante combinación de dos clásicos juegos: Snake y Pong. Esta fusión ofrece una experiencia de juego única, desafiante y altamente adictiva. En este artículo, te guiaré a través de los pasos para crear tu propio SnakePong utilizando HTML, CSS y JavaScript.
1. Estructura HTML:
Comenzaremos creando la estructura básica del juego en HTML. Necesitaremos un lienzo de juego y algunos elementos adicionales para controlar el juego.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Day #59 - Snake Pong | AsmrProg</title>
</head>
<body>
<div class="score-container">
<div>Score : <span id="current-score">0</span></div>
<div>High Score : <span id="high-score">0</span></div>
</div>
<canvas id="gameCanvas" width="420" height="420"></canvas>
<div id="game-over">
Game Over!
<button id="restart-btn">Restart Game</button>
</div>
<script src="script.js"></script>
</body>
</html>
2. Estilos CSS:
Agreguemos algunos estilos básicos para hacer que nuestro juego se vea atractivo y sea fácil de jugar.
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
body{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #333;
color: #fff;
overflow: hidden;
font-family: 'Poppins',sans-serif;
}
canvas{
border: 2px solid #fff;
}
.score-container{
display: flex;
justify-content: space-between;
width: 420px;
font-size: 18px;
}
#restart-btn{
margin-top: 15px;
padding: 10px 15px;
background-color: #f4f4f4;
border: none;
cursor: pointer;
transition: all 0.3s ease;
}
#game-over{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.8);
padding: 20px;
color: #fff;
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
}
3. Lógica del Juego en JavaScript:
Ahora, vamos a implementar la lógica del juego utilizando JavaScript.
const canvas = document.getElementById('gameCanvas');
const context = canvas.getContext('2d');
const gameOverScreen = document.getElementById('game-over');
const restartBtn = document.getElementById('restart-btn');
const GRID_SIZE = 20;
const SNAKE_SIZE = GRID_SIZE;
const FOOD_SIZE = GRID_SIZE;
let snake, food, dx, dy, blinkCounter;
let gamePaused = false;
let score = 0;
let highScore = localStorage.getItem('highScore') || 0;
let currentScoreElem = document.getElementById('current-score');
let highScoreElem = document.getElementById('high-score');
// Initialize game state
function initializeGame() {
// Set initial snake segments
snake = [
{ x: Math.floor(canvas.width / 2 / GRID_SIZE) * GRID_SIZE, y: Math.floor(canvas.height / 2 / GRID_SIZE) * GRID_SIZE },
{ x: Math.floor(canvas.width / 2 / GRID_SIZE) * GRID_SIZE, y: (Math.floor(canvas.height / 2 / GRID_SIZE) + 1) * GRID_SIZE },
];
// Set the initial food position and direction
food = {
...generateFoodPosition(),
dx: (Math.random() < 0.5 ? 1 : -1) * GRID_SIZE,
dy: (Math.random() < 0.5 ? 1 : -1) * GRID_SIZE
};
// Set initial snake direction
dx = 0;
dy = -GRID_SIZE;
blinkCounter = 0;
score = 0;
currentScoreElem.textContent = score;
highScoreElem.textContent = highScore;
}
initializeGame();
// Handle keyboard inputs for snake movement
document.addEventListener('keydown', function (event) {
switch (event.key) {
case 'ArrowUp':
if (dy === 0) {
dx = 0;
dy = -GRID_SIZE;
}
break;
case 'ArrowDown':
if (dy === 0) {
dx = 0;
dy = GRID_SIZE;
}
break;
case 'ArrowLeft':
if (dx === 0) {
dx = -GRID_SIZE;
dy = 0;
}
break;
case 'ArrowRight':
if (dx === 0) {
dx = GRID_SIZE;
dy = 0;
}
break;
}
});
// Generate a food position that doesn't collide with the snake
function generateFoodPosition() {
while (true) {
let newFoodPosition = {
x: Math.floor(Math.random() * canvas.width / GRID_SIZE) * GRID_SIZE,
y: Math.floor(Math.random() * canvas.height / GRID_SIZE) * GRID_SIZE
};
let collisionWithSnake = false;
for (let segment of snake) {
if (segment.x === newFoodPosition.x && segment.y === newFoodPosition.y) {
collisionWithSnake = true;
break;
}
}
// Return the position if there is no collision
if (!collisionWithSnake) {
return newFoodPosition;
}
}
}
// Check for collisions with wall or self
function checkCollision() {
if (snake[0].x < 0 || snake[0].x >= canvas.width || snake[0].y < 0 || snake[0].y >= canvas.height) {
return true;
}
for (let i = 1; i < snake.length; i++) {
if (snake[i].x === snake[0].x && snake[i].y === snake[0].y) {
return true;
}
}
return false;
}
// Main game update function
function update() {
if (gamePaused) return;
// Calculate new snake head position
const head = { x: snake[0].x + dx, y: snake[0].y + dy };
snake.unshift(head);
// Check for collisions
if (checkCollision()) {
if (score > highScore) {
highScore = score;
localStorage.setItem('highScore', highScore);
highScoreElem.textContent = highScore;
}
gameOver();
return;
}
// Check for snake eating food
if (head.x === food.x && head.y === food.y) {
score++;
currentScoreElem.textContent = score;
food = {
...generateFoodPosition(),
dx: (Math.random() < 0.5 ? 1 : -1) * GRID_SIZE,
dy: (Math.random() < 0.5 ? 1 : -1) * GRID_SIZE
};
// Check for win condition (snake fills entire screen)
if (snake.length === (canvas.width / GRID_SIZE) * (canvas.height / GRID_SIZE)) {
gameWin();
return;
}
} else {
snake.pop(); // Remove tail segment
}
// Update food position
if (blinkCounter % 4 === 0) {
food.x += food.dx;
food.y += food.dy;
// Handle food collisions with wall
if (food.x < 0) {
food.dx = -food.dx;
food.x = 0;
}
if (food.x >= canvas.width) {
food.dx = -food.dx;
food.x = canvas.width - GRID_SIZE;
}
if (food.y < 0) {
food.dy = -food.dy;
food.y = 0;
}
if (food.y >= canvas.height) {
food.dy = -food.dy;
food.y = canvas.height - GRID_SIZE;
}
}
blinkCounter++;
draw(); // Draw the game objects
}
// Draw the background grid
function drawGrid() {
context.strokeStyle = "#AAA";
for (let i = 0; i < canvas.width; i += GRID_SIZE) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, canvas.height);
context.stroke();
}
for (let j = 0; j < canvas.height; j += GRID_SIZE) {
context.beginPath();
context.moveTo(0, j);
context.lineTo(canvas.width, j);
context.stroke();
}
}
// Draw game objects (snake and food)
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
drawGrid();
for (const segment of snake) {
context.fillStyle = 'green';
context.fillRect(segment.x, segment.y, SNAKE_SIZE, SNAKE_SIZE);
}
context.fillStyle = 'red';
context.fillRect(food.x, food.y, FOOD_SIZE, FOOD_SIZE);
}
// Handle game over state
function gameOver() {
gamePaused = true;
gameOverScreen.style.display = 'flex';
}
// Handle game win state
function gameWin() {
gamePaused = true;
alert("Congratulations! You won!");
initializeGame();
}
// Restart game when restart button clicked
restartBtn.addEventListener('click', function () {
gameOverScreen.style.display = 'none';
gamePaused = false;
initializeGame();
update();
});
// Call update function every 100ms
setInterval(update, 100);
// Pause the game when window loses focus
window.addEventListener('blur', function () {
gamePaused = true;
});
// Resume the game when window gains focus
window.addEventListener('focus', function () {
gamePaused = false;
update();
});
Conclusión: ¡Felicidades! Ahora tienes las bases para crear tu propio juego de SnakePong. Puedes personalizarlo añadiendo características adicionales como niveles de dificultad, sonidos o incluso gráficos más avanzados. ¡Diviértete desarrollando y jugando SnakePong!
AQUÍ PUEDES VER EL RESULTADO DEL JUEGO YA TERMINADO
Desarrollado por: CRSITHIAN WEB