Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Neon Mutation Breakout - AI Edition</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| body { | |
| margin: 0; | |
| overflow: hidden; | |
| background-color: #0f172a; | |
| font-family: 'Courier New', monospace; | |
| } | |
| canvas { | |
| display: block; | |
| } | |
| .status-panel { | |
| position: absolute; | |
| top: 20px; | |
| right: 20px; | |
| width: 300px; | |
| background: rgba(15, 23, 42, 0.8); | |
| border: 2px solid #4f46e5; | |
| border-radius: 8px; | |
| padding: 15px; | |
| color: #e2e8f0; | |
| font-size: 14px; | |
| box-shadow: 0 0 20px #4f46e5; | |
| max-height: 80vh; | |
| overflow-y: auto; | |
| } | |
| .mutation-event { | |
| margin-bottom: 10px; | |
| padding-bottom: 10px; | |
| border-bottom: 1px solid #334155; | |
| animation: pulse 0.5s; | |
| } | |
| @keyframes pulse { | |
| 0% { background-color: rgba(79, 70, 229, 0); } | |
| 50% { background-color: rgba(79, 70, 229, 0.3); } | |
| 100% { background-color rgba(79, 70, 229, 0); } | |
| } | |
| .mutation-positive { | |
| color: #4ade80; | |
| } | |
| .mutation-negative { | |
| color: #f87171; | |
| } | |
| .mutation-neutral { | |
| color: #60a5fa; | |
| } | |
| .title { | |
| position: absolute; | |
| top: 20px; | |
| left: 20px; | |
| color: #e2e8f0; | |
| font-size: 24px; | |
| text-shadow: 0 0 10px #4f46e5; | |
| } | |
| .score { | |
| position: absolute; | |
| top: 60px; | |
| left: 20px; | |
| color: #e2e8f0; | |
| font-size: 18px; | |
| text-shadow: 0 0 5px #4f46e5; | |
| } | |
| .game-over { | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| background: rgba(15, 23, 42, 0.9); | |
| border: 2px solid #4f46e5; | |
| border-radius: 8px; | |
| padding: 30px; | |
| color: #e2e8f0; | |
| text-align: center; | |
| box-shadow: 0 0 30px #4f46e5; | |
| display: none; | |
| } | |
| .restart-btn { | |
| background: #4f46e5; | |
| color: white; | |
| border: none; | |
| padding: 10px 20px; | |
| margin-top: 20px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| font-family: 'Courier New', monospace; | |
| font-size: 16px; | |
| transition: all 0.3s; | |
| } | |
| .restart-btn:hover { | |
| background: #6366f1; | |
| transform: scale(1.05); | |
| } | |
| .speed-indicator { | |
| position: absolute; | |
| bottom: 20px; | |
| left: 20px; | |
| color: #e2e8f0; | |
| font-size: 14px; | |
| } | |
| .speed-bar { | |
| height: 5px; | |
| background: linear-gradient(90deg, #4f46e5, #ec4899); | |
| margin-top: 5px; | |
| border-radius: 5px; | |
| } | |
| .ai-controls { | |
| position: absolute; | |
| bottom: 20px; | |
| right: 20px; | |
| display: flex; | |
| gap: 10px; | |
| } | |
| .ai-btn { | |
| background: rgba(79, 70, 229, 0.7); | |
| color: white; | |
| border: none; | |
| width: 60px; | |
| height: 60px; | |
| border-radius: 50%; | |
| font-size: 24px; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| box-shadow: 0 0 10px #4f46e5; | |
| } | |
| .ai-btn:hover { | |
| background: rgba(79, 70, 229, 1); | |
| transform: scale(1.1); | |
| } | |
| .ai-btn:active { | |
| transform: scale(0.95); | |
| } | |
| .ai-mode { | |
| position: absolute; | |
| top: 100px; | |
| left: 20px; | |
| color: #e2e8f0; | |
| font-size: 14px; | |
| } | |
| .ai-learning { | |
| position: absolute; | |
| top: 120px; | |
| left: 20px; | |
| color: #e2e8f0; | |
| font-size: 14px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="title">NEON MUTATION BREAKOUT - PERFECT AI</div> | |
| <div class="score">SCORE: <span id="score">0</span></div> | |
| <div class="ai-mode">AI MODE: <span id="ai-mode">PERFECT</span></div> | |
| <div class="ai-learning">AI LEARNING RATE: <span id="ai-learning">100%</span></div> | |
| <div class="speed-indicator"> | |
| GAME SPEED: <span id="speed">1.0x</span> | |
| <div class="speed-bar" id="speed-bar"></div> | |
| </div> | |
| <div class="status-panel"> | |
| <h3 class="text-lg font-bold mb-4 text-center border-b border-indigo-500 pb-2">MUTATION EVENTS</h3> | |
| <div id="mutation-log"></div> | |
| </div> | |
| <div class="game-over" id="game-over"> | |
| <h2 class="text-2xl font-bold mb-4">LEVEL COMPLETE</h2> | |
| <p>Final Score: <span id="final-score">0</span></p> | |
| <p>Mutations Achieved: <span id="mutation-count">0</span></p> | |
| <p>AI Mastery: <span id="ai-mastery">100%</span></p> | |
| <button class="restart-btn" id="restart-btn">NEXT LEVEL</button> | |
| </div> | |
| <div class="ai-controls"> | |
| <button class="ai-btn" id="ai-train-btn">🧠</button> | |
| <button class="ai-btn" id="ai-play-btn">🤖</button> | |
| </div> | |
| <canvas id="gameCanvas"></canvas> | |
| <script> | |
| // Game canvas setup | |
| const canvas = document.getElementById('gameCanvas'); | |
| const ctx = canvas.getContext('2d'); | |
| canvas.width = window.innerWidth; | |
| canvas.height = window.innerHeight; | |
| // Game state | |
| let gameRunning = true; | |
| let score = 0; | |
| let gameSpeed = 1.0; | |
| let speedIncreaseTimer = 0; | |
| let mutationCount = 0; | |
| let lastMutationTime = 0; | |
| // AI state | |
| let aiMode = 'PERFECT'; // 'LEARNING' or 'PLAYING' or 'PERFECT' | |
| let aiLearningRate = 1.0; | |
| let aiMastery = 1.0; | |
| let aiMemory = []; | |
| let aiDecisionThreshold = 1.0; | |
| // Paddle | |
| const paddle = { | |
| width: 100, | |
| height: 15, | |
| x: canvas.width / 2 - 50, | |
| y: canvas.height - 30, | |
| speed: 15, | |
| color: '#4f46e5' | |
| }; | |
| // Ball | |
| const ball = { | |
| radius: 10, | |
| x: canvas.width / 2, | |
| y: canvas.height / 2, | |
| dx: 5 * gameSpeed, | |
| dy: -5 * gameSpeed, | |
| color: '#ec4899', | |
| speed: 5 | |
| }; | |
| // Bricks | |
| const brick = { | |
| rowCount: 5, | |
| columnCount: 10, | |
| width: 75, | |
| height: 20, | |
| padding: 10, | |
| offsetTop: 60, | |
| offsetLeft: 30, | |
| colors: ['#4f46e5', '#6366f1', '#818cf8', '#a5b4fc', '#c7d2fe'] | |
| }; | |
| let bricks = []; | |
| function initBricks() { | |
| bricks = []; | |
| for (let c = 0; c < brick.columnCount; c++) { | |
| bricks[c] = []; | |
| for (let r = 0; r < brick.rowCount; r++) { | |
| bricks[c][r] = { x: 0, y: 0, status: 1, color: brick.colors[r] }; | |
| } | |
| } | |
| } | |
| // Mutation effects | |
| const mutations = { | |
| paddleWiden: { name: "Paddle Widened", effect: () => { paddle.width += 20; }, type: "positive" }, | |
| paddleNarrow: { name: "Paddle Narrowed", effect: () => { paddle.width = Math.max(60, paddle.width - 20); }, type: "negative" }, | |
| ballSpeedUp: { name: "Ball Speed Increased", effect: () => { ball.speed += 1; updateBallSpeed(); }, type: "neutral" }, | |
| ballSpeedDown: { name: "Ball Speed Decreased", effect: () => { ball.speed = Math.max(3, ball.speed - 1); updateBallSpeed(); }, type: "neutral" }, | |
| multiBall: { name: "Multi-Ball!", effect: () => { createExtraBall(); }, type: "positive" }, | |
| gameSpeedUp: { name: "Game Speed Increased", effect: () => { gameSpeed = Math.min(3.0, gameSpeed + 0.2); updateSpeedDisplay(); }, type: "neutral" }, | |
| gameSpeedDown: { name: "Game Speed Decreased", effect: () => { gameSpeed = Math.max(0.8, gameSpeed - 0.2); updateSpeedDisplay(); }, type: "neutral" }, | |
| paddleSpeedUp: { name: "Paddle Speed Increased", effect: () => { paddle.speed += 2; }, type: "positive" }, | |
| paddleSpeedDown: { name: "Paddle Speed Decreased", effect: () => { paddle.speed = Math.max(5, paddle.speed - 2; }, type: "negative" }, | |
| aiLearningBoost: { name: "AI Learning Boost", effect: () => { aiLearningRate = Math.min(1, aiLearningRate + 0.1); updateAIDisplay(); }, type: "positive" }, | |
| aiForget: { name: "AI Memory Reset", effect: () => { aiMemory = []; aiLearningRate = Math.max(0, aiLearningRate - 0.2); updateAIDisplay(); }, type: "negative" } | |
| }; | |
| let extraBalls = []; | |
| function createExtraBall() { | |
| extraBalls.push({ | |
| radius: 10, | |
| x: ball.x, | |
| y: ball.y, | |
| dx: (Math.random() > 0.5 ? 1 : -1) * ball.speed * gameSpeed, | |
| dy: -ball.speed * gameSpeed, | |
| color: `hsl(${Math.random() * 360}, 100%, 70%)` | |
| }); | |
| } | |
| // AI functions - PERFECT VERSION | |
| function makeAIDecision() { | |
| if (aiMode !== 'PERFECT' && aiMode !== 'PLAYING') return; | |
| // Perfect prediction of ball's position | |
| const prediction = perfectBallPrediction(); | |
| // Move paddle to intercept the ball perfectly | |
| const paddleCenter = paddle.x + paddle.width / 2; | |
| const targetX = prediction - paddle.width / 2; | |
| // Smooth movement to target position | |
| if (targetX > paddle.x + 5) { | |
| paddle.x = Math.min(targetX, paddle.x + paddle.speed * gameSpeed); | |
| } else if (targetX < paddle.x - 5) { | |
| paddle.x = Math.max(targetX, paddle.x - paddle.speed * gameSpeed); | |
| } | |
| } | |
| function perfectBallPrediction() { | |
| // Simulate ball's path perfectly | |
| let simX = ball.x; | |
| let simY = ball.y; | |
| let simDX = ball.dx; | |
| let simDY = ball.dy; | |
| while (simY < paddle.y) { | |
| // Move ball | |
| simX += simDX; | |
| simY += simDY; | |
| // Check wall collisions | |
| if (simX < ball.radius || simX > canvas.width - ball.radius) { | |
| simDX = -simDX; | |
| } | |
| // Check ceiling collision | |
| if (simY < ball.radius) { | |
| simDY = -simDY; | |
| } | |
| // Check brick collisions | |
| for (let c = 0; c < brick.columnCount; c++) { | |
| for (let r = 0; r < brick.rowCount; r++) { | |
| const b = bricks[c][r]; | |
| if (b.status === 1) { | |
| if (simX > b.x && simX < b.x + brick.width && | |
| simY > b.y && simY < b.y + brick.height) { | |
| simDY = -simDY; | |
| // Don't actually break the brick in simulation | |
| } | |
| } | |
| } | |
| } | |
| } | |
| // Return predicted X position at paddle level | |
| return Math.max(ball.radius, Math.min(canvas.width - ball.radius, simX)); | |
| } | |
| function updateAIDisplay() { | |
| document.getElementById('ai-mode').textContent = aiMode; | |
| document.getElementById('ai-learning').textContent = `${Math.floor(aiLearningRate * 100)}%`; | |
| } | |
| // Input handling | |
| let rightPressed = false; | |
| let leftPressed = false; | |
| document.addEventListener('keydown', keyDownHandler); | |
| document.addEventListener('keyup', keyUpHandler); | |
| document.addEventListener('mousemove', mouseMoveHandler); | |
| // AI control buttons | |
| document.getElementById('ai-train-btn').addEventListener('click', () => { | |
| aiMode = 'LEARNING'; | |
| updateAIDisplay(); | |
| }); | |
| document.getElementById('ai-play-btn').addEventListener('click', () => { | |
| aiMode = 'PERFECT'; | |
| updateAIDisplay(); | |
| }); | |
| function keyDownHandler(e) { | |
| if (e.key === 'Right' || e.key === 'ArrowRight') { | |
| rightPressed = true; | |
| } else if (e.key === 'Left' || e.key === 'ArrowLeft') { | |
| leftPressed = true; | |
| } | |
| } | |
| function keyUpHandler(e) { | |
| if (e.key === 'Right' || e.key === 'ArrowRight') { | |
| rightPressed = false; | |
| } else if (e.key === 'Left' || e.key === 'ArrowLeft') { | |
| leftPressed = false; | |
| } | |
| } | |
| function mouseMoveHandler(e) { | |
| if (aiMode === 'PERFECT') return; | |
| const relativeX = e.clientX - canvas.offsetLeft; | |
| if (relativeX > paddle.width / 2 && relativeX < canvas.width - paddle.width / 2) { | |
| paddle.x = relativeX - paddle.width / 2; | |
| } | |
| } | |
| // Collision detection | |
| function collisionDetection() { | |
| for (let c = 0; c < brick.columnCount; c++) { | |
| for (let r = 0; r < brick.rowCount; r++) { | |
| const b = bricks[c][r]; | |
| if (b.status === 1) { | |
| if ( | |
| ball.x > b.x && | |
| ball.x < b.x + brick.width && | |
| ball.y > b.y && | |
| ball.y < b.y + brick.height | |
| ) { | |
| ball.dy = -ball.dy; | |
| b.status = 0; | |
| score += 10 * gameSpeed; | |
| document.getElementById('score').textContent = Math.floor(score); | |
| // Chance to trigger mutation when hitting a brick | |
| if (Math.random() < 0.1 && Date.now() - lastMutationTime > 5000) { | |
| triggerRandomMutation(); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| function triggerRandomMutation() { | |
| lastMutationTime = Date.now(); | |
| mutationCount++; | |
| // Get random mutation | |
| const mutationKeys = Object.keys(mutations); | |
| const randomKey = mutationKeys[Math.floor(Math.random() * mutationKeys.length)]; | |
| const mutation = mutations[randomKey]; | |
| // Apply mutation effect | |
| mutation.effect(); | |
| // Log mutation | |
| logMutation(mutation.name, mutation.type); | |
| } | |
| function logMutation(name, type) { | |
| const logElement = document.createElement('div'); | |
| logElement.className = `mutation-event mutation-${type}`; | |
| const time = new Date().toLocaleTimeString(); | |
| logElement.innerHTML = `<strong>${time}</strong>: ${name}`; | |
| const logContainer = document.getElementById('mutation-log'); | |
| logContainer.insertBefore(logElement, logContainer.firstChild); | |
| // Keep log from growing too large | |
| if (logContainer.children.length > 20) { | |
| logContainer.removeChild(logContainer.lastChild); | |
| } | |
| // Highlight new event | |
| logElement.style.animation = 'pulse 1s'; | |
| setTimeout(() => { | |
| logElement.style.animation = ''; | |
| }, 1000); | |
| } | |
| // Game functions | |
| function updateBallSpeed() { | |
| const directionX = ball.dx > 0 ? 1 : -1; | |
| const directionY = ball.dy > 0 ? 1 : -1; | |
| ball.dx = directionX * ball.speed * gameSpeed; | |
| ball.dy = directionY * ball.speed * gameSpeed; | |
| } | |
| function updateSpeedDisplay() { | |
| document.getElementById('speed').textContent = gameSpeed.toFixed(1) + 'x'; | |
| document.getElementById('speed-bar').style.width = `${(gameSpeed / 3) * 100}%`; | |
| } | |
| function drawBall(ballObj) { | |
| ctx.beginPath(); | |
| ctx.arc(ballObj.x, ballObj.y, ballObj.radius, 0, Math.PI * 2); | |
| ctx.fillStyle = ballObj.color; | |
| ctx.fill(); | |
| ctx.closePath(); | |
| // Glow effect | |
| ctx.shadowBlur = 15; | |
| ctx.shadowColor = ballObj.color; | |
| ctx.fill(); | |
| ctx.shadowBlur = 0; | |
| } | |
| function drawPaddle() { | |
| ctx.beginPath(); | |
| ctx.rect(paddle.x, paddle.y, paddle.width, paddle.height); | |
| ctx.fillStyle = paddle.color; | |
| ctx.fill(); | |
| ctx.closePath(); | |
| // Glow effect | |
| ctx.shadowBlur = 20; | |
| ctx.shadowColor = paddle.color; | |
| ctx.fill(); | |
| ctx.shadowBlur = 0; | |
| } | |
| function drawBricks() { | |
| for (let c = 0; c < brick.columnCount; c++) { | |
| for (let r = 0; r < brick.rowCount; r++) { | |
| if (bricks[c][r].status === 1) { | |
| const brickX = c * (brick.width + brick.padding) + brick.offsetLeft; | |
| const brickY = r * (brick.height + brick.padding) + brick.offsetTop; | |
| bricks[c][r].x = brickX; | |
| bricks[c][r].y = brickY; | |
| ctx.beginPath(); | |
| ctx.rect(brickX, brickY, brick.width, brick.height); | |
| ctx.fillStyle = bricks[c][r].color; | |
| ctx.fill(); | |
| ctx.closePath(); | |
| // Glow effect | |
| ctx.shadowBlur = 10; | |
| ctx.shadowColor = bricks[c][r].color; | |
| ctx.fill(); | |
| ctx.shadowBlur = 0; | |
| } | |
| } | |
| } | |
| } | |
| function draw() { | |
| if (!gameRunning) return; | |
| // Clear canvas | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| // Draw game elements | |
| drawBricks(); | |
| drawBall(ball); | |
| for (const extraBall of extraBalls) { | |
| drawBall(extraBall); | |
| } | |
| drawPaddle(); | |
| // AI functions | |
| makeAIDecision(); | |
| // Collision detection | |
| collisionDetection(); | |
| // Wall collision (left/right) | |
| if (ball.x + ball.dx > canvas.width - ball.radius || ball.x + ball.dx < ball.radius) { | |
| ball.dx = -ball.dx; | |
| } | |
| // Wall collision (top) | |
| if (ball.y + ball.dy < ball.radius) { | |
| ball.dy = -ball.dy; | |
| } | |
| // Paddle collision | |
| if ( | |
| ball.y + ball.dy > canvas.height - ball.radius - paddle.height && | |
| ball.y + ball.dy < canvas.height - ball.radius && | |
| ball.x > paddle.x && | |
| ball.x < paddle.x + paddle.width | |
| ) { | |
| // Calculate bounce angle based on where ball hits paddle | |
| const hitPosition = (ball.x - (paddle.x + paddle.width / 2)) / (paddle.width / 2); | |
| const angle = hitPosition * Math.PI / 3; // Max 60 degree angle | |
| ball.dy = -Math.abs(ball.speed * gameSpeed * Math.cos(angle)); | |
| ball.dx = ball.speed * gameSpeed * Math.sin(angle); | |
| } | |
| // Extra balls paddle collision | |
| for (let i = 0; i < extraBalls.length; i++) { | |
| const eb = extraBalls[i]; | |
| if ( | |
| eb.y + eb.dy > canvas.height - eb.radius - paddle.height && | |
| eb.y + eb.dy < canvas.height - eb.radius && | |
| eb.x > paddle.x && | |
| eb.x < paddle.x + paddle.width | |
| ) { | |
| const hitPosition = (eb.x - (paddle.x + paddle.width / 2)) / (paddle.width / 2); | |
| const angle = hitPosition * Math.PI / 3; | |
| eb.dy = -Math.abs(eb.dy * Math.cos(angle)); | |
| eb.dx = eb.dx * Math.sin(angle); | |
| } | |
| // Extra balls wall collision | |
| if (eb.x + eb.dx > canvas.width - eb.radius || eb.x + eb.dx < eb.radius) { | |
| eb.dx = -eb.dx; | |
| } | |
| if (eb.y + eb.dy < eb.radius) { | |
| eb.dy = -eb.dy; | |
| } | |
| // Move extra balls | |
| eb.x += eb.dx; | |
| eb.y += eb.dy; | |
| // Remove extra balls that go out of bounds | |
| if (eb.y > canvas.height) { | |
| extraBalls.splice(i, 1); | |
| i--; | |
| } | |
| } | |
| // Game over check (should never happen with perfect AI) | |
| if (ball.y + ball.dy > canvas.height) { | |
| // Check if this is the last ball | |
| if (extraBalls.length === 0) { | |
| gameOver(); | |
| return; | |
| } else { | |
| // Remove main ball but keep playing with extra balls | |
| ball.y = -100; | |
| } | |
| } | |
| // Move ball | |
| ball.x += ball.dx; | |
| ball.y += ball.dy; | |
| // Move paddle (if not in AI PERFECT mode) | |
| if (aiMode !== 'PERFECT') { | |
| if (rightPressed && paddle.x < canvas.width - paddle.width) { | |
| paddle.x += paddle.speed * gameSpeed; | |
| } else if (leftPressed && paddle.x > 0) { | |
| paddle.x -= paddle.speed * gameSpeed; | |
| } | |
| } | |
| // Gradually increase game speed | |
| speedIncreaseTimer++; | |
| if (speedIncreaseTimer > 500 && gameSpeed < 3.0) { | |
| gameSpeed += 0.05; | |
| updateSpeedDisplay(); | |
| speedIncreaseTimer = 0; | |
| } | |
| // Check win condition | |
| let allBricksDestroyed = true; | |
| for (let c = 0; c < brick.columnCount; c++) { | |
| for (let r = 0; r < brick.rowCount; r++) { | |
| if (bricks[c][r].status === 1) { | |
| allBricksDestroyed = false; | |
| break; | |
| } | |
| } | |
| if (!allBricksDestroyed) break; | |
| } | |
| if (allBricksDestroyed) { | |
| // Level complete - reset with more bricks | |
| brick.rowCount = Math.min(8, brick.rowCount + 1); | |
| initBricks(); | |
| // Reset ball position | |
| ball.x = canvas.width / 2; | |
| ball.y = canvas.height / 2; | |
| ball.dx = 5 * gameSpeed; | |
| ball.dy = -5 * gameSpeed; | |
| // Bonus points for completing level | |
| score += 100 * gameSpeed; | |
| document.getElementById('score').textContent = Math.floor(score); | |
| // Higher chance for mutation after level complete | |
| if (Math.random() < 0.3) { | |
| triggerRandomMutation(); | |
| } | |
| } | |
| requestAnimationFrame(draw); | |
| } | |
| function gameOver() { | |
| gameRunning = false; | |
| document.getElementById('final-score').textContent = Math.floor(score); | |
| document.getElementById('mutation-count').textContent = mutationCount; | |
| document.getElementById('ai-mastery').textContent = `${Math.floor(aiLearningRate * 100)}%`; | |
| document.getElementById('game-over').style.display = 'block'; | |
| } | |
| function resetGame() { | |
| gameRunning = true; | |
| score = 0; | |
| gameSpeed = 1.0; | |
| speedIncreaseTimer = 0; | |
| mutationCount = 0; | |
| lastMutationTime = 0; | |
| extraBalls = []; | |
| // Reset AI | |
| aiLearningRate = 1.0; | |
| aiMemory = []; | |
| aiMode = 'PERFECT'; | |
| document.getElementById('score').textContent = '0'; | |
| document.getElementById('speed').textContent = '1.0x'; | |
| document.getElementById('speed-bar').style.width = '33.3%'; | |
| document.getElementById('game-over').style.display = 'none'; | |
| document.getElementById('mutation-log').innerHTML = ''; | |
| updateAIDisplay(); | |
| // Reset paddle | |
| paddle.width = 100; | |
| paddle.speed = 15; | |
| paddle.x = canvas.width / 2 - 50; | |
| // Reset ball | |
| ball.speed = 5; | |
| ball.x = canvas.width / 2; | |
| ball.y = canvas.height / 2; | |
| ball.dx = 5 * gameSpeed; | |
| ball.dy = -5 * gameSpeed; | |
| updateBallSpeed(); | |
| // Reset bricks | |
| brick.rowCount = 5; | |
| initBricks(); | |
| draw(); | |
| } | |
| // Initialize game | |
| document.getElementById('restart-btn').addEventListener('click', resetGame); | |
| // Handle window resize | |
| window.addEventListener('resize', () => { | |
| canvas.width = window.innerWidth; | |
| canvas.height = window.innerHeight; | |
| paddle.y = canvas.height - 30; | |
| }); | |
| initBricks(); | |
| updateSpeedDisplay(); | |
| updateAIDisplay(); | |
| draw(); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=Lookimi/myawesomeface" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body> | |
| </html> |