Managing ball vs ball collision with Flash

Emanuele Feronato 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:

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

From null to full HTML5 cross platform game

I will take you by hand from the bare bones of JavaScript programming through the creation of a full cross platform HTML5 game, with detailed explainations and source code.

If you don't know where to start, then From null to full HTML5 cross platform game is the book for you.

Comments 42

  1. ciaren coleman

    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

    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

    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. Post
    Author
  5. Patrik TG

    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 :)

  6. Monkios

    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;

  7. Ed

    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?

  8. Diego

    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

  9. jones

    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.

  10. Pingback: Boink Blogs

  11. Pingback: Managing ball vs ball collision with Flash at Flash Game Script

  12. ryan

    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?

  13. Pingback: Flash ball vs ball game concept : Emanuele Feronato - italian geek and PROgrammer

  14. Pingback: Managing multiple balls collisions with Flash : Emanuele Feronato - italian geek and PROgrammer

  15. Vikky

    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?

  16. RussellSprouts

    Sorry for so many posts, but I have a way to make it work for more balls:
    Make collisions an array, and do this for each one. It only has problems near the walls.
    _root[“ball_”+x].collision[y]
    _root[“ball_”+y].collision[x]

  17. vicky

    i need algorithm for implementation of carrom game in C. If anybody have developed it or can helpin its development(i.e implementation of coins collision in C language)plz let me know and mail me the coding/algorithm.
    thanks.

  18. bill bond

    Hi Emanuele, thanks for your excellent insight! i feel so close, but still struggling… What I’m trying to do is to create the same effect but with separate MovieClips rather that generated iterations of the same.. Any clues would be very welcome..

  19. Alex Nino

    Hi there, excellent work!!

    I’ve been working a bit with physics in flash and I found that the more your program depends on Sin/Cos functions the lower performance you have. Sin and Cos functions are quite CPU intensive, and in most of the cases these functions take up to 90% of your program execution time.

    There is actually a way to achieve exactly the same you’re doing in this article without using Math.sin/Math.cos at all, which means that your program could run up to 10 times faster. Have you ever tried running your manage_bounce function working with 100 balls on the stage?

    take a look on how it works:
    http://www.yoambulante.com/en/labs/elastic_collision.php

    cheers!!

  20. pandoraEudora

    Greate Tutorial! Just one thing about the physics…it’s actually a 2D collision so the yspeed doesn’t just stay the same…take a look:
    here is my modification to your code

    dirChanger = function (mc1, mc2) {
    //calculate collision angle
    dx = mc1._x-mc2._x;
    dy = mc1._y-mc2._y;
    phi = Math.atan2(dy, dx);
    //Transformations
    ux = (mc1.vect_x+mc2.vect_x)/2;
    uy = (mc1.vect_y+mc2.vect_y)/2;
    //Calculate magnitude of each vector for mc1 and mc2
    mc1vx = mc1.vect_x-ux;
    mc1vy = mc1.vect_y-uy;
    mc2vx = mc2.vect_x-ux;
    mc2vy = mc2.vect_y-uy;
    mc1_vmagnitude = Math.sqrt(mc1vx*mc1vx+mc1vy*mc1vy);
    mc2_vmagnitude = Math.sqrt(mc2vx*mc2vx+mc2vy*mc2vy);
    //calculate direction of each vector
    alfa = Math.atan2(mc1vy, mc1vx);
    beta = Math.atan2(mc2vy, mc2vx);
    //Get new vectors
    v1x = mc1_vmagnitude*(Math.cos(2*phi-alfa)*-1)+ux;
    v1y = mc1_vmagnitude*(Math.sin(2*phi-alfa)*-1)+uy;
    v2x = mc2_vmagnitude*(Math.cos(2*phi-beta)*-1)+ux;
    v2y = mc2_vmagnitude*(Math.sin(2*phi-beta)*-1)+uy;
    //apply new vectors
    mc1.vect_x = v1x;
    mc1.vect_y = v1y;
    mc2.vect_x = v2x;
    mc2.vect_y = v2y;
    //to somewhat mediate the stick problem such them apart further…
    mc1._x += v1x;
    mc1._y += v1y;
    mc2._x += v2x;
    mc2._y += v2y;
    }
    I guess the only problem is if you exceed, say 20 balls you start to get the stick problem which is similar to the “going-through-the-wall” problem

    Cheers

    1. Simon

      I’m not too good at programming (or physics) but I would agree that the y-velocities would also need to be updated.

      So, are we saying that instead of:

      final_yspeed_1 = new_yspeed_1;
      final_yspeed_2 = new_yspeed_2;

      we need to put something else? Can anybody provide that? Pandora, I appreciate all the code you provided but I was working through the earlier code and I am finding it difficult to match up your variables names with the original. Could anybody update the original code please?

      Thanking you in advance

      Si

  21. Vinh

    I found a bug: two circle collided and it was sticked together.

    I’m finding the reason and try to fix it.

    Anyway, this is cool tutorial that is exactly what I want.

    Thanks Emanuele so much.

  22. Rodrigo

    Hello! very nice tutorial, gratz! just what i wanted.

    Actually i need one more thing, when you click on a ball, it duplicate in 2…
    its possible?

    thanks

  23. CoProgrammer

    Thanks! This is a very good website for tutorials and I have enjoyed learning some Physics as well! I am currently trying to create a Brick-Breaker game. I will hopefully create a tutorial about that later.

  24. CoProgrammer

    Thanks! This is a very good website for tutorials and I have enjoyed learning some Physics as well! I am currently trying to create a Brick-Breaker game. I will hopefully create a tutorial about that later.

    To extend the code add:

    this.removeMovieClip(ball);

    Or for the bowling game:

    ball.xspeed = 0
    ball.yspeed = 0

    on(release){
    ball.xspeed = speed_limit
    ball.yspeed = speed_limit
    }

  25. Josh

    This was super helpful. I was also running into issues with the balls sticking together, especially since I’m working on an asteroids clone.

    I decided the best solution is that after the balls have collided, do all the collision calculations and then move them so that they will be just outside the area where they collided, along the collision vector. My variables are a little differently named, but the principle is the same:

    This would go between the equivalent of line 61 and 62 above, where minDist = the sum of the radii and rockDist = the distance between centerpoints.

    var rockOffset = minDist – rockDist;
    RockB.rock.x -= Math.cos(collisionAngle)*rockOffset;
    RockB.rock.y -= Math.sin(collisionAngle)*rockOffset;

Leave a Reply

Your email address will not be published. Required fields are marked *