Heartbeat lags behind on server script for script-controlled Goalkeeper

I’ve had some trouble lately trying to script an AI goalkeeper, who aligns himself according to the position of the ball and tries to keep it out. It’s very inconsistent. While it can save powerful shots from a straight angle, it is not able to save corner shots from a weird angle due to it TPing to the ball’s Z.coordinate and disadvantaging himself by either missing the save or putting it into his own net, something that should not happen IRL and should not happen on ROBLOX either. I can’t figure out a way to make it run smoother, as LocalScript renderstepped does not work (no clue why it’s not moving, maybe something with NetworkOwnership), and server .Stepped makes no difference. I have to do it on the server as I want to set network ownership of the ball to the server and makes it more convenient to run.


game:GetService("RunService").Heartbeat:Connect(function()
	if animPlaying then return end
	if workspace:FindFirstChild("GameBall") then
		local magnitude = (workspace:FindFirstChild("GameBall").Position - character:FindFirstChild("HumanoidRootPart").Position).magnitude 
		if magnitude < 12 then
			animation1:Play()
			animPlaying = true
			wait(1)
			animPlaying = false
		elseif magnitude >= 12 and magnitude <= 20 then
			if character.HumanoidRootPart.Position.Z > -1.084 then
				--animation2R:Play()
				animation1:Play()
				divingright = true
				animPlaying = true
				wait(2)
				animPlaying = false
				divingright = false
			else 
				--animation3L:Play()
				animation1:Play()
				divingleft = true
				animPlaying = true
				wait(2)
				animPlaying = false
				divingleft = false
			end
		end
	end
end)
local TargetPart = game.Workspace:WaitForChild("GameBall")

game:GetService("RunService").Stepped:Connect(function()
	if TargetPart then
		character.HumanoidRootPart.CFrame = CFrame.new(character.HumanoidRootPart.Position) * CFrame.Angles(0,Vector3.new(CFrame.new(character.HumanoidRootPart.Position, TargetPart.Position):ToOrientation()).Y,0)
	end
end)

game:GetService("RunService").Stepped:Connect(function()
	if TargetPart then
		if divingleft or divingright then
			local magnitude = (workspace:FindFirstChild("GameBall").Position - character:FindFirstChild("HumanoidRootPart").Position).magnitude 
			character.HumanoidRootPart.CFrame = CFrame.new(-146, math.clamp(TargetPart.Position.Y, 5.762, math.huge), (math.clamp(TargetPart.Position.Z, -14.209, 11.713)))
		else
			local magnitude = (workspace:FindFirstChild("GameBall").Position - character:FindFirstChild("HumanoidRootPart").Position).magnitude 
			character.HumanoidRootPart.CFrame = CFrame.new(-146, 5.762, (math.clamp(TargetPart.Position.Z, -4.084, 1.916)))
		end
	end
end)
1 Like

Your running heartbeat on a server script?
Heartbeat is running on fps, also i don’t recommended using heartbeat in a server script only use it on a client script.
Edit2 i don’t have a computer at the moment so you have to figure out something.

1 Like

Yep, seemed like only possiblity seeing as I am not a fan of while true do loops.

How would I use an alternative? The only alternative is a while true do loop. I’m not a fan of that, but I’ll try that for now.

nevermind, that didn’t work and just destroyed the char movement

Still need help for this. Any suggestions to improve this would be appreciated!

I know you’re not a fan of while loop but it’s bad to abuse RunService loops so you should use while loop when a RunService loop is not needed.

To make a while loop faster you can do:

local RunService = game:GetService("RunService")

local RenderStepped = RunService.RenderStepped

while condition do
    -- the code your want to run.
    RenderStepped:Wait() -- never use wait, use Heartbeat or Stepped for ServerScripts.
end

Therefore, you require frame works. Since having only one while loop isn’t a major concern, I would suggest using frame works. You can simply have one while loop and run everything inside of it, which is what I do. I have a while loop on the server and a Run Service on the client.