I know there are tons of posts dealing with ball vs ball collision and I have looked over any I could find, however none of them seem to work exactly like I want and I have been looking over examples for weeks now.
I have a script I modified from this site
(http://www.krazydad.com/bestiary/bestiary_superball.html)
that is pretty close but there is one problem I have yet to solve. Here is my modified code:
This part just updates the balls position based on their vx and vy variables. It gets called on a timer:
public function moveBalls():void {
var loopLength=ballArray.length-1;
for (var count:int=0; count<=loopLength; count++) {
var currentBall=ballArray[count];
var currentBallRadius=currentBall.ballRadius;
currentBall.tempX = currentBall.x;
currentBall.tempY = currentBall.y;
currentBall.tempX += currentBall.vx;
currentBall.tempY += currentBall.vy;
if (currentBall.tempY-currentBallRadius<topEdge) {
currentBall.tempY = topEdge+currentBallRadius;
currentBall.vy *= -1;
}
else if (currentBall.tempY+currentBallRadius>bottomEdge) {
currentBall.tempY = bottomEdge-currentBallRadius;
currentBall.vy *= -1;
}
if (currentBall.tempX-currentBallRadius<leftEdge) {
currentBall.tempX = leftEdge+currentBallRadius;
currentBall.vx *= -1;
}
else if (currentBall.tempX+currentBallRadius>rightEdge) {
currentBall.tempX = rightEdge-currentBallRadius;
currentBall.vx *= -1;
}
}
for (count=0; count<=loopLength; count++) {
currentBall=ballArray[count];
for (var subCount:int=count+1; subCount<=loopLength; subCount++) {
var currentSubBall=ballArray[subCount];
var xdiff:Number = currentSubBall.tempX-currentBall.tempX;
var ydiff:Number = currentSubBall.tempY-currentBall.tempY;
var dist:Number = Math.sqrt(xdiff*xdiff+ydiff*ydiff);
if ((dist<=(currentBallRadius+currentSubBall.ballRadius)) && (!currentBall.isCollide ||!currentSubBall.isCollide) ) {
currentBall.isCollide=true;
currentSubBall.isCollide=true;
doCollisionNew(currentBall,currentSubBall,dist,xdiff,ydiff);
}
else {
currentBall.isCollide=false;
currentSubBall.isCollide=false;
}
}
}
updateBalls();
}
Next we actually update the balls real position:
function updateBalls():void {
var loopLength=ballArray.length-1;
for (var count:int=0; count<=loopLength; count++) {
var currentBall=ballArray[count];
currentBall.x = currentBall.tempX;
currentBall.y = currentBall.tempY;
}
}
Ok, and here is the real part I’m having problems with. It gets called when there is a collision:
function doCollisionNew(b1:BreakerBall, b2:BreakerBall,dist,xdiff,ydiff):void {
var mag1 = Math.sqrt(b1.vx*b1.vx+b1.vy*b1.vy);
var mag2 = Math.sqrt(b2.vx*b2.vx+b2.vy*b2.vy);
if ( dist==0) {
var angle = Math.atan2(ydiff,xdiff);
var cosa = Math.cos(angle);
var sina = Math.sin(angle);
var diff = ((b1.ballRadius+b2.ballRadius)-dist)/2;
var cosd = cosa*diff;
var sind = sina*diff;
b1.tempX -= cosd;
b1.tempY -= sind;
b2.tempX += cosd;
b2.tempY += sind;
b2.vx=-b1.vx;
b2.vy=-b1.vy;
b1.vx=-b2.vx;
b1.vy=-b2.vy;
}
else {
b2.vx = (mag1*xdiff/dist);
b1.vx = -(mag2*xdiff/dist);
b2.vy = (mag1*ydiff/dist);
b1.vy = -(mag2*ydiff/dist);
}
}
Most of it is the same as jbum’s script (http://www.krazydad.com/bestiary/bestiary_superball.html) except I added the part within the if statement ( if (dist==0) {…} ). This is kind of a hack, because I found if the balls are moving fast enough where they end up on top of each other, the vx/vy comes back as NaN and the balls end up stuck in the top left corner of the screen. Probably not the “right” way to do things, but it seems to work ok for my purposes.
Alright, so what I’m looking for is a random number of balls bouncing around the screen and colliding against each other in the simplest way possible. Everything works fine with this code, however if two balls start at the same Y position and travel down and toward each other, they collide wrong. Instead of moving outward from each other and continuing down, instead they just get stuck bouncing back and forth straight on x. Here is an example of this where ball1 starts at x=30, y=50 and ball2 starts at x=230, y=50. The first ball has vx=5, vy=5 and the second ball is vx=-5, vy=5.
http://metalblend.com/ballTest/proto-2a.html
This should work more like this:
http://metalblend.com/ballTest/proto-2b.html
The problem I see is that if the first balls vy is equal to the second balls vy then the variable ydiff is equal to zero. This causes this
b2.vy = (mag1*ydiff/dist);
b1.vy = -(mag2*ydiff/dist);
to set both balls vy to zero, making them ‘stuck’ on the x plane.
I can get it to work right (shown in the second link) using this script for the collision calculation instead:
function doCollision(b1:BreakerBall, b2:BreakerBall, dist:Number, xdiff:Number, ydiff:Number):void {
var angle = Math.atan2(ydiff,xdiff);
var cosa = Math.cos(angle);
var sina = Math.sin(angle);
var vx1p = cosa*b1.vx+sina*b1.vy;
var vy1p = cosa*b1.vy-sina*b1.vx;
var vx2p = cosa*b2.vx+sina*b2.vy;
var vy2p = cosa*b2.vy-sina*b2.vx;
var P = vx1p+vx2p;
var V = vx1p-vx2p;
vx1p = (P-V)/2;
vx2p = V+vx1p;
b1.vx = cosa*vx1p-sina*vy1p;
b1.vy = cosa*vy1p+sina*vx1p;
b2.vx = cosa*vx2p-sina*vy2p;
b2.vy = cosa*vy2p+sina*vx2p;
var diff = ((b1.ballRadius+b2.ballRadius)-dist)/2;
var cosd = cosa*diff;
var sind = sina*diff;
b1.tempX -= cosd;
b1.tempY -= sind;
b2.tempX += cosd;
b2.tempY += sind;
}
There are a couple problems with using the second script though. One of the main problems, is that I would like all the balls to stay at a constant speed after they collide. This is probably more of a “fake” collision, but that is what I am looking for. With this second function if you start all balls out with the same speed like vx=5,vy=5 for all balls, after bouncing for a bit, some start to move slower and some start to move faster.
Here is an example of this problem (using the more complex script):
http://metalblend.com/ballTest/proto-2c.html
The first script (jbum’s) doesn’t do this (they stay at a constant speed):
http://metalblend.com/ballTest/proto-2d.html
Also this second function has much more calculations to it and I’d rather keep it simple to avoid overhead and frame rate problems when dealing with a lot of balls bouncing. As well, this script is too confusing for me to understand for the most part :).
So…if anyone knows an easy way to make the first script work right, without the problem of getting stuck on the x plane, MUCH APPRECIATED :).
Oh,and the source file’s I’m playing with can be downloaded here:
http://metalblend.com/ballTest/ballTest.zip