<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <title>Breakout</title> <style> body { display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: linear-gradient(to bottom, #b0e0e6, #a0a0a0); font-family: 'Press Start 2P', cursive; color: #333; text-align: center; } #gameContainer { display: flex; flex-direction: column; align-items: center; background: rgba(200, 200, 200, 0.8); padding: 20px; border-radius: 10px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5); } h1 { font-size: 2em; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); margin-bottom: 20px; } canvas { border: 2px solid #fff; border-radius: 10px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); background: radial-gradient(ellipse at center, #70ffff, transparent), radial-gradient(ellipse at bottom, #ffffff, transparent); } #scoreboard { display: flex; justify-content: space-around; width: 100%; margin: 20px 0; } .score-item { font-size: 0.8em; margin: 0 5px; } .score-item span { margin-left: 2px; } button { font-family: 'Press Start 2P', cursive; font-size: 1em; padding: 10px 20px; margin-top: 10px; border: none; border-radius: 5px; background: #0095DD; color: #fff; cursor: pointer; transition: background 0.3s; } button:hover { background: #007bb5; } </style> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet"> </head> <body style="overflow: hidden"> <div id="gameContainer"> <h1>Breakout</h1> <canvas id="myCanvas" width="480" height="320"></canvas> <div id="scoreboard"> <div id="lives" class="score-item">Vidas:<span id="livesCount">5</span></div> <div id="score" class="score-item">Puntuación:<span id="scoreCount">0</span></div> <div id="level" class="score-item">Fase:<span id="levelCount">1</span></div> </div> <div id="livesSelectContainer"> <label for="livesSelect">Selecciona el número de vidas:</label> <select id="livesSelect"> <!-- Opciones para seleccionar entre 1 y 10 vidas --> <!-- Usar un bucle for para generar las opciones --> <!-- Asegurarse de que la opción seleccionada por defecto sea 5 --> </select> </div> <button id="startGameButton" onclick="startGame()">Iniciar Juego</button> <button id="restartButton" onclick="restartGame()" style="display: none;">Jugar Otra Vez</button> </div> <script> let canvas = document.getElementById("myCanvas"); let ctx = canvas.getContext("2d"); let ballRadius = 10; let x, y, dx, dy, paddleHeight, paddleWidth, paddleX, rightPressed, leftPressed, bricks, score, lives, level, running, ballLaunched; let lifeLostPause = false; let spaceKeyEnabled = true; const brickRowCount = 5; const brickColumnCount = 8; const brickWidth = 45; const brickHeight = 20; const brickPadding = 10; const brickOffsetTop = 30; const brickOffsetLeft = (canvas.width - (brickColumnCount * (brickWidth + brickPadding))) / 2; const initialBallSpeed = 1; const speedIncrement = 0; // Incremento de velocidad tras cada fase function getRandomColor() { const letters = '0123456789ABCDEF'; let color = '#'; for (let i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } return color; } function initBricks() { bricks = []; for (let c = 0; c < brickColumnCount; c++) { bricks[c] = []; for (let r = 0; r < brickRowCount; r++) { let brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft; let brickY = (r * (brickHeight + brickPadding)) + brickOffsetTop; let brickColor = getRandomColor(); bricks[c][r] = { x: brickX, y: brickY, status: 1, color: brickColor }; } } } function initGame() { x = canvas.width / 2; y = canvas.height - 30 - ballRadius; dx = initialBallSpeed; dy = -initialBallSpeed; paddleHeight = 10; paddleWidth = 75; paddleX = (canvas.width - paddleWidth) / 2; rightPressed = false; leftPressed = false; ballLaunched = false; bricks = []; initBricks(); score = 0; lives = 5; level = 1; running = false; updateScoreboard(); draw(); } function startGame() { let gameOverText = document.getElementById("gameOverText"); if (gameOverText) { gameOverText.remove(); } document.getElementById("restartButton").style.display = "none"; // Ocultar el botón "Jugar Otra Vez" initGame(); document.addEventListener("keydown", keyDownHandler, false); document.addEventListener("keyup", keyUpHandler, false); document.addEventListener("keydown", spaceKeyHandler, false); document.getElementById("startGameButton").style.display = "none"; // Obtener el número de vidas seleccionado let livesSelect = document.getElementById("livesSelect"); lives = parseInt(livesSelect.value); // Ocultar el control de selección de vidas después de iniciar el juego document.getElementById("livesSelectContainer").style.display = "none"; updateScoreboard(); // Actualizar el marcador de vidas en la pantalla running = true; draw(); } function confirmLives() { // Obtener el número de vidas seleccionado let livesSelect = document.getElementById("livesSelect"); lives = parseInt(livesSelect.value); updateScoreboard(); // Actualizar el marcador de vidas en la pantalla // Cambiar el texto del botón para indicar que el juego está listo para comenzar document.getElementById("startGameButton").textContent = "Continuar"; } function keyDownHandler(e) { if (lifeLostPause) return; // Agrega esta línea if (e.key == "Right" || e.key == "ArrowRight") { rightPressed = true; } else if (e.key == "Left" || e.key == "ArrowLeft") { leftPressed = true; } } function keyUpHandler(e) { if (lifeLostPause) return; // Agrega esta línea if (e.key == "Right" || e.key == "ArrowRight") { rightPressed = false; } else if (e.key == "Left" || e.key == "ArrowLeft") { leftPressed = false; } } function spaceKeyHandler(e) { if (e.key === " " && spaceKeyEnabled) { ballLaunched = true; running = true; draw(); } } function collisionDetection() { for (let c = 0; c < brickColumnCount; c++) { for (let r = 0; r < brickRowCount; r++) { let b = bricks[c][r]; if (b.status == 1) { if (x > b.x && x < b.x + brickWidth && y > b.y && y < b.y + brickHeight) { dy = -dy; b.status = 0; score++; if (score % 30 == 0) { lives++; displayLifeGain(); } updateScoreboard(); if (score == brickRowCount * brickColumnCount * level) { level++; updateScoreboard(); nextLevel(); } } } } } } function displayLifeGain() { let lifeGainText = document.createElement("div"); lifeGainText.textContent = "+1 Vida"; lifeGainText.style.position = "absolute"; lifeGainText.style.top = "60%"; lifeGainText.style.left = "50%"; lifeGainText.style.transform = "translate(-50%, -50%)"; lifeGainText.style.color = "green"; lifeGainText.style.fontSize = "2em"; lifeGainText.style.fontWeight = "bold"; lifeGainText.style.animation = "fadeInOut 2s"; document.body.appendChild(lifeGainText); setTimeout(() => { lifeGainText.remove(); }, 2000); } function displayLifeLoss() { let lifeLossText = document.createElement("div"); lifeLossText.textContent = "-1 Vida"; lifeLossText.style.position = "absolute"; lifeLossText.style.top = "60%"; lifeLossText.style.left = "50%"; lifeLossText.style.transform = "translate(-50%, -50%)"; lifeLossText.style.color = "red"; lifeLossText.style.fontSize = "2em"; lifeLossText.style.fontWeight = "bold"; lifeLossText.style.animation = "fadeInOut 2s"; document.body.appendChild(lifeLossText); setTimeout(() => { lifeLossText.remove(); if (lives > 0) { x = canvas.width / 2; y = canvas.height - 30 - ballRadius; dx = initialBallSpeed * level; // Velocidad inicial dy = -initialBallSpeed * level; // Velocidad inicial paddleX = (canvas.width - paddleWidth) / 2; ballLaunched = false; running = true; spaceKeyEnabled = true; // Habilitar la tecla espacio después de la pérdida de vida draw(); } else { displayGameOver(); running = false; // Detener el bucle de animación } }, 2000); } function displayGameOver() { let gameOverText = document.createElement("div"); gameOverText.id = "gameOverText"; gameOverText.textContent = "GAME OVER"; gameOverText.style.position = "absolute"; gameOverText.style.top = "62%"; gameOverText.style.left = "50%"; gameOverText.style.transform = "translate(-50%, -50%)"; gameOverText.style.color = "red"; gameOverText.style.fontSize = "3em"; gameOverText.style.fontWeight = "bold"; gameOverText.style.textShadow = "2px 2px 4px rgba(0, 0, 0, 0.5)"; document.body.appendChild(gameOverText); // Mostrar el botón "Jugar Otra Vez" let restartButton = document.getElementById("restartButton"); restartButton.style.display = "block"; } function drawBall() { let gradient = ctx.createRadialGradient(x, y, ballRadius / 4, x, y, ballRadius); gradient.addColorStop(0, "#ff4b4b"); gradient.addColorStop(1, "#8b0000"); ctx.beginPath(); ctx.arc(x, y, ballRadius, 0, Math.PI * 2); ctx.fillStyle = gradient; ctx.fill(); ctx.closePath(); } function drawPaddle() { let gradient = ctx.createLinearGradient(paddleX, canvas.height - paddleHeight, paddleX + paddleWidth, canvas.height); gradient.addColorStop(0, "#0095DD"); gradient.addColorStop(1, "#004f7a"); ctx.beginPath(); ctx.roundRect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight, 5); ctx.fillStyle = gradient; ctx.fill(); ctx.lineWidth = 0; ctx.strokeStyle = "#00000000"; ctx.stroke(); ctx.closePath(); } function drawBricks() { for (let c = 0; c < brickColumnCount; c++) { for (let r = 0; r < brickRowCount; r++) { if (bricks[c][r].status == 1) { let brickX = bricks[c][r].x; let brickY = bricks[c][r].y; let brickColor = bricks[c][r].color; let gradient = ctx.createRadialGradient(brickX + brickWidth / 2, brickY + brickHeight / 2, brickWidth / 4, brickX + brickWidth / 2, brickY + brickHeight / 2, brickWidth); gradient.addColorStop(0, brickColor); gradient.addColorStop(1, "#000000"); ctx.beginPath(); ctx.roundRect(brickX, brickY, brickWidth, brickHeight, 5); ctx.fillStyle = gradient; ctx.fill(); ctx.lineWidth = 0; ctx.strokeStyle = "#00000000"; ctx.stroke(); ctx.closePath(); } } } } function draw() { if (!running) { return; } ctx.clearRect(0, 0, canvas.width, canvas.height); drawBricks(); drawBall(); drawPaddle(); collisionDetection(); if (!ballLaunched) { x = paddleX + paddleWidth / 2; y = canvas.height - paddleHeight - ballRadius; ctx.font = "16px 'Press Start 2P'"; ctx.fillStyle = "#0095DD"; ctx.fillText("Presiona Espacio para lanzar", 20, canvas.height - 60); spaceKeyEnabled = true; // Habilitar la tecla espacio cuando la bola no está lanzada } else { x += dx; y += dy; spaceKeyEnabled = false; // Deshabilitar la tecla espacio cuando la bola está en movimiento if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) { dx = -dx; } if (y + dy < ballRadius) { dy = -dy; } else if (y + dy > canvas.height - ballRadius) { if (x > paddleX && x < paddleX + paddleWidth) { dy = -dy; } else { lives--; if (!lives) { displayGameOver(); // Llamar a displayGameOver en lugar de alert running = false; // Detener el juego } else { updateScoreboard(); displayLifeLoss(); running = false; return; } } } } if (rightPressed && paddleX < canvas.width - paddleWidth) { paddleX += 7; } else if (leftPressed && paddleX > 0) { paddleX -= 7; } requestAnimationFrame(draw); } function updateScoreboard() { document.getElementById("livesCount").textContent = lives; document.getElementById("scoreCount").textContent = score; document.getElementById("levelCount").textContent = level; } function nextLevel() { initBricks(); x = canvas.width / 2; y = canvas.height - 30; // Reducir el incremento de velocidad let levelSpeedIncrement = 0; // Cambia este valor según tus necesidades // Ajustar la velocidad de la bola con un incremento menor dx = (initialBallSpeed + (speedIncrement * (level - 1) * levelSpeedIncrement)) * Math.sign(dx); dy = -(initialBallSpeed + (speedIncrement * (level - 1) * levelSpeedIncrement)) * Math.sign(dy); paddleX = (canvas.width - paddleWidth) / 2; ballLaunched = false; spaceKeyEnabled = true; // Habilitar la tecla espacio para el nuevo nivel } function displayGameOver() { let gameOverText = document.createElement("div"); gameOverText.id = "gameOverText"; gameOverText.textContent = "GAME OVER"; gameOverText.style.position = "absolute"; gameOverText.style.top = "62%"; gameOverText.style.left = "50%"; gameOverText.style.transform = "translate(-50%, -50%)"; gameOverText.style.color = "red"; gameOverText.style.fontSize = "3em"; gameOverText.style.fontWeight = "bold"; gameOverText.style.textShadow = "2px 2px 4px rgba(0, 0, 0, 0.5)"; document.body.appendChild(gameOverText); // Mostrar el botón "Jugar Otra Vez" let restartButton = document.getElementById("restartButton"); restartButton.style.display = "block"; // Actualizar el marcador de vidas document.getElementById("livesCount").textContent = "0"; } function restartGame() { // Mostrar el selector del número de vidas nuevamente document.getElementById("livesSelectContainer").style.display = "block"; // Mostrar el botón "Iniciar Juego" y ocultar el botón "Jugar Otra Vez" document.getElementById("startGameButton").style.display = "inline-block"; document.getElementById("restartButton").style.display = "none"; // Eliminar cualquier texto de "Game Over" que pueda estar presente let gameOverText = document.getElementById("gameOverText"); if (gameOverText) { gameOverText.remove(); } // Reiniciar el juego initGame(); // Agregar event listeners para el teclado document.addEventListener("keydown", keyDownHandler, false); document.addEventListener("keyup", keyUpHandler, false); document.addEventListener("keydown", spaceKeyHandler, false); } CanvasRenderingContext2D.prototype.roundRect = function (x, y, width, height, radius) { if (width < 2 * radius) radius = width / 2; if (height < 2 * radius) radius = height / 2; this.beginPath(); this.moveTo(x + radius, y); this.arcTo(x + width, y, x + width, y + height, radius); this.arcTo(x + width, y + height, x, y + height, radius); this.arcTo(x, y + height, x, y, radius); this.arcTo(x, y, x + width, y, radius); this.closePath(); return this; }; initGame(); let livesSelect = document.getElementById("livesSelect"); // Generar las opciones del control de selección de vidas for (let i = 1; i <= 10; i++) { let option = document.createElement("option"); option.value = i; option.textContent = i + " vidas"; if (i === 5) { option.selected = true; // Seleccionar 5 vidas por defecto } livesSelect.appendChild(option); } </script> </body> </html>