hello, im currently in the process of making a custom physics system for just a ball, and everythings working correctly but when the ball comes to rest after losing energy after each bounce, it just slowly starts sinking into the ground
So then I realized I was lacking a normal force which will counteract the force of gravity, but I added it and then it’s still sinking, I’m just not sure what else to do
I know im setting the normal force correctly because I tried multiplying it and it made the ball go up infinitely
Video of issue
The code
game:GetService("RunService").Heartbeat:Connect(function(deltaTime)
local hitPart, hitNormal = detectCollisions()
if hitPart then
resolveCollision(hitPart, hitNormal)
-- Setting the normal force using the angle of the collision normal
local surfaceAngle = math.deg(math.acos(gravity:Dot(hitNormal)/(gravity.Magnitude * hitNormal.Magnitude)))
normalForce = 1 * mass * gravity * math.cos(surfaceAngle)
if hitNormal.Y < 0 then
velocity = Vector3.new(velocity.X, -velocity.Y * e, velocity.Z)
end
end
local netForce = mass * acceleration + normalForce
local dampingForce = -damping * velocity
position = position + velocity + 0.5 * (netForce + dampingForce) / mass
velocity = velocity + (netForce + dampingForce) / mass
acceleration = gravity
ball.CFrame = CFrame.new(position)
end)
How about printing your hitNormal.Y, position, velocity and acceleration right before your CFrame line. It might tell you which of the values from your calculations is causing the ball to sink.
And then I let it hit the ground and sink, but then I looked closely and the Position Y is going down ever so slowly, which is most likely the sinking thats happening, but how do i fix it though?
It looks like your calculatins are suffering from floating point error. Try using math.round to round the values in your calculatins to 2 or 3 decimal places.
Thank you for taking the time to reply, but I found out that the acceleration was causing the position of the ball to descend even when it was touching the ground, so when the raycast hit I just checked if it was done bouncing my getting the length of the velocity vector and seeing if it was a really really small number, and it worked (system is still very buggy thoughh…)
Full Code
local Physics = {}
local ball : Part = workspace.SoccerBall
local mass = 1
local gravity = Vector3.new(0,-0.001,0)
local position = ball.CFrame.Position
local acceleration = gravity
local e = 5
local damping = 0.01
local velocity = Vector3.new(1,0,1)
local function resolveCollision(hitPart : Part, hitNormal)
local collisionNormal = hitNormal
local relativeVelocity = velocity:Dot(collisionNormal)
if relativeVelocity < 0 then
local mass2 = hitPart:GetMass()
local j = -(1 + e) * relativeVelocity / (1 / mass + 1 / mass2)
velocity = velocity + j / mass * collisionNormal
end
end
local function detectCollisions()
local origin = ball.Position
local direction = velocity.Unit
local raycastResult = workspace:Raycast(origin, direction * ball.Size.X / 2)
if raycastResult and raycastResult.Instance ~= ball then
return raycastResult.Instance, raycastResult.Position, raycastResult.Normal
end
end
game:GetService("RunService").Heartbeat:Connect(function(deltaTime)
local hitPart, hitPosition, hitNormal = detectCollisions()
if hitPart then
resolveCollision(hitPart, hitNormal)
if hitNormal.Y < 0 then
velocity = Vector3.new(velocity.X, -velocity.Y * e, velocity.Z)
end
if velocity.Magnitude <= 0.00022 then
acceleration = Vector3.zero
end
local offset = ball.Size.Y / 2
local targetPosition = hitPosition + offset * hitNormal
position = targetPosition
else
local netForce = mass * acceleration
local dampingForce = -damping * velocity
velocity = velocity + (netForce + dampingForce) / mass
acceleration = gravity
position = position + velocity + 0.5 * (netForce + dampingForce) / mass
end
ball.CFrame = CFrame.new(position)
end)
return Physics