|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Star Wars: Asteroid Evasion</title> |
|
|
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Prompt:wght@300;500&display=swap" rel="stylesheet"> |
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
|
<style> |
|
|
* { |
|
|
margin: 0; |
|
|
padding: 0; |
|
|
box-sizing: border-box; |
|
|
} |
|
|
|
|
|
body { |
|
|
font-family: 'Prompt', sans-serif; |
|
|
background-color: #000; |
|
|
color: #fff; |
|
|
overflow: hidden; |
|
|
height: 100vh; |
|
|
perspective: 1000px; |
|
|
} |
|
|
|
|
|
#game-container { |
|
|
position: relative; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background-image: |
|
|
radial-gradient(circle at center, rgba(0, 20, 80, 0.8) 0%, rgba(0, 0, 0, 1) 70%), |
|
|
url('https://starshipsofa.com/wp-content/uploads/2013/07/starfield.jpg'); |
|
|
overflow: hidden; |
|
|
} |
|
|
|
|
|
.stars { |
|
|
position: absolute; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"><circle cx="10" cy="10" r="1" fill="white"/><circle cx="50" cy="30" r="1" fill="white"/><circle cx="80" cy="10" r="1" fill="white"/><circle cx="130" cy="20" r="1" fill="white"/><circle cx="170" cy="5" r="1" fill="white"/><circle cx="30" cy="80" r="1" fill="white"/><circle cx="90" cy="60" r="1" fill="white"/><circle cx="150" cy="70" r="1" fill="white"/><circle cx="10" cy="120" r="1" fill="white"/><circle cx="70" cy="100" r="1" fill="white"/><circle cx="120" cy="130" r="1" fill="white"/><circle cx="180" cy="110" r="1" fill="white"/><circle cx="30" cy="170" r="1" fill="white"/><circle cx="80" cy="150" r="1" fill="white"/><circle cx="140" cy="180" r="1" fill="white"/><circle cx="190" cy="160" r="1" fill="white"/></svg>'); |
|
|
background-repeat: repeat; |
|
|
animation: starScroll 200s linear infinite; |
|
|
} |
|
|
|
|
|
@keyframes starScroll { |
|
|
from { background-position: 0 0; } |
|
|
to { background-position: 200px 200px; } |
|
|
} |
|
|
|
|
|
#intro-screen, #game-over-screen { |
|
|
position: absolute; |
|
|
top: 0; |
|
|
left: 0; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
justify-content: center; |
|
|
align-items: center; |
|
|
z-index: 1000; |
|
|
background-color: rgba(0, 0, 0, 0.8); |
|
|
text-align: center; |
|
|
} |
|
|
|
|
|
#game-screen { |
|
|
display: none; |
|
|
height: 100%; |
|
|
} |
|
|
|
|
|
.title { |
|
|
font-family: 'Orbitron', sans-serif; |
|
|
color: #ffe81f; |
|
|
text-shadow: 0 0 10px #ff6, 0 0 20px #ff6; |
|
|
font-size: 4rem; |
|
|
margin-bottom: 2rem; |
|
|
letter-spacing: 0.5rem; |
|
|
animation: pulse 2s infinite; |
|
|
} |
|
|
|
|
|
@keyframes pulse { |
|
|
0% { transform: scale(1); } |
|
|
50% { transform: scale(1.05); } |
|
|
100% { transform: scale(1); } |
|
|
} |
|
|
|
|
|
.scroll-text { |
|
|
position: relative; |
|
|
height: 60%; |
|
|
width: 60%; |
|
|
overflow: hidden; |
|
|
color: #ffe81f; |
|
|
font-family: 'Orbitron', sans-serif; |
|
|
font-size: 1.5rem; |
|
|
line-height: 1.5; |
|
|
text-align: justify; |
|
|
transform: perspective(300px) rotateX(20deg); |
|
|
text-align: center; |
|
|
} |
|
|
|
|
|
.scroll-content { |
|
|
position: absolute; |
|
|
top: 100%; |
|
|
animation: scroll 40s linear forwards; |
|
|
} |
|
|
|
|
|
@keyframes scroll { |
|
|
0% { top: 100%; } |
|
|
100% { top: -500%; } |
|
|
} |
|
|
|
|
|
.btn { |
|
|
background: linear-gradient(to right, #3a3a98, #1a1a4e); |
|
|
color: #ffe81f; |
|
|
border: 2px solid #ffe81f; |
|
|
padding: 1rem 2rem; |
|
|
font-family: 'Orbitron', sans-serif; |
|
|
font-size: 1.2rem; |
|
|
border-radius: 5px; |
|
|
cursor: pointer; |
|
|
transition: all 0.3s; |
|
|
margin-top: 2rem; |
|
|
box-shadow: 0 0 15px rgba(255, 232, 31, 0.5); |
|
|
} |
|
|
|
|
|
.btn:hover { |
|
|
background: linear-gradient(to right, #4e4eb8, #2a2a6e); |
|
|
transform: scale(1.05); |
|
|
box-shadow: 0 0 25px rgba(255, 232, 31, 0.8); |
|
|
} |
|
|
|
|
|
#player { |
|
|
position: absolute; |
|
|
width: 60px; |
|
|
height: 100px; |
|
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 150"><polygon points="50,0 0,100 20,100 50,30 80,100 100,100" fill="%23ffe81f"/><rect x="40" y="100" width="20" height="50" fill="%23ffe81f"/></svg>'); |
|
|
background-repeat: no-repeat; |
|
|
z-index: 10; |
|
|
transition: transform 0.1s; |
|
|
left: 50%; |
|
|
bottom: 100px; |
|
|
transform: translateX(-50%); |
|
|
} |
|
|
|
|
|
.asteroid { |
|
|
position: absolute; |
|
|
width: 50px; |
|
|
height: 50px; |
|
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="45" fill="%23666"/><path d="M30,30 Q40,20 50,30 Q60,20 70,30 Q75,40 70,50 Q75,60 70,70 Q60,75 50,70 Q40,75 30,70 Q25,60 30,50 Q25,40 30,30" fill="%23444"/></svg>'); |
|
|
background-repeat: no-repeat; |
|
|
z-index: 5; |
|
|
} |
|
|
|
|
|
.powerup { |
|
|
position: absolute; |
|
|
width: 40px; |
|
|
height: 40px; |
|
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="%2300ff00"/><circle cx="50" cy="50" r="30" fill="%23ffffff"/><circle cx="50" cy="50" r="20" fill="%2300ff00"/><circle cx="50" cy="50" r="10" fill="%23ffffff"/></svg>'); |
|
|
background-repeat: no-repeat; |
|
|
z-index: 5; |
|
|
animation: pulse 1s infinite; |
|
|
} |
|
|
|
|
|
#hud { |
|
|
position: absolute; |
|
|
top: 20px; |
|
|
left: 20px; |
|
|
z-index: 20; |
|
|
font-family: 'Orbitron', sans-serif; |
|
|
color: #ffe81f; |
|
|
display: flex; |
|
|
gap: 30px; |
|
|
} |
|
|
|
|
|
.hud-item { |
|
|
background-color: rgba(0, 0, 0, 0.7); |
|
|
padding: 10px 20px; |
|
|
border: 1px solid #ffe81f; |
|
|
border-radius: 5px; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 10px; |
|
|
} |
|
|
|
|
|
.laser { |
|
|
position: absolute; |
|
|
width: 5px; |
|
|
height: 30px; |
|
|
background-color: red; |
|
|
z-index: 6; |
|
|
border-radius: 5px; |
|
|
box-shadow: 0 0 10px red; |
|
|
} |
|
|
|
|
|
.explosion { |
|
|
position: absolute; |
|
|
width: 80px; |
|
|
height: 80px; |
|
|
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="%23ff0"/><path d="M30,30 Q50,10 70,30 Q90,50 70,70 Q50,90 30,70 Q10,50 30,30" fill="%23f00"/><path d="M40,40 Q50,30 60,40 Q70,50 60,60 Q50,70 40,60 Q30,50 40,40" fill="%23ff0"/></svg>'); |
|
|
background-repeat: no-repeat; |
|
|
z-index: 15; |
|
|
animation: explosion 0.5s forwards; |
|
|
} |
|
|
|
|
|
@keyframes explosion { |
|
|
0% { transform: scale(0); opacity: 1; } |
|
|
100% { transform: scale(2); opacity: 0; } |
|
|
} |
|
|
|
|
|
#score-display { |
|
|
font-size: 2rem; |
|
|
position: absolute; |
|
|
top: 20px; |
|
|
right: 20px; |
|
|
background-color: rgba(0, 0, 0, 0.7); |
|
|
padding: 10px 20px; |
|
|
border: 1px solid #ffe81f; |
|
|
border-radius: 5px; |
|
|
font-family: 'Orbitron', sans-serif; |
|
|
color: #ffe81f; |
|
|
} |
|
|
|
|
|
#audio-toggle { |
|
|
position: absolute; |
|
|
bottom: 20px; |
|
|
right: 20px; |
|
|
z-index: 100; |
|
|
background: rgba(0, 0, 0, 0.7); |
|
|
border: 1px solid #ffe81f; |
|
|
color: #ffe81f; |
|
|
width: 50px; |
|
|
height: 50px; |
|
|
border-radius: 50%; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
cursor: pointer; |
|
|
font-size: 1.5rem; |
|
|
} |
|
|
|
|
|
.instructions { |
|
|
color: #ffe81f; |
|
|
font-family: 'Prompt', sans-serif; |
|
|
margin-top: 2rem; |
|
|
max-width: 600px; |
|
|
padding: 0 2rem; |
|
|
} |
|
|
|
|
|
.instructions h2 { |
|
|
margin-bottom: 1rem; |
|
|
color: #00ff00; |
|
|
} |
|
|
|
|
|
.controls { |
|
|
display: flex; |
|
|
gap: 20px; |
|
|
margin-top: 1rem; |
|
|
} |
|
|
|
|
|
.control-key { |
|
|
background: rgba(255, 255, 255, 0.2); |
|
|
border: 1px solid #ffe81f; |
|
|
padding: 5px 10px; |
|
|
border-radius: 5px; |
|
|
font-family: 'Orbitron', sans-serif; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<div id="game-container"> |
|
|
<div class="stars"></div> |
|
|
|
|
|
<div id="intro-screen"> |
|
|
<h1 class="title">STAR WARS</h1> |
|
|
<h2 class="title" style="font-size: 2rem;">ASTEROID EVASION</h2> |
|
|
|
|
|
<div class="scroll-text"> |
|
|
<div class="scroll-content"> |
|
|
<p>Episode IV</p> |
|
|
<p>A NEW GAME</p> |
|
|
<br> |
|
|
<p>The galaxy is in turmoil as Rebel forces attempt to outrun the Imperial fleet through an asteroid field.</p> |
|
|
<br> |
|
|
<p>As a skilled pilot, your mission is to navigate the treacherous field, collecting power-ups to sustain your ship.</p> |
|
|
<br> |
|
|
<p>Beware of the asteroids that float menacingly through space - a single collision could mean the end of your journey...</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<button class="btn" id="start-game">BEGIN MISSION</button> |
|
|
|
|
|
<div class="instructions"> |
|
|
<h2>Mission Controls:</h2> |
|
|
<p>Use WASD or arrow keys to navigate your ship through the asteroid field.</p> |
|
|
<p>Collect power-ups to increase your score and survive longer.</p> |
|
|
<p>Press SPACE to fire lasers and destroy incoming asteroids.</p> |
|
|
|
|
|
<div class="controls"> |
|
|
<span class="control-key"><i class="fas fa-arrow-up"></i> / W</span> |
|
|
<span class="control-key"><i class="fas fa-arrow-left"></i> / A</span> |
|
|
<span class="control-key"><i class="fas fa-arrow-down"></i> / S</span> |
|
|
<span class="control-key"><i class="fas fa-arrow-right"></i> / D</span> |
|
|
<span class="control-key"><i class="fas fa-star"></i> SPACE</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="game-screen"> |
|
|
<div id="hud"> |
|
|
<div class="hud-item"> |
|
|
<i class="fas fa-heart" style="color: red;"></i> |
|
|
<span id="lives">3</span> |
|
|
</div> |
|
|
<div class="hud-item"> |
|
|
<i class="fas fa-bolt" style="color: #00ff00;"></i> |
|
|
<span id="energy">100%</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="score-display">SCORE: 0</div> |
|
|
|
|
|
<div id="player"></div> |
|
|
</div> |
|
|
|
|
|
<div id="game-over-screen" style="display: none;"> |
|
|
<h1 class="title">GAME OVER</h1> |
|
|
<p style="font-size: 1.5rem; margin-bottom: 1rem;">Final Score: <span id="final-score">0</span></p> |
|
|
<button class="btn" id="restart-game">RETRY MISSION</button> |
|
|
</div> |
|
|
|
|
|
<div id="audio-toggle"> |
|
|
<i class="fas fa-volume-up"></i> |
|
|
</div> |
|
|
|
|
|
<audio id="theme-music" loop> |
|
|
<source src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" type="audio/mpeg"> |
|
|
Your browser does not support the audio element. |
|
|
</audio> |
|
|
|
|
|
<audio id="laser-sound"> |
|
|
<source src="https://www.soundjay.com/buttons/sounds/button-09.mp3" type="audio/mpeg"> |
|
|
</audio> |
|
|
|
|
|
<audio id="explosion-sound"> |
|
|
<source src="https://www.soundjay.com/explosion-sounds/explosion-01.mp3" type="audio/mpeg"> |
|
|
</audio> |
|
|
|
|
|
<audio id="powerup-sound"> |
|
|
<source src="https://www.soundjay.com/buttons/sounds/button-21.mp3" type="audio/mpeg"> |
|
|
</audio> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
|
|
|
let gameActive = false; |
|
|
let score = 0; |
|
|
let lives = 3; |
|
|
let energy = 100; |
|
|
let playerSpeed = 5; |
|
|
let energyDrain = 0.1; |
|
|
let asteroids = []; |
|
|
let powerups = []; |
|
|
let lasers = []; |
|
|
let gameSpeed = 1; |
|
|
let asteroidSpawnRate = 2500; |
|
|
let powerupSpawnRate = 8000; |
|
|
let lastAsteroidSpawn = 0; |
|
|
let lastPowerupSpawn = 0; |
|
|
let keys = {}; |
|
|
let audioEnabled = true; |
|
|
let difficultyIncreaseInterval; |
|
|
|
|
|
|
|
|
const introScreen = document.getElementById('intro-screen'); |
|
|
const gameScreen = document.getElementById('game-screen'); |
|
|
const gameOverScreen = document.getElementById('game-over-screen'); |
|
|
const startButton = document.getElementById('start-game'); |
|
|
const restartButton = document.getElementById('restart-game'); |
|
|
const player = document.getElementById('player'); |
|
|
const livesDisplay = document.getElementById('lives'); |
|
|
const energyDisplay = document.getElementById('energy'); |
|
|
const scoreDisplay = document.getElementById('score-display'); |
|
|
const finalScoreDisplay = document.getElementById('final-score'); |
|
|
const themeMusic = document.getElementById('theme-music'); |
|
|
const laserSound = document.getElementById('laser-sound'); |
|
|
const explosionSound = document.getElementById('explosion-sound'); |
|
|
const powerupSound = document.getElementById('powerup-sound'); |
|
|
const audioToggle = document.getElementById('audio-toggle'); |
|
|
const gameContainer = document.getElementById('game-container'); |
|
|
|
|
|
|
|
|
const PLAYER_WIDTH = 60; |
|
|
const PLAYER_HEIGHT = 100; |
|
|
const GAME_WIDTH = window.innerWidth; |
|
|
const GAME_HEIGHT = window.innerHeight; |
|
|
|
|
|
|
|
|
function initGame() { |
|
|
|
|
|
score = 0; |
|
|
lives = 3; |
|
|
energy = 100; |
|
|
gameSpeed = 1; |
|
|
asteroidSpawnRate = 2500; |
|
|
|
|
|
|
|
|
asteroids.forEach(asteroid => asteroid.element.remove()); |
|
|
powerups.forEach(powerup => powerup.element.remove()); |
|
|
lasers.forEach(laser => laser.element.remove()); |
|
|
|
|
|
asteroids = []; |
|
|
powerups = []; |
|
|
lasers = []; |
|
|
|
|
|
|
|
|
updateHUD(); |
|
|
|
|
|
|
|
|
player.style.left = '50%'; |
|
|
player.style.bottom = '100px'; |
|
|
player.style.transform = 'translateX(-50%)'; |
|
|
|
|
|
|
|
|
introScreen.style.display = 'none'; |
|
|
gameOverScreen.style.display = 'none'; |
|
|
gameScreen.style.display = 'block'; |
|
|
|
|
|
|
|
|
gameActive = true; |
|
|
startGameLoop(); |
|
|
|
|
|
|
|
|
if (difficultyIncreaseInterval) clearInterval(difficultyIncreaseInterval); |
|
|
difficultyIncreaseInterval = setInterval(increaseDifficulty, 10000); |
|
|
|
|
|
|
|
|
if (audioEnabled) { |
|
|
themeMusic.currentTime = 0; |
|
|
themeMusic.play(); |
|
|
} |
|
|
|
|
|
|
|
|
gameScreen.focus(); |
|
|
} |
|
|
|
|
|
|
|
|
function gameLoop(timestamp) { |
|
|
if (!gameActive) return; |
|
|
|
|
|
|
|
|
movePlayer(); |
|
|
|
|
|
|
|
|
if (timestamp - lastAsteroidSpawn > asteroidSpawnRate) { |
|
|
spawnAsteroid(); |
|
|
lastAsteroidSpawn = timestamp; |
|
|
} |
|
|
|
|
|
|
|
|
if (timestamp - lastPowerupSpawn > powerupSpawnRate) { |
|
|
spawnPowerup(); |
|
|
lastPowerupSpawn = timestamp; |
|
|
} |
|
|
|
|
|
|
|
|
updateAsteroids(); |
|
|
|
|
|
|
|
|
updatePowerups(); |
|
|
|
|
|
|
|
|
updateLasers(); |
|
|
|
|
|
|
|
|
checkCollisions(); |
|
|
|
|
|
|
|
|
energy -= energyDrain; |
|
|
if (energy <= 0) { |
|
|
energy = 0; |
|
|
loseLife(); |
|
|
} |
|
|
|
|
|
|
|
|
updateHUD(); |
|
|
|
|
|
|
|
|
requestAnimationFrame(gameLoop); |
|
|
} |
|
|
|
|
|
function startGameLoop() { |
|
|
requestAnimationFrame(gameLoop); |
|
|
} |
|
|
|
|
|
|
|
|
function movePlayer() { |
|
|
const playerRect = player.getBoundingClientRect(); |
|
|
const gameRect = gameContainer.getBoundingClientRect(); |
|
|
let moveX = 0; |
|
|
let moveY = 0; |
|
|
|
|
|
|
|
|
if ((keys['ArrowLeft'] || keys['a'] || keys['A']) && playerRect.left > gameRect.left) { |
|
|
moveX = -playerSpeed; |
|
|
} |
|
|
if ((keys['ArrowRight'] || keys['d'] || keys['D']) && playerRect.right < gameRect.right) { |
|
|
moveX = playerSpeed; |
|
|
} |
|
|
|
|
|
|
|
|
if ((keys['ArrowUp'] || keys['w'] || keys['W']) && playerRect.top > gameRect.top) { |
|
|
moveY = -playerSpeed; |
|
|
} |
|
|
if ((keys['ArrowDown'] || keys['s'] || keys['S']) && playerRect.bottom < gameRect.bottom) { |
|
|
moveY = playerSpeed; |
|
|
} |
|
|
|
|
|
|
|
|
const currentLeft = parseFloat(player.style.left) || (GAME_WIDTH / 2 - PLAYER_WIDTH / 2); |
|
|
const currentBottom = parseFloat(player.style.bottom) || 100; |
|
|
|
|
|
player.style.left = `${currentLeft + moveX}px`; |
|
|
player.style.bottom = `${currentBottom + moveY}px`; |
|
|
|
|
|
|
|
|
if (moveX !== 0) { |
|
|
player.style.transform = `translateX(0) rotate(${moveX * 2}deg)`; |
|
|
} else { |
|
|
player.style.transform = 'translateX(0) rotate(0deg)'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function spawnAsteroid() { |
|
|
const asteroid = document.createElement('div'); |
|
|
asteroid.className = 'asteroid'; |
|
|
asteroid.style.width = `${Math.random() * 50 + 30}px`; |
|
|
asteroid.style.height = asteroid.style.width; |
|
|
|
|
|
const x = Math.random() * (GAME_WIDTH - 100) + 50; |
|
|
const speed = Math.random() * 3 + 2 * gameSpeed; |
|
|
|
|
|
asteroid.style.left = `${x}px`; |
|
|
asteroid.style.top = '-100px'; |
|
|
|
|
|
gameScreen.appendChild(asteroid); |
|
|
|
|
|
asteroids.push({ |
|
|
element: asteroid, |
|
|
x: x, |
|
|
y: -100, |
|
|
speed: speed, |
|
|
width: parseInt(asteroid.style.width), |
|
|
height: parseInt(asteroid.style.height) |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function spawnPowerup() { |
|
|
const powerup = document.createElement('div'); |
|
|
powerup.className = 'powerup'; |
|
|
|
|
|
const x = Math.random() * (GAME_WIDTH - 50) + 25; |
|
|
const speed = Math.random() * 2 + 1 * gameSpeed; |
|
|
|
|
|
powerup.style.left = `${x}px`; |
|
|
powerup.style.top = '-50px'; |
|
|
|
|
|
gameScreen.appendChild(powerup); |
|
|
|
|
|
powerups.push({ |
|
|
element: powerup, |
|
|
x: x, |
|
|
y: -50, |
|
|
speed: speed, |
|
|
width: 40, |
|
|
height: 40 |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function updateAsteroids() { |
|
|
const playerRect = player.getBoundingClientRect(); |
|
|
|
|
|
for (let i = asteroids.length - 1; i >= 0; i--) { |
|
|
const asteroid = asteroids[i]; |
|
|
asteroid.y += asteroid.speed; |
|
|
asteroid.element.style.top = `${asteroid.y}px`; |
|
|
|
|
|
|
|
|
if (asteroid.y > GAME_HEIGHT) { |
|
|
asteroid.element.remove(); |
|
|
asteroids.splice(i, 1); |
|
|
score += 5; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
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 > GAME_HEIGHT) { |
|
|
powerup.element.remove(); |
|
|
powerups.splice(i, 1); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function fireLaser() { |
|
|
if (energy < 5) return; |
|
|
|
|
|
energy -= 5; |
|
|
|
|
|
const laser = document.createElement('div'); |
|
|
laser.className = 'laser'; |
|
|
|
|
|
const playerRect = player.getBoundingClientRect(); |
|
|
const x = playerRect.left + playerRect.width / 2 - 2.5; |
|
|
const y = playerRect.top; |
|
|
|
|
|
laser.style.left = `${x}px`; |
|
|
laser.style.top = `${y}px`; |
|
|
|
|
|
gameScreen.appendChild(laser); |
|
|
|
|
|
lasers.push({ |
|
|
element: laser, |
|
|
x: x, |
|
|
y: y, |
|
|
speed: 10 * gameSpeed, |
|
|
width: 5, |
|
|
height: 30 |
|
|
}); |
|
|
|
|
|
if (audioEnabled) { |
|
|
laserSound.currentTime = 0; |
|
|
laserSound.play(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function updateLasers() { |
|
|
for (let i = lasers.length - 1; i >= 0; i--) { |
|
|
const laser = lasers[i]; |
|
|
laser.y -= laser.speed; |
|
|
laser.element.style.top = `${laser.y}px`; |
|
|
|
|
|
|
|
|
if (laser.y + laser.height < 0) { |
|
|
laser.element.remove(); |
|
|
lasers.splice(i, 1); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function checkCollisions() { |
|
|
const playerRect = player.getBoundingClientRect(); |
|
|
|
|
|
|
|
|
for (let i = lasers.length - 1; i >= 0; i--) { |
|
|
const laser = lasers[i]; |
|
|
const laserRect = laser.element.getBoundingClientRect(); |
|
|
|
|
|
for (let j = asteroids.length - 1; j >= 0; j--) { |
|
|
const asteroid = asteroids[j]; |
|
|
const asteroidRect = asteroid.element.getBoundingClientRect(); |
|
|
|
|
|
if (isColliding(laserRect, asteroidRect)) { |
|
|
|
|
|
createExplosion(asteroid.x + asteroid.width / 2, asteroid.y + asteroid.height / 2); |
|
|
|
|
|
|
|
|
laser.element.remove(); |
|
|
lasers.splice(i, 1); |
|
|
asteroid.element.remove(); |
|
|
asteroids.splice(j, 1); |
|
|
|
|
|
|
|
|
score += 20; |
|
|
|
|
|
|
|
|
if (audioEnabled) { |
|
|
explosionSound.currentTime = 0; |
|
|
explosionSound.play(); |
|
|
} |
|
|
|
|
|
|
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (let i = asteroids.length - 1; i >= 0; i--) { |
|
|
const asteroid = asteroids[i]; |
|
|
const asteroidRect = asteroid.element.getBoundingClientRect(); |
|
|
|
|
|
if (isColliding(playerRect, asteroidRect)) { |
|
|
|
|
|
createExplosion( |
|
|
asteroid.x + asteroid.width / 2, |
|
|
asteroid.y + asteroid.height / 2 |
|
|
); |
|
|
|
|
|
|
|
|
asteroid.element.remove(); |
|
|
asteroids.splice(i, 1); |
|
|
|
|
|
|
|
|
loseLife(); |
|
|
|
|
|
|
|
|
if (audioEnabled) { |
|
|
explosionSound.currentTime = 0; |
|
|
explosionSound.play(); |
|
|
} |
|
|
|
|
|
|
|
|
player.style.opacity = '0.5'; |
|
|
setTimeout(() => { |
|
|
player.style.opacity = '1'; |
|
|
}, 1000); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (let i = powerups.length - 1; i >= 0; i--) { |
|
|
const powerup = powerups[i]; |
|
|
const powerupRect = powerup.element.getBoundingClientRect(); |
|
|
|
|
|
if (isColliding(playerRect, powerupRect)) { |
|
|
|
|
|
powerup.element.remove(); |
|
|
powerups.splice(i, 1); |
|
|
|
|
|
|
|
|
energy = Math.min(100, energy + 20); |
|
|
score += 10; |
|
|
|
|
|
|
|
|
if (audioEnabled) { |
|
|
powerupSound.currentTime = 0; |
|
|
powerupSound.play(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function isColliding(rect1, rect2) { |
|
|
return !( |
|
|
rect1.right < rect2.left || |
|
|
rect1.left > rect2.right || |
|
|
rect1.bottom < rect2.top || |
|
|
rect1.top > rect2.bottom |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
function createExplosion(x, y) { |
|
|
const explosion = document.createElement('div'); |
|
|
explosion.className = 'explosion'; |
|
|
explosion.style.left = `${x - 40}px`; |
|
|
explosion.style.top = `${y - 40}px`; |
|
|
|
|
|
gameScreen.appendChild(explosion); |
|
|
|
|
|
setTimeout(() => { |
|
|
explosion.remove(); |
|
|
}, 500); |
|
|
} |
|
|
|
|
|
|
|
|
function loseLife() { |
|
|
lives--; |
|
|
|
|
|
if (lives <= 0) { |
|
|
gameOver(); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
energy = 100; |
|
|
} |
|
|
|
|
|
|
|
|
function gameOver() { |
|
|
gameActive = false; |
|
|
clearInterval(difficultyIncreaseInterval); |
|
|
|
|
|
|
|
|
themeMusic.pause(); |
|
|
|
|
|
|
|
|
gameScreen.style.display = 'none'; |
|
|
gameOverScreen.style.display = 'flex'; |
|
|
finalScoreDisplay.textContent = score; |
|
|
} |
|
|
|
|
|
|
|
|
function updateHUD() { |
|
|
livesDisplay.textContent = lives; |
|
|
energyDisplay.textContent = `${Math.max(0, Math.floor(energy))}%`; |
|
|
scoreDisplay.textContent = `SCORE: ${score}`; |
|
|
} |
|
|
|
|
|
|
|
|
function increaseDifficulty() { |
|
|
gameSpeed += 0.1; |
|
|
asteroidSpawnRate = Math.max(500, asteroidSpawnRate - 100); |
|
|
|
|
|
|
|
|
gameScreen.style.boxShadow = 'inset 0 0 50px rgba(255, 0, 0, 0.5)'; |
|
|
setTimeout(() => { |
|
|
gameScreen.style.boxShadow = 'none'; |
|
|
}, 500); |
|
|
} |
|
|
|
|
|
|
|
|
startButton.addEventListener('click', initGame); |
|
|
restartButton.addEventListener('click', initGame); |
|
|
|
|
|
audioToggle.addEventListener('click', () => { |
|
|
audioEnabled = !audioEnabled; |
|
|
if (audioEnabled) { |
|
|
audioToggle.innerHTML = '<i class="fas fa-volume-up"></i>'; |
|
|
if (gameActive) themeMusic.play(); |
|
|
} else { |
|
|
audioToggle.innerHTML = '<i class="fas fa-volume-mute"></i>'; |
|
|
themeMusic.pause(); |
|
|
} |
|
|
}); |
|
|
|
|
|
window.addEventListener('keydown', (e) => { |
|
|
keys[e.key] = true; |
|
|
|
|
|
|
|
|
if (gameActive && (e.key === ' ' || e.key === 'Spacebar')) { |
|
|
fireLaser(); |
|
|
} |
|
|
}); |
|
|
|
|
|
window.addEventListener('keyup', (e) => { |
|
|
keys[e.key] = false; |
|
|
}); |
|
|
|
|
|
|
|
|
window.addEventListener('keydown', (e) => { |
|
|
if (e.key === ' ' && e.target === document.body) { |
|
|
e.preventDefault(); |
|
|
} |
|
|
}); |
|
|
</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 <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> |
|
|
</html> |