//Lanna Lang
//Section D
//lannal@andrew.cmu.edu
//Project 11 - Landscape
//variables for the gradients;
var yAxis = 1;
var c1, c2, c3, c4, c5; //background colors
//variables to draw the clouds
var cloudX = [500, 700, 1200];
var cloudY = [150, 120, 190];
var cloudDist = 5; //the distance the cloud moves
//arrays for the tree and house objects
var trees = [];
var houses = [];
function setup() {
createCanvas(480, 480);
frameRate(20);
c1 = color('#9a99d3'); //background sky lavender
c2 = color('#ff829f'); //background sky pink
c3 = color('#f6944d'); //background sky orange
c4 = color('#a29078'); //train color 1
c5 = color('#f2f2f4'); //train color 2
//create an initial collection of trees
for (var i = 0; i < 10; i++) {
var rtx = random(width);
var rty = random(281, 330);
trees[i] = makeTree(rtx, rty);
}
//create an initial collection of houses
for (var i = 0; i < 10; i++) {
var rhx = random(width);
var rhy = random(300, 350);
houses[i] = makeHouse(rhx, rhy);
}
}
function draw() {
drawBackground();
drawClouds();
drawLandscape();
UandDTrees();
removeTrees();
addNewTrees();
UandDHouses();
removeHouses();
addNewHouses();
drawTrain();
}
//function to draw the background and
//the canvas for the train
function drawBackground() {
//rectangle around full canvas
drawGradDGtoG(0, 0, width, height, c4, c5, yAxis);
//draw the sky with gradients
drawGradPtoP(35, 100, 400, 80, c1, c2, yAxis);
drawGradPtoO(35, 181, 400, 105, c2, c3, yAxis);
}
//draw the landscape inside the train windows
function drawLandscape() {
var mtnSpeed = 0.0005;
var mtnDetail = 0.01;
//draw the moutains
stroke('#445c3c');
for (var x = 35; x <= 435; x++) {
var t = (x * mtnDetail) + (millis() * mtnSpeed);
var y = map(noise(t), 0, 1, 170, 300);
line(x, y, x, 380);
}
//draw the grass/horizon
noStroke();
fill('#798f44');
rect(35, 281, 400, 107);
}
//draw the clouds
function drawClouds() {
for (var i = 0; i < cloudX.length; i++) {
cloudX[i] -= cloudDist; //the clouds move 5 pixels to the left
//draw the 3 clouds
noStroke();
fill('#faa3b1');
ellipse(cloudX[i], cloudY[i] + 10, 100, 8);
ellipse(cloudX[i] - 24, cloudY[i] + 1, 30, 20);
ellipse(cloudX[i] + 3, cloudY[i], 40, 22);
ellipse(cloudX[i] - 5, cloudY[i] - 10, 40, 20);
ellipse(cloudX[i] + 22, cloudY[i], 30, 18);
//when the clouds reach the end of the canvas,
//they will reset back at the other side of the canvas
//at a random x postion between 500 and 1300
if (cloudX[i] < 0) {
cloudX[i] = random(500, 1300);
}
}
}
//function to draw gradient from purple to pink
function drawGradPtoP(x, y, w, h, c1, c2, axis) {
noFill();
if (axis == yAxis) {
for (var i = y; i <= y + h; i++) {
var inter = map(i, y, y + h, 0, 1);
var cPtoP = lerpColor(c1, c2, inter);
stroke(cPtoP);
line(x, i, x + w, i);
}
}
}
//function to draw gradient from pink to orange
function drawGradPtoO (x, y, w, h, c2, c3, axis) {
noFill();
if (axis == yAxis) {
for(var i = y; i <= y + h; i++) {
var inter = map(i, y, y + h, 0 , 1);
var cPtoO = lerpColor(c2, c3, inter);
stroke(cPtoO);
line(x, i, x + w, i);
}
}
}
//function to draw gradient from tan to light grey
function drawGradDGtoG (x, y, w, h, c4, c5, axis) {
noFill();
if (axis == yAxis) {
for(var i = y; i <= y + h; i++) {
var inter = map(i, y, y + h, 0 , 1);
var cDGtoG = lerpColor(c4, c5, inter);
stroke(cDGtoG);
line(x, i, x + w, i);
}
}
}
//function to draw the train
function drawTrain() {
//redraw the very left and right sides of the train
//because of the clouds moving
drawGradDGtoG(0, 0, 35, height, c4, c5, yAxis);
drawGradDGtoG(435, 0, 490, height, c4, c5, yAxis);
//rectangle to separate the sky gradient into two windows
drawGradDGtoG(210, 0, 60, height, c4, c5, yAxis);
//dark brown line in the middle
noStroke();
fill('#2e2423');
rect(235, 0, 10, height);
//black rect sign under windows
fill(0);
rect(280, 400, 140, 20);
rect(50, 400, 140, 20);
//dark brown window frames
strokeWeight(2);
stroke('#2e2423');
noFill();
rect(30, 85, 185, 310);
rect(265, 85, 175, 310);
//sign under windowa that says "Do not lean on train door"
fill(224);
textSize(11);
textStyle(BOLD);
text("Do not lean on train door", 284, 413);
text("Do not lean on train door", 54, 413);
//draw the door handles on the train doors
stroke(193);
fill(220);
rect(180, 440, 35, 70);
rect(265, 440, 35, 70);
//draw the insides of the door handles
fill(130);
rect(190, 450, 15, 70);
rect(275, 450, 15, 70);
//draw the train handles
for (var j = 0; j < width + 50; j += 150) {
stroke(200);
strokeWeight(13);
noFill();
line(j, 0, j, 70);
line(j, 70, j + 33, 130);
line(j, 70, j - 30, 130);
line(j - 30, 130, j + 33, 130);
}
}
//update the tree's positions, and display them
function UandDTrees() {
for (var i = 0; i < trees.length; i++) {
trees[i].move();
trees[i].draw();
}
}
//if a tree has dropped off the left edge,
//remove it from the array
function removeTrees() {
var treesToKeep = [];
for (var i = 0; i < trees.length; i++) {
if (trees[i].x + trees[i].tw > 0 &
trees[i].y + trees[i].th > 0) {
treesToKeep.push(trees[i]);
}
}
trees = treesToKeep; //remember the surviving trees
}
//with a very tiny probability, add a new tree to the end
function addNewTrees() {
var newTreeChance = 0.01;
if (random(0.1) < newTreeChance) {
trees.push(makeTree(width, random(281, 330)));
}
}
//update position of the tree at every frame
function moveTree() {
this.x += this.speed;
}
//draw the tree and tree trunk
function drawTree() {
noStroke();
fill('#c39a2b');
push();
translate(this.x, this.y);
triangle(0, -this.th, 0 - this.tw / 2, 0,
0 + this.tw / 2, 0);
pop();
fill('#512a17');
push();
translate(this.x, this.y);
rect(-3, 0, 4, 5);
pop();
}
//this function accepts parameters and uses the values
//of those parameters to initialize fields in the tree object
function makeTree(birthLocationX, birthLocationY) {
var mktr = {x: birthLocationX,
y: birthLocationY,
tw: random(5, 15),
speed: -5.0,
th: random(15, 30),
move: moveTree,
draw: drawTree}
return mktr;
}
//update the house's positions, and display them
function UandDHouses() {
for (var i = 0; i < houses.length; i++) {
houses[i].move();
houses[i].draw();
}
}
//if a house has dropped off the left edge,
//remove it from the array
function removeHouses() {
var housesToKeep = [];
for (var i = 0; i < houses.length; i++) {
if (houses[i].x2 + houses[i].hw > 0 &
houses[i].y2 + houses[i].hh > 0) {
housesToKeep.push(houses[i]);
}
}
houses = housesToKeep; //remember the surviving houses
}
//with a very tiny probability, add a new house to the end
function addNewHouses() {
var newHouseChance = 0.003;
if (random(0.1) < newHouseChance) {
houses.push(makeHouse(width, random(300, 350)));
}
}
//update position of the tree at every frame
function moveHouse() {
this.x2 += this.speed2;
}
//draw the house and the house roof
function drawHouse() {
noStroke();
fill('#e7d2a0');
push();
translate(this.x2, this.y2);
rect(-10, 0, 20, 10);
pop();
fill('#95221b');
push();
translate(this.x2, this.y2);
triangle(0, -this.hh / 2, 0 - this.hw / 2, 0,
0 + this.hw / 2, 0);
pop();
}
//this function accepts parameters and uses the values
//of those parameters to initialize fields in the house object
function makeHouse(birthLocationX2, birthLocationY2) {
var mkh = {x2: birthLocationX2,
y2: birthLocationY2,
hw: random(10, 40),
speed2: -5.0,
hh: random(10, 30),
move: moveHouse,
draw: drawHouse}
return mkh;
}
When I first read this prompt, what came up to my mind immediately was creating a landscape that mimics what I see when sitting on a high-speed train. My favorite sceneries are usually what I see when I pass by complete cities in just a few hours on those trains. I had a lot of fun creating this landscape, but it was also very challenging for me. It definitely took me more than a couple of hours, but it was worth it.