kyungak + dayoungl – finalproject

For our final project, Sharon and I made a game named, “TOM.” In order to play TOM, users are to:

  1. Use the arrow keys (up, down, left, right) to move the main character, TOM
  2. Avoid contact with bombs – if contact is made, TOM dies and the game is over
  3. Avoid contact with puffs – if contact is made, TOM loses a point (-1)
  4. Consume hearts – if contact is made, TOM earns a point (+1)
  5. Notice: If bombs make contact with hearts, the bomb bursts and gets rid of the hearts
  6. Notice: Hearts randomly get patched across the canvas. It shrinks in size and disappears if not consumed by TOM.
  7. Notice: When the game starts, you might immediately see the game over sign because the randomly generated bombs overlap with the initial position of TOM (100,100). Don’t panic and just refresh the webpage so you can restart.

Your goal is to get as much point as possible. Compete with friends and see who can get the most points!

Please download the file and use the local file to access the html file of TOM.

PLAY ME

GRADE ME

sketch

//Kyunga Ko
//15104B
//kyungak@andrew.cmu.edu
//Capstone Project:Tom and Toms (COMPLETE VERSION)

var bomb;
var puff;
var heart;
var explosion;
var tomcharacter; 
var eating;
var gameover;
var scoreboard;
var score = 0;

function preload() {

  //Preloading gameover and scoreboard image
  gameover = loadImage("https://i.imgur.com/VlLC4xC.png");
  scoreboard = loadImage("https://i.imgur.com/8ke3Z26.png");

}

function setup() {
  createCanvas(800,800);  

  //Grouping variables
  bomb = new Group();
  puff = new Group();
  heart = new Group();
  explosion = new Group();
  tomcharacter = new Group();
  eating = new Group();

  //Create bomb at random locations on canvas
  for(var i=0; i<15; i++) {
    createBomb(random(0,width), random(0,height));
  }

  //Single character "Tom" is created
  for(var i=0; i<1; i++) {
    createTom(100, 100);
  }

}

function draw() {
  background(230);
  //Reduce the size of the heart by the rate of the frameCount
  if(frameCount%60==0 & heart.length<5) {
    //Create hearts at random locations on the canvas
    createHeart(random(0,width), random(0,height)); 
  }
  
  //Recycle puff on four sides = randomly displaced
  if(frameCount%60==0 & puff.length<10) {
    var canvasside = floor(random(0,4));
    
    if(canvasside == 0) //left
      createPuff(0, random(height));
    if(canvasside == 1) //right
      createPuff(width, random(height));
    if(canvasside == 2) //top
      createPuff(random(width), 0);
    if(canvasside == 3) //bottom
      createPuff(random(width), height);
      
    }
  
  //(BOMB) Bomb orientation in general
  for(var i = 0; i<bomb.length; i++) {
  
    var b = bomb[i];
    b.noisePosition += 0.1;
    b.rotation += (noise(b.noisePosition)-0.5)*10;
    b.setSpeed(2, b.rotation);
    randomrelocation(b);

  }
  
  //(PUFF) When puff collides with bomb and heart
  for(var i = 0; i<puff.length; i++) {
      var p = puff[i]; 
      randomrelocation(p);

      for(var j = 0; j<bomb.length; j++) {
        var b = bomb[j]; 
        //Distance btw puff and bomb
        var dis = p5.Vector.dist(p.position, b.position); 
        
        //Puff and bomb does not attract
        if(dis < 70) {   
          var angle = degrees(atan2(b.position.y-p.position.y, 
            b.position.x-p.position.x));
          //repel
          var attraction = -30 / dis;
          p.addSpeed(attraction, angle);

        }
      }

      for(var z = 0; z<heart.length; z++) {
        var h = heart[z]; 
        //Distance btw heart and puff
        var dis2 = p5.Vector.dist(p.position, h.position); 
        
        //Puff and heart attract
        if(dis2 < 30) {   
          var angle2 = degrees(atan2(h.position.y-p.position.y, 
            h.position.x-p.position.x));
          var attraction2 = 100 / dis2;
          p.addSpeed(attraction2, angle2);

        }

      }
  }

  //(HEART) When heart collides with bomb and puff
  for(var i = 0; i<heart.length; i++) {

      var h = heart[i]; //save in a temp variable
      h.scale = map(h.life, 300, 0, 1, 0);
      h.overlap(bomb, bombeatsheart);
      h.overlap(puff, puffeatsheart); 

  }

  //(TOM) When Tom collides with bomb and heart
  for(var i = 0; i<tomcharacter.length; i++) {

    var t = tomcharacter[i]; //save in a temp variable
    t.overlap(bomb, bombmeetstom); 
    t.overlap(heart, heartmeetstom);
    t.overlap(puff, puffmeetstom);
   
  }

  //Scoreboard
  image(scoreboard, 580, 15); //Scoreboard image
  textSize(30);
  fill(0); 
  text(score,670,90); //Displays the score

  //Draws all sprites
  drawSprites();

}

//Makes Tom move up, down, left, right using the arrow keys
function keyPressed(){
  var tab = 20;
  var clickCount = 0;

  for (var i = 0; i<tomcharacter.length; i++ ){
    var t = tomcharacter[i];

    if (keyIsPressed === true){
      clickCount ++; //clickcount increases with movement
    }

    if (keyIsDown(LEFT_ARROW)){
      t.position.x -= tab; //left
    }

    if (keyIsDown(RIGHT_ARROW)){
      t.position.x += tab; //right
    }

    if (keyIsDown(UP_ARROW)){
      t.position.y -= tab; //up

    } else if (keyIsDown(DOWN_ARROW)){
      t.position.y += tab; //down
      }
    
  }
  
}

//The object dissapears outside the canvas and is randomly located again
function randomrelocation(w) {
   //wrap around the screen
    if (w.position.x > width)
      w.position.x = 0;
    if (w.position.x < 0)
      w.position.x = width;
    if (w.position.y > height)
      w.position.y = 0;
    if (w.position.y < 0)
      w.position.y = height;

}

//When puff eats the heart, they multiply x2 
function puffeatsheart(puff, heart) {
  puff.remove();
  createPuff(heart.position.x, heart.position.y);

}

//When Tom meets puff, score decreases by one
function puffmeetstom(puff, tomcharacter) {
  tomcharacter.remove();
  score--;

}

//Bomb eats/gets rid of the heart + explosion sign
function bombeatsheart(bomb, heart) {
  bomb.remove();
  createExplosion(heart.position.x, heart.position.y);
  createExplosion(heart.position.x, heart.position.y);
  createExplosion(heart.position.x, heart.position.y);
  createExplosion(heart.position.x, heart.position.y);
  createExplosion(heart.position.x, heart.position.y);
  createExplosion(heart.position.x, heart.position.y);
  createExplosion(heart.position.x, heart.position.y);
  

}

//Tom eats heart and +1 sign comes up
function heartmeetstom(heart, tomcharacter) {
  tomcharacter.remove();
  aftereatingheart(heart.position.x, heart.position.y);
  score++;
  
}

//When bomb meets Tom, Tom dies and game over sign comes up
function bombmeetstom(bomb, Tom) {
  bomb.remove();
  noLoop();
  push();
  scale(0.7);
  image(gameover, 175, 400);
  pop();

}

//Bomb is created
function createBomb(x, y) {

  var b = createSprite(x, y);
  b.addAnimation("bomb", "https://i.imgur.com/N4m1kty.png");
  b.setSpeed(2, random(0,360));
  b.noisePosition = random(0, 1000);
  b.maxSpeed = 2;
  bomb.add(b);

}

//When bomb eats heart, explosion is created to indicate that a heart was ate
function createExplosion(x, y) {

  var e = createSprite(x, y);
  e.addAnimation("bomb", "https://i.imgur.com/wzVAcbK.png");
  e.setSpeed(2, random(0,360));
  e.noisePosition = random(0, 1000);
  e.maxSpeed = 2;
  explosion.add(e);

}

//After Tom eats heart, +1 sign is created
function aftereatingheart(x, y) {

  var a = createSprite(x,y);
  a.addAnimation("eat", "https://i.imgur.com/b9C1Xyl.png");
  a.setSpeed(2, random(0,360));
  a.noisePosition = random(0, 1000);
  a.maxSpeed = 2;
  eating.add(a);

}

//Puff is created
function createPuff(x, y) {

  var p = createSprite(x, y);
  p.addAnimation("puff", "https://i.imgur.com/cs8Mkcr.png");
  p.setSpeed(-2, random(0,360));
  p.maxSpeed = 1;
  puff.add(p);

}

//Heart is created
function createHeart(x, y) {
  
  var h = createSprite(x, y);
  h.addAnimation("heart", "https://i.imgur.com/u2uRAYl.png");
  h.life = 300; 
  heart.add(h);

}

//Tom is created
function createTom(x, y) {

  var t = createSprite(x, y);
  t.addAnimation("tomcharacter", "https://i.imgur.com/Q8FnPtP.png", 
    "https://i.imgur.com/QzOR227.png");
  tomcharacter.add(t);

}

















kyungak-lookingoutwards-12

(Jason Rohrer, “Inside a Star-Filled Sky”, 2011)

https://www.artsy.net/article/artsy-editorial-are-video-games-art

Jason Rohrer is a computer programmer and a game designer that not only produces games for its original purpose, but also as art. He codes creative games that are usually sold and played in the public domain, but also combines a series of them to exhibit as art works. Most shame came from the public who thought that games could not be art. However, Rohrer still believed them as artworks because creation of games was no different from painting to him. When I saw his works, I was inspired to create something similar to the pieces in his exhibitions. Similar to the format of the Pac man game, I wanted to have vivid graphics but a simple mechanism that kept the game running. Rohrer’s games and visuals were a great inspiration for me.

(Jenova Chen, “Flower”, 2009)

http://jenovachen.info/flower/

Jenova Chen is the designer of the playstation game, “Flower” that was released in 2009. Although this game is an actual game, it is largely considered as an art work for its aesthetic value. The interaction of the game with the players isn’t about winning or competing for a prize. The wander and exploration through the landscapes and the stunning visuals were the initial goals of this game. As visuals are important for the final project I’m planning, I wanted to get inspirations from the way she portrayed her objects. Her project was beautiful.

 

kyungak-final-project-proposal

For the final Project, I will be collaborating with Sharon Lee from section E. Together, we will be using p5js to create a Pac-man inspired interactive game which will be divided into 3 stages. The basic components of the game include a main character in which users are able to control with keys, enemies of the main character, and the “foods” the character feeds on to either get larger or smaller. From stage 1 to 3, the stages get harder with more frequencies of “enemies” appearing on the screen.  In order to progress to the next stage, the users need to reach certain points. Users gain points by the number of enemies they defeat..? We are still working on the structure of the game, but I hope this give a general idea of what our game will be like. In terms of diving up workload, we will be working together to create the basic structure of the program. Sharon will focus on the visual materials, and code stage 1 (moving the characters and imbedding the animation). I will follow up with her code and add 2 more stages to the code. I will add attraction and repel code to the characters and the enemies.

kyungak-project-11-Composition

sketch

//Kyunga Ko
//15104B
//kyungak@andrew.cmu.edu
//Project-11

var turtle = [];
var redcolor = 100;
var greencolor = 150;
var bluecolor = 200;
var xinc = 0;
var yinc = 0;
var zinc = 0;

function setup() {
    createCanvas(480, 480);

    background(255);

    for(var i = 0; i < 50; i++) {
        turtle[i] = makeTurtle(random(width),random(height));
        turtle[i].setColor(color(redcolor,greencolor,bluecolor));
        turtle[i].setWeight(0.4);
        turtle[i].penDown();
        frameRate(10);
    }

}

function draw(){

    for (var i = 0; i < 50; i++) {
        turtle[i].setColor(color(redcolor,greencolor,bluecolor));
        turtle[i].forward(xinc);
        turtle[i].right(zinc);
        turtle[i].back(xinc);

    } 

    map(mouseX,0,600,0,5);
    xinc = random(0,30);
    yinc = random(0,30);
    zinc = random(0,mouseX);
        
}

function mousePressed(){

    redcolor = random(0,255);
    bluecolor = random(0,255);
    greencolor = random(0,255);

}

function turtleLeft(d){this.angle-=d;}
function turtleRight(d){this.angle+=d;}
function turtleForward(p){var rad=radians(this.angle);var newx=this.x+cos(rad)*p;
var newy=this.y+sin(rad)*p;this.goto(newx,newy);}
function turtleBack(p){
this.forward(-p);}
function turtlePenDown(){this.penIsDown=true;}
function turtlePenUp(){this.penIsDown = false;}
function turtleGoTo(x,y){
if(this.penIsDown){stroke(this.color);strokeWeight(this.weight);
line(this.x,this.y,x,y);}this.x = x;this.y = y;}
function turtleDistTo(x,y){
return sqrt(sq(this.x-x)+sq(this.y-y));}
function turtleAngleTo(x,y){
var absAngle=degrees(atan2(y-this.y,x-this.x));
var angle=((absAngle-this.angle)+360)%360.0;return angle;}
function turtleTurnToward(x,y,d){var angle = this.angleTo(x,y);if(angle< 180){
this.angle+=d;}else{this.angle-=d;}}
function turtleSetColor(c){this.color=c;}
function turtleSetWeight(w){this.weight=w;}
function turtleFace(angle){
this.angle = angle;}
function makeTurtle(tx,ty){var turtle={x:tx,y:ty,
angle:0.0,penIsDown:true,color:color(128),weight:1,left:turtleLeft,
right:turtleRight,forward:turtleForward, back:turtleBack,penDown:turtlePenDown,
penUp:turtlePenUp,goto:turtleGoTo, angleto:turtleAngleTo,
turnToward:turtleTurnToward,distanceTo:turtleDistTo, angleTo:turtleAngleTo,
setColor:turtleSetColor, setWeight:turtleSetWeight,face:turtleFace};
return turtle;}

I wanted to express snowflakes through the turtles function. When you move mouseX around the canvas, it changes the angle to which the snowflakes spread. When you click the mouse, the color changes. It will create a dynamic and a non-symmetrical snowflake across the canvas. It was a very interesting process, and the results were satisfying.

kyungak-lookingoutwards-11

(Simon de Diesbach, Jonas Lacôte, Laura Perrenoud,  “The Computer Orchestra”, 2013)

The creators of “The Computer Orchestra” initially met  at University of Art and Design of Lausanne in Switzerland during their Bachelor’s degree in media and interaction design. This project started as a small project, but later grew into an amazing piece that was exhibited in various parts of the world.

“The Computer Orchestra” is an interactive installation that allows viewers to conduct their own orchestra.  Users can upload or download music samples and integrate them to their own taste using the simple interface within in the computer. The sounds also change according to space. Kinect connected to the center of the computer detects motion of the user’s hands and position and interacts accordingly.

I personally admire the interactivity of this artwork. Being able to produce an orchestra that usually needs a handful of people with computers sounds amazing. The original thought and the combination of interactiveness made the artwork accessible and fun. I feel like this artwork was also educational, which makes it extra worthy to exhibit.

kyungak-project-10-generative-landscape

sketch

//Kyunga Ko
//15104B
//kyungak@andrew.cmu.edu
//Project 10

var terrainspeed = 0.0005;
var terraincurve = 0.025;
var binocular;
var cactus = [];

//loads the images from imgur (binoculars and cactus)
function preload() {
    binocular = loadImage("https://i.imgur.com/bVzNOic.png");
    cactus1 = loadImage("https://i.imgur.com/E2dHw8Y.png")
}

function setup() {
    createCanvas(480, 480);

    //initially iterates cactus
    for (var i = 0; i < 5; i++){
        var location = random(width);
        cactus[i] = makeCactus(location);
    }

    frameRate(10);
}
 
function draw() {
    background(214,196,211,200);

    backgroundmountain();
    bottomsand();

    updateCactus();
    displayCactus();
    addCactus();
    makeCactus(); 
    moveCactus();

    // structure of sun
    fill(255,0,0,150);
    noStroke();
    ellipse(70,70,50,50);
    stroke(255,0,0,150);
    strokeWeight(3);
    line(70,30,70,45);
    line(70,95,70,110);
    line(30,70,45,70);
    line(95,70,110,70);

    //Binoculars
    image(binocular,mouseX-500,mouseY-500); 
}

//updating cactus location and movement
function updateCactus(){
    for (var i = 0; i < cactus.length; i++){
        cactus[i].move();
        cactus[i].display();
    }
}

// adding new cactus from the left side of the canvas
function addCactus() {
    var a = random(1);
    if (a < 0.03) {
        cactus.push(makeCactus(width));
    }
}

//moving the position of cactus 
function moveCactus() {
    this.x += this.speed;
}
    

//drawing and displaying cactus
function displayCactus() {
    push();
    translate(this.x, this.height);
    for(var i=0; i<this.number; i++) {
        image(cactus1,this.x*i, 100);
    }
    pop();
}

//making cactus + variables needed to make cactus
function makeCactus(birthx) {
    var cactus2 = {x: birthx,
                number: floor(random(1,2)),
                speed: -3,
                height: random(90,100),
                move: moveCactus,
                display: displayCactus}
    return cactus2;
}

//function that draws the mountains
function backgroundmountain() {  

    //back mountain
    noStroke();
    fill(9, 69, 32); 
    beginShape(); 
    //for loop makes back layer of mountain
    for (var x = 0; x < width; x++) {
        var t = (terraincurve * 2 * x) + (millis() * terrainspeed);
        var y = map(noise(t/2), 0, 1, 70, height);
        curveVertex(x, y); 
    }
    curveVertex(width, height);
    curveVertex(0,width);
    endShape(CLOSE);  

    //front mountain
    noStroke();
    fill(89, 107, 89,200); 
    beginShape(); 
    //for loop makes front layer of mountain
    for (var x = 0; x < width; x++) {
        var t = (terraincurve * x) + (millis() * terrainspeed);
        var y = map(noise(t/2), 0, 1, 0, height);
        curveVertex(x, y); 
    }
    curveVertex(width, height);
    curveVertex(0,width);
    endShape(CLOSE);

}

//function that draws the sand layer on the bottom
function bottomsand() { 

    //front mountain
    noStroke();
    fill(179,145,86); 
    beginShape(); 
    //for loop makes the sand layers on the bottom
    for (var x = 0; x < width; x++) {
        var t = (terraincurve * x) + (millis() * terrainspeed);
        var y = map(noise(t/2), 0, 1, 370, height);
        curveVertex(x, y); 
    }
    curveVertex(width, height);
    curveVertex(0,width);
    endShape(CLOSE); 

}

For this project, I wanted to make a landscape that contained both a desert and a forest. On the bottom desert layer, I altered the original terrain function by reducing the amount of noise. This allowed me to make a smoother surface of sand. For the random cactuses, I made them into javascript objects and coded accordingly. The cactus image was photoshopped by me and embedded through imgur. I then utilized the provided terrain code to slightly alter and make the forest layers. I then gave a little twist by photoshopping a binocular image and putting it on top of the landscape function. It made it as if you are looking through the binoculars from a distance. Although the process was a bit rocky, I managed to understand and use the javascript object function. I was able to learn a lot through this project.

 

kyungak-lookingoutwards-10

(Kate Hollenbach, USER_IS_PRESENT, 2017)

Kate Hollenbach is an artist and a designer that works with computational programs to generate her works. She holds MFA from UCLA and a degree of computer science and engineering from MIT and was a director of design and computation at Oblong industries. Now, she examines new technologies to create an interactive space that explores the connection between one’s body, gestures, and physical space in relation to technological devices, such as phones.

“USER_IS_PRESENT” is an expansion of the relationship I just stated above. The work consists of three monitors that split across virtual and physical spaces. Hollenbach recorded three different point of views of the phone: the actual screen, back camera, and front camera. She captured the motion of both the user, phone, and the outside world and tried to bring them altogether. I admire the concept of her work. The spontaneous capture of the three view points looked fascinating when they were put together. The emphasis on being in both virtual and physical space seemed amazing.

kyungak-project-09-portrait

sketch

//Kyunga Ko
//15104B
//kyungak@andrew.cmu.edu
//Project 09

var selfportrait; //self portrait image
var x = []; //x position array
var y = []; //y position array
var dx = []; //x velocity array
var dy = []; //y velocity array

function preload() {
    var imageURL = "https://i.imgur.com/pvmAYGW.jpg"
    selfportrait = loadImage(imageURL); // preloads the image
}

function setup() {
  createCanvas(480, 480);
  noStroke();

  //for loop for assigning random values for x,y,dx,dy
  for (var i=0; i<150; i++) {
        x.push(random(width));
        y.push(random(height));
        dx.push(random(-10,10));
        dy.push(random(-10,10));
  }
}

function draw() {
  //image(selfportrait,-250,-50);

  //for loop for 
  for (var j=0; j<x.length; j++) {
    //pixel colors from image is stored into x and y array
    var color = selfportrait.get((x[j]+250), y[j]+50);
        //canvas is filled with image color
        fill(color);
        //ellipse fills the canvas + random movements with dx,dy
        ellipse(x[j],y[j],10,10);
        x[j]+=dx[j];
        y[j]+=dy[j];
    }

    //xpos and ypos is determined by mousex and mousey
    var xpos = floor(mouseX);
    var ypos = floor(mouseY);
    //color is assigned to mousex and mousey
    var color = selfportrait.get((xpos+250), ypos+50);

    fill(color,25);
    noStroke();
    //according to mouse position canvas is colored
    rect(xpos,ypos,10,10);

}

 

1                               2                              3

  1. A loop of 150 ellipses initially color the canvas
  2. MouseX and MouseY function is used to fill in the blanks
  3. Final portrait is done

For this project, I was able to reuse functions and skills that I previously learned from this class. I set up a series of position and velocity arrays to form a loop of circles that randomly moved across the canvas with the image colors. After most of the image was colored, you can also custom color the blanks with the mousex and mousey function. I thought this project was really interesting, and I am pretty satisfied with the result.

kyungak-lookingoutwards-09

(Walt Disney Animation Studios, 2012, Paperman)

Link to the original post: https://courses.ideate.cmu.edu/15-104/f2017/2017/09/28/looking-outwards-05-3d-graphics/

As a student that personally admires all of the Disney films, I was very thrilled to come across Sarah’s post about Disney’s 3D graphics in the short film Paperman. Although this film is black and white, the intricate movements and details put into the figures, objects, and backgrounds make the scene live as if they are colored and real. I very much agree with Sarah’s comment about Disney sticking to the older practice of creating animation. The combination of artistic skills enabled the production of such a solid piece of work. Especially after knowing how intense and time consuming it is to draw each frame and convert it to 3D graphic images, I have deep respect to the animators at Walt Disney animation studios.

kyungak-lookingoutwards-08

(Jake Barton, “Like Falling In Love”, 2012)

Link to Barton’s website: https://localprojects.net/

Jake Barton is an American designer who is also the founder of the company “Local Projects.” To introduce his educational background, Barton got a Bachelor in Science of Speech at Northwestern University and studied at New York University for his M.P.S. Interactive Telecommunications. He then recruited a media design team to launch his company.

Local projects is a media and physical design company that invents and build upon new media form to help customers connect with algorithms and up to date technology. Barton mainly focuses on making products that explores the relationship between technology and emotions that are most of the times derived from customers.

One of Barton’s most admirable work  is the media of the 9/11 museum in New York City. This piece was created through a custom algorithm that reproduced clips of video, text and audio of that tragic day. Although the contents could have been sensitive, I felt that Barton’s approach to this tragedy was smart. His approach was indirect and subtle enough to not upset those who were victimized, but also strong enough to get the message across. His balance and approach was ideal.

Barton’s usage of pictures and examples of his algorithmic products makes the talk more engaging. It definitely catches attention of the viewers and also makes his words more understandable. Also the interaction with the viewers by asking questions was smart.