<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ellis John</title>
    <description>The latest articles on DEV Community by Ellis John (@ellis_john_bfe0348def630b).</description>
    <link>https://dev.to/ellis_john_bfe0348def630b</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4243670%2F889a1175-1bba-40b3-a255-3bebba6f03ad.png</url>
      <title>DEV Community: Ellis John</title>
      <link>https://dev.to/ellis_john_bfe0348def630b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ellis_john_bfe0348def630b"/>
    <language>en</language>
    <item>
      <title>gat</title>
      <dc:creator>Ellis John</dc:creator>
      <pubDate>Fri, 13 Nov 2026 23:29:22 +0000</pubDate>
      <link>https://dev.to/ellis_john_bfe0348def630b/gat-2b1p</link>
      <guid>https://dev.to/ellis_john_bfe0348def630b/gat-2b1p</guid>
      <description>&lt;p&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
    &lt;/p&gt;
🏙️ Street Life - Mini City Game
&lt;br&gt;
    &amp;lt;br&amp;gt;
        * { margin:0; padding:0; box-sizing:border-box; font-family:Arial, sans-serif; }&amp;lt;br&amp;gt;
        body { background:#1a472a; text-align:center; color:white; padding:10px; }&amp;lt;br&amp;gt;
        canvas { background:#333; border:4px solid #222; }&amp;lt;br&amp;gt;
        .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; }&amp;lt;br&amp;gt;
        .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; }&amp;lt;br&amp;gt;
    &lt;br&gt;
&lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;💰 Money: &amp;lt;span id="money"&amp;gt;0&amp;lt;/span&amp;gt;
🚗 Vehicle: &amp;lt;span id="vehicle"&amp;gt;Walking&amp;lt;/span&amp;gt;
📍 Mission: &amp;lt;span id="mission"&amp;gt;None&amp;lt;/span&amp;gt;
⏱️ Time: &amp;lt;span id="time"&amp;gt;60&amp;lt;/span&amp;gt;s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;⬆⬇⬅➡ Move | E=Enter/Exit Car | SPACE=Complete Mission&lt;/p&gt;

&lt;p&gt;const canvas = document.getElementById('game');&lt;br&gt;
const ctx = canvas.getContext('2d');&lt;/p&gt;

&lt;p&gt;// Player&lt;br&gt;
let player = { x:400, y:300, w:24, h:32, speed:3, inCar:false, car:null };&lt;br&gt;
let money = 0;&lt;br&gt;
let timeLeft = 60;&lt;br&gt;
let gameTime = 0;&lt;br&gt;
let mission = null;&lt;br&gt;
let missionText = 'None';&lt;/p&gt;

&lt;p&gt;// World&lt;br&gt;
let buildings = [];&lt;br&gt;
let roads = [];&lt;br&gt;
let cars = [];&lt;br&gt;
let pickups = [];&lt;/p&gt;

&lt;p&gt;// Input&lt;br&gt;
const keys = {};&lt;br&gt;
document.addEventListener('keydown', e=&amp;gt;keys[e.key]=true);&lt;br&gt;
document.addEventListener('keyup', e=&amp;gt;keys[e.key]=false);&lt;/p&gt;

&lt;p&gt;// Generate city&lt;br&gt;
function initWorld() {&lt;br&gt;
    // Roads&lt;br&gt;
    roads = [&lt;br&gt;
        {x:0,y:250,w:800,h:100},&lt;br&gt;
        {x:0,y:450,w:800,h:100},&lt;br&gt;
        {x:250,y:0,w:100,h:800},&lt;br&gt;
        {x:500,y:0,w:100,h:800}&lt;br&gt;
    ];&lt;br&gt;
    // Buildings&lt;br&gt;
    let bData = [&lt;br&gt;
        {x:20,y:20,w:200,h:200,c:'#4a6fa5',n:'Apartments'},&lt;br&gt;
        {x:300,y:20,w:150,h:200,c:'#8b4513',n:'Warehouse'},&lt;br&gt;
        {x:580,y:20,w:200,h:200,c:'#d68029',n:'Mall'},&lt;br&gt;
        {x:20,y:320,w:200,h:100,c:'#555',n:'Bank'},&lt;br&gt;
        {x:580,y:320,w:200,h:100,c:'#2e8b57',n:'Hospital'},&lt;br&gt;
        {x:20,y:520,w:200,h:60,c:'#777',n:'Garage'},&lt;br&gt;
        {x:580,y:520,w:200,h:60,c:'#b8860b',n:'Casino'}&lt;br&gt;
    ];&lt;br&gt;
    bData.forEach(b=&amp;gt;buildings.push({...b}));&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 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();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;function spawnPickup() {&lt;br&gt;
    pickups.push({&lt;br&gt;
        x: 80 + Math.random()*640,&lt;br&gt;
        y: 80 + Math.random()*440,&lt;br&gt;
        w:20,h:20,&lt;br&gt;
        value: Math.random()&amp;gt;0.8 ? 100 : 25&lt;br&gt;
    });&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function newMission() {&lt;br&gt;
    let missions = [&lt;br&gt;
        {text:'Drive to Hospital', target:'Hospital', reward:150},&lt;br&gt;
        {text:'Go to Bank', target:'Bank', reward:200},&lt;br&gt;
        {text:'Visit Garage', target:'Garage', reward:100},&lt;br&gt;
        {text:'Go to Mall', target:'Mall', reward:120},&lt;br&gt;
        {text:'Deliver to Apartments', target:'Apartments', reward:180}&lt;br&gt;
    ];&lt;br&gt;
    mission = missions[Math.floor(Math.random()*missions.length)];&lt;br&gt;
    missionText = mission.text;&lt;br&gt;
    timeLeft = 45;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function updateUI() {&lt;br&gt;
    document.getElementById('money').textContent = '$' + money;&lt;br&gt;
    document.getElementById('vehicle').textContent = player.inCar ? '🚗 Driving' : '🚶 Walking';&lt;br&gt;
    document.getElementById('mission').textContent = missionText;&lt;br&gt;
    document.getElementById('time').textContent = timeLeft;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function checkBuildingCollision(rect) {&lt;br&gt;
    for(let b of buildings) {&lt;br&gt;
        if(rect.x &amp;lt; b.x+b.w &amp;amp;&amp;amp; rect.x+rect.w &amp;gt; b.x &amp;amp;&amp;amp;&lt;br&gt;
           rect.y &amp;lt; b.y+b.h &amp;amp;&amp;amp; rect.y+rect.h &amp;gt; b.y) return b;&lt;br&gt;
    }&lt;br&gt;
    return null;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function update() {&lt;br&gt;
    gameTime++;&lt;br&gt;
    if(gameTime % 60 === 0 &amp;amp;&amp;amp; timeLeft&amp;gt;0) timeLeft--;&lt;br&gt;
    if(timeLeft&amp;lt;=0 &amp;amp;&amp;amp; mission) { missionText='Failed!'; mission=null; }&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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 &amp;amp;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=&amp;amp;gt;{
    if(player.x &amp;amp;lt; p.x+p.w &amp;amp;amp;&amp;amp;amp; player.x+player.w &amp;amp;gt; p.x &amp;amp;amp;&amp;amp;amp;
       player.y &amp;amp;lt; p.y+p.h &amp;amp;amp;&amp;amp;amp; player.y+player.h &amp;amp;gt; p.y) {
        money += p.value;
        return false;
    }
    return true;
});
if(gameTime % 180 === 0) spawnPickup();

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

updateUI();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;function draw() {&lt;br&gt;
    // Ground&lt;br&gt;
    ctx.fillStyle='#3d6b34';&lt;br&gt;
    ctx.fillRect(0,0,canvas.width,canvas.height);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Roads
roads.forEach(r=&amp;amp;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&amp;amp;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=&amp;amp;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&amp;amp;lt;Math.floor(b.w/40);i++) {
        for(let j=0;j&amp;amp;lt;Math.floor(b.h/35);j++) {
            if(Math.random()&amp;amp;gt;0.3) ctx.fillRect(b.x+10+i*40, b.y+25+j*35,12,15);
        }
    }
});

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

// Cars
cars.forEach(c=&amp;amp;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=&amp;amp;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();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;function loop() { update(); draw(); requestAnimationFrame(loop); }&lt;br&gt;
initWorld();&lt;br&gt;
loop();&lt;/p&gt;



</description>
      <category>frontend</category>
      <category>gamedev</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
