DEV Community

Ellis John
Ellis John

Posted on

gat

<!DOCTYPE html>


🏙️ Street Life - Mini City Game
<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
Enter fullscreen mode Exit fullscreen mode

⬆⬇⬅➡ 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();
Enter fullscreen mode Exit fullscreen mode

}

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 &lt; 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=&gt;{
    if(player.x &lt; p.x+p.w &amp;&amp; player.x+player.w &gt; p.x &amp;&amp;
       player.y &lt; p.y+p.h &amp;&amp; player.y+player.h &gt; p.y) {
        money += p.value;
        return false;
    }
    return true;
});
if(gameTime % 180 === 0) spawnPickup();

// Complete mission
if(keys[' '] &amp;&amp; mission) {
    let b = checkBuildingCollision({x:player.x,y:player.y,w:player.w,h:player.h});
    if(b &amp;&amp; b.n === mission.target) {
        money += mission.reward;
        missionText = 'Complete! +$'+mission.reward;
        mission=null;
        setTimeout(newMission, 1500);
    }
    keys[' ']=false;
}

updateUI();
Enter fullscreen mode Exit fullscreen mode

}

function draw() {
// Ground
ctx.fillStyle='#3d6b34';
ctx.fillRect(0,0,canvas.width,canvas.height);

// Roads
roads.forEach(r=&gt;{
    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&gt;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=&gt;{
    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&lt;Math.floor(b.w/40);i++) {
        for(let j=0;j&lt;Math.floor(b.h/35);j++) {
            if(Math.random()&gt;0.3) ctx.fillRect(b.x+10+i*40, b.y+25+j*35,12,15);
        }
    }
});

// Money pickups
pickups.forEach(p=&gt;{
    ctx.font='20px Arial'; ctx.fillText('💰',p.x-2,p.y+16);
});

// Cars
cars.forEach(c=&gt;{
    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=&gt;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();
    }
}
Enter fullscreen mode Exit fullscreen mode

}

function loop() { update(); draw(); requestAnimationFrame(loop); }
initWorld();
loop();

Top comments (0)