Final Project Documentation by Amber Wang (Marcela)

Final Project Beauty & the Beast Documentation

Instructor: Marcela Godoy

Produced by Amber Wang and Esme Wang

Documented by Amber Wang

Date: May 16, 2017

  1. The idea of our project

Beauty and the Beast is the final Interaction Lab project made by Esme and I. It is a physically interactive game, competing with the computer. Basically how it works is that the player acts as the character of “the Beast” and is supposed to defend “the Beauty” against waves of bats (the enemy) in certain time. As is shown in the following map, when the game starts, there will be bats coming from the five entrances and moving along the path to approach the castle and “the Beauty”. The player can also move along the path to fight against the bats. The rule is that the bats will not hurt “the Beast” and you lose only when there’s one bat get into the castle. If you can survive certain time, you will win.

map  IMG_1010

It is designed as an entertaining game. The users can be any physically healthy people who search for fun! Besides, the game is especially suitable for those “indoorsman” and “indoorswoman”, which allows them to have enough exercise and entertainment playing at home. The special design of our project is that it is not just a typical computer game, instead, it involves a series of physical movements of the user to play in an open space. As you can see, we borrowed the idea from Dance Dance Revolution moving pad, and designed our four stepping pads to control the player’s movement. Likewise, our game also requires players’ quick response, because there’re five paths on the map and you have to keep an eye on either of them and move quickly enough to stop the bats from getting closer to the castle. Besides the foot movements, the player will also wear a claw glove, with which he/she has to wave to scratch the enemies. The inspiration also comes from our midterm project Dodgeplane, which motivates us to design a more physically engaged game with a better interaction.

IMG_0953IMG_0951

2.  Early Planning and Preparations

After we decided the main idea of our final project and wrote the proposal about three weeks ago, we started our early preparations. We divided the task into two parts and work on it simultaneously. As for me, I mainly focus on the graphic design of our project.

Because we had made a clear and concrete story and character setting in our proposal, so  I need to design the features of the game accordingly. The first step and also the most important one is to design a game map. As we mentioned in our proposal, we wanted the enemies to come from different directions and approach the castle, so I need to indicate the path in the map. Our first sketch, as you can see below, has quite curved paths and the main paths are connected to each other through certain small paths. However, we found it of too much difficulty to write the coordinate equations of the paths, as well as not clearly enough for the player to move along the paths. (For example, if the path has an inclined angle, the user has to step on both UP and Left button to move up, which is quite troublesome.) Therefore, we changed the paths to be horizontally and vertically placed. When I actually started to frame the map, I had another struggling, which is the viewing angle of the game. Especially after learning 3d modelling in Tinkercad, I found it of vital importance to effectively demonstrate a three dimension object in a two dimension screen. I first though of the top view, like our midterm project, which can clearly show the setup of the map. However, then my player and other characters will only be seen as the top of their heads, which is not so lively and also hard to find corresponding picture materials. Then I think of using the first person view of the player, like Temple Run and Counter-Strike, but again it affects the game experience because the players are supposed to view every path at the same time, and the first person view will only allow them see the path that they are on. After researches and comparisons, I finally decided to borrow from the Pokemon video game and design a view that can both show the paths and objects’ shapes.

The designing process is quite painful, because before this I didn’t have too many Photoshop background and only knew very basic tools in Photoshop. And I understood if I drew out the map, it will take me too much time and to be host, I am not that good at drawing. Luckily, during my long-time research on game materials in Google and Pinterest, I found out great graphic materials which could be used in my design. I used the keywords including “Pokemon”, “RPG Maker”, “game map”, “pixel arts” and “tilesets”, and found incredible game patterns. I then also found out that most of the game maps, like Pokemon, are actually made up of with tiled squares, and each square has its pattern. I successfully downloaded two images which contained a great many pattern units, like trees, grass, ground tiles, and buildings, etc. I then copied the two images for many times and cropped them into the patterns that I needed. In Photoshop, I first tried to copy and paste those small units and tile them one by one, but it took too much effort and felt so stupid. So I watched several Youtube tutorials and learned to use “Define Pattern” and “Fill—Pattern” to quickly fill the whole canvas with the unit pattern I need. I also used the same tool to design the road. I just needed to simply select the rectangle that I wanted to pave the path and fill them with the ground tile units. The whole design process was quite complex and I spent almost a week to finally accomplish it. Especially for the decorations of the map, I really did it tile by tile. As for the trees and the snow on trees, I didn’t find an effective way to do them in group, so I indeed “planted” and adjusted the trees one by one and added the snow to them. Also for the paths you see now is actually a revised final version of the map, and before we had discussed different ways of paving them and did it several times until deciding this way to best improve user experiences. I have used more than a hundred layers to finally set up the whole map. It is exhausting, but makes me proud!

Screen Shot 2017-05-07 at 3.37.46 PM

3. Working Process

After finishing the map design, I later worked on the character design and game effects. This involves a lot of searching as well. During my search, I found that a lot of games have the character images in different views, so when the character is moving, the image changes and it feels like the character is actually turning around. It was a great inspiration for me so I decided to design our game with a similar effect instead of just plane view like our midterm project was. After finding appropriate character images, I started to code the effect in Processing. Like what we did in midterm project, I first designed the version based on the keyboards. As is shown in the code, I had different images with different states of the character and stored them in different PImage variables. I used “Class” to code it. I also created three more variables to be the current image, x, and y coordinate of the image. I set an initial display image, which is m1 and displayed it in an initial position. Then with the different “keyPressed”, the current image changed to the corresponding view of the character and its x and y position changed accordingly. Similarly, I Photoshopped four different images of a claw scratch and put the corresponding image right in front of the character when the “attack” key is pressed. It is a very lively game effect, which looks like the character is actually turning around, moving and attacking.

Screen Shot 2017-05-12 at 3.41.10 PM Screen Shot 2017-05-21 at 10.04.16 AM Screen Shot 2017-05-21 at 10.05.58 AM

While I was working on the graphic design and game effects, my partner Esme was working on the game principle design in Processing. It was a quite new realm for her because it requires the object to move only within the designed path. It means even though the player pressed the moving buttons, if they were at the edge of the path, they could not move out of it. She made a lot of effort on this and consulted many experts, and finally made it work by using Collision. Moon helped her with a smart idea of identifying colors. So basically she put another layer of map composed of barely pure color, and let the object moves only when it is on the certain color. The “hidden” map looks as follows. If you want to know more about how the things work, please refer to Esme Wang’s documentation post.

mapWall3

She also worked on the time count and other theoretical game design like: setting the enemies coming from every road and moving randomly; the bats will only disappear when the player is close enough to them and press the attack key; the game will over when either the time is out or one bat is close enough to the castle, etc.

At the same time, I started to work on the Arduino circuits and physical mechanism part of our project. I first looked into the “attack” interaction. While the most common way of attacking in most games is to press a button, this time, I want to make it different and also more closely related to the game. As for “the Beast” in the game attacks the enemies by scratching, then I thought of letting the players do the same scratching action. As mentioned in our proposals, we thought of asking the players to wear the claw-like glove and wave the glove to trigger the “attack” function. So I decided to use 3 axis accelerometer as the sensor. As is shown in the sample code of the accelerometer, this sensor can actually give out the x, y, z coordinates of a point as well as its acceleration in the three axises. With the help of Marcela, I then figured out to use only the acceleration on X axis to be my input variable. And after reading the values in serial monitor, I found the  value domain smaller than -1.5 and bigger than 1.5 is the best indicator of a effective “attack”. So I set the if statement that if the former two conditions happen, Arduino will print “1”.

The whole process of setting the sensor went through well, however, the most challenging part is the stepping pad. At very beginning, I thought about several approaches to make the pads, by either using pressure sensors or carpet, but I then  gave up them and found a better way by making our own “buttons”. Actually for the midterm project, Rudy had mentioned to me about making self-designed buttons, but I always felt it too hard and troublesome and found another alternative with already-built buttons. This time, when I was discussing with Marcela about using pressure sensors, she also suggested me building buttons by myself. So I decided to take the challenge. After figuring out the principal of a button mechanism, things become easier, and all I need to do is to find fitting materials.

The basic mechanism of our self-built button is composed of two boards and one layer of foam. At first I was trying to use many layers of fabric to be the “soft isolation layer” of the button, but when I found the foam materials in the equipment room,  I settled on it all at once. So what I did was to pave the two boards with the conductive tape, and dug out a whole in the foam layer. So when the board are pressed, the foam layer will be compressed and then the two conductive layers will be connected. The real mechanism looks as follows:

IMG_0928 IMG_0927

To better polish our stepping board as well as apply to our game them, I also used Illustrator to design the footprints and laser cut them on the wooden boards.

IMG_0865 IMG_0975

(Actually the first version of our stepping board didn’t work so sensitively after the testing because the foam hole was too small. I later took part the boards and dug a much bigger hole LOL)

Then Esme helped me solder each conductive side of the board to wires and I connected them to my Arduino circuits. The circuits are the basic button circuits with combination of resistors, and connecting to Arduino’s digital pins to read the values. I then wrote for the serial communications between Arduino and Processing by using String to send multiple variables. (For a more clear explanation of how to use String to send multiple variables from Arduino to Processing, please refer to my midterm project Dodgeplan documentation post.) After further combinations with Esme’s codes and some adjustments, our project was finally DONE!

4. The Video Demo

5. Reflections and Improvements

I have to say this project is my most favourite project so far and I have to give great thanks to my best partner Esme, and also IMA fellows Marcela, Jiwon, Moon for their help. It is more than exciting to have the project finished in time and also meet all our proposals and expectations! The most valuable lesson I learned from this project is that I have to take the risk and dare to think big. Just like how I tried to build my first self-made electronic component instead of just using the ready-made. Also, because we made it clear about our complex game design, it motivated me to keep polishing the whole graphic design as well as detailed game effects.

The improvement we can further make to this game is that we can add a ranking system. Right now the idea is wether the player can win or lose in certain time, (usually 30 -45 seconds), however, in the future, we can change it to record the longest time the player can stay alive (keep the bats away from the castle) and give them an updated ranking each time they play.

 

 

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));
}

One thought on “Final Project Documentation by Amber Wang (Marcela)

  1. Amber, I would like to congratulate you because you worked really hard during the semester, and did a great job in every assignment.
    I think the partnership with Esme worked great and you were able to improve more and more every time and achieve all your goals on time.
    I’m glad you are happy with the results!
    your documentation is great as always 🙂
    hope to see you around next semesters even if you are not taking IMA classes.
    have a great break!

Leave a Reply