Final Project – Alice Kwok (Leon)

Project Name: Bouncing Balls (Alice and Krystal)

Bouncing Balls is a game where players compete with each other by hitting the tables to increase the numbers of balls on their side of the screen (each with a corresponding colour). The first player who gets to 100 wins. We first plan to make a clapping game where two players compete with each other, but we are also extremely interested in making beautiful graphics with processing, so in the end, we decided to combine the two factors together to create an interactive fun yet pretty game.

Inspirations:

Graphics:

  • One of our inspiration is a piece created by Alessandro Valentino. This work can be found in this link: https://www.openprocessing.org/sketch/402537 The author uses processing to create the piece. When you press the play button, the patterns will start to “flow” off from the middle of the screen.

  • Another inspiration is a piece by Marius Watz. This work can be found in this link: https://www.openprocessing.org/sketch/102329 In this piece, different circle and line will sprout from the trial of your mouse. This work is one of the biggest inspiration for our project as the reason why we decide to use the colour pink and blue is from this project.

Game:

  • For the game aspect, the biggest inspiration would be Hungry Hungry Hippos which is shown by us by our professor. It is an extremely simple game where players compete with each other to “eat” the most balls by pressing the button quickly.

  • Another major inspiration for this project is also the act of clapping. A lot of times clapping is used as a way to congratulate and compliment other people. After doing some research, I also realised that clapping is also good for your health.
  • Another major inspiration/motive for our project is also the stress of academics or in life. Since currently, it is the final week, in the academic building you can see many people studying furiously and staying up late to finish their work. Everyone is very tired and stress. During our user testing, the initial way of playing this game is through clapping. However, some people decided to hit the table instead of clapping. A lot of other people follow suit after the first person did it. We also try out hitting the table instead of clapping and we realised hitting the table makes someone feel very relax and also it can also make the players more focus and into the game. So we decided to make the game hitting the table instead of clapping.

Process:

Brainstorming:

  • Initially, we decided to make a game where users compete with other to be the first person to control the location of the ball using the sound of the clap to the correct location. However, it is hard to think of variables to make clapping the only factor that controls the x and y values of the mouse. So we decided to change our idea.
  • We then decide to make an interactive canvas where users can create drawings on the canvas by moving their hand up/down as the x-value and left/right as the y-values. However, we think although this idea might be pretty and in some sense interactive but it does not require as much attention from the user.
  • After talking to the professor, we then decide to create a game where two players compete with each other to make their colour of shape to cover the whole screen first by clapping the quickest.

Processing/Arduino:

  • We first try out the sound sensor for the project. At first, we were not too sure of using sound sensors because sound sensors are too sensitive to the surrounding noise.

  • To code for the project, I decided to use multiple values: Arduino to Processing. Using the code from the examples from the slides, it was really simple to use. However, a problem that I run into is that the values from Arduino could not be sent to Processing. The values will appear as normal when I run it in Arduino but if I also run it in Processing it will only say 0. After asking for help from another professor, I realised that there are some extra codes on the Arduino part that affect the values from being properly sent to Processing. From this, I learn that you have to very exact with the code any additional code will also impact the outcome. Below is a video of the values successfully send to Processing:

  • A problem I thought of for our project (at that time is making the shape bigger by clapping) is that if we decide to make both players share a screen and make their shape the first one to cover the screen. One shape will overlap with the other. However, in Processing, the order fo the codes will determine the order of the shapes. So I decided to separate the screen into two sides (half), one user will have a side of the screen. So this works out fine.

  • However, I think this project is a bit too simple, and I really want to implement more graphic elements in the game. So I decided to change the whole visual of the game. I initially plan to make something like confetti. The idea is if you clap, there will be a spray of confetti will appear and the person who have the most confetti wins. I plan to use the image of confetti since it has a meaningful connection to the act of clapping. Both an act of celebration. However it is really difficult for me to code a range of confetti to appear at a time, so I decided to use balls instead.
  • I use the example code for object class from the slides to make the balls. I first create a new tab and copy and paste the original set of code under the Ball tab to create two sets of balls. I then alter the boundary of each set of balls so that they will bounce off in the middle of the screen. Both balls will not mix together.
  • However, I ran into a problem since for testing I decided to use mouse pressed as the signal to increase the number of balls instead of a sensor. So sometimes the balls will be stuck on the certain part of the screen unable to move from right to left. I realised that it is because I did not specify which class of balls I will be using in different areas of my screen. So I then specify that when the mouse is at this area, only one set of balls will show up and vice versa. Below is a video of the successful outcome.

  • After this, I decided to change the colour of the balls, as the colour is a bit ugly. I then decided to use HSB instead of RGB colours because I want to keep the two class of balls different but also consistent with each other. So I kept the hue constant but put a random function with a range of numbers for saturation and brightness. Note that the range of the random function is the exact same for the two object classes.
  • Then, after successfully changing the colour, I decided to make a counter so that everytime you click on the screen and a ball increase, there will be a score that will track the number. After asking help from the professor, I realised that there is a function that allows integers in the Arduino to be converted into text. So this is the outcome (note that after taking this video, I also added transparency to the circles to give the game a softer vibe) :

  • I then create victory pages for the game. I created two victory pages one for each user. I added colours to the page to let the player know more easily. A problem that I face is that even though after the victory pages appear you can still increase the number of balls on both sides. After asking for some help, I found the solution to it by clearing the array list of the classes.

  • After all the Processing aspect is done, I connected it to the Arduino using two sound sensors. One sensor for one side of the screen. I put a threshold for the sound sensor at 400, so that the surrounding sound will not impact the gameplay itself (however, during the IMA show, I change it to 700 since the room is louder). After this, I start to code for the main page of the game.
  • For the main page, I want to create a simple page that is consistent to the victory page. So I only added a simple text which is the same colour as all the other text. The box in the middle of the screen is also the same box as the victory screen. I then added two balls one in pink and one in blue that bounce off the screen to create more interesting visual to the page and also to link the pages of the game together (make more connection between the game).

  • However, after this, the major issue I ran into is that each page will not completely disappear after I press the TAB or ENTER button. The box from the main page will continue on to the game page. So after asking for help from a professor, he recommends me to create a count for each page in the game. So when a specific code is run, the count for the page of the game will change which will also change the game screen itself.
  • After the user-testing, I got a lot of precious feedback. One comment I got is that I should incorporate a timer page. During the testing, we have to help the user click the enter button to make the game fair. So a timer is very essential to the game.
  • However making a timer page, is extremely hard for me because the count has to be the same as seconds. So after asking for help, the count is in seconds. However, the count will not disappear at 0 automatically rather there will be a small glimpse of -1 on the screen before it fades away. However, after changing some things that the problem is then solved. Another problem with the timer is that after you return to the main page after a round of game, the next round of game will not appear the timer. Also after asking for some help, I realised I forgot to write the code to reset the timer.
  • For the design of the box to put the Arduino, we decide to use colour circles as the cover to match the visuals of the game. We also use reflective colour papers to cover up the wires and sensor.

Our final project looks like this:

Improvements:

  • Create a more interactive and interesting tutorial or instruction for the start page since we realised users often do not read the instruction even if we try to shorten the instructions to make it easy to read.
  • Instead of using mouse keys, we can make two users clap at the same time as a way to transition between the pages this will be more interesting and more relevant to the game.
  • Also, we could find a way to not use any wires in the game, something like a wireless game. Users can carry the sensor to different areas and still play the game. (This will also lead to the next point)
  • Since we are ultimately using a sound sensor for the project, even though we have tried to increase the length of the wires so that the sound from one player will not affect the other user as much. But still, there are still some influences on the other player’s sensor. A solution we came up is actually to put the sensor in two separate table so that it will not be able to influence each other.
  • We can also think of a better way and more comfortable for users to interact with the project. Since a lot of people complain that your hand really hurt after playing this game. We can potentially create a soft pad on the table for the users, but this can potentially cause the sensor to not pick up the sound as you are hitting on a soft pad. Other people also suggest we can use drums as a way of interacting, which is a really good idea.

Conclusion:

We originally struggle to come up with ideas for our final project. For this project, we only started from a very small and basic idea, but during the process, we find more and more interesting ways to experiment and add upon the project. Through this process, I realised that it is better to have a big broader idea on what you want to achieve rather than limiting yourself to a specific area.

I had an extremely good time working on this project. When I first took the class, I know nothing about coding. Thus, it was extremely difficult and stressful for me during the midterm project as I don’t know and don’t understand the code that well to apply it. However, when I am working on the final project, I was very at ease and was very excited to try out different ways I might be able to make the project better. It was really nice as I can feel that I really learn and understand the logic behind coding. Especially during user-testing and IMA show when the users who try out our project were really happy and engage in it. I feel really happy that I manage to create something that users really enjoy.

Additionally and most importantly, I also really want to thank the wonderful professors and fellows who are always so kind in helping us for our project. Thank you very much. I will not be able to go through this course without your precious help. Thank you.

//ARDUINO
void setup() {
  Serial.begin(9600);
  pinMode(A0,INPUT);
  pinMode(A1,INPUT);
}

void loop() {
  int sensor1 = analogRead(A0);
  int sensor2 = analogRead(A1);

  Serial.print(sensor1);
  Serial.print(",");  // put comma between sensor values
  Serial.println(sensor2);

  delay(10);
}

//PROCESSING 
//Final (MAIN PAGE)
import processing.serial.*;

String myString = null;
Serial myPort;


int NUM_OF_VALUES = 2;   /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
int[] sensorValues;      /** this array stores values from Arduino **/

ArrayList<Ball> balls = new ArrayList<Ball>();
ArrayList<Ball2> balls2 = new ArrayList<Ball2>();

int count1;
int count2;
int screen = 0;

boolean ballCount1 = true;
boolean ballCount2 = true;


int x3 = 0;
int y3 = 0;
int w3 = 100;
int xSpeed3 = 5;
int ySpeed3 = 5;

int x4 = 34;
int y4 = 40;
int w4 = 100;
int xSpeed4 = 6;
int ySpeed4 = 6;

int prevFrameCount;
int counter = 0;
int countDown = 3;

void setup() {
  fullScreen();
  noStroke();
  colorMode(HSB, 360, 60, 60);
  ellipseMode(CORNER);
  setupSerial();
}

void draw() {
  updateSerial();
  printArray(sensorValues);
  
  background(#FFFFFF);

  if (screen == 0) {
    title();
  } else if (screen == 1) {
    time();
  } else if (screen == 2) {
    game();
  } else if (screen == 3) {
    score1();
  } else if (screen == 4) {
    score2();
  }

  if (key == ENTER) {
    println(counter);
    if (frameCount - prevFrameCount > 60) { 
      counter = counter + 1;
      prevFrameCount = frameCount;
    }  screen = 1;
  }

    if (countDown == 0) {
    screen = 2;
    ballCount1 = true;
    ballCount2 = true;
  }

  if (count1 >= 100) {
    score1();
  }

  if (count2 >= 100) {
    score2();
  }

  if (key == TAB) {
    screen = 0;
    countDown = 3;
    for (int i = balls.size() - 1; i >= 0; i--) {
      balls.remove(i);
    }
    for (int t = balls2.size() - 1; t >= 0; t--) {
      balls2.remove(t);
    }
  }
}

void title() {
  background (#FFFFFF);
  fill (326, 20, 60, 200);
  ellipse (x3, y3, w3, w3);
  fill (199, 20, 60, 200);
  ellipse (x4, y4, w4, w4);

  x3 = x3+xSpeed3;
  y3 = y3+ySpeed3;
  if (x3 > width-w3||x3 < 0) {
    xSpeed3 = xSpeed3 * -1;
  }  
  if (y3 > height-w3||y3 < 0) {
    ySpeed3 = ySpeed3 * -1;
  }

  x4 = x4+xSpeed4;
  y4 = y4+ySpeed4;

  if (x4 > width-w4||x4 < 0) {
    xSpeed4 = xSpeed4 * -1;
  } 
  if (y4 > height-w4||y4 < 0) {
    ySpeed4 = ySpeed4 * -1;
  }

  noStroke();
  fill (#E6E5E8, 220);
  rect (360, 225, 720, 450);
  textSize(45);
  fill(200, 7, 27);
  count1 = 0;
  count2 = 0;
  text("Hit The Table to Increase", 445, 325);
  text("the Number of Circles", 480, 425);
  text("First to 100 Wins!", 525, 525);
  textSize(55);
  text("Press ENTER to Start", 450, 625);
}

void time() {
  countDown = 3 - counter;
  noStroke();
  fill (#E6E5E8, 220);
  rect (360, 225, 720, 450);
  textSize(120);
  fill(200, 7, 27);
  text(str(countDown), 672, 490);
}

void game() {
  for (int i=0; i<balls.size(); i++) {
   Ball b = balls.get(i); 
    b.move();
    b.bounce();
    b.display();
  }
  for (int t=0; t<balls2.size(); t++) {
    Ball2 c = balls2.get(t); 
    c.move();
    c.bounce();
    c.display();
  }

  if (sensorValues[1] > 700) {
    if (ballCount1 == true) {
      count1 ++;
      balls.add( new Ball(360, height/2));
    } else if (ballCount1 == false) {
    }
  }
  if (sensorValues[0] > 700) {
    if (ballCount2 == true) {
      count2 ++;
      balls2.add( new Ball2(1080, height/2) );
    } else if (ballCount2 == false) {
    }
  }

  noStroke();
  fill (#E6E5E8, 120);
  rectMode(CORNER);
  rect (30, 30, 130, 170);

  textSize(28);
  fill(200, 7, 27);
  text("Count", 53, 70);
  textSize(50);
  fill(200, 7, 27);
  text(str(count1), 50, 150);

  noStroke();
  fill (#E6E5E8, 120);
  rectMode(CORNER);
  rect (1280, 30, 130, 170);

  textSize(28);
  fill(200, 7, 27);
  text("Count", 1303, 70);
  textSize(50);
  fill(200, 7, 27);
  text(str(count2), 1300, 150);
}

void score1() {
  count1 = 100;
  ballCount2 = false;
  noStroke();
  fill (#E6E5E8, 220);
  rect (360, 225, 720, 450);
  fill (#8E5D78, 100);
  rect (380, 245, 680, 410);
  textSize(55);
  fill(180, 7, 27);
  text("VICTORY!", 595, 350);
  text("Player 1", 620, 450);
  text("Press TAB to continue", 430, 550);
  counter = 0;
}

void score2() {
  count2 = 100;
  ballCount1 = false;
  noStroke();
  fill (#E6E5E8, 220);
  rect (360, 225, 720, 450);
  fill (#5D8D8E, 100);
  rect (380, 245, 680, 410);
  textSize(55);
  fill(180, 7, 27);
  text("VICTORY!", 595, 350);
  text("Player 2", 620, 450);
  text("Press TAB to continue", 430, 550);
    counter = 0;

}

void setupSerial() {
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[ 2 ], 9600);
  // WARNING!
  // You will definitely get an error here.
  // Change the PORT_INDEX to 0 and try running it again.
  // And then, check the list of the ports,
  // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" 
  // and replace PORT_INDEX above with the index number of the port.

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

//Ball (CLASS 1)
class Ball {
  float x, y, size;
  color clr;
  float xspeed, yspeed;

  Ball(float tempX, float tempY) {
    x = tempX;
    y = tempY;
    size = random(10, 100);
    clr = color(326,random(10,30), random(30,60), 200);

    xspeed = random(-2, 2);
    yspeed = random(-2, 2);
  }

  void display() {
    fill(clr);
    ellipse(x, y, size, size);
  }

  void move() {
    x += xspeed;
    y += yspeed;
  }

  void bounce() {
    if (x < 0) {
      xspeed = -xspeed;
    } else if (x > 720) {
      xspeed = -xspeed;
    }
    if (y < 0) {
      yspeed = -yspeed;
    } else if (y > height-size) {
      yspeed = -yspeed;
    }
  }
}

//Ball2 (CLASS 2)
class Ball2 {
  float x2, y2, size2;
  color clr2;
  float xspeed2, yspeed2;

  Ball2(float tempX2, float tempY2) {
    x2 = tempX2;
    y2 = tempY2;
    size2 = random(10, 100);
    clr2 = color(180, random(10,30), random(30,60), 200);

    xspeed2 = random(-2, 2);
    yspeed2 = random(-2, 2);
  }

  void display() {
    fill(clr2);
    ellipse(x2, y2, size2, size2);
  }

  void move() {
    x2 += xspeed2;
    y2 += yspeed2;
  }

  void bounce() {
    if (x2 < 720) {
      xspeed2 = -xspeed2;
    } else if (x2 > width-size2) {
      xspeed2 = -xspeed2;
    }
    if (y2 < 0) {
      yspeed2 = -yspeed2;
    } else if (y2 > height-size2) {
      yspeed2 = -yspeed2;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
//THIS IS THE TEST CODE (WITHOUT ARDUINO, USE MOUSE PRESSED INSTEAD OF SENSORS)
//PROCESSING 
//Test (MAIN PAGE)
ArrayList<Ball> balls = new ArrayList<Ball>();
ArrayList<Ball2> balls2 = new ArrayList<Ball2>();

int count1;
int count2;
int screen = 0;

boolean ballCount1 = true;
boolean ballCount2 = true;

int x3 = 0;
int y3 = 0;
int w3 = 100;
int xSpeed3 = 5;
int ySpeed3 = 5;

int x4 = 34;
int y4 = 40;
int w4 = 100;
int xSpeed4 = 6;
int ySpeed4 = 6;

int prevFrameCount;
int counter = 0;
int countDown = 3;

void setup() {
  fullScreen();
  //size(300, 300);
  noStroke();
  colorMode(HSB, 360, 60, 60);
  ellipseMode(CORNER);
}

void draw() {
  background(#FFFFFF);

  if (screen == 0) {
    title();
  } else if (screen == 1) {
    time();
  } else if (screen == 2) {
    game();
  } else if (screen == 3) {
    score1();
  } else if (screen == 4) {
    score2();
  }

  if (key == ENTER) {
    println(counter);
    if (frameCount - prevFrameCount > 60) { 
      counter = counter + 1;
      prevFrameCount = frameCount;
    }  screen = 1;
  }

  if (countDown == 0) {
    screen = 2;
    ballCount1 = true;
    ballCount2 = true;
  }

  if (count1 >= 100) {
    score1();
  }

  if (count2 >= 100) {
    score2();
  }

  if (key == TAB) {
    screen = 0;
    for (int i = balls.size() - 1; i >= 0; i--) {
      balls.remove(i);
    }
    for (int t = balls2.size() - 1; t >= 0; t--) {
      balls2.remove(t);
    }
  }
}

void title() {
  background (#FFFFFF);
  fill (326, 20, 60, 200);
  ellipse (x3, y3, w3, w3);
  fill (199, 20, 60, 200);
  ellipse (x4, y4, w4, w4);

  x3 = x3+xSpeed3;
  y3 = y3+ySpeed3;
  if (x3 > width-w3||x3 < 0) {
    xSpeed3 = xSpeed3 * -1;
  }  
  if (y3 > height-w3||y3 < 0) {
    ySpeed3 = ySpeed3 * -1;
  }

  x4 = x4+xSpeed4;
  y4 = y4+ySpeed4;

  if (x4 > width-w4||x4 < 0) {
    xSpeed4 = xSpeed4 * -1;
  } 
  if (y4 > height-w4||y4 < 0) {
    ySpeed4 = ySpeed4 * -1;
  }

  noStroke();
  fill (#E6E5E8, 220);
  rect (360, 225, 720, 450);
  textSize(45);
  fill(200, 7, 27);
  count1 = 0;
  count2 = 0;
  text("Hit The Table to Increase", 445, 325);
  text("the Number of Circles", 480, 425);
  text("First to 100 Wins!", 525, 525);
  textSize(55);
  text("Press ENTER to Start", 450, 625);
}

void time() {
  countDown = 3 - counter;
  noStroke();
  fill (#E6E5E8, 220);
  rect (360, 225, 720, 450);
  textSize(120);
  fill(200, 7, 27);
  text(str(countDown), 672, 490);
}

void game() {
  for (int i=0; i<balls.size(); i++) {
   Ball b = balls.get(i); 
    b.move();
    b.bounce();
    b.display();
  }
  for (int t=0; t<balls2.size(); t++) {
   Ball2 c = balls2.get(t); 
    c.move();
    c.bounce();
    c.display();
  }

  ellipseMode (CORNER);
  if (mousePressed && (mouseX > 0) && (mouseX < 720) && (mouseY > 0) && (mouseY < height)) {
    if (ballCount1 == true) {
      count1 ++;
      balls.add( new Ball(mouseX, mouseY) );
    } else if (ballCount1 == false) {
    }
  }
  if (mousePressed && (mouseX > 720) && (mouseX < width) && (mouseY > 0) && (mouseY < height)) {
    if (ballCount2 == true) {
      count2 ++;
      balls2.add( new Ball2(mouseX, mouseY) );
    } else if (ballCount2 == false) {
    }
  }

  noStroke();
  fill (#E6E5E8, 120);
  rectMode(CORNER);
  rect (30, 30, 130, 170);

  textSize(28);
  fill(200, 7, 27);
  text("Count", 53, 70);
  textSize(50);
  fill(200, 7, 27);
  text(str(count1), 50, 150);

  noStroke();
  fill (#E6E5E8, 120);
  rectMode(CORNER);
  rect (1280, 30, 130, 170);

  textSize(28);
  fill(200, 7, 27);
  text("Count", 1303, 70);
  textSize(50);
  fill(200, 7, 27);
  text(str(count2), 1300, 150);
}

void score1() {
  count1 = 100;
  ballCount1 = false;
  ballCount2 = false;
  noStroke();
  fill (#E6E5E8, 220);
  rect (360, 225, 720, 450);
  fill (#8E5D78, 100);
  rect (380, 245, 680, 410);
  textSize(55);
  fill(180, 7, 27);
  text("VICTORY!", 595, 350);
  text("Player 1", 620, 450);
  text("Press TAB to continue", 430, 550);
}

void score2() {
  count2 = 100;
  ballCount1 = false;
  ballCount2 = false;
  noStroke();
  fill (#E6E5E8, 220);
  rect (360, 225, 720, 450);
  fill (#5D8D8E, 100);
  rect (380, 245, 680, 410);
  textSize(55);
  fill(180, 7, 27);
  text("VICTORY!", 595, 350);
  text("Player 2", 620, 450);
  text("Press TAB to continue", 430, 550);
}

//Ball (CLASS 1)
class Ball {
  float x, y, size;
  color clr;
  float xspeed, yspeed;

  Ball(float tempX, float tempY) {
    x = tempX;
    y = tempY;
    size = random(10, 100);
    clr = color(326,random(10,30), random(30,60), 200);

    xspeed = random(-2, 2);
    yspeed = random(-2, 2);
  }

  void display() {
    fill(clr);
    ellipse(x, y, size, size);
  }

  void move() {
    x += xspeed;
    y += yspeed;
  }

  void bounce() {
    if (x < 0) {
      xspeed = -xspeed;
    } else if (x > 720-size) {
      xspeed = -xspeed;
    }
    if (y < 0) {
      yspeed = -yspeed;
    } else if (y > height - size) {
      yspeed = -yspeed;
    }
  }
}

//Ball2 (CLASS 2)
class Ball2 {
  float x2, y2, size2;
  color clr2;
  float xspeed2, yspeed2;

  Ball2(float tempX2, float tempY2) {
    x2 = tempX2;
    y2 = tempY2;
    size2 = random(10, 100);
    clr2 = color(180, random(10,30), random(30,60), 200);

    xspeed2 = random(-2, 2);
    yspeed2 = random(-2, 2);
  }

  void display() {
    fill(clr2);
    ellipse(x2, y2, size2, size2);
  }

  void move() {
    x2 += xspeed2;
    y2 += yspeed2;
  }

  void bounce() {
    if (x2 < 720) {
      xspeed2 = -xspeed2;
    } else if (x2 > width-size2) {
      xspeed2 = -xspeed2;
    }
    if (y2 < 0) {
      yspeed2 = -yspeed2;
    } else if (y2 > height-size2) {
      yspeed2 = -yspeed2;
    }
  }
}

Recitation 10 – Alice Kwok (Leon)

For this recitation exercise, I decided to use a potentiometer to control the colour of the tint in the image on processing. I use this image:

I first make a circuit with a potentiometer and connect it to the Arduino. For this part, I used the sample code for Arduino from previous classes that allow us to send single values from Arduino to Processing. I then use another example code from the recent class which is under “ex00_pimage_get” to add the picture to processing. I modify the code so that the size of the canvas is exactly the size of the picture and delete some of the code that is not relevant to the exercise. After this, I used another sample code on Processing to send single values from Arduino to Processing. I tried to copy the codes from the image window on Processing to this window on Processing that sends the values. However, it keeps saying error and that the image could not be found. So I then tried to copy the codes from processing that sends values from Arduino to Processing that have the image. This then works, I believe the error occurred because the image is only in the specific processing file. I then play around the values to make the colour and transparency of the tint. I decided to add colourMode() to make a bigger variety of colours.

Link to the picture:

http://creativity103.com/collections/Texture/slides/brickpatternP8095293.html

//ARDUINO
int potentiometer = A1;

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


void loop() {
  int valOne = analogRead(potentiometer);
  Serial.write (valOne);

  // too fast communication might cause some latency in Processing
  // this delay resolves the issue.
  delay(10);
}

//PROCESSING
PImage img;

import processing.serial.*;
Serial myPort;

int valueFromArduino;

void setup() {
  size(640, 480);
  img = loadImage("brick.jpg");
  colorMode(HSB, 100);


  printArray(Serial.list());

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

void draw() {
  image(img, 0, 0, width, height);
  //tint(0, valueFromArduino, 255, 150);
  tint(valueFromArduino, 120, 255, 150);
  image(img, 200, 0);
  
    while ( myPort.available() > 0) {
    valueFromArduino = myPort.read();
  }
  println(valueFromArduino);
}

Recitation 9 – Alice Kwok (Leon)

Exercise 1

For this exercise, I used Arduino to Processing: Multiple Values. I think this exercise is pretty easy as I understand the concept behind it. Although it works, I think it is hard to find an adequate size for the ellipse for it to look like the drawings on Etch A Sketch.

Exercise 2

For this exercise, I used Processing to Arduino: One Value. I was a bit confused if I should use multiple values or one value for this exercise. I also played around with the tone() function to make the two tones more distinct from each other. In the end, although I did make the tones pretty distinct from each other, I cannot seem to code for a nicer sounding tone.

//EXERCISE 1
//ARDUINO

int potentiometerOne = A1;
int potentiometerTwo = A0;

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

void loop() {
int valOne = analogRead (potentiometerOne);
int valTwo = analogRead (potentiometerTwo);

Serial.print (valOne);
Serial.print (",");
Serial.print (valTwo);
Serial.println ();
}

//PROCESSING

import processing.serial.*;

String myString = null;
Serial myPort;

int NUM_OF_VALUES = 2;   /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/
int[] sensorValues;      /** this array stores values from Arduino **/

void setup() {
  size(800, 800);
  background(255);
  setupSerial();
}

void draw() {
  updateSerial();
  //printArray(sensorValues);
  println(sensorValues [0]);
  println(sensorValues [1]);

  noStroke();
  fill(#000000);
  ellipse (sensorValues [0], sensorValues [1], 20, 20);
}

void setupSerial() {
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[ 2 ], 9600);
  // WARNING!
  // You will definitely get an error here.
  // Change the PORT_INDEX to 0 and try running it again.
  // And then, check the list of the ports,
  // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" 
  // and replace PORT_INDEX above with the index number of the port.

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

//EXERCISE 2
//PROCESSING

import processing.serial.*;

Serial myPort;
int valueFromArduino;

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

  printArray(Serial.list());
  // this prints out the list of all available serial ports on your computer.
  
  myPort = new Serial(this, Serial.list()[ 2 ], 9600);
  // WARNING!
  // You will definitely get an error here.
  // Change the PORT_INDEX to 0 and try running it again.
  // And then, check the list of the ports,
  // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" 
  // and replace PORT_INDEX above with the index number of the port.
}


void draw() {
   if (mouseX > 100 && mouseY > 100) {
    myPort.write('C');
  } else {
    myPort.write('B');
  }
}

//ARDUINO

char valueFromProcessing;
int buzzerPin = 8;

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

void loop() {
  // to receive a value from Processing
  while (Serial.available()) {
    valueFromProcessing = Serial.read();
  }
  
    if (valueFromProcessing == 'C') {
     tone(8, 657, 342);
  } else if (valueFromProcessing == 'B') {
     tone(8, 487, 292);
  }

  delay(10);
}

Final Project – Alice Kwok (Leon)

Final Project Proposal Essay

Project Title

Jump Clap

Project Statement of Purpose 

This project is an interactive fun game. We decided to make a game where the users will have to move the location of the shape into the designated position through clapping. We plan to use using sensors on the Arduino (perhaps the sound sensor or maybe others) to control the graphics on processing. The loudness and consistency of the claps will affect the position of the shape. We are thinking of making this a games with different levels, from easiest to hard.

Project Plan 

To make this project work. We first have to test out the all the sensors that are relevant to the project and see which sensors collect the clearest data. Then have to set the range of each data collected from the Arduino, so that each specific range will symbolize a different height or movement on the ball. As this will be impacted by the target audience. Difference age groups might have different styles of clapping, so we have to take into account and collect different types of clapping data on different people.

Additionally, we have to design the graphics and visual on Processing for the screen. So we have to decide which shapes we are using, where each designated location on each level will be, how many levels, the colour theme for each level, how to control the difficulty of each level (size of the shape? movement of the shape? the number of shapes? time limit?). We also have to design a physical device to put the sensor and Arduino to make the user experience better. It’s also important to create a reset function on the screen so that users can reset the screen, perhaps through keys/mouse on Processing, or perhaps even a sound command, or switch button on Arduino

We could consider making it a multiplayer game and more competitive game, so people compete with each other (at the same time) by clapping and see which shapes get into the designated space first.

Context and Significance 

A reason why we choose to make a game using body movement is that we aim to make a game that users can physically interact with rather than just use keys and mouse. Users have to use their own body movement to control the things on the screen. This will make the users more focus and be more involved with the game.

A reason why we choose clapping is that the act of clapping is a positive action and most often have a positive connotation. After researching online, I also realised clapping have health benefits too. So this is really amazing. Clapping can help with blood pressure and blood circulation in the body. I tried to research some projects that use clapping for interaction. Most of the projects I find is using the number of claps to control the LED/light by turning on or off.

The project aligns with my definition of interaction which is:

Interaction is a process that contains an action by any party which causes an effect of varying degree on at least one other party or more. The parties in this process are not limited to living things such as humans and animals but also to inorganic substances such as rocks, electronics, and water.

I think this projects really shows the “causes an effect of varying degree” since we are technically using this idea to challenge the users/players by controlling their claps to cause an effect of varying degree. So in a sense, we are asking users to purposefully control their interaction, specifically their effects to be able to win the game.

This project can be extended so instead of clapping, you can use your voice to control the shapes on the screen. This could become some singing games. You can also incorporate it to perhaps virtual reality to create a game so that users are using the movement of their body and also their senses to play the game.

 

Recitation 8, Final Project Process – Alice Kwok (Leon)

A. 

My definition of interaction during the group project was “the action of transmitting (input) and receiving (output) information between more than one party.” I think during that time we only learn about Arduino and in some sense, Arduino does need an input and an output to cause some sorts of interaction. So my definition of interaction is limited to that area.

B. 

Now, I think about interaction in a broader sense. I think interaction is an action between more than one party (does not necessarily have to be between human but also objects, electronics and screens) and there are some sorts of effect from that action. I think more view change a lot since learning about processing because using keyboard or mouse and ‘interacting’ with the objects on the screen would not be considered as conventional interaction, but still, it is a form of interaction.

C. 

A project that aligns with my definition of interaction:

Putting the Pieces Back Together Again is a project by Ralf Baecker, in this project, there is 1250 stepper motor with a pointer at the surface which spins at a random direction at the same current. The pointer is at a longer length so it will hit the neighbour pointers which cause it to then spin at an opposite direction and so on. This project aligns with my definition of interaction because this is very much an interactive piece of artwork. Although it is not between humans and humans or humans with other objects, the pointers are very much interacting with each other through hitting (cause) and then spinning in another direction (effect).

A project that clashes with my definition of interaction:

These arts made from sand are something that clashes with my definition of interaction. I think these types of arts are something that is the opposite of interaction. Because to interact with these arts, you could very well damage those art pieces since they are made from sand. So with these types of arts or project, my definition of interaction will never exist.

D. 

Interaction is a process that contains an action by any party which causes an effect of varying degree on at least one other party or more. The parties in this process are not limited to living things such as humans and animals but also to inorganic substances such as rocks, electronics, and water.

In-Class Exercise (18) – Alice Kwok (Leon)

Exercise One:

Exercise Two:

// EXERCISE ONE

int a = int (random(999));
int b = int (random(999));
int c = int (random(999));
int d = int (random(999));
int e = int (random(999));
int f = int (random(999));
int g = int (random(999));
int h = int (random(999));

int [] Numbers = {a, b, c, d, e, f, g, h};
printArray (Numbers);


// EXERCISE TWO

int [] sizeValues = {200, 100, 50, 80, 70};
int [] posX = {150, 450, 350, 250, 550};
int [] posY = {150, 450, 200, 310, 350};


void setup() {
  size(600, 600);
  background(255);
}

void draw() {
  for (int i = 0; i < 5; i++){
  drawFace(sizeValues[i], posX[i], posY[i], color(250,106,166));
  }
}


void drawFace(int size, float x, float y, color c) {
  noStroke();
  fill(c);  
  ellipse(x, y, size, size);
  fill(255);
  ellipse(x-size*0.3, y-size*0.1, size*0.05, size*0.05);
  ellipse(x+size*0.3, y-size*0.1, size*0.05, size*0.05);
  arc(x, y, size*0.6, size*0.6, 0, PI);
}

Recitation 7 – Alice Kwok (Leon)

Recitation Exercise:

So I decided to animate the drawing I did in the last recitation which is this:

At first, I plan to make it so the shapes around the circle will rotate continuously. However, after working with it and asking for the professor’s help, I realised in order to create the effect I want there are a few problems. First, is that I have to alter the coordinates for all of the lines so that their center (0, 0) will be the (0, 0) that I input the code. Second, is that if I did change all of the coordinates, I have to figure out a way to make it rotate continuously. So I end up switching to another idea.

Then, I decided to make the circle in the middle to grow bigger and smaller, so that it seems like the shapes around it are putting energy into it. I did that using boolean and using conditional statements. A small problem I ran into is I got really confused on where to put the code for the white background since if I put it in void setup() it will show the whole process of the circle getting bigger and smaller. Thus, making a big black hole in the middle. However, if I put it at the top in void draw() all of my other shapes will disappear except for the circle. After trying out multiple methods, I manage to make it so that when you first run the code, a blank page will appear, and the buttons you press will cause all the other images to appear.

I also added a colour change in the drawing. At first, I used the random function with RGB to make the animation for colours. However, later after I finished working on the recitation homework, I change the code for my recitation exercise since the colour change in the homework since it is much prettier and nicer to look at than my original animation in the exercise. So I switched it. I’ll talk more about the colours in the recitation homework. I added a frameRate to made the transition of colours and the movement of the circle more mellow and slower. Since before the transition (especially the yellow colour) is very irritating to the eyes since it changes too quickly. So I made it slower using a frameRate.

I also insert conditional statements with keys. So there are two key types of functions in this exercise, first is the tab key. So when you press tab, a black and white version of the animation will appear. In this animation, there are no colour change but the small circle in the middle will become bigger and smaller. If you press enter, a colourful version of the animation will appear. In this animation, there are both colour change and the animation of the circle. I decided to make a black and white version other than a colour version is because since when you first originally run the code it will appear a blank screen. So I thought it will be a bit too simple if there will only be an animation of colours with the circle with one key pressed. So I made it, that there are two keys you can press to alternate the colour schemes.

Recitation Homework:

So first I work on making the circle become bigger and smaller. I did not have a big problem working on it because I use the same code that I use to make the circle in my recitation exercise bigger and smaller.

I then work on coding the colours of the stroke of the circle. This was really confusing for me at first, as I do not really know how to use colourMode(). I put the colourMode() into void setup() and made it so the colours will be written in HSB. I then went to the colour selector, and play through the colours to see what does h, s, b stands for and what colours match the image that was presented to us on the recitation. I then make the colour change base on the hue with a conditional statement.

Next step I did was to code it so that the circles will listen to the commands of the keys (up, down, right, left), I use the key function to code it. I left the code in a way that for example if you press up the circle will keep going up without stopping instead of having to repeatedly press the up button. I had some difficulty with making the screen the border for the circle. I made use of the idea from the in-class exercise when we make the ball bounce inside the screen. So I set up conditional statements stating the maximum and minimum values of the x position and y position of the circle. However, the circle will always be halfway outside of the canvas before it stops. I then try to minus the strokeweight from the maximum and minimum values thinking that that might be the problem. However, it still doesn’t work. So I try to minus the radius from the maximum and minimum values, and it works.

//RECITATION EXERCISE
int hue = 0;
boolean Circle = true;
int radius = 10;

void setup() {
  frameRate (10);
  size (600, 600);
  colorMode(HSB, 100);
}

void draw() {
  background (#FFFFFF);

  if (key == ENTER) {
    stroke (hue, 155, 155);
    fill (hue, 155, 155);
    hue++;
    if (hue > 100) {
      hue = 0;
    }

    line(100, 100, 285, 285);
    line(315, 315, 500, 500);
    line (100, 500, 285, 315);
    line (500, 100, 315, 285);

    line(215, 196, 285, 285); //first diamond shape
    line(196, 215, 285, 285); //first diamond shape
    line(100, 100, 196, 215); //first diamond shape
    line(100, 100, 215, 196); //first diamond shape

    line(430, 411, 500, 500); //second diamond shape
    line(411, 430, 500, 500); //second diamond shape
    line(315, 315, 430, 411); //second diamond shape
    line(315, 315, 411, 430); //second diamond shape

    line(198, 420, 100, 500); //third diamond shape
    line(285, 315, 198, 420); //third diamond shape
    line(175, 406, 100, 500); //third diamond shape
    line(175, 406, 285, 315); //third diamond shape

    line (411, 205, 315, 285);
    line (411, 205, 500, 100);
    line (407, 179, 315, 285);
    line (407, 179, 500, 100);

    line (300, 50, 300, 285);
    line (313, 176, 300, 285);
    line (313, 176, 300, 50);
    line (287, 176, 300, 285);
    line (287, 176, 300, 50);

    line (300, 550, 300, 315);
    line (287, 430, 300, 550);
    line (287, 430, 300, 315);
    line (313, 430, 300, 550);
    line (313, 430, 300, 315);

    line (550, 300, 315, 300);
    line (430, 289, 315, 300);
    line (430, 289, 550, 300);
    line (430, 311, 315, 300);
    line (430, 311, 550, 300);

    line (50, 300, 285, 300);
    line (169, 289, 285, 300);
    line (169, 289, 50, 300);
    line (169, 311, 285, 300);
    line (169, 311, 50, 300);

    noStroke();
    ellipse(width/2, height/2, radius, radius);
  }

  if (key == TAB) {
    stroke (161, 98, 0);
    fill (161, 98, 0);
    line(100, 100, 285, 285);
    line(315, 315, 500, 500);
    line (100, 500, 285, 315);
    line (500, 100, 315, 285);

    line(215, 196, 285, 285); //first diamond shape
    line(196, 215, 285, 285); //first diamond shape
    line(100, 100, 196, 215); //first diamond shape
    line(100, 100, 215, 196); //first diamond shape

    line(430, 411, 500, 500); //second diamond shape
    line(411, 430, 500, 500); //second diamond shape
    line(315, 315, 430, 411); //second diamond shape
    line(315, 315, 411, 430); //second diamond shape

    line(198, 420, 100, 500); //third diamond shape
    line(285, 315, 198, 420); //third diamond shape
    line(175, 406, 100, 500); //third diamond shape
    line(175, 406, 285, 315); //third diamond shape

    line (411, 205, 315, 285);
    line (411, 205, 500, 100);
    line (407, 179, 315, 285);
    line (407, 179, 500, 100);

    line (300, 50, 300, 285);
    line (313, 176, 300, 285);
    line (313, 176, 300, 50);
    line (287, 176, 300, 285);
    line (287, 176, 300, 50);

    line (300, 550, 300, 315);
    line (287, 430, 300, 550);
    line (287, 430, 300, 315);
    line (313, 430, 300, 550);
    line (313, 430, 300, 315);

    line (550, 300, 315, 300);
    line (430, 289, 315, 300);
    line (430, 289, 550, 300);
    line (430, 311, 315, 300);
    line (430, 311, 550, 300);

    line (50, 300, 285, 300);
    line (169, 289, 285, 300);
    line (169, 289, 50, 300);
    line (169, 311, 285, 300);
    line (169, 311, 50, 300);

    noStroke();
    ellipse(width/2, height/2, radius, radius);
  }

  if (Circle) {
    radius--;
    if (radius == 0) {
      Circle = false;
    }
  } else {
    radius ++;
    if (radius == 20) {
      Circle = true;
    }
  }
}


// RECITATION HOMEWORK

boolean Ellipse = true;
int radius = 150;
int hue = 0; 
int PositionX = 300;
int PositionY = 300;

void setup() {
  size (600, 600);
  colorMode(HSB, 100);
}

void draw () { 
  background (#FFFFFF);
  ellipseMode (CORNER);
  strokeWeight (20);
  stroke (hue, 100, 100);
  hue++;
  if (hue > 100) {
    hue = 0;
  }
  ellipse (PositionX, PositionY, radius, radius);

  if (Ellipse) {
    radius--;
    if (radius == 100) {
      Ellipse = false;
    }
  } else {
    radius ++;
    if (radius == 200) {
      Ellipse = true;
    }
  }

  if (keyCode == UP) {
    PositionY = PositionY - 1;
  }

  if (keyCode == DOWN) {
    PositionY = PositionY + 1;
  }

  if (keyCode == LEFT) {
    PositionX = PositionX - 1;
  }

  if (keyCode == RIGHT) {
    PositionX = PositionX + 1;
  }

  if (PositionX > width-radius) {
    PositionX = width-radius;
  }
  if (PositionX < 0) {
    PositionX = 0;
  }
  if (PositionY > height-radius) {
    PositionY = height-radius;
  }
  if (PositionY < 0) {
    PositionY = 0;
  }
}

In-Class Exercise (17) – Alice Kwok (Leon)

Exercise One:

For this exercise, I decided to make it so that every time you click on your mouse, there will be a new circle with random colours on the canvas. I also set it up so that any keys you pressed will refresh the canvas into a blank page.

Exercise Two:

I used the for loops for this exercise. I copied the coordinates of each segment of the lines and put in into the for loop.

//EXERCISE ONE
void setup() {
  size(500, 500);
  background(255);
}
void draw() {
  int r = int(random(0, 255));
  int g = int(random(0, 255));
  int b = int(random(0, 255));

  if (mousePressed) {
    fill(r, g, b);
    noStroke();
    ellipse (mouseX, mouseY, 50, 50);
  }

  if (keyPressed) {
    background(255);
  }
}


//EXERCISE TWO

void setup() {
  strokeWeight(4);
  size(600, 600);
  rect(0, 0, width/2, height/2);
  rect(width/2, 0, width/2, height/2);
  rect(0, height/2, width/2, height/2);
  rect(width/2, height/2, width/2, height/2);

  for (int i=0; i<15; i++) {
    line(s*i, 0, s*i, width/2);
  }

  for (int i=0; i<15; i++) {
    line(width/2, s*i, width, s*i);
  }


  for (int i=0; i<16; i++) {
    line(0, height/2 + s*i, s*i, width/2);
  }

  for (int i=0; i<16; i++) {
    line(s*i, height, width/2, height/2 + s*i);
  }

  for (int i=0; i<16; i++) {
    line(width/2 + s*i, height/2, width + s*i, height);
  }

  for (int i=0; i<16; i++) {
    line(width/2, height/2 + s*i, width - s*i, height);
  }
}

In-Class Exercise (16) – Alice Kwok (Leon)

Our task is to use conditionals to make the ellipse (ball) to always move inside the screen. I decided to separate the speed into xSpeed and ySpeed in order to monitor the ellipse more clearly. A small problem I had was that the ellipse will bounce off the screen at x-axis but not at y-axis. After asking for some help, I change y to height instead of width (like in x) which solve the problem. For a small effect, I added ellipseMode(CORNER) so that the ellipse will bounce off the screen after the corners have reached the limit of the canvas.

 

int x = 0;
int y = 0;
int w = 50;
int xSpeed = 5;
int ySpeed = 5;


void setup() {
  size(320, 240);
}

void draw() {
  background(0);
  ellipseMode(CORNER);
  ellipse(x, y, w, w);
  x = x+xSpeed;
  y = y+ySpeed;

 if (x > width-w||x < 0) {
  xSpeed = xSpeed * -1;
}

 if (y > height-w||y < 0) {
  ySpeed = ySpeed * -1;
}
}

Recitation 6, Processing Basics – Alice Kwok (Leon)

This is the picture I choose from the Art of Computer Designing:

I really like this type of drawings such as mandala, so I decided to pick this picture. Looking at this picture, I decided to use the line function to create the shapes coming out of the middle and substitute the dark centre with a small black circle. However, after I start to code in processing I realised it is extremely difficult for me to calculate the coordinates for each line. I really struggled to calculate the numbers to make all of those lines the same size and symmetrical with each other. So in the end, I only ended up making 8 shapes coming out from the centre instead of the 12 shapes in the original picture. Although the drawing I created from processing is not as ‘full’ as the original picture nor as proportionate, I still think that it is of a similar style. I think with more practice and more in-depth math calculations I could refine my current drawing on processing.

My Drawing:

 

size (600, 600);
background (#FFFFFF);
line(100, 100, 285, 285);
line(315, 315, 500, 500);
line (100, 500, 285, 315);
line (500, 100, 315, 285);

line(215, 196, 285, 285); //first diamond shape
line(196, 215, 285, 285); //first diamond shape
line(100, 100, 196, 215); //first diamond shape
line(100, 100, 215, 196); //first diamond shape

line(430, 411, 500, 500); //second diamond shape
line(411, 430, 500, 500); //second diamond shape
line(315, 315, 430, 411); //second diamond shape
line(315, 315, 411, 430); //second diamond shape

line(198, 420, 100, 500); //third diamond shape
line(285, 315, 198, 420); //third diamond shape
line(175, 406, 100, 500); //third diamond shape
line(175, 406, 285, 315); //third diamond shape

line (411, 205, 315, 285);
line (411, 205, 500, 100);
line (407, 179, 315, 285);
line (407, 179, 500, 100);

line (300, 50, 300, 285);
line (313, 176, 300, 285);
line (313, 176, 300, 50);
line (287, 176, 300, 285);
line (287, 176, 300, 50);

line (300, 550, 300, 315);
line (287, 430, 300, 550);
line (287, 430, 300, 315);
line (313, 430, 300, 550);
line (313, 430, 300, 315);

line (550, 300, 315, 300);
line (430, 289, 315, 300);
line (430, 289, 550, 300);
line (430, 311, 315, 300);
line (430, 311, 550, 300);

line (50, 300, 285, 300);
line (169, 289, 285, 300);
line (169, 289, 50, 300);
line (169, 311, 285, 300);
line (169, 311, 50, 300);

fill (#000000);
ellipseMode (CENTER);
ellipse(300, 300, 20, 20);