Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Cosmic Evasion</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| overflow: hidden; | |
| font-family: 'Arial', sans-serif; | |
| } | |
| #game-container { | |
| position: relative; | |
| width: 100vw; | |
| height: 100vh; | |
| overflow: hidden; | |
| } | |
| #game-canvas { | |
| display: block; | |
| background-color: #000; | |
| } | |
| #ui { | |
| position: absolute; | |
| top: 20px; | |
| left: 20px; | |
| color: white; | |
| font-size: 18px; | |
| text-shadow: 0 0 5px rgba(0, 255, 255, 0.8); | |
| z-index: 10; | |
| } | |
| #start-screen { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-color: rgba(0, 0, 0, 0.7); | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| color: white; | |
| z-index: 20; | |
| } | |
| #game-over { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-color: rgba(0, 0, 0, 0.7); | |
| display: none; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| color: white; | |
| z-index: 20; | |
| } | |
| .btn { | |
| margin-top: 20px; | |
| padding: 10px 30px; | |
| background: linear-gradient(135deg, #00d2ff 0%, #3a7bd5 100%); | |
| border: none; | |
| border-radius: 30px; | |
| color: white; | |
| font-size: 18px; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| box-shadow: 0 5px 15px rgba(0, 210, 255, 0.4); | |
| } | |
| .btn:hover { | |
| transform: translateY(-3px); | |
| box-shadow: 0 8px 20px rgba(0, 210, 255, 0.6); | |
| } | |
| .btn:active { | |
| transform: translateY(1px); | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-black"> | |
| <div id="game-container"> | |
| <canvas id="game-canvas"></canvas> | |
| <div id="ui"> | |
| <div>Score: <span id="score">0</span></div> | |
| <div>Distance: <span id="distance">0</span> light-years</div> | |
| <div>Speed: <span id="speed">0</span></div> | |
| </div> | |
| <div id="start-screen"> | |
| <h1 class="text-4xl font-bold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-cyan-400 to-blue-500">COSMIC EVASION</h1> | |
| <p class="text-xl mb-8">Navigate through space and avoid obstacles!</p> | |
| <button id="start-btn" class="btn">START GAME</button> | |
| <div class="mt-8 text-sm opacity-70"> | |
| <p>Controls: Arrow Keys or WASD to move</p> | |
| <p>Space to boost (limited fuel)</p> | |
| </div> | |
| </div> | |
| <div id="game-over"> | |
| <h1 class="text-4xl font-bold mb-4 text-transparent bg-clip-text bg-gradient-to-r from-red-400 to-pink-600">GAME OVER</h1> | |
| <p class="text-xl mb-2">Final Score: <span id="final-score">0</span></p> | |
| <p class="text-xl mb-8">Distance Traveled: <span id="final-distance">0</span> light-years</p> | |
| <button id="restart-btn" class="btn">PLAY AGAIN</button> | |
| </div> | |
| </div> | |
| <script> | |
| // Game variables | |
| const canvas = document.getElementById('game-canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| const scoreElement = document.getElementById('score'); | |
| const distanceElement = document.getElementById('distance'); | |
| const speedElement = document.getElementById('speed'); | |
| const finalScoreElement = document.getElementById('final-score'); | |
| const finalDistanceElement = document.getElementById('final-distance'); | |
| const startScreen = document.getElementById('start-screen'); | |
| const gameOverScreen = document.getElementById('game-over'); | |
| const startBtn = document.getElementById('start-btn'); | |
| const restartBtn = document.getElementById('restart-btn'); | |
| // Set canvas size | |
| canvas.width = window.innerWidth; | |
| canvas.height = window.innerHeight; | |
| // Game state | |
| let gameRunning = false; | |
| let score = 0; | |
| let distance = 0; | |
| let speed = 3; | |
| let gameSpeed = 3; | |
| let boostFuel = 100; | |
| let isBoosting = false; | |
| let backgroundOffset = 0; | |
| let currentBackground = 0; | |
| let obstacleSpawnTimer = 0; | |
| let starSpawnTimer = 0; | |
| let planetSpawnTimer = 0; | |
| let animationFrameId; | |
| // Background colors for different zones | |
| const backgroundColors = [ | |
| { top: '#000428', bottom: '#004e92' }, // Blue nebula | |
| { top: '#1a1a2e', bottom: '#16213e' }, // Deep space | |
| { top: '#0f0c29', bottom: '#302b63' }, // Purple nebula | |
| { top: '#3a1c71', bottom: '#d76d77' }, // Pink/purple | |
| { top: '#000000', bottom: '#0f2027' }, // Dark space | |
| { top: '#1e3c72', bottom: '#2a5298' }, // Blue space | |
| { top: '#614385', bottom: '#516395' }, // Purple space | |
| { top: '#0f2027', bottom: '#203a43' } // Dark blue | |
| ]; | |
| // Player | |
| const player = { | |
| x: canvas.width / 4, | |
| y: canvas.height / 2, | |
| width: 40, | |
| height: 30, | |
| speed: 5, | |
| color: '#00d2ff', | |
| boostColor: '#ff5e62', | |
| isBoosting: false, | |
| draw() { | |
| ctx.save(); | |
| ctx.fillStyle = this.isBoosting ? this.boostColor : this.color; | |
| // Draw spaceship | |
| ctx.beginPath(); | |
| ctx.moveTo(this.x, this.y); | |
| ctx.lineTo(this.x - this.width, this.y + this.height/2); | |
| ctx.lineTo(this.x, this.y + this.height); | |
| ctx.closePath(); | |
| ctx.fill(); | |
| // Draw boost flame if boosting | |
| if (this.isBoosting) { | |
| ctx.beginPath(); | |
| ctx.moveTo(this.x - this.width, this.y + this.height/2 - 5); | |
| ctx.lineTo(this.x - this.width - 15, this.y + this.height/2); | |
| ctx.lineTo(this.x - this.width, this.y + this.height/2 + 5); | |
| ctx.closePath(); | |
| ctx.fill(); | |
| } | |
| ctx.restore(); | |
| }, | |
| update() { | |
| // Boundary checking | |
| if (this.y < 0) this.y = 0; | |
| if (this.y > canvas.height - this.height) this.y = canvas.height - this.height; | |
| } | |
| }; | |
| // Stars for background | |
| const stars = []; | |
| class Star { | |
| constructor() { | |
| this.x = canvas.width; | |
| this.y = Math.random() * canvas.height; | |
| this.size = Math.random() * 3; | |
| this.speed = speed + Math.random() * 3; | |
| this.color = `rgba(255, 255, 255, ${Math.random()})`; | |
| } | |
| update() { | |
| this.x -= this.speed; | |
| } | |
| draw() { | |
| ctx.fillStyle = this.color; | |
| ctx.beginPath(); | |
| ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); | |
| ctx.fill(); | |
| } | |
| isOffScreen() { | |
| return this.x + this.size < 0; | |
| } | |
| } | |
| // Planets for background | |
| const planets = []; | |
| class Planet { | |
| constructor() { | |
| this.x = canvas.width; | |
| this.y = Math.random() * canvas.height; | |
| this.size = 50 + Math.random() * 100; | |
| this.speed = speed * 0.5; | |
| this.color = `hsl(${Math.random() * 360}, 70%, 50%)`; | |
| this.hasRing = Math.random() > 0.7; | |
| } | |
| update() { | |
| this.x -= this.speed; | |
| } | |
| draw() { | |
| // Planet | |
| ctx.fillStyle = this.color; | |
| ctx.beginPath(); | |
| ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); | |
| ctx.fill(); | |
| // Ring | |
| if (this.hasRing) { | |
| ctx.strokeStyle = `hsla(${Math.random() * 360}, 80%, 60%, 0.7)`; | |
| ctx.lineWidth = 5; | |
| ctx.beginPath(); | |
| ctx.ellipse(this.x, this.y, this.size * 1.5, this.size * 0.3, 0, 0, Math.PI * 2); | |
| ctx.stroke(); | |
| } | |
| } | |
| isOffScreen() { | |
| return this.x + this.size < 0; | |
| } | |
| } | |
| // Obstacles | |
| const obstacles = []; | |
| class Obstacle { | |
| constructor() { | |
| this.width = 40 + Math.random() * 60; | |
| this.height = 40 + Math.random() * 100; | |
| this.x = canvas.width; | |
| this.y = Math.random() * (canvas.height - this.height); | |
| this.speed = speed; | |
| this.color = `hsl(${Math.random() * 60 + 20}, 80%, 50%)`; | |
| this.type = Math.random() > 0.5 ? 'rectangle' : 'triangle'; | |
| } | |
| update() { | |
| this.x -= this.speed; | |
| } | |
| draw() { | |
| ctx.fillStyle = this.color; | |
| if (this.type === 'rectangle') { | |
| ctx.fillRect(this.x, this.y, this.width, this.height); | |
| } else { | |
| ctx.beginPath(); | |
| ctx.moveTo(this.x, this.y); | |
| ctx.lineTo(this.x + this.width, this.y + this.height/2); | |
| ctx.lineTo(this.x, this.y + this.height); | |
| ctx.closePath(); | |
| ctx.fill(); | |
| } | |
| } | |
| isOffScreen() { | |
| return this.x + this.width < 0; | |
| } | |
| collidesWith(player) { | |
| return player.x < this.x + this.width && | |
| player.x + player.width > this.x && | |
| player.y < this.y + this.height && | |
| player.y + player.height > this.y; | |
| } | |
| } | |
| // Power-ups | |
| const powerups = []; | |
| class PowerUp { | |
| constructor() { | |
| this.x = canvas.width; | |
| this.y = Math.random() * canvas.height; | |
| this.radius = 15; | |
| this.speed = speed; | |
| this.type = Math.random() > 0.5 ? 'fuel' : 'shield'; | |
| } | |
| update() { | |
| this.x -= this.speed; | |
| } | |
| draw() { | |
| ctx.save(); | |
| if (this.type === 'fuel') { | |
| ctx.fillStyle = '#00d2ff'; | |
| ctx.beginPath(); | |
| ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2); | |
| ctx.fill(); | |
| // Draw fuel symbol | |
| ctx.fillStyle = '#000'; | |
| ctx.font = 'bold 20px Arial'; | |
| ctx.textAlign = 'center'; | |
| ctx.textBaseline = 'middle'; | |
| ctx.fillText('F', this.x, this.y); | |
| } else { | |
| // Shield | |
| ctx.fillStyle = '#3a7bd5'; | |
| ctx.beginPath(); | |
| ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2); | |
| ctx.fill(); | |
| // Draw shield symbol | |
| ctx.strokeStyle = '#000'; | |
| ctx.lineWidth = 2; | |
| ctx.beginPath(); | |
| ctx.arc(this.x, this.y, this.radius - 5, -Math.PI/4, Math.PI/4); | |
| ctx.stroke(); | |
| ctx.beginPath(); | |
| ctx.arc(this.x, this.y, this.radius - 8, -Math.PI/4, Math.PI/4); | |
| ctx.stroke(); | |
| } | |
| ctx.restore(); | |
| } | |
| isOffScreen() { | |
| return this.x + this.radius < 0; | |
| } | |
| collidesWith(player) { | |
| const dx = this.x - (player.x + player.width/2); | |
| const dy = this.y - (player.y + player.height/2); | |
| const distance = Math.sqrt(dx * dx + dy * dy); | |
| return distance < this.radius + Math.max(player.width, player.height)/2; | |
| } | |
| } | |
| // Input handling | |
| const keys = { | |
| ArrowUp: false, | |
| ArrowDown: false, | |
| ArrowLeft: false, | |
| ArrowRight: false, | |
| w: false, | |
| a: false, | |
| s: false, | |
| d: false, | |
| ' ': false | |
| }; | |
| window.addEventListener('keydown', (e) => { | |
| if (keys.hasOwnProperty(e.key)) { | |
| keys[e.key] = true; | |
| } | |
| }); | |
| window.addEventListener('keyup', (e) => { | |
| if (keys.hasOwnProperty(e.key)) { | |
| keys[e.key] = false; | |
| } | |
| }); | |
| // Game functions | |
| function startGame() { | |
| gameRunning = true; | |
| score = 0; | |
| distance = 0; | |
| speed = 3; | |
| gameSpeed = 3; | |
| boostFuel = 100; | |
| currentBackground = 0; | |
| backgroundOffset = 0; | |
| obstacles.length = 0; | |
| stars.length = 0; | |
| planets.length = 0; | |
| powerups.length = 0; | |
| player.x = canvas.width / 4; | |
| player.y = canvas.height / 2; | |
| player.isBoosting = false; | |
| startScreen.style.display = 'none'; | |
| gameOverScreen.style.display = 'none'; | |
| animationFrameId = requestAnimationFrame(gameLoop); | |
| } | |
| function endGame() { | |
| gameRunning = false; | |
| finalScoreElement.textContent = score; | |
| finalDistanceElement.textContent = distance.toFixed(1); | |
| gameOverScreen.style.display = 'flex'; | |
| cancelAnimationFrame(animationFrameId); | |
| } | |
| function handleInput() { | |
| player.isBoosting = false; | |
| // Vertical movement | |
| if ((keys.ArrowUp || keys.w) && !(keys.ArrowDown || keys.s)) { | |
| player.y -= player.speed; | |
| } else if ((keys.ArrowDown || keys.s) && !(keys.ArrowUp || keys.w)) { | |
| player.y += player.speed; | |
| } | |
| // Horizontal movement | |
| if ((keys.ArrowLeft || keys.a) && !(keys.ArrowRight || keys.d)) { | |
| player.x -= player.speed; | |
| } else if ((keys.ArrowRight || keys.d) && !(keys.ArrowLeft || keys.a)) { | |
| player.x += player.speed; | |
| } | |
| // Boost | |
| if ((keys[' ']) && boostFuel > 0) { | |
| player.isBoosting = true; | |
| boostFuel -= 0.5; | |
| gameSpeed = speed * 2; | |
| } else { | |
| gameSpeed = speed; | |
| } | |
| // Recharge boost when not in use | |
| if (!keys[' '] && boostFuel < 100) { | |
| boostFuel += 0.1; | |
| } | |
| } | |
| function spawnObjects() { | |
| // Spawn stars | |
| starSpawnTimer++; | |
| if (starSpawnTimer > 5) { | |
| stars.push(new Star()); | |
| starSpawnTimer = 0; | |
| } | |
| // Spawn obstacles | |
| obstacleSpawnTimer++; | |
| if (obstacleSpawnTimer > 60 - Math.min(50, distance / 10)) { | |
| obstacles.push(new Obstacle()); | |
| obstacleSpawnTimer = 0; | |
| // Occasionally spawn power-up after obstacle | |
| if (Math.random() > 0.7) { | |
| powerups.push(new PowerUp()); | |
| } | |
| } | |
| // Spawn planets | |
| planetSpawnTimer++; | |
| if (planetSpawnTimer > 300) { | |
| planets.push(new Planet()); | |
| planetSpawnTimer = 0; | |
| } | |
| } | |
| function updateObjects() { | |
| // Update stars | |
| for (let i = stars.length - 1; i >= 0; i--) { | |
| stars[i].update(); | |
| if (stars[i].isOffScreen()) { | |
| stars.splice(i, 1); | |
| } | |
| } | |
| // Update obstacles | |
| for (let i = obstacles.length - 1; i >= 0; i--) { | |
| obstacles[i].speed = gameSpeed; | |
| obstacles[i].update(); | |
| if (obstacles[i].isOffScreen()) { | |
| obstacles.splice(i, 1); | |
| score += 10; | |
| } | |
| // Check collision | |
| if (obstacles[i].collidesWith(player)) { | |
| endGame(); | |
| return; | |
| } | |
| } | |
| // Update planets | |
| for (let i = planets.length - 1; i >= 0; i--) { | |
| planets[i].speed = gameSpeed * 0.5; | |
| planets[i].update(); | |
| if (planets[i].isOffScreen()) { | |
| planets.splice(i, 1); | |
| } | |
| } | |
| // Update power-ups | |
| for (let i = powerups.length - 1; i >= 0; i--) { | |
| powerups[i].speed = gameSpeed; | |
| powerups[i].update(); | |
| if (powerups[i].isOffScreen()) { | |
| powerups.splice(i, 1); | |
| } | |
| // Check collision | |
| if (powerups[i].collidesWith(player)) { | |
| if (powerups[i].type === 'fuel') { | |
| boostFuel = Math.min(100, boostFuel + 30); | |
| } else { | |
| // Shield - temporary invincibility | |
| // For simplicity, we'll just add score | |
| score += 50; | |
| } | |
| powerups.splice(i, 1); | |
| } | |
| } | |
| } | |
| function drawBackground() { | |
| // Gradient background based on current zone | |
| const bgColor = backgroundColors[currentBackground % backgroundColors.length]; | |
| const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height); | |
| gradient.addColorStop(0, bgColor.top); | |
| gradient.addColorStop(1, bgColor.bottom); | |
| ctx.fillStyle = gradient; | |
| ctx.fillRect(0, 0, canvas.width, canvas.height); | |
| // Draw distant stars (parallax effect) | |
| ctx.fillStyle = 'rgba(255, 255, 255, 0.8)'; | |
| for (let i = 0; i < 100; i++) { | |
| const x = (i * 200 + backgroundOffset * 0.2) % canvas.width; | |
| const y = (i * 150) % canvas.height; | |
| const size = 1 + (i % 3); | |
| ctx.beginPath(); | |
| ctx.arc(x, y, size, 0, Math.PI * 2); | |
| ctx.fill(); | |
| } | |
| } | |
| function drawUI() { | |
| // Boost fuel meter | |
| ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; | |
| ctx.fillRect(20, canvas.height - 40, 200, 20); | |
| ctx.fillStyle = '#00d2ff'; | |
| ctx.fillRect(20, canvas.height - 40, 200 * (boostFuel / 100), 20); | |
| ctx.strokeStyle = 'white'; | |
| ctx.lineWidth = 2; | |
| ctx.strokeRect(20, canvas.height - 40, 200, 20); | |
| ctx.fillStyle = 'white'; | |
| ctx.font = '14px Arial'; | |
| ctx.fillText('BOOST', 25, canvas.height - 25); | |
| } | |
| function updateGameState() { | |
| // Increase distance and speed over time | |
| distance += gameSpeed * 0.01; | |
| speed = 3 + Math.floor(distance / 20) * 0.5; | |
| // Change background zone every 50 distance units | |
| if (distance > (currentBackground + 1) * 50) { | |
| currentBackground++; | |
| } | |
| // Update UI elements | |
| scoreElement.textContent = score; | |
| distanceElement.textContent = distance.toFixed(1); | |
| speedElement.textContent = gameSpeed.toFixed(1); | |
| // Move background for parallax effect | |
| backgroundOffset += gameSpeed * 0.1; | |
| } | |
| function gameLoop() { | |
| if (!gameRunning) return; | |
| // Clear canvas | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| // Draw background | |
| drawBackground(); | |
| // Handle input | |
| handleInput(); | |
| // Spawn objects | |
| spawnObjects(); | |
| // Update objects | |
| updateObjects(); | |
| if (!gameRunning) return; // Check again in case collision occurred | |
| player.update(); | |
| // Draw objects | |
| for (const star of stars) star.draw(); | |
| for (const planet of planets) planet.draw(); | |
| for (const obstacle of obstacles) obstacle.draw(); | |
| for (const powerup of powerups) powerup.draw(); | |
| player.draw(); | |
| // Draw UI | |
| drawUI(); | |
| // Update game state | |
| updateGameState(); | |
| // Next frame | |
| animationFrameId = requestAnimationFrame(gameLoop); | |
| } | |
| // Event listeners for buttons | |
| startBtn.addEventListener('click', startGame); | |
| restartBtn.addEventListener('click', startGame); | |
| // Handle window resize | |
| window.addEventListener('resize', () => { | |
| canvas.width = window.innerWidth; | |
| canvas.height = window.innerHeight; | |
| // Keep player in bounds if screen gets smaller | |
| if (player.y > canvas.height - player.height) { | |
| player.y = canvas.height - player.height; | |
| } | |
| }); | |
| // Initial setup | |
| canvas.width = window.innerWidth; | |
| canvas.height = window.innerHeight; | |
| </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=JohnPork04/neural-canvas" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |