FPS Arena - Map 2
by NeonGamer522148 lines34.6 KB
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>FPS Arena - Map 2</title>
<style>
html,body{
margin:0;
width:100%;
height:100%;
overflow:hidden;
background:#000;
font-family:Arial,sans-serif;
}
#game{
position:fixed;
inset:0;
width:100%;
height:100%;
}
#mini{
position:fixed;
right:15px;
top:15px;
width:220px;
height:180px;
border:3px solid white;
background:#111;
z-index:20;
}
#hud{
position:fixed;
left:15px;
top:15px;
z-index:20;
color:white;
background:rgba(0,0,0,.82);
padding:12px;
border-radius:10px;
line-height:1.5;
}
.bar{
width:180px;
height:13px;
background:#222;
border:1px solid white;
border-radius:5px;
overflow:hidden;
}
.health{
width:100%;
height:100%;
background:#19df45;
}
#crosshair{
position:fixed;
left:50%;
top:50%;
transform:translate(-50%,-50%);
color:white;
font-size:30px;
z-index:10;
pointer-events:none;
}
#message{
position:fixed;
left:50%;
top:18%;
transform:translateX(-50%);
color:white;
font-size:32px;
font-weight:bold;
text-align:center;
z-index:30;
text-shadow:0 3px 8px black;
}
#weapon{
position:fixed;
bottom:0;
left:50%;
transform:translateX(-50%);
z-index:10;
}
#weaponName{
position:fixed;
bottom:90px;
left:50%;
transform:translateX(-50%);
color:white;
font-weight:bold;
z-index:10;
}
#menu,#pause,#death{
position:fixed;
inset:0;
background:rgba(0,0,0,.94);
color:white;
z-index:100;
display:flex;
align-items:center;
justify-content:center;
text-align:center;
}
#pause,#death{
display:none;
}
.panel{
width:430px;
max-width:85%;
background:#18182b;
padding:30px;
border-radius:16px;
border:2px solid #754cff;
}
button{
padding:11px 17px;
margin:4px;
border:0;
border-radius:7px;
background:#7045ff;
color:white;
font-size:16px;
cursor:pointer;
}
button:hover{
background:#936cff;
}
input{
padding:12px;
width:80%;
border:0;
border-radius:7px;
background:#292940;
color:white;
font-size:16px;
}
#bossBar{
display:none;
position:fixed;
bottom:20px;
left:50%;
transform:translateX(-50%);
width:500px;
max-width:70%;
z-index:30;
}
#bossTitle{
color:red;
text-align:center;
font-size:23px;
font-weight:bold;
}
#bossOuter{
height:25px;
background:#222;
border:2px solid white;
border-radius:8px;
overflow:hidden;
}
#bossHealth{
width:100%;
height:100%;
background:linear-gradient(90deg,red,orange);
}
</style>
</head>
<body>
<canvas id="game"></canvas>
<canvas id="mini" width="220" height="180"></canvas>
<div id="crosshair">+</div>
<div id="message"></div>
<div id="weaponName"></div>
<div id="weapon"></div>
<div id="hud">
👤 <span id="playerName">Player</span><br>
❤️ Health: <span id="hp">100</span>/100
<div class="bar">
<div id="playerHealth" class="health"></div>
</div>
🔫 Ammo: <span id="ammo">12 / 60</span><br>
🏆 Score: <span id="score">0</span><br>
⭐ Level: <span id="level">1</span><br>
🤖 Bots: <span id="bots">0</span><br>
🗺️ Map: <span id="mapNumber">1</span>
<br>
<button onclick="lockMouse()">🖱️ LOCK MOUSE</button>
<button onclick="togglePause()">⏸️ PAUSE</button>
<button onclick="fullScreen()">⛶ FULLSCREEN</button>
<br><br>
WASD = Move<br>
Mouse = Aim<br>
Click = Shoot<br>
1 = Pistol<br>
2 = Shotgun<br>
3 = Rifle<br>
R = Reload<br>
P = Pause<br>
F = Fullscreen
</div>
<div id="menu">
<div class="panel">
<h1>🎯 FPS ARENA</h1>
<p>
LEVELS 1–2: MAP 1<br>
LEVELS 3–8: MAP 2<br>
LEVEL 8: 👹 MEGA BOSS
</p>
<input id="nameInput" placeholder="Player name">
<br><br>
<button onclick="startGame()">🎮 START GAME</button>
<button onclick="fullScreen()">⛶ FULLSCREEN</button>
</div>
</div>
<div id="pause">
<div class="panel">
<h1>⏸️ PAUSED</h1>
<button onclick="togglePause()">▶️ RESUME</button>
</div>
</div>
<div id="death">
<div class="panel">
<h1>💀 YOU DIED</h1>
<p id="deathText"></p>
<button onclick="respawn()">🔄 RESPAWN</button>
</div>
</div>
<div id="bossBar">
<div id="bossTitle">
👹 MEGA BOSS
</div>
<div id="bossOuter">
<div id="bossHealth"></div>
</div>
</div>
<script>
/* =====================================================
CANVAS
===================================================== */
const canvas=document.getElementById("game");
const ctx=canvas.getContext("2d");
const mini=document.getElementById("mini");
const mctx=mini.getContext("2d");
function resize(){
canvas.width=innerWidth;
canvas.height=innerHeight;
}
resize();
addEventListener("resize",resize);
/* =====================================================
MAP 1
===================================================== */
const MAP1=[
"111111111111111111111111",
"100000000000000000000001",
"100011111000000111110001",
"100010001000000100010001",
"100010001000000100010001",
"100000001000000100000001",
"101111111000000111111101",
"100000001000000100000001",
"100000001000000100000001",
"100000001000000100000001",
"100000001000000100000001",
"100000000000000000000001",
"100000001000000100000001",
"100000001000000100000001",
"100000001000000100000001",
"100111110000000011111001",
"100100010000000010001001",
"100100010000000010001001",
"100000000000000000000001",
"111111111111111111111111"
];
/* =====================================================
MAP 2
THE MIDDLE IS FILLED WITH WALLS.
IMPORTANT:
There are OPENINGS at the LEFT and RIGHT
so the player can go around the center.
===================================================== */
const MAP2=[
"111111111111111111111111",
"100000000000000000000001",
"101111111011111111110101",
"101000001010000000010101",
"101011101010111111010101",
"101010001010100001010101",
"101010001010100001010101",
"101010000000000001010101",
/* LEFT + RIGHT OPEN AROUND CENTER */
"100000000011111100000001",
"100000000011111100000001",
"100000000011111100000001",
"100000000011111100000001",
"101010000000000001010101",
"101010001010100001010101",
"101011101010111111010101",
"101000001010000000010101",
"101111111011111111110101",
"100000000000000000000001",
"100000000000000000000001",
"111111111111111111111111"
];
let currentMap=MAP1;
/* =====================================================
PLAYER
===================================================== */
const player={
x:2.5,
y:9.5,
angle:0,
health:100,
maxHealth:100,
speed:3
};
/* =====================================================
GAME
===================================================== */
let playing=false;
let paused=false;
let level=1;
let score=0;
let enemies=[];
let pickups=[];
let keys={};
let lastTime=0;
let changing=false;
/* =====================================================
WEAPONS
===================================================== */
const weapons=[
{
name:"PISTOL",
damage:25,
maxAmmo:12,
ammo:12,
reserve:60,
rate:350,
range:12
},
{
name:"SHOTGUN",
damage:75,
maxAmmo:6,
ammo:6,
reserve:30,
rate:800,
range:8
},
{
name:"RIFLE",
damage:15,
maxAmmo:30,
ammo:30,
reserve:120,
rate:110,
range:18
}
];
let weapon=0;
let lastShot=0;
let reloading=false;
/* =====================================================
KEYBOARD
===================================================== */
addEventListener("keydown",e=>{
keys[e.key.toLowerCase()]=true;
if(e.key==="1")changeWeapon(0);
if(e.key==="2")changeWeapon(1);
if(e.key==="3")changeWeapon(2);
if(e.key.toLowerCase()==="r")reload();
if(e.key.toLowerCase()==="p")togglePause();
if(e.key.toLowerCase()==="f")fullScreen();
});
addEventListener("keyup",e=>{
keys[e.key.toLowerCase()]=false;
});
/* =====================================================
WALL COLLISION
===================================================== */
function wall(x,y){
const mx=Math.floor(x);
const my=Math.floor(y);
if(
mx<0 ||
my<0 ||
mx>=24 ||
my>=20
)
return true;
return currentMap[my][mx]==="1";
}
/* =====================================================
START
===================================================== */
function startGame(){
document.getElementById("playerName").textContent=
document.getElementById("nameInput").value ||
"Player";
document.getElementById("menu").style.display="none";
level=1;
score=0;
currentMap=MAP1;
player.x=2.5;
player.y=9.5;
player.angle=0;
player.health=100;
playing=true;
paused=false;
changing=false;
resetWeapons();
spawnLevel();
updateWeapon();
message("LEVEL 1<br>MAP 1");
lockMouse();
}
/* =====================================================
WEAPONS RESET
===================================================== */
function resetWeapons(){
weapons.forEach(w=>{
w.ammo=w.maxAmmo;
});
}
/* =====================================================
SPAWN LEVEL
===================================================== */
function spawnLevel(){
enemies=[];
pickups=[];
document.getElementById(
"bossBar"
).style.display="none";
/* SWITCH MAP AFTER LEVEL 2 */
if(level===3){
currentMap=MAP2;
/*
This is an OPEN AREA on Map 2.
It is NOT inside the middle wall.
*/
player.x=2.5;
player.y=8.5;
player.angle=0;
message(
"🗺️ MAP 2<br>LEVEL 3"
);
}
/* LEVEL 8 BOSS */
if(level===8){
spawnBoss();
return;
}
/* FIND OPEN SPACES */
let spots=[];
for(let y=1;y<19;y++){
for(let x=1;x<23;x++){
if(!wall(x+.5,y+.5)){
if(
Math.hypot(
x+.5-player.x,
y+.5-player.y
)>6
){
spots.push([
x+.5,
y+.5
]);
}
}
}
}
spots.sort(
()=>Math.random()-.5
);
let amount=
Math.min(
4+level*2,
18
);
for(
let i=0;
i<amount && i<spots.length;
i++
){
const p=spots[i];
enemies.push({
x:p[0],
y:p[1],
health:100+level*15,
maxHealth:100+level*15,
speed:.5+level*.035,
attack:0,
alive:true,
boss:false
});
}
/* PICKUPS */
spawnPickups();
updateHUD();
}
/* =====================================================
PICKUPS
===================================================== */
function spawnPickups(){
let spots=[];
for(let y=1;y<19;y++){
for(let x=1;x<23;x++){
if(!wall(x+.5,y+.5)){
if(
Math.hypot(
x+.5-player.x,
y+.5-player.y
)>3
){
spots.push([
x+.5,
y+.5
]);
}
}
}
}
spots.sort(
()=>Math.random()-.5
);
for(
let i=0;
i<Math.min(4,spots.length);
i++
){
pickups.push({
x:spots[i][0],
y:spots[i][1],
type:"ammo"
});
}
for(
let i=4;
i<Math.min(7,spots.length);
i++
){
pickups.push({
x:spots[i][0],
y:spots[i][1],
type:"health"
});
}
}
/* =====================================================
BOSS
===================================================== */
function spawnBoss(){
enemies=[{
/*
BOSS STARTS IN THE OPEN
RIGHT SIDE OF MAP 2.
*/
x:20.5,
y:8.5,
health:1800,
maxHealth:1800,
speed:.55,
attack:0,
alive:true,
boss:true
}];
document.getElementById(
"bossBar"
).style.display="block";
message(
"👹 LEVEL 8<br>MEGA BOSS!"
);
}
/* =====================================================
PLAYER MOVEMENT
===================================================== */
function updatePlayer(dt){
if(!playing||paused)
return;
let forward=0;
let strafe=0;
if(keys.w)forward++;
if(keys.s)forward--;
if(keys.a)strafe--;
if(keys.d)strafe++;
if(forward&&strafe){
forward*=.707;
strafe*=.707;
}
const dx=
Math.cos(player.angle)*
forward*
player.speed*
dt+
Math.cos(
player.angle+Math.PI/2
)*
strafe*
player.speed*
dt;
const dy=
Math.sin(player.angle)*
forward*
player.speed*
dt+
Math.sin(
player.angle+Math.PI/2
)*
strafe*
player.speed*
dt;
if(!wall(player.x+dx,player.y))
player.x+=dx;
if(!wall(player.x,player.y+dy))
player.y+=dy;
/* PICKUPS */
pickups.forEach(p=>{
if(
Math.hypot(
p.x-player.x,
p.y-player.y
)<.7
){
if(p.type==="health"){
player.health=
Math.min(
player.maxHealth,
player.health+35
);
message("❤️ HEALTH +35");
}
if(p.type==="ammo"){
weapons.forEach(w=>{
w.reserve+=20;
});
message("📦 AMMO +20");
}
p.collected=true;
}
});
pickups=
pickups.filter(
p=>!p.collected
);
}
/* =====================================================
MOUSE LOCK
===================================================== */
canvas.addEventListener("click",()=>{
if(
playing &&
!paused
){
if(
document.pointerLockElement!==canvas
){
lockMouse();
}else{
shoot();
}
}
});
function lockMouse(){
if(
playing &&
!paused
){
canvas.requestPointerLock();
}
}
document.addEventListener(
"mousemove",
e=>{
if(
document.pointerLockElement===canvas &&
playing &&
!paused
){
player.angle+=
e.movementX*.0025;
}
}
);
/* =====================================================
PAUSE
===================================================== */
function togglePause(){
if(!playing)
return;
paused=!paused;
document.getElementById(
"pause"
).style.display=
paused?"flex":"none";
if(paused){
if(document.pointerLockElement)
document.exitPointerLock();
}else{
lockMouse();
}
}
/* =====================================================
FULLSCREEN
===================================================== */
function fullScreen(){
if(!document.fullscreenElement){
document.documentElement
.requestFullscreen()
.catch(()=>{});
}else{
document.exitFullscreen();
}
}
/* =====================================================
SHOOT
===================================================== */
function shoot(){
if(reloading)
return;
const w=weapons[weapon];
const now=performance.now();
if(now-lastShot<w.rate)
return;
if(w.ammo<=0){
reload();
return;
}
lastShot=now;
w.ammo--;
let target=null;
let closest=999;
enemies.forEach(enemy=>{
if(!enemy.alive)
return;
const dx=
enemy.x-player.x;
const dy=
enemy.y-player.y;
const distance=
Math.hypot(dx,dy);
if(distance>w.range)
return;
const angle=
Math.atan2(dy,dx);
const difference=
Math.atan2(
Math.sin(angle-player.angle),
Math.cos(angle-player.angle)
);
if(
Math.abs(difference)<.14 &&
distance<closest
){
target=enemy;
closest=distance;
}
});
if(target){
target.health-=
target.boss
?w.damage*.75
:w.damage;
if(target.health<=0){
target.health=0;
target.alive=false;
if(target.boss){
score+=5000;
document.getElementById(
"bossBar"
).style.display="none";
message("🏆 BOSS DEFEATED!");
setTimeout(()=>{
level++;
spawnLevel();
},2000);
}else{
score+=100;
checkLevel();
}
}
}
updateHUD();
}
/* =====================================================
RELOAD
===================================================== */
function reload(){
if(reloading)
return;
const w=weapons[weapon];
if(
w.ammo>=w.maxAmmo ||
w.reserve<=0
)
return;
reloading=true;
message("🔄 RELOADING");
setTimeout(()=>{
const need=
w.maxAmmo-w.ammo;
const amount=
Math.min(
need,
w.reserve
);
w.ammo+=amount;
w.reserve-=amount;
reloading=false;
updateHUD();
},700);
}
/* =====================================================
WEAPON DISPLAY
===================================================== */
function changeWeapon(i){
weapon=i;
updateWeapon();
updateHUD();
}
function updateWeapon(){
const w=
document.getElementById("weapon");
document.getElementById(
"weaponName"
).textContent=
weapons[weapon].name;
if(weapon===0){
/* PISTOL */
w.innerHTML=`
<div style="
position:relative;
width:110px;
height:80px">
<div style="
position:absolute;
left:10px;
top:20px;
width:75px;
height:18px;
background:#202020;
border:3px solid #888;
border-radius:4px">
</div>
<div style="
position:absolute;
left:35px;
top:36px;
width:25px;
height:40px;
background:#444;
transform:rotate(12deg)">
</div>
</div>
`;
}
if(weapon===1){
/* SHOTGUN */
w.innerHTML=`
<div style="
position:relative;
width:240px;
height:80px">
<div style="
position:absolute;
left:5px;
top:22px;
width:200px;
height:18px;
background:#111;
border:3px solid #777">
</div>
<div style="
position:absolute;
left:75px;
top:40px;
width:90px;
height:24px;
background:#74452b;
border-radius:5px">
</div>
</div>
`;
}
if(weapon===2){
/* RIFLE */
w.innerHTML=`
<div style="
position:relative;
width:310px;
height:90px">
<div style="
position:absolute;
left:10px;
top:32px;
width:220px;
height:15px;
background:#222;
border:3px solid #777">
</div>
<div style="
position:absolute;
left:75px;
top:47px;
width:65px;
height:40px;
background:#202020;
transform:rotate(10deg)">
</div>
<div style="
position:absolute;
left:95px;
top:10px;
width:90px;
height:8px;
background:#111;
border:2px solid #777">
</div>
<div style="
position:absolute;
right:0;
top:35px;
width:65px;
height:8px;
background:#111">
</div>
</div>
`;
}
}
/* =====================================================
BOT AI
===================================================== */
function updateEnemies(dt){
if(!playing||paused)
return;
enemies.forEach(enemy=>{
if(!enemy.alive)
return;
const dx=
player.x-enemy.x;
const dy=
player.y-enemy.y;
const distance=
Math.hypot(dx,dy);
if(distance>1.3){
const nx=
enemy.x+
dx/distance*
enemy.speed*
dt;
const ny=
enemy.y+
dy/distance*
enemy.speed*
dt;
if(!wall(nx,enemy.y))
enemy.x=nx;
if(!wall(enemy.x,ny))
enemy.y=ny;
}
if(distance<1.5){
enemy.attack-=dt;
if(enemy.attack<=0){
enemy.attack=
enemy.boss?.6:1;
damagePlayer(
enemy.boss
?18
:6+level
);
}
}
});
}
/* =====================================================
PLAYER DAMAGE
===================================================== */
function damagePlayer(amount){
player.health-=amount;
if(player.health<=0){
player.health=0;
die();
}
}
/* =====================================================
DEATH
===================================================== */
function die(){
playing=false;
if(document.pointerLockElement)
document.exitPointerLock();
document.getElementById(
"deathText"
).textContent=
"Level "+level+
" • Score "+score;
document.getElementById(
"death"
).style.display="flex";
}
/* =====================================================
RESPAWN
===================================================== */
function respawn(){
document.getElementById(
"death"
).style.display="none";
player.health=100;
if(currentMap===MAP1){
player.x=2.5;
player.y=9.5;
}else{
player.x=2.5;
player.y=8.5;
}
resetWeapons();
playing=true;
spawnLevel();
lockMouse();
}
/* =====================================================
LEVEL COMPLETE
===================================================== */
function checkLevel(){
if(changing)
return;
if(
enemies.some(
e=>e.alive
)
)
return;
changing=true;
message("⭐ LEVEL COMPLETE!");
setTimeout(()=>{
level++;
changing=false;
spawnLevel();
},1500);
}
/* =====================================================
HUD
===================================================== */
function updateHUD(){
const w=weapons[weapon];
document.getElementById("hp")
.textContent=
Math.ceil(player.health);
document.getElementById(
"playerHealth"
).style.width=
Math.max(
0,
player.health
)+"%";
document.getElementById("ammo")
.textContent=
w.ammo+
" / "+
w.reserve;
document.getElementById("score")
.textContent=score;
document.getElementById("level")
.textContent=level;
document.getElementById("bots")
.textContent=
enemies.filter(
e=>e.alive
).length;
document.getElementById("mapNumber")
.textContent=
currentMap===MAP1
?1
:2;
const boss=
enemies.find(
e=>e.boss&&e.alive
);
if(boss){
document.getElementById(
"bossHealth"
).style.width=
(
boss.health/
boss.maxHealth*
100
)+"%";
}
}
/* =====================================================
MESSAGE
===================================================== */
let messageTimer;
function message(text){
document.getElementById(
"message"
).innerHTML=text;
clearTimeout(messageTimer);
messageTimer=setTimeout(()=>{
document.getElementById(
"message"
).innerHTML="";
},2500);
}
/* =====================================================
RAYCAST
===================================================== */
function ray(angle){
let distance=0;
while(distance<30){
distance+=.03;
const x=
player.x+
Math.cos(angle)*
distance;
const y=
player.y+
Math.sin(angle)*
distance;
if(wall(x,y))
return distance;
}
return 30;
}
/* =====================================================
3D RENDER
===================================================== */
const FOV=Math.PI/3;
function render(){
const W=canvas.width;
const H=canvas.height;
ctx.fillStyle=
currentMap===MAP1
?" #182845".trim()
:"#082938";
ctx.fillRect(
0,
0,
W,
H/2
);
ctx.fillStyle=
currentMap===MAP1
?" #342517".trim()
:"#123035";
ctx.fillRect(
0,
H/2,
W,
H/2
);
const rays=
Math.min(W,700);
const column=W/rays;
for(
let i=0;
i<rays;
i++
){
const camera=
i/rays-.5;
const angle=
player.angle+
camera*FOV;
let distance=
ray(angle);
distance*=
Math.cos(
camera*FOV
);
const height=
Math.min(
H,
H/(distance*.8)
);
const top=
(H-height)/2;
const brightness=
Math.max(
25,
200-distance*10
);
ctx.fillStyle=
currentMap===MAP1
?
`rgb(
${brightness},
${brightness*.7},
${brightness*.45}
)`
:
`rgb(
${brightness*.25},
${brightness*.6},
${brightness}
)`;
ctx.fillRect(
i*column,
top,
column+1,
height
);
}
/* BOTS */
enemies.forEach(enemy=>{
if(!enemy.alive)
return;
const dx=
enemy.x-player.x;
const dy=
enemy.y-player.y;
const distance=
Math.hypot(dx,dy);
const angle=
Math.atan2(dy,dx);
const difference=
Math.atan2(
Math.sin(angle-player.angle),
Math.cos(angle-player.angle)
);
if(
Math.abs(difference)>FOV/2
)
return;
if(
distance>ray(angle)
)
return;
const x=
W/2+
difference/(FOV/2)*
W/2;
let size=
Math.min(
500,
H/(distance*.8)
);
if(enemy.boss)
size*=2;
ctx.textAlign="center";
ctx.font=size+"px Arial";
ctx.fillText(
enemy.boss
?"👹"
:"🤖",
x,
H/2+size*.35
);
/* BOT HEALTH BAR */
const barWidth=
Math.max(
50,
size*.8
);
const barX=
x-barWidth/2;
const barY=
H/2-size*.6;
ctx.fillStyle="#222";
ctx.fillRect(
barX,
barY,
barWidth,
9
);
ctx.fillStyle=
enemy.boss
?"orange"
:"red";
ctx.fillRect(
barX,
barY,
barWidth*
Math.max(
0,
enemy.health/
enemy.maxHealth
),
9
);
ctx.strokeStyle="white";
ctx.strokeRect(
barX,
barY,
barWidth,
9
);
});
/* PICKUPS */
pickups.forEach(p=>{
const dx=
p.x-player.x;
const dy=
p.y-player.y;
const distance=
Math.hypot(dx,dy);
const angle=
Math.atan2(dy,dx);
const difference=
Math.atan2(
Math.sin(angle-player.angle),
Math.cos(angle-player.angle)
);
if(
Math.abs(difference)>FOV/2 ||
distance>ray(angle)
)
return;
const x=
W/2+
difference/(FOV/2)*
W/2;
const size=
Math.min(
80,
H/(distance*1.5)
);
ctx.font=size+"px Arial";
ctx.textAlign="center";
ctx.fillText(
p.type==="health"
?"❤️"
:"📦",
x,
H/2+size*.3
);
});
}
/* =====================================================
MINIMAP
===================================================== */
function drawMini(){
const W=220;
const H=180;
mctx.clearRect(
0,0,W,H
);
const sx=W/24;
const sy=H/20;
for(
let y=0;
y<20;
y++
){
for(
let x=0;
x<24;
x++
){
if(
currentMap[y][x]==="1"
){
mctx.fillStyle=
currentMap===MAP2
?" #17536a".trim()
:"#555";
}else{
mctx.fillStyle=
currentMap===MAP2
?" #06151c".trim()
:"#111";
}
mctx.fillRect(
x*sx,
y*sy,
sx+1,
sy+1
);
}
}
/* PICKUPS */
pickups.forEach(p=>{
mctx.fillStyle=
p.type==="health"
?"lime"
:"yellow";
mctx.fillRect(
p.x*sx-3,
p.y*sy-3,
6,
6
);
});
/* RED BOTS */
enemies.forEach(e=>{
if(!e.alive)
return;
mctx.fillStyle=
e.boss
?"orange"
:"red";
mctx.beginPath();
mctx.arc(
e.x*sx,
e.y*sy,
e.boss?8:5,
0,
Math.PI*2
);
mctx.fill();
});
/* BLUE PLAYER */
mctx.fillStyle="#168cff";
mctx.beginPath();
mctx.arc(
player.x*sx,
player.y*sy,
6,
0,
Math.PI*2
);
mctx.fill();
/* PLAYER DIRECTION */
mctx.strokeStyle="#168cff";
mctx.lineWidth=2;
mctx.beginPath();
mctx.moveTo(
player.x*sx,
player.y*sy
);
mctx.lineTo(
(
player.x+
Math.cos(player.angle)*1.5
)*sx,
(
player.y+
Math.sin(player.angle)*1.5
)*sy
);
mctx.stroke();
}
/* =====================================================
GAME LOOP
===================================================== */
function loop(time){
if(!lastTime)
lastTime=time;
let dt=
(time-lastTime)/1000;
lastTime=time;
if(dt>.05)
dt=.05;
updatePlayer(dt);
updateEnemies(dt);
updateHUD();
render();
drawMini();
requestAnimationFrame(loop);
}
updateWeapon();
requestAnimationFrame(loop);
</script>
</body>
</html>
Game Source: FPS Arena - Map 2
Creator: NeonGamer52
Libraries: none
Complexity: complex (2148 lines, 34.6 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: fps-arena-map-2-neongamer52" to link back to the original. Then publish at arcadelab.ai/publish.