rocket-game / index.html
adeism's picture
Add 2 files
0a94a0c verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Galaxy Defender</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
margin: 0;
overflow: hidden;
background-color: #000;
cursor: none;
}
#gameCanvas {
display: block;
background: linear-gradient(to bottom, #000428, #004e92);
}
#gameUI {
position: absolute;
top: 10px;
left: 10px;
color: white;
font-family: 'Arial', sans-serif;
pointer-events: none;
}
#startScreen, #gameOverScreen, #levelCompleteScreen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.7);
color: white;
font-family: 'Arial', sans-serif;
}
#gameOverScreen, #levelCompleteScreen {
display: none;
}
.custom-cursor {
position: absolute;
width: 20px;
height: 20px;
background-color: rgba(255, 255, 255, 0.7);
border-radius: 50%;
pointer-events: none;
z-index: 9999;
transform: translate(-50%, -50%);
mix-blend-mode: difference;
}
.powerup {
animation: pulse 1s infinite;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="gameUI">
<div class="flex space-x-4">
<div class="bg-gray-800 bg-opacity-70 px-4 py-2 rounded">
Level: <span id="levelDisplay">1</span>
</div>
<div class="bg-gray-800 bg-opacity-70 px-4 py-2 rounded">
Score: <span id="scoreDisplay">0</span>
</div>
<div class="bg-gray-800 bg-opacity-70 px-4 py-2 rounded">
Health: <span id="healthDisplay">100</span>%
</div>
<div class="bg-gray-800 bg-opacity-70 px-4 py-2 rounded">
Weapon: <span id="weaponDisplay">Basic</span>
</div>
<div class="bg-gray-800 bg-opacity-70 px-4 py-2 rounded">
Bombs: <span id="bombDisplay">3</span>
</div>
</div>
</div>
<div id="startScreen">
<h1 class="text-5xl font-bold mb-6 text-blue-400">GALAXY DEFENDER</h1>
<p class="text-xl mb-8 text-gray-300">Defend the galaxy against alien invaders!</p>
<button id="startButton" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-full text-xl transition-all duration-300 transform hover:scale-110">
START MISSION
</button>
<div class="mt-8 text-gray-400">
<p>Controls: Move with mouse | Hold left click to shoot | Right click for bomb</p>
<p class="mt-2">Power-ups will appear during gameplay</p>
</div>
</div>
<div id="gameOverScreen">
<h1 class="text-5xl font-bold mb-6 text-red-400">MISSION FAILED</h1>
<p class="text-xl mb-4">Your score: <span id="finalScore">0</span></p>
<p class="text-xl mb-8">Level reached: <span id="finalLevel">1</span></p>
<button id="restartButton" class="bg-red-600 hover:bg-red-700 text-white font-bold py-3 px-6 rounded-full text-xl transition-all duration-300 transform hover:scale-110">
TRY AGAIN
</button>
</div>
<div id="levelCompleteScreen">
<h1 class="text-5xl font-bold mb-6 text-green-400">LEVEL COMPLETE!</h1>
<p class="text-xl mb-8">Preparing for next mission...</p>
<div class="w-64 h-3 bg-gray-700 rounded-full overflow-hidden">
<div id="levelProgress" class="h-full bg-green-500 transition-all duration-1000"></div>
</div>
</div>
<div class="custom-cursor" id="customCursor"></div>
<script>
// Game variables
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const startScreen = document.getElementById('startScreen');
const gameOverScreen = document.getElementById('gameOverScreen');
const levelCompleteScreen = document.getElementById('levelCompleteScreen');
const startButton = document.getElementById('startButton');
const restartButton = document.getElementById('restartButton');
const scoreDisplay = document.getElementById('scoreDisplay');
const healthDisplay = document.getElementById('healthDisplay');
const levelDisplay = document.getElementById('levelDisplay');
const weaponDisplay = document.getElementById('weaponDisplay');
const bombDisplay = document.getElementById('bombDisplay');
const finalScore = document.getElementById('finalScore');
const finalLevel = document.getElementById('finalLevel');
const levelProgress = document.getElementById('levelProgress');
const customCursor = document.getElementById('customCursor');
// Set canvas size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Game state
let gameRunning = false;
let score = 0;
let health = 100;
let level = 1;
let enemies = [];
let bullets = [];
let enemyBullets = [];
let powerups = [];
let explosions = [];
let bombs = [];
let lastEnemySpawn = 0;
let lastPowerupSpawn = 0;
let enemiesDefeated = 0;
let enemiesToDefeat = 10;
let currentWeapon = 'basic';
let weaponCooldown = 0;
let bombCount = 3;
let isMouseDown = false;
let lastShotTime = 0;
let mouseX = canvas.width / 2;
let mouseY = canvas.height / 2;
let player = {
x: canvas.width / 2,
y: canvas.height - 100,
width: 50,
height: 60,
speed: 8
};
// Weapon types
const weapons = {
basic: {
cooldown: 15,
damage: 10,
color: '#00FFFF',
size: 5,
speed: 10,
spread: 0
},
double: {
cooldown: 20,
damage: 10,
color: '#FF00FF',
size: 5,
speed: 10,
spread: 0.2
},
laser: {
cooldown: 5,
damage: 5,
color: '#FFFF00',
size: 3,
speed: 15,
spread: 0
},
plasma: {
cooldown: 40,
damage: 25,
color: '#FF4500',
size: 8,
speed: 7,
spread: 0
}
};
// Enemy types
const enemyTypes = [
{
name: 'Scout',
width: 40,
height: 40,
speed: 2,
health: 30,
color: '#FF5555',
score: 50,
fireRate: 120,
bulletSpeed: 5,
bulletColor: '#FF0000',
movementPattern: 'straight',
directionChangeRate: 1000
},
{
name: 'Fighter',
width: 50,
height: 50,
speed: 3,
health: 50,
color: '#FFAA00',
score: 100,
fireRate: 90,
bulletSpeed: 6,
bulletColor: '#FF6600',
movementPattern: 'zigzag',
directionChangeRate: 800
},
{
name: 'Bomber',
width: 70,
height: 60,
speed: 1.5,
health: 100,
color: '#AA55FF',
score: 200,
fireRate: 150,
bulletSpeed: 4,
bulletColor: '#AA00FF',
movementPattern: 'sinusoidal',
directionChangeRate: 500
},
{
name: 'Elite',
width: 45,
height: 45,
speed: 4,
health: 80,
color: '#00FFAA',
score: 250,
fireRate: 60,
bulletSpeed: 7,
bulletColor: '#00FF00',
movementPattern: 'random',
directionChangeRate: 300
}
];
// Powerup types
const powerupTypes = [
{
name: 'Health',
color: '#00FF00',
effect: (game) => {
game.health = Math.min(100, game.health + 30);
createFloatingText('+30 Health', game.player.x, game.player.y, '#00FF00');
}
},
{
name: 'Double Shot',
color: '#FF00FF',
effect: (game) => {
game.currentWeapon = 'double';
setTimeout(() => {
if (game.currentWeapon === 'double') {
game.currentWeapon = 'basic';
createFloatingText('Double Shot Ended', game.player.x, game.player.y, '#FF00FF');
}
}, 10000);
createFloatingText('Double Shot!', game.player.x, game.player.y, '#FF00FF');
}
},
{
name: 'Laser',
color: '#FFFF00',
effect: (game) => {
game.currentWeapon = 'laser';
setTimeout(() => {
if (game.currentWeapon === 'laser') {
game.currentWeapon = 'basic';
createFloatingText('Laser Ended', game.player.x, game.player.y, '#FFFF00');
}
}, 10000);
createFloatingText('Rapid Laser!', game.player.x, game.player.y, '#FFFF00');
}
},
{
name: 'Plasma',
color: '#FF4500',
effect: (game) => {
game.currentWeapon = 'plasma';
setTimeout(() => {
if (game.currentWeapon === 'plasma') {
game.currentWeapon = 'basic';
createFloatingText('Plasma Ended', game.player.x, game.player.y, '#FF4500');
}
}, 10000);
createFloatingText('Plasma Cannon!', game.player.x, game.player.y, '#FF4500');
}
},
{
name: 'Bomb',
color: '#FFFFFF',
effect: (game) => {
game.bombCount = Math.min(5, game.bombCount + 1);
createFloatingText('+1 Bomb', game.player.x, game.player.y, '#FFFFFF');
updateUI();
}
}
];
// Floating text for effects
let floatingTexts = [];
function createFloatingText(text, x, y, color) {
floatingTexts.push({
text,
x,
y,
color,
alpha: 1,
lifetime: 60
});
}
// Initialize game
function initGame() {
gameRunning = true;
score = 0;
health = 100;
level = 1;
enemies = [];
bullets = [];
enemyBullets = [];
powerups = [];
explosions = [];
bombs = [];
floatingTexts = [];
enemiesDefeated = 0;
enemiesToDefeat = 10;
currentWeapon = 'basic';
bombCount = 3;
player.x = canvas.width / 2;
player.y = canvas.height - 100;
updateUI();
startScreen.style.display = 'none';
gameOverScreen.style.display = 'none';
levelCompleteScreen.style.display = 'none';
// Start game loop
requestAnimationFrame(gameLoop);
}
// Game loop
function gameLoop(timestamp) {
if (!gameRunning) return;
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw starfield background
drawBackground();
// Update and draw player
updatePlayer();
drawPlayer();
// Spawn enemies
if (timestamp - lastEnemySpawn > 1000 - (level * 50) && enemies.length < 5 + Math.floor(level / 2)) {
spawnEnemy();
lastEnemySpawn = timestamp;
}
// Spawn powerups
if (timestamp - lastPowerupSpawn > 15000 && Math.random() < 0.02) {
spawnPowerup();
lastPowerupSpawn = timestamp;
}
// Continuous firing when mouse is held down
if (isMouseDown && timestamp - lastShotTime > weapons[currentWeapon].cooldown) {
shoot();
lastShotTime = timestamp;
}
// Update and draw enemies
updateEnemies(timestamp);
drawEnemies();
// Update and draw bullets
updateBullets();
drawBullets();
// Update and draw enemy bullets
updateEnemyBullets();
drawEnemyBullets();
// Update and draw powerups
updatePowerups();
drawPowerups();
// Update and draw explosions
updateExplosions();
drawExplosions();
// Update and draw bombs
updateBombs();
drawBombs();
// Update and draw floating text
updateFloatingTexts();
drawFloatingTexts();
// Check level completion
if (enemiesDefeated >= enemiesToDefeat) {
levelComplete();
return;
}
// Check game over
if (health <= 0) {
gameOver();
return;
}
// Update weapon cooldown
if (weaponCooldown > 0) {
weaponCooldown--;
}
// Continue game loop
requestAnimationFrame(gameLoop);
}
// Draw starfield background
function drawBackground() {
// Draw gradient background
const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
gradient.addColorStop(0, '#000428');
gradient.addColorStop(1, '#004e92');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw stars
for (let i = 0; i < 100; i++) {
const x = (i * canvas.width / 100 + Date.now() / 1000 * 10) % canvas.width;
const y = (i * canvas.height / 100 + Date.now() / 500 * 5) % canvas.height;
const size = Math.random() * 2;
const opacity = Math.random() * 0.8 + 0.2;
ctx.fillStyle = `rgba(255, 255, 255, ${opacity})`;
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fill();
}
}
// Update player position based on mouse
function updatePlayer() {
// Smooth movement towards mouse
player.x += (mouseX - player.x) * 0.1;
player.y += (mouseY - player.y) * 0.1;
// Keep player within bounds
player.x = Math.max(player.width / 2, Math.min(canvas.width - player.width / 2, player.x));
player.y = Math.max(player.height / 2, Math.min(canvas.height - player.height / 2, player.y));
}
// Draw player ship
function drawPlayer() {
ctx.save();
ctx.translate(player.x, player.y);
// Draw ship body
ctx.fillStyle = '#3498db';
ctx.beginPath();
ctx.moveTo(0, -player.height / 2);
ctx.lineTo(-player.width / 2, player.height / 2);
ctx.lineTo(player.width / 2, player.height / 2);
ctx.closePath();
ctx.fill();
// Draw ship details
ctx.fillStyle = '#2980b9';
ctx.beginPath();
ctx.moveTo(0, -player.height / 4);
ctx.lineTo(-player.width / 4, player.height / 4);
ctx.lineTo(player.width / 4, player.height / 4);
ctx.closePath();
ctx.fill();
// Draw engine glow
if (Math.random() < 0.3) {
ctx.fillStyle = '#e74c3c';
ctx.beginPath();
ctx.moveTo(-player.width / 4, player.height / 2);
ctx.lineTo(0, player.height / 2 + 10 + Math.random() * 5);
ctx.lineTo(player.width / 4, player.height / 2);
ctx.closePath();
ctx.fill();
}
ctx.restore();
}
// Spawn a new enemy
function spawnEnemy() {
const typeIndex = Math.min(Math.floor(Math.random() * (level / 2)), enemyTypes.length - 1);
const type = enemyTypes[typeIndex];
const enemy = {
x: Math.random() * (canvas.width - type.width) + type.width / 2,
y: -type.height,
width: type.width,
height: type.height,
speed: type.speed,
health: type.health,
maxHealth: type.health,
color: type.color,
score: type.score,
type: typeIndex,
lastShot: 0,
fireRate: type.fireRate,
bulletSpeed: type.bulletSpeed,
bulletColor: type.bulletColor,
movementPattern: type.movementPattern,
directionChangeRate: type.directionChangeRate,
lastDirectionChange: 0,
directionX: Math.random() > 0.5 ? 1 : -1,
directionY: 1,
angle: 0,
amplitude: Math.random() * 50 + 50,
frequency: Math.random() * 0.01 + 0.01
};
enemies.push(enemy);
}
// Update all enemies
function updateEnemies(timestamp) {
for (let i = enemies.length - 1; i >= 0; i--) {
const enemy = enemies[i];
const type = enemyTypes[enemy.type];
// Move enemy based on movement pattern
switch(enemy.movementPattern) {
case 'straight':
enemy.y += enemy.speed;
break;
case 'zigzag':
if (timestamp - enemy.lastDirectionChange > enemy.directionChangeRate) {
enemy.directionX = Math.random() > 0.5 ? 1 : -1;
enemy.lastDirectionChange = timestamp;
}
enemy.x += enemy.speed * 0.5 * enemy.directionX;
enemy.y += enemy.speed * 0.8;
break;
case 'sinusoidal':
enemy.angle += enemy.frequency;
enemy.x = enemy.x + Math.sin(enemy.angle) * 0.5;
enemy.y += enemy.speed * 0.7;
break;
case 'random':
if (timestamp - enemy.lastDirectionChange > enemy.directionChangeRate) {
enemy.directionX = Math.random() * 2 - 1;
enemy.directionY = Math.random() * 0.5 + 0.5;
enemy.lastDirectionChange = timestamp;
}
enemy.x += enemy.speed * enemy.directionX;
enemy.y += enemy.speed * enemy.directionY;
break;
}
// Keep enemies within bounds
enemy.x = Math.max(enemy.width / 2, Math.min(canvas.width - enemy.width / 2, enemy.x));
// Enemy shooting with random spread
if (timestamp - enemy.lastShot > enemy.fireRate) {
const spread = Math.random() * 0.5 - 0.25;
enemyBullets.push({
x: enemy.x,
y: enemy.y + enemy.height / 2,
width: 5,
height: 10,
speed: enemy.bulletSpeed,
damage: 10,
color: enemy.bulletColor,
directionX: spread
});
enemy.lastShot = timestamp;
}
// Check if enemy is out of bounds
if (enemy.y > canvas.height + enemy.height) {
enemies.splice(i, 1);
}
}
}
// Draw all enemies
function drawEnemies() {
for (const enemy of enemies) {
ctx.save();
ctx.translate(enemy.x, enemy.y);
// Draw enemy body
ctx.fillStyle = enemy.color;
ctx.beginPath();
ctx.moveTo(0, -enemy.height / 2);
ctx.lineTo(-enemy.width / 2, enemy.height / 2);
ctx.lineTo(0, enemy.height / 4);
ctx.lineTo(enemy.width / 2, enemy.height / 2);
ctx.closePath();
ctx.fill();
// Draw enemy details
ctx.fillStyle = '#000';
ctx.beginPath();
ctx.arc(0, -enemy.height / 4, enemy.width / 8, 0, Math.PI * 2);
ctx.fill();
// Draw health bar
const healthPercent = enemy.health / enemy.maxHealth;
ctx.fillStyle = '#FF0000';
ctx.fillRect(-enemy.width / 2, -enemy.height / 2 - 10, enemy.width, 5);
ctx.fillStyle = '#00FF00';
ctx.fillRect(-enemy.width / 2, -enemy.height / 2 - 10, enemy.width * healthPercent, 5);
ctx.restore();
}
}
// Spawn a powerup
function spawnPowerup() {
const typeIndex = Math.floor(Math.random() * powerupTypes.length);
const type = powerupTypes[typeIndex];
const powerup = {
x: Math.random() * (canvas.width - 30) + 15,
y: -30,
width: 30,
height: 30,
speed: 2,
type: typeIndex,
color: type.color
};
powerups.push(powerup);
}
// Update all powerups
function updatePowerups() {
for (let i = powerups.length - 1; i >= 0; i--) {
const powerup = powerups[i];
// Move powerup
powerup.y += powerup.speed;
// Check collision with player
if (
powerup.x + powerup.width / 2 > player.x - player.width / 2 &&
powerup.x - powerup.width / 2 < player.x + player.width / 2 &&
powerup.y + powerup.height / 2 > player.y - player.height / 2 &&
powerup.y - powerup.height / 2 < player.y + player.height / 2
) {
// Apply powerup effect
powerupTypes[powerup.type].effect({
player,
health,
currentWeapon,
score,
bombCount
});
// Remove powerup
powerups.splice(i, 1);
continue;
}
// Check if powerup is out of bounds
if (powerup.y > canvas.height + powerup.height) {
powerups.splice(i, 1);
}
}
}
// Draw all powerups
function drawPowerups() {
for (const powerup of powerups) {
ctx.save();
ctx.translate(powerup.x, powerup.y);
// Draw powerup
ctx.fillStyle = powerup.color;
ctx.beginPath();
ctx.arc(0, 0, powerup.width / 2, 0, Math.PI * 2);
ctx.fill();
// Draw plus sign for health
if (powerup.type === 0) {
ctx.fillStyle = '#FFF';
ctx.fillRect(-powerup.width / 4, -2, powerup.width / 2, 4);
ctx.fillRect(-2, -powerup.width / 4, 4, powerup.width / 2);
}
// Draw bomb icon
else if (powerup.type === 4) {
ctx.fillStyle = '#000';
ctx.beginPath();
ctx.moveTo(0, -powerup.width / 4);
ctx.lineTo(-powerup.width / 4, powerup.width / 8);
ctx.lineTo(powerup.width / 4, powerup.width / 8);
ctx.closePath();
ctx.fill();
ctx.fillStyle = '#FF0000';
ctx.beginPath();
ctx.arc(0, -powerup.width / 6, powerup.width / 8, 0, Math.PI * 2);
ctx.fill();
}
ctx.restore();
}
}
// Player shooting
function shoot() {
if (weaponCooldown > 0) return;
const weapon = weapons[currentWeapon];
weaponCooldown = weapon.cooldown;
if (currentWeapon === 'basic' || currentWeapon === 'plasma') {
// Single shot
bullets.push({
x: player.x,
y: player.y - player.height / 2,
width: weapon.size,
height: weapon.size * 2,
speed: -weapon.speed,
damage: weapon.damage,
color: weapon.color
});
} else if (currentWeapon === 'double') {
// Double shot
bullets.push({
x: player.x - 15,
y: player.y - player.height / 2,
width: weapon.size,
height: weapon.size * 2,
speed: -weapon.speed,
damage: weapon.damage,
color: weapon.color
});
bullets.push({
x: player.x + 15,
y: player.y - player.height / 2,
width: weapon.size,
height: weapon.size * 2,
speed: -weapon.speed,
damage: weapon.damage,
color: weapon.color
});
} else if (currentWeapon === 'laser') {
// Rapid laser
bullets.push({
x: player.x + (Math.random() - 0.5) * 10,
y: player.y - player.height / 2,
width: weapon.size,
height: weapon.size * 2,
speed: -weapon.speed,
damage: weapon.damage,
color: weapon.color
});
}
}
// Update all bullets
function updateBullets() {
for (let i = bullets.length - 1; i >= 0; i--) {
const bullet = bullets[i];
// Move bullet
bullet.y += bullet.speed;
// Check collision with enemies
for (let j = enemies.length - 1; j >= 0; j--) {
const enemy = enemies[j];
if (
bullet.x + bullet.width / 2 > enemy.x - enemy.width / 2 &&
bullet.x - bullet.width / 2 < enemy.x + enemy.width / 2 &&
bullet.y + bullet.height / 2 > enemy.y - enemy.height / 2 &&
bullet.y - bullet.height / 2 < enemy.y + enemy.height / 2
) {
// Damage enemy
enemy.health -= bullet.damage;
// Create explosion
createExplosion(bullet.x, bullet.y, bullet.color);
// Remove bullet
bullets.splice(i, 1);
// Check if enemy is defeated
if (enemy.health <= 0) {
// Add score
score += enemy.score;
enemiesDefeated++;
// Create bigger explosion
createExplosion(enemy.x, enemy.y, enemy.color, 2);
// Remove enemy
enemies.splice(j, 1);
// Random chance to drop powerup
if (Math.random() < 0.1) {
spawnPowerup();
}
}
updateUI();
break;
}
}
// Check if bullet is out of bounds
if (bullet.y < -bullet.height) {
bullets.splice(i, 1);
}
}
}
// Draw all bullets
function drawBullets() {
for (const bullet of bullets) {
ctx.save();
ctx.translate(bullet.x, bullet.y);
// Draw bullet
ctx.fillStyle = bullet.color;
ctx.beginPath();
ctx.rect(-bullet.width / 2, -bullet.height / 2, bullet.width, bullet.height);
ctx.fill();
// Add glow effect
if (bullet.damage > 10) {
ctx.fillStyle = `rgba(255, 255, 255, 0.3)`;
ctx.beginPath();
ctx.arc(0, 0, bullet.width * 1.5, 0, Math.PI * 2);
ctx.fill();
}
ctx.restore();
}
}
// Update all enemy bullets
function updateEnemyBullets() {
for (let i = enemyBullets.length - 1; i >= 0; i--) {
const bullet = enemyBullets[i];
// Move bullet with possible spread
bullet.y += bullet.speed;
bullet.x += bullet.directionX * 2;
// Check collision with player
if (
bullet.x + bullet.width / 2 > player.x - player.width / 2 &&
bullet.x - bullet.width / 2 < player.x + player.width / 2 &&
bullet.y + bullet.height / 2 > player.y - player.height / 2 &&
bullet.y - bullet.height / 2 < player.y + player.height / 2
) {
// Damage player
health -= 10;
// Create explosion
createExplosion(bullet.x, bullet.y, bullet.color);
// Remove bullet
enemyBullets.splice(i, 1);
updateUI();
continue;
}
// Check if bullet is out of bounds
if (bullet.y > canvas.height + bullet.height) {
enemyBullets.splice(i, 1);
}
}
}
// Draw all enemy bullets
function drawEnemyBullets() {
for (const bullet of enemyBullets) {
ctx.save();
ctx.translate(bullet.x, bullet.y);
// Draw bullet
ctx.fillStyle = bullet.color;
ctx.beginPath();
ctx.rect(-bullet.width / 2, -bullet.height / 2, bullet.width, bullet.height);
ctx.fill();
ctx.restore();
}
}
// Create explosion effect
function createExplosion(x, y, color, sizeMultiplier = 1) {
const particleCount = 10 + Math.floor(Math.random() * 10);
for (let i = 0; i < particleCount; i++) {
explosions.push({
x,
y,
radius: Math.random() * 3 * sizeMultiplier + 1,
color,
speedX: (Math.random() - 0.5) * 5,
speedY: (Math.random() - 0.5) * 5,
alpha: 1,
lifetime: 30 + Math.random() * 30
});
}
}
// Update all explosions
function updateExplosions() {
for (let i = explosions.length - 1; i >= 0; i--) {
const explosion = explosions[i];
// Move particle
explosion.x += explosion.speedX;
explosion.y += explosion.speedY;
// Fade out
explosion.alpha -= 1 / explosion.lifetime;
// Remove when faded out
if (explosion.alpha <= 0) {
explosions.splice(i, 1);
}
}
}
// Draw all explosions
function drawExplosions() {
for (const explosion of explosions) {
ctx.save();
ctx.globalAlpha = explosion.alpha;
// Draw particle
ctx.fillStyle = explosion.color;
ctx.beginPath();
ctx.arc(explosion.x, explosion.y, explosion.radius, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
}
// Activate bomb
function activateBomb() {
if (bombCount <= 0) return;
bombCount--;
updateUI();
// Create a big explosion that covers most of the screen
createExplosion(player.x, player.y, '#FFFFFF', 5);
// Damage all enemies on screen
for (let i = enemies.length - 1; i >= 0; i--) {
const enemy = enemies[i];
// Damage enemy
enemy.health -= 50;
// Check if enemy is defeated
if (enemy.health <= 0) {
// Add score
score += enemy.score;
enemiesDefeated++;
// Create bigger explosion
createExplosion(enemy.x, enemy.y, enemy.color, 2);
// Remove enemy
enemies.splice(i, 1);
}
}
// Clear all enemy bullets
enemyBullets = [];
// Show bomb effect
bombs.push({
x: player.x,
y: player.y,
radius: 0,
maxRadius: Math.max(canvas.width, canvas.height) * 0.8,
color: 'rgba(255, 255, 255, 0.3)',
lifetime: 30
});
}
// Update all bombs
function updateBombs() {
for (let i = bombs.length - 1; i >= 0; i--) {
const bomb = bombs[i];
// Expand bomb radius
bomb.radius += (bomb.maxRadius - bomb.radius) * 0.1;
// Fade out
bomb.lifetime--;
// Remove when expired
if (bomb.lifetime <= 0) {
bombs.splice(i, 1);
}
}
}
// Draw all bombs
function drawBombs() {
for (const bomb of bombs) {
ctx.save();
// Draw bomb shockwave
ctx.fillStyle = bomb.color;
ctx.beginPath();
ctx.arc(bomb.x, bomb.y, bomb.radius, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
}
// Update floating texts
function updateFloatingTexts() {
for (let i = floatingTexts.length - 1; i >= 0; i--) {
const text = floatingTexts[i];
// Move up
text.y -= 1;
// Fade out
text.alpha -= 1 / text.lifetime;
// Remove when faded out
if (text.alpha <= 0) {
floatingTexts.splice(i, 1);
}
}
}
// Draw floating texts
function drawFloatingTexts() {
for (const text of floatingTexts) {
ctx.save();
ctx.globalAlpha = text.alpha;
ctx.font = '16px Arial';
ctx.fillStyle = text.color;
ctx.textAlign = 'center';
ctx.fillText(text.text, text.x, text.y);
ctx.restore();
}
}
// Update UI displays
function updateUI() {
scoreDisplay.textContent = score;
healthDisplay.textContent = health;
levelDisplay.textContent = level;
weaponDisplay.textContent = currentWeapon.charAt(0).toUpperCase() + currentWeapon.slice(1);
bombDisplay.textContent = bombCount;
}
// Level complete
function levelComplete() {
gameRunning = false;
levelCompleteScreen.style.display = 'flex';
// Animate progress bar
let progress = 0;
const interval = setInterval(() => {
progress += 0.01;
levelProgress.style.width = `${progress * 100}%`;
if (progress >= 1) {
clearInterval(interval);
nextLevel();
}
}, 10);
}
// Start next level
function nextLevel() {
level++;
enemiesDefeated = 0;
enemiesToDefeat = 10 + level * 2;
bombCount = Math.min(bombCount + 1, 5); // Add one bomb per level, max 5
// Clear bullets and powerups
bullets = [];
enemyBullets = [];
powerups = [];
updateUI();
levelCompleteScreen.style.display = 'none';
gameRunning = true;
requestAnimationFrame(gameLoop);
}
// Game over
function gameOver() {
gameRunning = false;
finalScore.textContent = score;
finalLevel.textContent = level;
gameOverScreen.style.display = 'flex';
}
// Event listeners
startButton.addEventListener('click', initGame);
restartButton.addEventListener('click', initGame);
// Mouse movement
document.addEventListener('mousemove', (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
// Update custom cursor position
customCursor.style.left = `${e.clientX}px`;
customCursor.style.top = `${e.clientY}px`;
});
// Mouse click to shoot
document.addEventListener('mousedown', (e) => {
if (gameRunning) {
if (e.button === 0) { // Left click
isMouseDown = true;
shoot();
lastShotTime = Date.now();
} else if (e.button === 2) { // Right click
activateBomb();
}
}
});
// Mouse release to stop shooting
document.addEventListener('mouseup', (e) => {
if (e.button === 0) { // Left click
isMouseDown = false;
}
});
// Prevent context menu on right click
document.addEventListener('contextmenu', (e) => {
e.preventDefault();
});
// Window resize
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Keep player on screen
player.x = Math.max(player.width / 2, Math.min(canvas.width - player.width / 2, player.x));
player.y = Math.max(player.height / 2, Math.min(canvas.height - player.height / 2, player.y));
});
// Set canvas size on load
window.addEventListener('load', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
});
</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 <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=adeism/rocket-game" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>