We help IT Professionals succeed at work.
Get Started

Help with multiple 2D ball collision code

1,406 Views
Last Modified: 2012-05-10
am having problems with my code for dealing with multiple ball collisions.

The code works absolutely perfect 99% of the time however there appears to be a bug where with certain ball positions, angles and velocities the collision reaction is erratic.

I need this code to be highly optimised as it is for a mobile phone game.

I have spent weeks trying to fix this with the only outcome being my head hurting. When I trace the variable values I can see the problem appears to occur when the value of dt is greater than 1 (see code attached) but I cannot work out how to solve this issue.

Fingers crossed!
local function moveBallObjects()


	local friction = 0.8
	
	local dV = 0.08
	
	
	for i = allBallsGroup.numChildren, 1, -1 do

	
		local horizontalVelocity = allBallsGroup[i].horizontalVelocity
		local verticalVelocity = allBallsGroup[i].verticalVelocity

		local V = (horizontalVelocity * horizontalVelocity) + (verticalVelocity * verticalVelocity)
	
		if V ~= 0 then
			
			V = mSqrt(V)
	
			allBallsGroup[i][2].rotation = allBallsGroup[i][2].rotation + 10 * V
		
			local k = (V - dV) / V
	
			if k < 0 then
	
				k = 0
		
			end
			
			print ("k = " ..k)
	
			allBallsGroup[i].horizontalVelocity = horizontalVelocity * k
			allBallsGroup[i].verticalVelocity = verticalVelocity * k
			
			print ("horizontalVelocity = " .. allBallsGroup[i].horizontalVelocity)
			print ("verticalVelocity = " .. allBallsGroup[i].verticalVelocity)
		
			allBallsGroup[i].tempX = allBallsGroup[i].tempX + allBallsGroup[i].horizontalVelocity
			allBallsGroup[i].tempY = allBallsGroup[i].tempY + allBallsGroup[i].verticalVelocity
			
			for j = allBallsGroup.numChildren, 1, -1 do

				if allBallsGroup[i] ~= allBallsGroup[j] then

					checkForCollisionWithBall (allBallsGroup[i], allBallsGroup[j])

				end
			end
			
			
	
			allBallsGroup[i].x = allBallsGroup[i].tempX
			allBallsGroup[i].y = allBallsGroup[i].tempY

		end
	
		
	
			
	end

	
end


local function checkForCollisionWithBall( firstBallRef, secondBallRef )

	-- ------------------
	-- Set some constants
	-- ------------------

	local radius = 14 -- Radius of ball
	local radiusSquared = (2 * radius) * (2 * radius) -- Radius squared
	
		
	-- ---------------------------------------------
	-- Calculate distance between balls on both axis
	-- ---------------------------------------------
	
	local dx = secondBallRef.tempX - firstBallRef.tempX -- horizontal distance between the 2 balls
	local dy = secondBallRef.tempY - firstBallRef.tempY -- vertical distance between the 2 balls
	
		
	local dxy = (dx * dx) + (dy * dy)
	
	if (dxy < 0.00001) then
	
		print ("dxy less than 0.00001: dxy = " .. dxy)
	
		return
	
	end
	
	-- -----------------------------------------------------------------------------------
	-- If the distance squared is less than the radius squared then we have a collision
	-- Note this is an optimisation to prevent having to perform a square root calculation
	-- -----------------------------------------------------------------------------------
	
	
	if (dxy < radiusSquared) then
	
		-- --------------------
		-- We have a collision!
		-- --------------------
		
		-- ------------------------------------------------------------------------------
		-- We now perform the square root to calculate the distance between the two balls
		-- ------------------------------------------------------------------------------
		
		dxy = mSqrt(dxy)
		
		local cs = dx/dxy
		local sc = dy/dxy
		
		-- -----------------------------------------------------------
		-- Calculate component of velocity in the direction of (dx,dy)
		-- -----------------------------------------------------------
		
		local vp1 = firstBallRef.horizontalVelocity * cs + firstBallRef.verticalVelocity * sc
		local vp2 = secondBallRef.horizontalVelocity * cs + secondBallRef.verticalVelocity * sc
		
		local dt = (radius + radius - dxy) / (vp1 - vp2)
		
		firstBallRef.tempX = firstBallRef.tempX - (firstBallRef.horizontalVelocity * dt)
		firstBallRef.tempY = firstBallRef.tempY - (firstBallRef.verticalVelocity * dt)
			
		secondBallRef.tempX = secondBallRef.tempX - (secondBallRef.horizontalVelocity * dt)
		secondBallRef.tempY = secondBallRef.tempY - (secondBallRef.verticalVelocity * dt)
		
		dx = secondBallRef.tempX - firstBallRef.tempX -- horizontal distance between the 2 balls
		dy = secondBallRef.tempY - firstBallRef.tempY -- vertical distance between the 2 balls
		
		local distance = mSqrt(dx * dx + dy * dy)
		local ax = dx/distance
		local ay = dy/distance
		
		local va1 = (firstBallRef.horizontalVelocity * ax + firstBallRef.verticalVelocity * ay)
		local vb1 = (-1 * firstBallRef.horizontalVelocity * ay + firstBallRef.verticalVelocity * ax)
		
		local va2 = (secondBallRef.horizontalVelocity * ax + secondBallRef.verticalVelocity * ay)
		local vb2 = (-1 * secondBallRef.horizontalVelocity * ay + secondBallRef.verticalVelocity * ax)
		
		local vaP1 = va1 + (1 + 1) * (va2 - va1)/(1 + 1/1)
		local vaP2 = va2 + (1 + 1) * (va1 - va2)/(1 + 1/1)

		
		firstBallRef.horizontalVelocity = vaP1 * ax - vb1 * ay
		firstBallRef.verticalVelocity = vaP1 * ay + vb1 * ax
		
		secondBallRef.horizontalVelocity = vaP2 * ax - vb2 * ay
		secondBallRef.verticalVelocity = vaP2 * ay + vb2 * ax

		
		firstBallRef.tempX = firstBallRef.tempX + firstBallRef.horizontalVelocity * dt
		firstBallRef.tempY = firstBallRef.tempY + firstBallRef.verticalVelocity * dt
		
		secondBallRef.tempX = secondBallRef.tempX + secondBallRef.horizontalVelocity * dt
		secondBallRef.tempY = secondBallRef.tempY + secondBallRef.verticalVelocity * dt
		
		checkForCollisionWithBall ( firstBallRef, secondBallRef )

	
	end
	
end

Open in new window

Comment
Watch Question
Commented:
This problem has been solved!
Unlock 1 Answer and 20 Comments.
See Answer
Why Experts Exchange?

Experts Exchange always has the answer, or at the least points me in the correct direction! It is like having another employee that is extremely experienced.

Jim Murphy
Programmer at Smart IT Solutions

When asked, what has been your best career decision?

Deciding to stick with EE.

Mohamed Asif
Technical Department Head

Being involved with EE helped me to grow personally and professionally.

Carl Webster
CTP, Sr Infrastructure Consultant
Ask ANY Question

Connect with Certified Experts to gain insight and support on specific technology challenges including:

  • Troubleshooting
  • Research
  • Professional Opinions
Did You Know?

We've partnered with two important charities to provide clean water and computer science education to those who need it most. READ MORE