Parts moving slower or spinning slower depending on fps

The title is self explanatory, but anyways, sorry if my english is bad i’ll try my best to explain it.
So, i’m working a game and the some projectiles are moving slower depending on the fps that player has.

I Can’t really provide any gifs or videos here because i cant find any way to replicated the lag.
But i can provide some code.

Code for the part that rotates:

runService.RenderStepped:Connect(function(deltaTime:number)
	for _,val in pairs(confetti) do
		if (confettiColors) then val:SetColors(confettiColors) end
		val.Enabled = confettiActive
		val:Update()
	end

	if onSettings then return end
	if placing == nil and not onSettings then module.showInfo() highlight.Parent = script return end
	if not mouse.Target then return end
	if mouse.Target.Parent.Parent.Name ~= 'Tiles' then return end
	if mouse.Target.Parent.Name ~= player.Name then return end
	if getTurn() ~= player.Name then return end
	if not mouse.Target:FindFirstChild('OccupiedBy') then return end
	if highlight.Parent ~= mouse.Target then sounds:WaitForChild('HoverSFX'):Play() end
	if not mouse.Target:FindFirstChild(highlight.Name) then highlight.Parent = mouse.Target end
	if not model then module.setModel() return end
	model.PrimaryPart.CFrame = mouse.Target.CFrame * CFrame.new(0, 2.3, 0)
	
	if arrow.Parent == camera then
		spinAngle += 3.5
		
		arrow.Position = mouse.Target.Position + Vector3.new(0, 6, 0)
		arrow.Orientation = Vector3.new(0, 0, -90)
		arrow.CFrame *= CFrame.Angles(math.rad(spinAngle), 0, 0)
	end
	
	if mouse.Target:WaitForChild('OccupiedBy').Value == 'None' then highlight.FillColor = Color3.new(0.827451, 1, 0.815686); tile = mouse.Target; arrow.Color = Color3.fromRGB(81, 255, 0) return end
	highlight.FillColor = Color3.new(1, 0.454902, 0.454902); tile = nil; arrow.Color = Color3.fromRGB(255, 0, 4)
end)

Code to the projectile:

local replicatedStorage = game:GetService('ReplicatedStorage')
local tweenService = game:GetService('TweenService')
local events = replicatedStorage:WaitForChild('Events')
local assets = replicatedStorage:WaitForChild('Assets')

local function quadraticSupport(p0, p1, p2, t)
	return p0:Lerp(p1, t), p1:Lerp(p2, t)
end

return function(unit:Model, enemy:Model)
	local primaryPart = unit.PrimaryPart
	local E_primaryPart = enemy.PrimaryPart
	local originalCFrame = primaryPart.CFrame

	local lookAt = tweenService:Create(primaryPart, TweenInfo.new(0.2, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {CFrame = CFrame.lookAt(primaryPart.Position, Vector3.new(E_primaryPart.Position.X, primaryPart.Position.Y, E_primaryPart.Position.Z))})
	lookAt:Play()
	
	local ball = assets:WaitForChild('Ball'):Clone()
	ball.Parent = workspace
	ball.CFrame = primaryPart.CFrame

	local attackSfx = primaryPart:WaitForChild('SFX').Attack:GetChildren()[math.random(1, #primaryPart:WaitForChild('SFX').Attack:GetChildren())]
	attackSfx:Play()

	local middle = (primaryPart.Position:Lerp(E_primaryPart.Position, 0.5)) + Vector3.new(0, 5, 0)

	for t = 0, 1, 1/20 do
		local p0, p1 = quadraticSupport(primaryPart.Position, middle, E_primaryPart.Position, t)
		ball.Position = p0:Lerp(p1, t)
		task.wait(0.01)
	end

	task.delay(1, function()
		local lookAt2 = tweenService:Create(primaryPart, TweenInfo.new(0.2, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut), {CFrame = originalCFrame})
		lookAt2:Play()
	end)
	
	enemy.PrimaryPart.RootAttachment.DMGTaken.Enabled = true task.delay(0.2, function() enemy.PrimaryPart.RootAttachment.DMGTaken.Enabled = false end)
	ball:Destroy()
end

I’ve seen some posts saying to multiply DeltaTime with something, but i didnt understand it as much.

Try adding the delta time to the spin angle instead of 3.5

like math.rad(deltaTime)?

no, spinAngle += deltatime

charrrr

Hello, sorry for long response.
Well, i tried doing what you said, but its now veeeeeeery slow.

Just multiply deltaTime by a larger amount and you can get to your desired speed.

it worked, but what about the projectile? do i need to multiply with the position?

Are you lerping the position of the projectile?

yes, i’m using a bezier curve for it.


This to be exact:

for t = 0, 1, 1/20 do
		local p0, p1 = quadraticSupport(primaryPart.Position, middle, E_primaryPart.Position, t)
		ball.Position = p0:Lerp(p1, t)
		task.wait(0.01)
	end

Then you should definitely use something like deltaTime for handling the Lerp.

If you don’t want to deal with the hassle of recoding the projectile script, you can also use Tweens.

The culprit is the event itself. It depends a lot on the frame rate. To make sure you’re not inadvertently making frame rate and advantage or disadvantage, use the deltaTime parameter. It must be a multiplying factor.

What’s even complementary to that, you could try using os methods to get the time for better time sync accuracies.

i don’t really know how to use os tho, i never really found a use to it.

something like this? the projectile appearance is loaded on the client, it dont really affects the server.

for t = 0, 1, 1/20 do
		local p0, p1 = quadraticSupport(primaryPart.Position, middle, E_primaryPart.Position, t)
		ball.Position = p0:Lerp(p1, t)
		game:GetService('RunService').RenderStepped:Wait()
	end

It still doesn’t account for unstable fps.

You can save the deltaTime, consistently add it to a variable and do something like this for the lerp percentage:

1 / (totalTime / elapsed)

1 / (t / game:GetService('RunService').RenderStepped:Wait()) this…?

No… that won’t work. The event won’t return any values.

yeah i tried it… but, if i used the tween method, wouldnt it be affected by the fps?

you should multiply where you will move your projectile with delta time
this is an example for a normal part that will move with the same speed in any fps

local RunService = game:GetService("RunService")
local movingPart = workspace.movingPart

RunService.Heartbeat:Connect(function(dt)
	local speed = Vector3.new(0, 0, .05) * (dt * 60) -- moves .1 studs per second on the z axis
	movingPart.Position += speed 
end)

this is how it works


if you are running on 60 fps then (dt * 60) will be 1 but it will run 60 times per second
if you are running on 120 fps then (dt * 60) will be .5 but it will run 120 times per second
if you are running on 240 fps then (dt * 60) will be .25 but it will run 240times per second
etc…


1 Like