Final Project_Beauty and the Beast

Professor: Marcela

Final Project: Beauty and the Beast

Team members: Esme Wang & Amber Wang

Material: cardboard, froth, wood board, cables, an accelerometer, conductive tap, beast claw glove

I. Motivation & Inspiration

What motivated me to make the game, Beauty and the Beat, was to give people a health way to have fun. Generally, people who enjoy playing video games would end up with chronic diseases. Because they would always stare at the computer screen and sit in front of the computer for a long time. It seems that they would have to sacrifice health when having fun in the electronic world. Therefore, we want to make a video game that can hep people to balance health and having fun.

Dancing machine is one of the most important inspirations for our final project. As we all know, players would dance in a certain way on the dancing machine according to the movement showed in the game. The players would not only be entertained but also stretch the body by fully involved in the game, which protecting themselves from any chronic diseases.

屏幕快照 2017-05-16 下午9.42.27

II. Idea

 

Inspired by the dancing machine, we decided to make a video game, called Beauty and the Beast. The player is the beast and would try to prevent the monsters from approaching the castle to protect the princess. The player can control the movement of the beast by stepping on corresponding footboard and can kill the monsters by shaking hands. But the monsters can not attack the beast. In a certain amount of time, if the monsters enter the castle and catch the princess, the player would lose the game. Otherwise, the player would be the winner and the beast would have a happy ending with the princess. According to the idea, we drew three pieces of prototypes.

屏幕快照 2017-04-26 下午11.06.46

屏幕快照 2017-04-26 下午11.19.18

屏幕快照 2017-04-26 下午11.06.40

During the presentation of final project proposal, Zersh noticed a problem in the game. Since all paths lead to the castle, the player would eventually wait right near the castle. The player then can kill all the monsters without moving at all. Thanks to Zersh, we could improve our idea in time. We distributed the path to different directions instead of accumulating the ends of the paths to one point. And the beast can only stay outside of the castle. In this way, the beast has to run through differences to kill the monsters.

In addition, Amber and I had a disagreement on the shape of the path. Should we make curved, slant or straight path? We asked people what kind of direction button they want to push if they would go along a slant or curved path. Most of them would choose to push buttons like ↖️↗️↘️↙️. That is to say, we would have to make eight direction buttons for the game, which would be a much heavier work. Comparing with curved or slant path, straight path would be a better indicator to directions. So we decided to use straightforward paths.

One of the most challenging work in the project was how to make the game interface clear, so that players can distinguish the beast, the castle, the beauty and the monsters. At first, we wanted to use characters in the Disney cartoon “Beauty and the Beast”. However, if we shrink the size of the picture, nobody can tell that it is the beast. Considering about limited time, we gave up the idea of drawing the character. Fortunately, we found some rng makers on Pinterest, like pieces of grass, house, princess. We would design our own map with various rng makers.

III. Processing

In order to do the project efficiently, Amber would take the work of Arduino and Photoshop, I would do Processing coding and we would make the environmental setting together.

The foremost logic in my code was that both the beast and the monsters can only  move along the paths. They cannot enter the grass area that are not defined as “path”. To help me start with the project, Professor Rudi gave me some examples about collision. Based on the examples, I firstly divided the grass area into 15 rectangles. I calculated the distance between the beast (sketched as an ellipse at first) and rectangles. As one of the example showed, the distance could be expressed in a general way with radius of ellipse, width and height of rectangles. This distance formula is suitable for the ellipse and either one of the rectangles. And the logic is quite clear. When the distance between the ellipse and the rectangle is larger than d, half width (height) of the rectangle plus radius, the ellipse can move. Otherwise, the ellipse cannot move. However, when the distance is smaller than d, the ellipse would stop and can never move again. Ideally, the ellipse can return back to its last position once the distance is smaller than d, so that it can move again. But it is hard to know where its last position was, thus it is impossible to return it back simply by decreasing y or x of the ellipse. Since Jerry’s midterm project maze is similar with ours, I went to him for help. He suggested me using the idea “future position”. I was supposed to set two pairs of variables for the position of the ellipse, x1, y1, and x2, y2. I used x1 and y1 (current position) to initialize the position of the ellipse, while I used x2 and y2 (future position) in the move function and the checking collision function. Once there is no collision (distance > d), x1 = x2 and y1 = y2. The current position equals the future position, and ellipse would move to a new position. Otherwise, they are not equal so the current ellipse would be stopped by the collision function. Personally, I really appreciate this way to solve the problem.

Unlike the beast, the code of the monsters is an arraylist. I used similar collision code in the arraylist. It did not work because the movement of the beast would influence that of the monsters. I also used to certain changing movement code. For example, when y < 500, speed of x would increase. One particular changing movement condition can only work for monsters on one of the path. Because the monsters would come from different directions, it is necessary to get a general principle applied for all the monsters. Thanks to Professor Moon, I got to know a more efficient way of collision coding — color collision. I set a variable, color c, as the color the ellipse would touch. Under the map we designed, I put another map with only three color, black (as the grass area), grey (as the path area), and green (as the castle area). So this is the map the player would see.

屏幕快照 2017-05-16 下午9.25.09

And this is the map for color coding covered by the real map.

mapWall3副本

Once the ellipses sense black, they would change their movement. Professor Moon also suggested me to make the bumping effect. That is to say, the ellipses would randomly go left or right (when they are moving vertically and sense black color), and go up or down (when they are moving horizontally and sense black color). The unpredictable movement of monsters absolutely made the game more interesting and gives the player more challenges.

Done with coding the movement of the beast and the monsters, I began to code the attack. When pushing button “h”, the beast would kill the monsters. Under the condition of pushing button “h”, I set the speed of x and speed of y as 0 and moved them to other places. But when I moved them to grass area, their speed would change and began to move. With the help of Jiwon, I used boolean to remove the monsters being attacked. In the situation of attacking, the “dead boolean” would be “true” and monsters would be removed. And the “dead boolean” would be part of the color collision.

In addition, I would had to add the gameover part. When the left time is larger than 0 and the monsters sense green color, the player would lose the game. When in a certain amount of time the monsters does not sense the green color, the player would win the game. However, when the game is over, I cannot restart the game without running the Processing again. With the help of Kevin, I found that if I used noloop() as the midterm project,  the game was stopped entirely so I had to run the Processing again. Actually, I was supposed to create a game over boolean. For the two conditions of game over listed above, game over is true. Otherwise, it is false. To restart the game, the player has to press the space bar. At the same time, new list of balls (monster) would be created and the time would be set back to 45 seconds.

When the game is over, the game needs an ending part. I insert a image with bat monsters to indicate losing and another image with kisses of the beast and the princess to indicate winning. Nevertheless, when the image showed up, there were monsters and beasts still staying on the image. I moved the class of the beast before the class of the monsters, so that the ending image would cover the beast. To cover the monsters, I tried to used boolean function that only if the image does not show up, monster display function would run. The boolean function failed due to there is no b.display outside of the monster class. Marcela helped me to set up an “if” function that only if the gameover boolean is true and display boolean is true (particularly for the losing condition), the image would show up. The “if” statement would run at the end of the “draw” function, so that it can cover functions above.

After I almost done with the Processing code, I combined my part with Amber’s code of setting images. Since the image was a rectangle, I had to change part of the collision code.

IV. Environmental Setting

To fit with the theme of the game, we planned to design an environmental setting with the style of beast. There are four pieces of footboard, representing four directions “Up” “Down” “Left” “Right”. We laser cut the wood board to engrave beast footprints on it. At first we set 35cm of width and 30cm of height. However, if we laser cut according to this size, the wood board would be wasted a lot. So we changed the size to 30cm of width and 30cm of height. We tried stepping on the board but it seems that people would hardly know whether they put enough pressure on the board to make the beast move. Therefore, we decided to construct footboard with evaluation change. Given the suggestion from Marcela, we constructed a footboard with three layers. A piece of cardboard was at the bottom, a piece of froth was the intermedia, and a piece of wood board engraved with footprints was at the top. We pasted conductive tap on half side of the cardboard and on half side of the wood board without engraved footprint. We also made a hole on the half side of the froth so that the conductive taps can touch each other when someone stepped on the board. Cables were soldered and attached to the conductive taps. In this way, the footboard was exactly like a switch. When someone stepped on it, the switch was turned on. When there was no pressure on the board, the forth would support the wood board to leave some space between the wood board and the cardboard and the switch would be turned off. Also, since there was a change of evaluation when someone stepped on it, the player could better control the switch as he wants.

WechatIMG456

WechatIMG457

WechatIMG451

After finishing the footboard, we asked Professor Rudi to test the game. Professor Rudi gave us the feedback that the switch attached to the footboard was not sensitive enough. He also suggested us to make a bigger hole on the forth and make a large piece of conductive tap attached to the boards. As a result, there was a larger region that the cardboard and the wood board could touch each other, and the switch would be more sensitive.

In the game, the beast would kill the monster with his claws. For the environmental setting, we bought a claw glove that the player can wear as a weapon. Amber sewed an accelerometer in the glove. When the player shakes his hand, the sensor would work and the beast would attack the monsters. The brown glove fits well with the color of the beast in the game.

IMG_5833

V. Reflection

Actually, I felt upset at the beginning and I was afraid that I could not finish this huge project with limited time. Fortunately, I could work with Amber and we did make an interesting game. I also learned a lot through this process. When doing the Processing part, I not only reviewed the codes I learned before, but also got to know new knowledge, like collision codes. Sometimes, the codes I used for my midterm project did not work as expected in my final project. By adapting the codes to a new project, I managed to enhance my comprehension about Processing and to code in a more advanced way.

Furthermore, what I felt satisfied about was the fancy game interface and corresponding environmental setting. Thanks to Amber’s qualified photoshop skills, the interface of the game is clear as well as funny. Compared with our midterm project, we now have an environmental setting that can better fit the game. The player would clearly realize the connection between the footboard and the claw glove with the game itself. Also, I am quite satisfied about the full interaction in our game. As you can see, the whole body of the player would get involved in the game. Beauty and the Beast did achieve a higher level of interaction.

If I have more time, I would improve my project in two respects. Firstly, I would try to organize the cables. Since there are multiple cables attached to the footboard,  all the cables twines around each other. The player would even pull the cables when he moves from footboard to footboard. I might tie the cables together and organize them clearly. In addition, I would try to stabilize four pieces of footboard with a carpet. During the game, the player would step on the footboard and even move the footboard from original places. And the player can hardly realize where the footboard is, when he focuses on the game interface on the computer. Marcela also suggested us to use the emery paper. But we have little time to buy it and set it up. Before the IMA Show, Amber and I used double faced adhesive tape to stablize the footboards.

I am really proud of our project and of my partner. I really appreciate the help and support from professors, fellows and my friends. During the IMA Show, I achived a huge sense of accomplishment when people were enjoying our video game. Here is a video about how our project works.

PImage map;
PImage mapWall3;
PImage m1, m2, m3, m4;
PImage c1, c2, c3, c4;
PImage monster;
PImage g;
PImage win;
PImage lose;
Beastprince p;
import processing.serial.*;
String myString = null;
int NUM_OF_VALUES = 5; 
Serial myPort;
int[] potValues; 
import processing.sound.*;
SoundFile soundfile;
float timeLeft;
float timeTotal;
int lastTime = 0;
int delta = 0;
ArrayList<Ball> balls = new ArrayList<Ball>();
float x1; //
float y1;//Beast
float x2;
float y2;
//future position
float radius = 5;
float rectx1 = 0;
float recty1 = 0;
float rectw1 = 150;
float recth1 = 300;

float rectx2 = 0;
float recty2 = 280;
float rectw2 = 40;
float recth2 = 520;

float rectx3 = 0;
float recty3 = 0;
float rectw3 = 800;
float recth3 = 50;

float rectx4 = 720;
float recty4 = 0;
float rectw4 = 100;
float recth4 = 600;

float rectx5 = 300;
float recty5 = 0;
float rectw5 = 200;
float recth5 = 200;

float rectx6 = 200;
float recty6 = 100;
float rectw6 = 150;
float recth6 = 300;

float rectx7 = 80;
float recty7 = 350;
float rectw7 = 70;
float recth7 = 400;

float rectx8 = 150;
float recty8 = 450;
float rectw8 = 120;
float recth8 = 300;

float rectx9 = 320;
float recty9 = 450;
float rectw9 = 120;
float recth9 = 300;

float rectx10 = 400;
float recty10 = 300;
float rectw10 = 150;
float recth10 = 90;

float rectx11 = 480;
float recty11 = 400;
float rectw11 = 70;
float recth11 = 360;

float rectx12 = 600;
float recty12 = 400;
float rectw12 = 75;
float recth12 = 360;

float rectx13 = 600;
float recty13 = 100;
float rectw13 = 75;
float recth13 = 250;

float rectx14 = 400;
float recty14 = 100;
float rectw14 = 160;
float recth14 = 150;

float rectx15 = 680;
float recty15 = 650;
float rectw15 = 160;
float recth15 = 150;

int frameC = 0;

boolean gameover = false;
boolean displayLose = false;

void setup() {
   setupSerial();
  size(800, 700);
  timeTotal = timeLeft = 45;
  mapWall3 = loadImage("mapWall3.png");
  map = loadImage("map.png");
  m1 = loadImage("move1.png");
  m2 = loadImage("move2.png");
  m3 = loadImage("move3.png");
  m4 = loadImage("move4.png");
  c1 = loadImage("claw1.png");
  c2 = loadImage("claw2.png");
  c3 = loadImage("claw3.png");
  c4 = loadImage("claw4.png");
  g = loadImage("prince1.png");
  monster = loadImage("bad.png");
  win = loadImage("win.png");
  lose = loadImage("lose.jpg");
  p = new Beastprince();
  soundfile = new SoundFile(this, "Martin Garrix - Oops.mp3");
  soundfile.loop();
}

void draw() {
  background(0);
  updateSerial();
  rect(rectx1, recty1, rectw1, recth1);
  rect(rectx2, recty2, rectw2, recth2);
  rect(rectx3, recty3, rectw3, recth3);
  rect(rectx4, recty4, rectw4, recth4);
  rect(rectx5, recty5, rectw5, recth5);
  rect(rectx6, recty6, rectw6, recth6);
  rect(rectx7, recty7, rectw7, recth7);
  rect(rectx8, recty8, rectw8, recth8);
  rect(rectx9, recty9, rectw9, recth9);
  rect(rectx10, recty10, rectw10, recth10);
  rect(rectx11, recty11, rectw11, recth11);
  rect(rectx12, recty12, rectw12, recth12);
  rect(rectx13, recty13, rectw13, recth13);
  rect(rectx14, recty14, rectw14, recth14);
  rect(rectx15, recty15, rectw15, recth15);
  image(mapWall3, 0, 0, 800, 800);
  
  image(map, 0, 0, 800, 800);
  //image(mapWall3, 0, 0, 800, 800);
  image(g, 350, 135, 55, 55);
  //time
  fill(0);
  textSize(40);      
  delta = millis() - lastTime; // time difference from last to prev frame
  timeLeft = timeLeft - (delta / 1000.0); // milli to seconds
  lastTime = millis();
  if (timeLeft < 0) timeLeft = 0;
  text(round(timeLeft), 50, 50);
  //println("Time Left: ", timeLeft);

  // rect border
  /*
  rect(rectx1, recty1, rectw1, recth1);
   rect(rectx2, recty2, rectw2, recth2);
   rect(rectx3, recty3, rectw3, recth3);
   rect(rectx4, recty4, rectw4, recth4);
   rect(rectx5, recty5, rectw5, recth5);
   rect(rectx6, recty6, rectw6, recth6);
   rect(rectx7, recty7, rectw7, recth7);
   rect(rectx8, recty8, rectw8, recth8);
   rect(rectx9, recty9, rectw9, recth9);
   rect(rectx10, recty10, rectw10, recth10);
   rect(rectx11, recty11, rectw11, recth11);
   rect(rectx12, recty12, rectw12, recth12);
   rect(rectx13, recty13, rectw13, recth13);
   rect(rectx14, recty14, rectw14, recth14);
   rect(rectx15, recty15, rectw15, recth15);
   */

  boolean collision1Detected = isCollidingCircle1Rectangle(x1, y1, radius, rectx1, recty1, rectw1, recth1);
  boolean collision2Detected = isCollidingCircle2Rectangle(x1, y1, radius, rectx2, recty2, rectw2, recth2);
  boolean collision3Detected = isCollidingCircle3Rectangle(x1, y1, radius, rectx3, recty3, rectw3, recth3);
  boolean collision4Detected = isCollidingCircle4Rectangle(x1, y1, radius, rectx4, recty4, rectw4, recth4);
  boolean collision5Detected = isCollidingCircle5Rectangle(x1, y1, radius, rectx5, recty5, rectw5, recth5);
  boolean collision6Detected = isCollidingCircle6Rectangle(x1, y1, radius, rectx6, recty6, rectw6, recth6);
  boolean collision7Detected = isCollidingCircle7Rectangle(x1, y1, radius, rectx7, recty7, rectw7, recth7);
  boolean collision8Detected = isCollidingCircle8Rectangle(x1, y1, radius, rectx8, recty8, rectw8, recth8);
  boolean collision9Detected = isCollidingCircle9Rectangle(x1, y1, radius, rectx9, recty9, rectw9, recth9);
  boolean collision10Detected = isCollidingCircle10Rectangle(x1, y1, radius, rectx10, recty10, rectw10, recth10);
  boolean collision11Detected = isCollidingCircle11Rectangle(x1, y1, radius, rectx11, recty11, rectw11, recth11);
  boolean collision12Detected = isCollidingCircle12Rectangle(x1, y1, radius, rectx12, recty12, rectw12, recth12);
  boolean collision13Detected = isCollidingCircle13Rectangle(x1, y1, radius, rectx13, recty13, rectw13, recth13);
  boolean collision14Detected = isCollidingCircle14Rectangle(x1, y1, radius, rectx14, recty14, rectw14, recth14);
  boolean collision15Detected = isCollidingCircle15Rectangle(x1, y1, radius, rectx15, recty15, rectw15, recth15);

  p.move();
  p.display();
  
  for (int i=0; i<balls.size(); i++) {
    Ball b = balls.get(i); 
    //boolean displayLose = b.displayLose();
    
    if (!gameover) b.move();
    if (b.checkGameOver()) gameover = true;
    boolean dead = b.checkBoundary();
    
    if (dead) {
      balls.remove(i);
    }
      b.display();

  }


  //p.attack();
  if(frameC % 10 == 0){
  int randomValue = int(random(0, 5));
  if (randomValue == 0) {
    balls.add( new Ball(60, 700));
  } else if (randomValue == 1) {
    balls.add( new Ball(300, 700));
  } else if (randomValue == 2) {
    balls.add( new Ball(460, 700));
  } else if (randomValue == 3) {
    balls.add( new Ball(580, 700));
  }
  if (randomValue == 4) {
  balls.add( new Ball(793, 622));
}
  }
frameC++;
println(frameC);

    if (gameover == true && displayLose==true){
      image(lose, 0, 0, 800, 700); 
    }

}

void keyPressed() {
  if (key == ' ' && gameover) {
    balls = new ArrayList<Ball>();
    gameover = false;
    timeLeft = timeTotal;
  }
}

void mouseClicked() {
  println(mouseX + ", " + mouseY);
}
  
  void setupSerial() {
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[2], 9600);
  myPort.clear();
  // Throw out the first reading,
  // in case we started reading in the middle of a string from the sender.
  myString = myPort.readStringUntil( 10 );  // 10 = 'n'  Linefeed in ASCII
  myString = null;

  potValues = new int[NUM_OF_VALUES];
}

void updateSerial() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil( 10 ); // 10 = 'n'  Linefeed in ASCII
    if (myString != null) {
      String[] serialInArray = split(trim(myString), ",");
      if (serialInArray.length == NUM_OF_VALUES) {
        for (int i=0; i<serialInArray.length; i++) {
          potValues[i] = int(serialInArray[i]);    
        }        
      }
    }
  }
}

class Beastprince {
  PImage mo;
  float x1, y1;

  Beastprince() {
    x1 = 372;
    y1 = 380;
    mo = m1;
  }
  void display() {
    pushStyle();
    imageMode(CENTER);
    image(mo, x1, y1-20, 60, 60);
    popStyle();
  }
  void move() {
    float x2, y2;
    x2 = x1;
    y2 = y1;
    //if (keyPressed) {

    if (potValues[3] == 1) {
      if (x2 > 0) {
        mo = m2;
        x2 = x2 - 10;
      }
    }

    if (potValues[2] == 1) {
      if (y2 < 700) {
        mo = m1; 
        y2 = y2 + 10;
      }
    }

    if (potValues[0] == 1) {
      if (x2 < 800) {
        mo = m3;
        x2=x2+10;
      }
    }

    if (potValues[1] == 1) {
      if (y2 > 0) {
        mo = m4;
        y2=y2-10;
      }
    }
    //}
    if (!isCollidingCircle1Rectangle(x2, y2, radius, rectx1, recty1, rectw1, recth1) && 
      !isCollidingCircle2Rectangle(x2, y2, radius, rectx2, recty2, rectw2, recth2) && 
      !isCollidingCircle3Rectangle(x2, y2, radius, rectx3, recty3, rectw3, recth3) &&
      !isCollidingCircle1Rectangle(x2, y2, radius, rectx4, recty4, rectw4, recth4) &&
      !isCollidingCircle5Rectangle(x2, y2, radius, rectx5, recty5, rectw5, recth5) &&
      !isCollidingCircle6Rectangle(x2, y2, radius, rectx6, recty6, rectw6, recth6) &&
      !isCollidingCircle7Rectangle(x2, y2, radius, rectx7, recty7, rectw7, recth7) &&
      !isCollidingCircle8Rectangle(x2, y2, radius, rectx8, recty8, rectw8, recth8) &&
      !isCollidingCircle9Rectangle(x2, y2, radius, rectx9, recty9, rectw9, recth9) &&
      !isCollidingCircle10Rectangle(x2, y2, radius, rectx10, recty10, rectw10, recth10) &&
      !isCollidingCircle11Rectangle(x2, y2, radius, rectx11, recty11, rectw11, recth11) &&
      !isCollidingCircle12Rectangle(x2, y2, radius, rectx12, recty12, rectw12, recth12) &&
      !isCollidingCircle13Rectangle(x2, y2, radius, rectx13, recty13, rectw13, recth13) &&
      !isCollidingCircle14Rectangle(x2, y2, radius, rectx14, recty14, rectw14, recth14) &&
      !isCollidingCircle15Rectangle(x2, y2, radius, rectx15, recty15, rectw15, recth15)) {
      x1 = x2;
      y1 = y2;
    }
    if (potValues[4] == 1) {

      if (mo == m1) {
        image(c1, x2-30, y2, 60, 60);
      }
      if (mo == m2) {
        image(c2, x2-60, y2-30, 60, 60);
      }
      if (mo == m3) {
        image(c3, x2, y2-30, 60, 60);
      }
      if (mo == m4) {
        image(c4, x2-30, y2-80, 60, 60);
      }
    }
  }
}

class Ball {
  float x, y, size;
  //color clr;
  float xspeed, yspeed;
  PImage m;


  Ball (float tempX, float tempY) {

    x = tempX;
    y = tempY;
    xspeed = 0;
    yspeed = -2;
    m = monster;
  }
  void display() {
    //fill(clr);
    pushStyle();
    imageMode(CENTER);
    image(monster, x, y, 30, 30);
    popStyle();
  }


  void move() {
    x += xspeed;
    y += yspeed;
  }
  boolean checkBoundary() {
    //color c1 = color (0,0,0);
    color c = mapWall3.get(int(x), int(y));   
    //println(red(c) + " " + green(c)+ " " + blue(c));
    if ( blue(c) < 100 && red(c) < 200) { //black
      // it's going up or down
      if (xspeed == 0) {
        y = y - yspeed*5;
        yspeed = 0;
        if (random(1) < 0.5) {
          xspeed = 2;
        } else {
          xspeed = -2;
        }
      }
   
      else if (yspeed == 0) {
        x = x - xspeed*5;
        xspeed = 0;
        if (random(1) < 0.5) {
          yspeed = 2;
        } else {
          yspeed = -2;
        }
      }
    }
  
    if ( blue(c) < 100 && red(c) > 200 ) {  //&& goingThroughAWall == false
      if (xspeed == 0) { 
        //println(y);
        y = y - yspeed*5;
        yspeed = 0;
        int randomValue = int(random(0, 2));
        if (randomValue == 0) {
          xspeed = -2;
        } else if (randomValue == 1) {
          xspeed = 0;
          yspeed = -2;
        }
      }
    }
    if (dist(x, y, p.x1, p.y1) < 60) {

      if (potValues[4] == 1) {
        //println ("attack");
        xspeed = 0;
        yspeed = 0;
        //x = 0;
        //y = 0;
        return true;
      }
    }

    return false;
  }


  boolean checkGameOver() {

    color c = mapWall3.get(int(x), int(y));
    //println(red(c) + " " + green(c)+ " " + blue(c));
    if (blue(c) < 100 && green (c) > 220) {
      displayLose = true;
      return true;
    }


    if (timeLeft <= 0) {

      image(win, 0, 0, 800, 700);
      return true;
    } else {
      return false;
    }
  }
}

//boolean 1
boolean isCollidingCircle1Rectangle(
  float x1, 
  float y1, 
  float radius, 
  float rectx1, 
  float recty1, 
  float rectw1, 
  float recth1)
{

  float distancex1 = abs(x1 - rectx1 - rectw1/2);
  float distancey1 = abs(y1 - recty1 - recth1/2);

  if (distancex1 > (rectw1/2+radius)) { 
    return false;
  }
  if (distancey1 > (recth1/2+radius)) { 
    return false;
  }

  if (distancex1 <= (rectw1/2+radius)) { 
    return true;
  } 
  if (distancey1 <= (recth1/2+radius)) { 
    return true;
  }

  float cornerDistance_sq = pow(distancex1-rectw1/2, 2) +
    pow(distancey1-recth1/2, 2);

  return (cornerDistance_sq <= pow(radius, 2));
}

//boolean 2
boolean isCollidingCircle2Rectangle(
      float x1, 
      float y1, 
      float radius,
      float rectx2,
      float recty2,
      float rectw2,
      float recth2)
      {

    float distancex2 = abs(x1 - rectx2 - rectw2/2);
    float distancey2 = abs(y1 - recty2 - recth2/2);

    if (distancex2 > (rectw2/2 + radius)) { return false; }
    if (distancey2 > (recth2/2 + radius)) { return false; }

    if (distancex2 <= (rectw2/2+ radius)) { return true; } 
    if (distancey2 <= (recth2/2+ radius)) { return true; }

    float cornerDistance_sq = pow(distancex2 - rectw2/2, 2) +
                              pow(distancey2 - recth2/2, 2);

    return (cornerDistance_sq <= pow(radius,2));
}
     
//boolean 3
boolean isCollidingCircle3Rectangle(
      float x1, 
      float y1, 
      float radius,
      float rectx3,
      float recty3,
      float rectw3,
      float recth3)
      {

    float distancex3 = abs(x1 - rectx3 - rectw3/2);
    float distancey3 = abs(y1 - recty3 - recth3/2);

    if (distancex3 > (rectw3/2 + radius)) { return false; }
    if (distancey3 > (recth3/2 + radius)) { return false; }

    if (distancex3 <= (rectw3/2+ radius)) { return true; } 
    if (distancey3 <= (recth3/2+ radius)) { return true; }

    float cornerDistance_sq = pow(distancex3 - rectw3/2, 2) +
                              pow(distancey3 - recth3/2, 2);

    return (cornerDistance_sq <= pow(radius,2));
}

//boolean 4
boolean isCollidingCircle4Rectangle(
      float x1, 
      float y1, 
      float radius,
      float rectx4,
      float recty4,
      float rectw4,
      float recth4)
      {

    float distancex4 = abs(x1 - rectx4 - rectw4/2);
    float distancey4 = abs(y1 - recty4 - recth4/2);

    if (distancex4 > (rectw4/2 + radius)) { return false; }
    if (distancey4 > (recth4/2 + radius)) { return false; }

    if (distancex4 <= (rectw4/2+ radius)) { return true; } 
    if (distancey4 <= (recth4/2+ radius)) { return true; }

    float cornerDistance_sq = pow(distancex4 - rectw4/ 2, 2) +
                              pow(distancey4 - recth4/2, 2);

    return (cornerDistance_sq <= pow(radius,2));
}

//boolean 5
boolean isCollidingCircle5Rectangle(
  float x1, 
  float y1, 
  float radius, 
  float rectx5, 
  float recty5, 
  float rectw5, 
  float recth5)
{

  float distancex5 = abs(x1 - rectx5 - rectw5/2);
  float distancey5 = abs(y1 - recty5 - recth5/2);

  if (distancex5 > (rectw5/2 + radius)) { 
    return false;
  }
  if (distancey5 > (recth5/2 + radius)) { 
    return false;
  }

  if (distancex5 <= (rectw5/2+ radius)) { 
    return true;
  } 
  if (distancey5 <= (recth5/2+ radius)) { 
    return true;
  }

  float cornerDistance_sq = pow(distancex5 - rectw5/2, 2) +
    pow(distancey5 - recth5/2, 2);

  return (cornerDistance_sq <= pow(radius, 2));
}

//boolean 6
boolean isCollidingCircle6Rectangle(
  float x1, 
  float y1, 
  float radius, 
  float rectx6, 
  float recty6, 
  float rectw6, 
  float recth6)
{

  float distancex6 = abs(x1 - rectx6 - rectw6/2);
  float distancey6 = abs(y1 - recty6 - recth6/2);

  if (distancex6 > (rectw6/2 + radius)) { 
    return false;
  }
  if (distancey6 > (recth6/2 + radius)) { 
    return false;
  }

  if (distancex6 <= (rectw6/2+ radius)) { 
    return true;
  } 
  if (distancey6 <= (recth6/2+ radius)) { 
    println("bump");
    return true;
  }

  float cornerDistance_sq = pow(distancex6 - rectw6/2, 2) +
    pow(distancey6 - recth6/2, 2);

  return (cornerDistance_sq <= pow(radius, 2));
}

//boolean 7
boolean isCollidingCircle7Rectangle(
      float x1, 
      float y1, 
      float radius,
      float rectx7,
      float recty7,
      float rectw7,
      float recth7)
      {

    float distancex7 = abs(x1 - rectx7 - rectw7/2);
    float distancey7 = abs(y1 - recty7 - recth7/2);

    if (distancex7 > (rectw7/2 + radius)) { return false; }
    if (distancey7 > (recth7/2 + radius)) { return false; }

    if (distancex7 <= (rectw7/2+ radius)) { return true; } 
    if (distancey7 <= (recth7/2+ radius)) { return true; }

    float cornerDistance_sq = pow(distancex7 - rectw7/ 2, 2) +
                              pow(distancey7 - recth7/2, 2);

    return (cornerDistance_sq <= pow(radius,2));
}

//boolean 8
boolean isCollidingCircle8Rectangle(
  float x1, 
  float y1, 
  float radius, 
  float rectx8, 
  float recty8, 
  float rectw8, 
  float recth8)
{

  float distancex8 = abs(x1 - rectx8 - rectw8/2);
  float distancey8 = abs(y1 - recty8 - recth8/2);

  if (distancex8 > (rectw8/2 + radius)) { 
    return false;
  }
  if (distancey8 > (recth8/2 + radius)) { 
    return false;
  }

  if (distancex8 <= (rectw8/2+ radius)) { 
    return true;
  } 
  if (distancey8 <= (recth8/2+ radius)) { 
    return true;
  }

  float cornerDistance_sq = pow(distancex8 - rectw8/ 2, 2) +
    pow(distancey8 - recth8/2, 2);

  return (cornerDistance_sq <= pow(radius, 2));
}

//boolean 9
boolean isCollidingCircle9Rectangle(
  float x1, 
  float y1, 
  float radius, 
  float rectx9, 
  float recty9, 
  float rectw9, 
  float recth9)
{

  float distancex9 = abs(x1 - rectx9 - rectw9/2);
  float distancey9 = abs(y1 - recty9 - recth9/2);

  if (distancex9 > (rectw8/2 + radius)) { 
    return false;
  }
  if (distancey9 > (recth8/2 + radius)) { 
    return false;
  }

  if (distancex9 <= (rectw9/2+ radius)) { 
    return true;
  } 
  if (distancey9 <= (recth9/2+ radius)) { 
    return true;
  }

  float cornerDistance_sq = pow(distancex9 - rectw9/ 2, 2) +
    pow(distancey9 - recth9/2, 2);

  return (cornerDistance_sq <= pow(radius, 2));
}

//boolean 10
boolean isCollidingCircle10Rectangle(
  float x1, 
  float y1, 
  float radius, 
  float rectx10, 
  float recty10, 
  float rectw10, 
  float recth10)
{

  float distancex10 = abs(x1 - rectx10 - rectw10/2);
  float distancey10 = abs(y1 - recty10 - recth10/2);

  if (distancex10 > (rectw10/2 + radius)) { 
    return false;
  }
  if (distancey10> (recth10/2 + radius)) { 
    return false;
  }

  if (distancex10 <= (rectw10/2+ radius)) { 
    return true;
  } 
  if (distancey10 <= (recth10/2+ radius)) { 
    return true;
  }

  float cornerDistance_sq = pow(distancex10 - rectw10/ 2, 2) +
    pow(distancey10 - recth10/2, 2);

  return (cornerDistance_sq <= pow(radius, 2));
}

//boolean 11
boolean isCollidingCircle11Rectangle(
  float x1, 
  float y1, 
  float radius, 
  float rectx11, 
  float recty11, 
  float rectw11, 
  float recth11)
{

  float distancex11 = abs(x1 - rectx11 - rectw11/2);
  float distancey11 = abs(y1 - recty11 - recth11/2);

  if (distancex11 > (rectw11/2 + radius)) { 
    return false;
  }
  if (distancey11> (recth11/2 + radius)) { 
    return false;
  }

  if (distancex11 <= (rectw11/2+ radius)) { 
    return true;
  } 
  if (distancey11 <= (recth11/2+ radius)) { 
    return true;
  }

  float cornerDistance_sq = pow(distancex11 - rectw11/ 2, 2) +
    pow(distancey11 - recth11/2, 2);

  return (cornerDistance_sq <= pow(radius, 2));
}

//boolean 12
boolean isCollidingCircle12Rectangle(
  float x1, 
  float y1, 
  float radius, 
  float rectx12, 
  float recty12, 
  float rectw12, 
  float recth12)
{

  float distancex12 = abs(x1 - rectx12 - rectw12/2);
  float distancey12 = abs(y1 - recty12 - recth12/2);

  if (distancex12 > (rectw12/2 + radius)) { 
    return false;
  }
  if (distancey12> (recth12/2 + radius)) { 
    return false;
  }

  if (distancex12 <= (rectw12/2+ radius)) { 
    return true;
  } 
  if (distancey12 <= (recth12/2+ radius)) { 
    return true;
  }

  float cornerDistance_sq = pow(distancex12 - rectw12/ 2, 2) +
    pow(distancey12 - recth12/2, 2);

  return (cornerDistance_sq <= pow(radius, 2));
}

//boolean 13
boolean isCollidingCircle13Rectangle(
  float x1, 
  float y1, 
  float radius, 
  float rectx13, 
  float recty13, 
  float rectw13, 
  float recth13)
{

  float distancex13 = abs(x1 - rectx13 - rectw13/2);
  float distancey13 = abs(y1 - recty13 - recth13/2);

  if (distancex13 > (rectw13/2 + radius)) { 
    return false;
  }
  if (distancey13> (recth13/2 + radius)) { 
    return false;
  }

  if (distancex13 <= (rectw13/2+ radius)) { 
    return true;
  } 
  if (distancey13 <= (recth13/2+ radius)) { 
    return true;
  }

  float cornerDistance_sq = pow(distancex13 - rectw13/ 2, 2) +
    pow(distancey13 - recth13/2, 2);

  return (cornerDistance_sq <= pow(radius, 2));
}

//boolean 14
boolean isCollidingCircle14Rectangle(
  float x1, 
  float y1, 
  float radius, 
  float rectx14, 
  float recty14, 
  float rectw14, 
  float recth14)
{

  float distancex14 = abs(x1 - rectx14 - rectw14/2);
  float distancey14 = abs(y1 - recty14 - recth14/2);

  if (distancex14 > (rectw14/2 + radius)) { 
    return false;
  }
  if (distancey14> (recth14/2 + radius)) { 
    return false;
  }

  if (distancex14 <= (rectw14/2+ radius)) { 
    return true;
  } 
  if (distancey14 <= (recth14/2+ radius)) { 
    return true;
  }

  float cornerDistance_sq = pow(distancex14 - rectw14/ 2, 2) +
    pow(distancey14 - recth14/2, 2);

  return (cornerDistance_sq <= pow(radius, 2));
}

//boolean 15
boolean isCollidingCircle15Rectangle(
  float x1, 
  float y1, 
  float radius, 
  float rectx15, 
  float recty15, 
  float rectw15, 
  float recth15)
{

  float distancex15 = abs(x1 - rectx15 - rectw15/2);
  float distancey15 = abs(y1 - recty15 - recth15/2);

  if (distancex15 > (rectw15/2 + radius)) { 
    return false;
  }
  if (distancey15> (recth15/2 + radius)) { 
    return false;
  }

  if (distancex15 <= (rectw15/2+ radius)) { 
    return true;
  } 
  if (distancey15 <= (recth15/2+ radius)) { 
    return true;
  }

  float cornerDistance_sq = pow(distancex15 - rectw15/ 2, 2) +
    pow(distancey15 - recth15/2, 2);

  return (cornerDistance_sq <= pow(radius, 2));
}

Lab 12 – Media Controller

Professor: Macela

Partner: Leslie Zhao

Materials: a potentiometer, a breadboard, an arduino board, cables

Experiements:

In Lab 12, we had to use Arduino to contol images ad audio on Processing. Leslie would take in charge of Arduino part and I woul do Processing part. We decided to use a potentiometer to control the volume of a music as well as to switch over four pictures. Leslie found a comic made up of four pictures on MomComic.com, and I uploaded them on Processing with different image names. I also uploaded a sound file which I downloaded on line. Since the value which a potentiometer coordinates is between 0 and 1024, we devided the value into four intervals: 0 to 256, 257 to 512, 513 to 768, 769 to 1024. And there are four Several.wright attached to the four value intervals, 0, 1, 2, 3. Four pictures respectively corresponds to four value intervals. For the sound file, I mapped the volume of the sound into the values given by the potentiometer. That is to say, when the value from Arduino changes from 0 to 3, the vilume will change from 1 to 0, which means the sound will become louder as the Arduino value increases. However, when we ran the codes, there was always  an error about the port we used (even though we used the usb port). With the help of Luis, we found that we used the port twice, which resulted in a port error.

 

Based on the lecture and lab about images, videos and sound, I managed to put the knowledge into practice. Also, I revised how to connect Arduino with Processing in today’s lab, which is beneficial to my final project.

//Processing
PImage photo1;
PImage photo2;
PImage photo3;
PImage photo4;
import processing.sound.*;
import processing.serial.*;
Serial myPort;
int valueFromArduino;
int val;
SoundFile soundfile;
void setup() {
  String portName = Serial.list()[2];
  myPort = new Serial(this, portName, 9600);
  printArray(Serial.list());
  size(350, 310);
  photo1 = loadImage("1.jpg");
  photo2 = loadImage("2.jpg");
  photo3 = loadImage("3.jpg");
  photo4 = loadImage("4.jpg");
  soundfile = new SoundFile(this, "Redbone.mp3");
  //soundfile.play();
  soundfile.loop();
}

void draw() {
  if (myPort.available()>0) {
    val = myPort.read();
  
  if (val==0) {
    image(photo1, 0, 0);
  }
  if (val == 1) {
    image(photo2, 0, 0);
  }
  if (val == 2){
    image(photo3, 0, 0);
  }
  if (val == 3){
    image(photo4, 0, 0);
  }
  
  soundfile.amp(map(val, 0, 3, 1.0, 0.0));
  }
}

void keyPressed() {
  if (soundfile.isPlaying() > 0) {
    soundfile.stop();
  } else {
    soundfile.play();
  }
}

//Arduino
int potPin = 0;
int ledPin = 13;
int val = 0;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, INPUT);
}

void loop() {
  int potPin = analogRead(A0);
  // Serial.println(potPin);
  int volMapped = int(map(potPin, 0, 1023, 0, 255));

  if (potPin < 256) {
    Serial.write(0);
  } else if (potPin < 512) {
    Serial.write(1);
  } else if (potPin < 768) {
    Serial.write(2);
  } else if (potPin < 1024) {
    Serial.write(3);
  }
  delay(300);
}

Lab 11 – Drawing Machines

Instructor: Marcela

Partner: Leslie Zhao, Amber Wang, and Eric Zhang

Materials: 1 stepper motor, 1 SH75440NE ic chip, 1 5 volt power supply, 1 power plug, 1 potentiometer from your kit, 1 Arduino and USB cable from your kit, Laser-cut mechanisms, Pens that fit the laser-cut mechanisms, 1 potentiometer

Experiment:

In Lab 11,  the task was to make a drawing machine using materials provided. Leslie and I built the circuits based on instructions online. We attached the arm to the stepper motor and jointed the Laser-cut mechanical arms together with three nails. With the code,  stepper_oneRevolution example, we managed to make the stepper motor work and the mechanical arms to move. As you can see in the model, the drawing machine does not work well. It simply enables the pen to leave marks randomly.

IMG_8724

After finishing our drawing machine, we tried to combine with the drawing machine of Amber and Eric. Since there were two mechanical arms that can control the pen, the machine now could draw some patterns.

IMG_8729

WechatIMG119

For the third part, we used the code stepper_speedControl and a potentiometer to control the speed of the motor. This time when we combined with Amber and Eric, we used to Laser-cut mechanisms to fix the position of the stepper motors in case that the motor would move when it drew. We could also contolled the machine to draw fast or slowly. However, the speeds of two motors were different, the lines drawn could not coincide very well. The second painting looked better. Finally, we exhibited out painting on the wall of the lab.

WechatIMG120

 

 

Final Project Proposal

Professor: Marcela

Partner of Final Project: Amber Wang

Personal Definition of Interaction

As far as I am concerned, interaction usually occurs when there are two or more objects that have influences on one another. Compare with one-way effect, information in the process of interaction is sent from different objects. This kind of information is in either form, such as sound, light and pressure. When one of the objects sends the information to the other objects, there must be responses from the receivers to the sender. In this way, the information flows in multiple directions and the objects affect each other mutually.

Final Project Proposal

Following the idea of interaction, I gradually came up with the idea of my final project. Amber and I would make a game named Beauty and the Beast. For the Processing part, we will sketch the game interface. We will set a castle, where the Beauty lives, at the bottom of the screen. There will be several spaths leading to the castle, and monsters will come forward to the castle along the paths. The job of the Beast is to kill monsters with his claws from a certain distance and protecting the Beauty. Like the monsters, the Beast can only move along the paths and cannot stay in the scope of the castle. If he wants to move from one path to another, he has to go across a tunnel connecting paths with each other. As time goes by, monsters would move in a faster speed. If the Beast can survive by keeping monsters away from the Beauty in a certain amount of time, the player would win. Otherwise, the monsters would catch the Beauty and the player would lose. We will project the scene of the game on the wall, instead of on a computer. Here is a sketch about the game.

屏幕快照 2017-04-26 下午11.19.18

For the Arduino part, we will make devices the player can use to control the Beast. Basically, we will laser cut four footprints which represent four directions of movement “UP”, “DOWN” “LEFT” and “Right”. Suggested by Marcela, we will use fabric adhering to the footprint. When the player steps on the footprint, there will be a change of evaluation which would make the game more interactive. There will also be pressure sensors right attached to the footprints so that the player can make the Beast move in a certain direction by stepping on the them. Here are two sketches about the footprint. The first one is about arrangement of footprints and the second one is about the a footprint’s construction.

屏幕快照 2017-04-26 下午11.06.40

屏幕快照 2017-04-26 下午11.06.46

Besides, we will use two gloves which the player will wear. There are sensors attached to the gloves, which can sense vibration. When the player moves his hands, the Beast moves his claws correspondingly to kill the monster. In this way, the whole body of the player gets involved in the game. And there is more space for the player to interact with the game, comparing with playing the game on a computer.

Critique on Interaction of Midterm Project

Actually, what originally generates my idea of the final project is my midterm project. We made a game named Dodgeplane as our midterm project. Generally, two players use joy stickers to control the movement of the planes. However, the environmental setting (including two joy stickers attached to two colorful balls, and a white box containing the Arduino board) does not fit the game very well. When players take the devices, they sometimes wonder how the devices relate to the game. Therefore, we are going to make some improvements about the environmental setting in our final project.

Lab 10: 3D Modeling

Professor: Marcela

Partner: None

Material: Tinkercad, a 4 digit display

In previous lectures, we have already leared how to use Tinkercad to create models for 3D printing. Today, we were required to use Tinkercad to design a 3D model of a wearable device, a game controller or a security camera that can support some of the sensors. And I decided to design a watch. I would draw the watchband and the container supporting  a 4 digit display (which is the dial plate) with Thinkercad.

I first create a solid cylinder with radius of 30mm and with height of 9 mm. In order to make a watchband, I inserted another hollow cylinder. However, these two clinder can not fit with each other very well, since I change rotated one of them. I deleted the original  hollow clinder and copied the solid cylinder to make these two models combine with each other. For the container for the 4 digit diplay, I created a half-cylinder. Before I made the model, I measured the size of the display with a venier caliper. I set the length of the display as the height of the half-cylinder, and the width of the display as the diameter of the bottom circle of the half-cylinder. In this way, cables connected with the  4 digit display woule be attched to the inner side of the the watchband and people can check the time with the diplay contained by the half-cylinde. Here are some pictures about the watch observed from different angles.

屏幕快照 2017-04-21 下午2.28.07

屏幕快照 2017-04-21 下午2.27.52

Through today’s lab, I became more familiar with Tinkercad and 3D printing. It is beneficial for me to  put it into practial project and use it in my lives.

Stamp Work

In today’s class, we learned about digital fabrication and how to use Illustrator. After watching a tutorial given by Marcela, I tried to make a 3D stamp by myself. In the beginning, I used a picture of stamp as a model to draw. I drew three circles with different sizes, which piled up with each other. Then I wrote “NYUSH IMA” and “ESME” on the edge of the smallest circle inside. But I failed to change the position of the text. With the help of Marcela, I found that I have to create another layer on which “ESME” lies on. That is to say, to move the position of “NYUSH IMA” and “ESME” separately, they should lie on different layers. Under this circumstance, I changed the position by moving three lines connected to the circle to which “ESME” is tied. For the center part of my stamp, I originally was attempted to draw a symbol of lips at the center. Marcela suggested me to use a picture of lips online, since drawing it by myself would take more time and might not look as good as expected. Thus I copied a picture of lips online and pasted it on Illustrator.  Then I transformed it into a shape and expanded the shape. When finishing drawing the stamp, I had to expand the whole stamp to make sure that everything is a shape. At the end, I added a curve around the outer circle, for the sake of cutting the stamp along the curve. I also rotate the whole shape vertically. Only in this way, can the text stamped on paper go from the left to the right.

Screen Shot 2017-04-11 at 8.02.07 PM

Finally, Marcela helped me to laser cut the shape. It took five times for the machine to cut the stamp. To make it work better, Marcela had to clean the dust from time to time.

I attached the stamp to the bottom of a cup, so that it is easier to use it. But somehow I could hardly stamp the complete shape.

IMG_5621

IMG_5622

I found it very interesting to create a real entity by using Illustrator and laser cutting. I think it would be great to combine laser cutting with my final project in the future.

Midterm Project – Dodgeplane

Professor: Marcela

Partner: Amber Wang

  1. Motivation

What motivated us to do the midterm project was to solve a daily problem of who should go down and pick the food delivery. Everytime I ordered food on Elema or Sherpas with my friends, nobody actually wants to go to pick the food delivery. In order to solve this life problem, Amber and I wanted to design a game which not only could involve two players in competeing against each other, but also could solve the problem in an entertaining way. Most importantly, it should take two players as short of timeas possible to play the game, in case of keeping the deliverman waiting for a long time.

2. Reference

Generally, we referred to two simple video games. The first one if a game called PlaneWar on Wechat. In this game, player (the plane at the botton of the screen) is required to shoot other enemy planes. The more planes you can shoot, the higher grade you would get. At the same time, you should avoid crashing other planes as well. It is an interesting game for challenging a player’s agility. Here is a picture about the PlaneWar.

屏幕快照 2017-03-31 下午4.32.23

The other reference is a game named Block Run on 4399.com.  As you can see from the picture following, this game is designed for the player (the red column) to dodge other grey columns. There are several chances for you to stay alive when failing to dodge greay columns.

屏幕快照 2017-03-31 下午4.42.53

3. Idea

With the help of two references, we decided to make a game called Dodgeplane. Before coding, we first stretched the idea on a paper. There are two players, which are attacker and defender. The screen would be seperated as two parts. The defender is on the upper part and the attacker is on the lower part. Both of them can move up, down, left and right on their own part. The attacker can send missiles to shoot the defender. In 60 seconds, if missiles hit the defender, the attacker would win. Otherwise, if the defender can sucessfully dodge missiles, the defender would win. Players can use “w”, “a”, “s”, “d” to make the defender move up, left, down, right and they can use the keyboard of UP, LEFT, DOWN, RIGHT to control the movement of the attacker. However, we decided to use joysticks to control the movement of planes at last. Comparing with crowding in front of a computer, joystickes would make the game more interactive and interesting.

IMG_5577

4. Coding

In order to improve work efficiency, I was in charged of the Processing part and Amber focued on the Arduino part (which mainly includes attaching joysticks to the game).

In the begining, I drew two ellispses to represent two airplanes. Amber would photoshop two pictures of planes to replace the ellipses when I finished coding. With the help of Jiwon,  I started with coding the defender and the attacker. Since planes can move in four directions, I set x, y of the defender and the attacker as variables. I used keyPressed function so that I could use keyboards to control the planes. I also print the keyCode I used so that I could find clearly whether the keyPressed function worked.

The most challenging part for me was to code the missile. There is no restrictive condition for the attacker to send missiles, and the player can send as many missiles as he  wants. The player could send missiles through pushing the space bar. Jiwon taugt how to use boolean to set the missiles. There were two variables, boolean shoot and boolean setStart. Initially, they are equal to “false”. When the player pushed space bar, they are equal to “true”. Under the circumstance of “true”, a missile would move forward and its position would go back to the initial position when it is out of the screen. However, in this way, the attacker cannot constantly send missiles. If the attacker send missiles before former ones reach the end of the screen, the former would turn back to the starting position. Here is a video about the problem of missiles.

Professor Antonius helped me to improve the code of missiles by adding an important part–resetting the missile. That is to say, only when a missile reaches the end of the screen, can the position of the missile be reset. As a result, the attacker cannot send another missile until the former one reaches the end of the screen. Missiles that has already been sent will keeping moving and would not be drove back by pushing the space bar.  Here is a video about the imoroved version of missiles.

It is after I took the class of Arraylist that I truly figured out how to code the missiles. Marcela’s examples helped me a lot to learn Arraylist. There were 14 examples from Array to Arraylist, from drawing random line to drawing random circles, from random fixed circles to circles with random speed. It took me a whole afternoon to understand the examples. By changing some values of codes, I managed to figure out what exactly every function works. Moreover, Marcela recommended a Youtube Tutorial which educative as well as funny. Although some coding in the video is outdated, the general logic remains unchanged.

For the missiles, I used Arraylist, the class function including display function and move function. The starting position of missile is the same as that of the attacker so that missiles can fly away from where the attacker is. In the move function, the x of missiles would not change while the y of missiles would decreases at a speed of 2. When referring to examples of Arraylist, I used mousePressed to add new missiles. But I found that once I pressed the mouse, there would be missiles continuously sent out even if I released the mouse button. Therefore, I used mouseClicked instead, which means, the moment you click the mouse, a missile would be sent out. By decreasing the size of missiles, I managed to control the amount of missiles I want to send accurately.

Another tricky part was to set that when a missile hits the defender, the attacker will win the game is over. I set time as a variable and the time would decrease by subtracting mills. When the difference between y2 (y of the defender) and y (y of the missile) is 0, the screen will show a picture that with “YOU LOSE” on the upper side and “YOU WIN” on the lower side. However, since I used Arraylist as a function to code missiles, the y of missiles would keep decreasing. That is to say, there is only a moment that y2-y=0. And it is so fast that the picture cannot showed on the screen. With the help of Avan, I used dist, the absolute value of distance, to express the distance between the defender and the missile.

Thanks to the “Tree Model” Professor Antonius taught me, I could organize my codes clearly. For example, I would first write p1.move(); as a title in the draw function. And under a new Tab “Move”, I would add the move function of plane 1 separately. Organizing code in this way could effectively helps me to avoid missing } and makes it more convenient for me to improve my codes.

5. Physical Surrounding

We tried to improve the physical surrounding of the game to make it more interactive. Since it is not comfortable to hold the joysticks we found in lab, we attached two rubber hemispheres to them. The rubber hemispheres could fit into people’s hands very well. this way, players would find it easier and more convenient to use the joysticks. IMG_5572

IMG_5575

6. Dodgeplane is Born!

7. Improvement

After we finished out project, some of my classmates tried the game. Most of them found that it is an unfair game. Since there is no limit to the amount of missiles, attacker can easily kill the defender. Lack of time to improve the project, I merely shortened the time the game lasts to 20 seconds. So far, there has been no player of defender that could hold on more than 15 seconds.  If we had more time, we would have improved the project by limiting the missiles the attacker can send at one time. For example, the attacker can only send five missiles at one time. After the fifth missile reaches the end of the screen, can the attacker send another round of missiles.

8. Reflection

I really appreciate the help of professors and teaching fellow. I would not have made Dodgeplane come into being without their assistance. The midterm project was a valuable opportunity for me to integrate codes I learned before and use them in a practical way. At the same time, I earned a strong sense of achievement from the project. In this process, I sometimes felt very depressive because of failing to write the codes as I expected. Thanks to the support of Marcela, I gradually understand that the process of learning is more important than a final result. The purpose is not only to make a game, but also to learn how to code, how to interact and enjoying the process of coding.

//Processing
int time;
Plane1 p1;
Plane2 p2;
import processing.serial.*;
String myString = null;
Serial myPort;
int NUM_OF_VALUES = 5;   /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
int[] sensorValues; 
PImage plane1, plane2, plane1win, plane2win;
int x1, y1; //plane1
int x2, y2; //plane2
ArrayList<Ball> balls = new ArrayList<Ball>();

void setup() {
  size(800, 700);
  //printArray(Serial.list());
  time = 20; 
  plane1 = loadImage("plane1.png");
  plane2 = loadImage("plane2.png");
  plane1win = loadImage("lose-win.png");
  plane2win =  loadImage("win-lose.png");
  setupSerial();
  x1 = width/2-50;
  y1 = height-100;
  x2 = width/2-50;
  y2 = 0;
}

void draw() {
  background(81, 54, 96);
  updateSerial();
  p1 = new Plane1();
  p2 = new Plane2();
  p1.display();
  p1.move();
  p2.display();
  p2.move();
  //p1w.display();
  //p2w.display();
  println(sensorValues[4]);
  //while (myPort.available() >0) {
  //valueFromArduino = myPort.read();
  //}
  // //  println(valueFromArduino);
  fill(255);
  textAlign(CENTER);
  textSize(32);
  text(time+1-(millis()/1000), width/2, height/2);

  if (sensorValues[4] == 1) {
    println("adding new ball");
    balls.add( new Ball(x1+48, y1));
  }
  for (int i=0; i<balls.size(); i++) {
    Ball b = balls.get(i); 
    b.move();
    b.display();
  }
}

void mouseClicked() {
  balls.add( new Ball(x1+48, y1));
}

class Plane1 {
  Plane1() {
  } 

  void display() {
    image(plane1, x1, y1, 100, 100);
  }

  void move() {
    if (sensorValues[1] < 300) {
      if (y1 > height/2 ) {
        y1 = y1 - 20;
      }
    }
    if (sensorValues[1] > 700 && sensorValues[4] == 0) {
      if (y1 < height -100) {
        y1 = y1 + 20;
      }
    }
    if (sensorValues[0] < 300) {
      if (x1 > 0) {
        x1 = x1 - 20;
      }
    }
    if (sensorValues[0] > 700) {
      if (x1 < width - 100) {
        x1 = x1 + 20;
      }
    }
  }
}

class Plane2 {
  Plane2() {
  } 

  void display() {
    image(plane2, x2, y2, 100, 100);
  }

  void move() {
    if (sensorValues[3] < 300) {
      if (x2 > 0) {
        x2 = x2 - 20;
      }
    }
    if (sensorValues[3] > 700) {
      if (x2< width - 100) {
        x2 = x2 + 20;
      }
    }
    if (sensorValues[2] < 300) {
      if (y2 > 0 ) {
        y2 = y2 - 20; 
      }
    }
    if (sensorValues[2] > 700 && sensorValues[2] < 1023) {
      if (y2 < height/2 - 100 ) {
        y2 = y2 + 20;
      }
    }
  }
}

void setupSerial() {
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[2], 115200);
  myPort.clear();
  // Throw out the first reading,
  // in case we started reading in the middle of a string from the sender.
  myString = myPort.readStringUntil( 10 );  // 10 = 'n'  Linefeed in ASCII
  myString = null;
  sensorValues = new int[NUM_OF_VALUES];
}

void updateSerial() {
  while (myPort.available() > 0) {
    myString = myPort.readStringUntil( 10 ); // 10 = 'n'  Linefeed in ASCII
    if (myString != null) {
      String[] serialInArray = split(trim(myString), ",");
      if (serialInArray.length == NUM_OF_VALUES) {
        for (int i=0; i<serialInArray.length; i++) {
          sensorValues[i] = int(serialInArray[i]);
        }
      }
    }
  }
}

class Ball{
  float x, y, size;
  color clr;
  float xspeed, yspeed;
  
Ball (float tempX, float tempY){
    x = tempX;
    y = tempY;
    size = 5;
    clr = color(0);
    xspeed = 0;
    yspeed = 2;
  }
  void display(){
    fill(clr);
    ellipse(x, y, size, size);
  }
  void move() {
    x += 0;
    y -= yspeed;
  }
}


//Arduino 
int buttonPin = 0;

void setup() {
  Serial.begin(115200);
}

void loop() {
  int pot1 = analogRead(A0);
  int pot2 = analogRead(A1);
  int pot3 = analogRead(A2);
  int pot4 = analogRead(A3);

  buttonPin = digitalRead(12);

  Serial.print(pot1);
  Serial.print(",");  // put comma between sensor values
  Serial.print(pot2);
  Serial.print(",");
  Serial.print(pot3);
  Serial.print(",");
  Serial.print(pot4);
  Serial.print(",");
  //  Serial.print(buttonPin);

  if (pot2 == 1023) {
    Serial.print(1);
  }else{
    Serial.print(0);
  }
  Serial.println();


  //Serial.write(buttonPin);
  delay(10);


}

Lab 6 Communication between Arduino and Processing

Instructor: Marcela Godoy

Partner: Amber Wang

Goal: From Aruduino to Processing & From Processing to Arduino

Material Needed: Power Supply, breadboard, cables, 1 buzzer, 1 switch, 1 resister

Experiments:

Before gatting to start experiments, we referred to examples in class to revise how to make Arduino and Processing communicate. The first experiement was about sending value from Arduino to Processing. Basically, we wanted to use a switch to change the color shown on Processing window. We first set a variable on Arduino buttonPin. The value of buttonPin is either 0 or 1, which represents switching off or swittching on. On Processing, the value of buttonPin would be translated to color changes. When buttonPin is 0, the color would not change. When buttonPin is 1, the color would change. However, when we tested our codes, we found that the color kept flashing when someone push the button. Thanks to the help of Luis, we learned that adding another condition, pv == 0. This condition means that when buttonPin is 1 and at the same time, the previous buttonPin value was 0, the color would change. Otherwise, if the previous buttonPin value has already been 1 (someone already pushed the button), the color would not change. Also we changed to delay from 10 to 100, so that Processing can receive information properly. Here is the video of this experiment.

The second experiment was about sending from Processing to Arduino. Basically, we wanted to turn on and off a buzzer by changing the value sending from Processing. When someone clicked on the Processing window, the buzzer would alarm. To write codes, I reffered to one of the examples about using Processing to control an Led light. The variable we set was mousePressed. If the value of mousePressed is H, the buzzerPin value would be 1 and the buzzer would alarm. Here is the video of the second expriement.

Through Lab 6, we both have a better understanding about how Arduino and Processing communicate with each other. It would be very helpful to our midterm project.

//From Arduino to Processing 

//Arduino 
int buttonPin = 0;

void setup(){
  Serial.begin(9600);
}

void loop(){
  buttonPin = digitalRead(12);
  
  Serial.write(buttonPin);
  
  delay(100);

//Processing 
import processing.serial.*;

Serial myPort;
int valueFromArduino, pv;

void setup(){
  size(500, 500);
  myport = new Serial(this, Serial.list()[1], 9600);
}
void draw(){
  while (myPort.available() > 0) {
    valueFromArduino = myPort.read();
  }
  if (valueFromArduino == 1 && pv == 0){
    int r = int(random(0, 255));
    int g= int(random(0, 255));
    int b = int(random(0, 255));
    background(r,g,b);}
    pv = valueFromArduino;
}


//From Processing to Arduino 

//Processing 
import processing.serial.*;

Serial myPort;
int valueFromArduino;


void setup() {
  size(500, 500);
  background(0);

  printArray(Serial.list());
  
  myPort = new Serial(this, Serial.list()[3], 9600);
}

void draw() {
  // to send a value to the Arduino
  if (mousePressed) {
    myPort.write('H');
  } else {
    myPort.write('L');
  }
}

//Arduino 
int valueFromProcessing;
int buzzerPin = 12;

void setup() {
  Serial.begin(9600);
  pinMode(buzzerPin, OUTPUT);
}

void loop() {
  while (Serial.available()) {
    valueFromProcessing = Serial.read();
  }
   
  if(valueFromProcessing == 'H'){
    digitalWrite(buzzerPin, 1);
  }
  else{
     digitalWrite(buzzerPin, 0);
  }

  delay(100);
}

Stupid Pet Trick_Stupid Toy

Project: Stupid Pet Trick

Instructor: Marcela Godoy

Partner: None

Goal: Make a stupid toy with fading eyes controlled by a tilt switch

Material Needed: Power Supply, breadboard, cables, 10 LED, tilt switch, 10 resistors, paper board

Idea:

The process of coming up with an idea was a biit tricky. Originally, I wanted to make a heart shape formed by 20 LEDs. Controlled by an accelerometer, the LEDs could shine and fade gradually. After I talked about the idea with Professor Antonious, he suggested me to make it relatively simple. After all, it was merely aa small project. Therefore, I decided to make a stupid toy with two eyes, which would be made up of 10 LEDs. Instead of being controled by an accelerometer, I used a tilt switch. When I shake the tilt switch, the eyes sould shine. Otherwise, the eyes would fade gradually.

Code:

Generally, I referred to two examples, Fade and Button when writing the codes. With the help wo Marcela and Lewis, I set two variables in order to use tilt switch to sense speed. The first variable I set was buttonState. When someone shakes the tilt switch, the button is on so the buttonState is 1. While the button is off, the buttonState is 0. The second variable I set was a, which was used for measuring the brightness. As you can see my code below, as button is on for more times, there will be many buttonStates that equals 1, and a is a certain amount of added buttonStates. In this way, as someone shakes the tilt switch, a would get bigger so that brightness would be higher and the LED would get brighter. While when buttonState achieves 255, the highest value, the brightness would decrease by a certain fadeamount. Since I wrote the code before I actully finished my circuits, I used a LED to test my code. When testing my codes, I found that the LED faded too fast. Hence, I made the fadeamount smaller so that people can notice that the brightness is changing.

Circuits:

Actually, I think the most diffifult for me in completeing this project was to build an organized circuit. To attach LEDS to a paper board, I cut two small holes to insert two legs of the LED. After that, I soldered the legs with cables. In case of short circuits, I tied tap to every connected part. When I plugged the end of cables to the breadboard, I found they were loosen. Because there were twenty cables in total, it was easily for me to mess them up, which made me fail to light all the LEDS up in the first time.

In order to fix this problem, I intended to tie all the positive ends together and all the negative ends together. Then I connected a single cable with either side. It worked t first, but half of the LEDs were broken due to short circuits. As a result, I had to change the LEDs and soldered them again, which made me suffer from a heavier work.

IMG_5463

With the help of Marcela, I tried to organize the circuits clearly. We cut part of the legs of the resistors, in case that they would connect with other parts of cables. As the photo shows, the resistors and cables are very short and tightly plugged into the breadboard. In this way, the negative ends and the positive sides were seperated to two sides of the breadboard. When I connected cables of one LED, it suddenly blew up. In the end, I had to replace with with a drawn eye. To make the toy look more natural, I attached the tilt switch to the back of a cute cat paw. After I completed the circuits, I tested the project. I found that the tilt switch was too sensitive sometimes that LEDs could not fade but became brighter again and again. To make the buttonState zero, I had to prevent the sitch from moving by pressing it against a table. Due to the time limit, I did not continued to improve my project at this aspect.

IMG_5465

Although I have been through many troubles, I have learned a lot about how to write codes and build circuits. I think that will be very helpful to my midterm and final projects.

const int buttonPin = 2;    
const int ledPin =  9;     
int brightness = 0;
int fadeAmount = 3;
int a = 0;
int buttonState = 0;    
void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  Serial.begin(9600);
}

void loop() {
  buttonState = digitalRead(buttonPin);
  Serial.print(buttonState);
  Serial.print(",");
  Serial.print(a);
  Serial.print(",");
  analogWrite(ledPin, brightness);
  Serial.println(brightness);
  a = a + buttonState;
  
  if (buttonState == 1) {
    brightness = 70 + a*5;
  }

  if (brightness == 255){
    a = 0;
  }

  brightness = brightness - fadeAmount;

  if (brightness <= 0) {
   brightness = 0;
  }

 delay(100);
    
}

Lab 4 – Sensors

Lab 4 – Sensors

Instructor: Marcela Godoy

Individual Project

Goal: Test Moisture Sensor

Material Needed: a Moisture Sensor, Power Supply, breadboard, cables,1 buzzer,

Experiments:

In Lab 4, I chose one of the sensors, the moisture sensr to test with a buzzer. I intended to control the tone of the buzzer by changing the moisture variables. First of all, I built the Arduino curcits. There are four cables connected to the sensors. The yellow cable connects to A0 (which the code showed), the white one connects to nothing. the red one connects to power, and the black one connects to the ground. I also coded that the buzzerPin was 8. After that, I had to write codes based on the codes provided online. Basically, I used the map function to convert sensor values (input) into buzzerTone (output). The higher the moisture is, the louder the buzzer will be. As a result, the buzzer alarmed in a low sound even if the value of moisture was zero. With the help of Marcela, I managed to make the tone of the buzzer fade. I combined the if & else statement with the map function. I coded that if the sensor value is smaller than 100, there should be no tone at all. And if the sensor valule is more than 100, the buzzr would alarm frequently. In this way, the buzzer would not keep alarming. Here is the video about my project.

Generally, the Arduino coding is still a very challenging part for me so far. Through this lab, I feel it necessary to refer to codes online frequently. I can’t wait to start my own stupid pet trick project.

int sensorPin = A0; 
int sensorValue = 0;
float buzzerTone;
int buzzerPin = 8;    

void setup() {
  
    Serial.begin(9600); 
    pinMode(buzzerPin, OUTPUT); 
}
void loop() {

    sensorValue = analogRead(sensorPin); 
    Serial.print("sensor = " ); 
    Serial.println(sensorValue); 
    delay(1000); 
    
    if (sensorValue < 100){
      noTone(buzzerPin);
    }else{
    buzzerTone = map (sensorValue, 0, 800, 0, 600);
    tone(buzzerPin, buzzerTone); 
    }
}