We help IT Professionals succeed at work.

# Help with multiple 2D ball collision code

on
1,406 Views
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].rotation = allBallsGroup[i].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
-- ------------------

-- ---------------------------------------------
-- 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
-- -----------------------------------------------------------------------------------

-- --------------------
-- 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
``````
Comment
Watch Question
Commented:
This problem has been solved!
###### 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

Deciding to stick with EE.

Mohamed Asif

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

Carl Webster
CTP, Sr Infrastructure Consultant