Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>CYBER FLIGHT | Neural Net Challenge</title> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Quantico:wght@400;700&display=swap'); | |
| :root { | |
| --primary: #00ff9d; | |
| --secondary: #00a1ff; | |
| --danger: #ff2a6d; | |
| --bg-dark: #0e0e2c; | |
| --bg-darker: #070716; | |
| --glow-intensity: 0; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| background-color: var(--bg-darker); | |
| font-family: 'Quantico', sans-serif; | |
| color: white; | |
| overflow: hidden; | |
| height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| background-image: | |
| radial-gradient(circle at 20% 30%, rgba(0, 255, 157, 0.05) 0%, transparent 20%), | |
| radial-gradient(circle at 80% 70%, rgba(0, 161, 255, 0.05) 0%, transparent 20%), | |
| linear-gradient(var(--bg-darker), var(--bg-dark)); | |
| } | |
| header { | |
| padding: 1.5rem 2rem; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| background-color: rgba(7, 7, 22, 0.8); | |
| border-bottom: 1px solid rgba(0, 255, 157, 0.2); | |
| box-shadow: 0 0 20px rgba(0, 255, 157, 0.1); | |
| z-index: 10; | |
| } | |
| .logo { | |
| font-family: 'Orbitron', sans-serif; | |
| font-weight: 900; | |
| font-size: 2rem; | |
| background: linear-gradient(90deg, var(--primary), var(--secondary)); | |
| -webkit-background-clip: text; | |
| background-clip: text; | |
| color: transparent; | |
| text-shadow: 0 0 10px rgba(0, 255, 157, 0.3); | |
| letter-spacing: 2px; | |
| } | |
| .stats { | |
| display: flex; | |
| gap: 2rem; | |
| } | |
| .stat-box { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| padding: 0.5rem 1.5rem; | |
| background: rgba(14, 14, 44, 0.7); | |
| border: 1px solid rgba(0, 161, 255, 0.2); | |
| border-radius: 4px; | |
| box-shadow: 0 0 10px rgba(0, 161, 255, 0.1); | |
| } | |
| .stat-label { | |
| font-size: 0.7rem; | |
| color: var(--secondary); | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| } | |
| .stat-value { | |
| font-family: 'Orbitron', sans-serif; | |
| font-size: 1.5rem; | |
| color: var(--primary); | |
| font-weight: 700; | |
| } | |
| .game-container { | |
| flex: 1; | |
| position: relative; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| #gameCanvas { | |
| border: 2px solid rgba(0, 255, 157, 0.3); | |
| box-shadow: | |
| 0 0 30px rgba(0, 255, 157, 0.2), | |
| inset 0 0 20px rgba(0, 255, 157, 0.1); | |
| background-color: var(--bg-dark); | |
| border-radius: 4px; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .scanline { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: linear-gradient( | |
| to bottom, | |
| transparent 0%, | |
| rgba(0, 255, 157, 0.05) 50%, | |
| transparent 100% | |
| ); | |
| background-size: 100% 8px; | |
| pointer-events: none; | |
| animation: scanline 8s linear infinite; | |
| } | |
| @keyframes scanline { | |
| 0% { transform: translateY(0); } | |
| 100% { transform: translateY(100vh); } | |
| } | |
| .noise { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAQElEQVR42u3OMQEAAAQAoNuVzV4GJ3xHkCSZ2JIkSZK0M7ElSZIkSZIkSZIkSZKk/zAx3ABFwz1QNNwDSZIkSZKW7QEmZgxYI0i3NgAAAABJRU5ErkJggg=="); | |
| opacity: 0.03; | |
| pointer-events: none; | |
| } | |
| .menu { | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| background: rgba(7, 7, 22, 0.9); | |
| border: 2px solid var(--primary); | |
| border-radius: 6px; | |
| padding: 2rem 3rem; | |
| text-align: center; | |
| box-shadow: | |
| 0 0 30px rgba(0, 255, 157, 0.3), | |
| inset 0 0 20px rgba(0, 255, 157, 0.2); | |
| z-index: 100; | |
| } | |
| .menu.hidden { | |
| display: none; | |
| } | |
| .menu h2 { | |
| font-family: 'Orbitron', sans-serif; | |
| color: var(--primary); | |
| margin-bottom: 1.5rem; | |
| font-size: 1.8rem; | |
| text-transform: uppercase; | |
| letter-spacing: 3px; | |
| } | |
| .menu p { | |
| color: var(--secondary); | |
| margin-bottom: 2rem; | |
| max-width: 300px; | |
| line-height: 1.6; | |
| } | |
| .btn { | |
| background: linear-gradient(45deg, var(--primary), var(--secondary)); | |
| border: none; | |
| color: var(--bg-darker); | |
| font-family: 'Orbitron', sans-serif; | |
| font-weight: 700; | |
| padding: 0.8rem 2rem; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| font-size: 0.9rem; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 0 15px rgba(0, 255, 157, 0.5); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .btn:hover { | |
| box-shadow: 0 0 25px rgba(0, 255, 157, 0.8); | |
| transform: translateY(-2px); | |
| } | |
| .btn:active { | |
| transform: translateY(0); | |
| } | |
| .btn::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: -100%; | |
| width: 100%; | |
| height: 100%; | |
| background: linear-gradient( | |
| 90deg, | |
| transparent, | |
| rgba(255, 255, 255, 0.2), | |
| transparent | |
| ); | |
| transition: none; | |
| } | |
| .btn:hover::before { | |
| left: 100%; | |
| transition: all 0.5s ease-in-out; | |
| } | |
| .glow { | |
| position: absolute; | |
| width: 100%; | |
| height: 100%; | |
| top: 0; | |
| left: 0; | |
| background: radial-gradient(circle at center, rgba(0, 255, 157, 0.1) 0%, transparent 70%); | |
| opacity: var(--glow-intensity); | |
| pointer-events: none; | |
| transition: opacity 0.5s ease; | |
| } | |
| .game-over { | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| background: rgba(255, 0, 77, 0.1); | |
| padding: 2rem; | |
| border: 2px solid var(--danger); | |
| border-radius: 6px; | |
| text-align: center; | |
| box-shadow: 0 0 30px rgba(255, 42, 109, 0.4); | |
| z-index: 100; | |
| display: none; | |
| } | |
| .game-over h2 { | |
| color: var(--danger); | |
| margin-bottom: 1rem; | |
| font-family: 'Orbitron', sans-serif; | |
| text-transform: uppercase; | |
| } | |
| .terminal { | |
| font-family: monospace; | |
| background-color: rgba(0, 0, 0, 0.7); | |
| padding: 1rem; | |
| border-radius: 4px; | |
| margin: 1rem 0; | |
| text-align: left; | |
| max-height: 150px; | |
| overflow-y: auto; | |
| border-left: 3px solid var(--primary); | |
| } | |
| .terminal-line { | |
| margin-bottom: 0.3rem; | |
| color: var(--primary); | |
| } | |
| .terminal-line.system { | |
| color: var(--secondary); | |
| } | |
| .terminal-line.warning { | |
| color: var(--danger); | |
| } | |
| .pipes { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| pointer-events: none; | |
| z-index: 1; | |
| } | |
| .cyber-circle { | |
| position: absolute; | |
| width: 200px; | |
| height: 200px; | |
| border-radius: 50%; | |
| border: 2px solid var(--primary); | |
| box-shadow: | |
| 0 0 20px var(--primary), | |
| inset 0 0 20px var(--primary); | |
| opacity: 0.1; | |
| pointer-events: none; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="logo">CYBER FLIGHT</div> | |
| <div class="stats"> | |
| <div class="stat-box"> | |
| <span class="stat-label">Neural Score</span> | |
| <span class="stat-value" id="score">0</span> | |
| </div> | |
| <div class="stat-box"> | |
| <span class="stat-label">High Score</span> | |
| <span class="stat-value" id="high-score">0</span> | |
| </div> | |
| <div class="stat-box"> | |
| <span class="stat-label">Energy</span> | |
| <span class="stat-value" id="energy">100%</span> | |
| </div> | |
| </div> | |
| </header> | |
| <div class="game-container"> | |
| <canvas id="gameCanvas" width="350" height="600"></canvas> | |
| <div class="scanline"></div> | |
| <div class="noise"></div> | |
| <div class="glow"></div> | |
| <div class="menu"> | |
| <h2>Neural Net Challenge</h2> | |
| <div class="terminal"> | |
| <div class="terminal-line system">> System initializing...</div> | |
| <div class="terminal-line">> Cybernetic augmentation complete</div> | |
| <div class="terminal-line system">> Neural interface active</div> | |
| <div class="terminal-line">> Flight systems: ONLINE</div> | |
| <div class="terminal-line system">> Ready for simulation</div> | |
| </div> | |
| <p>Execute neural synchronization to commence cybernetic flight simulation.</p> | |
| <button class="btn" id="startBtn">ENGAGE SYSTEMS</button> | |
| </div> | |
| <div class="game-over"> | |
| <h2>SYSTEM FAILURE</h2> | |
| <div class="terminal"> | |
| <div class="terminal-line warning">> Critical impact detected</div> | |
| <div class="terminal-line">> Neural score: <span id="final-score">0</span></div> | |
| <div class="terminal-line system">> Rebooting flight systems...</div> | |
| </div> | |
| <button class="btn" id="restartBtn">REINITIALIZE</button> | |
| </div> | |
| <div id="cyber-circles"></div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const canvas = document.getElementById('gameCanvas'); | |
| const ctx = canvas.getContext('2d'); | |
| const startBtn = document.getElementById('startBtn'); | |
| const restartBtn = document.getElementById('restartBtn'); | |
| const menu = document.querySelector('.menu'); | |
| const gameOver = document.querySelector('.game-over'); | |
| const scoreDisplay = document.getElementById('score'); | |
| const highScoreDisplay = document.getElementById('highScore'); | |
| const finalScoreDisplay = document.getElementById('final-score'); | |
| const energyDisplay = document.getElementById('energy'); | |
| const glow = document.querySelector('.glow'); | |
| // Game variables | |
| let score = 0; | |
| let highScore = localStorage.getItem('cyberFlightHighScore') || 0; | |
| let gameRunning = false; | |
| let animationId; | |
| let gameSpeed = 2; | |
| let gravity = 0.5; | |
| let energy = 100; | |
| let energyDrainInterval; | |
| let glowIntensity = 0; | |
| // Bird properties | |
| const bird = { | |
| x: 100, | |
| y: canvas.height / 2, | |
| width: 30, | |
| height: 24, | |
| velocity: 0, | |
| flapPower: -8, | |
| color: '#00ff9d' | |
| }; | |
| // Pipes | |
| const pipes = []; | |
| const pipeWidth = 60; | |
| const pipeGap = 150; | |
| let pipeFrequency = 120; // frames | |
| function createPipe() { | |
| // Only create pipes if game is running | |
| if (!gameRunning) return; | |
| const minHeight = 50; | |
| const maxHeight = canvas.height - pipeGap - minHeight; | |
| const height = Math.floor(Math.random() * (maxHeight - minHeight + 1)) + minHeight; | |
| pipes.push({ | |
| x: canvas.width, | |
| height: height, | |
| passed: false, | |
| color: `hsl(${Math.floor(Math.random() * 60) + 180}, 80%, 50%)` | |
| }); | |
| } | |
| function drawBird() { | |
| // Cybernetic bird with glow effect | |
| ctx.save(); | |
| // Glow effect | |
| const gradient = ctx.createRadialGradient( | |
| bird.x + bird.width / 2, | |
| bird.y + bird.height / 2, | |
| 0, | |
| bird.x + bird.width / 2, | |
| bird.y + bird.height / 2, | |
| bird.width * 2 | |
| ); | |
| gradient.addColorStop(0, bird.color); | |
| gradient.addColorStop(1, 'rgba(0, 255, 157, 0)'); | |
| ctx.fillStyle = gradient; | |
| ctx.beginPath(); | |
| ctx.arc( | |
| bird.x + bird.width / 2, | |
| bird.y + bird.height / 2, | |
| bird.width * 1.5, | |
| 0, | |
| Math.PI * 2 | |
| ); | |
| ctx.fill(); | |
| // Bird body (cybernetic shape) | |
| ctx.fillStyle = bird.color; | |
| ctx.beginPath(); | |
| ctx.moveTo(bird.x + bird.width * 0.3, bird.y); | |
| ctx.lineTo(bird.x + bird.width, bird.y + bird.height / 2); | |
| ctx.lineTo(bird.x + bird.width * 0.3, bird.y + bird.height); | |
| ctx.lineTo(bird.x, bird.y + bird.height / 2); | |
| ctx.closePath(); | |
| ctx.fill(); | |
| // Bird eye (glowing) | |
| ctx.fillStyle = '#00a1ff'; | |
| ctx.beginPath(); | |
| ctx.arc( | |
| bird.x + bird.width * 0.6, | |
| bird.y + bird.height * 0.4, | |
| bird.width * 0.15, | |
| 0, | |
| Math.PI * 2 | |
| ); | |
| ctx.fill(); | |
| // Hexagonal pattern on wings | |
| ctx.strokeStyle = '#00a1ff'; | |
| ctx.lineWidth = 1; | |
| drawHexPattern(bird.x + bird.width * 0.3, bird.y + bird.height / 2, 5, 10); | |
| ctx.restore(); | |
| } | |
| function drawHexPattern(x, y, hexSize, count) { | |
| ctx.save(); | |
| ctx.translate(x, y); | |
| for (let i = 0; i < count; i++) { | |
| const hexX = i % 2 === 0 ? | |
| (Math.floor(i / 2) * hexSize * 1.5) : | |
| (Math.floor(i / 2) * hexSize * 1.5 + hexSize * 0.75); | |
| const hexY = i % 2 === 0 ? | |
| -hexSize * 0.5 : | |
| hexSize * 0.5; | |
| drawHexagon(hexX, hexY, hexSize); | |
| } | |
| ctx.restore(); | |
| } | |
| function drawHexagon(x, y, size) { | |
| ctx.beginPath(); | |
| for (let i = 0; i < 6; i++) { | |
| const angle = (i * 2 * Math.PI / 6) + (Math.PI / 6); | |
| const xx = x + size * Math.cos(angle); | |
| const yy = y + size * Math.sin(angle); | |
| if (i === 0) { | |
| ctx.moveTo(xx, yy); | |
| } else { | |
| ctx.lineTo(xx, yy); | |
| } | |
| } | |
| ctx.closePath(); | |
| ctx.stroke(); | |
| } | |
| function drawPipes() { | |
| pipes.forEach((pipe, index) => { | |
| // Top pipe | |
| ctx.save(); | |
| // Pipe gradient | |
| const pipeGradient = ctx.createLinearGradient( | |
| pipe.x, 0, | |
| pipe.x + pipeWidth, 0 | |
| ); | |
| pipeGradient.addColorStop(0, 'rgba(0, 255, 157, 0)'); | |
| pipeGradient.addColorStop(0.1, pipe.color); | |
| pipeGradient.addColorStop(0.9, pipe.color); | |
| pipeGradient.addColorStop(1, 'rgba(0, 255, 157, 0)'); | |
| ctx.fillStyle = pipeGradient; | |
| // Hexagon pattern on pipes | |
| ctx.beginPath(); | |
| ctx.moveTo(pipe.x, pipe.height); | |
| ctx.lineTo(pipe.x + pipeWidth, pipe.height); | |
| ctx.lineTo(pipe.x + pipeWidth, 0); | |
| ctx.lineTo(pipe.x, 0); | |
| ctx.closePath(); | |
| ctx.fill(); | |
| // Pipe border (glowing) | |
| ctx.strokeStyle = pipe.color; | |
| ctx.lineWidth = 2; | |
| ctx.stroke(); | |
| // Bottom pipe | |
| const bottomY = pipe.height + pipeGap; | |
| ctx.beginPath(); | |
| ctx.moveTo(pipe.x, bottomY); | |
| ctx.lineTo(pipe.x + pipeWidth, bottomY); | |
| ctx.lineTo(pipe.x + pipeWidth, canvas.height); | |
| ctx.lineTo(pipe.x, canvas.height); | |
| ctx.closePath(); | |
| ctx.fill(); | |
| // Pipe border | |
| ctx.stroke(); | |
| // Circuit pattern | |
| drawPipeCircuit(pipe, index); | |
| ctx.restore(); | |
| }); | |
| } | |
| function drawPipeCircuit(pipe, index) { | |
| ctx.save(); | |
| ctx.strokeStyle = '#00a1ff'; | |
| ctx.fillStyle = '#00a1ff'; | |
| ctx.lineWidth = 1; | |
| // Draw circuit lines on top pipe | |
| const segments = Math.floor(pipe.height / 15); | |
| for (let i = 0; i < segments; i++) { | |
| const y = i * 15; | |
| if (i % 2 === index % 2) { | |
| ctx.beginPath(); | |
| ctx.moveTo(pipe.x, y); | |
| ctx.lineTo(pipe.x + pipeWidth, y); | |
| ctx.stroke(); | |
| } else { | |
| ctx.beginPath(); | |
| ctx.rect(pipe.x + pipeWidth * 0.3, y, pipeWidth * 0.4, 2); | |
| ctx.fill(); | |
| } | |
| // Circuit nodes | |
| if (i % 3 === 0) { | |
| ctx.beginPath(); | |
| ctx.arc( | |
| pipe.x + pipeWidth * 0.1, | |
| y + 7, | |
| 2, | |
| 0, | |
| Math.PI * 2 | |
| ); | |
| ctx.fill(); | |
| ctx.beginPath(); | |
| ctx.arc( | |
| pipe.x + pipeWidth * 0.9, | |
| y + 7, | |
| 2, | |
| 0, | |
| Math.PI * 2 | |
| ); | |
| ctx.fill(); | |
| } | |
| } | |
| // Draw circuit lines on bottom pipe | |
| const bottomY = pipe.height + pipeGap; | |
| const bottomHeight = canvas.height - bottomY; | |
| const bottomSegments = Math.floor(bottomHeight / 15); | |
| for (let i = 0; i < bottomSegments; i++) { | |
| const y = bottomY + i * 15; | |
| if (i % 2 === index % 2) { | |
| ctx.beginPath(); | |
| ctx.moveTo(pipe.x, y); | |
| ctx.lineTo(pipe.x + pipeWidth, y); | |
| ctx.stroke(); | |
| } else { | |
| ctx.beginPath(); | |
| ctx.rect(pipe.x + pipeWidth * 0.3, y, pipeWidth * 0.4, 2); | |
| ctx.fill(); | |
| } | |
| // Circuit nodes | |
| if (i % 3 === 0) { | |
| ctx.beginPath(); | |
| ctx.arc( | |
| pipe.x + pipeWidth * 0.1, | |
| y + 7, | |
| 2, | |
| 0, | |
| Math.PI * 2 | |
| ); | |
| ctx.fill(); | |
| ctx.beginPath(); | |
| ctx.arc( | |
| pipe.x + pipeWidth * 0.9, | |
| y + 7, | |
| 2, | |
| 0, | |
| Math.PI * 2 | |
| ); | |
| ctx.fill(); | |
| } | |
| } | |
| ctx.restore(); | |
| } | |
| function updateBird() { | |
| bird.velocity += gravity; | |
| bird.y += bird.velocity; | |
| // Keep bird within canvas bounds | |
| if (bird.y < 0) { | |
| bird.y = 0; | |
| bird.velocity = 0; | |
| } | |
| if (bird.y + bird.height > canvas.height) { | |
| bird.y = canvas.height - bird.height; | |
| bird.velocity = 0; | |
| } | |
| } | |
| function updatePipes() { | |
| // Move pipes | |
| pipes.forEach((pipe) => { | |
| pipe.x -= gameSpeed; | |
| // Check if bird passed the pipe | |
| if (!pipe.passed && pipe.x + pipeWidth < bird.x) { | |
| pipe.passed = true; | |
| score++; | |
| scoreDisplay.textContent = score; | |
| energy = Math.min(100, energy + 5); // Energy boost for passing obstacles | |
| energyDisplay.textContent = `${Math.floor(energy)}%`; | |
| // Trigger glow effect | |
| glowIntensity = 0.5; | |
| document.documentElement.style.setProperty('--glow-intensity', glowIntensity); | |
| setTimeout(() => { | |
| glowIntensity = 0; | |
| document.documentElement.style.setProperty('--glow-intensity', glowIntensity); | |
| }, 200); | |
| } | |
| }); | |
| // Remove off-screen pipes | |
| while (pipes.length > 0 && pipes[0].x + pipeWidth < 0) { | |
| pipes.shift(); | |
| } | |
| // Create new pipes | |
| if (frameCount % pipeFrequency === 0) { | |
| createPipe(); | |
| // Increase difficulty | |
| if (score > 0 && score % 3 === 0) { | |
| gameSpeed = Math.min(5, gameSpeed + 0.2); | |
| pipeGap = Math.max(120, pipeGap - 5); | |
| pipeFrequency = Math.max(80, pipeFrequency - 5); | |
| } | |
| } | |
| } | |
| function checkCollisions() { | |
| // Check if bird hit top or bottom | |
| if (bird.y <= 0 || bird.y + bird.height >= canvas.height) { | |
| endGame(); | |
| return; | |
| } | |
| // Check if bird hit any pipes | |
| for (const pipe of pipes) { | |
| if (bird.x + bird.width > pipe.x && | |
| bird.x < pipe.x + pipeWidth && | |
| (bird.y < pipe.height || bird.y + bird.height > pipe.height + pipeGap)) { | |
| endGame(); | |
| return; | |
| } | |
| } | |
| } | |
| function drainEnergy() { | |
| energy = Math.max(0, energy - 0.5); | |
| energyDisplay.textContent = `${Math.floor(energy)}%`; | |
| // Change bird color based on energy level | |
| if (energy > 50) { | |
| bird.color = '#00ff9d'; | |
| } else if (energy > 20) { | |
| bird.color = '#ffcc00'; | |
| } else { | |
| bird.color = '#ff2a6d'; | |
| } | |
| // End game if energy depleted | |
| if (energy <= 0) { | |
| endGame(); | |
| } | |
| } | |
| function drawBackground() { | |
| // Dark gradient background | |
| ctx.fillStyle = '#070716'; | |
| ctx.fillRect(0, 0, canvas.width, canvas.height); | |
| // Grid pattern | |
| ctx.strokeStyle = 'rgba(0, 161, 255, 0.05)'; | |
| ctx.lineWidth = 1; | |
| // Vertical lines | |
| for (let x = 0; x < canvas.width; x += 40) { | |
| ctx.beginPath(); | |
| ctx.moveTo(x, 0); | |
| ctx.lineTo(x, canvas.height); | |
| ctx.stroke(); | |
| } | |
| // Horizontal lines | |
| for (let y = 0; y < canvas.height; y += 40) { | |
| ctx.beginPath(); | |
| ctx.moveTo(0, y); | |
| ctx.lineTo(canvas.width, y); | |
| ctx.stroke(); | |
| } | |
| // Center line (cybernetic pulse) | |
| ctx.strokeStyle = 'rgba(0, 255, 157, 0.1)'; | |
| ctx.lineWidth = 2; | |
| ctx.beginPath(); | |
| ctx.moveTo(canvas.width / 2, 0); | |
| ctx.lineTo(canvas.width / 2, canvas.height); | |
| ctx.stroke(); | |
| // Moving scan lines | |
| ctx.fillStyle = 'rgba(0, 255, 157, 0.03)'; | |
| for (let y = frameCount % 40; y < canvas.height; y += 40) { | |
| ctx.fillRect(0, y, canvas.width, 2); | |
| } | |
| } | |
| function createCyberCircles() { | |
| const container = document.getElementById('cyber-circles'); | |
| container.innerHTML = ''; | |
| const circleCount = 15; | |
| for (let i = 0; i < circleCount; i++) { | |
| const circle = document.createElement('div'); | |
| circle.className = 'cyber-circle'; | |
| // Random position | |
| const left = Math.random() * 100; | |
| const top = Math.random() * 100; | |
| // Random size | |
| const size = 50 + Math.random() * 150; | |
| // Random animation | |
| const duration = 5 + Math.random() * 10; | |
| const delay = Math.random() * 5; | |
| circle.style.left = `${left}%`; | |
| circle.style.top = `${top}%`; | |
| circle.style.width = `${size}px`; | |
| circle.style.height = `${size}px`; | |
| circle.style.animation = `pulse ${duration}s ${delay}s infinite alternate`; | |
| container.appendChild(circle); | |
| } | |
| } | |
| function startGame() { | |
| // Reset game state | |
| score = 0; | |
| energy = 100; | |
| gameSpeed = 2; | |
| bird.y = canvas.height / 2; | |
| bird.velocity = 0; | |
| pipes.length = 0; | |
| frameCount = 0; | |
| scoreDisplay.textContent = '0'; | |
| energyDisplay.textContent = '100%'; | |
| // Hide menu and show game | |
| menu.classList.add('hidden'); | |
| gameOver.style.display = 'none'; | |
| gameRunning = true; | |
| // Start energy drain | |
| clearInterval(energyDrainInterval); | |
| energyDrainInterval = setInterval(drainEnergy, 100); | |
| // Start game loop | |
| gameLoop(); | |
| } | |
| function endGame() { | |
| gameRunning = false; | |
| clearInterval(energyDrainInterval); | |
| // Update high score | |
| if (score > highScore) { | |
| highScore = score; | |
| localStorage.setItem('cyberFlightHighScore', highScore); | |
| document.getElementById('high-score').textContent = highScore; | |
| } | |
| // Show game over screen | |
| finalScoreDisplay.textContent = score; | |
| gameOver.style.display = 'block'; | |
| cancelAnimationFrame(animationId); | |
| } | |
| function gameLoop() { | |
| if (!gameRunning) return; | |
| frameCount++; | |
| // Clear canvas | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| // Draw game elements | |
| drawBackground(); | |
| drawPipes(); | |
| drawBird(); | |
| // Update game state | |
| updateBird(); | |
| updatePipes(); | |
| checkCollisions(); | |
| animationId = requestAnimationFrame(gameLoop); | |
| } | |
| // Event listeners | |
| startBtn.addEventListener('click', startGame); | |
| restartBtn.addEventListener('click', startGame); | |
| document.addEventListener('keydown', (e) => { | |
| if (e.code === 'Space' || e.key === ' ' || e.key === 'ArrowUp') { | |
| e.preventDefault(); | |
| if (!gameRunning && menu.classList.contains('hidden')) { | |
| startGame(); | |
| } else if (gameRunning) { | |
| bird.velocity = bird.flapPower; | |
| energy = Math.max(0, energy - 1); // Energy cost for flapping | |
| energyDisplay.textContent = `${Math.floor(energy)}%`; | |
| } | |
| } | |
| }); | |
| canvas.addEventListener('click', (e) => { | |
| if (!gameRunning && menu.classList.contains('hidden')) { | |
| startGame(); | |
| } else if (gameRunning) { | |
| bird.velocity = bird.flapPower; | |
| energy = Math.max(0, energy - 1); | |
| energyDisplay.textContent = `${Math.floor(energy)}%`; | |
| } | |
| }); | |
| // Initialize UI | |
| createCyberCircles(); | |
| document.getElementById('high-score').textContent = highScore; | |
| // Game loop variables | |
| let frameCount = 0; | |
| // Insert new terminal line every 3 seconds while in menu | |
| const terminal = document.querySelector('.terminal'); | |
| const terminalMessages = [ | |
| { text: "> Neural pathways engaged", class: "" }, | |
| { text: "> Cybernetic core at 98%", class: "system" }, | |
| { text: "> Awaiting user command", class: "" }, | |
| { text: "> Warning: Energy levels critical", class: "warning" }, | |
| { text: "> Activating neural boosters", class: "system" } | |
| ]; | |
| let messageIndex = 2; // Start after initial messages | |
| setInterval(() => { | |
| if (!gameRunning && !menu.classList.contains('hidden')) { | |
| const message = terminalMessages[messageIndex % terminalMessages.length]; | |
| const newLine = document.createElement('div'); | |
| newLine.classList.add('terminal-line', message.class); | |
| newLine.textContent = message.text; | |
| terminal.appendChild(newLine); | |
| terminal.scrollTop = terminal.scrollHeight; | |
| messageIndex++; | |
| } | |
| }, 3000); | |
| }); | |
| </script> | |
| </body> | |
| </html> |