🎮ArcadeLab

Zombie Survival 3D

by LaserTiger28
781 lines13.2 KB🛠️ Three.js (3D graphics)
▶ Play
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zombie Survival 3D</title>

<style>
    * {
        box-sizing: border-box;
    }

    body {
        margin: 0;
        overflow: hidden;
        background: #000;
        font-family: Arial, sans-serif;
    }

    #hud {
        position: fixed;
        top: 15px;
        left: 15px;
        color: white;
        font-size: 20px;
        z-index: 10;
        text-shadow: 2px 2px 4px #000;
    }

    #menu {
        position: fixed;
        inset: 0;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        background: rgba(0,0,0,.8);
        color: white;
        z-index: 20;
        text-align: center;
    }

    #menu h1 {
        font-size: 50px;
        margin-bottom: 10px;
    }

    button {
        padding: 15px 30px;
        font-size: 20px;
        border: none;
        border-radius: 10px;
        cursor: pointer;
        background: #2ecc71;
        color: white;
    }

    #crosshair {
        position: fixed;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        color: white;
        font-size: 25px;
        z-index: 5;
        pointer-events: none;
    }

    #message {
        position: fixed;
        bottom: 25px;
        left: 50%;
        transform: translateX(-50%);
        color: white;
        font-size: 18px;
        z-index: 10;
        text-align: center;
    }
</style>
</head>

<body>

<div id="menu">
    <h1>🧟 ZOMBIE SURVIVAL 3D</h1>
    <p>Sobreviva o máximo que conseguir!</p>
    <p>WASD = andar | Mouse = olhar</p>
    <p>Corra dos zumbis e encontre os itens!</p>
    <button onclick="startGame()">COMEÇAR</button>
</div>

<div id="hud">
    ❤️ Vida: <span id="health">100</span><br>
    ⭐ Pontos: <span id="score">0</span><br>
    ⏱️ Tempo: <span id="time">0</span><br>
    🧟 Zumbis: <span id="zombies">0</span>
</div>

<div id="crosshair">+</div>

<div id="message">
    Encontre os itens verdes para ganhar pontos!
</div>

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

<script>

let scene, camera, renderer;
let player;
let zombies = [];
let items = [];

let health = 100;
let score = 0;
let gameTime = 0;
let gameStarted = false;

let keys = {};

const clock = new THREE.Clock();


// ==========================
// INICIAR JOGO
// ==========================

function startGame() {

    document.getElementById("menu").style.display = "none";

    gameStarted = true;

    health = 100;
    score = 0;
    gameTime = 0;

    init();

    document.body.requestPointerLock();

    animate();
}


// ==========================
// CRIAR CENA
// ==========================

function init() {

    scene = new THREE.Scene();

    scene.background = new THREE.Color(0x101820);

    scene.fog = new THREE.Fog(
        0x101820,
        20,
        180
    );


    // CÂMERA

    camera = new THREE.PerspectiveCamera(
        75,
        window.innerWidth / window.innerHeight,
        0.1,
        500
    );


    camera.position.set(
        0,
        2,
        10
    );


    // RENDERIZADOR

    renderer = new THREE.WebGLRenderer({
        antialias: true
    });

    renderer.setSize(
        window.innerWidth,
        window.innerHeight
    );

    renderer.shadowMap.enabled = true;

    document.body.appendChild(
        renderer.domElement
    );


    // LUZ

    const ambient = new THREE.AmbientLight(
        0xffffff,
        0.45
    );

    scene.add(ambient);


    const moon = new THREE.DirectionalLight(
        0xffffff,
        1
    );

    moon.position.set(
        30,
        50,
        20
    );

    moon.castShadow = true;

    scene.add(moon);


    // CHÃO

    const floorGeometry =
        new THREE.PlaneGeometry(
            300,
            300
        );

    const floorMaterial =
        new THREE.MeshStandardMaterial({
            color: 0x263238
        });

    const floor =
        new THREE.Mesh(
            floorGeometry,
            floorMaterial
        );

    floor.rotation.x = -Math.PI / 2;

    floor.receiveShadow = true;

    scene.add(floor);


    // ESTRADA

    const roadGeometry =
        new THREE.PlaneGeometry(
            18,
            300
        );

    const roadMaterial =
        new THREE.MeshStandardMaterial({
            color: 0x151515
        });

    const road =
        new THREE.Mesh(
            roadGeometry,
            roadMaterial
        );

    road.rotation.x = -Math.PI / 2;

    road.position.y = 0.01;

    scene.add(road);


    // ÁRVORES

    for (let i = 0; i < 100; i++) {
        createTree();
    }


    // CASAS

    for (let i = 0; i < 20; i++) {
        createHouse();
    }


    // JOGADOR

    const playerGeometry =
        new THREE.BoxGeometry(
            1,
            2,
            1
        );

    const playerMaterial =
        new THREE.MeshStandardMaterial({
            color: 0x3498db
        });

    player =
        new THREE.Mesh(
            playerGeometry,
            playerMaterial
        );

    player.position.set(
        0,
        1,
        10
    );

    player.castShadow = true;

    scene.add(player);


    // ITENS

    for (let i = 0; i < 20; i++) {
        createItem();
    }


    // ZUMBIS

    for (let i = 0; i < 8; i++) {
        createZombie();
    }


    // CONTROLES

    document.addEventListener(
        "keydown",
        e => {
            keys[e.key.toLowerCase()] = true;
        }
    );

    document.addEventListener(
        "keyup",
        e => {
            keys[e.key.toLowerCase()] = false;
        }
    );


    document.addEventListener(
        "mousemove",
        mouseLook
    );


    window.addEventListener(
        "resize",
        resize
    );
}


// ==========================
// ÁRVORE
// ==========================

function createTree() {

    const trunk =
        new THREE.Mesh(
            new THREE.CylinderGeometry(
                0.4,
                0.6,
                4
            ),
            new THREE.MeshStandardMaterial({
                color: 0x5d4037
            })
        );

    const leaves =
        new THREE.Mesh(
            new THREE.SphereGeometry(
                2.2,
                8,
                8
            ),
            new THREE.MeshStandardMaterial({
                color: 0x1b5e20
            })
        );

    const x =
        (Math.random() - .5) * 250;

    const z =
        (Math.random() - .5) * 250;

    trunk.position.set(
        x,
        2,
        z
    );

    leaves.position.set(
        x,
        5,
        z
    );

    trunk.castShadow = true;
    leaves.castShadow = true;

    scene.add(trunk);
    scene.add(leaves);
}


// ==========================
// CASA
// ==========================

function createHouse() {

    const house =
        new THREE.Mesh(
            new THREE.BoxGeometry(
                8,
                5,
                8
            ),
            new THREE.MeshStandardMaterial({
                color: 0x546e7a
            })
        );

    house.position.set(
        (Math.random() - .5) * 220,
        2.5,
        (Math.random() - .5) * 220
    );

    house.castShadow = true;

    scene.add(house);
}


// ==========================
// ITEM
// ==========================

function createItem() {

    const item =
        new THREE.Mesh(
            new THREE.BoxGeometry(
                0.8,
                0.8,
                0.8
            ),
            new THREE.MeshStandardMaterial({
                color: 0x00ff66,
                emissive: 0x003311
            })
        );

    item.position.set(
        (Math.random() - .5) * 180,
        0.5,
        (Math.random() - .5) * 180
    );

    scene.add(item);

    items.push(item);
}


// ==========================
// ZUMBI
// ==========================

function createZombie() {

    const zombie =
        new THREE.Mesh(
            new THREE.BoxGeometry(
                1.2,
                2.2,
                1.2
            ),
            new THREE.MeshStandardMaterial({
                color: 0x7cb342
            })
        );

    zombie.position.set(
        (Math.random() - .5) * 180,
        1.1,
        (Math.random() - .5) * 180
    );

    zombie.speed =
        0.015 + Math.random() * 0.02;

    zombie.castShadow = true;

    scene.add(zombie);

    zombies.push(zombie);
}


// ==========================
// MOVIMENTO
// ==========================

function updatePlayer() {

    if (!player) return;

    let speed = 0.12;

    if (keys["shift"]) {
        speed = 0.2;
    }

    if (keys["w"] || keys["arrowup"]) {
        player.position.z -= speed;
    }

    if (keys["s"] || keys["arrowdown"]) {
        player.position.z += speed;
    }

    if (keys["a"] || keys["arrowleft"]) {
        player.position.x -= speed;
    }

    if (keys["d"] || keys["arrowright"]) {
        player.position.x += speed;
    }

    camera.position.x =
        player.position.x;

    camera.position.y =
        player.position.y + 1;

    camera.position.z =
        player.position.z + 5;
}


// ==========================
// ZUMBIS SEGUEM O JOGADOR
// ==========================

function updateZombies() {

    zombies.forEach(zombie => {

        const direction =
            new THREE.Vector3()
            .subVectors(
                player.position,
                zombie.position
            )
            .normalize();

        zombie.position.x +=
            direction.x * zombie.speed;

        zombie.position.z +=
            direction.z * zombie.speed;


        const distance =
            zombie.position.distanceTo(
                player.position
            );


        if (distance < 1.8) {

            health -= 0.15;

            if (health <= 0) {
                gameOver();
            }
        }
    });
}


// ==========================
// PEGAR ITENS
// ==========================

function updateItems() {

    for (
        let i = items.length - 1;
        i >= 0;
        i--
    ) {

        const item = items[i];

        const distance =
            item.position.distanceTo(
                player.position
            );

        if (distance < 2) {

            score += 10;

            scene.remove(item);

            items.splice(i, 1);

            createItem();
        }
    }
}


// ==========================
// MOUSE
// ==========================

let rotationY = 0;

function mouseLook(event) {

    if (!gameStarted) return;

    rotationY -=
        event.movementX * 0.002;

    camera.rotation.y =
        rotationY;
}


// ==========================
// TEMPO
// ==========================

function updateGame() {

    gameTime +=
        clock.getDelta();

    // A cada 15 segundos aparece um novo zumbi

    if (
        Math.floor(gameTime) % 15 === 0 &&
        zombies.length < 40
    ) {

        if (
            Math.random() < 0.03
        ) {
            createZombie();
        }
    }


    document.getElementById(
        "health"
    ).textContent =
        Math.max(
            0,
            Math.floor(health)
        );


    document.getElementById(
        "score"
    ).textContent =
        score;


    document.getElementById(
        "time"
    ).textContent =
        Math.floor(gameTime);


    document.getElementById(
        "zombies"
    ).textContent =
        zombies.length;
}


// ==========================
// GAME OVER
// ==========================

function gameOver() {

    gameStarted = false;

    document.exitPointerLock();

    document.getElementById(
        "menu"
    ).style.display = "flex";

    document.querySelector(
        "#menu h1"
    ).textContent =
        "GAME OVER";

    document.querySelector(
        "#menu p"
    ).textContent =
        "Pontuação: " + score;

    document.querySelector(
        "#menu button"
    ).textContent =
        "JOGAR NOVAMENTE";
}


// ==========================
// RESIZE
// ==========================

function resize() {

    camera.aspect =
        window.innerWidth /
        window.innerHeight;

    camera.updateProjectionMatrix();

    renderer.setSize(
        window.innerWidth,
        window.innerHeight
    );
}


// ==========================
// LOOP
// ==========================

function animate() {

    if (!gameStarted) return;

    requestAnimationFrame(
        animate
    );

    updatePlayer();

    updateZombies();

    updateItems();

    updateGame();

    renderer.render(
        scene,
        camera
    );
}

</script>

</body>
</html>

Game Source: Zombie Survival 3D

Creator: LaserTiger28

Libraries: three

Complexity: complex (781 lines, 13.2 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: zombie-survival-3d-lasertiger28" to link back to the original. Then publish at arcadelab.ai/publish.