<!
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Space Invaders</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Courier New', monospace;
background: #000;
color: #0f0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
position: relative;
}
/* Starfield background */
.stars {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.star {
position: absolute;
background: white;
border-radius: 50%;
animation: twinkle 3s infinite;
}
@keyframes twinkle {
0%, 100% { opacity: 0.3; }
50% { opacity: 1; }
}
/* Game container */
.game-container {
position: relative;
border: 2px solid #0f0;
box-shadow: 0 0 20px #0f0;
background: rgba(0, 0, 0, 0.8);
}
canvas {
display: block;
image-rendering: pixelated;
}
/* UI Overlay */
.ui-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
padding: 10px;
display: flex;
justify-content: space-between;
font-size: 18px;
text-shadow: 0 0 5px #0f0;
pointer-events: none;
}
.score, .lives, .level {
background: rgba(0, 0, 0, 0.7);
padding: 5px 15px;
border: 1px solid #0f0;
border-radius: 5px;
}
/* Game over screen */
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
display: none;
background: rgba(0, 0, 0, 0.9);
padding: 30px;
border: 2px solid #0f0;
border-radius: 10px;
box-shadow: 0 0 30px #0f0;
}
.game-over h2 {
font-size: 48px;
margin-bottom: 20px;
text-shadow: 0 0 10px #0f0;
}
.game-over p {
font-size: 24px;
margin-bottom: 30px;
}
.game-over button {
font-family: 'Courier New', monospace;
font-size: 20px;
padding: 10px 30px;
background: #000;
color: #0f0;
border: 2px solid #0f0;
cursor: pointer;
transition: all 0.3s;
}
.game-over button:hover {
background: #0f0;
color: #000;
box-shadow: 0 0 20px #0f0;
}
/* Start screen */
.start-screen {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.9);
z-index: 10;
}
.start-screen h1 {
font-size: 64px;
margin-bottom: 20px;
text-shadow: 0 0 20px #0f0;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.start-screen p {
font-size: 20px;
margin-bottom: 30px;
text-align: center;
line-height: 1.5;
}
.start-screen button {
font-family: 'Courier New', monospace;
font-size: 24px;
padding: 15px 40px;
background: #000;
color: #0f0;
border: 2px solid #0f0;
cursor: pointer;
transition: all 0.3s;
margin-bottom: 20px;
}
.start-screen button:hover {
background: #0f0;
color: #000;
box-shadow: 0 0 30px #0f0;
}
.controls {
font-size: 16px;
opacity: 0.7;
}
</style>
</head>
<body>
<!-- Starfield background -->
<div class="stars" id="stars"></div>
<!-- Game container -->
<div class="game-container">
<canvas id="gameCanvas" width="800" height="600"></canvas>
<!-- UI Overlay -->
<div class="ui-overlay">
<div class="score">SCORE: <span id="score">0</span></div>
<div class="level">LEVEL: <span id="level">1</span></div>
<div class="lives">LIVES: <span id="lives">3</span></div>
</div>
<!-- Start screen -->
<div class="start-screen" id="startScreen">
<h1>SPACE INVADERS</h1>
<button onclick="startGame()">START GAME</button>
<div class="controls">
<p>← → Arrow Keys: Move</p>
<p>SPACE: Shoot</p>
<p>P: Pause</p>
</div>
</div>
<!-- Game over screen -->
<div class="game-over" id="gameOver">
<h2 id="gameOverTitle">GAME OVER</h2>
<p>Final Score: <span id="finalScore">0</span></p>
<button onclick="restartGame()">PLAY AGAIN</button>
</div>
</div>
<script>
// Create starfield
function createStars() {
const starsContainer = document.getElementById('stars');
for (let i = 0; i < 100; i++) {
const star = document.createElement('div');
star.className = 'star';
star.style.left = Math.random() * 100 + '%';
star.style.top = Math.random() * 100 + '%';
star.style.width = star.style.height = Math.random() * 3 + 'px';
star.style.animationDelay = Math.random() * 3 + 's';
starsContainer.appendChild(star);
}
}
createStars();
// Game variables
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
let gameRunning = false;
let gamePaused = false;
let score = 0;
let lives = 3;
let level = 1;
let alienDirection = 1;
let alienDropDistance = 20;
let lastAlienShot = 0;
let alienShootInterval = 2000;
// Player
const player = {
x: canvas.width / 2 - 25,
y: canvas.height - 60,
width: 50,
height: 30,
speed: 5,
color: '#0f0'
};
// Arrays for game objects
let bullets = [];
let alienBullets = [];
let aliens = [];
let particles = [];
// Input handling
const keys = {};
document.addEventListener('keydown', (e) => {
keys[e.key] = true;
if (e.key === ' ') {
e.preventDefault();
if (gameRunning && !gamePaused) shoot();
}
if (e.key === 'p' || e.key === 'P') {
togglePause();
}
});
document.addEventListener('keyup', (e) => {
keys[e.key] = false;
});
// Create aliens
function createAliens() {
aliens = [];
const rows = 5;
const cols = 10;
const alienWidth = 40;
const alienHeight = 30;
const spacing = 10;
const startX = (canvas.width - (cols * (alienWidth + spacing))) / 2;
const startY = 50;
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
aliens.push({
x: startX + col * (alienWidth + spacing),
y: startY + row * (alienHeight + spacing),
width: alienWidth,
height: alienHeight,
type: row < 2 ? 'strong' : row < 4 ? 'medium' : 'weak',
points: row < 2 ? 30 : row < 4 ? 20 : 10,
color: row < 2 ? '#f0f' : row < 4 ? '#ff0' : '#0ff'
});
}
}
}
// Shoot bullet
function shoot() {
if (bullets.length < 3) { // Limit bullets
bullets.push({
x: player.x + player.width / 2 - 2,
y: player.y,
width: 4,
height: 10,
speed: 7,
color: '#0f0'
});
}
}
// Alien shoot
function alienShoot() {
if (aliens.length > 0 && Date.now() - lastAlienShot >
alienShootInterval) {
const shooter = aliens[Math.floor(Math.random() * aliens.length)];
alienBullets.push({
x: shooter.x + shooter.width / 2 - 2,
y: shooter.y + shooter.height,
width: 4,
height: 10,
speed: 3 + level * 0.5,
color: '#f00'
});
lastAlienShot = Date.now();
alienShootInterval = Math.max(500, 2000 - level * 200);
}
}
// Create explosion particles
function createExplosion(x, y, color) {
for (let i = 0; i < 10; i++) {
particles.push({
x: x,
y: y,
vx: (Math.random() - 0.5) * 5,
vy: (Math.random() - 0.5) * 5,
size: Math.random() * 3 + 1,
life: 1,
color: color
});
}
}
// Update game
function update() {
if (!gameRunning || gamePaused) return;
// Move player
if (keys['ArrowLeft'] && player.x > 0) {
player.x -= player.speed;
}
if (keys['ArrowRight'] && player.x < canvas.width - player.width) {
player.x += player.speed;
}
// Update bullets
bullets = bullets.filter(bullet => {
bullet.y -= bullet.speed;
return bullet.y > -bullet.height;
});
// Update alien bullets
alienBullets = alienBullets.filter(bullet => {
bullet.y += bullet.speed;
return bullet.y < canvas.height;
});
// Move aliens
let shouldDrop = false;
aliens.forEach(alien => {
alien.x += alienDirection * (0.5 + level * 0.1);
if (alien.x <= 0 || alien.x >= canvas.width - alien.width) {
shouldDrop = true;
}
});
if (shouldDrop) {
alienDirection *= -1;
aliens.forEach(alien => {
alien.y += alienDropDistance;
if (alien.y + alien.height >= player.y) {
gameOver(false);
}
});
}
// Alien shooting
alienShoot();
// Check bullet-alien collisions
bullets.forEach((bullet, bulletIndex) => {
aliens.forEach((alien, alienIndex) => {
if (bullet.x < alien.x + alien.width &&
bullet.x + bullet.width > alien.x &&
bullet.y < alien.y + alien.height &&
bullet.y + bullet.height > alien.y) {
// Hit!
createExplosion(alien.x + alien.width/2, alien.y +
alien.height/2, alien.color);
score += alien.points;
updateUI();
bullets.splice(bulletIndex, 1);
aliens.splice(alienIndex, 1);
// Check win
if (aliens.length === 0) {
nextLevel();
}
}
});
});
// Check alien bullet-player collisions
alienBullets.forEach((bullet, bulletIndex) => {
if (bullet.x < player.x + player.width &&
bullet.x + bullet.width > player.x &&
bullet.y < player.y + player.height &&
bullet.y + bullet.height > player.y) {
// Hit!
createExplosion(player.x + player.width/2, player.y +
player.height/2, '#0f0');
lives--;
updateUI();
alienBullets.splice(bulletIndex, 1);
if (lives <= 0) {
gameOver(false);
}
}
});
// Update particles
particles = particles.filter(particle => {
particle.x += particle.vx;
particle.y += particle.vy;
particle.life -= 0.02;
particle.size *= 0.98;
return particle.life > 0;
});
}
// Draw game
function draw() {
// Clear canvas
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw player
ctx.fillStyle = player.color;
ctx.fillRect(player.x, player.y, player.width, player.height);
// Player cannon
ctx.fillRect(player.x + player.width/2 - 3, player.y - 10, 6, 10);
// Draw aliens
aliens.forEach(alien => {
ctx.fillStyle = alien.color;
ctx.fillRect(alien.x, alien.y, alien.width, alien.height);
// Alien details
ctx.fillStyle = '#000';
ctx.fillRect(alien.x + 5, alien.y + 5, 5, 5);
ctx.fillRect(alien.x + alien.width - 10, alien.y + 5, 5, 5);
ctx.fillRect(alien.x + alien.width/2 - 2, alien.y + alien.height -
5, 4, 5);
});
// Draw bullets
bullets.forEach(bullet => {
ctx.fillStyle = bullet.color;
ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
});
// Draw alien bullets
alienBullets.forEach(bullet => {
ctx.fillStyle = bullet.color;
ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
});
// Draw particles
particles.forEach(particle => {
ctx.fillStyle = particle.color;
ctx.globalAlpha = particle.life;
ctx.fillRect(particle.x, particle.y, particle.size, particle.size);
ctx.globalAlpha = 1;
});
// Draw pause indicator
if (gamePaused) {
ctx.fillStyle = '#0f0';
ctx.font = '48px Courier New';
ctx.textAlign = 'center';
ctx.fillText('PAUSED', canvas.width/2, canvas.height/2);
}
}
// Game loop
function gameLoop() {
update();
draw();
requestAnimationFrame(gameLoop);
}
// Update UI
function updateUI() {
document.getElementById('score').textContent = score;
document.getElementById('lives').textContent = lives;
document.getElementById('level').textContent = level;
}
// Start game
function startGame() {
document.getElementById('startScreen').style.display = 'none';
gameRunning = true;
score = 0;
lives = 3;
level = 1;
bullets = [];
alienBullets = [];
particles = [];
createAliens();
updateUI();
}
// Next level
function nextLevel() {
level++;
createAliens();
alienShootInterval = Math.max(500, 2000 - level * 200);
updateUI();
}
// Game over
function gameOver(won) {
gameRunning = false;
document.getElementById('gameOverTitle').textContent = won ? 'YOU WIN!'
: 'GAME OVER';
document.getElementById('finalScore').textContent = score;
document.getElementById('gameOver').style.display = 'block';
}
// Restart game
function restartGame() {
document.getElementById('gameOver').style.display = 'none';
startGame();
}
// Toggle pause
function togglePause() {
if (gameRunning) {
gamePaused = !gamePaused;
}
}
// Start game loop
gameLoop();
</script>
</body>
</html>