Managing ball vs ball collision with Flash

This is another headache post. I am sorry, but since there is a ball physics competition, I have to focus tutorials on ball physics.

This tutorial covers collisions between balls, and it works with any number of balls, and it's based on Raman Pfaff's Physics of an Elastic Collision.

What is an "elastic collision"?

From Wikipedia: "An elastic collision is a collision in which the total kinetic energy of the colliding bodies after collision is equal to their total kinetic energy before collision."

In this tutorial I simply made one single object, a 15px radius circle, linked as "ball".

Then, in the first frame, just eighty lines of actionscript:

ACTIONSCRIPT:
  1. number_of_balls = 3;
  2. speed_limit = 10;
  3. for (x=1; x<=number_of_balls; x++) {
  4.     ball = attachMovie("ball", "ball_"+x, _root.getNextHighestDepth(), {_x:Math.random()*400-50, _y:Math.random()*300-50});
  5.     ball.collision = 0;
  6.     ball.mass = 1;
  7.     ball.xspeed = Math.random()*8-4;
  8.     ball.yspeed = Math.random()*8-4;
  9.     ball.onEnterFrame = function() {
  10.         if (this._x<15) {
  11.             this._x = 15;
  12.             this.xspeed *= -1;
  13.         }
  14.         else if (this._x>485) {
  15.             this._x = 485;
  16.             this.xspeed *= -1;
  17.         }
  18.         if (this._y<15) {
  19.             this._y = 15;
  20.             this.yspeed *= -1;
  21.         }
  22.         else if (this._y>385) {
  23.             this._y = 385;
  24.             this.yspeed *= -1;
  25.         }
  26.         if (this.xspeed>speed_limit) {
  27.             this.xspeed = speed_limit;
  28.         }
  29.         if (this.xspeed<speed_limit*-1) {
  30.             this.xspeed = speed_limit*-1;
  31.         }
  32.         if (this.yspeed>speed_limit) {
  33.             this.yspeed = speed_limit;
  34.         }
  35.         if (this.yspeed<speed_limit*-1) {
  36.             this.yspeed = speed_limit*-1;
  37.         }
  38.         this._x += this.xspeed;
  39.         this._y += this.yspeed;
  40.     };
  41. }
  42. function manage_bounce(ball, ball2) {
  43.     dx = ball._x-ball2._x;
  44.     dy = ball._y-ball2._y;
  45.     collisionision_angle = Math.atan2(dy, dx);
  46.     magnitude_1 = Math.sqrt(ball.xspeed*ball.xspeed+ball.yspeed*ball.yspeed);
  47.     magnitude_2 = Math.sqrt(ball2.xspeed*ball2.xspeed+ball2.yspeed*ball2.yspeed);
  48.     direction_1 = Math.atan2(ball.yspeed, ball.xspeed);
  49.     direction_2 = Math.atan2(ball2.yspeed, ball2.xspeed);
  50.     new_xspeed_1 = magnitude_1*Math.cos(direction_1-collisionision_angle);
  51.     new_yspeed_1 = magnitude_1*Math.sin(direction_1-collisionision_angle);
  52.     new_xspeed_2 = magnitude_2*Math.cos(direction_2-collisionision_angle);
  53.     new_yspeed_2 = magnitude_2*Math.sin(direction_2-collisionision_angle);
  54.     final_xspeed_1 = ((ball.mass-ball2.mass)*new_xspeed_1+(ball2.mass+ball2.mass)*new_xspeed_2)/(ball.mass+ball2.mass);
  55.     final_xspeed_2 = ((ball.mass+ball.mass)*new_xspeed_1+(ball2.mass-ball.mass)*new_xspeed_2)/(ball.mass+ball2.mass);
  56.     final_yspeed_1 = new_yspeed_1;
  57.     final_yspeed_2 = new_yspeed_2;
  58.     ball.xspeed = Math.cos(collisionision_angle)*final_xspeed_1+Math.cos(collisionision_angle+Math.PI/2)*final_yspeed_1;
  59.     ball.yspeed = Math.sin(collisionision_angle)*final_xspeed_1+Math.sin(collisionision_angle+Math.PI/2)*final_yspeed_1;
  60.     ball2.xspeed = Math.cos(collisionision_angle)*final_xspeed_2+Math.cos(collisionision_angle+Math.PI/2)*final_yspeed_2;
  61.     ball2.yspeed = Math.sin(collisionision_angle)*final_xspeed_2+Math.sin(collisionision_angle+Math.PI/2)*final_yspeed_2;
  62. }
  63. _root.onEnterFrame = function() {
  64.     for (x=1; x<number_of_balls; x++) {
  65.         for (y=x+1; y<=number_of_balls; y++) {
  66.             distance_x = Math.abs(_root["ball_"+x]._x-_root["ball_"+y]._x);
  67.             distance_y = Math.abs(_root["ball_"+x]._y-_root["ball_"+y]._y);
  68.             distance = Math.sqrt(distance_x*distance_x+distance_y*distance_y);
  69.             if (distance<=30 && (_root["ball_"+x].collision == 0 or _root["ball_"+y].collision == 0)) {
  70.                 _root["ball_"+x].collision = 1;
  71.                 _root["ball_"+y].collision = 1;
  72.                 manage_bounce(_root["ball_"+x],_root["ball_"+y]);
  73.             }
  74.             else if (distance>30) {
  75.                 _root["ball_"+x].collision = 0;
  76.                 _root["ball_"+y].collision = 0;
  77.             }
  78.         }
  79.     }
  80.    
  81. };

Let' see how does it work

Line 1: Defining the number of balls in the stage. Placing an high number of balls can cause some problems, as I will explain later

Line 2: Setting a speed limit. It's not necessary in this example but we should always set a speed limit. The higher the speed, the lower the accuracy of our collisions.

Line 3: Beginning of a cycle to be repeated n times, where n = number of balls in the stage

Line 4: Attaching the ball on the stage in a random position. Please note that when I place a ball, I don't check if it will overlay a previously placed ball. This is why placing an high number of balls can cause some problems, but placing "safe" balls is not the aim of this tutorial. Moreover, you can easily script the routine to check if two balls overlay.

Line 5: Setting a collision property to the ball. Collision = 0 means there is no collisions

Line 6: Mass property. Having all same masses helps us to verify the script works... but you can set the mass at any value, and the script will work. It's just that you'll see some strange bounces and you won't understand why since the balls in the stage do not display their mass.

Lines 7-8: Assigning a random x and y speeds to the ball

Line 9: Beginning of the routine to be executed at every frame for each ball

Lines 10-13: Checking if the ball is closer than 15 pixels (its radius) to the left edge of the stage. If so, it means the ball must "bounce" on the edge, so its x position is set to 15 and its x speed is inverted.

Lines 14-17: Same thing with the right edge

Lines 18-21: Same thing with the upper edge

Lines 22-25: Same thing with the bottom

Lines 26-28: Checking if the ball xspeed exceeds speed limits. If true, setting xspeed to speed limit

Lines 29-31: Same thing with negative x speed (from right to left)

Lines 32-37: Same thing with y positive and negative speeds

Lines 38-39: Updating ball position according to x and y speeds

Well, I told the script was 80 lines long (81 to be precise)... we are at its half and we did not encounter hard points. Unfortunately, this will not last for long...

Lines 42-62: Mysterious routine that solves the collision between two balls updating their speeds according to various collision parameters. At the moment you don't need to know more.

Line 63: Function to be executed at every frame

Lines 64-65: This is a double cycle used to check the collision between a ball and the other ones. If you look at the parameters of both cycles, you'll notice they are designed to avoid checking collision twice. For example, I will never check collision between ball 2 and ball 1, because I already checked collision between ball 1 and 2. So, if we have 4 balls, the collision checks will be: ball 1 with 2, 1 with 3, 1 with 4, 2 with 3, 2 with 4 and 3 with 4.

Lines 66-68: Determining distance between xth and yth balls with the Pytagorean theorem

Line 69: Checking if the distance is less than 30 pixels (ball diameter, or 2*ball radius) and both balls are not already colliding.

Why are we checking if balls are already in collision? Because we want an elastic collision, and an elastic collision must occour only at a distance of 30 pixels. Unfortunately, we can't check the distance between balls in a continuous time, but only every 1/framerate seconds, so in most cases we miss the moment when two balls start colliding... in most cases the collision begins when a ball overlayed another one and we have to avoid "fake bounces" as the ones explained in Create a flash draw game like Line Rider or others - part 4... so the entire process is an approximation of a real elastic collision, but this won't affect gameplay.

Lines 70-71: Set the collision propery of both balls to 1

Line 72: Calling the "mysterious routine"

Lines 74-77: If the distance is more than 30px, then there is no collision and I set the collision property to zero. This is not necessary in most cases but I leave to you the code optimization.

That's all! Did I forget something? What? The Mysterious routine?

Well... you asked for... you deserved it... don't blame me for your headache.

Line 42: Function declaration: two arguments, both movieclips, both balls

Line 43: Calculating the horizontal distance between balls

Line 44: Calculating the vertical between balls

Line 45: Calculating the collision angle using trigonometry as explained in Create a flash draw game like Line Rider or others - part 3

Line 46: Calculating the ball1 speed, here called "magnitude" because this is the "real name" of the speed in this environment

Line 47: Calculating the ball2 speed in the same way

Lines 48-49: Determining balls direction using trigonometry

Nothing new until here, if you are a regular reader. Now, let's mess up everything.

That's what we have: a collision of 2 balls in a standard reference axis system, with an horizontal and a vertical speed that form the magnitude like in this picture

As you can see, y speed is vertical while x speed is horizontal.

Now imagine to change reference axis system, where the x speed lies along the collision line, and the y speed is perpendicular to that, without changing magnitude and direction, in this way

Both pictures show the concept on the right ball, but it's the same for both balls

All variables we need to know are known, so new speeds are determined this way:

Line 50: Calculating new xspeed using trigonometry applied to the difference from the direction angle and the collision angle (in other words, how many degrees it takes to make the xspeed vector overlay the angle of collision)

Lines 51-54: Same thing for other vectors: ball 1 yspeed and ball 2 xspeed and yspeed

Now new vectors are known. It's time to calculate what happens in this collision. Let's think about the collision we have: balls are moving on a 2D environment, but with this axis transformation the collision happens in a 1D environment: along the x axis.

The only thing we need to solve is an elastic collision along one axis.

Just like Superman, the law of conservation of momentum comes in our help (and without blue/red underpants).

From Wikipedia: In an isolated system (one where external forces are absent) the total momentum will be constant: this is implied by Newton's first law of motion. Newton's third law of motion, the law of reciprocal actions, which dictates that the forces acting between systems are equal in magnitude, but opposite in sign, is due to the conservation of momentum.

Do we have an isolated system? Yes, external forces are absent, it's windy today in Italy but the wind does not affect my spheres in the stage.

So our friend Newton says in an elastic collision total kinetic energy is the same before and after the collision and total momentum remains constant throughout the collision. Calling v1 and v2 the new magnitudes (speeds) of the balls after the collision, u1 and u2 the magnitudes before collision, and m1 and m2 the masses, we have:

v1 = (u1*(m1-m2) + 2*m2*u2)/(m1+m2)

and

v2 = (u2*(m2-m1) + 2*m1*u1)/(m1+m2)

Notice that if m1=m2 then

v1 = u2

and

v2 = u1

That means the balls exchange their magnitude.

Translated into actionscript, this is:

Line 54: Determining final x speed for ball 1

Line 55: Determining final y speed for ball 2

Lines 56-57: y speed does not changes (it's a 1D collision)

And now we have the new x and y speeds, but they are still related to the axis environment we created to have a 1D collision.

Time to transform speeds in the old, standard x-y Cartesian coordinate system

Lines 58-61: Determining x and y speeds on the standard axis system using trigonometry. Notice that Math.PI/2 because the angle between xspeed and yspeed must always be 90 degrees (pi/2 radians)

And the problem is solved... here you can see three balls with equal masses bouncing up and down the stage. Should you see two balls overlaying, that's due to the wrong initial placing as explaining at the beginning of this tutorial. Simply reload the page and everything should work.

Download the source code and give me feedback

Improve the blog rating this post
Tell me what do you think about this post. I'll write better and better entries.
1 Star2 Stars3 Stars4 Stars5 Stars (4 votes, average: 4.5 out of 5)
Loading ... Loading ...

» Flash Templates provided by Template Monster are pre-made web design products developed using Flash technology.
They can be easily customized to meet the unique requirements of your project.

24 Responses to “Managing ball vs ball collision with Flash”

  1. ciaren coleman on August 19th, 2007 1:31 pm

    I like this but I would like to know how to keep the balls still when you start the movie in positions which you choose and have one ball you can drag and throw so that you can make a bowling game.

  2. hansa on August 19th, 2007 3:03 pm

    thanks you for one more great tut and if possible could you save you source as flash mx (if you dont already do that)

    //hansa

  3. Raman Pfaff on August 19th, 2007 6:31 pm

    Thanks for the mention of my unbelievably old article over on DOUG! I think at that time I was teaching so much physics that I made the article as complex as possible :)

  4. Emanuele Feronato on August 19th, 2007 7:53 pm

    Thanks to you for writing such an interesting way to approach the problem.

  5. s0daplayer on August 20th, 2007 4:24 am

    Ive been waiting for you to create the tutorial on how to make this thanks.

  6. mojopodolido on August 20th, 2007 7:16 pm

    there is only one ball in flash mx

  7. Patrik TG on August 21st, 2007 11:54 pm

    Now this is great!!
    But like ciaren coleman I would love to know how to keep them still in the beginning of the movie.
    You can do so many thing with that.

    Thanks again :)

  8. Monkios on August 22nd, 2007 2:50 pm

    On line 7 and 8, you assign a random speed to your ball.

    Set the speed to 0 and the ball will stop.

    ie:
    ball.xspeed = 0;
    ball.yspeed = 0;

  9. Ed on August 23rd, 2007 5:31 pm

    How would I change this so that only 1 ball appears at the beginning and every, for example, 3 seconds another ball appears? I managed to do this with Intervals but then the balls wouldn’t collide. Any help?

  10. Diego on August 25th, 2007 2:49 am

    Wow nice tutorial, based on this I was thinking on making a Pool Game with things like Backspin, Masse, and stuff like that! When I get home I’ll try to do it.
    Nice tuts! Continue making them! So glad I found your website

  11. s0daplayer on August 29th, 2007 12:13 am

    http://www.gotoandplay.it/_articles/2004/07/collisions.php
    I found this flash also based of raman pfuff’s article. Take a look at the source code and you can find a way for the balls not to stick to each other.

  12. computergeek67 on September 5th, 2007 2:52 am

    Now how would I make it so that when one circle touches another, It goes to another frame?

  13. Tony on September 10th, 2007 12:01 am

    How can I remove all balls from stage?

    Please answer

    Tony

  14. jones on September 22nd, 2007 12:00 pm

    Hi,
    just read your article and I really enjoy playing around with it. I started to modify the source a bit and encountered some strange behavior.
    Maybe I just haven´t figured it out yet but: if I look at 69-77 I ask myself what happens if you have, lets say 10 balls flying around.
    This part of the code will check if the distance is less than 30 px and if not it will set collision to false. What if one of the balls has a collision thing goin on far away on the stage? it will have a collision=false afterwards…this may be some problem…in fact it is exactly the problem I am just facing.
    any idea?
    But anyway: damn nice work.

  15. Jalla on September 28th, 2007 6:55 pm

    How could i make it so that when an arrow key controlled movieclip hits one of the balls, the movie clip dissapeared?

  16. Ben on November 8th, 2007 8:44 am

    Thanks so much! The collision formula was soooo useful.

  17. ryan on November 25th, 2007 11:32 am

    hmmmm my particles are sticking together a lot and they don’t seem to be bouncing correctly… anyone have ideas as to what I’m doing wrong?

  18. Oli C on December 4th, 2007 5:47 pm

    How do you use different movieclips for each ball? I would like to have different objects bouncing off each other.

  19. Vikky on June 19th, 2008 1:03 pm

    Hi, in this code if you make the ball size small and let them collide they stick with each other and rotate together :(
    How to make it a clean collision?

  20. filo on October 31st, 2008 10:39 am

    do you have any suggestion to solve the *magnetic-stick* problem and multiple (i.e. 4 or more balls) elements handling?

    TIA

Leave a Reply




Trackbacks

  1. Boink Blogs on October 18th, 2007 7:30 am

    [...] ball vs ball collision with Flash Emanuele Feronato placed an observative post today on Managing ball vs ball collision with FlashHere’s a quick [...]

  2. Managing ball vs ball collision with Flash at Flash Game Script on October 29th, 2007 11:09 am

    [...] Original post by Emanuele Feronato - italian geek and PROgrammer [...]

  3. Flash ball vs ball game concept : Emanuele Feronato - italian geek and PROgrammer on December 6th, 2007 6:03 pm

    [...] the studies of Raman Pfaff’s Physics of an Elastic Collision and its derivated tutorials such as Managing ball vs ball collision with Flash by myself and Elastic collisions by Marijn van Aerle and come out with a good prototype where the [...]

  4. Managing multiple balls collisions with Flash : Emanuele Feronato - italian geek and PROgrammer on May 27th, 2008 10:58 pm

    [...] already published a tutorial about Managing ball vs ball collision with Flash but this time we’ll manage any number of [...]