Timothy Liu — Project 11 — Landscape

tcliu-project-11

// Timothy Liu
// 15-104, Section C
// tcliu@andrew.cmu.edu
// OpenProject-11

var cowArray = []; // array for all cows
var birdArray = []; // array for all birds

// variables to control the shape and speed of the rows of trees
var backTreesStructure = 0.04;
var backTreesSpeed = 0.0009;
var frontTreesStructure = 0.04;
var frontTreesSpeed = 0.0009;

// hill in the front
var rollingPlain = 0.005;
var rollingPlainSpeed = 0.0001;

function setup() {

    createCanvas(600, 240); 

    // start with 3 cows on the screen
    for (var i = 0; i < 3; i++){
        var cowPlacement = random(0, width);
        cowArray[i] = cowObj(cowPlacement); // places the 3 cows in random locations

    }

    // draws in birds; start with 5 on the screen
    for (var j = 0; j < 5; j++) {
        birdArray.push(birdObj(j * 30 + random(40, width - 40),
                        random(20, 60), random(10, 25))); // gives the birds random x, y, and size
    }

    frameRate(40);

}

function draw() {

    background(124, 196, 230); // sky color

    drawTrees(); // draw the two rows of trees first (in the background)

    updateAndShowCows(); // draw and have the cows move

    updateCowsOffScreen(); // account for when cows move off screen

    updateAndShowBirds(); // draw and have the birds move

    updateBirdsOffScreen(); // account for when birds move off screen

    newCows(); // draws in new cows (from edge of screen)

    newBirds(); // draws in new birds (from edge of screen)
}

function drawTrees() {

    // the back (darker) row of trees
    beginShape();
    fill(40, 120, 61);
    noStroke();
    vertex(0, height);

    // use noise function to draw random tree line
    for (var x = 0; x < width; x++) {
        var t = (x * backTreesStructure) + (millis() * backTreesSpeed);
        var y = map(noise(t), 0, 1, 40, 150);
        vertex(x, y); 
    }
    vertex(width, height);
    endShape();

    // the front (lighter) row of trees
    beginShape(); 
    fill(50, 168, 82);
    noStroke();
    vertex(0, height);

    //use noise function to draw random, lower tree line to create depth
    for (var x = 0; x < width; x++) {
        var t = (x * frontTreesStructure) + (millis() * frontTreesSpeed);
        var y = map(noise(t * 0.7), 0, 1, 80, 200);
        vertex(x, y); 
    }
    vertex(width, height);
    endShape();

    // the light-green hills in front
    beginShape(); 
    fill(154, 196, 118);
    noStroke();
    vertex(0, height);

    // use a dampened version of the noise function to make slowly rolling hills
    for (var x = 0; x < width; x++) {
        var t = (x * rollingPlain) + (millis() * rollingPlainSpeed);
        var y = map(noise(t * 0.5), 0, 1, 170, 200);
        vertex(x, y); 
    }
    vertex(width, height);
    endShape();

}

// puts the cows on the canvas and makes them move
function updateAndShowCows(){

    for (var i = 0; i < cowArray.length; i++){

        cowArray[i].move(); // move property of the cow obj
        cowArray[i].show(); // show property of the bird obj

    }
}

// puts the birds on the canvas and makes them move
function updateAndShowBirds(){

    for (var i = 0; i < birdArray.length; i++){

        birdArray[i].moveB(); // move property of the bird obj
        birdArray[i].showB(); // show property of the bird obj

    }
}

// eliminates the cows that move off screen
function updateCowsOffScreen(){

    var cowsToKeep = []; // to determine which cows are still on screen

    for (var i = 0; i < cowArray.length; i++) {
        if (cowArray[i].x + cowArray[i].cowWidth > 0) { // if the cow is still on the screen
            cowsToKeep.push(cowArray[i]); // put it into the new array
        }
    }

    // cowsToKeep[] becomes the new array of cows currently on screen
    cowArray = cowsToKeep;
}

// eliminates the birds that move off screen
function updateBirdsOffScreen(){

    var birdsToKeep = []; // to determine which birds are still on screen

    for (var i = 0; i < birdArray.length; i++) {
        if (birdArray[i].bx + birdArray[i].sizeOfBird > 0) { // if the bird is still on the screen
            birdsToKeep.push(birdArray[i]); // put it into the new array
        }
    }

    // birdsToKeep[] becomes the new array of birds currently on screen
    birdArray = birdsToKeep;
}

// occasionally, add a new cow to the end of the screen
function newCows() {
    var newCowOdds = 0.008; 
    if (random(0, 1) < newCowOdds) {
        cowArray.push(cowObj(width)); // add a new cow to the array
    }
}

// occasionally, add a new bird to the end of the screen
function newBirds() {
    var newBirdOdds = 0.008;
    if (random(0, 1) < newBirdOdds) {
        birdArray.push(birdObj(width, random(20, 50), random(10, 25))); // add a new bird to the array
    }
}

// makes the cows move
function movingCows() {
    this.x += this.speed;
}

// makes the birds move
function movingBirds() {
    this.bx += this.speedBird;
}

// this is what actually draws in, and displays, the cows using various cow object properties
function showCows() {

    var cowPlacement = this.randomLoc;
    var earOffset = 7;
    var headOffset = 15;
    var eyeOffset = 10;
    var spot2Offset = 5;
    var spot3Offset = 4;
    var snoutOffset = 6;

    push();

    translate(this.x, height); // places the cows onto the canvas

    // shadow
    noStroke();
    fill(7, 66, 25);
    ellipse(0, -cowPlacement + 10, this.cowWidth, this.cowHeight / 4);

    // cow body
    fill(this.randomColor);
    arc(0, -cowPlacement, this.cowWidth, this.cowHeight * 0.75, 2 * PI / 3, PI / 3, CHORD);
    
    // cow ears
    arc(-headOffset - earOffset, -cowPlacement - headOffset, this.earW, this.earW * 0.75, 4 * PI / 3, PI / 3, CHORD);
    arc(-headOffset + earOffset, -cowPlacement - headOffset, this.earW, this.earW * 0.75, 2 * PI / 3, 5 * PI / 3, CHORD);
    
    // cow head
    ellipse(-headOffset, -(cowPlacement + eyeOffset), this.cowHead * 1.25, this.cowHead);

    // three spots
    fill(0);
    ellipse(this.spot1, -cowPlacement, this.spotW, this.spotH);
    ellipse(this.spot2, -cowPlacement + spot2Offset, this.spotW * 1.2, this.spotH);
    ellipse(this.spot3, -cowPlacement - spot3Offset, this.spotW, this.spotH * 1.2);

    // eyes
    ellipse(-18, -cowPlacement - eyeOffset, this.eye, this.eye * 1.2);
    ellipse(-12, -cowPlacement - eyeOffset, this.eye, this.eye * 1.2);

    // snout
    fill("#eba4dd");
    ellipse(-15, -(cowPlacement + snoutOffset), this.snout * 1.6, this.snout);
    
    pop();

}

// this is what actually draws in, and displays, the birds using various bird object properties
function showBirds() {

    var birdBod = 5; // body size of bird

    noFill();
    stroke(0);
    strokeWeight(2);

    push();

    // places and sizes the birds
    translate(this.bx, this.by);
    scale(this.sizeOfBird / 60);
    ellipseMode(CENTER);

    // uses arcs and ellipses to draw the wings and body
    arc(35, 35, 100, 100, 5 * PI / 4, 3 * PI / 2);
    arc(-35, 35, 100, 100, 3 * PI / 2, 7 * PI / 4);
    fill(0);
    ellipse(0, 0, birdBod, birdBod); 

    pop();

}

// here are all the properties of the cow object
function cowObj(x) {

    let colors = ["#8f6846", "#ffffff", "#918880"] // different colors of cows

    // cow obj properties
    var cow = {x: x,
                cowWidth: random(30, 40), // each cow has a diff size and shape
                cowHeight: random(25, 40),
                cowHead: random(10, 16),
                snout: 7,
                spot1: random(-12, -8),
                spot2: random(1, 5),
                spot3: random(5, 10),
                eye: 3,
                earW: 8,
                spotW: 8,
                spotH: 6,
                speed: random(-3, -1), // each cow moves at a diff speed
                move: movingCows,
                show: showCows,
                randomLoc: random(35, 60),
                randomColor: random(colors), // each cow has a different color
            }

    return cow;

}

// here are all the properties of the bird object
function birdObj(x, y, size) {

    // bird obj properties
    var bird = {bx: x, 
                by: y, 
                sizeOfBird: size, // each bird has a random size
                speedBird: random(-4, -1), // each bird has a random speed
                showB: showBirds,
                moveB: movingBirds
            };

    return bird;

}

When I thought about the “generative landscape” prompt for this week’s assignment, one of the first things that came to mind was the scenery during the long road trips my family takes every year from the Bay Area to Southern California. I distinctly remember staring out the window as a kid, watching cows idly graze in fields and the rolling trees and hills zoom by as we drove down I-5. Thus, I wanted to model my project after this landscape because it’s a very fond childhood memory of mine.

An example of a landscape similar to what I was trying to capture in my project.

In my generative landscape, I have cows of all sorts of shapes, colors, and sizes on grassy plains as the screen pans leftward. In the background, rows of trees and grassy hills roll by, and birds fly overhead at varying speeds. My piece is meant to represent an idyllic view of what a kid sees when they stare out the window on a road trip through California’s central valley. The blue sky, the flocking birds, and the vast greenery all convey warmth and happiness. Ultimately, I think it’s the motion and dynamism of my piece that really help capture the feeling of blissfulness.

Leave a Reply