Custom physics has ball sinking through ground after losing energy?

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.

1 Like

Alright so this is what it print out on the first bounce

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.

1 Like

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

image

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

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.