I let this rest for a while but came back to it because I wasn't satisfied. Studying up on rudementary physics and trig I've come to the conclusion that a lot of the demos and explanations on the internet are incomplete and in some cases just wrong. Or, on the opposite side of the coin, I am incomplete or just plain wrong!
Anyway, I went back to conservation of momentum principles, crashed a couple of matchbox cars together over and over to see what they were doing, and took another stab at my collision routine. As I had written previously, the big problem was dealing with an indirect hit, or glancing collision and dealing with the angle in relation to the collision normal.
In my scenario, I'm neglecting the influence of friction between the objects, and I'm neglecting spin. But I'm including deceleration which implies friction with the surface. What I've come up with seems to accurately depict colliding sphere's in 2 dimensions most of the time. Because of a bug, the sphere's sometimes go off in bizaar directions - I'll have to track that down.
The big problem with the angle between the balls actually had something to do with the atanfull() function. It calculates angles in the opposite direction to sin() cos() and tan(). This was a big deal because it threw off my calculations over and over and I couldn't figure out why. After reviewing a similar function in C, atan2(), I discovered that if I just reversed the x and the y in the atanfull() function and was fine! (I used atanfull(y,x) instead of the help file indication of atanfull(x,y) ). Now I could effectively calculate the angle between the collision normal (CN), and the direction a ball was traveling (this is the angle one ball hits the other at).
Ok this is fine. But now, in every case, this newly found angle always treated the CN as the x axis, regardless of what the CN angle was. I fixed this by calcuating the formed angle as if it were at the origin, and then just rotated the results to the angle the CN really was.
Here's some psuedo code of the procedure:
rem direction = angle a ball is moving relative to the world
rem normal = the collision line between two objects at a specific
rem angle relative to the world
rem theta = angle: the difference between the direction and the normal
rem mass1, mass2 ... = masses of the objects
rem speed1, speed2 ... = speeds of the objects
while the distance between the objects is > the sum of their radii
move whiteball at a certain speed // this could be a loop that applies to all the objects
endwhile
if there is a collision
theta = direction - normal
rem calculate the velocity along normal and
rem the velocity tangent to the normal for both
rem objects
rem vain - ball1 initial velocity along normal
rem vait - ball1 initial velocity along tangent
rem vbin - ball2 initial velocity along normal
rem vbit - ball2 initial velocity along tangent
vain = speed1*(cos(theta))
vait = speed1*(sin(theta))
vbin = speed2*(cos(theta2)) // if the second ball was moving in a different direction and not stationary - theta2
vbit = speed2*(sin(theta2))
rem the tangent directions are never affected by the
rem collision and therefore never change.
rem therefore vaft=vait and vbft=vbit. The collision
rem occurs along the CN so we have to apply conservation
rem of momentum to find the final velocities along
rem the CN. Then we have to use this velocity and the
rem tangent to find the new direction and speed
vfin=((vain*mass1)+(vbin*mass2))/(mass1+mass2)
vaft=vait
vbft=vbit
rem treat vfin as x for both objects and vaft,vbft as y
rem for each object, then rotate those back relative to
rem normal - Remember we were treating theta as if it
rem were opening up from x=0
vx1#=x_rotate(vfin,vatf,normal)
vz1#=y_rotate(vatf,vfin,normal)
vx2#=x_rotate(vfin,vbtf,normal)
vz2#=y_rotate(vbtf,vfin,normal)
rem now add these coordinates to the position of the balls
inc lastx1,vx1#
inc lastz1,vz1#
inc lastx2,vx2#
inc lastz2,vz2#
Rem my rotation functions
rem rotate x back to collision quad
function x_rotate(x#,y#,angle#)
xprime#=(x#*cos(angle#))-(y#*sin(angle#))
endfunction xprime#
rem rotate y (z in this case) back to collision quad
function y_rotate(y#,x#,angle#)
yprime#=(x#*sin(angle#))+(y#*cos(angle#))
endfunction yprime#
This is basically where I am with this right now. It does a pretty good job but there are a few glitches. If anyone can give any feedback that would be great.
I've included a demo. Needs a little work on the collision detection, but it's functional for the most part.
Enjoy your day.