APK FET
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!
<!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>