🎮ArcadeLab

3D FPS Zombie Game

by PlasmaHero19
200 lines4.6 KB🛠️ Three.js (3D graphics)
▶ Play
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>3D FPS Zombie Game</title>
<style>
body { margin:0; overflow:hidden; font-family:Arial; }
#hud {
  position:absolute; top:10px; left:10px;
  color:white; z-index:10;
}
#hpBar {
  width:200px; height:20px;
  background:red;
}
#hp {
  height:100%; width:100%;
  background:lime;
}
#msg {
  position:absolute;
  top:50%; left:50%;
  transform:translate(-50%,-50%);
  color:white;
  font-size:24px;
}
</style>
</head>
<body>

<div id="hud">
  ❤️ HP
  <div id="hpBar"><div id="hp"></div></div>
  🔫 Ammo: <span id="ammo">12</span>/12
</div>
<div id="msg">Click to Play</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>

<script>
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

camera.position.y = 2;

let move = {forward:false,back:false,left:false,right:false};
let velocity = new THREE.Vector3();

let hp = 100;
let ammo = 12;
let reloading = false;

let zombies = [];
let bullets = [];

function createCity(){
  for(let i=0;i<50;i++){
    let box = new THREE.Mesh(
      new THREE.BoxGeometry(2,Math.random()*10+2,2),
      new THREE.MeshBasicMaterial({color:0x555555})
    );
    box.position.set(
      (Math.random()-0.5)*100,
      box.geometry.parameters.height/2,
      (Math.random()-0.5)*100
    );
    scene.add(box);
  }
}

function createZombie(x,z){
  let zmb = new THREE.Mesh(
    new THREE.BoxGeometry(1,2,1),
    new THREE.MeshBasicMaterial({color:0x00ff00})
  );
  zmb.position.set(x,1,z);
  scene.add(zmb);
  zombies.push(zmb);
}

for(let i=0;i<5;i++){
  createZombie((Math.random()-0.5)*50, (Math.random()-0.5)*50);
}

createCity();

let pointerLocked = false;

document.body.onclick = () => {
  document.body.requestPointerLock();
  document.getElementById("msg").style.display="none";
};

document.addEventListener("mousemove", (e)=>{
  if(document.pointerLockElement === document.body){
    camera.rotation.y -= e.movementX * 0.002;
    camera.rotation.x -= e.movementY * 0.002;
  }
});

document.addEventListener("keydown", (e)=>{
  if(e.key=="w") move.forward=true;
  if(e.key=="s") move.back=true;
  if(e.key=="a") move.left=true;
  if(e.key=="d") move.right=true;
});

document.addEventListener("keyup", (e)=>{
  if(e.key=="w") move.forward=false;
  if(e.key=="s") move.back=false;
  if(e.key=="a") move.left=false;
  if(e.key=="d") move.right=false;
});

function shoot(){
  if(reloading) return;
  if(ammo<=0) return;

  ammo--;
  document.getElementById("ammo").innerText = ammo;

  let ray = new THREE.Raycaster();
  ray.setFromCamera({x:0,y:0}, camera);

  let hit = ray.intersectObjects(zombies);

  if(hit.length>0){
    let z = hit[0].object;

    scene.remove(z);
    zombies = zombies.filter(x=>x!==z);

    // spawn 2 zombies after 1 min
    setTimeout(()=>{
      createZombie(Math.random()*50-25, Math.random()*50-25);
      createZombie(Math.random()*50-25, Math.random()*50-25);
    },60000);
  }

  if(ammo==0){
    reloading = true;
    setTimeout(()=>{
      ammo = 12;
      document.getElementById("ammo").innerText = ammo;
      reloading = false;
    },2000);
  }
}

document.addEventListener("click", shoot);

function damagePlayer(){
  hp -= 0.1;
  document.getElementById("hp").style.width = hp+"%";
  if(hp<=0){
    alert("Game Over");
    location.reload();
  }
}

function animate(){
  requestAnimationFrame(animate);

  let speed = 0.2;

  if(move.forward) camera.position.z -= Math.cos(camera.rotation.y)*speed;
  if(move.forward) camera.position.x -= Math.sin(camera.rotation.y)*speed;

  if(move.back) camera.position.z += Math.cos(camera.rotation.y)*speed;
  if(move.back) camera.position.x += Math.sin(camera.rotation.y)*speed;

  if(move.left) camera.position.x -= Math.cos(camera.rotation.y)*speed;
  if(move.right) camera.position.x += Math.cos(camera.rotation.y)*speed;

  zombies.forEach(z=>{
    z.position.lerp(camera.position, 0.005);

    let dist = z.position.distanceTo(camera.position);
    if(dist<2){
      damagePlayer();
    }
  });

  renderer.render(scene,camera);
}

animate();

window.addEventListener("resize",()=>{
  camera.aspect = window.innerWidth/window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>

</body>
</html>

Game Source: 3D FPS Zombie Game

Creator: PlasmaHero19

Libraries: three

Complexity: complex (200 lines, 4.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: 3d-fps-zombie-game-plasmahero19" to link back to the original. Then publish at arcadelab.ai/publish.