openobject.org

Final-bouncy balls

From Physical Programming

Image:BANNER.jpg


Contents

INTRODUCTION

Having decided to use processing and the platform for my project I had ambitions to make a life and death style game with several variables. Once attempting processing in the first couple of weeks I decided to change my direction and to do a much more simple program well rather than a complex program really poorly. My focused shifted and I decided to try to make a program where by balls would be able to fly around the screen and would be able to detect the walls of the window and each other. This was final outcome, the balls can do both of these functions and have several inputs that can be altered to create a different visual display. Some of the inputs can be change while the program is running, inputs like the colour, velocity, and scale of the bounce reaction. While this is not the most elaborate program what it sets out to display I believe it achieves quite well, this was a challenge for me and proved to be a good project for this semester.

While this semester has been a trying one for me as this class was not exactly what I though it was going to be and this was my first encounter scripting which I discovered is not one of my strengths there has been some benefit. The processing format has made work with the aduino's easier to understand as they use the same style program and interface. All in all i have found this class like a roller-coaster at stages being engaging and challenging while at other times overwhelming and impossible, but the class itself has been fun and most enjoyable.


ABSTRACT

This program intends to graphically display a cause and effect reaction between a group of balls as they pass their kinetic energy from one to the other. They are constrained by the size of the window and have a universal mass. The power of the collision reaction between the balls can be manipulated by the user through using the UP and DOWN keys, other possible manipulations include colour and speed. These possibilities are just a click of the mouse away.


OUTLINE

This project was created as a requirement for industrial design, physical programming class. The initial concept was to create a emergent program using processing as the platform. I quickly became aware that this was beyond my abilities and while still trying to reach this goal I created this programming.

Bouncy balls is a program that is graphically demonstrates what it names suggests. Several balls are created on the screen, with several different variables.

  • 1. Each ball has a randomly generated colour.
  • 2. Each ball has a randomly generated velocity.
  • 3. Each ball has a randomly generated direction.

The balls are restricted buy several universal boundaries.

  • 1. They are restricted by the size of the screen.
  • 2. The balls cannot overlap with each other.

When these conditions occur they bounce.


STEPS ALONG THE WAY

These are only the major steps that I archived in creating this program, to show all the steps would be a semesters work in itself.

Step 1

  • Mastering the class structure and the initial setup for the program.

Step 2

  • Adding to the class structure and my first attempt at both wall bouncing and collision detection

Step 3

  • Mastering the collision detect and working out problems in the script, mainly with the wall detection.

As I progressed with this program I was creating several smaller projects along the way in order to test things that I may want to implement with in this project, things like keyCoding, mouseCoding. These small project may not all work but they allowed me to break down the bigger picture and make it less overwhelming.


THE FINAL PROGRAM

Universal variables

Universal variables that can be adjusted.

  • int numBalls = 12; - is the initial number of balls.
  • Circles[] circlearray = new Circles[numBalls]; - Allows multiple numbers of the same class to be called in a array, this allows all the balls to have the same properties. (see class below)
  • float intensity = 0.2; - is the strength of the bounce reaction.
  • boolean menutrigger= false; - is the status of the menu JPEG false = off. A boolean is a function that has only 2 states, true or false.
 int numBalls = 15;
 Circles[] circlearray = new Circles[numBalls];
 float intentsity = 0.1;
 boolean menutrigger = false;


Void setup

The void setup is called once during the running of this program and sets up the basis.

  • size - refers to the size of screen 800x800 pixels.
  • smooth - smooths the visual appearance necessary for any movement.
  • frame rate - assigns a frame rate to the animation.
  • fillpositionCircles - calls the randomization function for the initial x and y starting points.
  • velocitychange - calls the randomization function for the initial x velocity and the y velocity.
  • initialcolour - calls the randomization function for the initial colour of the balls.

void setup() {

 size(800, 800);
 smooth();
 frameRate(60);
 for (int i = 0; i < numBalls; i++) {
   circlearray[i] = new Circles(1, 1, 1, 1, 50, color(100));
 }
 fillpositionCircles();
 velocitychange();
 initialcolour();

}

Void draw

This section draws the functions to screen. This program loops through this draw function, this means that the movement that is shown on screen is simply the screen refreshing and the circles being drawn is a new position along a vector equation, giving the impression of movement.

  • fill - fills the screen with the colour (0,70) which refers to 0 on the grey scale meaning black and gives this a alpha channel of strength 70. This function is what gives the balls their tails by layering the new background over the previous screen they gradually fade out. Changing the alpha level will vary the length of a ball providing the speed before and after is the same.
  • rect - draws a rectangle to the screen with 0,0 co-ordinates and the size width, height referring to the size function, giving the fill function something to fill.
  • noStroke - removes the outlines from all the objects on the screen.
  • drawCircles - calls the drawCirlcles function.
  • moveCircles - calls the moveCircles function.
  • bounceCircles - calls the bounceCircles function.
  • collisionCircles - calls the collisionCircles function.

void draw() {

 fill(0,70);
 rect (0,0,width,height);
 noStroke();
 drawCircles();
 moveCircles();
 bounceCircles();
 collisionCircles();

}

Void keyPressed

This function allows various functions to be keybound giving the user the ability to modify certain functions while the program is running.

  • The keycode for the UP button is a simple math equation when the button is pressed if the intensity is less than 1 then .1 is added to the current number, if the button is pressed but the number is greater than 1 then it runs the else function, leaving the number at 1. The same function happens for the DOWN key only inverted.
  • The println function allows for the intensity to be displayed in the output window (black section down the bottom) of the processing coding window.
  • The coding for both the ALT and CTRL keys is the same if these keys are pressed it simply calls the corresponding function both of which are called earlier in the void setup

void keyPressed() {

 if (keyCode == UP){
   if (intentsity < 1) {
     intentsity = (intentsity + 0.1);
   }
   else {
     intentsity = 1;
   }
 }
 if (keyCode == DOWN){
   if (intentsity > 0.1) {
     intentsity = (intentsity - 0.1);
   }
   else {
     intentsity = 0.1;
   }
 }
 println (intentsity);
 if (keyCode == ENTER) {
   velocitychange();
 }
 if (keyCode == CONTROL) {
   initialcolour();
 }
 if (keyCode == ALT) {
   greyscale();
 }

}

Void mousePressed

  • Calls the menu function when the mouse is pressed.

void mousePressed() {

 menu();

}

Void menu

When this function is called from the mouse being pressed it loads the image "menu.jpg". This function is based on the state of the function menutrigger. if the state is false then it runs through this function until the mouse is pressed again changing the state to true. If this happens it then runs through the second part of the function the else statement where there is a noloop function making the picture disappear.

void menu() {

 PImage pic = loadImage("menu.jpg");
 if (menutrigger) {
   loop();
   menutrigger = false;
 }
 else {
   image(pic, 0, 0, width, height);
   menutrigger = true;
   noLoop();
 }

}

Class circles

This class is sets up the basis for all the balls, as they all have the same basic properties with varying values. These properties are not always needed and some are not used unless certain things happen like different keys being pressed.

  • The initial function outlines what the numbers contained within the brackets are referenced to.

class Circles {

 float xpos, ypos, xvel, yvel, radius;
 color col; 
 Circles() {  
 } 
 Circles(float x, float y, float xv, float yv, float r, color c) {  
   xpos = x;
   ypos = y;
   xvel = xv;
   yvel = yv;
   radius = r;
   col = c;
 } 
  • This function replaces the starting x and y co-ords with randomly generated numbers that fall within the maximum size of the window. Writing the function this way using the width and height functions allows the program to update if any changes are made to the windows makeup.


 void fillpositionvalues() { 
   xpos = int(random((0 + radius), (width - radius)));
   ypos = int(random((0 + radius), (height - radius))); 
 } 
  • This function gives the starting velocities to the balls. The random function allows a int or whole number to be called with in these constraints, -5 - 5, in both the x and y directions. A velocity of 0 is possible and will be represented with no movement but this is not a problem as the balls can hit each other so this will soon develop.
 void randomvelocity() {
   xvel = int(random(-5, 5));
   yvel = int(random(-5, 5));
 }
  • This function simply adds the x and y velocities to the x and y co-ords. Giving a new point for the circles once the screen is refreshed. (see void draw)
 void moveCircle() { 
   xpos += xvel;
   ypos += yvel; 
 }
  • This function assigns each ball a randomly generated RGB colour.
 void fillcolor() {
   col = color(int(random(255)),int(random(255)),int(random(255)));
 }
  • This function assigns each ball a randomly generated greyscale colour.
 void fillgreyscale() {
   col = color(int(random(255)));
 }
  • This function gives the object the shape in this case a ellipse.
 void drawCircle() { 
   fill(col);
   ellipse(xpos, ypos, radius, radius);
 }
  • This function forces the circles not to exceed the boundaries of the screen and in turn changes their direction if they reach the limits. Special note, the objects radius needs to be divided by a factor of 2 as the properties of the ellipse function require it to be given both a x and y direction radius. If this is not done the balls may exceed the screen on 1 side and bounce short of the edge on the other.
 void bounceCircle() {
   if (xpos > width - (radius / 2)) {
     xvel = abs(xvel) * -1;
   } 
   else if (xpos < radius / 2) {
     xvel = abs(xvel);
   }
   if (ypos > height - (radius / 2)) {
     yvel = abs(yvel) * -1;
   } 
   else if (ypos < radius / 2) {
     yvel = abs(yvel);
   }
 }
  • This function is the hardest aspect of this program and is the function that allows the balls to detect each other and bounce off if necessary. It runs through each ball and its proximity to all the other balls every time it is called.
    • eg if there were 3 balls this function would calculate ball 1 to 2, 1 to 3, 2 to 1, 2 to 3, ect.
  • This function also uses the intensity function, which varies the reaction of the balls when the collide and in turn bounce.
 void hitshit() {
   for (int i = 0; i < numBalls; i++) {
     float dx = circlearray[i].xpos - xpos;
     float dy = circlearray[i].ypos - ypos;
     float distance = sqrt(dx*dx + dy*dy);
     float minDist = circlearray[i].radius/2 + radius/2;
     if (distance < minDist) { 
       float angle = atan2(dy, dx);
       float targetX = xpos + cos(angle) * minDist;
       float targetY = ypos + sin(angle) * minDist;
       float ax = (targetX - circlearray[i].xpos) * intentsity;
       float ay = (targetY - circlearray[i].ypos) * intentsity;
       xvel -= ax;
       yvel -= ay;
       circlearray[i].xvel += ax;
       circlearray[i].yvel += ay;
     }
   }
 } 

}

Other 'void' functions

All the following functions are called by the void draw or void setup functions and all relate to a different aspect of the class structure, these functions act as a bridge between these properties and were the logical step written in before the balls were called in a array. They are still there as they make the structure of the program easier to understand and by writing the code in this way the program seemingly runs many small aspects simultaneously and therefor problems are far easier to identify.

void fillpositionCircles() {

 for (int i = 0; i < numBalls; i++) {
   circlearray[i].fillpositionvalues();
 }

}

void velocitychange() {

 for (int i = 0; i < numBalls; i++) {
   circlearray[i].randomvelocity();
 }

}

void drawCircles() {

 for (int i = 0; i < numBalls; i++) {
   circlearray[i].drawCircle();
 }

}

void initialcolour() {

 for (int i = 0; i < numBalls; i++) {
   circlearray[i].fillcolor();
 }

}

void greyscale() {

 for (int i = 0; i < numBalls; i++) {
   circlearray[i].fillgreyscale();
 }

}

void moveCircles() {

 for (int i = 0; i < numBalls; i++) {
   circlearray[i].moveCircle();
 }

}

void bounceCircles() {

 for (int i = 0; i < numBalls; i++) {
   circlearray[i].bounceCircle();
 }

}

void collisionCircles() {

 for (int i = 0; i < numBalls; i++) {
   circlearray[i].hitshit();
 }

}


NOTES

  • If the velocities were ints as they were originally when the intensity function is removed 2 balls traveling slowly toward each other stop when when they collide because their velocities round to the nearest whole number in this case 0.
  • The intensity function can not slow the balls down when it is reduced as it is a multiplication function, even reducing the number bellow 0 has no effect. If the intensity function is equal to 0 then the balls pass through each other.


OUTCOMES

Media:Final program.zip