| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Galaxy Defender</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <style> |
| body { |
| overflow: hidden; |
| background-color: #000; |
| font-family: 'Arial', sans-serif; |
| margin: 0; |
| padding: 0; |
| } |
| |
| #game-container { |
| position: relative; |
| width: 800px; |
| height: 600px; |
| margin: 20px auto; |
| background: linear-gradient(to bottom, #000033 0%, #000000 100%); |
| overflow: hidden; |
| } |
| |
| #player { |
| position: absolute; |
| width: 50px; |
| height: 50px; |
| background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><path d="M25 5 L5 25 L15 25 L15 45 L35 45 L35 25 L45 25 Z" fill="%2300FFFF" stroke="%23FFFFFF" stroke-width="2"/></svg>'); |
| z-index: 10; |
| } |
| |
| .enemy { |
| position: absolute; |
| width: 40px; |
| height: 40px; |
| background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><path d="M20 5 L5 20 L15 20 L15 35 L25 35 L25 20 L35 20 Z" fill="%23FF0000" stroke="%23FFFFFF" stroke-width="2"/></svg>'); |
| z-index: 5; |
| } |
| |
| .bullet { |
| position: absolute; |
| width: 5px; |
| height: 15px; |
| background-color: #FFFF00; |
| border-radius: 2px; |
| z-index: 8; |
| } |
| |
| .explosion { |
| position: absolute; |
| width: 50px; |
| height: 50px; |
| background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><circle cx="25" cy="25" r="20" fill="%23FF9900"/><circle cx="25" cy="25" r="15" fill="%23FF3300"/><circle cx="25" cy="25" r="10" fill="%23FFFF00"/></svg>'); |
| z-index: 15; |
| animation: explode 0.5s forwards; |
| } |
| |
| .powerup { |
| position: absolute; |
| width: 30px; |
| height: 30px; |
| background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><circle cx="15" cy="15" r="12" fill="%2300FF00" stroke="%23FFFFFF" stroke-width="2"/></svg>'); |
| z-index: 7; |
| animation: pulse 1s infinite alternate; |
| } |
| |
| .star { |
| position: absolute; |
| background-color: white; |
| border-radius: 50%; |
| z-index: 1; |
| } |
| |
| #score-display { |
| position: absolute; |
| top: 10px; |
| left: 10px; |
| font-size: 20px; |
| color: white; |
| text-shadow: 0 0 5px #00FFFF; |
| z-index: 20; |
| } |
| |
| #health-display { |
| position: absolute; |
| top: 10px; |
| right: 10px; |
| font-size: 20px; |
| color: white; |
| text-shadow: 0 0 5px #FF0000; |
| z-index: 20; |
| } |
| |
| #level-complete { |
| position: absolute; |
| top: 50%; |
| left: 50%; |
| transform: translate(-50%, -50%); |
| background-color: rgba(0, 0, 0, 0.8); |
| color: #00FF00; |
| padding: 30px; |
| border-radius: 15px; |
| text-align: center; |
| display: none; |
| z-index: 100; |
| font-size: 24px; |
| border: 2px solid #00FF00; |
| box-shadow: 0 0 20px #00FF00; |
| } |
| |
| #game-over { |
| position: absolute; |
| top: 50%; |
| left: 50%; |
| transform: translate(-50%, -50%); |
| background-color: rgba(0, 0, 0, 0.8); |
| color: #FF0000; |
| padding: 30px; |
| border-radius: 15px; |
| text-align: center; |
| display: none; |
| z-index: 100; |
| font-size: 24px; |
| border: 2px solid #FF0000; |
| box-shadow: 0 0 20px #FF0000; |
| } |
| |
| #restart-btn { |
| background: linear-gradient(to bottom, #FF3300 0%, #990000 100%); |
| color: white; |
| border: none; |
| padding: 10px 20px; |
| margin-top: 20px; |
| border-radius: 5px; |
| cursor: pointer; |
| font-size: 18px; |
| text-shadow: 0 0 5px #000; |
| } |
| |
| #restart-btn:hover { |
| background: linear-gradient(to bottom, #FF5500 0%, #BB0000 100%); |
| } |
| |
| @keyframes explode { |
| 0% { transform: scale(0.5); opacity: 1; } |
| 100% { transform: scale(2); opacity: 0; } |
| } |
| |
| @keyframes pulse { |
| 0% { transform: scale(1); } |
| 100% { transform: scale(1.2); } |
| } |
| |
| #boss { |
| position: absolute; |
| width: 80px; |
| height: 80px; |
| background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 80"><path d="M40 10 L10 40 L30 40 L30 70 L50 70 L50 40 L70 40 Z" fill="%23FF00FF" stroke="%23FFFFFF" stroke-width="3"/></svg>'); |
| z-index: 6; |
| } |
| </style> |
| </head> |
| <body class="flex flex-col items-center justify-center min-h-screen bg-black"> |
| <h1 class="text-4xl font-bold mb-4 text-blue-400 text-center" style="text-shadow: 0 0 10px #00FFFF;">GALAXY DEFENDER</h1> |
| |
| <div id="game-container"> |
| <div id="player"></div> |
| <div id="score-display">SCORE: 0</div> |
| <div id="health-display">HEALTH: 100%</div> |
| |
| <div id="level-complete"> |
| <h2 class="text-3xl font-bold mb-4">LEVEL COMPLETE!</h2> |
| <p id="final-score">Your score: 0</p> |
| <button id="restart-btn">Play Again</button> |
| </div> |
| |
| <div id="game-over"> |
| <h2 class="text-3xl font-bold mb-4">GAME OVER</h2> |
| <p id="game-over-score">Your score: 0</p> |
| <button id="restart-btn">Try Again</button> |
| </div> |
| </div> |
| |
| <div class="mt-4 text-gray-400 text-center"> |
| <p>Arrow keys to move | Space to shoot | Collect green power-ups</p> |
| </div> |
|
|
| <script> |
| document.addEventListener('DOMContentLoaded', () => { |
| |
| const gameContainer = document.getElementById('game-container'); |
| const player = document.getElementById('player'); |
| const scoreDisplay = document.getElementById('score-display'); |
| const healthDisplay = document.getElementById('health-display'); |
| const levelCompleteScreen = document.getElementById('level-complete'); |
| const gameOverScreen = document.getElementById('game-over'); |
| const finalScoreDisplay = document.getElementById('final-score'); |
| const gameOverScoreDisplay = document.getElementById('game-over-score'); |
| const restartBtns = document.querySelectorAll('#restart-btn'); |
| |
| |
| let score = 0; |
| let health = 100; |
| let gameRunning = true; |
| let levelComplete = false; |
| let playerX = 375; |
| let playerY = 500; |
| let playerSpeed = 8; |
| let bullets = []; |
| let enemies = []; |
| let explosions = []; |
| let powerups = []; |
| let stars = []; |
| let keys = {}; |
| let lastShotTime = 0; |
| let shotDelay = 300; |
| let enemySpawnTimer = 0; |
| let enemySpawnDelay = 1000; |
| let powerupSpawnTimer = 0; |
| let powerupSpawnDelay = 8000; |
| let bossActive = false; |
| let bossHealth = 10; |
| |
| |
| const gameWidth = gameContainer.offsetWidth; |
| const gameHeight = gameContainer.offsetHeight; |
| const playerWidth = 50; |
| const playerHeight = 50; |
| |
| |
| player.style.left = `${playerX}px`; |
| player.style.top = `${playerY}px`; |
| |
| |
| function createStars() { |
| for (let i = 0; i < 100; i++) { |
| const star = document.createElement('div'); |
| star.className = 'star'; |
| |
| const size = Math.random() * 3; |
| const x = Math.random() * gameWidth; |
| const y = Math.random() * gameHeight; |
| const opacity = Math.random(); |
| |
| star.style.width = `${size}px`; |
| star.style.height = `${size}px`; |
| star.style.left = `${x}px`; |
| star.style.top = `${y}px`; |
| star.style.opacity = opacity; |
| |
| gameContainer.appendChild(star); |
| stars.push({ |
| element: star, |
| x: x, |
| y: y, |
| speed: 0.5 + Math.random() * 2 |
| }); |
| } |
| } |
| |
| |
| document.addEventListener('keydown', (e) => { |
| keys[e.key] = true; |
| |
| |
| if (e.key === ' ' && gameRunning && !levelComplete) { |
| const now = Date.now(); |
| if (now - lastShotTime > shotDelay) { |
| shoot(); |
| lastShotTime = now; |
| } |
| } |
| }); |
| |
| document.addEventListener('keyup', (e) => { |
| keys[e.key] = false; |
| }); |
| |
| restartBtns.forEach(btn => { |
| btn.addEventListener('click', restartGame); |
| }); |
| |
| |
| function initGame() { |
| createStars(); |
| spawnEnemyWave(5); |
| } |
| |
| |
| function shoot() { |
| const bullet = document.createElement('div'); |
| bullet.className = 'bullet'; |
| bullet.style.left = `${playerX + playerWidth / 2 - 2}px`; |
| bullet.style.top = `${playerY - 15}px`; |
| gameContainer.appendChild(bullet); |
| |
| bullets.push({ |
| element: bullet, |
| x: playerX + playerWidth / 2 - 2, |
| y: playerY - 15, |
| speed: 10 |
| }); |
| } |
| |
| |
| function spawnEnemyWave(count) { |
| for (let i = 0; i < count; i++) { |
| setTimeout(() => { |
| if (!gameRunning || levelComplete) return; |
| |
| const enemy = document.createElement('div'); |
| enemy.className = 'enemy'; |
| |
| const x = Math.random() * (gameWidth - 40); |
| const y = -40; |
| |
| enemy.style.left = `${x}px`; |
| enemy.style.top = `${y}px`; |
| gameContainer.appendChild(enemy); |
| |
| enemies.push({ |
| element: enemy, |
| x: x, |
| y: y, |
| speed: 2 + Math.random() * 2, |
| health: 1 |
| }); |
| }, i * 500); |
| } |
| } |
| |
| |
| function spawnBoss() { |
| if (bossActive) return; |
| |
| bossActive = true; |
| const boss = document.createElement('div'); |
| boss.id = 'boss'; |
| |
| const x = gameWidth / 2 - 40; |
| const y = -80; |
| |
| boss.style.left = `${x}px`; |
| boss.style.top = `${y}px`; |
| gameContainer.appendChild(boss); |
| |
| enemies.push({ |
| element: boss, |
| x: x, |
| y: y, |
| speed: 1.5, |
| health: bossHealth, |
| isBoss: true |
| }); |
| } |
| |
| |
| function spawnPowerup() { |
| const powerup = document.createElement('div'); |
| powerup.className = 'powerup'; |
| |
| const x = Math.random() * (gameWidth - 30); |
| const y = -30; |
| |
| powerup.style.left = `${x}px`; |
| powerup.style.top = `${y}px`; |
| gameContainer.appendChild(powerup); |
| |
| powerups.push({ |
| element: powerup, |
| x: x, |
| y: y, |
| speed: 3 |
| }); |
| } |
| |
| |
| function createExplosion(x, y) { |
| const explosion = document.createElement('div'); |
| explosion.className = 'explosion'; |
| explosion.style.left = `${x - 25}px`; |
| explosion.style.top = `${y - 25}px`; |
| gameContainer.appendChild(explosion); |
| |
| explosions.push({ |
| element: explosion, |
| time: 0 |
| }); |
| |
| |
| setTimeout(() => { |
| gameContainer.removeChild(explosion); |
| }, 500); |
| } |
| |
| |
| function gameLoop() { |
| if (!gameRunning) return; |
| |
| |
| handleMovement(); |
| |
| |
| updateBullets(); |
| |
| |
| updateEnemies(); |
| |
| |
| updatePowerups(); |
| |
| |
| updateStars(); |
| |
| |
| enemySpawnTimer += 16; |
| if (enemySpawnTimer >= enemySpawnDelay) { |
| if (enemies.length < 10) { |
| spawnEnemyWave(3); |
| } |
| enemySpawnTimer = 0; |
| |
| |
| if (score >= 500 && !bossActive) { |
| spawnBoss(); |
| } |
| } |
| |
| |
| powerupSpawnTimer += 16; |
| if (powerupSpawnTimer >= powerupSpawnDelay) { |
| spawnPowerup(); |
| powerupSpawnTimer = 0; |
| } |
| |
| |
| if (bossActive && enemies.length === 0) { |
| levelComplete = true; |
| showLevelComplete(); |
| } |
| |
| requestAnimationFrame(gameLoop); |
| } |
| |
| |
| function handleMovement() { |
| if (keys['ArrowLeft'] || keys['a']) { |
| playerX = Math.max(0, playerX - playerSpeed); |
| } |
| |
| if (keys['ArrowRight'] || keys['d']) { |
| playerX = Math.min(gameWidth - playerWidth, playerX + playerSpeed); |
| } |
| |
| if (keys['ArrowUp'] || keys['w']) { |
| playerY = Math.max(0, playerY - playerSpeed); |
| } |
| |
| if (keys['ArrowDown'] || keys['s']) { |
| playerY = Math.min(gameHeight - playerHeight, playerY + playerSpeed); |
| } |
| |
| player.style.left = `${playerX}px`; |
| player.style.top = `${playerY}px`; |
| } |
| |
| |
| function updateBullets() { |
| for (let i = bullets.length - 1; i >= 0; i--) { |
| const bullet = bullets[i]; |
| bullet.y -= bullet.speed; |
| bullet.element.style.top = `${bullet.y}px`; |
| |
| |
| if (bullet.y < -15) { |
| gameContainer.removeChild(bullet.element); |
| bullets.splice(i, 1); |
| } |
| } |
| } |
| |
| |
| function updateEnemies() { |
| for (let i = enemies.length - 1; i >= 0; i--) { |
| const enemy = enemies[i]; |
| enemy.y += enemy.speed; |
| enemy.element.style.top = `${enemy.y}px`; |
| |
| |
| if (enemy.y > gameHeight) { |
| gameContainer.removeChild(enemy.element); |
| enemies.splice(i, 1); |
| } |
| |
| |
| for (let j = bullets.length - 1; j >= 0; j--) { |
| const bullet = bullets[j]; |
| |
| if (checkCollision(bullet, enemy)) { |
| |
| enemy.health--; |
| |
| |
| gameContainer.removeChild(bullet.element); |
| bullets.splice(j, 1); |
| |
| |
| if (enemy.health <= 0) { |
| createExplosion(enemy.x + 20, enemy.y + 20); |
| gameContainer.removeChild(enemy.element); |
| enemies.splice(i, 1); |
| |
| |
| const points = enemy.isBoss ? 200 : 50; |
| score += points; |
| scoreDisplay.textContent = `SCORE: ${score}`; |
| |
| |
| if (enemy.isBoss) { |
| bossActive = false; |
| } |
| } |
| |
| break; |
| } |
| } |
| |
| |
| if (checkCollision({x: playerX, y: playerY, width: playerWidth, height: playerHeight}, enemy)) { |
| createExplosion(enemy.x + 20, enemy.y + 20); |
| gameContainer.removeChild(enemy.element); |
| enemies.splice(i, 1); |
| |
| |
| health -= enemy.isBoss ? 30 : 10; |
| health = Math.max(0, health); |
| healthDisplay.textContent = `HEALTH: ${health}%`; |
| |
| if (health <= 0) { |
| gameOver(); |
| } |
| } |
| } |
| } |
| |
| |
| function updatePowerups() { |
| for (let i = powerups.length - 1; i >= 0; i--) { |
| const powerup = powerups[i]; |
| powerup.y += powerup.speed; |
| powerup.element.style.top = `${powerup.y}px`; |
| |
| |
| if (powerup.y > gameHeight) { |
| gameContainer.removeChild(powerup.element); |
| powerups.splice(i, 1); |
| } |
| |
| |
| if (checkCollision({x: playerX, y: playerY, width: playerWidth, height: playerHeight}, powerup)) { |
| gameContainer.removeChild(powerup.element); |
| powerups.splice(i, 1); |
| |
| |
| health = Math.min(100, health + 20); |
| healthDisplay.textContent = `HEALTH: ${health}%`; |
| |
| |
| const originalSpeed = playerSpeed; |
| playerSpeed = 12; |
| setTimeout(() => { |
| playerSpeed = originalSpeed; |
| }, 5000); |
| } |
| } |
| } |
| |
| |
| function updateStars() { |
| for (let i = 0; i < stars.length; i++) { |
| const star = stars[i]; |
| star.y += star.speed; |
| |
| if (star.y > gameHeight) { |
| star.y = 0; |
| star.x = Math.random() * gameWidth; |
| } |
| |
| star.element.style.top = `${star.y}px`; |
| } |
| } |
| |
| |
| function checkCollision(obj1, obj2) { |
| const obj1Width = obj1.width || 40; |
| const obj1Height = obj1.height || 40; |
| const obj2Width = obj2.width || 40; |
| const obj2Height = obj2.height || 40; |
| |
| return ( |
| obj1.x < obj2.x + obj2Width && |
| obj1.x + obj1Width > obj2.x && |
| obj1.y < obj2.y + obj2Height && |
| obj1.y + obj1Height > obj2.y |
| ); |
| } |
| |
| |
| function showLevelComplete() { |
| gameRunning = false; |
| finalScoreDisplay.textContent = `Your score: ${score}`; |
| levelCompleteScreen.style.display = 'block'; |
| } |
| |
| |
| function gameOver() { |
| gameRunning = false; |
| gameOverScoreDisplay.textContent = `Your score: ${score}`; |
| gameOverScreen.style.display = 'block'; |
| |
| |
| createExplosion(playerX + 25, playerY + 25); |
| player.style.display = 'none'; |
| } |
| |
| |
| function restartGame() { |
| |
| score = 0; |
| health = 100; |
| gameRunning = true; |
| levelComplete = false; |
| bossActive = false; |
| playerX = 375; |
| playerY = 500; |
| playerSpeed = 8; |
| |
| |
| scoreDisplay.textContent = `SCORE: 0`; |
| healthDisplay.textContent = `HEALTH: 100%`; |
| player.style.display = 'block'; |
| player.style.left = `${playerX}px`; |
| player.style.top = `${playerY}px`; |
| |
| |
| levelCompleteScreen.style.display = 'none'; |
| gameOverScreen.style.display = 'none'; |
| |
| |
| bullets.forEach(bullet => { |
| gameContainer.removeChild(bullet.element); |
| }); |
| |
| enemies.forEach(enemy => { |
| gameContainer.removeChild(enemy.element); |
| }); |
| |
| powerups.forEach(powerup => { |
| gameContainer.removeChild(powerup.element); |
| }); |
| |
| stars.forEach(star => { |
| gameContainer.removeChild(star.element); |
| }); |
| |
| |
| bullets = []; |
| enemies = []; |
| powerups = []; |
| stars = []; |
| |
| |
| initGame(); |
| |
| |
| requestAnimationFrame(gameLoop); |
| } |
| |
| |
| initGame(); |
| gameLoop(); |
| }); |
| </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=FriedsU/space" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |