<!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();
Top comments (0)