package game { import flash.geom.Point; import flash.geom.Rectangle; public class BallManager { protected var _game:BallGame; public function BallManager( game:BallGame ) { _game = game; } /** * Check collision for each ball */ public function update():void { var arr:Array; var bounds:Rectangle = _game.container; var detail:int = 5; var si:Number = 1 / detail; //interpolate the collission over some small degree for more accurate collision for (var i:int = 0; i < detail; i++) { var arr = _game.balls; for each(var ball:Ball in arr) { //update ball positions by the interpolated degree ball.x += ball.velX * si; ball.y += ball.velY * si; //check if they've collided with the wall if (ball.x + ball.radius > bounds.right) ball.velX = -Math.abs(ball.velX); else if (ball.x - ball.radius < bounds.left) ball.velX = Math.abs(ball.velX); else if (ball.y + ball.radius > bounds.bottom) ball.velY = -Math.abs(ball.velY); else if (ball.y - ball.radius < bounds.top) ball.velY = Math.abs(ball.velY); } //Check ball to ball collision while( arr.length ) { var pull:Ball = arr.pop(); var collides:Ball = filterColliding( pull, arr ); //if they collided update there positions and velocities if (collides) { var norm:Point = new Point( collides.x - pull.x, collides.y - pull.y ); var dis:Number = norm.length; var poc:Point = new Point( pull.x, pull.y ); norm.normalize(1); //get the point at which they collided var cen:Number = dis * ( pull.radius / ( pull.radius + collides.radius ) ); poc.x += norm.x * cen; poc.y += norm.y * cen; //move them to a position where they aren't overlapping anymore collides.x = poc.x + norm.x * collides.radius; collides.y = poc.y + norm.y * collides.radius; pull.x = poc.x - norm.x * pull.radius; pull.y = poc.y - norm.y * pull.radius; //reflect their velocities var colVel:Point = new Point( collides.velX, collides.velY ); colVel = reflectVector( colVel, norm ); norm.x *= -1; norm.y *= -1; var pullVel:Point = new Point( pull.velX, pull.velY ); pullVel = reflectVector( pullVel, norm ); //set the new velocity pull.velX = pullVel.x; pull.velY = pullVel.y; collides.velX = colVel.x; collides.velY = colVel.y; } } } } /** * Returns a Ball in the array if it collides with the supplied ball reference */ protected function filterColliding( ball:Ball, arr:Array ):Ball { for each(var sub:Ball in arr) { var ix:Number = sub.x - ball.x; var iy:Number = sub.y - ball.y; var disSqr:Number = ix * ix + iy * iy; var shrt:Number = ball.radius + sub.radius; shrt *= shrt; if (disSqr < shrt) return sub; } return null; } /** * reflects a vector over some normal line */ protected function reflectVector(vel:Point, norm:Point ):Point { var dot:Number = vel.x * norm.x + vel.y * norm.y; dot *= 2; vel.x -= norm.x * dot; vel.y -= norm.y * dot; return vel; } } }