Here is free Space Invaders game source code built with HTML, CSS and JavaScript. Learn how to create and customize a classic HTML5 space game.
If you want to build a classic arcade-style browser game using HTML, CSS, and JavaScript, this Space Invaders game is a fun project to start with.
The game is inspired by the classic space shooter idea. The player controls a spaceship at the bottom of the screen and shoots incoming alien enemies before they reach the bottom.
Space Invaders Game Source Code Features
This version uses HTML5 Canvas and vanilla JavaScript. There are no external libraries or frameworks required, so the complete game can run from a single HTML file.
It is also a useful project for beginners because the code demonstrates movement, shooting, enemy formations, collision detection, score tracking, and a basic game loop.
Space Invaders is a classic arcade-style shooting game.
The basic idea is simple. A group of enemies moves across the screen while the player controls a spaceship below them.
The player shoots bullets toward the enemies. Every time an enemy is hit, the player receives points.
The challenge becomes greater as the enemies move closer to the player.
For a beginner learning JavaScript game development, this type of project is useful because it combines several different programming concepts in one game.
Features of This Space Invaders Game
This free Space Invaders game includes:
- HTML5 Canvas
- Player spaceship
- Multiple enemy aliens
- Shooting system
- Keyboard controls
- Check movement
- Move detection
- Score counter
- Lives system
- Game over screen
- Restart button
- Increasing difficulty
- Responsive canvas
- No external libraries
- Single HTML file
Free Space Invaders Game Source Code
The complete source code is provided below.
Create a file named index.html, paste the code into it, save it, and open the file in your browser.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Space Invaders Game</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
background:
radial-gradient(circle at top, #172554, #020617 65%);
color: white;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.game-container {
width: 100%;
max-width: 760px;
text-align: center;
}
h1 {
font-size: 38px;
margin-bottom: 8px;
}
.description {
color: #cbd5e1;
margin-bottom: 18px;
}
.score-board {
display: flex;
justify-content: space-between;
gap: 12px;
margin-bottom: 15px;
}
.score-box {
flex: 1;
padding: 10px;
background: rgba(255,255,255,0.08);
border: 1px solid #334155;
border-radius: 8px;
font-weight: bold;
}
.game-wrapper {
background: #000;
padding: 8px;
border-radius: 14px;
border: 2px solid #334155;
}
canvas {
display: block;
width: 100%;
height: auto;
background: #020617;
border-radius: 8px;
}
.controls {
margin-top: 15px;
color: #cbd5e1;
line-height: 1.7;
}
.start-btn {
margin-top: 18px;
padding: 12px 28px;
border: none;
border-radius: 9px;
background: #2563eb;
color: white;
font-size: 17px;
font-weight: bold;
cursor: pointer;
}
.start-btn:hover {
background: #1d4ed8;
}
@media (max-width: 550px) {
h1 {
font-size: 30px;
}
.score-board {
font-size: 14px;
}
}
</style>
</head>
<body>
<div class="game-container">
<h1>Space Invaders</h1>
<p class="description">
Destroy the aliens before they reach your spaceship.
</p>
<div class="score-board">
<div class="score-box">
Score:
<span id="score">0</span>
</div>
<div class="score-box">
Lives:
<span id="lives">3</span>
</div>
</div>
<div class="game-wrapper">
<canvas
id="gameCanvas"
width="700"
height="600">
</canvas>
</div>
<div class="controls">
Move with
<strong>Arrow Left / Arrow Right</strong>
and shoot with
<strong>Space</strong>.
</div>
<button
class="start-btn"
id="startBtn">
Start Game
</button>
</div>
<script>
const canvas =
document.getElementById("gameCanvas");
const ctx =
canvas.getContext("2d");
const scoreElement =
document.getElementById("score");
const livesElement =
document.getElementById("lives");
const startBtn =
document.getElementById("startBtn");
const player = {
width: 55,
height: 20,
x: canvas.width / 2 - 27,
y: canvas.height - 50,
speed: 6
};
let bullets = [];
let enemies = [];
let score = 0;
let lives = 3;
let gameRunning = false;
let gameOver = false;
let animationFrame;
let enemyDirection = 1;
let enemySpeed = 0.7;
let lastShot = 0;
const keys = {};
function createEnemies() {
enemies = [];
const rows = 4;
const columns = 8;
const enemyWidth = 42;
const enemyHeight = 28;
const gap = 18;
const startX = 75;
const startY = 60;
for (let row = 0; row < rows; row++) {
for (
let column = 0;
column < columns;
column++
) {
enemies.push({
x:
startX +
column *
(enemyWidth + gap),
y:
startY +
row *
(enemyHeight + gap),
width: enemyWidth,
height: enemyHeight,
alive: true
});
}
}
}
function resetGame() {
score = 0;
lives = 3;
bullets = [];
enemyDirection = 1;
enemySpeed = 0.7;
player.x =
canvas.width / 2 -
player.width / 2;
createEnemies();
scoreElement.textContent =
score;
livesElement.textContent =
lives;
gameOver = false;
}
function startGame() {
cancelAnimationFrame(
animationFrame
);
resetGame();
gameRunning = true;
startBtn.textContent =
"Restart Game";
gameLoop();
}
function shoot() {
const now =
Date.now();
if (
!gameRunning ||
now - lastShot < 250
) {
return;
}
bullets.push({
x:
player.x +
player.width / 2 -
2,
y:
player.y - 10,
width: 4,
height: 12,
speed: 8
});
lastShot = now;
}
function updatePlayer() {
if (
keys["ArrowLeft"] ||
keys["a"] ||
keys["A"]
) {
player.x -= player.speed;
}
if (
keys["ArrowRight"] ||
keys["d"] ||
keys["D"]
) {
player.x += player.speed;
}
if (player.x < 0) {
player.x = 0;
}
if (
player.x + player.width >
canvas.width
) {
player.x =
canvas.width -
player.width;
}
}
function updateBullets() {
bullets.forEach(
bullet => {
bullet.y -=
bullet.speed;
}
);
bullets =
bullets.filter(
bullet =>
bullet.y +
bullet.height > 0
);
}
function updateEnemies() {
let moveDown = false;
enemies.forEach(
enemy => {
if (!enemy.alive) {
return;
}
enemy.x +=
enemySpeed *
enemyDirection;
if (
enemy.x <= 0 ||
enemy.x +
enemy.width >=
canvas.width
) {
moveDown = true;
}
}
);
if (moveDown) {
enemyDirection *= -1;
enemies.forEach(
enemy => {
if (enemy.alive) {
enemy.y += 22;
}
}
);
}
}
function collision(
a,
b
) {
return (
a.x <
b.x + b.width &&
a.x + a.width >
b.x &&
a.y <
b.y + b.height &&
a.y + a.height >
b.y
);
}
function checkCollisions() {
bullets.forEach(
bullet => {
enemies.forEach(
enemy => {
if (
enemy.alive &&
collision(
bullet,
enemy
)
) {
enemy.alive =
false;
bullet.y =
-100;
score += 10;
scoreElement.textContent =
score;
}
}
);
}
);
// Check if enemies reach player
enemies.forEach(
enemy => {
if (
enemy.alive &&
enemy.y +
enemy.height >=
player.y
) {
loseLife();
}
}
);
}
function loseLife() {
lives--;
livesElement.textContent =
lives;
if (lives <= 0) {
endGame();
} else {
player.x =
canvas.width / 2 -
player.width / 2;
bullets = [];
}
}
function checkWin() {
const remaining =
enemies.filter(
enemy =>
enemy.alive
);
if (remaining.length === 0) {
score += 100;
scoreElement.textContent =
score;
createEnemies();
enemySpeed += 0.25;
}
}
function drawPlayer() {
ctx.fillStyle =
"#22c55e";
ctx.fillRect(
player.x,
player.y,
player.width,
player.height
);
ctx.fillStyle =
"#4ade80";
ctx.fillRect(
player.x + 20,
player.y - 10,
15,
10
);
}
function drawBullets() {
ctx.fillStyle =
"#facc15";
bullets.forEach(
bullet => {
ctx.fillRect(
bullet.x,
bullet.y,
bullet.width,
bullet.height
);
}
);
}
function drawEnemies() {
enemies.forEach(
enemy => {
if (!enemy.alive) {
return;
}
ctx.fillStyle =
"#ef4444";
ctx.fillRect(
enemy.x,
enemy.y,
enemy.width,
enemy.height
);
ctx.fillStyle =
"#020617";
ctx.fillRect(
enemy.x + 8,
enemy.y + 7,
7,
7
);
ctx.fillRect(
enemy.x + 27,
enemy.y + 7,
7,
7
);
ctx.fillStyle =
"#ef4444";
ctx.fillRect(
enemy.x - 5,
enemy.y + 10,
5,
5
);
ctx.fillRect(
enemy.x +
enemy.width,
enemy.y + 10,
5,
5
);
}
);
}
function drawStars() {
ctx.fillStyle =
"rgba(255,255,255,0.7)";
for (
let i = 0;
i < 45;
i++
) {
const x =
(i * 97) %
canvas.width;
const y =
(i * 53) %
canvas.height;
ctx.fillRect(
x,
y,
2,
2
);
}
}
function drawGameOver() {
if (!gameOver) {
return;
}
ctx.fillStyle =
"rgba(0,0,0,0.65)";
ctx.fillRect(
0,
0,
canvas.width,
canvas.height
);
ctx.fillStyle =
"#ffffff";
ctx.textAlign =
"center";
ctx.font =
"bold 46px Arial";
ctx.fillText(
"Game Over",
canvas.width / 2,
canvas.height / 2 - 25
);
ctx.font =
"24px Arial";
ctx.fillText(
"Final Score: " + score,
canvas.width / 2,
canvas.height / 2 + 20
);
ctx.font =
"18px Arial";
ctx.fillText(
"Click Start Again to play",
canvas.width / 2,
canvas.height / 2 + 60
);
}
function draw() {
ctx.fillStyle =
"#020617";
ctx.fillRect(
0,
0,
canvas.width,
canvas.height
);
drawStars();
drawEnemies();
drawBullets();
drawPlayer();
drawGameOver();
}
function update() {
if (!gameRunning) {
return;
}
updatePlayer();
updateBullets();
updateEnemies();
checkCollisions();
checkWin();
}
function endGame() {
gameRunning = false;
gameOver = true;
startBtn.textContent =
"Start Again";
draw();
}
function gameLoop() {
update();
draw();
if (gameRunning) {
animationFrame =
requestAnimationFrame(
gameLoop
);
}
}
document.addEventListener(
"keydown",
function(event) {
keys[event.key] = true;
if (
event.code ===
"Space"
) {
event.preventDefault();
shoot();
}
}
);
document.addEventListener(
"keyup",
function(event) {
keys[event.key] = false;
}
);
startBtn.addEventListener(
"click",
function() {
startGame();
}
);
resetGame();
draw();
</script>
</body>
</html>
