forms

Urban Havoc 3D Game

Urban Havoc 3D is a high-octane, neon-drenched combat driving simulator built for speed and destruction. Set in a sprawling procedural "cyber-noir" city, you pilot a heavily armed tactical unit designed for maximum impact.

Key Features:

Tactical Combat: Engage infinite waves of urban traffic using a front-mounted kinetic cannon.

Dynamic Power-ups: Scavenge the grid for yellow data-modules to upgrade your chassis with "Triple-Shot" or "Rapid-Fire" capabilities.

Immersive Visuals: Experience a high-contrast aesthetic with real-time shadows, fog-heavy atmosphere, and responsive particle effects for every explosion.

High-Speed Physics: Master a drift-heavy handling model where momentum is your best friend and your worst enemy.

Live Dashboard: Monitor your chassis integrity and tachometer in real-time with a sleek, minimalist glass-morphism UI.

Controls:

WASD / Arrows: Accelerate, Brake, and Steer.

SPACE: Unleash your primary weapon.

Objective: Survive the grid, collect modules, and wreak as much havoc as possible!

Code Snippet

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Urban Havoc 3D</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;900&display=swap');
        
        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
            background-color: #000;
            font-family: 'Inter', sans-serif;
            color: white;
        }

        #ui-container {
            position: absolute;
            top: 24px;
            left: 24px;
            right: 24px;
            display: flex;
            justify-content: space-between;
            pointer-events: none;
            z-index: 20;
        }

        .stat-panel {
            background: rgba(0, 0, 0, 0.9);
            padding: 16px;
            border-left: 4px solid #dc2626;
            backdrop-filter: blur(10px);
            min-width: 220px;
            margin-bottom: 8px;
        }

        .stat-label {
            font-size: 10px;
            color: #6b7280;
            text-transform: uppercase;
            letter-spacing: 0.1em;
            font-weight: 900;
            margin-bottom: 4px;
        }

        .health-bar-bg {
            width: 100%;
            height: 8px;
            background: #111827;
            border-radius: 999px;
            overflow: hidden;
            border: 1px solid rgba(255, 255, 255, 0.05);
        }

        #health-fill {
            height: 100%;
            background: linear-gradient(to right, #b91c1c, #ef4444);
            transition: width 0.3s ease;
            width: 100%;
        }

        .speed-panel {
            text-align: right;
            border-left: 0;
            border-right: 4px solid #2563eb;
        }

        #speed-val {
            font-size: 48px;
            font-weight: 900;
            font-style: italic;
            letter-spacing: -0.05em;
        }

        .unit-label {
            font-size: 14px;
            color: #3b82f6;
        }

        #menu-overlay {
            position: absolute;
            inset: 0;
            background: rgba(0, 0, 0, 0.9);
            backdrop-filter: blur(20px);
            display: flex;
            align-items: center;
            justify-content: center;
            text-align: center;
            z-index: 50;
        }

        .hero-title {
            font-size: clamp(48px, 10vw, 120px);
            font-weight: 900;
            font-style: italic;
            letter-spacing: -0.05em;
            line-height: 0.8;
            margin-bottom: 16px;
        }

        .red-accent { color: #dc2626; font-style: normal; }

        #start-btn {
            background: #dc2626;
            color: white;
            border: none;
            padding: 24px 80px;
            font-size: 24px;
            font-weight: 900;
            text-transform: uppercase;
            cursor: pointer;
            transform: skewX(-12deg);
            transition: all 0.3s;
            box-shadow: 0 0 50px rgba(220, 38, 38, 0.4);
            pointer-events: auto;
        }

        #start-btn:hover {
            background: white;
            color: black;
            box-shadow: 0 0 70px rgba(255, 255, 255, 0.2);
        }

        #crosshair {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 64px;
            height: 64px;
            border: 1px solid rgba(255, 255, 255, 0.1);
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            pointer-events: none;
            display: none;
        }

        .dot {
            width: 6px;
            height: 6px;
            background: #dc2626;
            border-radius: 50%;
            box-shadow: 0 0 15px red;
        }
    </style>
</head>
<body>

    <div id="ui-container">
        <div>
            <div class="stat-panel">
                <div class="stat-label">Chassis Integrity</div>
                <div class="health-bar-bg">
                    <div id="health-fill"></div>
                </div>
            </div>
            <div class="stat-panel" style="border-color: #eab308;">
                <div class="stat-label">Active Module</div>
                <div id="weapon-name" style="color: #eab308; font-weight: 900; font-size: 24px; text-transform: uppercase;">Standard</div>
            </div>
        </div>
        <div class="speed-panel stat-panel">
            <div class="stat-label">Tachometer</div>
            <div id="speed-val">0 <span class="unit-label">KM/H</span></div>
            <div style="font-size: 10px; margin-top: 10px; color: #9ca3af;">HAVOC: <span id="score-val" style="color: white; font-size: 14px;">0</span></div>
        </div>
    </div>

    <div id="crosshair"><div class="dot"></div></div>

    <div id="menu-overlay">
        <div>
            <h1 class="hero-title" id="main-title">URBAN<span class="red-accent">HAVOC</span></h1>
            <div style="height: 4px; width: 96px; background: #dc2626; margin: 0 auto 32px;"></div>
            <p id="sub-title" style="letter-spacing: 0.4em; color: #9ca3af; text-transform: uppercase; font-size: 12px; margin-bottom: 48px;">
                Advanced Urban Combat Logistics Protocol
            </p>
            <button id="start-btn">Deploy Unit</button>
            <div style="margin-top: 60px; display: flex; justify-content: center; gap: 40px; color: #6b7280; font-size: 10px; text-transform: uppercase; letter-spacing: 0.2em; border-top: 1px solid rgba(255,255,255,0.1); padding-top: 30px;">
                <div><span style="color: white; display: block; font-size: 14px; margin-bottom: 4px;">WASD</span> Movement</div>
                <div><span style="color: white; display: block; font-size: 14px; margin-bottom: 4px;">SPACE</span> Fire Weapon</div>
            </div>
        </div>
    </div>

    <script>
        let gameActive = false;
        let score = 0;
        let health = 100;
        
        const keys = {};
        const state = {
            bullets: [],
            traffic: [],
            pickups: [],
            particles: [],
            lastFireTime: 0,
            weaponCooldown: 400,
            worldSize: 5000,
            blockSize: 200,
            roadWidth: 40
        };

        let scene, camera, renderer, player;

        // Ensure key states are tracked globally regardless of game status
        window.addEventListener('keydown', e => { 
            keys[e.code] = true;
        });
        window.addEventListener('keyup', e => { 
            keys[e.code] = false;
        });

        function init() {
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0x020205);
            scene.fog = new THREE.Fog(0x020205, 100, 850);

            camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 3000);
            
            renderer = new THREE.WebGLRenderer({ antialias: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.shadowMap.enabled = true;
            document.body.appendChild(renderer.domElement);

            scene.add(new THREE.AmbientLight(0xffffff, 0.3));
            const sun = new THREE.DirectionalLight(0xffffff, 1.2);
            sun.position.set(200, 500, 200);
            sun.castShadow = true;
            sun.shadow.camera.left = -1000;
            sun.shadow.camera.right = 1000;
            sun.shadow.camera.top = 1000;
            sun.shadow.camera.bottom = -1000;
            scene.add(sun);

            createWorld();
            spawnPlayer();
            spawnTraffic(80);
            spawnPickups(15);

            window.addEventListener('resize', onWindowResize);
            
            // Animation loop starts immediately
            animate();
        }

        function createWorld() {
            const ground = new THREE.Mesh(
                new THREE.PlaneGeometry(state.worldSize, state.worldSize),
                new THREE.MeshStandardMaterial({ color: 0x0a0a0a })
            );
            ground.rotation.x = -Math.PI / 2;
            ground.receiveShadow = true;
            scene.add(ground);

            const roadMat = new THREE.MeshStandardMaterial({ color: 0x1a1a1a });

            for (let i = -12; i <= 12; i++) {
                const pos = i * state.blockSize;
                // Horizontal Roads
                const hRoad = new THREE.Mesh(new THREE.PlaneGeometry(state.worldSize, state.roadWidth), roadMat);
                hRoad.rotation.x = -Math.PI / 2;
                hRoad.position.set(0, 0.05, pos);
                scene.add(hRoad);

                // Vertical Roads
                const vRoad = new THREE.Mesh(new THREE.PlaneGeometry(state.roadWidth, state.worldSize), roadMat);
                vRoad.rotation.x = -Math.PI / 2;
                vRoad.position.set(pos, 0.05, 0);
                scene.add(vRoad);

                for (let j = -12; j <= 12; j++) {
                    const bx = j * state.blockSize;
                    if (Math.abs(bx) < 50 && Math.abs(pos) < 50) continue; 
                    if (Math.random() > 0.3) {
                        const h = 40 + Math.random() * 160;
                        const w = 40 + Math.random() * 30;
                        const color = [0x222222, 0x333333, 0x1a1a1a][Math.floor(Math.random()*3)];
                        scene.add(createBuildingModel(bx + 80, pos + 80, w, h, color));
                    }
                    scene.add(createTreeModel(bx + 30, pos + 30));
                }
            }
        }

        function createBuildingModel(x, z, w, h, color) {
            const group = new THREE.Group();
            const body = new THREE.Mesh(new THREE.BoxGeometry(w, h, w), new THREE.MeshStandardMaterial({ color, roughness: 0.7 }));
            body.position.y = h / 2;
            body.castShadow = true;
            group.add(body);
            group.position.set(x, 0, z);
            return group;
        }

        function createTreeModel(x, z) {
            const group = new THREE.Group();
            const trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.5, 0.8, 4), new THREE.MeshStandardMaterial({color: 0x3d2b1f}));
            trunk.position.y = 2;
            group.add(trunk);
            const foliage = new THREE.Mesh(new THREE.ConeGeometry(3, 8, 7), new THREE.MeshStandardMaterial({color: 0x1b3d1b}));
            foliage.position.y = 7;
            group.add(foliage);
            group.position.set(x, 0, z);
            return group;
        }

        function createVehicleModel(color, isPlayer = false) {
            const group = new THREE.Group();
            const bodyMat = new THREE.MeshStandardMaterial({ color, roughness: 0.1, metalness: 0.8 });
            const chassis = new THREE.Mesh(new THREE.BoxGeometry(5, 1.5, 10), bodyMat);
            chassis.position.y = 1.5;
            chassis.castShadow = true;
            group.add(chassis);
            const cabin = new THREE.Mesh(new THREE.BoxGeometry(4.2, 1.5, 5.5), bodyMat);
            cabin.position.set(0, 2.8, -0.5);
            group.add(cabin);
            
            const wheels = [];
            const wheelGeo = new THREE.CylinderGeometry(1, 1, 1.2, 12);
            const wheelMat = new THREE.MeshStandardMaterial({ color: 0x050505 });
            [[2.6, 1, 3], [-2.6, 1, 3], [2.6, 1, -3], [-2.6, 1, -3]].forEach(p => {
                const w = new THREE.Mesh(wheelGeo, wheelMat);
                w.rotation.z = Math.PI / 2;
                w.position.set(...p);
                group.add(w);
                wheels.push(w);
            });
            if (isPlayer) {
                const barrel = new THREE.Mesh(new THREE.CylinderGeometry(0.3, 0.4, 4), new THREE.MeshStandardMaterial({color: 0x111111}));
                barrel.rotation.x = Math.PI / 2;
                barrel.position.set(0, 2, 5.5);
                group.add(barrel);
            }
            group.userData.wheels = wheels;
            return group;
        }

        function spawnPlayer() {
            const mesh = createVehicleModel(0xdc2626, true);
            scene.add(mesh);
            player = { 
                mesh, 
                speed: 0, 
                angle: 0, 
                health: 100, 
                weaponType: 'Standard',
                accel: 0.15,      // Increased base acceleration
                maxSpeed: 4.5,    // Terminal velocity
                friction: 0.94    // Natural deceleration
            };
        }

        function spawnTraffic(count) {
            const colors = [0x2563eb, 0xd97706, 0x059669, 0x7c3aed];
            for (let i = 0; i < count; i++) {
                const car = createVehicleModel(colors[i % colors.length]);
                const rx = (Math.round((Math.random() - 0.5) * 12)) * state.blockSize;
                const rz = (Math.random() - 0.5) * 3000;
                car.position.set(rx + (Math.random() > 0.5 ? 10 : -10), 0, rz);
                if (Math.random() > 0.5) car.rotation.y = Math.PI;
                scene.add(car);
                state.traffic.push({ mesh: car, speed: 0.8 + Math.random() * 1.2 });
            }
        }

        function spawnPickups(count) {
            for (let i = 0; i < count; i++) {
                const p = new THREE.Group();
                const box = new THREE.Mesh(new THREE.BoxGeometry(4, 4, 4), new THREE.MeshStandardMaterial({color: 0xffff00, emissive: 0x444400}));
                p.add(box);
                p.position.set((Math.random()-0.5)*2000, 3, (Math.random()-0.5)*2000);
                scene.add(p);
                state.pickups.push(p);
            }
        }

        function fire() {
            const now = Date.now();
            if (now - state.lastFireTime < state.weaponCooldown) return;
            state.lastFireTime = now;

            const makeBullet = (offsetAngle = 0) => {
                const b = new THREE.Mesh(new THREE.SphereGeometry(0.6), new THREE.MeshBasicMaterial({color: 0xffaa00}));
                // Start bullet at the end of the barrel
                const bulletPos = new THREE.Vector3(0, 2.5, 8).applyQuaternion(player.mesh.quaternion).add(player.mesh.position);
                b.position.copy(bulletPos);
                
                const v = new THREE.Vector3(0, 0, 7.5).applyQuaternion(player.mesh.quaternion);
                if(offsetAngle !== 0) v.applyAxisAngle(new THREE.Vector3(0,1,0), offsetAngle);
                b.userData = { v, life: 120 };
                scene.add(b);
                state.bullets.push(b);
            };

            if(player.weaponType === 'Triple') {
                makeBullet(-0.15); makeBullet(0); makeBullet(0.15);
            } else {
                makeBullet(0);
            }
        }

        function explode(pos, color = 0xff4400) {
            for (let i = 0; i < 15; i++) {
                const p = new THREE.Mesh(new THREE.SphereGeometry(0.5), new THREE.MeshBasicMaterial({ color }));
                p.position.copy(pos);
                p.userData = { v: new THREE.Vector3((Math.random()-0.5)*4, Math.random()*4, (Math.random()-0.5)*4), life: 1.0 };
                scene.add(p);
                state.particles.push(p);
            }
        }

        function animate() {
            requestAnimationFrame(animate);

            if (gameActive && player) {
                // Input handling
                if (keys['KeyW'] || keys['ArrowUp']) player.speed += player.accel;
                if (keys['KeyS'] || keys['ArrowDown']) player.speed -= player.accel;
                
                // Friction / Deceleration
                player.speed *= player.friction;
                
                // Limit Speed
                if (player.speed > player.maxSpeed) player.speed = player.maxSpeed;
                if (player.speed < -player.maxSpeed / 2) player.speed = -player.maxSpeed / 2;

                // Steering
                if (Math.abs(player.speed) > 0.02) {
                    const turnSpeed = 0.045;
                    const direction = player.speed > 0 ? 1 : -1;
                    if (keys['KeyA'] || keys['ArrowLeft']) player.angle += turnSpeed * direction;
                    if (keys['KeyD'] || keys['ArrowRight']) player.angle -= turnSpeed * direction;
                }

                // Apply transforms
                player.mesh.rotation.y = player.angle;
                const moveVec = new THREE.Vector3(0, 0, 1).applyQuaternion(player.mesh.quaternion).multiplyScalar(player.speed);
                player.mesh.position.add(moveVec);
                
                // Spin wheels
                player.mesh.userData.wheels.forEach(w => w.rotation.x += player.speed * 0.8);

                if (keys['Space']) fire();

                // Projectiles
                for (let i = state.bullets.length - 1; i >= 0; i--) {
                    const b = state.bullets[i];
                    b.position.add(b.userData.v);
                    b.userData.life--;
                    
                    state.traffic.forEach(t => {
                        if (b.position.distanceTo(t.mesh.position) < 10) {
                            explode(t.mesh.position, 0xffff00);
                            t.mesh.position.set((Math.random()-0.5)*1000, 0, player.mesh.position.z + 1500);
                            score += 500;
                            document.getElementById('score-val').innerText = score.toLocaleString();
                            b.userData.life = 0;
                        }
                    });
                    
                    if (b.userData.life <= 0) { 
                        scene.remove(b); 
                        state.bullets.splice(i, 1); 
                    }
                }

                // Traffic Interaction
                state.traffic.forEach(t => {
                    t.mesh.translateZ(t.speed);
                    // Respawn traffic once it gets too far behind
                    if (t.mesh.position.distanceTo(player.mesh.position) > 2000) {
                        t.mesh.position.z = player.mesh.position.z + 1500;
                    }

                    if (t.mesh.position.distanceTo(player.mesh.position) < 9) {
                        health -= 25;
                        explode(t.mesh.position);
                        t.mesh.position.set(t.mesh.position.x, 0, player.mesh.position.z + 1000);
                        updateUI();
                    }
                });

                // Pickups
                state.pickups.forEach((pk, i) => {
                    pk.rotation.y += 0.05;
                    if (pk.position.distanceTo(player.mesh.position) < 12) {
                        applyPowerup();
                        scene.remove(pk);
                        state.pickups.splice(i, 1);
                        spawnPickups(1);
                    }
                });

                // Particles
                for (let i = state.particles.length - 1; i >= 0; i--) {
                    const p = state.particles[i];
                    p.position.add(p.userData.v);
                    p.userData.life -= 0.025;
                    p.scale.setScalar(Math.max(0.01, p.userData.life));
                    if(p.userData.life <= 0) { scene.remove(p); state.particles.splice(i, 1); }
                }

                // Smooth Camera Follow
                const camOffset = new THREE.Vector3(0, 22, -50).applyQuaternion(player.mesh.quaternion);
                const targetCamPos = player.mesh.position.clone().add(camOffset);
                camera.position.lerp(targetCamPos, 0.1);
                camera.lookAt(player.mesh.position.clone().add(new THREE.Vector3(0, 5, 25).applyQuaternion(player.mesh.quaternion)));

                // UI Speed
                document.getElementById('speed-val').innerHTML = `${Math.round(Math.abs(player.speed) * 45)} <span class="unit-label">KM/H</span>`;
            } else {
                // Idle Menu View
                if(player) {
                    const time = Date.now() * 0.0005;
                    camera.position.set(
                        player.mesh.position.x + Math.sin(time) * 80, 
                        40, 
                        player.mesh.position.z + Math.cos(time) * 80
                    );
                    camera.lookAt(player.mesh.position);
                }
            }

            renderer.render(scene, camera);
        }

        function updateUI() {
            const fill = document.getElementById('health-fill');
            fill.style.width = Math.max(0, health) + '%';
            if (health <= 0) {
                gameActive = false;
                document.getElementById('main-title').innerHTML = '<span class="red-accent">WASTED</span>';
                document.getElementById('menu-overlay').style.display = 'flex';
                document.getElementById('crosshair').style.display = 'none';
                document.getElementById('start-btn').innerText = 'Re-Deploy';
            }
        }

        function applyPowerup() {
            const types = ['Triple', 'Rapid'];
            const type = types[Math.floor(Math.random()*types.length)];
            player.weaponType = type;
            state.weaponCooldown = type === 'Rapid' ? 120 : 400;
            const label = document.getElementById('weapon-name');
            label.innerText = type;
            label.style.color = '#ef4444';
            
            setTimeout(() => {
                player.weaponType = 'Standard';
                state.weaponCooldown = 400;
                label.innerText = 'Standard';
                label.style.color = '#eab308';
            }, 8000);
        }

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        window.onload = () => {
            init();
            const startBtn = document.getElementById('start-btn');
            startBtn.addEventListener('click', () => {
                if (health <= 0) {
                    location.reload();
                } else {
                    gameActive = true;
                    document.getElementById('menu-overlay').style.display = 'none';
                    document.getElementById('crosshair').style.display = 'flex';
                    // Force focus for keyboard events
                    window.focus();
                }
            });
        }
    </script>
</body>
</html>

Media & Assets

Urban Havoc 3D Game
Resource ID: #00028
Posted: December 22, 2025
© 2025 Your Code Library.