Invaders / index.html
Luis-Filipe's picture
Update index.html
c655c61 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Space Invaders - Arcade Edition</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #000;
color: #0f0;
font-family: 'Orbitron', monospace;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
overflow: hidden;
}
.arcade-container {
background: #111;
border: 4px solid #333;
border-radius: 10px;
padding: 20px;
box-shadow: 0 0 30px rgba(0, 255, 0, 0.3);
}
.game-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding: 10px;
background: #222;
border: 2px solid #444;
border-radius: 5px;
}
.score-display, .lives-display, .level-display {
font-size: 18px;
font-weight: 700;
text-shadow: 0 0 10px currentColor;
}
.score-display {
color: #0ff;
}
.lives-display {
color: #f0f;
}
.level-display {
color: #ff0;
}
#gameCanvas {
border: 3px solid #0f0;
background: #000;
display: block;
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
image-rendering: crisp-edges;
}
.controls {
margin-top: 15px;
text-align: center;
font-size: 14px;
color: #888;
}
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.9);
border: 3px solid #f00;
border-radius: 10px;
padding: 30px;
text-align: center;
display: none;
z-index: 1000;
}
.game-over h2 {
color: #f00;
font-size: 32px;
margin-bottom: 20px;
text-shadow: 0 0 20px currentColor;
}
.game-over p {
color: #0f0;
font-size: 20px;
margin-bottom: 20px;
}
.restart-btn {
background: #0f0;
color: #000;
border: none;
padding: 15px 30px;
font-family: 'Orbitron', monospace;
font-size: 18px;
font-weight: 700;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s;
}
.restart-btn:hover {
background: #0ff;
box-shadow: 0 0 20px rgba(0, 255, 255, 0.5);
}
.start-screen {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.95);
border: 3px solid #0f0;
border-radius: 10px;
padding: 40px;
text-align: center;
z-index: 1000;
}
.start-screen h1 {
color: #0f0;
font-size: 36px;
margin-bottom: 20px;
text-shadow: 0 0 30px currentColor;
}
.start-screen p {
color: #0ff;
font-size: 16px;
margin-bottom: 30px;
line-height: 1.6;
}
</style>
</head>
<body>
<div class="arcade-container">
<div class="game-header">
<div class="score-display">SCORE: <span id="score">0</span></div>
<div class="level-display">LEVEL: <span id="level">1</span></div>
<div class="lives-display">LIVES: <span id="lives">3</span></div>
</div>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<div class="controls">
Use ← → ARROWS to move • SPACEBAR to shoot • ENTER to start/pause
</div>
</div>
<div class="start-screen" id="startScreen">
<h1>SPACE INVADERS</h1>
<p>
Defend Earth from alien invasion!<br>
Destroy all invaders before they reach you.<br>
Each level gets faster and more challenging.
</p>
<button class="restart-btn" onclick="startGame()">START GAME</button>
</div>
<div class="game-over" id="gameOverScreen">
<h2>GAME OVER</h2>
<p>Final Score: <span id="finalScore">0</span></p>
<button class="restart-btn" onclick="restartGame()">PLAY AGAIN</button>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// Game state
let gameRunning = false;
let gamePaused = false;
let score = 0;
let lives = 3;
let level = 1;
let invaderDirection = 1;
let invaderSpeed = 0.5;
let lastTime = 0;
// Game objects
const player = {
x: canvas.width / 2 - 25,
y: canvas.height - 60,
width: 50,
height: 30,
speed: 5
};
const bullets = [];
const invaderBullets = [];
const invaders = [];
const particles = [];
// Input handling
const keys = {};
document.addEventListener('keydown', (e) => {
keys[e.code] = true;
if (e.code === 'Enter') {
if (!gameRunning) startGame();
else gamePaused = !gamePaused;
}
});
document.addEventListener('keyup', (e) => {
keys[e.code] = false;
});
// Initialize invaders
function createInvaders() {
invaders.length = 0;
const rows = 5;
const cols = 11;
const invaderWidth = 40;
const invaderHeight = 30;
const spacing = 15;
const startX = 50;
const startY = 50;
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
invaders.push({
x: startX + col * (invaderWidth + spacing),
y: startY + row * (invaderHeight + spacing),
width: invaderWidth,
height: invaderHeight,
type: row < 2 ? 'strong' : 'normal',
points: row < 2 ? 20 : 10
});
}
}
}
// Create particle effect
function createParticles(x, y, color) {
for (let i = 0; i < 8; i++) {
particles.push({
x: x,
y: y,
vx: (Math.random() - 0.5) * 6,
vy: (Math.random() - 0.5) * 6,
life: 30,
color: color
});
}
}
// Draw player
function drawPlayer() {
ctx.fillStyle = '#0f0';
// Player ship design
ctx.fillRect(player.x + 20, player.y, 10, 20);
ctx.fillRect(player.x + 10, player.y + 10, 30, 15);
ctx.fillRect(player.x, player.y + 20, 50, 10);
// Add glow effect
ctx.shadowColor = '#0f0';
ctx.shadowBlur = 10;
ctx.fillRect(player.x + 20, player.y + 5, 10, 5);
ctx.shadowBlur = 0;
}
// Draw invader
function drawInvader(invader) {
ctx.fillStyle = invader.type === 'strong' ? '#f0f' : '#0ff';
// Simple invader design
const centerX = invader.x + invader.width / 2;
const centerY = invader.y + invader.height / 2;
// Body
ctx.fillRect(invader.x + 5, invader.y + 5, invader.width - 10, invader.height - 10);
// Eyes
ctx.fillStyle = '#000';
ctx.fillRect(invader.x + 10, invader.y + 10, 8, 8);
ctx.fillRect(invader.x + invader.width - 18, invader.y + 10, 8, 8);
// Antennas
ctx.strokeStyle = invader.type === 'strong' ? '#f0f' : '#0ff';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(invader.x + 10, invader.y);
ctx.lineTo(invader.x + 5, invader.y - 5);
ctx.moveTo(invader.x + invader.width - 10, invader.y);
ctx.lineTo(invader.x + invader.width - 5, invader.y - 5);
ctx.stroke();
}
// Draw bullet
function drawBullet(bullet, isPlayer = true) {
ctx.fillStyle = isPlayer ? '#ff0' : '#f00';
ctx.shadowColor = isPlayer ? '#ff0' : '#f00';
ctx.shadowBlur = 5;
ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
ctx.shadowBlur = 0;
}
// Draw particles
function drawParticles() {
particles.forEach((particle, index) => {
if (particle.life <= 0) {
particles.splice(index, 1);
return;
}
ctx.fillStyle = particle.color;
ctx.globalAlpha = particle.life / 30;
ctx.fillRect(particle.x, particle.y, 3, 3);
ctx.globalAlpha = 1;
particle.x += particle.vx;
particle.y += particle.vy;
particle.life--;
});
}
// Update game logic
function update(deltaTime) {
if (!gameRunning || gamePaused) return;
// Player movement
if (keys['ArrowLeft'] && player.x > 0) {
player.x -= player.speed;
}
if (keys['ArrowRight'] && player.x < canvas.width - player.width) {
player.x += player.speed;
}
// Player shooting
if (keys['Space']) {
if (bullets.length === 0 || bullets[bullets.length - 1].y < player.y - 50) {
bullets.push({
x: player.x + player.width / 2 - 2,
y: player.y,
width: 4,
height: 10,
speed: 8
});
}
}
// Update bullets
bullets.forEach((bullet, index) => {
bullet.y -= bullet.speed;
if (bullet.y < 0) {
bullets.splice(index, 1);
}
});
// Update invader bullets
invaderBullets.forEach((bullet, index) => {
bullet.y += bullet.speed;
if (bullet.y > canvas.height) {
invaderBullets.splice(index, 1);
}
});
// Update invaders
let shouldDrop = false;
invaders.forEach(invader => {
invader.x += invaderDirection * invaderSpeed;
if (invader.x <= 0 || invader.x + invader.width >= canvas.width) {
shouldDrop = true;
}
});
if (shouldDrop) {
invaderDirection *= -1;
invaders.forEach(invader => {
invader.y += 20;
});
}
// Invader shooting
if (Math.random() < 0.001 * level && invaders.length > 0) {
const shooter = invaders[Math.floor(Math.random() * invaders.length)];
invaderBullets.push({
x: shooter.x + shooter.width / 2 - 2,
y: shooter.y + shooter.height,
width: 4,
height: 8,
speed: 3
});
}
// Collision detection - bullets vs invaders
bullets.forEach((bullet, bulletIndex) => {
invaders.forEach((invader, invaderIndex) => {
if (bullet.x < invader.x + invader.width &&
bullet.x + bullet.width > invader.x &&
bullet.y < invader.y + invader.height &&
bullet.y + bullet.height > invader.y) {
createParticles(invader.x + invader.width / 2, invader.y + invader.height / 2, '#0ff');
bullets.splice(bulletIndex, 1);
invaders.splice(invaderIndex, 1);
score += invader.points;
updateUI();
}
});
});
// Collision detection - invader bullets vs player
invaderBullets.forEach((bullet, index) => {
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) {
createParticles(player.x + player.width / 2, player.y + player.height / 2, '#0f0');
invaderBullets.splice(index, 1);
lives--;
updateUI();
if (lives <= 0) {
gameOver();
}
}
});
// Check if invaders reached player
invaders.forEach(invader => {
if (invader.y + invader.height >= player.y) {
gameOver();
}
});
// Check if all invaders destroyed
if (invaders.length === 0) {
nextLevel();
}
}
// Render game
function render() {
// Clear canvas
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw stars
ctx.fillStyle = '#fff';
for (let i = 0; i < 50; i++) {
const x = (i * 137.5) % canvas.width;
const y = (i * 234.7) % canvas.height;
ctx.fillRect(x, y, 1, 1);
}
// Draw game objects
drawPlayer();
invaders.forEach(drawInvader);
bullets.forEach(bullet => drawBullet(bullet, true));
invaderBullets.forEach(bullet => drawBullet(bullet, false));
drawParticles();
// Draw pause text
if (gamePaused) {
ctx.fillStyle = '#0f0';
ctx.font = '48px Orbitron';
ctx.textAlign = 'center';
ctx.fillText('PAUSED', canvas.width / 2, canvas.height / 2);
ctx.textAlign = 'left';
}
}
// Game loop
function gameLoop(currentTime) {
const deltaTime = currentTime - lastTime;
lastTime = currentTime;
update(deltaTime);
render();
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';
document.getElementById('gameOverScreen').style.display = 'none';
gameRunning = true;
gamePaused = false;
score = 0;
lives = 3;
level = 1;
invaderSpeed = 0.5;
bullets.length = 0;
invaderBullets.length = 0;
particles.length = 0;
player.x = canvas.width / 2 - 25;
player.y = canvas.height - 60;
createInvaders();
updateUI();
}
// Next level
function nextLevel() {
level++;
invaderSpeed += 0.2;
createInvaders();
updateUI();
}
// Game over
function gameOver() {
gameRunning = false;
document.getElementById('finalScore').textContent = score;
document.getElementById('gameOverScreen').style.display = 'block';
}
// Restart game
function restartGame() {
startGame();
}
// Initialize game
updateUI();
requestAnimationFrame(gameLoop);
</script>
</body>
</html>