OOP: Balls bouncing off each other, resting on each other

Hi guys, I’ve been trying to recreate the yugop example(www.yugop.com) where the balls seem to bounce off each other, but the difference is, they can also rest on top of each other. I’ve included my example and the class for help.

Thanks.

click to add more balls.

SWF: http://www.fuzzfolio.com/workarea/myBallYugop.html


main.fla
 
var ballcount:Number=1;
var ballSet:Array = new Array();
 
for (i = 0; i < ballcount; i++){ 
 ballSet* = new myBallDynamics(i,_root);
 ballSet*.bounceAround();
} 
 
mybox.onPress=function(){
 mybox.onRollOut();
 ballSet[ballcount] = new myBallDynamics(ballcount,_root);
 ballSet[ballcount].startBallScale();
 
      mybox.onMouseMove=function(){
           ballSet[ballcount].followCursor();
      }
 
      mybox.onRollOut=function(){
          mybox.onMouseMove=null;
          ballSet[ballcount].stopBallScale();
          ballSet[ballcount].bounceAround();
          ballcount=ballcount+1;
      };
};
 
mybox.onRelease=function(){
         mybox.onMouseMove=null;
         mybox.onRollOut=null;
 
         ballSet[ballcount].stopBallScale();
         ballSet[ballcount].bounceAround();
         ballcount=ballcount+1;
};
 
stop();

my class


class myBallDynamics{
 public var bid:Number;
 
 private var ballX:Number;
 private var ballY:Number;
 private var velX:Number;
 private var velY:Number;
 
 private var gravity:Number = 0;
 private var boundaries:Object;
 
 private var parentHolder:MovieClip;
 private var holder:MovieClip;
 
 private var radius:Number;
 private var mass:Number;
 
 function myBallDynamics(numOfBalls:Number, parentMC:MovieClip){ 
  bid = numOfBalls;
  parentHolder = parentMC;
  holder = parentHolder.attachMovie("ball", "ball"+numOfBalls, numOfBalls,{_x:150, _y:150}); 
 
  init(10);
 }
 
 function init(pgravity:Number){
  gravity = pgravity;
  radius = holder._width / 2;
  mass = radius;
 
  velX = Math.random()*20-10; 
  velY = -Math.random()*20;
 
  ballX = holder._x; 
  ballY = holder._y; 
 
  checkForWalls();
 }
 
 function getMass(){
  return mass;
 }
 
 function getX(){
  return holder._x;
 }
 
 function getY(){
  return holder._y;
 }
 
 function getVX(){
  return velX;
 }
 
 function getVY(){
  return velY;
 }
 
 function getBX(){
  return ballX;
 }
 
 function getBY(){
  return ballY;
 }
 
 function setVX(newVX:Number){
  velX = newVX;
 }
 
 function setVY(newVY:Number){
  velY = newVY;
 }
 
 function setBX(newBX:Number){
  ballX = newBX;
 }
 
 function setBY(newBY:Number){
  ballY = newBY;
 }
 
 function getWidth(){
  return holder._width;
 }
 
 function getHeight(){
  return holder._height;
 }
 
 function setWidth(newWidth:Number){
  holder._width = newWidth;
 }
 
 function setHeight(newHeight:Number){
  holder._heifht = newHeight;
 }
 
 function setX(newX:Number){
  holder._x = newX;
 }
 
 function setY(newY:Number){
  holder._y = newY;
 }
 
 function getRadius(){
  return radius;
 }
 
 function followCursor(){
  holder._x = _root._xmouse;
  holder._y = _root._ymouse;
 }
 
 function startBallScale(){
  followCursor();
 
  var dir:Number=5;
  holder.onEnterFrame=function(Void):Void{
   if (this._width >= 100){
    dir=-5;
   }
   if(this._height <= 25){
    dir=5;
   }
 
   this._width += dir;
   this._height += dir;
  }
 }
 
 function stopBallScale(){
  radius = holder._width / 2;
  holder.onEnterFrame=null;
 }
 
 function updateMovement(){
    // render our new position
        holder._x = ballX;
        holder._y = ballY;
        updateAfterEvent();
 }
 
 function bounceAround(){
  holder['obj']=this;
  holder.onEnterFrame=function(Void):Void { 
   this.obj.ballX = this._x;
   this.obj.ballY = this._y;
 
   this.obj.velY += this.obj.gravity;
 
   //this.obj.ballX += this.obj.velX; 
   this.obj.ballY += this.obj.velY; 
 
   this.obj.checkForWalls();
   this.obj.checkForBalls();
   this.obj.updateMovement();
  }
 
 }  
 
 function checkForWalls():Void {
       // top
       if (ballY - radius < 0) {
           ballY = radius;
 
           velY *= -1;
       }
       // bottom
       else if (ballY + radius > Stage.height) {
           ballY = Stage.height - radius;
           velY *= -1;
       }
       // left
       if (ballX - radius < 0) {
           ballX = radius;
     if(velX > 0 ) {
         velX = velX - 1;
     } else {
      velX = velX + 1;
     }
           velX *= -1;   
       }
       // right
       else if (ballX + radius > Stage.width) {
           ballX = Stage.width - radius;
     if(velX > 0 ) {
         velX = velX - 1;
     } else {
      velX = velX + 1;
     }
     velX *= -1;
 
    }
    }
 
 
    function checkForBalls():Void {
        // Have a look at the other balls on the stage and see if
        // we're hitting them.  If so, react accordingly.
 
        // shortcut to the array that knows about all of the Balls on
        // the stage
        var allBalls:Array = parentHolder.ballSet; 
        // for each of the balls on the stage
        for (var i = 0; i < allBalls.length; i++) {
        // if our bid is less than theirs
        // (this makes sure that each ball only looks for a collision
        // with each other ball once per frame)
        // If you ever delete balls - make sure you reset all the bids
         if (allBalls*.bid > bid) {
            // figure out how far away we are from them
            // distance on the x axis
               var xdiff:Number = allBalls*.getBX() - ballX;
            // distance on the y axis
               var ydiff:Number = allBalls*.getBY() - ballY;
            // use pythagoras' magic
               var dist:Number = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
 
               // hit test is easy with circles
               // if dist <= sum of radii, we're hitting
               if (dist <= (radius + allBalls*.getRadius())) {
                   // we're hitting, call the reaction function
                   ballBallReaction(this, allBalls*, dist, xdiff, ydiff);
               }
             }
         }
     }
 
 
     function ballBallReaction(b1:myBallDynamics, b2:myBallDynamics, dist:Number, xdiff:Number, ydiff:Number):Void {
  // params
     //            b1 - first ball in collision
     //            b2 - second ball in collision
     //            dist - distance between the middle of the two balls
     //            xdiff - diff between balls on the x axis
     //            ydiff - diff between balls on the y axis
 
     // This function is where the billiard goodness takes place.
     // It's physics madness... I'll explain the bits I think I understand
 
     // find the angle between the balls
        var angle = Math.atan2(ydiff, xdiff);
 
        var cosa = Math.cos(angle);
        var sina = Math.sin(angle);
 
     // find the current linear momentum on each axis for each ball
     // I think this rotates the coordinate system so that we can
     // determine a 2 dimensional collision
        var vx1p = cosa * b1.getVX() + sina * b1.getVY();
        var vy1p = cosa * b1.getVY() - sina * b1.getVX();
        var vx2p = cosa * b2.getVX() + sina * b2.getVY();
        var vy2p = cosa * b2.getVY() - sina * b2.getVX();
 
     // P = momentum?
     // V = velocity?
        var P = vx1p * b1.getMass() + vx2p * b2.getMass();
        var V = vx1p - vx2p;
 
        vx1p = (P - b2.getMass() * V)/(b1.getMass() + b2.getMass());
        vx2p = V + vx1p;
 
     // tell each ball how fast they're going on each axis
        b1.setVX(cosa * vx1p - sina * vy1p);
        b1.setVY(cosa * vy1p + sina * vx1p);
        b2.setVX(cosa * vx2p - sina * vy2p);
        b2.setVY(cosa * vy2p + sina * vx2p);
 
     // Work out the where the balls are colliding along the
     // "Line of Action" so that we can project them far enough
     // away from each other to no longer intersect
        var diff = ((b1.getRadius() + b2.getRadius()) - dist) / 2;
 
        var cosd = cosa * diff;
        var sind = sina * diff;
 
     // update their temporary positions
        b1.setBX(b1.getBX()- cosd);
        b1.setBY(b1.getBY()- sind);
        b2.setBX(b2.getBX()+ cosd);
        b2.setBY(b2.getBY()+ sind);
    }
}