<!DOCTYPE html>
<br> * { margin:0; padding:0; box-sizing:border-box; font-family:Arial, sans-serif; }<br> body { background:#1a472a; text-align:center; color:white; padding:10px; }<br> canvas { background:#333; border:4px solid #222; }<br> .ui { position:fixed; top:10px; left:10px; text-align:left; background:rgba(0,0,0,0.6); padding:10px; border-radius:8px; z-index:10; }<br> .controls { position:fixed; bottom:10px; left:50%; transform:translateX(-50%); background:rgba(0,0,0,0.6); padding:8px 15px; border-radius:8px; font-size:14px; }<br>
💰 Money: <span id="money">0</span> 🚗 Vehicle: <span id="vehicle">Walking</span> 📍 Mission: <span id="mission">None</span> ⏱️ Time: <span id="time">60</span>s ⬆⬇⬅➡ Move | E=Enter/Exit Car | SPACE=Complete Mission
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
// Player
let player = { x:400, y:300, w:24, h:32, speed:3, inCar:false, car:null };
let money = 0;
let timeLeft = 60;
let gameTime = 0;
let mission = null;
let missionText = 'None';
// World
let buildings = [];
let roads = [];
let cars = [];
let pickups = [];
// Input
const keys = {};
document.addEventListener('keydown', e=>keys[e.key]=true);
document.addEventListener('keyup', e=>keys[e.key]=false);
// Generate city
function initWorld() {
// Roads
roads = [
{x:0,y:250,w:800,h:100},
{x:0,y:450,w:800,h:100},
{x:250,y:0,w:100,h:800},
{x:500,y:0,w:100,h:800}
];
// Buildings
let bData = [
{x:20,y:20,w:200,h:200,c:'#4a6fa5',n:'Apartments'},
{x:300,y:20,w:150,h:200,c:'#8b4513',n:'Warehouse'},
{x:580,y:20,w:200,h:200,c:'#d68029',n:'Mall'},
{x:20,y:320,w:200,h:100,c:'#555',n:'Bank'},
{x:580,y:320,w:200,h:100,c:'#2e8b57',n:'Hospital'},
{x:20,y:520,w:200,h:60,c:'#777',n:'Garage'},
{x:580,y:520,w:200,h:60,c:'#b8860b',n:'Casino'}
];
bData.forEach(b=>buildings.push({...b}));
// Parked cars cars = [ {x:120,y:210,w:40,h:24,c:'#e63946',dx:0,dy:0}, {x:360,y:210,w:40,h:24,c:'#457b9d',dx:0,dy:0}, {x:620,y:210,w:40,h:24,c:'#2a9d8f',dx:0,dy:0}, {x:120,y:490,w:40,h:24,c:'#f4a261',dx:0,dy:0}, {x:620,y:490,w:40,h:24,c:'#9b5de5',dx:0,dy:0} ]; // Money pickups spawnPickup(); newMission(); }
function spawnPickup() {
pickups.push({
x: 80 + Math.random()*640,
y: 80 + Math.random()*440,
w:20,h:20,
value: Math.random()>0.8 ? 100 : 25
});
}
function newMission() {
let missions = [
{text:'Drive to Hospital', target:'Hospital', reward:150},
{text:'Go to Bank', target:'Bank', reward:200},
{text:'Visit Garage', target:'Garage', reward:100},
{text:'Go to Mall', target:'Mall', reward:120},
{text:'Deliver to Apartments', target:'Apartments', reward:180}
];
mission = missions[Math.floor(Math.random()*missions.length)];
missionText = mission.text;
timeLeft = 45;
}
function updateUI() {
document.getElementById('money').textContent = '$' + money;
document.getElementById('vehicle').textContent = player.inCar ? '🚗 Driving' : '🚶 Walking';
document.getElementById('mission').textContent = missionText;
document.getElementById('time').textContent = timeLeft;
}
function checkBuildingCollision(rect) {
for(let b of buildings) {
if(rect.x < b.x+b.w && rect.x+rect.w > b.x &&
rect.y < b.y+b.h && rect.y+rect.h > b.y) return b;
}
return null;
}
function update() {
gameTime++;
if(gameTime % 60 === 0 && timeLeft>0) timeLeft--;
if(timeLeft<=0 && mission) { missionText='Failed!'; mission=null; }
let moveX=0, moveY=0; let speed = player.inCar ? 5 : player.speed; if(keys['ArrowUp']) moveY=-speed; if(keys['ArrowDown']) moveY=speed; if(keys['ArrowLeft']) moveX=-speed; if(keys['ArrowRight']) moveX=speed; // Enter/Exit car if(keys['e'] || keys['E']) { keys['e']=keys['E']=false; if(!player.inCar) { for(let c of cars) { let dist = Math.hypot(player.x-c.x, player.y-c.y); if(dist < 40) { player.inCar = true; player.car = c; c.dx=0; c.dy=0; break; } } } else { player.inCar = false; player.x = player.car.x + 30; player.y = player.car.y; player.car = null; } } // Movement if(player.inCar) { player.car.x += moveX; player.car.y += moveY; // Boundaries player.car.x = Math.max(0, Math.min(canvas.width-player.car.w, player.car.x)); player.car.y = Math.max(0, Math.min(canvas.height-player.car.h, player.car.y)); player.x = player.car.x; player.y = player.car.y; } else { let nx = player.x + moveX; let ny = player.y + moveY; if(!checkBuildingCollision({x:nx,y:player.y,w:player.w,h:player.h})) player.x=nx; if(!checkBuildingCollision({x:player.x,y:ny,w:player.w,h:player.h})) player.y=ny; player.x = Math.max(0, Math.min(canvas.width-player.w, player.x)); player.y = Math.max(0, Math.min(canvas.height-player.h, player.y)); } // Pick up money pickups = pickups.filter(p=>{ if(player.x < p.x+p.w && player.x+player.w > p.x && player.y < p.y+p.h && player.y+player.h > p.y) { money += p.value; return false; } return true; }); if(gameTime % 180 === 0) spawnPickup(); // Complete mission if(keys[' '] && mission) { let b = checkBuildingCollision({x:player.x,y:player.y,w:player.w,h:player.h}); if(b && b.n === mission.target) { money += mission.reward; missionText = 'Complete! +$'+mission.reward; mission=null; setTimeout(newMission, 1500); } keys[' ']=false; } updateUI(); }
function draw() {
// Ground
ctx.fillStyle='#3d6b34';
ctx.fillRect(0,0,canvas.width,canvas.height);
// Roads roads.forEach(r=>{ ctx.fillStyle='#444'; ctx.fillRect(r.x,r.y,r.w,r.h); ctx.strokeStyle='#fff'; ctx.setLineDash([30,20]); ctx.lineWidth=2; ctx.beginPath(); if(r.h>r.w) { ctx.moveTo(r.x+r.w/2,r.y); ctx.lineTo(r.x+r.w/2,r.y+r.h); } else { ctx.moveTo(r.x,r.y+r.h/2); ctx.lineTo(r.x+r.w,r.y+r.h/2); } ctx.stroke(); ctx.setLineDash([]); }); // Buildings buildings.forEach(b=>{ ctx.fillStyle=b.c; ctx.fillRect(b.x,b.y,b.w,b.h); ctx.strokeStyle='#222'; ctx.lineWidth=3; ctx.strokeRect(b.x,b.y,b.w,b.h); ctx.fillStyle='#fff'; ctx.font='12px Arial'; ctx.fillText(b.n, b.x+8, b.y+18); // Windows ctx.fillStyle='#ffff99'; for(let i=0;i<Math.floor(b.w/40);i++) { for(let j=0;j<Math.floor(b.h/35);j++) { if(Math.random()>0.3) ctx.fillRect(b.x+10+i*40, b.y+25+j*35,12,15); } } }); // Money pickups pickups.forEach(p=>{ ctx.font='20px Arial'; ctx.fillText('💰',p.x-2,p.y+16); }); // Cars cars.forEach(c=>{ ctx.fillStyle=c.c; ctx.fillRect(c.x,c.y,c.w,c.h); ctx.fillStyle='#222'; ctx.fillRect(c.x+4,c.y+4,c.w-8,c.h-8); ctx.fillStyle='#fff'; ctx.font='11px Arial'; ctx.fillText('🚗',c.x+8,c.y+18); }); // Player if(!player.inCar) { ctx.font='26px Arial'; ctx.fillText('🧍',player.x-4,player.y+26); } // Mission arrow if(mission) { let tgt = buildings.find(b=>b.n===mission.target); if(tgt) { ctx.strokeStyle='#ffff00'; ctx.lineWidth=3; ctx.beginPath(); ctx.moveTo(player.x+12, player.y+16); ctx.lineTo(tgt.x+tgt.w/2, tgt.y+tgt.h/2); ctx.stroke(); } } }
function loop() { update(); draw(); requestAnimationFrame(loop); }
initWorld();
loop();
