STAR STRIKE
by GoldenBuilder46736 lines13.0 KB
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>STAR STRIKE</title>
<style>
*{box-sizing:border-box}
body{
margin:0;
overflow:hidden;
background:#02030d;
font-family:Arial,sans-serif;
}
canvas{
display:block;
background:linear-gradient(#02051b,#080018);
}
#hud{
position:fixed;
top:15px;
left:15px;
right:15px;
display:flex;
justify-content:space-between;
color:white;
font-size:18px;
font-weight:bold;
pointer-events:none;
}
#start,#over{
position:fixed;
inset:0;
display:flex;
align-items:center;
justify-content:center;
flex-direction:column;
background:rgba(0,0,15,.82);
color:white;
text-align:center;
}
#over{display:none}
h1{
font-size:60px;
margin:0 0 10px;
letter-spacing:5px;
}
p{font-size:20px}
button{
border:0;
border-radius:12px;
padding:15px 35px;
font-size:20px;
font-weight:bold;
cursor:pointer;
}
</style>
</head>
<body>
<canvas id="game"></canvas>
<div id="hud">
<span>⭐ <span id="score">0</span></span>
<span>🚀 LEVEL <span id="level">1</span></span>
<span>❤️ <span id="lives">3</span></span>
</div>
<div id="start">
<h1>STAR STRIKE</h1>
<p>Destroy the invasion and defeat the bosses!</p>
<p>← → / A D = Move | SPACE = Shoot</p>
<button onclick="startGame()">START GAME</button>
</div>
<div id="over">
<h1>GAME OVER</h1>
<p>Score: <span id="finalScore">0</span></p>
<button onclick="restart()">PLAY AGAIN</button>
</div>
<script>
const canvas=document.getElementById("game");
const ctx=canvas.getContext("2d");
function resize(){
canvas.width=innerWidth;
canvas.height=innerHeight;
}
resize();
addEventListener("resize",resize);
const keys={};
addEventListener("keydown",e=>{
keys[e.code]=true;
if(e.code==="Space") e.preventDefault();
});
addEventListener("keyup",e=>{
keys[e.code]=false;
});
let score=0;
let lives=3;
let level=1;
let running=false;
let boss=null;
let spawnTimer=0;
let shotTimer=0;
const player={
x:0,
y:0,
speed:8,
size:22
};
let bullets=[];
let enemyBullets=[];
let enemies=[];
let particles=[];
let powerups=[];
let stars=[];
function resetPlayer(){
player.x=canvas.width/2;
player.y=canvas.height-90;
}
for(let i=0;i<160;i++){
stars.push({
x:Math.random()*innerWidth,
y:Math.random()*innerHeight,
s:Math.random()*2+0.5,
speed:Math.random()*2+0.5
});
}
function startGame(){
document.getElementById("start").style.display="none";
restart();
}
function restart(){
score=0;
lives=3;
level=1;
boss=null;
bullets=[];
enemyBullets=[];
enemies=[];
particles=[];
powerups=[];
spawnTimer=0;
running=true;
resetPlayer();
document.getElementById("over").style.display="none";
}
function shoot(){
if(shotTimer>0)return;
bullets.push({
x:player.x,
y:player.y-25,
speed:13,
size:5
});
shotTimer=8;
}
function spawnEnemy(){
enemies.push({
x:Math.random()*(canvas.width-60)+30,
y:-40,
size:20+Math.random()*15,
speed:2+level*.25,
hp:1+Math.floor(level/3)
});
}
function spawnBoss(){
boss={
x:canvas.width/2,
y:100,
size:70,
hp:80+level*20,
maxHp:80+level*20,
direction:1,
timer:0
};
}
function explosion(x,y){
for(let i=0;i<25;i++){
particles.push({
x:x,
y:y,
vx:(Math.random()-.5)*8,
vy:(Math.random()-.5)*8,
life:30+Math.random()*20,
size:2+Math.random()*5
});
}
}
function dropPowerup(x,y){
if(Math.random()<.12){
powerups.push({
x:x,
y:y,
size:12,
speed:3
});
}
}
function update(){
if(!running)return;
// movement
if(keys.ArrowLeft||keys.KeyA)
player.x-=player.speed;
if(keys.ArrowRight||keys.KeyD)
player.x+=player.speed;
player.x=Math.max(25,Math.min(canvas.width-25,player.x));
// shooting
if(keys.Space)shoot();
if(shotTimer>0)shotTimer--;
// stars
stars.forEach(s=>{
s.y+=s.speed;
if(s.y>canvas.height){
s.y=0;
s.x=Math.random()*canvas.width;
}
});
// spawn enemies
spawnTimer--;
if(!boss && spawnTimer<=0){
spawnEnemy();
spawnTimer=Math.max(
12,
50-level*3
);
}
// bullets
bullets.forEach(b=>{
b.y-=b.speed;
});
bullets=bullets.filter(b=>b.y>-30);
// enemies
enemies.forEach(e=>{
e.y+=e.speed;
});
// enemy bullets
enemyBullets.forEach(b=>{
b.y+=b.speed;
});
enemyBullets=enemyBullets.filter(
b=>b.y<canvas.height+30
);
// enemy shooting
enemies.forEach(e=>{
if(Math.random()<.004+level*.0005){
enemyBullets.push({
x:e.x,
y:e.y,
speed:4+level*.2,
size:5
});
}
});
// boss
if(boss){
boss.x+=boss.direction*2;
if(
boss.x<boss.size ||
boss.x>canvas.width-boss.size
){
boss.direction*=-1;
}
boss.timer++;
if(boss.timer%45===0){
enemyBullets.push({
x:boss.x,
y:boss.y+boss.size,
speed:6,
size:8
});
}
}
// bullet vs enemies
for(let i=enemies.length-1;i>=0;i--){
let e=enemies[i];
for(let j=bullets.length-1;j>=0;j--){
let b=bullets[j];
if(
Math.hypot(
b.x-e.x,
b.y-e.y
)<e.size
){
bullets.splice(j,1);
e.hp--;
explosion(b.x,b.y);
if(e.hp<=0){
score+=10;
dropPowerup(e.x,e.y);
explosion(e.x,e.y);
enemies.splice(i,1);
}
break;
}
}
}
// bullets vs boss
if(boss){
for(let i=bullets.length-1;i>=0;i--){
let b=bullets[i];
if(
Math.hypot(
b.x-boss.x,
b.y-boss.y
)<boss.size
){
bullets.splice(i,1);
boss.hp--;
explosion(b.x,b.y);
if(boss.hp<=0){
score+=500;
explosion(boss.x,boss.y);
boss=null;
level++;
}
break;
}
}
}
// player vs enemy bullets
for(let i=enemyBullets.length-1;i>=0;i--){
let b=enemyBullets[i];
if(
Math.hypot(
b.x-player.x,
b.y-player.y
)<player.size+8
){
enemyBullets.splice(i,1);
hitPlayer();
}
}
// player vs enemies
for(let i=enemies.length-1;i>=0;i--){
let e=enemies[i];
if(
Math.hypot(
e.x-player.x,
e.y-player.y
)<e.size+player.size
){
enemies.splice(i,1);
explosion(e.x,e.y);
hitPlayer();
}
else if(e.y>canvas.height+50){
enemies.splice(i,1);
hitPlayer();
}
}
// powerups
powerups.forEach(p=>{
p.y+=p.speed;
});
for(let i=powerups.length-1;i>=0;i--){
let p=powerups[i];
if(
Math.hypot(
p.x-player.x,
p.y-player.y
)<30
){
score+=50;
lives=Math.min(5,lives+1);
powerups.splice(i,1);
}
else if(p.y>canvas.height){
powerups.splice(i,1);
}
}
// particles
particles.forEach(p=>{
p.x+=p.vx;
p.y+=p.vy;
p.life--;
});
particles=particles.filter(p=>p.life>0);
// boss appears every 500 points
if(
score>0 &&
score%500<10 &&
!boss
){
spawnBoss();
}
document.getElementById("score").textContent=score;
document.getElementById("lives").textContent=lives;
document.getElementById("level").textContent=level;
}
function hitPlayer(){
lives--;
explosion(player.x,player.y);
if(lives<=0){
gameOver();
}
}
function draw(){
ctx.clearRect(
0,0,
canvas.width,
canvas.height
);
// stars
ctx.fillStyle="white";
stars.forEach(s=>{
ctx.globalAlpha=.4+Math.random()*.6;
ctx.fillRect(
s.x,s.y,
s.s,s.s
);
});
ctx.globalAlpha=1;
// player
ctx.save();
ctx.translate(
player.x,
player.y
);
ctx.shadowBlur=25;
ctx.shadowColor="#00ffff";
ctx.fillStyle="#00ffff";
ctx.beginPath();
ctx.moveTo(0,-30);
ctx.lineTo(-25,25);
ctx.lineTo(0,15);
ctx.lineTo(25,25);
ctx.closePath();
ctx.fill();
ctx.fillStyle="white";
ctx.beginPath();
ctx.arc(0,-5,7,0,Math.PI*2);
ctx.fill();
ctx.restore();
// player bullets
ctx.fillStyle="#00ffcc";
ctx.shadowBlur=15;
ctx.shadowColor="#00ffcc";
bullets.forEach(b=>{
ctx.fillRect(
b.x-b.size/2,
b.y,
b.size,
18
);
});
// enemies
enemies.forEach(e=>{
ctx.save();
ctx.translate(e.x,e.y);
ctx.shadowBlur=20;
ctx.shadowColor="#ff1744";
ctx.fillStyle="#ff1744";
ctx.beginPath();
ctx.arc(
0,0,
e.size,
0,
Math.PI*2
);
ctx.fill();
ctx.fillStyle="#111";
ctx.beginPath();
ctx.arc(-7,-4,4,0,Math.PI*2);
ctx.arc(7,-4,4,0,Math.PI*2);
ctx.fill();
ctx.restore();
});
// boss
if(boss){
ctx.save();
ctx.translate(
boss.x,
boss.y
);
ctx.shadowBlur=30;
ctx.shadowColor="#a020f0";
ctx.fillStyle="#8e44ad";
ctx.beginPath();
ctx.arc(
0,0,
boss.size,
0,
Math.PI*2
);
ctx.fill();
ctx.fillStyle="#ff4444";
ctx.beginPath();
ctx.arc(-25,-10,10,0,Math.PI*2);
ctx.arc(25,-10,10,0,Math.PI*2);
ctx.fill();
ctx.restore();
// boss health bar
ctx.fillStyle="#333";
ctx.fillRect(
canvas.width/2-150,
25,
300,
12
);
ctx.fillStyle="#ff3366";
ctx.fillRect(
canvas.width/2-150,
25,
300*(boss.hp/boss.maxHp),
12
);
}
// enemy bullets
ctx.fillStyle="#ff5555";
enemyBullets.forEach(b=>{
ctx.beginPath();
ctx.arc(
b.x,
b.y,
b.size,
0,
Math.PI*2
);
ctx.fill();
});
// powerups
powerups.forEach(p=>{
ctx.fillStyle="#ffd32a";
ctx.shadowBlur=20;
ctx.shadowColor="#ffd32a";
ctx.beginPath();
ctx.arc(
p.x,
p.y,
p.size,
0,
Math.PI*2
);
ctx.fill();
ctx.fillStyle="#111";
ctx.font="bold 14px Arial";
ctx.textAlign="center";
ctx.fillText("+",p.x,p.y+5);
});
// explosions
particles.forEach(p=>{
ctx.globalAlpha=p.life/50;
ctx.fillStyle="#ffcc00";
ctx.beginPath();
ctx.arc(
p.x,
p.y,
p.size,
0,
Math.PI*2
);
ctx.fill();
});
ctx.globalAlpha=1;
ctx.shadowBlur=0;
}
function gameOver(){
running=false;
document.getElementById("finalScore")
.textContent=score;
document.getElementById("over")
.style.display="flex";
}
function loop(){
update();
draw();
requestAnimationFrame(loop);
}
resetPlayer();
loop();
</script>
</body>
</html>Game Source: STAR STRIKE
Creator: GoldenBuilder46
Libraries: none
Complexity: complex (736 lines, 13.0 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: star-strike-goldenbuilder46" to link back to the original. Then publish at arcadelab.ai/publish.