Interface and application programming

Federico, 22 April 2020

The assignments of this first week were:

  1. Individual Assignment: write an application that interfaces a user with an input &/or output device that you made.
  2. Group Assignment: Compare as many tool options as possible.

Link to the lesson. Link to the videolesson.

Learning Processing

Since I always heard of Arduino was built on this environment I thought that would be easy to start with it. Both My instructor Antonio and one of my friend have suggested me to start watching the Processing tutorial made by Daniel Shiffman. The tutorial is very understandable, I would suggest it to a beginner that never have started to program.

Link to Processing and to its reference.

There is also a javascript library for processing p5.js, but it’s not my intention to use it now.

Programming Pong

This is the first time I programmed with Objects, I only have used C in some university courses. For this week I started thinking about programming a simple Pong game where the players are controlled by hands with ultrasonic sensor. I was thinking of using Arduino for collecting ultrasonic sensor data and then using the serial protocol to send data to processing.

Basically is the idea of control the player of pong with the hand without touching anything, the ultrasonic sensor is detaching the distance from the hand.

alt

Starting from bare minimum, the basic structure of processing sketch is:


//initializing classes and global variables

void setup(){
// initialization of variables or classes here, this will run once 

}

void draw(){
// the looping function that continues to draw thingsobjects in the processing window
}

and here is the summary scheme to build a class:

Class Classname{

// first af all, define some PARAMETERS of the class of object you're going to use 
//remember to name the classes with the first capital letter or someone will get angry
...


//then you have to set up the CONSTRUCTOR: this will be used to build new object. 
...


//then you can start associate FUNCTIONS to this class.
...

}

after I started thinking of how to create a Class for the Ball and about some parameters that are essential:


 //************************** Ball Class

class Ball{      // I set up the player class
 
// about dimension 
  float r;          //setting the radius of the ball
 
// about initial position
  float xpos;      // this variables contains the (x,y) coordinate of the ball
  float ypos;      
//about movement 
  float xspeed;
  float yspeed;     // setting the speed of the ball while it's moving
  float factor;     // increase the factor to accelerate the ball
  int   x_sign=1;       // change sign to change direction 
  int   y_sign=1;       // 
//about color
  color rgbvalue;  // setting the color of the ball
  
  

I tried to keep them well organized.

! ! ! Be Careful ! ! !

You can define a different number of constructor for every class. That’s because in some cases is more convienient initialize an object in many different ways. In my case I decided to define two types of constructors. Remember that you can define new variables and do some stuff while you are creating the >object: I decided to do the random initialization for the first time the ball will >appear and to set the speed factor factor to 1;

So here is how I coded my constructors:

 Ball(float radius, float tempInitialXpos, float tempInitialYpos,float tempXspeed, float tempYspeed, color temprgbvalue){    // I define the constructor of the ball
   
   r = radius;
   xpos = tempInitialXpos;
   ypos = tempInitialYpos;
   xspeed = tempXspeed;
   yspeed = tempYspeed;
   rgbvalue = temprgbvalue;
   
   // sign random initialization, random ball start , this procedure will start at the making of the new object
   
   factor = 1;
   
   int[] numbers_random_array = { -1 , 1 };
   int i = int(random(numbers_random_array.length)); // this will generate random index between 0 and 1 ,the index 2 is not included in this case.
   x_sign = numbers_random_array[i];
 
   }
    
 Ball(float radius, float tempInitialXpos, float tempInitialYpos,float tempXspeed, float tempYspeed){    // I define the constructor of the ball
   
   r = radius;
   xpos = tempInitialXpos;
   ypos = tempInitialYpos;
   xspeed = tempXspeed;
   yspeed = tempYspeed;
   
   rgbvalue = color(258,162,0); 
   
   // sign random initialization, random ball start , this procedure will start at the making of the new object
   
   factor = 1;

   
   int[] numbers_random_array = { -1 , 1 };
   int i = int(random(numbers_random_array.length)); // this will generate random index between 0 and 1 ,the index 2 is not included in this case.
   x_sign = numbers_random_array[i];
 
   }

and then I started think about functions:

class Ball {
...//parameters
...//constructors

void display(){
  // this is only for displaying the ellipse 
}

void moveandscore(){
  // this is for moving and scoring the points of the player.
}

void restart(){
  //this is for place the ball at the center of the window once the ball reached on vertical edge of the window
}

void edgedetection(){
  //this is only for detecteng the collision between ball and players
}

void void measure_dist_real(Player player){
  // this is a debug function for measuting the distance from the nearest edges of the shape
}

}

The display() function

 void display(){

   fill(rgbvalue);      // I decide the the color that I want to fill the ball, 1 parameter for grayscale value, 3 parameter for a rgb value
   stroke(0,255,0);     // I decide the the color that I want to fill the contour of the ball, 1 parameter for grayscale value, 3 parameter for a rgb value
   ellipseMode(CENTER); // THE X AND Y position are referred to the center of the ellipse
   ellipse (xpos,ypos,r,r); // generation function for the ball

 }

in this function you have to call three function before you call the ellipse(); function, they are describing the characteristics of the ellipse that will be drawn. remember that rgbvalue is initialized inside the costructor in the same function as:

rgbvalue = color(258,162,0);

We need to told Processing that this vector is a color, listing the three component of the colors, respectively Red,Green,Blue component. We have to use with a 8 bit value. (8 bit value goes from 0 to (2^8)-1=255, 255 is the maximum value.) Otherwise we can decide to put the three component directly as argument of the function as I did in the stroke(); function.

ellipseMode() is the function we need to call to tell that the next ellipse() function will be drawn in in respect to different origin point. In my case I choose to draw with the ellipseMode(CENTER) , specifing that the x position and the y position of ellipse (xpos,ypos,d,d); are referred to the center of the ellipse. The function ellipse has 4 arguments:

ellipse(a, b, c, d)

a	float: x-coordinate of the ellipse      => xpos
b	float: y-coordinate of the ellipse      => ypos
c	float: width of the ellipse by default  => d = diameter of the ball  
d	float: height of the ellipse by default => d = diameter of the ball

It’s convenient to use a variable like xpos for a and ypos for b if you want to keep the ellipse moving.

So basically this function is displaying an ellipse of the framerate if called in the draw function.

The moveandscore() function

void moveandscore(){ // it's convenient to move and score together without risking that one score is not counted because the position has altready been resetted.
   xpos = xpos + (xspeed * factor * x_sign );
   ypos = ypos + (yspeed * factor * y_sign );
  
  if (xpos >= player_R.xpos){
     player_R.score++;
  }
  
  if (xpos <= player_L.xpos){
     player_L.score++; 
  }
  
  if (xpos >= (width-(d/2)) || xpos <= (d/2) ){ // once the ball touched the edge of the windows, call the restart routine
    restart();   
  }
  
  if (ypos >= (height-(d/2)) || ypos <= (d/2) ){ // once the ball touched the upper or the lower of the windows, invert the sign of yspeed component
    y_sign = (y_sign)*(-1);                      //inverting the value of y_sign  
  }
   
 }

Everytime this function is executed we need to update the ball position, so I decided to structure the incremental mechanism as

  xpos = xpos + (xspeed * factor * x_sign );

this is the better way the keep track of the positioning system, everytime xposition incremented by (xspeed * factor * x_sign ), this is conceived as follow:

  1. xspeed : this is the initial spees factor
  2. factor : this is for incrementing and decreasing the speed, is value is only positive and is greater than zero. This is initialized at 1 at the moment of the object is built.
  3. x_sign : this is a variable that only can have to value: “-1” or “1”. This is needed to keep track of the direction of the ball on the x axis.

then I coded the conditional statement for increasing point, this is very easy:

! ! ! Be careful ! ! !

it’s really important to refer everytime to absolute values of the programs. e.g. you can refer to heigth and width of the windows if you don’t want to manually change parameters of configuration inside the if statements, etc.. everytime!!

the conditional statements that let the ball bounces on the horizontal edges of the windows are:

if (xpos >= player_R.xpos){
     player_R.score++;
  }

 if (xpos <= player_L.xpos){
     player_L.score++; 
  }

! ! ! Cool thing ! ! !

You can easily access to the parameters of the other objects by writing <nameoftheobject>.<hisparameteryouwanttoaccess>

and the if statement that reposition the ball at the center of the screen is

 if (xpos >= (width-(d/2)) || xpos <= (d/2) ){ // once the ball touched the edge of the windows, call the restart routine
    restart(); 

The restart() function

this is very similar to the initialization inside the construcor of the object so one piece of code is similar.

void restart(){
    
   // start from the center of the screen
   
   xpos=width/2;
   ypos=height/2;
   
   // then start moving in a random direction, but first reset the factor speed at 1
   
   factor = 1;
   
   // sign random initialization, random ball start , this procedure will start at the making of the new object
   
   int[] numbers_random_array = { -1 , 1 };
   int i = int(random(numbers_random_array.length)); // this will generate random index between 0 and 1 , 2 is not included in this case.
   x_sign = numbers_random_array[i];
   
 }

the only thing that it changes is that everytime we have to initialize from the center of the screen.

The edgedetection() function

This is a critical part, every code I wrote is very buggy but works well for the detection with the vertical edge of the player.

I decided to use the approach of dividing the problem in 5 cases

alt

so I tried to write a nested if statement like this :

 if  ( abs(xpos-player_R.xpos)  == ( (d/2) + (player_R.dimXWidth)/2)  ){     // for Player_R , when the horizontal edge is detected...
      if( abs(ypos-player_R.ypos) <= ( (d/2) + (player_R.dimYHeigth/2) ) ){
         x_sign = (x_sign)*(-1);
       }
   }
   
   if ( abs(ypos-player_R.ypos) == ((d/2) + (player_R.dimYHeigth)/2)){
     if ( ( (  (player_R.xpos-(player_R.dimXWidth/2))<=xpos) && (xpos<=(player_R.xpos+(player_R.dimXWidth/2)) )   )  )
           y_sign = (y_sign)*(-1);
   }

I use the absolute difference operatorabs() to do the differeces between coordinates (that can led to a negative result) to compare them to the dimension of the shapes. This is a really aproximate as the physics of the 2D bounce is not well decribed by this function.

I tried a different approach thinking about comparing the angle. But this will happen only when the distanse between the two nearest edges of the shape are touching. Then if you have a certain angle “α” calculate between the two centers of the shapes. After comparing “α” to the “ß” angle you can know if the ball will bounce on the horizontal/vertical side of the player.

alt

In this picture I tried to sketch the behaviour of the ball bouncing near to the edges of teh rectangle

measure_dist_real(Player player) function

so I think it would be nice to have a function that calculate the distance between the nearest edges, so I tried to sketch a quick graphic calculation:

alt

  void measure_dist_real(Player player){     
     float dist_real;
     float angle;
     
     angle = atan (abs(ball.ypos-player.ypos)/abs(ball.xpos-player.xpos));    // calculating the angle
     dist_real = dist(ball.xpos,ball.ypos,player.xpos,player.ypos) - ball.d - ((player.dimXWidth/2)/cos(angle));
     
     if(dist_real<=1)
     println("touched!");
     
     println("angle"+angle);
     println("distance   "+dist_real);
   }

then I added the conditional statement to give time to the computer to see if the real distance is less or equal to one: as you can see from the image the code works but the distance smaller than one is not detected sometimes.

alt

Player class

The player class was more easy to do. I think the best way to write code is to build class together as you are thinking the parameters you are missing.

I ended up with a class player like this:


//****************************** Player class
class Player{      // I set up the player class
 
  int dimXWidth;        // setting the value of the player dimension
  int dimYHeigth;
 
  float xpos;      // this variables contains the (x,y) coordinate of the player
  float ypos;      
 
 
 //relative position respect the ball
  float distance_ball=-1;  // the initial distance that that player has from the ball is set  negative.
   
   
  float yspeed;    // reading the speed of the player while it's moving, not used for now
  
  color rgbvalue;  // setting the color of the player
  
  int score;       //setting up the score
  
  
                            //I specify more than one constructor for this type of object
  
 // constuctor number one, complete
Player( int tempDimX, int tempDimY, float tempInitialXpos, float tempInitialYpos, float tempYspeed, color temprgbvalue){
   
   dimXWidth = tempDimX;
   dimYHeigth = tempDimY;
   
   xpos = tempInitialXpos;
   ypos = tempInitialYpos;
   
   yspeed = tempYspeed;
   rgbvalue = temprgbvalue;
   
   score=0;            // Once the object is built the score starts from zero
 
   }
   
   
  // constructor number 2 , without the colors 
  Player( int tempDimX, int tempDimY, float tempInitialXpos, float tempInitialYpos, float tempYspeed){
   
   dimXWidth = tempDimX;
   dimYHeigth = tempDimY;
   
   xpos = tempInitialXpos;
   ypos = tempInitialYpos;
   
   yspeed = tempYspeed;
   rgbvalue = color(255,0,0);
   
   score=0;            // Once the object is built the score starts from zero
 
   }
   
 
 void display(){
    stroke(0);
    fill(rgbvalue);
    rectMode(CENTER);          // keep the xpos,ypos at the center of the rect
    rect(xpos,ypos,dimXWidth,dimYHeigth);
 }
  
 void move(){ // remember that the player can't move on the x- axis in pong.
     ypos= mouseY;
   
    if( ypos >= ( height - int(dimYHeigth/2) )  ) {    // lower ypos bound
      ypos = height - int(dimYHeigth/2); 
    }
   
     if(  ypos <= (dimYHeigth/2)){                  // upper ypos bound
         ypos = (dimYHeigth/2); 
     }
     
     
 }

}

I can say that the behaviour it’s the same but more bounded, so I need to write less parameters.

Success

I have to say that it’s very satisfing made something work after lot of time without programming, the game -as is- isn’t very funny, but I think it will be a good starting point for a nice project!

For now, I put the Y-axis control of the player just to test the game, so even you’re alone, you can try it!

alt

Some Issues

  1. one of my first issues was that I didn’t put background in the void draw() function, so my real background wasn’t the one that I was expecting

  2. this is one of my problem that I found mistakenly exchanged the Width and Heigth dimension of the two rectangle draw function

alt

  1. The variable “angle” that contains the valure of the angle between formed by the center of the player and the ball is printer out in Radiant, according to the Processing Reference. Also the function “cos” is working right with radiant values. Check the official reference below:

alt

alt

Remember that the formula conversion for print out degrees angle is:


angle_degrees = (angle_radiant*180)/PI;

  1. Another problem is the dist_real variable becoming negative as showed below:

alt

I really can’t figure out why is happening, but I think that the calcuations of the distance isn’t done every step the balls move. In that way there are some misrepresented values.

Even Tough, I find that using if I use the OpenGL-compatible graphics hardware, the better results are given:

alt

This is really useful for let your Processing sketches running faster! It’s possibile to do declaring the initial windows size in this way:


  size(1000,800,P2D); // setting the draw area with P2D support

  1. Sometimes the ball tries to run away between the players’ corners and probably this can be fixed using the dist_real variable in a strategic way, even if this is a really heavy continuos calculus, I think. With this function we can find the right bounce axis of the ball when is colliding with the player.

Optional improvement

  1. If you don’t want to care too much about the vertical side bouncing you can reduce the width of the player (best trick ever) 😁

  2. one cool thing to do is to add sounds when shapes are touching.

  3. The original Pong game has more feature: for example , you can let the ball move faster when you hit it with a fast move of the player. Also, The score of the players is missing.