Fixing Ball Not Bouncing Off Wall Correctly

[SCROLL DOWN TO THE LATEST REPLY I DIDNT WANT TO CLOG POSTS]

I’ve been working on this game for a little bit where you play soccer, I’ve encountered a problem with heartbeat where it’s slower in game than in studio. I’ve tried a few solutions but none seem to work out.

In-Game:

Studio:


(The heartbeat rate is ~240)

I don’t want a whole system being written, I just need to know where I should look for ways to make this possible, alongside with a prediction system.

My code currently:

game["Run Service"].Heartbeat:Connect(function(dt)
	BallPhysicsEnabled = not (BallHolder)
	Ball.Trail.Enabled = BallPhysicsEnabled

	if BallPhysicsEnabled then
		local vel:Vector3 = Ball:GetAttribute("Velocity")
		local velWithoutY = Vector3.new(vel.X,0,vel.Z)
		local params = RaycastParams.new(); params.FilterType = Enum.RaycastFilterType.Include; params.FilterDescendantsInstances = {workspace.Field}
		local CheckResolution = Ball.Size.Y/16
		local AirTime = tick()-AirBegin
		local angVel:Vector3 = Ball:GetAttribute("AngularVelocity")
		
		local rayDir = vel*Ball.Size.Y
		local movementRay = workspace:Raycast(Ball.Position,rayDir,params)
		if movementRay then
			local normal =movementRay.Normal
			if normal == Vector3.new(0,1,0) then
				vel = Vector3.new(vel.X,-vel.Y*BounceAmount,vel.Z)
			else
				vel *= -normal
			end
			func:PlaySound(SoundService.SFX.BallGround,.5,Ball)
		end
		velWithoutY = Vector3.new(vel.X,0,vel.Z)
		
		local gRay = workspace:Raycast(Ball.Position,Vector3.new(0,-5000,0),params); local dist; if gRay then dist = gRay.Distance GroundPosition=gRay.Position.Y else dist = math.huge end
		Grounded = dist <= CheckResolution+Ball.Size.Y/1.85
		if not Grounded then
			vel -= Vector3.new(0,GravityAmount,0)
			vel = Vector3.new(vel.X,math.clamp(vel.Y,-CheckResolution*16,math.huge),vel.Z)
			if not OldGrounded then AirBegin = tick() end
		else
			if OldGrounded and vel.Y < 0 and math.abs(vel.Y) <= 0.1 then 
				vel = velWithoutY 
				func:PlaySound(SoundService.SFX.BallGround,.5,Ball)
			end
		end
		
		if vel.Magnitude > 0.1 then
			angVel += Ball.CFrame:VectorToWorldSpace(Vector3.new(vel.Unit.Z,0,0))
		end
		
		local frictionAmount = .005; if Grounded then frictionAmount = .015 end
		Ball.Rotation += angVel/18; angVel = angVel:Lerp(Vector3.zero,frictionAmount)
		
		local bpos = Ball.Position+vel
		local grnd = workspace.Field.MainGround
		local x = math.clamp(bpos.X,-grnd.Size.X/2,grnd.Size.X/2)	
		local z = math.clamp(bpos.Z,-grnd.Size.Z/2,grnd.Size.Z/2)
		Ball.Position = Vector3.new(x,math.clamp(bpos.Y,GroundPosition+CheckResolution,math.huge),z)
		
		Ball:SetAttribute("Velocity",velWithoutY:Lerp(Vector3.zero,frictionAmount)+Vector3.new(0,vel.Y,0))
		Ball:SetAttribute("AngularVelocity",angVel)
		OldGrounded = Grounded
		
		if CanScore then
			local touching = workspace:GetPartsInPart(Ball)
			for i,v in touching do
				if v.Parent == workspace.GoalHitboxes then
					ScoreAgainst(v.Name,LastTouch.Player)
				end
			end
		end
	else
		Ball:SetAttribute("Velocity",Vector3.zero)
		Ball:SetAttribute("AngularVelocity",Vector3.zero)
	end
	if BallHolder then
		Ball.Position = BallHolder.HumanoidRootPart.BallPosition.WorldPosition
	end
end)
1 Like

What you want is the Heartbeat running at a precise FPS. You can do this by doing an if statement.

local RS = game:GetService("RunService")

local accumulated = 0
local rate = 60 -- max "FPS"

local FPS = 1/rate

RS.Heartbeat:Connect(function(DT)
     accumulated += DT

     if accumulated >= FPS then
         -- your whole system goes here.
     end
end)

I tried your solution and it doesnt seem to work at all, in-game is still slower than in studio, this is the logic i used: (I only want the ball to have ~60 fps)

local accumulated = 0
local rate = 60
local FPS = 1/rate

game["Run Service"].Heartbeat:Connect(function(dt)
	BallPhysicsEnabled = not (BallHolder)
	Ball.Trail.Enabled = BallPhysicsEnabled
	if BallPhysicsEnabled then accumulated += dt end
	if BallPhysicsEnabled and accumulated >= FPS then
           -- rest of the logic here
    end
end)

Are you factoring in frame time in your calculations?

I’ve tried and the result doesn’t turn out well, the ball seems to just go slower overall and detect it’s grounded a few studs above the ground, currently rewriting my system so i can predict where the ball will go, factoring in-frame-time calculations in there

Can you show how you’re factoring them in? I don’t see you using delta time in the script you posted.

I tried using dt calculations before posting this, i cant find the exact script but i remember i used this formula:

local framerate = 1/dt
local ns = (framerate/60)
local speed = math.min(1, 1/ns)
-- some other stuff here..
Ball.Position += vel*speed

remember the basic formula

speed = distance / time

dT is the frame time, I’m not sure why you’re converting it to frame rate, then dividing by 60, then dividing 1 by that?

Well i used it in a local script before to sync stuff like lerps, thought it would work on heartbeat too, and also my system wasnt really calculating positions ahead of time, it was more of a reactive system and im currently rewriting it to see if it would fix my issue

Im not the best when it comes to math

Changed my system now its fine.

1 Like

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