// Nadia Susanto
// nsusanto@andrew.cmu.edu
// Section B
// Final Project
var terrainSpeed = 0.0005;
var terrainDetail = 0.003;
var clouds = [];
var pipes = [];
var birdY = 300;
var birdX = 65;
var birdGravity = 0.75;
var birdVelocity = 0;
var birdUpForce = -18;
var secs = 0;
function setup() {
createCanvas(600, 600);
background(135,235,250);
pipes.push(makePipe());
//initalizing clouds
for (var x = 0; x < 5; x++) {
var cx = random(width);
clouds[x] = makeClouds(cx);
}
frameRate(60);
}
function draw() {
//blue sky
background(135,235,250);
//show mountains and waves
makeMountains();
makeWaves();
//show clouds
addNewClouds();
updateAndDisplayClouds();
removeCloudsOutofView();
//pipes
addNewPipes();
updateAndDisplayPipes();
//bird
drawBird();
updateBird();
//collision detection for bird with pipe
topCollision();
bottomCollision();
if (frameCount % 60 == 0) {
secs += 1;
}
//score
fill("black");
textSize(30);
textAlign(LEFT);
text("TIME = " + secs, 5, 50);
}
//collision for bird with top pipe
function topCollision() {
for (var i = 0; i < pipes.length; i++) {
if ((birdY < pipes[i].top + 30) & (birdX > pipes[i].x && (birdX < pipes[i].x + pipes[i].w))) {
gameOver();
}
}
}
//collision for bird with bottom pipe
function bottomCollision() {
for (var i = 0; i < pipes.length; i++) {
if ((birdY > pipes[i].top + 150) & (birdX > pipes[i].x && (birdX < pipes[i].x + pipes[i].w))) {
gameOver();
}
}
}
//game over function that stops the game when triggered
function gameOver() {
fill("red");
textAlign(CENTER);
textSize(60);
text("GAME OVER", width/2, height/2);
noLoop();
}
//constantly calling the pipes
function updateAndDisplayPipes() {
for (var i = 0; i < pipes.length; i++) {
pipes[i].move();
pipes[i].draw();
}
}
function addNewPipes() {
if (frameCount % 150 == 0) {
pipes.push(makePipe());
}
}
//moving the pipes right to left
function movePipe() {
this.x -= this.speed;
}
function drawPipe() {
noStroke();
//top pipe
fill(112,186,45);
rect(this.x, 0, this.w, this.top);
rect(this.x - 5, this.top - 2, this.w + 10, 20, 10);
//bottom pipe
rect(this.x, height, this.w, this.top - height + 150);
rect(this.x - 5, this.top + 135, this.w + 10, 20, 10);
}
//object for pipe
function makePipe() {
var pipe = {x: width,
w: 50,
top: random(50, height/2),
speed: 1.5,
move: movePipe,
draw: drawPipe
}
return pipe;
}
//drawing the bird
function drawBird() {
//legs
fill(0);
ellipse(birdX - 10, birdY + 15, 3, 10);
ellipse(birdX + 10, birdY + 15, 3, 10);
//halo
noFill();
stroke("gold");
ellipse(birdX, birdY - 20, 40, 5);
//body
fill("yellow");
ellipse(birdX, birdY, 35, 35);
//eye
fill(0);
ellipse(birdX + 5, birdY - 5, 5);
//beak
fill("orange");
triangle(birdX + 18, birdY - 4, birdX + 23, birdY, birdX + 18, birdY + 4);
}
//implementing velocity and gravity
function updateBird() {
birdVelocity += birdGravity;
//air resistance
birdVelocity *= 0.9;
birdY += birdVelocity;
//making sure it doesnt go beyond top and bottom of canvas
if (birdY > height) {
birdY = height;
birdVelocity = 0;
}
if (birdY < 0) {
birdY = 0;
birdVelocity = 0;
}
}
//adding up force to bird velocity
function birdUp() {
birdVelocity += birdUpForce;
}
//if space bar pressed, trigger the bird to go up
function keyPressed() {
if (key == ' ') {
birdUp();
}
}
//constantly calling the clouds
function updateAndDisplayClouds() {
for (var x = 0; x < clouds.length; x++){
clouds[x].move();
clouds[x].draw();
}
}
function removeCloudsOutofView() {
var cloudsKeep = [];
for (var x = 0; x < clouds.length; x++) {
if (clouds[x].x > 0) {
cloudsKeep.push(clouds[x]);
}
}
clouds = cloudsKeep; //remember the clouds
}
function addNewClouds() {
var cloudProb = 0.01;
//if random number less than probability then a new cloud is shown
if (random(0, 1) < cloudProb) {
clouds.push(makeClouds(width));
}
}
function cloudsMove() {
//move the clouds from right to left
this.x -= this.speed;
}
function drawClouds() {
//draw the white clouds
fill("white");
ellipse(this.x, this.y, this.width, 10);
ellipse(this.x - 25, this.y - 10, 35, 30);
ellipse(this.x + 25, this.y - 10, 30, 30);
ellipse(this.x + 5, this.y - 15, 40, 25);
}
function makeClouds(cloudX) {
//creating object for cloud
var cloud = {x: cloudX,
y: 50,
width: random(50, 100),
speed: 0.50,
move: cloudsMove,
draw: drawClouds}
return cloud;
}
//adopted the terrain starter code to make mountains in background
function makeMountains() {
noStroke();
fill(127,221,136);
beginShape();
for (var x = 0; x < width; x++) {
var t = (x * terrainDetail*3) + (millis() * terrainSpeed);
var y = map(noise(t), 0, 1, height/4, height/3);
vertex(x, y);
}
vertex(width, height);
vertex(0, height);
endShape(CLOSE);
}
//adopted the terrain starter code to make ocean waves
function makeWaves() {
noStroke();
fill(1, 108, 194);
beginShape();
for (var x = 0; x < width; x++) {
var t = (x * terrainDetail/3) + (millis() * terrainSpeed/2);
var y = map(noise(t), 0, 1, height/2, height);
vertex(x, y);
}
vertex(width, height);
vertex(0, height);
endShape(CLOSE);
}
For my final project I made angel bird! I have always been a gamer at heart and love competition whether it be beating my peers or my personal bests. Originally for my proposal I wanted to do scream go hero but had difficulties with voice recognition. Flappy bird was my backup and I am really happy with the way it turned out. I used my knowledge of objects to create the generative backgrounds and the pipes, and I believe my angel bird with a halo is pretty cute.
How the game works:
The game automatically starts and all you have to do is press the space bar to make the bird go up. Instead of scoring, you want to beat your personal best times as you want to see how long you can go without the dreaded “GAME OVER.” Enjoy!
]]>For the final project, I want to challenge myself by learning a p5js function we did not learn about. I want to create an interactive game using speech/voice recognition. I want to create a game like Scream Go Hero where the user has to “scream” to get the avatar to move. A soft voice would make the avatar move. A loud voice would make the avatar jump. The higher the volume, the higher the avatar can jump. The objective of the game will be the same as the avatar has to collect as many objects as it can without falling through the cracks. The actual game doesn’t have much design into it, so I want to create a version where it incorporates a generative landscape and other obstacles.
If I have having trouble getting the speech recognition to work, then I will do a version of flappy bird.
I wanted to look at Phoenix Perry and Heather Kelley because they are both game developers. Phoenix Perry created a game called Bot Party where it explores intimacy through physical play using sound. It’s an interactive sound experience for humans and the bots need help from humans to communicate with their friends. The technology itself uses proprietary bot to skin to skin to bot communication protocol to send encoded secret messages.
Heather Kelley collaborated with several others on the project Fabulous/Fabuleux. It is a physical interface game for public interior spaces where players solve “connect the dots” challenges using the hotspots of the room. The players uses a “squisher” interface object and by connecting the hotspots it reveals objects on screen which relate to the fairy tale “The Girl Who Trod On A Loaf.”
Both of these games interest me because they require physical human interaction within it. I will be doing a project that requires human interaction, so I was inspired by these projects.
To learn more about bot party click below:
http://playbotparty.com/2018/01/24/WhatIsBotPartyl-prep/
To learn more about Fabulous/Fabuleux click below:
]]>// Nadia Susanto
// nsusanto@andrew.cmu.edu
// Section B
// Project-11-Generative Landscape
var terrainSpeed = 0.0005;
var terrainDetail = 0.005;
var boats = [];
var clouds = [];
function setup() {
createCanvas(480, 480);
//initalizing boats
for (var i = 0; i < 3; i++){
var bx = random(width);
boats[i] = makeBoats(bx);
}
//initalizing clouds
for (var x = 0; x < 5; x++) {
var cx = random(width);
clouds[x] = makeClouds(cx);
}
frameRate(20);
}
function draw() {
//pinkish sky
background(254, 165, 159);
//show mountains and waves
makeMountains();
makeWaves();
//show boats
addNewBoats();
updateAndDisplayBoats();
removeBoatsOutofView();
//show clouds
addNewClouds();
updateAndDisplayClouds();
removeCloudsOutofView();
}
function updateAndDisplayClouds() {
//constantly calling the clouds
for (var x = 0; x < clouds.length; x++){
clouds[x].move();
clouds[x].draw();
}
}
function removeCloudsOutofView() {
var cloudsKeep = [];
for (var x = 0; x < clouds.length; x++) {
if (clouds[x].x > 0) {
cloudsKeep.push(clouds[x]);
}
}
clouds = cloudsKeep; //remember the clouds
}
function addNewClouds() {
var cloudProb = 0.01;
//if random number less than probability then a new cloud is shown
if (random(0, 1) < cloudProb) {
clouds.push(makeClouds(width));
}
}
function cloudsMove() {
//move the clouds from right to left
this.x -= this.speed;
}
function drawClouds() {
//draw the white clouds
fill("white");
ellipse(this.x, this.y, this.width, 10);
}
function makeClouds(cloudX) {
//creating object for cloud
var cloud = {x: cloudX,
y: random(10, 100),
width: random(50, 100),
speed: 0.50,
move: cloudsMove,
draw: drawClouds}
return cloud;
}
function updateAndDisplayBoats() {
//constantly calling the boats
for (var i = 0; i < boats.length; i++){
boats[i].move();
boats[i].draw();
}
}
function removeBoatsOutofView() {
var boatsKeep = [];
for (var i = 0; i < boats.length; i++) {
if (boats[i].x > 0) {
boatsKeep.push(boats[i]);
}
}
boats = boatsKeep; //remember the boats
}
function addNewBoats() {
//if random number less than probability then a new boat is shown
var boatProb = 0.005;
if (random(0, 1) < boatProb) {
boats.push(makeBoats(width));
}
}
function boatsMove() {
//move the boats from right to left
this.x -= this.speed;
}
function drawBoats() {
//random color for boats
fill(this.colorR, this.colorG, this.colorB);
//base of boat
arc(this.x, 350, 75, 50, 0, PI, CHORD);
//pole holding the sail
ellipse(this.x, 330, 10, 80);
//sail of boat
triangle(this.x, 290, this.x, 330, this.x + 15, 310);
}
function makeBoats(boatX) {
//creating object for boat
var boat = {x: boatX,
colorR: random(0, 255),
colorG: random(0, 100),
colorB: random(0, 200),
speed: 1,
move: boatsMove,
draw: drawBoats}
return boat;
}
//adopted the terrain starter code to make mountains in background
function makeMountains() {
noStroke();
fill(35, 144, 79);
beginShape();
for (var x = 0; x < width; x++) {
var t = (x * terrainDetail*3) + (millis() * terrainSpeed);
var y = map(noise(t), 0, 1, height/4, height/2);
vertex(x, y);
}
vertex(width, height);
vertex(0, height);
endShape(CLOSE);
}
//adopted the terrain starter code to make ocean waves
function makeWaves() {
noStroke();
fill(1, 108, 194);
beginShape();
for (var x = 0; x < width; x++) {
var t = (x * terrainDetail/3) + (millis() * terrainSpeed/2);
var y = map(noise(t), 0, 1, height/2, height);
vertex(x, y);
}
vertex(width, height);
vertex(0, height);
endShape(CLOSE);
}
For this project I went back to a time when I was in Banff, Canada. I would canoe or ride in a boat on the lake with the mountains behind me. I created moving mountains and moving ocean waves with boats of random colors popping in and out. It was tough at first to figure out how to code the objects, but it was a fun project and I am happy with the final product.
Chloe Varelidi is an indie game designer/developer that designs and builds playful products that empowers humans to be creative, kind, and curious.
One of her projects was the Minicade, and this was a collaboration with Atul Varma for her artist residency at Eyebeam. The Minicade is a website and app where people can collaboratively build mini arcade games with multiple users. Each person can add a link to one or more games to a custom playlist and instantly play them as one massive game, that keeps track of score and increases the difficulty. Its very simple to use and users can either play the games already provided or remix the mini-game with their own code. While the Minicade is mostly used by kids to encourage them to learn the basics of programming, it is fun for everyone to use.
The use of mini-games itself reminds me of mini-games in popular apps like Dumb Ways to Die, and it adds a cool competitive aspect for kids to interact with each other by building games they did themselves.
To learn more about this project, click the links below:
]]>// Nadia Susanto
// nsusanto@andrew.cmu.edu
// Section B
// Project-10-Interactive Sonic Sketch
function preload() {
//loaded image from imgur
TigerWoodsImg = loadImage("https://i.imgur.com/ETVJsHl.jpg");
golfhitSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/golfhit.wav");
tigerRoarSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/tigerroar.wav");
golfBallCupSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/golfballincup.wav");
cheeringSound = loadSound("https://courses.ideate.cmu.edu/15-104/f2019/wp-content/uploads/2019/11/cheering.wav");
}
function setup() {
createCanvas(600, 600);
TigerWoodsImg.resize(600, 600);
useSound();
}
function soundSetup() { // setup for audio generation
golfhitSound.setVolume(1);
tigerRoarSound.setVolume(1);
golfBallCupSound.setVolume(1);
cheeringSound.setVolume(1, 3);
}
function draw() {
background(200);
image(TigerWoodsImg, 0, 0);
}
function mousePressed() {
//sound of a golf ball being hit when clicked on the caddy
if (mouseX > 400 & mouseX < 500 && mouseY > 400) {
golfhitSound.play();
}
else {
golfhitSound.pause();
}
//sound of cheering when clicked on the crowd behind the green
if (mouseY < 300 & mouseY > 150) {
cheeringSound.play();
}
else {
cheeringSound.pause();
}
//sound of a tiger roar when clicked on Tiger Woods
if (mouseX < 300 & mouseX > 200 && mouseY > 350) {
tigerRoarSound.play();
}
else {
tigerRoarSound.pause();
}
//sound of a golf ball going in the hole when clicked on flag
if (mouseX < 330 & mouseX > 300 && mouseY > 250 && mouseY < 320) {
golfBallCupSound.play();
}
else {
golfBallCupSound.pause();
}
}
In the spirit of Tiger Woods winning his 82nd PGA Tour win this past weekend, I wanted to use a picture of him at Augusta National for the Masters and incorporate multiple sounds. I included a tiger roar from the animal itself when you click on Tiger Woods, a sound of the golf ball being hit when clicked on Tiger’s caddy on the right, a sound of the crowd cheering when clicked on the many people in the back of the green, and the sound of a golf ball going into the hole when clicked on the yellow flag on the green.
]]>The Computer Orchestra is an interactive orchestra consisting of multiple computers. It was created by fragment.in, and the goal was to let the user conduct their own orchestra and music. The conductor’s hand movements are accurately recognized using an Xbox Kinect motion controller that is connected to a central computer. Instructions are given to many musician screens. Screen-musicians then send the sound to the conductor and produces visual feedback.
What I love most about the Computer Orchestra is that it crowdsources sounds that people can upload, and then the musician can access it and play it. It’s incredible to see that one person can control the music through simple hand motions and gestures. The simple interface of the centralized computer also makes it extremely easy for the conductor to change where he wants vocals, violin, etc.
To learn more about the Computer Orchestra, click the link below:
]]>// Nadia Susanto
// nsusanto@andrew.cmu.edu
// Section B
// Project-09-Computational Portrait
var underImage;
function preload() {
//preloading image from imgur
//var myImage = "https://i.imgur.com/R80wzCp.jpg";
var myImage = "https://i.imgur.com/uezsOBb.jpg";
underImage = loadImage(myImage);
}
function setup() {
createCanvas(480, 480);
//resize the image so it fits the canvas
underImage.resize(480, 480);
background(0);
underImage.loadPixels();
frameRate(100);
}
function draw() {
var px = random(width);
var py = random(height);
var ix = constrain(floor(px), 0, width-1);
var iy = constrain(floor(py), 0, height-1);
//gets colors from specific image location
var colorXY = underImage.get(ix, iy);
//random rectangles
stroke(colorXY);
strokeWeight(random(1, 10));
noFill();
rect(ix, iy, 20, 10);
}
//random ellipses when mouse is pressed
function mouseDragged() {
ellipse(mouseX, mouseY, random(5, 50), random(5, 30));
}
For my portrait picture I used a picture of myself in a bamboo forest in Japan. I decided to use this picture because it has many different shades of green to the image. Since there was only one main color, I wanted to incorporate different shapes. The main shape is a rectangle, and when the mouse is dragged it switches to ellipses.
I looked at Ammar Hassonjee’s LO 2. He studied a generative art project called “Breathing Wall II” by Behnaz Farahi in 2014, a USC architecture professor. The installation is made out of wood, PVC, and fabric. To capture the hand motions and signals they use many systems like Leap Motion system and DC systems then project contour lines on the wall.
Ammar liked the relationship between movement, light, and color and how it gave power to users to interact with that environment. He also says his favorite types of art are ones that are adaptive and involves user activity. I can agree that this is my favorite type of art as well because involving human behavior brings extra beauty to the artwork.
What I love about this project is that it seems so simple and has a deeper meaning to it. Farahi mentioned how mobile devices used touch and gesture-based languages like swiping, clicking, or dragging for natural control. With the rise of technology and social media, we are entranced by this environment of likes and scrolling through people’s photos with meaningless connections. We forget the real surrounding environment around us, so this project sets a great reminder that those basic controls can be used to control the surrounding environment.
To learn more about this installation, click the link below:
]]>Kim Rees is the Head of Information Visualization at Periscopic, a socially conscious data visualization firm based in Portland, Oregon. Kim has garnered many awards and has presented herself to be a prominent figure in the world of information visualization. Kim’s work has been featured in the MOMA, the Parsons Journal of Information Mapping, and was an award winner in the VAST 2010 Challenge.
I really admire her work because she is taking her skills of creating beautiful pieces of information visuals to talk about bigger societal issues that are needed in this day and age. Below is one of her famous works regarding gun violence. What many don’t understand is that there is an overwhelming magnitude of loss from US gun deaths. The orange line depicts the person that died, and the white line that continues from the orange depicts how long they could’ve lived for. By this heart-wrenching visual, its easy to see how many years of life were stolen at the hands of guns.
To see the whole visual from above come to life, click the link below:
https://guns.periscopic.com/?year=2013
While Kim Rees was unable to showcase her works with Periscopic at Eyeo, her talk on the future of data was inspiring. She was not afraid to seem controversial and had great insights into privacy, actualized data, and more. Kim values open data and believes that using more and more data can help solve social issues. Watch her talk below at Eyeo 2014.