Examples / p5.js Examples / / drawCity

drawCity

example p5.js javascript creating-functions random

This sketch builds off of the drawTown example:



Click here to run this code in the p5 editor!

function setup() {
  createCanvas(600, 600);
  noLoop();
}

function draw() {
  background(0, 255, 100);
  drawCity(0, 0, width, height);
}

function drawCity(cityX, cityY, cityWidth, cityHeight) {
  drawTown(cityX, cityY, cityWidth * .5, cityHeight * .5);
  drawTown(cityX + cityWidth * .5, cityY,
           cityWidth * .5, cityHeight * .5);
  drawTown(cityX, cityY + cityHeight * .5,
           cityWidth * .5, cityHeight * .5);
  drawTown(cityX + cityWidth * .5, cityY + cityHeight * .5,
           cityWidth * .5, cityHeight * .5);
}

function drawTown(townX, townY, townWidth, townHeight) {
  drawBlock(townX, townY,
            townWidth * .45, townHeight * .45);
  drawBlock(townX + townWidth * .55, townY,
            townWidth * .45, townHeight * .45);
  drawBlock(townX, townY + townHeight * .55,
            townWidth * .45, townHeight * .45);
  drawBlock(townX + townWidth * .55, townY + townHeight * .55,
            townWidth * .45, townHeight * .45);
  
  // roads
  noStroke();
  fill(32);
  rect(townX + townWidth * .45, townY, townWidth * .1, townHeight);
  rect(townX, townY + townHeight * .45, townWidth, townHeight * .1);
  stroke(255, 255, 0);
  line(townX + townWidth * .5, townY,
       townX + townWidth * .5, townY + townHeight)
  line(townX, townY + townHeight * .5,
       townX + townWidth, townY + townHeight * .5); 
}

function drawBlock(blockX, blockY, blockWidth, blockHeight) {
  // yard
  fill(0, random(200, 255), 0);
  noStroke();
  rect(blockX, blockY, blockWidth, blockHeight);
  
  const r = random(1);
  if(r < .25){
    drawPlot(blockX + blockWidth * .1, blockY + blockHeight * .1,
              blockWidth * .3, blockHeight * .7);
    drawPlot(blockX + blockWidth * .6, blockY + blockHeight * .1,
             blockWidth * .3, blockHeight * .7);
  } else if(r < .5){
    drawPlot(blockX + blockWidth * .1, blockY + blockHeight * .1,
              blockWidth * .7, blockHeight * .3);
    drawPlot(blockX + blockWidth * .1, blockY + blockHeight * .6,
             blockWidth * .7, blockHeight * .3);
  } else {
    drawPlot(blockX + blockWidth * .1, blockY + blockHeight * .1,
             blockWidth * .3, blockHeight * .3);
    drawPlot(blockX + blockWidth * .6, blockY + blockHeight * .1,
             blockWidth * .3, blockHeight * .3);
    drawPlot(blockX + blockWidth * .1, blockY + blockHeight * .6,
             blockWidth * .3, blockHeight * .3);
    drawPlot(blockX + blockWidth * .6, blockY + blockHeight * .6,
             blockWidth * .3, blockHeight * .3);
  }
}

function drawPlot(plotX, plotY, plotWidth, plotHeight) {
  const r = random(1);
  if (r < .3) {
    drawHouse(plotX, plotY, plotWidth, plotHeight);
  } else if(r < .6) {
    drawOffice(plotX, plotY, plotWidth, plotHeight);
  } else {
    drawFactory(plotX, plotY, plotWidth, plotHeight);
  }
}

function drawHouse(houseX, houseY, houseWidth, houseHeight) {
  stroke(0);
  
  const frontY = houseY + houseHeight * .4;
  const frontHeight = houseHeight * .6;
  
  // front
  fill(random(255), random(255), random(255));
  rect(houseX, frontY, houseWidth, frontHeight);
  
  // roof
  fill(random(255), random(255), random(255));
  triangle(houseX, frontY,
           houseX + houseWidth * .5, houseY,
           houseX + houseWidth, frontY);
  
  const windowWidth = houseWidth * .25;
  const windowHeight = frontHeight * .25;
  const windowY = frontY + frontHeight * .15;
  
  const leftWindowX = houseX + houseWidth * .1;
  const rightWindowX = (houseX + houseWidth) - 
                       (houseWidth * .1) - windowWidth;
  
  // windows 
  fill(random(255), random(255), random(255));
  rect(leftWindowX, windowY, windowWidth, windowHeight);
  line(leftWindowX, windowY + windowHeight * .5,
       leftWindowX + windowWidth, windowY + windowHeight * .5);
  line(leftWindowX + windowWidth * .5, windowY,
       leftWindowX + windowWidth * .5, windowY + windowHeight);
  rect(rightWindowX, windowY, windowWidth, windowHeight);
  line(rightWindowX, windowY + windowHeight * .5,
       rightWindowX + windowWidth, windowY + windowHeight * .5);
  line(rightWindowX + windowWidth * .5, windowY,
       rightWindowX + windowWidth * .5, windowY + windowHeight);
  
  const doorWidth = houseWidth * .25;
  const doorHeight = frontHeight * .4;
  const doorX = houseX + houseWidth * .5 - doorWidth * .5;
  const doorY = houseY + houseHeight - doorHeight;
  
  // door
  fill(random(255), random(255), random(255));
  rect(doorX, doorY, doorWidth, doorHeight);
  
  const doorknobX = doorX + doorWidth * .2;
  const doorknobY = doorY + doorHeight * .5;
  const doorknobSize = houseWidth * .05;
  
  // doorknob
  fill(0);
  circle(doorknobX, doorknobY, doorknobSize);
}

function drawOffice(officeX, officeY, officeWidth, officeHeight) {
  stroke(0);
  fill(random(255), random(255), random(255));
  rect(officeX, officeY, officeWidth, officeHeight);
  
  // windows
  fill(random(255), random(255), random(255));
  rect(officeX + officeWidth * .1, officeY + officeHeight * .1,
       officeWidth * .2, officeHeight * .2);
  rect(officeX + officeWidth * .4, officeY + officeHeight * .1,
       officeWidth * .2, officeHeight * .2);
  rect(officeX + officeWidth * .7, officeY + officeHeight * .1,
       officeWidth * .2, officeHeight * .2);
  rect(officeX + officeWidth * .1, officeY + officeHeight * .4,
       officeWidth * .2, officeHeight * .2);
  rect(officeX + officeWidth * .4, officeY + officeHeight * .4,
       officeWidth * .2, officeHeight * .2);
  rect(officeX + officeWidth * .7, officeY + officeHeight * .4,
       officeWidth * .2, officeHeight * .2);
  
  // door
  fill(random(255), random(255), random(255));
  rect(officeX + officeWidth * .4, officeY + officeHeight * .8,
      officeWidth * .2, officeHeight * .2);
}

function drawFactory(factoryX, factoryY, factoryWidth, factoryHeight) {
  stroke(0);
  fill(random(255), random(255), random(255));
  
  // front
  rect(factoryX, factoryY + factoryHeight * .5,
       factoryWidth, factoryHeight * .5);
  
  // stacks
  rect(factoryX + factoryWidth * .2, factoryY + factoryHeight * .1,
       factoryWidth * .1, factoryHeight * .4);
  rect(factoryX + factoryWidth * .7, factoryY + factoryHeight * .1,
       factoryWidth * .1, factoryHeight * .4);
  
  // windows
  fill(random(255), random(255), random(255));
  rect(factoryX + factoryWidth * .2, factoryY + factoryHeight * .6,
       factoryWidth * .1, factoryHeight * .1);
  rect(factoryX + factoryWidth * .7, factoryY + factoryHeight * .6,
       factoryWidth * .1, factoryHeight * .1);
  
  // door
  rect(factoryX + factoryWidth * .4, factoryY + factoryHeight * .8,
       factoryWidth * .2, factoryHeight * .2);
}

This sketch defines a drawCity() function that calls the drawTown() function four times. The drawTown() function calls the drawBlock() function four times. The drawBlock() function chooses a random layout (either two buildings next to each other, two buildings on top of each other, or four buildings), and then calls the drawPlot() function based on the layout. The drawPlot() function randomly calls the drawHouse(), drawOffice(), or drawFactory() functions.

city city

Remix Ideas

  • Add other types of plots and buildings: try parks, monuments, and skyscrapers.
  • Randomize the layout of each town, so that the roads are different each time.
  • Make the city look more like where you live.

Comments and Questions

Happy Coding is a community of folks just like you learning about coding.
Do you have a comment or question? Post it here!