183 lines
6.7 KiB
HTML
183 lines
6.7 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Space Invaders</title>
|
|
<link rel="stylesheet" href="style.css">
|
|
</head>
|
|
<body>
|
|
<a class="menu-link" href="index.html">← Menü</a>
|
|
<h1>SPACE INVADERS</h1>
|
|
<div class="hud">
|
|
<div>SCORE <span id="score-display">0</span></div>
|
|
<div>LIVES <span id="lives-display">3</span></div>
|
|
<div>BEST <span id="hs-display">0</span></div>
|
|
</div>
|
|
<canvas id="canvas" width="480" height="480"></canvas>
|
|
|
|
<div class="overlay" id="overlay">
|
|
<h2 id="overlay-title">GAME OVER</h2>
|
|
<p id="final-score"></p>
|
|
<button class="retro-btn" onclick="startGame()">NEU STARTEN</button>
|
|
<a class="retro-btn" href="index.html" style="text-decoration:none;text-align:center;">← MENÜ</a>
|
|
</div>
|
|
|
|
<script src="scores.js"></script>
|
|
<script>
|
|
const canvas = document.getElementById('canvas');
|
|
const ctx = canvas.getContext('2d');
|
|
const overlay = document.getElementById('overlay');
|
|
|
|
const COLS = 11, ROWS = 5;
|
|
const ALIEN_W = 32, ALIEN_H = 24, ALIEN_PAD_X = 10, ALIEN_PAD_Y = 16;
|
|
const ALIEN_POINTS = [30, 20, 20, 10, 10];
|
|
const PLAYER_W = 36, PLAYER_H = 16, PLAYER_Y = 440, PLAYER_SPEED = 5;
|
|
const BULLET_W = 3, BULLET_H = 12, BULLET_SPEED = 8;
|
|
const ENEMY_BULLET_SPEED = 4;
|
|
|
|
let player, bullets, enemyBullets, aliens, alienDir, alienSpeed, alienDropped;
|
|
let score, lives, animId, keys, lastEnemyShot, alienMoveTimer, alienMoveInterval;
|
|
|
|
function createAliens() {
|
|
const arr = [];
|
|
for (let r = 0; r < ROWS; r++)
|
|
for (let c = 0; c < COLS; c++)
|
|
arr.push({ x: c * (ALIEN_W + ALIEN_PAD_X) + 40, y: r * (ALIEN_H + ALIEN_PAD_Y) + 60, alive: true, row: r, col: c });
|
|
return arr;
|
|
}
|
|
|
|
function updateHUD() {
|
|
document.getElementById('score-display').textContent = score.toLocaleString('de-DE');
|
|
document.getElementById('lives-display').textContent = lives;
|
|
document.getElementById('hs-display').textContent = getHighscore('spaceinvaders').toLocaleString('de-DE');
|
|
}
|
|
|
|
function showOverlay(title) {
|
|
cancelAnimationFrame(animId);
|
|
setHighscore('spaceinvaders', score);
|
|
document.getElementById('overlay-title').textContent = title;
|
|
document.getElementById('final-score').textContent = 'SCORE: ' + score.toLocaleString('de-DE');
|
|
document.getElementById('hs-display').textContent = getHighscore('spaceinvaders').toLocaleString('de-DE');
|
|
overlay.style.display = 'flex';
|
|
}
|
|
|
|
function startGame() {
|
|
player = { x: 220 };
|
|
bullets = []; enemyBullets = [];
|
|
aliens = createAliens();
|
|
alienDir = 1; alienSpeed = 20; alienDropped = false;
|
|
score = 0; lives = 3;
|
|
keys = {}; lastEnemyShot = 0; alienMoveTimer = 0; alienMoveInterval = 800;
|
|
overlay.style.display = 'none';
|
|
updateHUD();
|
|
animId = requestAnimationFrame(loop);
|
|
}
|
|
|
|
function drawAlien(x, y, row) {
|
|
ctx.fillStyle = row === 0 ? '#fd79a8' : row < 3 ? '#a29bfe' : '#4ecca3';
|
|
ctx.fillRect(x + 4, y + 4, ALIEN_W - 8, ALIEN_H - 8);
|
|
ctx.fillStyle = '#1a1a2e';
|
|
ctx.fillRect(x + 8, y + 8, 4, 4);
|
|
ctx.fillRect(x + ALIEN_W - 12, y + 8, 4, 4);
|
|
}
|
|
|
|
function loop(timestamp) {
|
|
// Spieler bewegen
|
|
if (keys['ArrowLeft']) player.x = Math.max(0, player.x - PLAYER_SPEED);
|
|
if (keys['ArrowRight']) player.x = Math.min(canvas.width - PLAYER_W, player.x + PLAYER_SPEED);
|
|
|
|
// Spieler-Bullets
|
|
bullets.forEach(b => b.y -= BULLET_SPEED);
|
|
bullets = bullets.filter(b => b.y > 0);
|
|
|
|
// Alien-Bewegung
|
|
alienMoveTimer += 16;
|
|
if (alienMoveTimer >= alienMoveInterval) {
|
|
alienMoveTimer = 0;
|
|
const alive = aliens.filter(a => a.alive);
|
|
const maxX = Math.max(...alive.map(a => a.x));
|
|
const minX = Math.min(...alive.map(a => a.x));
|
|
if ((alienDir > 0 && maxX + ALIEN_W >= canvas.width - 10) ||
|
|
(alienDir < 0 && minX <= 10)) {
|
|
aliens.forEach(a => { a.y += 20; });
|
|
alienDir *= -1;
|
|
alienMoveInterval = Math.max(100, alienMoveInterval - 30);
|
|
} else {
|
|
aliens.forEach(a => { a.x += alienDir * alienSpeed; });
|
|
}
|
|
}
|
|
|
|
// Alien beschießt Spieler zufällig
|
|
if (timestamp - lastEnemyShot > 1200) {
|
|
lastEnemyShot = timestamp;
|
|
const alive = aliens.filter(a => a.alive);
|
|
if (alive.length) {
|
|
const shooter = alive[Math.floor(Math.random() * alive.length)];
|
|
enemyBullets.push({ x: shooter.x + ALIEN_W / 2, y: shooter.y + ALIEN_H });
|
|
}
|
|
}
|
|
enemyBullets.forEach(b => b.y += ENEMY_BULLET_SPEED);
|
|
enemyBullets = enemyBullets.filter(b => b.y < canvas.height);
|
|
|
|
// Kollision: Spieler-Bullets vs Aliens
|
|
bullets.forEach(bull => {
|
|
aliens.forEach(a => {
|
|
if (!a.alive) return;
|
|
if (bull.x > a.x && bull.x < a.x + ALIEN_W && bull.y > a.y && bull.y < a.y + ALIEN_H) {
|
|
a.alive = false;
|
|
bull.y = -100;
|
|
score += ALIEN_POINTS[a.row];
|
|
updateHUD();
|
|
}
|
|
});
|
|
});
|
|
|
|
// Kollision: Alien-Bullets vs Spieler
|
|
enemyBullets.forEach(b => {
|
|
if (b.x > player.x && b.x < player.x + PLAYER_W && b.y > PLAYER_Y && b.y < PLAYER_Y + PLAYER_H) {
|
|
b.y = canvas.height + 1;
|
|
lives--;
|
|
updateHUD();
|
|
}
|
|
});
|
|
if (lives <= 0) { showOverlay('GAME OVER'); return; }
|
|
|
|
// Aliens erreichen Boden
|
|
if (aliens.some(a => a.alive && a.y + ALIEN_H >= PLAYER_Y)) { showOverlay('GAME OVER'); return; }
|
|
|
|
// Alle Aliens besiegt
|
|
if (!aliens.some(a => a.alive)) { showOverlay('GEWONNEN!'); return; }
|
|
|
|
// Zeichnen
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
aliens.forEach(a => { if (a.alive) drawAlien(a.x, a.y, a.row); });
|
|
ctx.fillStyle = '#4ecca3';
|
|
ctx.beginPath();
|
|
ctx.moveTo(player.x + PLAYER_W / 2, PLAYER_Y);
|
|
ctx.lineTo(player.x, PLAYER_Y + PLAYER_H);
|
|
ctx.lineTo(player.x + PLAYER_W, PLAYER_Y + PLAYER_H);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
ctx.fillStyle = '#4ecca3';
|
|
bullets.forEach(b => ctx.fillRect(b.x, b.y, BULLET_W, BULLET_H));
|
|
ctx.fillStyle = '#ff6b6b';
|
|
enemyBullets.forEach(b => ctx.fillRect(b.x, b.y, BULLET_W, BULLET_H));
|
|
|
|
if (lives > 0) animId = requestAnimationFrame(loop);
|
|
}
|
|
|
|
document.addEventListener('keydown', e => {
|
|
keys[e.key] = true;
|
|
if (e.key === ' ' && overlay.style.display !== 'flex') {
|
|
e.preventDefault();
|
|
if (bullets.length < 3) bullets.push({ x: player.x + PLAYER_W / 2 - BULLET_W / 2, y: PLAYER_Y });
|
|
}
|
|
});
|
|
document.addEventListener('keyup', e => { keys[e.key] = false; });
|
|
|
|
document.getElementById('hs-display').textContent = getHighscore('spaceinvaders').toLocaleString('de-DE');
|
|
startGame();
|
|
</script>
|
|
</body>
|
|
</html>
|