Code archives/Algorithms/Billiards Style Collision Physics

This code has been declared by its author to be Public Domain code.

Download source code

Billiards Style Collision Physics by Phish
(Posted 24 years ago)
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
;------------------------------------------
;------------------------------------------