//Steph Chun
//15-104 section #A
//heeseoc@andrew.cmu.edu
//Project-10
var buildings = [];
var terrainSpeed = 0.0005;
var terrainDetail = 0.008;
var c1, c2;
var lc1, lc2, lc3, lc4;
function setup() {
createCanvas(480, 480);
//background gradient color
c1 = color(60,1,29);
c2 = color(205,100,70);
//gradient color for reflected streetlight
lc1 = color(255,230,109,30);
lc2 = color(255,230,109,0);
//gradient color for reflected buildings
lc3 = color(random(180,200), random(100,150), random(100,150), 50);
lc4 = color(random(180,200), random(100,150), random(100,150), 0);
for (var i = 0; i < 10; i++){
var rx = random(width);
buildings[i] = makeBuilding(rx);
}
frameRate(20);
}
function draw() {
setGradient(0, 0, width, height/2+50, c1, c2, 1);
updateBuildings();
removeBuildings();
addBuildings();
makeBushes();
riverDisplay();
}
//gradient for the background(sky)
function setGradient(x, y, w, h, c1, c2, axis) {
noFill();
for (var i = y; i <= y+h; i++) {
var inter = map(i, y, y+h, 0, 1);
var c = lerpColor(c1, c2, inter);
stroke(c);
line(x, i, x+w, i);
}
}
//
function updateBuildings(){
for (var i = 0; i < buildings.length; i++){
buildings[i].move();
buildings[i].display();
}
}
//remove buildings when they're out of frame
function removeBuildings(){
var buildingsToKeep = [];
for (var i = 0; i < buildings.length; i++){
if (buildings[i].x + buildings[i].breadth > 0) {
buildingsToKeep.push(buildings[i]);
}
}
buildings = buildingsToKeep;
}
//introduce new buildings
function addBuildings() {
var newBuilding = 0.008;
if (random(0,1) < newBuilding) {
buildings.push(makeBuilding(width));
}
}
//move the buildings
function buildingMove() {
this.x += this.speed;
}
//draw multiple buildings
function buildingDisplay() {
var floorHeight = 20;
var bHeight = this.nFloors * floorHeight;
push();
noStroke();
fill(this.bColor);
translate(this.x, height - 190);
rect(0, -bHeight, this.breadth, bHeight);
stroke(200);
for (var y = 0; y < this.nFloors; y++) {
for (var x = 0; x < 6; x++){
noStroke();
fill(random(165,255), random(180,255), random(200,220));
rect(x*10+8, -10-(y*floorHeight), 4, 7);
}
}
pop();
}
//determine the shape and movement of the building
function makeBuilding(birthLocationX) {
var bldg = {x: birthLocationX,
breadth: 70,
speed: -1.2,
bColor: color(random(180,200), random(100,150), random(100,150)),
nFloors: round(random(3,10)),
move: buildingMove,
display: buildingDisplay}
return bldg;
}
//make bushes
function makeBushes(){
noStroke();
//the farthest bush
beginShape();
for (var x = 0; x < width; x++) {
fill(93,15,11);
var t = (terrainDetail * x) + (millis() * terrainSpeed);
var y = map(noise(t*2), -.5, 1, 370, height/2-30);
curveVertex(x, y);
}
curveVertex(width, height);
curveVertex(0,width);
endShape(CLOSE);
//second to the front
beginShape();
for (var x = 0; x < width; x++) {
fill(61,0,4);
var t2 = (terrainDetail * x) + (millis() * terrainSpeed);
var y2 = map(noise(t2*2), -.5, 1, 390, height/2-30);
curveVertex(x, y2);
}
curveVertex(width, height);
curveVertex(0,width);
endShape(CLOSE);
//closest(darkest) bush
beginShape();
for (var x = 0; x < width; x++) {
fill(31,7,6);
var t3 = (terrainDetail * x) + (millis() * terrainSpeed);
var y3 = map(noise(t3*2), -.7, 1.1, 420, height/2-10);
curveVertex(x, y3);
}
curveVertex(width, height);
curveVertex(0,width);
endShape(CLOSE);
}
function riverDisplay(){
//river and road
fill(31,4,9);
rect(0, height/2+50, width, height/2+50);
fill(120,6,41);
rect(0, height/2+50, width, 5);
fill(161,12,44);
rect(0, height/2+53, width, 2);
for (var s = 0; s < width; s++) {
//streetlight
strokeWeight(1.3);
stroke(255,216,205);
line(s*80-7, height/2+30, s*80+7, height/2+30);
stroke(217,136,109);
line(s*80, height/2+50, s*80, height/2+30);
noStroke();
fill(255,246,109,60);
quad(s*80-7, height/2+30, s*80+7, height/2+30, s*80+15, height/2+50, s*80-15, height/2+50);
//gradient for the reflected streetlights
setlGradient(s*80-8, height/2+55, 16, height/2-55, lc1, lc2, 1);
setl2Gradient(s*80-15, height/2+55, 30, height/2-55, lc1, lc2, 1);
//gradient for the reflected buildings
setl3Gradient(s*30+(random(10,70)), height/2+55, 10, height/2-55, lc3, lc4, 2);
}
//road detail
fill(31,4,9,80);
rect(0, height/2+53, width, 10);
}
//gradient for the reflected streetlights
function setlGradient(x, y, w, h, lc1, lc2, axis) {
noFill();
for (var i = y; i <= y+h; i++) {
var inter = map(i, y, y+h, 0, 1);
var lc = lerpColor(lc1, lc2, inter);
stroke(lc);
line(x, i, x+w, i);
}
}
function setl2Gradient(x, y, w, h, lc1, lc2, axis) {
noFill();
for (var i = y; i <= y+h; i++) {
var inter = map(i, y, y+h, 0, 1);
var lc = lerpColor(lc1, lc2, inter);
stroke(lc);
line(x, i, x+w, i);
}
}
//gradient for the reflected buildings
function setl3Gradient(x, y, w, h, lc3, lc4, axis) {
noFill();
for (var i = y; i <= y+h; i++) {
var inter = map(i, y, y+h, 0, 1);
var lc = lerpColor(lc3, lc4, inter);
stroke(lc);
line(x, i, x+w, i);
}
}
I created a cityscape at night, with the lights reflected on the river. I immediately came up with the image when I first read the instructions, and then noticed that the sample code would be super helpful for me to get started on this. I modified the code so that the shapes are visually more pleasing, and played around a lot with gradients to achieve the reflected city on the surface of the water. I wanted to have multiple layers of buildings, but for some reason, my code got broken whenever I tried adding more. So I just settled with varying the colors of the building to be more random.