Collect water!

This is my final project about collecting raindrops. Your health starts to lose from dehydration and the one way to survive is through collecting raindrops!. Watch out for those black ones, as they deplete your health if you touch them!

Get water final

//Yunfeng Jiang
//Section E

//setting up variables
var myCanvas;
var waterN = 10;
var water = [];
var p;
var plat;
var waterSlopeProj = []

var acc = 0.5;
var size = 40;
var score = 0;
var health = 100;

function setup() {
    myCanvas = createCanvas(500, 300);
    //push water object to water array
    for(var i = 0; i < waterN; i++){
        var w = createWater(random(20, width-20), random(-200, -10), 2);
        water.push(w);
    }

    //add platform object
    if(random()<0.5){
        plat = createPlatform(-125, random(25, 50), random(200, 250), 0);
    }
    else{
        plat = createPlatform(width+125, random(25, 50), random(200, 250), 1);
    }
    

    //push waterslopeProj to array
    for(var i = 0; i < waterN; i++){
        var k = plat.h / plat.w; //slope
        if(plat.sdir > 0.5){
        var wsp = 100-tan(k)*(-water[i].x+plat.x+0.5*plat.w)
        }
        else{
        var wsp = 100-tan(k)*(-water[i].x+plat.x-0.5*plat.w)    
        } //expression of the slope
        
        waterSlopeProj.push(wsp);
    } 
    
    //add player object
    p = player();  
}

function draw() {
    //draw scene
    background(176, 192, 200);
    myCanvas.parent('canvasPlaceholder');
    scene();
    strokeWeight(1)
    
    
    

    //add rain
    updateWater();
    addWater();
    

    //update player
    p.display(size); 
    p.moveY();
    playerMove();

    //add platform
    updatePlatform();
    addPlatform();

    //gameplay properties
    updateHealth();
    updateProj();
    checkHitRain();
    checkHitPlat();
        
}
    

//draw scene
function scene(){
    rectMode(CORNER)
    strokeWeight(0);
    fill(128, 96, 67);
    rect(0, 250, width, 50)
    text('score = '+ score, 10, 20);
    text('health = '+ health, 10, 50)
}

//jump
function keyPressed(){
    if (keyCode === 32 & p.y == 230){
                p.dy = -10
                }
            } 

//move player left and right
function playerMove(){
    if (keyIsPressed === true){
        
            if (keyIsDown(65) || keyIsDown(LEFT_ARROW)){
                if(p.x > size/2){
                    p.moveX(-5);
                }
                
            }
            if (keyIsDown(68) || keyIsDown(RIGHT_ARROW)){
                if(p.x < width-size/2){
                    p.moveX(5);
                }
            }    
        }
}

//update health
function updateHealth(){
    
    //deplete health
    if (frameCount%30 == 0){
        health = health - 1
    }
    
    //game over
    if (health < 0){
        textAlign(CENTER, CENTER)
        fill(255, 0, 0);
        textSize(50);
        text("GAME OVER", width/2, height/2)
        noLoop()
    }
}

//check player location to raindrops
function checkHitRain(){
    //check distance from player to rain
    for(var i = 0 ; i < waterN; i++){
        if(dist(p.x, p.y, water[i].x, water[i].y) < size*0.75){
            score += 1;
            //water that hits platform are considered bad water that depletes health
            if(water[i].bad == false){
                health += 1;
            }
            else{
                health -= 1;
            }
            var w = createWater(random(20, width-20), random(-200, -10), 2);
            water[i] = w;

        }
    }
}
 
function updateProj(){
    for(var i = 0; i < waterN; i++){
        var k = plat.h / plat.w; //slope
            if(plat.sdir == 1){
                waterSlopeProj[i] = 100-tan(k)*(-water[i].x+plat.x+0.5*plat.w) //expression of the slope
            }
            else{
                waterSlopeProj[i] = 100+tan(k)*(-water[i].x+plat.x-0.5*plat.w)  //expression of the slope
            }
        } 


}
function checkHitPlat(){
     for(var i = 0 ; i < waterN; i++){
        var k = plat.h / plat.w
        if(water[i].x > plat.x-plat.w*0.5 & water[i].x < plat.x + plat.w*0.5 && water[i].y > waterSlopeProj[i] && water[i].y < 100){
                water[i].bad = true;
                if(plat.sdir == 1){
                    water[i].x += 0.25*water[i].v/k
                    water[i].y += 0.25*water[i].v
                }
                else{
                    water[i].x -= 0.25*water[i].v/k
                    water[i].y += 0.25*water[i].v
                }
            }
        else{
            water[i].y += water[i].v
        }
            

}
}


Does AI think like a (white) man? By Anna Grubauer, 2020

Anna Grubauer writes about a series of artists and activists that have faced prejudices or noticed prejudices made from Artificial Intelligence. She writes that, as AI becomes more and more common, it is important for us to be aware of the shortcomings and even harms of this system. For example, Joy Buolamwini and Timnit Gebru investigated AI face recognition and found that the error rate for this system is significantly higher among women, and even higher among women with darker skin. This is harmful as face recognition is often used in medical fields to detect skin cancers, so if it is not accurate for a certain group of people, it puts them at risk. In addition, Mary Flanagan pointed out more discrimination in her project “[help me know the truth]”. She found that AI often has stereotypes based on race and will label “leaders” as those with more western features. The good news is that there are many up and coming feminist computer programmers working to get rid of this gap in research. One of these names is Caroline Siders, who has a website called Feminist Data Set which is a multi year art project that combines resources for a collection of feminist data. 

https://ars.electronica.art/aeblog/en/2020/04/10/women-in-media-arts-ai/

Project 11: Winter Scroll

sketch

//Name: Hari Vardhan Sampath
//Section: E
//eMail address: harivars@andrew.cmu.edu
//Project-11

var snowForeground = []; // array of snow particles in the foreground
var snowBackground = []; // array of snow particles in the background
var snowAmountForeground = 500;
var snowAmountBackground = 750;
var snowSize = 3;
var snowLayers = 3;

function setup() {
    createCanvas(500, 300);

    for (i = 0; i < snowAmountForeground; i++) {
        snowForeground[i] = new Object();
        snowForeground[i].x = random(width);
        snowForeground[i].y = random(height);
        snowForeground[i].dy = random(0.25, 1);
        snowForeground[i].c = color(random(200, 255));
    }

    for (i = 0; i < snowAmountBackground; i++) {
        snowBackground[i] = new Object();
        snowBackground[i].x = random(width);
        snowBackground[i].y = random(height);
        snowBackground[i].dy = random(0.25, 1);
        snowBackground[i].c = color(random(200, 255));
    }
}

// update position and draw each of 100 rectangles
function draw() {
    // background sky gradient
    for (var i = 0; i < height; i++) {
        // 
        var c1 = color(0, 20, 52);
        var c2 = color(0, 71, 126);
        // 
        var gradient = map(i, 0, height, 0, 1);
        var c = lerpColor(c1, c2, gradient);
        stroke(c);
        line(0, i, width, i);
    }

    // snow falling in the background
    noStroke();
    for (i = 0; i < snowAmountBackground; i++) {
        drawSnowBackground(snowBackground[i]);
        updateSnowBackground(snowBackground[i]);
    }

    // layers of winter forest
    forest();

    // snow falling in the foreground
    noStroke();
    for (i = 0; i < snowAmountForeground; i++) {
        drawSnowForeground(snowForeground[i]);
        updateSnowForeground(snowForeground[i]);
    }
}

function forest() {
    foliage0 = 0.06;
    foliage1 = 0.04;
    foliage2 = 0.02;
    foliage3 = 0.01;
    foliageSpeed0 = 0.001;
    foliageSpeed1 = 0.002;
    foliageSpeed2 = 0.003;
    foliageSpeed3 = 0.004;

    stroke(163, 196, 217);
    beginShape();
    for (var i = 0; i < width; i++) {
        var t0 = (i * foliage0) + (millis() * foliageSpeed0);
        var y0 = map(noise(t0), 0, 1, 200, 5);
        line(i, y0, i, height);
    }
    endShape();

    stroke(117, 163, 191);
    beginShape();
    for (var i = 0; i < width; i++) {
        var t1 = (i * foliage1) + (millis() * foliageSpeed1);
        var y1 = map(noise(t1), 0, 1, 250, 6);
        line(i, y1, i, height);
    }
    endShape();

    stroke(70, 113, 140);
    beginShape();
    for (var i = 0; i < width; i++) {
        var t2 = (i * foliage2) + (millis() * foliageSpeed2);
        var y2 = map(noise(t2), 0, 1, 275, 7);
        line(i, y2, i, height);
    }
    endShape();

    stroke(30, 51, 64);
    beginShape();
    for (var i = 0; i < width; i++) {
        var t3 = (i * foliage3) + (millis() * foliageSpeed2);
        var y3 = map(noise(t3), 0, 1, 300, 8);
        line(i, y3, i, height);
    }
    endShape();
}

function drawSnowForeground(s) {
    fill(s.c);
    circle(s.x, s.y, 2);
}

function updateSnowForeground(s) {
        s.y += s.dy;
        if (s.y > height) {
        s.y = 0;
        }
        else if (s.y < 0) {
            s.y = height;       
        }
}

function drawSnowBackground(s) {
    fill(s.c);
    circle(s.x, s.y, random(0.5,1.5));
}

function updateSnowBackground(s) {
        s.y += s.dy;
        if (s.y > height) {
        s.y = 0;
        }
        else if (s.y < 0) {
            s.y = height;       
        }
}


Train’s window
Credits: https://www.journeyb.com/2019/10/journeybasket-short-history-indian-railways-book-photos.html

LO 11: ImageNet Roulette: An Experiment in Classification, by Kate Crawford and Trevor Paglen

Kate Crawford (left) and Trevor Paglen (right), as classified by ImageNet Roulette Courtesy of the artist

ImageNet Roulette is a classification tool created by artist Trevor Paglen and AI researcher Kate Crawford as a provocation design to help us realise the way in which humans are classified in machine learning systems. This tool regularly returns racist, misogynistic, and cruel results which is because of the dataset it derives from ImageNet’s ‘Person’ category, which is an offset of face recognition experiments.

The ImageNet dataset is largely used for object recognition such as finding out apples and oranges when an image is uploaded. One of the subsets of ImageNet is the person category which are classified and labelled in terms of race, gender, age, and character. These labels used to tech the AI were supplied by lab staff and crowdsourced workers who introduced their conscious and unconscious opinions and biases into the algorithm.

Shortly after the ImageNet Roulette went viral, the ImageNet team announced plans to remove over 600,000 images featured in its people category. On the 27th of September 2019, the ImageNet Roulette has been taken off the internet after proving its point on how things can go wrong and remains as a physical art installation at the Fondazione Prada Osservertario in Milan.

Project 11 – Generative Landscape

I combined handdrawn assets from a previous project with walking sprite from Assignment 9 to create a scene of a person walking outside. The sketchy ‘handdrawn’ aesthetic of the assets combined with the layers scrolling at different speeds to create a sense of parallax. Occasionally, another character will pass by between the layer behind the main character.

sketch
var walkImage = [];   // an array to store the images
var character;

var fgElem = [];
var mgElem = [];
var bgElem = [];
var pgElem = [];

var fg = [];
var mg = [];
var bg = [];
var pg = [];

function preload(){
    // walk cycle
    walkImage[0] = loadImage("https://imgur.com/8HlL26L");
    walkImage[1] = loadImage("https://imgur.com/VLCqhEO");
    walkImage[2] = loadImage("https://imgur.com/6rAVlb8");
    walkImage[3] = loadImage("https://imgur.com/2VRJjQ6");
    walkImage[4] = loadImage("https://imgur.com/zFCNtnG");
    walkImage[5] = loadImage("https://imgur.com/AnyR09P");
    walkImage[6] = loadImage("https://imgur.com/PMB0qDG");
    walkImage[7] = loadImage("https://imgur.com/CiQWgmP");




    //loading foreground
    fgElem[0] = loadImage("https://imgur.com/RUYNCQT");
    fgElem[1] = loadImage("https://imgur.com/UaNr8wZ");
    fgElem[2] = loadImage("https://imgur.com/LsfvMCm");
    fgElem[3] = loadImage("https://imgur.com/GRwR31R");
    fgElem[4] = loadImage("https://imgur.com/xQtPjEQ");
    fgElem[5] = loadImage("https://imgur.com/cTUW62y");
    fgElem[6] = loadImage("https://imgur.com/cY58wgx");


    //loading midground
    mgElem[0] = loadImage("https://imgur.com/lal5lq9");
    mgElem[1] = loadImage("https://imgur.com/c5fb0jp");
    mgElem[2] = loadImage("https://imgur.com/kKwofLH");
    mgElem[3] = loadImage("https://imgur.com/iN2MTZN");
    mgElem[4] = loadImage("https://imgur.com/QclBuA8");
    mgElem[5] = loadImage("https://imgur.com/IAaQ7Ta");
    mgElem[6] = loadImage("https://imgur.com/g3xh1GG");
    mgElem[7] = loadImage("https://imgur.com/LWmOUjc");
    mgElem[8] = loadImage("https://imgur.com/xSvimmS");

    //loading background
    bgElem[0]= loadImage("https://imgur.com/8MNPtj6");
    bgElem[1]= loadImage("https://imgur.com/4bjqW3c");
    bgElem[2]= loadImage("https://imgur.com/q7xaqWr");
    bgElem[3]= loadImage("https://imgur.com/gEnWbVW");
    bgElem[4]= loadImage("https://imgur.com/0yBIPM8");
    bgElem[5]= loadImage("https://imgur.com/6TYtEHn");

    //loading clouds
    pgElem[0] = loadImage("https://imgur.com/pdXo0gP");
    pgElem[1] = loadImage("https://imgur.com/ohLIq5A");
    pgElem[2] = loadImage("https://imgur.com/I9uzjJC");
    pgElem[3] = loadImage("https://imgur.com/JYXlm2v");
}


function setup() {
    createCanvas(400, 400);
    background(202, 240, 248);
    frameRate(12);
    imageMode(CENTER);
    character = makeCharacter(width/4, height*0.62, 0, 0);
    surpriseChar = makeCharacter(-width*2.5, height*0.62, -5.5, 0);

    var rand = 27;
    //loading foreground
    var x1 = random(1, width/4);
    for (var i = 0; i<rand; i++){
        var envChar = makeCharacter(x1, height*(0.63), 5.5, 0);
        envChar.imageNum = int(random(0, fgElem.length));
        x1 += random(width/(rand), (2*width)/rand);
        fg.push(envChar);
    }

     //loading midground
     var rand2 = 20;
     var x2 = random(1, width);
     for (var i = 0; i<rand2; i++){
         var envChar = makeCharacter(x2, height*(0.59), 2.5, 0);
         envChar.imageNum = int(random(0, mgElem.length));
         envChar.size = random(0.1, 0.17);
         mg.push(envChar);
         x2 += random(width/4, width/2);
     }

    //loading background
    var rand3 = 10;
    var x3 = random(1, width);
    for (var i = 0; i<rand3; i++){
        var envChar = makeCharacter(x3, height*(0.4), 1, 0);
        envChar.imageNum = int(random(0, bgElem.length));
        x3 += random(width/6, width/3);
       
        bg.push(envChar);
    }

    //loading clouds
    var rand4 = 4;
    var x4 = random(1, width*(2/3));
    for (var i = 0; i<rand4; i++){
        var y = random(height*0.05, height*0.4);
        
        var envChar = makeCharacter(x4, y, 0.2, 0);
        envChar.imageNum = int(random(0, pgElem.length));
        envChar.size = random(0.1, 0.2);
        pg.push(envChar);
        x4 += random(width/3, width/2);
    }
}


function draw() {
    background(190, 225, 230);
    push();
    noStroke();
    
    ellipseMode(CENTER);
    fill(246, 241, 209, 90);
    circle(width*0.75, height*0.17, width*0.27);
    
    fill(244, 222, 44, 70);
    circle(width*0.75, height*0.17, width*0.22);
    fill(244, 222, 44, 120);
    circle(width*0.75, height*0.17, width*0.17);
    fill(243, 222, 44);
    circle(width*0.75, height*0.17, width*0.12);
    pop();

    updateArray(pg, pgElem);
    for (var i = 0; i<pg.length; i++){
        pg[i].drawFunction(pgElem); 
        pg[i].moveFunction(pgElem);
        
    }  

    updateArray(bg, bgElem);
    for (var i = 0; i < bg.length; i++){
        bg[i].drawFunction(bgElem);
        bg[i].moveFunction(bgElem);
    }

    surpriseChar.drawFunction(walkImage);
    surpriseChar.stepFunction(walkImage);
    surpriseChar.moveFunction();
    


    updateArray(mg, mgElem);
    for (var i = 0; i < mg.length; i++){
        mg[i].drawFunction(mgElem);   
        mg[i].moveFunction(mgElem);
        
    }

    character.drawFunction(walkImage);
    character.stepFunction(walkImage);
    

    updateArray(fg, fgElem);
    for (var i = 0; i<fg.length; i++){
        fg[i].drawFunction(fgElem); 
        fg[i].moveFunction(fgElem);
        
    }  

    push();
    noStroke();
    fill(226, 208, 180);
    rect(0, height*0.74, width, height);
    pop();
}


// Constructor for each walking character
function makeCharacter(cx, cy, cdx, cdy) {
    var c = {x: cx, y: cy, dx: cdx, dy: cdy,
             walkingRight: true, 
             imageNum: 0,
             stepFunction: stepCharacter,
             drawFunction: drawCharacter,
             moveFunction: moveCharacter
         }
    return c;
}

function stepCharacter(images){
    this.imageNum ++;
    this.imageNum = this.imageNum % images.length;
}

function moveCharacter(){
    this.x -= this.dx;
    if (this == surpriseChar & this.x > 200){
        this.x = -width;
    }
}

function drawCharacter(images){
    if (images == fgElem){
        push();
        translate(this.x, this.y);
        scale(0.1);
        image(images[this.imageNum], this.x, this.y);
        pop();
    } else if (images == bgElem){
        push();
        translate(this.x, this.y);
        scale(0.19);
        image(images[this.imageNum], this.x, this.y);
        pop();
    } else if (images == mgElem){
        push();
        translate(this.x, this.y);
        scale(0.18);
        image(images[this.imageNum], this.x, this.y);
        pop();
    } else if (images == pgElem){
        push();
        translate(this.x, this.y);
        scale(this.size);
        image(images[this.imageNum], this.x, this.y);
        pop();
    } else {
        if (this == surpriseChar){
            push();
            scale(-1, 1);
            image(images[this.imageNum], this.x, this.y);
            pop();
        } else {
            image(images[this.imageNum], this.x, this.y);
        }
    }
}

function updateArray(array, source){
    for (var i = 0; i < array.length; i++){
        elem = array[i];
        if ((source == fgElem & elem.x < -10)||
            (source != fgElem && elem.x < -100)){
            elem.x = width + random(width/4, width);
            elem.imageNum = int(random(0, source.length));
        }
    }
}





Looking Outwards 11: Societal Impacts of Digital Art

The article “How Artists Can Bridge the Digital Divide and Reimagine Humanity” by Agnes Chavez discusses the importance of bridging the ‘digital divide’ with regards to accessibility on 3 fronts:

  1. Digital capacity building
  2. Digital public goods
  3. Digital inclusion
Space Cloud
Space Cloud VR headsets

The ‘Space Cloud’, a 10,000 sqft inflatable pavilion equipped with programmable LED lights and virtual reality headsets is one such example of how focused long term engagement can help to dissemination such knowledge to students in rural New Mexico. This is just one method of working towards an “equitable and sustainable digital society” via “digital cooperation”. 

Chavez outlines 2 levels of digital divide – the first being accessibility and affordability of information and communication technologies (ICT) and the second being the “production gap”. According to Chavez, current production of the digital content is monopolized by “a small group of elites”. Giving a diverse pool of people the skills to transition from consumers to producers of such content would not only help empower people of underserved communities, but it would also ensure a greater range of content and deep our understanding of society.

Chavez concludes by emphasizing the importance of multiplicity with respect to solving modern problems: “In a world of complexity and constant change, no one approach is sufficient… By supporting these artists creating new digital tools and experiences, we allow our diverse communities to participate in reimagining our humanity.” 

One thing that was heavily emphasized in my undergraduate Architecture education was how multidisciplinary any given project could be. In the same way we are all participants in a larger society, a single building is but part of a greater urban fabric. The inclusion of multiple voices is essential for any amount of success.

Works Cited

Chavez, Agnes. “How Artists Can Bridge the Digital Divide and Reimagine Humanity”, National Endowments for the Arts, https://www.arts.gov/impact/media-arts/arts-technology-scan/essays/how-artists-can-bridge-digital-divide-and-reimagine-humanity.

Looking Outwards 11

Societal Impacts of Digital Art

ImageRoulette, an Artificial Intelligence device for generating labels, has been controversial due to its racial bias. Image Roulette is a classification tool that generates tags or labels based on an image of a person. These tags usually focus on occupation or suggested family roles. However, when several black tried this device out, they found that out of all 2500 tags, they were only labeled as “black”. When photos were varied, the results were the same and there was no further effort made by the software to classify other aspects of a black person’s photo.


Kate Crawford and Trevor Paglen, developers of ImageRoulette, claim that this is exactly what they hope to represent. They believe that they have proved that Artificial Intelligence is also subject to human bias and racism and that these topics will continue to follow us into the future. This project acted more like an art piece than a usable program; as of September 27th, 2019, it has been taken off the internet.

https://www.smithsonianmag.com/smart-news/art-project-exposed-racial-biases-artificial-intelligence-system-180973207/

Looking Outwards – 11

I looked into copyrights and the sale of the graphic artist Beeple’s artwork called “Everydays: The First 5000 Days” for $69.3 million in 2011. This kind of digital artwork is considered a non-fungible token. This means the ownership of a digital artwork can change, but the copyright still remains with the artist. Its record sales figure comes from the push for the NFTs to gain traction and become more commodifiable. It signifies a change in the art market and shows that more NFT can be bought and sold. The concept of NFTs evolved from the buying and selling of central art, digital artwork and video works, in the art world. Digital artists now can sell their artwork with more certainty that it will not cause legal issues.

https://www.washingtonpost.com/entertainment/museums/beeple-digital-artwork-sale-perspective/2021/03/15/6afc1540-8369-11eb-81db-b02f0398f49a_story.html

Graphic designer Beeple’s artwork “Everydays: The First 5000 Days”

LO11:Societal Impacts of Digital Art

In this week’s looking outward, I read the article about NFT and copyright.

In this reading, the author mainly talks about the newly appeared NFT(Non Fungible Token), as well as its unique features. NFT, as a special token, gives a person more connection to the artwork he buys, and an “ownership” of the artwork. Yet the ownership is tricky because it doesn’t mean that the buyer has full control of the artwork, as the copyright and the right to print on other places without creator’s permission. In the condition that NFT is so expensive, this copyright problem is something that people need to think about.

Also, the definition of NFT determines that there are some sort of copyright problems coming up. As the original artist that create the NFT is allowed to create derivative works from the NFT already sold, there might be NFTs that are similar, or maybe the buyer will not be happy. Yet the original artist has the right to do so, therefore, the buyer could not sue the artist, which makes the situation hard to explain.

A day in the future city

I took inspiration from a scene in cyberpunk edgerunner and made a city landscape based on that. I am surprised by the flexibility of object, the properties can be manipulated in different ways to create completely different stuff. For example, the pillars, foreground, and background buildings are created with one single object.

Inspired scene

sketch

//Jason Jiang
//Section E

//setting up arrays of objects
var bldg = [];
var bldgBack = []
var pillar = []
var vhc = []

//number of objects in each array
var bldgN = 6;
var bldgBackN = 11;
var vhcN = 2;

//color palatte for buildings
var palatte = ['#7670b2', '#5ab6b0', '#5ab6b0', '#3f5c60', '#1c4167', '#3f5c60', '#7e9868'];

//image links of assets
var facadeLink = [
            "https://i.imgur.com/oPA4x4y.png",
            "https://i.imgur.com/xeOW3sz.png", 
            "https://i.imgur.com/gbr6ySL.png",
            "https://i.imgur.com/WqUehK3.png"];
var facadeImg = [];
var vehicleLink = [
            "https://i.imgur.com/gFtwhqV.png",
            "https://i.imgur.com/KX1dLCi.png",
            "https://i.imgur.com/Fo43Kep.png"];
var vehicleImg = [];

//load assets
function preload(){
    train = loadImage("https://i.imgur.com/BFxe31d.png");
    for (var i = 0; i < facadeLink.length; i++){
        facadeImg[i] = loadImage(facadeLink[i]);
    }
    for (var i = 0; i < vehicleLink.length; i++){
        vehicleImg[i] = loadImage(vehicleLink[i]);
    }

}

function setup() {

    createCanvas(400, 200);
    imageMode(CENTER);
    colorMode(HSB);
    
    
    //create front building arrays
    for(var i = 0; i < bldgN; i++){
        //randomly pick color from array
        var palatteIndex = floor(random(palatte.length));
        //randomly pick an image from array
        var facadeIndex = floor(random(facadeImg.length));
        var b = building(80*i, random(-height/3, height/3), random(80, 100), color(palatte[palatteIndex]), facadeImg[facadeIndex]);
        bldg.push(b);
    }

    //create back building arrays
    for(var i = 0; i < bldgBackN; i++){
        var b = building(40*i, random(150), 40, color(20, 10, 30, 0.5), -1);
        bldgBack.push(b);
    }

    //create pillars
    for (var i = 0; i < 2; i++) {
        var p = building(200*i, 70, 20, color(80), -1);
        pillar.push(p);
    }

    //creating vehicles
    for (var i = 0; i < 2; i++) {
        //randomly pick an image from array
        var vehicleIndex = floor(random(vehicleImg.length));
        //randomize vehicle moving direction
        if (random(1) <= 0.5){
            //vehicles from left to right
            var v = vehicle(random(-width/2, 0), random(50, 150), random(5, 10), vehicleImg[vehicleIndex]);
        }
        else{
            //vehicles from right to left
            var v = vehicle(random(width, 1.5*width), random(50, 150), random(-5, -10), vehicleImg[vehicleIndex]);
        }
        vhc.push(v);
    }

 }


function draw() {
    background(200, 20, 100);
    //update information in each frame
    updateObjs();
    updateArray();
    //add train image
    image(train, 200, 90); 
    }


function updateObjs(){
    
    //updating building background
    for(var i = 0; i < bldgBack.length; i++){
        bldgBack[i].move(2);
        bldgBack[i].display();
    }

    //updating building foreground
    for(var i = 0; i < bldg.length; i++){
        bldg[i].move(5);
        bldg[i].display();
    }
    //updating pillars
    for(var i = 0; i < pillar.length; i++){
        pillar[i].move(5);
        pillar[i].display();
    }

    //updating vehicles
    for (var i = 0; i < vhc.length; i++) {
        vhc[i].move();
        vhc[i].display();
    }
    
}


//displaying buildings
function buildingDisplay(){
    
    //draw rectangles
    noStroke();
    fill(this.color);
    rect(this.x, this.y, this.w, height-this.y);
    var centerX = this.x + 0.5*this.w ;
    var centerY = this.y + 0.5*(height - this.y);
   
    //see if the detail property of object is an image, since not pillars and background buildings dont need facade details on them
    if (this.detail != -1){
    //add details on building facade
    push();
    translate(centerX, centerY);
    image(this.detail, 0, 0, 0.8*this.w, 0.95*(height-this.y));
    pop();
    }
   
}

//update building position
function buildingMove(s){
    this.x -= s;
}

//displaying vehicles
function vehicleDisplay(){
    push();
    //flip the image if going from right to left
    if(this.s < 0){
        scale(-1, 1);
        image(this.detail, -this.x, this.y);
    }
    else{
        image(this.detail, this.x, this.y);
    } 
    pop();
}

//update vehicles position and age
function vehicleMove(){
    this.x += this.s;
    this.age += 1;
}




function updateArray(){
    //replacing foreground buildings outside canvas
     for(var i = 0; i < bldg.length; i++){
        if (bldg[i].x <= -bldg[i].w){
            var palatteIndex = floor(random(palatte.length));
            var facadeIndex = floor(random(facadeImg.length));
            var b = building(400, random(-height/3, height/3), random(80, 100), color(palatte[palatteIndex]), facadeImg[facadeIndex]);
            bldg[i] = b;
             
        }
    }

    //replacing background buildings outside canvas
    for(var i = 0; i < bldgBack.length; i++){
        if (bldgBack[i].x <= -bldgBack[i].w){
            var b = building(400, random(150), 40, color(20, 10, 30, 0.5), -1);
            bldgBack[i] = b;
        }
     }

    //replacing pillars outside canvas
    for(var i = 0; i < pillar.length; i++){
        if (pillar[i].x <= -pillar[i].w){
            var p = building(400, 70, 20, color(80), -1);
            pillar[i] = p;
        }
     }

     //replacing vehicles after a certain time
     for(var i = 0; i < vhc.length; i++){
        
        if (vhc[i].age > 200){
            var vehicleIndex = floor(random(vehicleImg.length));
            if (random(1) <= 0.5){
                var v = vehicle(random(-width/2, 0), random(50, 150), random(5, 10), vehicleImg[vehicleIndex]);
            }
            else{
                var v = vehicle(random(width, 1.5*width), random(50, 150), random(-5, -10), vehicleImg[vehicleIndex]);
            }
            vhc[i] = v;
        }
    }

}


//create building objects
function building(buildingX, buildingY, buildingWidth, buildingColor, buildingDetail) {
    var b = {   x: buildingX,
                y: buildingY,
                w: buildingWidth,
                color: buildingColor,
                detail: buildingDetail,
                display: buildingDisplay,
                move: buildingMove
    }
    return b;
}

//create vehicle objects
function vehicle(vehicleX, vehicleY, vehicleSpeed, vehicleDetail) {
    var v = {   x: vehicleX,
                y: vehicleY,
                s: vehicleSpeed,
                age: 0,
                detail: vehicleDetail,
                display: vehicleDisplay,
                move: vehicleMove
    }
    return v;

}