In this interactive game/animation:
(click on the canvas first)
Press left arrow to add birds, press right arrow to add chimneys. Bird nests and raccoons will show up according to the added elements. The position of mouseY changes the color of the sky. As more birds are added, bird sound gets louder.
sketch
var Y_AXIS = 1;var c1, c2;var PREFIX = "https://courses.ideate.cmu.edu/15-104/f2018/wp-content/uploads/2018/12/";var birdSound;
var trainSound;
var bV = 0.2;
var houseList = [];var allTrees = [];var birdList = [];var raccoonList = [];var flap = true;
var nestCount = 0;
var birdperNest = 3;var trainList = [];var rachouseCount = 0;
frameCount = 200;
function preload(){
birdSound = loadSound(PREFIX + "birds.wav");
trainSound = loadSound(PREFIX + "train.wav");
trainSound.setVolume(0.5);
}
function setup() {
createCanvas(500, 300);
c1 = color(244, 248, 255); c2 = color(94, 164, 186);
drawBackground();
for(var i = 0; i < 10; i++) {
var newX = random(80, 420);
var newY = random(120, 200);
if (houseList.length < 1){
houseList.push(makeHouse(newX, newY));
}
else{
while (checkifLess(newX, newY, houseList, 30)){
newX = random(80, 420);
newY = random(120, 200);
}
houseList.push(makeHouse(newX, newY));
}
}
for(var i = 0; i < 40; i++) {
allTrees.push(makeTree());
}
sortTree(allTrees);
sortTree(houseList);
birdList.push(makeBird(width / 2,height / 2, 15));
raccoonList.push(makeRac(width / 2, height / 2, 5));
}
function draw() {
birdSound.setVolume(bV);
if (frameCount % 100 == 0){
birdSound.play();
}
bV = (map(birdList.length, 0, 20, 0, 1));
drawBackground();
drawStairs();
nestCount = 0;
rachouseCount = 0;
for (var i = 0; i < houseList.length; i++) {
if (houseList[i].rh){
rachouseCount += 1;
}
}
if (raccoonList.length < rachouseCount * 2){
raccoonList.push(makeRac(random(0, 500), random(150, 220)));
}
for (var i = 0; i < raccoonList.length; i++) {
raccoonList[i].draw();
raccoonList[i].rx += raccoonList[i].vel;
if (racoutofBound(raccoonList[i])){
raccoonList.splice(i, 1);
i -= 1;
}
}
for (var i = 0; i < houseList.length; i++) {
houseList[i].draw();
}
for (var i = 0; i < allTrees.length; i++){
if (i % 3 == 0){
allTrees[i].draw1();
} else if (i % 3 == 1){
allTrees[i].draw2();
} else {
allTrees[i].draw3();
}
if (allTrees[i].nest){
nestCount += 1;
}
}
drawTracks();
if (frameCount % 40 == 0){
flap = !(flap);
}
for (var i = 0; i < birdList.length; i++) {
if (birdoutofBound(birdList[i])){
birdList.splice(i, 1);
i -= 1;
}
}
for (var i = 0; i < birdList.length; i++) {
if (flap){
birdList[i].draw2();
} else {
birdList[i].draw();
}
birdList[i].bx += birdList[i].xvel * noise(1);
birdList[i].by += birdList[i].yvel * noise(1);
};
if (frameCount % 100 == 0){
for (var i = 0; i < birdList.length; i++) {
birdList[i].xvel += random(-3, 3) * (map(pow(2, birdList[i].by / 50), 0, pow(2, 300 / 50), 1, 100)) / 35;
birdList[i].yvel += random(-1, 1) * (map(pow(2, birdList[i].by / 50), 0, pow(2, 300 / 50), 1, 100)) / 35;
}
}
var darkness = map(mouseY, 0, height, 0, 200);
fill(0, 0, 0, darkness);
noStroke();
rect(0, 0, width, height);
if (birdList.length > 0 & int(birdList.length / birdperNest) < 40){
if (int(birdList.length / birdperNest) > nestCount){
var seltree = int(random(0, allTrees.length));
while (allTrees[seltree].nest){
seltree = int(random(0, allTrees.length));
}
allTrees[seltree].nest = true;
} else if (int(birdList.length / birdperNest) < nestCount){
var seltree = int(random(0, allTrees.length));
if (allTrees[seltree].nest == true){
allTrees[seltree].nest = false;
}
}
}
if (frameCount % 400 == 0) {
trainList.push(makeTrain());
trainSound.play();
}
for (var i = 0; i < trainList.length; i++) {
trainList[i].x -= trainList[i].vel;
trainList[i].draw();
};
if (trainList.length > 0){
if (trainList[0].x < -750){
trainList.splice(0, 1);
}
}
}
function racoutofBound(bird){
if (bird.rx < 0){
return true;
} else if (bird.rx > width){
return true;
} else if (bird.ry < 0){
return true;
} else if (bird.ry > height){
return true;
}
return false;
}
function birdoutofBound(bird){
if (bird.bx < 0){
return true;
} else if (bird.bx > width){
return true;
} else if (bird.by < 0){
return true;
} else if (bird.by > height){
return true;
}
return false;
}
function sortTree(treelist){
n = treelist.length;
for (var i = 0; i < n; i++){
for (var j = 0; j < n - i - 1; j++){
if (treelist[j].y > treelist[j+1].y){
var temp = treelist[j];
treelist[j] = treelist[j+1];
treelist[j+1] = temp;
}
}
}
}
function ispointIn(x, y, house){
var x1 = house.x;
var x2 = house.x + house.w;
var y1 = house.y - house.w / 3;
var y2 = house.y + house.h * house.f;
if (x < x1){
return false;
} else if (x > x2){
return false;
} else if (y < y1){
return false;
} else if (y > y2 + 13){
return false;
}
return true;
}
function hListcheck(x, y, list, n){
if (list.length < 1){
return false;
}
if (n < list.length - 2){
return (ispointIn(x, y, list[n]) || hListcheck(x, y, list, n + 1));
} else {
return ispointIn(x, y, list[n]);
}
}
function checkifLess(x, y, list, mindist){
var chck = false;
for (var i = 0; i < list.length; i++) {
var objdist = dist(x, y, list[i].x, list[i].y);
if (objdist < mindist){
chck = true;
}
}
return chck;
}
function makeHouse(locX, locY){
var num = 75;
var house = { x: locX,
y: locY,
w: map(pow(2, locY / num), 0, pow(2, 300 / num), 1, 100), f: floor(random() * 2 + 1), rh: false, draw: drawHouse
};
return house;
}
function drawHouse(){
noStroke();
fill(173, 110, 110);
var h = this.w / 2;
rect(this.x, this.y, this.w, h * this.f); rect(this.x + this.w * 0.7, this.y - this.w / 3,
this.w / 5, this.w / 3); triangle(this.x, this.y,
this.x + this.w / 2, this.y - this.w / 3,
this.x + this.w, this.y); if(this.f == 1){
for (var i = 0; i < this.y / 10; i++) {
var op2 = map(i, 0, 50, 0, 200);
stroke(201, 141, 141, op2);
line(this.x, i * this.y * 0.005 + this.y,
this.x + this.w, i * this.y * 0.005 + this.y);
}
drawWindow(this.x + this.w / 5, this.y + this.w / 6,
this.w * 0.3, this.w / 5);
drawShrub(this.x, this.y + h,
this.w * 0.5, this.w * 0.3);
}else{
for (var i = 0; i < this.y / 5; i++) {
var op3 = map(i, 0, 50, 0, 200);
stroke(201, 141, 141, op3);
line(this.x, i * this.y * 0.005 + this.y,
this.x + this.w, i * this.y * 0.005 + this.y);
}
drawWindow(this.x + this.w / 5, this.y + this.w / 6,
this.w * 0.3, this.w / 5);
drawWindow(this.x + this.w / 5, this.y + this.w * 0.6,
this.w * 0.3, this.w / 5);
drawShrub(this.x, this.y + this.w,
this.w * 0.4, this.w * 0.3);
}
if(this.rh){
fill(135, 81, 132);
rect(this.x + this.w,
this.y + h / 5, this.w / 6, (h * this.f) * 0.75);
triangle(this.x + this.w, this.y + h * this.f,
this.x + this.w, this.y + (h * this.f) / 2,
this.x + this.w + this.w / 3, this.y + h * this.f);
}
}
function drawWindow(x, y, w, h){
noStroke();
fill(239, 233, 218);
rect(x, y, w, h);
}
function drawShrub(x, y, w, h){
noStroke();
fill(143, 168, 104);
ellipse(x, y, w, h);
ellipse(x + 5, y, w * 0.8, h * 0.5);
ellipse(x + 3, y - 2, w * 0.8, h * 0.8);
}
function makeTree(){
var num1 = 75;
var tempY = random(120, 200);
var tempX = random(0, 450)
var mult = map(pow(2, tempY / num1), 0, pow(2, 300 / num1), 1, 100) / 40;
var tX = tempX + 3 * mult;
var tY = tempY + 30 * mult;
while (hListcheck(tX, tY, houseList, 0)){
tempY = random(120, 200);
tempX = random(0, 450)
tX = tempX + 3 * mult;
tY = tempY + 30 * mult;
}
var tree = { x: tempX,
y: tempY,
w: map(pow(2, tempY / num1), 0, pow(2, 300 / num1), 1, 100), m: map(pow(2, tempY / num1), 0, pow(2, 300 / num1), 1, 100) / 40,
draw1: tree1draw,
draw2: tree2draw,
draw3: tree3draw,
nest: false
};
return tree;
}
function tree1draw(){
noStroke();
push();
translate(this.x, this.y);
scale(this.m, this.m);
fill(122, 98, 66);
rect(3, 0, 3, 30);
fill(95, 140, 99, 180);
ellipse(0, -5, 30, 35);
ellipse(15, -5, 20, 25);
ellipse(5, 8, 50, 20);
if(this.nest == true){
fill(89, 68, 49);
rect(0, 0, 10, 10);
fill(193, 164, 137);
ellipse(5, 5, 4, 4);
}
pop();
}
function tree2draw(){
noStroke();
push();
translate(this.x, this.y);
scale(this.m, this.m);
fill(122, 98, 66);
rect(5, 0, 3, 30);
fill(95, 120, 96, 200);
triangle(18, 18, -6, 18, 6, -30);
if(this.nest == true){
fill(89, 68, 49);
rect(0, 0, 10, 10);
fill(193, 164, 137);
ellipse(5, 5, 4, 4);
}
pop();
}
function tree3draw(){
noStroke();
push();
var mult = this.w / 40;
translate(this.x, this.y);
scale(mult, mult);
fill(122, 98, 66);
rect(3, 0, 3, 30);
fill(108, 132, 102, 200);
ellipse(4, -17, 20, 20);
ellipse(4, -8, 30, 20);
ellipse(4, 5, 40, 25);
if(this.nest == true){
fill(89, 68, 49);
rect(0, 0, 10, 10);
fill(193, 164, 137);
ellipse(5, 5, 4, 4);
}
pop();
}
function drawBackground(){
setGradient(0, 0, width, height * 0.45, c1, c2, Y_AXIS);
noStroke();
fill(75, 137, 138);
beginShape();
curveVertex(0, height);
curveVertex(0, height);
curveVertex(0, 200);
curveVertex(0, 180);
curveVertex(190, 60);
curveVertex(280, 80);
curveVertex(350, 70);
curveVertex(420, 100);
curveVertex(520, 80);
curveVertex(width, height);
curveVertex(width, height);
endShape();
for (var i = 0; i < 500; i++) {
var op = map(i, 100, 500, 0, 255);
stroke(255, 255, 255, op);
line(0, i * 0.6, width, i * 0.6);
}
noStroke();
strokeWeight(1);
fill(75, 147, 154);
beginShape();
curveVertex(0, height);
curveVertex(0, height);
curveVertex(0, 120);
curveVertex(0, 110);
curveVertex(100, 70);
curveVertex(200, 130);
curveVertex(300, 90);
curveVertex(400, 130);
curveVertex(500, 120);
curveVertex(500, 130);
curveVertex(width, height);
curveVertex(width, height);
endShape();
for (var i = 0; i < 500; i++) {
var op = map(i, 100, 500, 0, 255);
stroke(255, 183, 80, op);
line(0, i, width, i);
}
}
function drawStairs(){
noStroke();
fill(99, 88, 77);
for (var i = 0; i < 15; i++) {
rect(i * 5 + 30, i * 3 + 190, 8, 1.5);
rect(i * 5 + 40, -i * 2 + 190, 8, 1);
rect(i * 5 + 30, i * 3 + 120, 1 + i * 0.5, 1)
};
rect(35, 190, 2, 45);
rect(28, 190, 2, 45);
rect(28, 210, 8, 2);
rect(110, 162, 1, 35);
rect(116, 162, 1, 35);
rect(110, 170, 6, 1);
strokeWeight(2);
line(1, 1, 100, 100);
for (var j = 0; j < 30; j++) {
fill(117, 107, 98);
rect(j * 2 + 440, j * 3 + 130, 1 + j * 0.7, 1);
};
}
function drawTracks(){
stroke(122, 102, 82);
strokeWeight(2);
line(0, 280, 500, 280);
strokeWeight(1);
line(0, 275, 500, 275);
for (var i = 0; i < 15; i++) {
rect(i * 40, 273, 1, 6);
};
}
function makeTrain(){
var train = { x: 500,
y: 277,
vel: random(5, 15),
draw: drawTrain
};
return train;
}
function drawTrain(){
noStroke();
fill(80);
triangle(this.x, this.y - 5, this.x + 25, this.y - 5, this.x + 25, this.y - 20);
rect(this.x + 12, this.y - 40, 10, 15);
rect(this.x + 20, this.y - 40, 50, 35);
rect(this.x + 22, this.y - 50, 15, 25);
rect(this.x + 55, this.y - 59, 30, 4);
rect(this.x + 70, this.y - 16, 16, 8);
rect(this.x + 80, this.y - 16, 8, 8);
rect(this.x + 88, this.y - 13, 18, 3);
fill(140, 89, 88);
rect(this.x + 16, this.y - 45, 40, 25);
fill(140, 100, 88);
rect(this.x + 60, this.y - 55, 20, 45);
fill(201, 216, 215);
rect(this.x + 64, this.y - 52, 12, 18);
fill(96, 83, 58);
ellipse(this.x + 30, this.y - 5, 15, 15);
ellipse(this.x + 70, this.y - 5, 15, 15);
for (var i = 1; i < 5; i++) {
fill(80);
rect(this.x + 100 * i, this.y - 55, 90, 3);
rect(this.x + 100 * i, this.y - 13, 100, 3);
fill(140, 120, 88);
rect(this.x + 5 + 100 * i, this.y - 52, 80, 45);
fill(140, 130, 98);
rect(this.x + 5 + 100 * i, this.y - 22, 80, 15);
fill(201, 216, 215);
rect(this.x + 12 + 100 * i, this.y - 48, 30, 18);
rect(this.x + 48 + 100 * i, this.y - 48, 30, 18);
fill(96, 83, 58);
ellipse(this.x + 20 + 100 * i, this.y - 5, 15, 15);
ellipse(this.x + 70 + 100 * i, this.y - 5, 15, 15);
};
fill(0);
drawSmoke(this.x, this.y);
}
function drawSmoke(x, y){
fill(255, 255, 255, 100);
ellipse(x + 30, y - 60, 20, 10);
ellipse(x + 50, y - 70, 15, 8);
}
function makeBird(x, y) {
var num = 50;
var bird = {"bx": x,
"by": y,
"bsz": size,
"bsca": (map(pow(2, y / num), 0, pow(2, 300 / num), 1, 100)) / 35,
"xvel": random(-10, 10) * (map(pow(2, y / num), 0, pow(2, 300 / num), 1, 100)) / 35,
"yvel": random(-5, 5) * (map(pow(2, y / num), 0, pow(2, 300 / num), 1, 100)) / 35,
};
bird.draw = birdDraw;
bird.draw2 = birdDraw2;
return bird;
}
function birdDraw(){
noFill();
stroke(0);
strokeWeight(2);
push();
translate(this.bx, this.by);
scale(this.bsca);
ellipseMode(CENTER);
arc(35, 35, 100, 100, PI * 1.25, PI * 1.5);
arc(-35, 35, 100, 100, PI * 1.5, PI * 1.75);
fill(0);
ellipse(0, 0, 5, 5);
pop();
}
function birdDraw2(){
noFill();
stroke(0);
strokeWeight(2);
push();
translate(this.bx, this.by);
scale(this.bsca);
rotate(PI/10);
arc(35, 35, 100, 100, PI * 1.25, PI * 1.5);
fill(0);
ellipse(0, 0, 5, 5);
pop();
push();
translate(this.bx, this.by);
scale(this.bsca);
rotate(-PI / 10);
arc(-35, 35, 100, 100, PI * 1.5, PI * 1.75);
pop();
}
function makeRac(x, y){
var rac;
var num = 50;
rac = {
"rx": x ,
"ry": y,
"rsz": size,
"bsca": (map(pow(2, y / num), 0, pow(2, 300 / num), 1, 100)) / 400,
"vel": random(-2, 2) * (map(pow(2, y / num), 0, pow(2, 300 / num), 1, 50)) / 35
};
rac.draw = racDraw;
return rac;
}
function racDraw(){
var inv = -1;
push();
translate(this.rx, this.ry);
fill(0);
noStroke();
beginShape();
if (this.vel < 0){
scale(this.bsca, this.bsca);
} else{
scale(this.bsca * -1, this.bsca);
}
vertex(0, 0);
vertex(5, -10);
vertex(3, -20);
vertex(7, -30);
vertex(5, -40);
vertex(8, -45);
vertex(20, -40);
vertex(65, -55);
vertex(85, -65);
vertex(150, -60);
vertex(190, -30);
vertex(180, 20);
vertex(190, 50);
vertex(180, 80);
vertex(170, 80);
vertex(170, 75);
vertex(175, 73);
vertex(176, 55);
vertex(140, 25);
vertex(110, 25);
vertex(80, 80);
vertex(70, 80);
vertex(70, 75);
vertex(75, 75);
vertex(80, 50);
vertex(70, 10);
vertex(50, 10);
vertex(30, 5);
vertex(10, 10);
vertex(0, 0);
endShape();
beginShape();
vertex(200, -25);
vertex(192, 10);
vertex(200, 18);
vertex(210, -20);
endShape();
beginShape();
vertex(220, -15);
vertex(230, -8);
vertex(220, 30);
vertex(210, 22);
endShape();
beginShape();
vertex(240, -3);
vertex(250, 5);
vertex(242, 20);
vertex(232, 25);
endShape();
beginShape();
fill(255);
vertex(50, 10);
vertex(30, -15);
vertex(20, -13);
vertex(15, -5);
vertex(15, -5);
vertex(20, 0);
vertex(26, 0);
vertex(35, 6);
endShape();
fill(0);
ellipse(23, -8, 5, 5);
rect(112, 50, 15, 7);
rotate(PI / 4);
rect(60, -40, 10, 40);
rect(120, -80, 10, 30);
pop();
}
function keyPressed(){
if(keyCode === RIGHT_ARROW){
if (rachouseCount < houseList.length){
var selhouse = int(random(0, houseList.length));
while (houseList[selhouse].rh == true){
selhouse = int(random(0, houseList.length));
}
houseList[selhouse].rh = true;
}
}
if(keyCode === LEFT_ARROW){
birdList.push(makeBird(random(0, 500), random(0, 200)));
}
}
function setGradient(x, y, w, h, c1, c2, axis) {
noFill();
if (axis == Y_AXIS) { 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);
}
}
}
In this project I want to create an interactive animation on cohabitation wiht urban wildlife in cities. As we are displacing natural habitats to make way for urban sprawl, effects of a loss of biodiversity and edge effects from habitat fragmentation are becoming more pronounced. In my studio I am currently working on a thesis project dealing with the environment and cohabitation/negotiation of boundaries between human and more-than-human species, and creating installations for endangered species as well as synanthropic species to share urban space. I am inspired by the works of Joyce Hwang and Sarah Gunawan , and I want to create an animation that documents the vision of such installation projects and their impacts on our environment. Especially the bird landing pads and composting chimneys for raccoons.
In this animation, trains pass by at a certain interval of time, pressing left arrow adds a bird, and for every 3 birds added, an artificial bird nest attached to trees will pop up. (Nests will start disappearing when birds leave the screen). Pressing right arrow adds a compost chimney attached to houses, and every chimney attracts 2 raccoons.
Working on this project I spent a large chunk of my time illustrating the creatures and houses which in hindsight could have been done much easier if I just drew them and upload them to imgur. I also had trouble with overlapping objects and had to create functions that sort the order or the object array and also draws objects outside of the boundary of other objects. I feel like I reviewed everything we learned this semester through this project.
Sound Test
Audio Player
Audio Player
Audio Player
Audio Player