NRG ARCTIC: UFO CHASE | DreaMBarX
by PhantomPirate47236 lines11.4 KB
<!DOCTYPE html>
<html style="margin:0;padding:0;overflow:hidden">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>NRG ARCTIC: UFO CHASE | DreaMBarX</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body {background:#020818;font-family:system-ui,sans-serif}
#gameCanvas {display:block;margin:0 auto;background:#051028;box-shadow:0 0 80px rgba(80,200,255,0.25)}
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const W = 360, H = 640;
canvas.width = W; canvas.height = H;
const WORLD_W = 3500, WORLD_H = 2200;
let camera = {x: WORLD_W/2 - W/2, y: WORLD_H/2 - H/2};
let player = {x: WORLD_W/2, y: WORLD_H/2, w:40, h:55, baseSpeed:3.5, speed:3.5, health:100, energy:100, fireRate:220, bulletDamage:1, shield:0};
let parts = { thrusters:0, shields:0, cores:0 };
const REQUIRED_PARTS = { thrusters:8, shields:6, cores:4 };
let futureShipUnlocked = false;
let landmarks = [], aliens = [], ufos = [], bullets = [], enemyBullets = [], loot = [], particles = [];
let score = 0, lastShot = 0;
let keys = {up:false, down:false, left:false, right:false, boost:false, fire:false};
document.addEventListener('keydown',e=>{
if(e.key=='ArrowUp'||e.key=='w') keys.up=true;
if(e.key=='ArrowDown'||e.key=='s') keys.down=true;
if(e.key=='ArrowLeft'||e.key=='a') keys.left=true;
if(e.key=='ArrowRight'||e.key=='d') keys.right=true;
if(e.key=='Shift') keys.boost=true;
if(e.key==' ') keys.fire=true;
});
document.addEventListener('keyup',e=>{
if(e.key=='ArrowUp'||e.key=='w') keys.up=false;
if(e.key=='ArrowDown'||e.key=='s') keys.down=false;
if(e.key=='ArrowLeft'||e.key=='a') keys.left=false;
if(e.key=='ArrowRight'||e.key=='d') keys.right=false;
if(e.key=='Shift') keys.boost=false;
if(e.key==' ') keys.fire=false;
});
canvas.addEventListener('touchstart',e=>{
e.preventDefault();
const rect = canvas.getBoundingClientRect();
const tx = (e.touches[0].clientX - rect.left) * W / rect.width;
const ty = (e.touches[0].clientY - rect.top) * H / rect.height;
keys.up = ty < H/3; keys.down = ty > H*2/3; keys.left = tx < W/3; keys.right = tx > W*2/3; keys.boost = tx > W/2 && ty < H/5; keys.fire = ty > H/2 && tx > W/2;
});
canvas.addEventListener('touchmove',e=>{
e.preventDefault();
const rect = canvas.getBoundingClientRect();
const tx = (e.touches[0].clientX - rect.left) * W / rect.width;
const ty = (e.touches[0].clientY - rect.top) * H / rect.height;
keys.up = ty < H/3; keys.down = ty > H*2/3; keys.left = tx < W/3; keys.right = tx > W*2/3; keys.boost = tx > W/2 && ty < H/5; keys.fire = ty > H/2 && tx > W/2;
});
canvas.addEventListener('touchend',e=>{keys.up=keys.down=keys.left=keys.right=keys.boost=keys.fire=false});
function generateWorld(){
const landTypes = [
{name:'Glacial Lagoon', color:'#a0e8ff', type:'water'},
{name:'Alien Crash Site', color:'#90ffc0', type:'landmark'},
{name:'Black Sand Shore', color:'#2a2f3a', type:'ground'},
{name:'Ice Cave Hangar', color:'#a0d0ff', type:'landmark'},
{name:'Snowy Peak', color:'#f0f8ff', type:'mountain'},
{name:'Geyser Outpost', color:'#ffd090', type:'landmark'}
];
for(let i=0;i<22;i++){
const type = landTypes[Math.floor(Math.random()*landTypes.length)];
landmarks.push({x:Math.random()*(WORLD_W-300)+150,y:Math.random()*(WORLD_H-300)+150,w:120+Math.random()*180,h:90+Math.random()*140,...type})
}
for(let i=0;i<10;i++) spawnAlien();
for(let i=0;i<4;i++) spawnUFO();
}
function spawnAlien(){aliens.push({x:Math.random()*WORLD_W,y:Math.random()*WORLD_H,w:35,h:40,speed:1.5+Math.random(),hp:2,phase:Math.random()*Math.PI*2})}
function spawnUFO(){
const isMothership = Math.random()>0.75;
ufos.push({x:Math.random()*WORLD_W,y:Math.random()*WORLD_H,w:isMothership?90:55,h:isMothership?45:28,speed:isMothership?2.2:3.8,hp:isMothership?12:5,maxHp:isMothership?12:5,isMothership,state:'patrol',lastFire:0,phase:Math.random()*Math.PI*2})
}
function dropLoot(x,y,isUFO){
const types = ['thrusters','shields','cores'];
const count = isUFO ? (Math.random()>0.7?2:1) : 1;
for(let i=0;i<count;i++) loot.push({x:x+(Math.random()-0.5)*40,y:y+(Math.random()-0.5)*40,type:types[Math.floor(Math.random()*types.length)]});
score += isUFO ? 150 : 40;
}
function loop(t){
player.speed = player.baseSpeed + parts.thrusters*0.25;
player.fireRate = 220 - parts.cores*18;
player.bulletDamage = 1 + parts.cores*0.3;
player.shield = parts.shields*4;
let spd = keys.boost && player.energy>5 ? player.speed*1.7 : player.speed;
if(keys.up) player.y -= spd; if(keys.down) player.y += spd; if(keys.left) player.x -= spd; if(keys.right) player.x += spd;
if(keys.boost && (keys.up||keys.down||keys.left||keys.right)) player.energy -=0.18;
player.energy = Math.min(100, player.energy+0.06);
player.x = Math.max(50, Math.min(WORLD_W-50, player.x));
player.y = Math.max(50, Math.min(WORLD_H-50, player.y));
camera.x = Math.max(0, Math.min(WORLD_W-W, player.x - W/2));
camera.y = Math.max(0, Math.min(WORLD_H-H, player.y - H/2));
const bgGrad = ctx.createLinearGradient(0,0,0,H);
bgGrad.addColorStop(0,'#050c20'); bgGrad.addColorStop(0.4,'#102040'); bgGrad.addColorStop(1,'#1a3055');
ctx.fillStyle=bgGrad; ctx.fillRect(0,0,W,H);
ctx.fillStyle='rgba(120,255,210,0.04)';
for(let i=0;i<6;i++) ctx.fillRect(0, 100+Math.sin(t/700+i)*50, W, 70);
landmarks.forEach(lm=>{
const sx = lm.x - camera.x, sy = lm.y - camera.y;
if(sx > -lm.w && sx < W && sy > -lm.h && sy < H){
ctx.fillStyle=lm.color; ctx.shadowColor=lm.type=='landmark'?'#80e0ff':'transparent'; ctx.shadowBlur=lm.type=='landmark'?15:0;
ctx.fillRect(sx, sy, lm.w, lm.h);
}
});
ctx.shadowBlur=0;
if(keys.fire && t-lastShot>player.fireRate){
bullets.push({x:player.x,y:player.y-30,w:6,h:16,speed:-10,dmg:player.bulletDamage});
lastShot = t;
}
bullets = bullets.filter(b=>{
b.y += b.speed;
ctx.shadowColor='#0ff'; ctx.shadowBlur=12; ctx.fillStyle='#00ffff';
ctx.fillRect(b.x-3-camera.x, b.y-camera.y, b.w, b.h); ctx.shadowBlur=0;
return b.y > -20;
});
aliens.forEach((e,i)=>{
const dx = player.x - e.x, dy = player.y - e.y, dist = Math.sqrt(dx*dx+dy*dy);
e.x += (dx/dist)*e.speed + Math.sin(t/350+e.phase)*0.8; e.y += (dy/dist)*e.speed;
const sx = e.x - camera.x, sy = e.y - camera.y;
ctx.fillStyle='#70c8f0'; ctx.shadowColor='#a0e0ff'; ctx.shadowBlur=10;
ctx.fillRect(sx+8, sy, 20, e.h); ctx.fillRect(sx, sy+12, e.w, 16);
ctx.fillStyle='#ff5050'; ctx.fillRect(sx+14, sy+14, 6, 6); ctx.shadowBlur=0;
bullets.forEach((b,j)=>{
if(Math.abs(b.x-e.x)<25 && Math.abs(b.y-e.y)<25){
e.hp -= b.dmg; bullets.splice(j,1);
if(e.hp<=0){ dropLoot(e.x,e.y,false); aliens.splice(i,1); }
}
});
if(dist<35) player.health -= (player.shield>0 ? 0.15 : 0.4);
});
ufos.forEach((ufo,i)=>{
const dx = player.x - ufo.x, dy = player.y - ufo.y, dist = Math.sqrt(dx*dx+dy*dy);
if(ufo.hp < ufo.maxHp*0.3) ufo.state = 'flee';
else if(dist < 450) ufo.state = 'attack';
else ufo.state = 'patrol';
if(ufo.state == 'patrol'){
ufo.x += Math.sin(t/900+ufo.phase)*ufo.speed; ufo.y += Math.cos(t/1100+ufo.phase)*ufo.speed*0.6;
} else if(ufo.state == 'flee'){
ufo.x -= (dx/dist)*ufo.speed*1.4; ufo.y -= (dy/dist)*ufo.speed*1.4;
} else if(ufo.state == 'attack'){
ufo.x += (dx/dist)*ufo.speed*0.7 + Math.sin(t/400+ufo.phase)*1.2;
ufo.y += (dy/dist)*ufo.speed*0.5;
if(t-ufo.lastFire > (ufo.isMothership?900:1400)){
enemyBullets.push({x:ufo.x,y:ufo.y+20,vx:(dx/dist)*-4,vy:(dy/dist)*-4});
ufo.lastFire = t;
}
}
ufo.x = Math.max(100, Math.min(WORLD_W-100, ufo.x));
ufo.y = Math.max(100, Math.min(WORLD_H-100, ufo.y));
const sx = ufo.x - camera.x, sy = ufo.y - camera.y;
ctx.fillStyle='#40ff90'; ctx.shadowColor='#60ffb0'; ctx.shadowBlur=18;
ctx.beginPath(); ctx.ellipse(sx, sy+ufo.h/2, ufo.w/2, ufo.h/2, 0, 0, Math.PI*2); ctx.fill();
ctx.fillStyle='#a0ffd0'; ctx.beginPath(); ctx.arc(sx, sy, ufo.w/4, 0, Math.PI*2); ctx.fill();
ctx.fillStyle='#333'; ctx.fillRect(sx-25, sy-22, 50, 5);
ctx.fillStyle='#20ff80'; ctx.fillRect(sx-25, sy-22, 50*(ufo.hp/ufo.maxHp), 5); ctx.shadowBlur=0;
bullets.forEach((b,j)=>{
if(Math.abs(b.x-ufo.x)<ufo.w/2 && Math.abs(b.y-ufo.y)<ufo.h/2){
ufo.hp -= b.dmg; bullets.splice(j,1);
if(ufo.hp<=0){ dropLoot(ufo.x,ufo.y,true); ufos.splice(i,1); }
}
});
});
enemyBullets = enemyBullets.filter((b,i)=>{
b.x += b.vx; b.y += b.vy;
ctx.fillStyle='#ff7050'; ctx.shadowColor='#ff9070'; ctx.shadowBlur=8;
ctx.beginPath(); ctx.arc(b.x-camera.x, b.y-camera.y, 5, 0, Math.PI*2); ctx.fill(); ctx.shadowBlur=0;
const dx = player.x - b.x, dy = player.y - b.y;
if(Math.sqrt(dx*dx+dy*dy) < 25){
player.health -= (player.shield>0 ? 2 : 5); enemyBullets.splice(i,1);
}
return true;
});
loot = loot.filter((l,i)=>{
const sx = l.x - camera.x, sy = l.y - camera.y;
const colors = {thrusters:'#ff9900', shields:'#00ccff', cores:'#cc66ff'};
ctx.fillStyle=colors[l.type]; ctx.shadowColor=colors[l.type]; ctx.shadowBlur=14; ctx.fillRect(sx-5, sy-5, 10, 10); ctx.shadowBlur=0;
const dx = player.x - l.x, dy = player.y - l.y;
if(Math.sqrt(dx*dx+dy*dy) < 35){
parts[l.type]++; score +=25;
if(parts.thrusters>=REQUIRED_PARTS.thrusters && parts.shields>=REQUIRED_PARTS.shields && parts.cores>=REQUIRED_PARTS.cores) futureShipUnlocked = true;
return false;
}
return true;
});
const px = player.x - camera.x, py = player.y - camera.y;
ctx.fillStyle=futureShipUnlocked?'#ffd700':'#1a4aff';
ctx.shadowColor=futureShipUnlocked?'#ffea00':'#00ffff'; ctx.shadowBlur=22;
ctx.beginPath(); ctx.moveTo(px+20, py); ctx.lineTo(px, py+player.h); ctx.lineTo(px+player.w, py+player.h); ctx.fill();
ctx.fillStyle='#ffcc00'; ctx.fillRect(px+12, py+player.h-10, 16, 8); ctx.shadowBlur=0;
ctx.fillStyle='#fff'; ctx.font='bold 15px system-ui';
ctx.fillText(`SCORE: ${score}`,15,28);
ctx.fillText(`HEALTH: ${Math.round(player.health)}%`,15,48);
ctx.fillText(`ENERGY: ${Math.round(player.energy)}%`,15,68);
if(player.shield>0) ctx.fillText(`SHIELD: +${player.shield}%`,15,88);
ctx.fillStyle='#ff9900'; ctx.fillText(`THRUSTERS: ${parts.thrusters}/${REQUIRED_PARTS.thrusters}`,15,110);
ctx.fillStyle='#00ccff'; ctx.fillText(`SHIELDS: ${parts.shields}/${REQUIRED_PARTS.shields}`,15,130);
ctx.fillStyle='#cc66ff'; ctx.fillText(`CORES: ${parts.cores}/${REQUIRED_PARTS.cores}`,15,150);
if(futureShipUnlocked){ ctx.fillStyle='#ffd700'; ctx.font='bold 18px system-ui'; ctx.fillText('★ FUTURE SHIP UNLOCKED ★',15,175); }
ctx.fillStyle=player.health>30?'#0f8':'#f44'; ctx.fillRect(15,185,player.health*2.7,8);
ctx.fillStyle='#0af'; ctx.fillRect(15,197,player.energy*2.7,8);
ctx.strokeStyle='#fff'; ctx.lineWidth=1; ctx.strokeRect(15,185,270,8); ctx.strokeRect(15,197,270,8);
ctx.fillStyle='rgba(255,255,255,0.15)'; ctx.fillRect(W-85,15,75,75);
ctx.fillStyle='#0ff'; ctx.fillRect(W-85 + (player.x/WORLD_W)*75, 15 + (player.y/WORLD_H)*75,3,3);
ctx.fillStyle='#40ff90'; ufos.forEach(u=>{ ctx.fillRect(W-85 + (u.x/WORLD_W)*75,15 + (u.y/WORLD_H)*75,2.5,2.5) });
ctx.fillStyle='#ff9900'; loot.forEach(l=>{ ctx.fillRect(W-85 + (l.x/WORLD_W)*75,15 + (l.y/WORLD_H)*75,2,2) });
if(Math.random()<0.008) spawnAlien();
if(Math.random()<0.003) spawnUFO();
requestAnimationFrame(loop);
}
generateWorld();
requestAnimationFrame(loop);
</script>
</body>
</html>
Game Source: NRG ARCTIC: UFO CHASE | DreaMBarX
Creator: PhantomPirate47
Libraries: none
Complexity: complex (236 lines, 11.4 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: nrg-arctic-ufo-chase-dreambarx-phantompirate47" to link back to the original. Then publish at arcadelab.ai/publish.