Circle to Circle Collision

BlitzMax Forums/BlitzMax Programming/Circle to Circle Collision

I have been trying with no success to figure out how to deflect a moving circle off of a stationary circle. I have been pouring through all kinds of 2d Vector math and am having problems figuring out this one thing. It's easy to determine if the two circles collide. but once they do I need to calculate the reflection angle. I am using a basic 2d vector type and I have been looking at the Max 2D physics community project. It's becoming a little over whelming.. Is there anyone out there that can help me in a basic way how to do what I want.

Thanks for any help... I'm getting a little frustrated.
Eric

This is perfect, I have used it myself in Blitz:

http://freespace.virgin.net/hugo.elias/models/m_snokr.htm

Thanks I will work with this....Do you have a small working sample?

This was 3D. Assume z to be Y in 2D. Other things to note: each frame you add vx to x and vy to y. That gives you your ball positions... was a large array of types.

This assumes 2 snooker balls (a and b) have already collided. Use a simple distance check for collisions between two circles.

The code deals with response ie... rebounding correctly.

;ball a pos
A_X# = EntityX(ball(a)\object)
A_Z#=EntityZ(ball(a)\object)
						
;ball b pos
B_X# = EntityX(ball(b)\object)
B_Z# = EntityZ(ball(b)\object)
					
;store a
impact_X_A# = ball(a)\vx#
impact_Z_A# = ball(a)\vz#
									
;store b					
impact_X_B# = ball(b)\vx#
impact_Z_B# = ball(b)\vz#
						
;calculate impact of a and b
impact_X# = impact_X_A# - impact_X_B#
impact_Z# = impact_Z_A# - impact_Z_B#
			
;calculate the new impulse speed
impulse_X# = normalise(B_X# - A_X#)
impulse_Z# = normalise(B_Z# - A_Z#)
						
;calculate the new impact speeds
impactspeed_X# = (impact_X# * impulse_X#)
impactspeed_Z# = (impact_Z# * impulse_Z#)
						
;multiply impulse by masses
impulse_X# = impulse_X# * impactspeed_X# * MASS# * MASS#
impulse_Z# = impulse_Z# * impactspeed_Z# * MASS# * MASS#

;place back into equation
ball(a)\vx# = ball(a)\vx# - impulse_X# / MASS#
ball(a)\vz# = ball(a)\vz# - impulse_Z# / MASS#


It is a blitz version of the hugo elias stuff.

I hate to ask this, but can someone put this in code that runs... I've very frustrated with this topic and could use some help. It's important that the conservation of momentum is observed.

Thanks,
Eric

Heres a simple 2D Snooker/Pool example I converted to Max ...

The main Circle<>Circle collision checking is done via the UpdateBallPhysics() function.
You might want to play around with the FRICTION, BALL_MASS, and BALL_RADIUS constants too.


Rem
 Title: Billiards Style Collision Physics
 Description: 2D circle collision response which
 can be used where 2 objects collide in 2 dimensions

 2D COLLISION 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@...
End Rem

Const sw=800 , sh=600

Const FRICTION#		=	0.982
Const BALL_MASS#		=	160.0
Const BALL_RADIUS#	=	15.0

SetGraphicsDriver GLMax2DDriver()
Graphics sw,sh,0,60
SetClsColor 16,172,78

SeedRnd MilliSecs()

Global dx#=-1.0 , dy#=0 , power#=0.0

Global ballList:TList=New TList
Type ballType
	Field x#, y#     ' position
	Field dx#, dy#   ' x and y speeds
	Field radius#    ' radius of ball
	Field mass#      ' mass of ball
	Field r%,g%,b%   ' ball color
End Type

SetupTriangle
Global cueball:ballType=New ballType
SetupCueBall


' #############################################################

' MAIN LOOP
Repeat
	Global mx%,my%
	
	SetClsColor 60,140,80
	Cls
	UpdateBallPhysics
	RenderBalls

	' shoot
	If MouseDown(1)
		power=power+0.3+(power*0.04)
		If power>50.0 power=50.0
	Else
		If cueball.dx=0 And cueball.dy=0 ' ball stopped
			FlushMouse
			ang=angle(cueball.x,cueball.y,mx,my)
			cueball.dx=Sin(ang)*power ;	cueball.dy=-Cos(ang)*power
			power=0
		EndIf
	EndIf

	' reset
	If MouseHit(2)
		ballList.Clear
		SetupTriangle
		SetupCueBall
	End If

	' show shoot line when balls are stationary
	' (currently, only checks for cue ball stopped)
	If cueball.dx=0 And cueball.dy=0
		SetColor 180,180,180
		SetAlpha 0.4 ; SetBlend ALPHABLEND
		mx%=MouseX() ; my%=MouseY()
		dx=(mx-cueball.x)/20 ; dy=(my-cueball.y)/20
		DrawLine cueball.x,cueball.y,mx,my
		DrawOval mx-cueball.radius, my-cueball.radius, cueball.radius*2, cueball.radius*2
		DrawOval mx-cueball.radius+1, my-cueball.radius+1, cueball.radius*2-2, cueball.radius*2-2
		SetAlpha 1.0
	EndIf

	' draw power bar
	SetColor 0,0,0 ; SetAlpha 0.7
	DrawRect sw*0.3-1,sh-26,50*4+2,18
	SetColor 170,251,206
	DrawRect sw*0.3,sh-25,power*4,16

	SetAlpha 1.0 ; SetBlend MASKBLEND
	SetColor 200,200,200
	DrawText "[LMB] Shoot   [RMB] Reset    [Esc] Exit",10,10
	
	Flip
Until KeyHit(KEY_ESCAPE)

End

' #############################################################


Function SetupTriangle()
	Const ballTriangleSize%=5
	For Local xloop% = ballTriangleSize To 1 Step -1
		For Local yloop% = 1 To xloop
			Local c:ballType = New ballType
			ballList.AddLast c
			c.radius = BALL_RADIUS
			c.mass = BALL_MASS
			c.x = (5-xloop)*27 + 200
			c.y = (yloop*31) - (xloop*31)/2.0 + (sh/2)
			c.r=Rand(255) ; c.g=Rand(255) ; c.b=Rand(255)
		Next
	Next
End Function

Function SetupCueBall()
	cueball.x = sw-BALL_RADIUS-8
	cueball.y = sh/2
	cueball.dx=0.0 ; cueball.dy=0.0
	cueball.radius = BALL_RADIUS
	cueball.mass = BALL_MASS
	cueball.r=255 ; cueball.g=255 ; cueball.b=255
	ballList.Addlast cueball
End Function

Function UpdateBallPhysics()
' This is the main physics function for the
' balls. It contains the very basic movement
' physics as well as the collision response code
	For Local c:ballType = EachIn ballList
		' update positions
		c.x=c.x+c.dx
		c.y=c.y+c.dy
		' gradually slow down
		c.dx=c.dx*FRICTION
		c.dy=c.dy*FRICTION
		' stop completely when below a certain speed
		If Abs(c.dx)<0.068 Then c.dx=0
		If Abs(c.dy)<0.068 Then c.dy=0
		' COLLISION CHECKING
		' Check each ball in the loop against
		' every other (c against c2)
		For Local c2:ballType = EachIn ballList
			Local collisionDistance# = c.radius+c2.radius
			Local actualDistance# = Sqr((c2.x-c.x)^2+(c2.y-c.y)^2)
			' collided or not?
			If actualDistance<collisionDistance Then
				Local collNormalAngle#=ATan2(c2.y-c.y, c2.x-c.x)
				' position exactly touching, no intersection
				Local moveDist1#=(collisionDistance-actualDistance)*(c2.mass/Float((c.mass+c2.mass)))
				Local 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 balls.
				' we are finding the components of the normalised vector n
				Local nX#=Cos(collNormalAngle)
				Local nY#=Sin(collNormalAngle)
				' now find the length of the components of each movement vectors
				' along n, by using dot product.
				Local a1# = c.dx*nX  +  c.dy*nY
				Local a2# = c2.dx*nX +  c2.dy*nY
				' optimisedP = 2(a1 - a2)
				'             ----------
				'              m1 + m2
				Local optimisedP# = (2.0 * (a1-a2)) / (c.mass + c2.mass)
				' now find out the resultant vectors
				'' Local r1% = c1.v - optimisedP * mass2 * n
				c.dx = c.dx - (optimisedP*c2.mass*nX)
				c.dy = c.dy - (optimisedP*c2.mass*nY)
				'' Local 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
			c.x=c.radius
			c.dx=c.dx*-0.9
		End If
		If c.x>GraphicsWidth()-c.radius
			c.x=GraphicsWidth()-c.radius
			c.dx=c.dx*-0.9
		End If
		If c.y<c.radius
			c.y=c.radius
			c.dy=c.dy*-0.9
		End If
		If c.y>GraphicsHeight()-c.radius
			c.y=GraphicsHeight()-c.radius
			c.dy=c.dy*-0.9
		End If
	Next
End Function

Function RenderBalls()
	For Local c:ballType = EachIn ballList
		SetColor c.r,c.g,c.b
		DrawOval c.x-c.radius, c.y-c.radius, c.radius*2, c.radius*2
	Next
End Function

Function dist%(x1#, y1#, x2#, y2#)
	Local xd% = Abs(x1# - x2#) , yd% = Abs(y1# - y2#)
	Return Sqr(xd * xd + yd * yd)
End Function

Function angle%(x1#,y1#,x2#,y2#)
	Local angle%=ATan2(x2-x1,y2-y1)
	Return 180-angle
End Function


Now..Finally something I can play with...Thanks much Jim.

cool little program Jim.

Sorry to bump this, but I'd like to know how to calculate the force of a collision between two objects in the billiards code.

I'm thinking that high-speed head on collisions will cause more damage than slight glances, but I'm no mathematician. :)

Anyone?

Ignore the force and use the momentum

There is a law that says that in a collision the total sum of the momentum is the same before and after the collision.

the momentum is given by
Try reading this site
http://en.wikipedia.org/wiki/Momentum
and see if you can make any sense of it