Colliding Balls help!

Posted on 2006-04-17
Last Modified: 2008-02-01
I am working on something in which balls fall from the top of the stage and then bounce around, off the walls and one another. Each balls has a random size and mass defined at runtime, and all animation is scripted. My problem is on the collisions.

On the stage a clip runs a loop every frame going through each ball checking to see if a collision has been made with another ball. It seems that a collision is detected, processed, and the resultant velocities are applied to each ball properly, but because there is the possibility of overlapping at the time of the collision detection, the balls may be seen as colliding on the next frame as they try and move apart, resulting in another calculation. This causes the balls to just bunch up.

I seem to need some way to either

a) separate the balls properly when a collision is detected
b) make sure another collision calculation isn't processed until the distance between balls is greater than radius + radius2

How to go about this has me confused. Any thoughts?

I'll be more than happy to post my flash file for download if neccessary!!

Question by:D4Ly
    LVL 3

    Accepted Solution

    try the setInterval method instead of onEnterFrame... frames are too slow and possibly your app is running at only 12 per sencond, which would make it much slower... of course, if you don't have any frame based animation, you could just push that up and your check would be happening alot more... you'd need to change some vars like the speeds of balls moving etc... but your most stable bet is setInterval... with it, you can check for collision every millisecond if you want.

    basic usage.
    myInterval = setInterval(functionName, interval [, param1, param2, ..., paramN]);

    where function does the check... interval is your milliseconds... params are optional stuff you'd be passing into your function.

    when your need to get rid of the interval, use clearInterval(myInterval)... make sure the variable myInterval is accessible from whereever you clear it... i.e. don't make it local to one function and then clear it in another.

    hope this helps.
    LVL 9

    Author Comment

    Hi nifmcm-
    I tried your suggestion, but the result unfortunately is that the balls grab each other more smoothly.

    Check it out.

    this is with setInterval at 1ms.
    LVL 19

    Assisted Solution

    In the spirit of teaching you how to fish....



    LVL 9

    Author Comment

    I'm not sure how that is supposed to help. My direction change calculations are a little more complex, but the basic idea is exactly the same as the link you've provided, but does not address my issue of balls against the wall or floor (since there is in fact no wall or floor in that example). I know how to 'fish', and have done my research...that's why I am here :) Perhaps a solution is out there, but I have yet to find it.

    for(var i=0; i<maxBalls; i++){ //check collisions
                bi = _root["ball"+i];
                if(!bi)      continue;
                for(var j=i+1; j<maxBalls;j++){
                      bj = _root["ball"+j];
                      if(!bj)      continue;
                      var xd = bi._x - bj._x; var yd = bi._y - bj._y;
                      var dr = Math.sqrt(Math.pow(xd,2) + Math.pow(yd,2)); //distance between balls
                      var rads = ((bi._width / 2) + (bj._width / 2)); //total distance between center points
                      var tm = (bi.code.mass + bj.code.mass)/2; //half of total system mass

                      if(bi.hitTest(bj)){ //check if balls are colliding
                            var nx = xd/dr; var ny = yd/dr; //normal vectors
                            var v0 = ( bi.code.vx * nx + bi.code.vy * ny );
                            var v1 = ( bj.code.vx * nx + bj.code.vy * ny );
                            var relv = v0 - v1; //relative velocity calculation
                            var vec0 = -bounce * relv; var vec1 = bounce * relv; //new vectors
                            bi.code.vx = (bi.code.vx) + nx * vec0 * bj.code.mass / tm; //set the resultant velocities
                            bi.code.vy = (bi.code.vy) + ny * vec0 * bj.code.mass / tm;
                            bj.code.vx = (bj.code.vx) + nx * vec1 * bi.code.mass / tm;
                            bj.code.vy = (bj.code.vy) + ny * vec1 * bi.code.mass / tm;

    The math here works beautifully when the balls are both in the air. Its when one of the balls collides off of a wall or the floor that I run into some issues.

    I've been thinking. I never have an issue with the ball getting caught up in the wall or floor itself. I believe this is because when the ball collides with a wall or floor it's position is reset to be completely inside the container, and then the new velocities are applied. Perhaps a solution would be to move the balls apart in the direction they will be traveling and _then_ apply the resultant velocities. How to do this is a bit unclear at this point, as well as how to deal with the walls and floor when moving a ball that is say, stationary on the ground.

    Another thought would be to set a timer of some sort up, which would not allow for another collision calculation on the same 2 balls for a certain period of time, allowing them to move apart.

    LVL 7

    Assisted Solution

    I did something similar to this in my computer graphics class when I was an undergad. I did mine in C using OpenGL, but I use similar math (using a normal vector pointing from one mass to the other) to caculate the new velocity.

    I too was having this problem of overlapping balls since the collision sometimes happened between frames. Although, my math didn't seem to care once they were moving in the correct direction, they would keep travelling in that direction.

    Anyways, a simple fix I found was to look ahead one frame. Instead of checking collisions as they happen (or already happened) in this frame, I would see if any of them would collide in the next frame. If they were going to, I would set their nextFramePosition to exactly where the collision happens, and set the new velocity to that determined by your math equation.

    This, I noticed, always made sure that the objects never overlapping, and no collision was calculated twice. Since in the next frame (the one you are now checking), the objects will be moving apart.

    Hope this helps

    Featured Post

    Highfive Gives IT Their Time Back

    Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

    Join & Write a Comment

    This is a very simple example to help those of you who are still migrating from AS2 to AS3 understand the redesigned event model in AS3. In AS2.0, event functions (that is, the function to be performed when an event is fired) were stored as a pro…
    Here are some practices and techniques that can be adopted into your Flash/Flex application development process. Note: Not all "performance tips" provide an immediately-recognizable benefit.   This article does not include timing validation data,…
    The goal of the tutorial is to teach the user how to how to load their YouTube profile onto Flash Media Live Encoder.
    The goal of the tutorial is to teach the user how to select which audio input to use. Once you have an audio input plugged into the laptop or computer, you will go into the audio input settings and choose which audio input you want to use.

    745 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    15 Experts available now in Live!

    Get 1:1 Help Now