Code archives/Algorithms/Billiards Style Collision Physics
This code has been declared by its author to be Public Domain code.
Download source code
| This type of collision response isn't just useful for pool and billiard style games, and in fact, I didn't write it for that reason at all. I wrote it because I needed to have collision for the space ships in my game 'Unity'. When their shields are up, they use this relatively simple method. It can be used for almost anything - player character bouncing off enemies in a platform game, to space ship collision, to a game which does actually involve balls. The basic algorithm which I used would work for both 2d and 3d so if you would like to see it, email me at phish@.... I think that realistic physics, even if pretty simple, can make a game feel a lot more immersive and interesting. The idea is that you should read my code, see how I use the collision response section, hack it up, and use it in your own game :-) |
;------------------------------------------ ;2D COLLISION DEMO CODE ;------------------------------------------ ; By Joseph 'Phish' Humfrey ; This type of collision response isn't ; just useful for pool and billiard style ; games, and in fact, I didn't write it for ; that reason at all. I wrote it because I ; needed to have collision for the space ; ships in my game 'Unity'. When their ; shields are up, they use this relatively ; simple method. It can be used for almost ; anything - player character bouncing off ; enemies in a platform game, to space ; ship collision, to a game which does ; actually involve balls. The basic ; algorithm which I used would work for ; both 2d and 3d, so if you would like to ; see it, email me at phish@aelius.com ;------------------------------------------ ; The actual code which works out what ; happens after a collision is in the ; UpdateCirclePhysics() function. ;------------------------------------------ ; Enjoy! ;------------------------------------------ ;------------------------------------------ Graphics 800, 600, 16, 2 SetBuffer BackBuffer() SeedRnd MilliSecs() ;------------------------------------------ ; MAIN DATA TYPE ;------------------------------------------ ; This exact type isn't supposed to be used ; Instead, you should use some of the fields ; in your own type, or just use this one ; for reference, to see what each field does Type circle Field x#, y# ;position Field dx#, dy# ;x and y speeds Field radius# ;radius of circle Field mass# ;mass of circle End Type ;------------------------------------------ ;------------------------------------------ ;------------------------------------------ ; SET UP BALLS INTO A POOL STYLE ARRANGEMENT ; FOR DEMO ;------------------------------------------ .Setup ballTriangleSize=5 For xloop = ballTriangleSize To 1 Step -1 For yloop = 1 To xloop c.circle = New circle c\x = (5-xloop)*27 + 200 c\y = yloop*31-(xloop*31)/2.0 + 300 c\dx=0 c\dy=0 c\radius = 15 c\mass = 50 Next Next ;Cue ball (smaller so you know which it is :) cue.circle = New circle cue\x = 800 cue\y = 300 +20 cue\dx = -20 cue\dy = Rnd(4)-2 cue\radius = 14 cue\mass = 50 ;------------------------------------------ ;------------------------------------------ ;------------------------------------------ ;MAIN LOOP ;------------------------------------------ ; This is the main While..Wend game loop While Not KeyDown(1) Cls UpdateCirclePhysics() RenderCircles() ;------------ ; Reset button Text 10, 10, "Press a mouse button to reset." Text 10, 25, "Press Esc to exit." If GetMouse() Then For c.circle = Each circle Delete c Next Goto setup End If ;------------ Flip Wend ;------------------------------------------ ;------------------------------------------ End ;------------------------------------------ Function UpdateCirclePhysics() ;------------------------------------------ ; This is the main physics function for the ; circles. It contains the very basic ; movement physics as well as the collision ; response code. ;------------------------------------------ For c.circle = Each circle ;update positions c\x=c\x+c\dx c\y=c\y+c\dy ;gradually slow down c\dx=c\dx*0.99 c\dy=c\dy*0.99 ;------------------------------------------ ;COLLISION CHECKING ;------------------------------------------ ; Check each circle in the loop against ; every other (c against c2) For c2.circle = Each circle collisionDistance# = c\radius+c2\radius actualDistance# = Sqr((c2\x-c\x)^2+(c2\y-c\y)^2) ;Collided or not? If actualDistance<collisionDistance Then collNormalAngle#=ATan2(c2\y-c\y, c2\x-c\x) ;Position exactly touching, no intersection moveDist1#=(collisionDistance-actualDistance)*(c2\mass/Float((c\mass+c2\mass))) moveDist2#=(collisionDistance-actualDistance)*(c\mass/Float((c\mass+c2\mass))) c\x=c\x + moveDist1*Cos(collNormalAngle+180) c\y=c\y + moveDist1*Sin(collNormalAngle+180) c2\x=c2\x + moveDist2*Cos(collNormalAngle) c2\y=c2\y + moveDist2*Sin(collNormalAngle) ;------------------------------------------ ;COLLISION RESPONSE ;------------------------------------------ ;n = vector connecting the centers of the circles. ;we are finding the components of the normalised vector n nX#=Cos(collNormalAngle) nY#=Sin(collNormalAngle) ;now find the length of the components of each movement vectors ;along n, by using dot product. a1# = c\dx*nX + c\dy*nY a2# = c2\dx*nX + c2\dy*nY ;optimisedP = 2(a1 - a2) ; ---------- ; m1 + m2 optimisedP# = (2.0 * (a1-a2)) / (c\mass + c2\mass) ;now find out the resultant vectors ;r1 = c1\v - optimisedP * mass2 * n c\dx = c\dx - (optimisedP*c2\mass*nX) c\dy = c\dy - (optimisedP*c2\mass*nY) ;r2 = c2\v - optimisedP * mass1 * n c2\dx = c2\dx + (optimisedP*c\mass*nX) c2\dy = c2\dy + (optimisedP*c\mass*nY) End If Next ;------------------------------------------ ;------------------------------------------ ;Simple Bouncing off walls. If c\x<c\radius Then c\x=c\radius c\dx=c\dx*-0.9 End If If c\x>GraphicsWidth()-c\radius Then c\x=GraphicsWidth()-c\radius c\dx=c\dx*-0.9 End If If c\y<c\radius Then c\y=c\radius c\dy=c\dy*-0.9 End If If c\y>GraphicsHeight()-c\radius Then c\y=GraphicsHeight()-c\radius c\dy=c\dy*-0.9 End If Next End Function ;------------------------------------------ Function RenderCircles() ;------------------------------------------ ; Simple function draws all the circles ; on the screen. ;------------------------------------------ For c.circle = Each circle If c\radius=15 Then Color 200, 50, 50 Else Color 255, 255, 255 Oval c\x-c\radius, c\y-c\radius, c\radius*2, c\radius*2 Next End Function ;------------------------------------------ ;------------------------------------------ |