Moving models with RenderStepped, how to make them move the same speed for different framerates?

Hello, I’m making models move on the client every time a frame has passed. I want them to move the same speed for all frames, I’ve tried this at 360 FPS and they move way too fast…

local collectionService: CollectionService = game:GetService("CollectionService")
local runService: RunService = game:GetService("RunService")

local function getDeltaTime()
	return runService.RenderStepped:Wait()
end

for _, v in collectionService:GetTagged("Gloves") do
	local function updatePivot()
		while true do
			local framesPerSecond: number = (1 / getDeltaTime())
			
			local increment: number = 1

			for i = 1, (50 * framesPerSecond) / 60 do
				v:PivotTo(v:GetPivot() * CFrame.Angles(0, math.rad(((0.75) / framesPerSecond) * 60), 0) + Vector3.new(0, (((0.01 / framesPerSecond)) * 60) * increment, 0))
				increment -= 0.02
				runService.RenderStepped:Wait()
			end

			increment = 1

			for i = 1, (50 * framesPerSecond) / 60 do
				v:PivotTo(v:GetPivot() * CFrame.Angles(0, math.rad(((0.75) / framesPerSecond) * 60), 0) - Vector3.new(0, (((0.01 / framesPerSecond)) * 60) * increment, 0))
				increment -= 0.02
				runService.RenderStepped:Wait()
			end
		end
	end
	
	local pivotCoroutine = coroutine.create(updatePivot)
	coroutine.resume(pivotCoroutine)
end

try heartbeat idk

[30 msg aaaaaa]

1 Like

Heartbeat does the same thing, it does not matter if I fire it prior or after each frame.

1 Like

You can create a RenderStepped connection, which will pass in the delta time as an argument.

local RunService = game:GetService("RunService")

local rotationPerSecond = 60
RunService.RenderStepped:Connect(function(deltaTime)
	local rotationThisFrame = rotationPerSecond * deltaTime
end)

This doesn’t seem to work and there’s still differences between different framerates.

local collectionService: CollectionService = game:GetService("CollectionService")
local runService: RunService = game:GetService("RunService")

local function getDeltaTime()
	return runService.RenderStepped:Wait()
end

local positionPerSecond: number = 0.01
local rotationPerSecond: number = 0.75

local positionThisFrame: number = 0
local rotationThisFrame: number = 0

local function thisFrame(deltaTime: number)
	positionThisFrame = (positionPerSecond * deltaTime) * 60
	rotationThisFrame = (rotationPerSecond * deltaTime) * 60
end

runService.RenderStepped:Connect(thisFrame)
	
for _, v in collectionService:GetTagged("Gloves") do
	local function updatePivot()
		while true do
			local framesPerSecond: number = (1 / getDeltaTime())
			
			local increment: number = 1

			for i = 1, (50 * framesPerSecond) / 60 do
				v:PivotTo(v:GetPivot() * CFrame.Angles(0, math.rad(rotationThisFrame), 0) + Vector3.new(0, (positionThisFrame * increment), 0))
				increment -= 0.02
				runService.RenderStepped:Wait()
			end

			increment = 1

			for i = 1, (50 * framesPerSecond) / 60 do
				v:PivotTo(v:GetPivot() * CFrame.Angles(0, math.rad(rotationThisFrame), 0) - Vector3.new(0, (positionThisFrame * increment), 0))
				increment -= 0.02
				runService.RenderStepped:Wait()
			end
		end
	end
	
	local pivotCoroutine = coroutine.create(updatePivot)
	coroutine.resume(pivotCoroutine)
end

You need to move it multiplied by the delta time returned by RenderStepped

Here’s an amazing video that Jonas Tyroller made, he explains all of this extremely clearly and provides examples https://www.youtube.com/watch?v=yGhfUcPjXuE

What exactly do you mean with this? I’m now here, but obviously, this does not work.

local collectionService: CollectionService = game:GetService("CollectionService")
local runService: RunService = game:GetService("RunService")

local function getDeltaTime()
	return runService.RenderStepped:Wait()
end

local positionPerSecond: number = 0.01
local rotationPerSecond: number = 0.75

local positionThisFrame: number = 0
local rotationThisFrame: number = 0

local function thisFrame(deltaTime: number)
	positionThisFrame = (positionPerSecond * deltaTime)
	rotationThisFrame = (rotationPerSecond * deltaTime)
end

runService.RenderStepped:Connect(thisFrame)
	
for _, v in collectionService:GetTagged("Gloves") do
	local function updatePivot()
		while true do
			local framesPerSecond: number = (1 / getDeltaTime())
			
			local increment: number = 1

			for i = 1, (50 * framesPerSecond) / 60 do
				v:PivotTo(v:GetPivot() * CFrame.Angles(0, math.rad(rotationThisFrame) * getDeltaTime(), 0) + Vector3.new(0, (positionThisFrame * increment) * getDeltaTime(), 0))
				increment -= 0.02
				runService.RenderStepped:Wait()
			end

			increment = 1

			for i = 1, (50 * framesPerSecond) / 60 do
				v:PivotTo(v:GetPivot() * CFrame.Angles(0, math.rad(rotationThisFrame) * getDeltaTime(), 0) - Vector3.new(0, (positionThisFrame * increment) * getDeltaTime(), 0))
				increment -= 0.02
				runService.RenderStepped:Wait()
			end
		end
	end
	
	local pivotCoroutine = coroutine.create(updatePivot)
	coroutine.resume(pivotCoroutine)
end

Sorry, I don’t want to read all that code. But I’ll show you how it’s done.

-- localscript
RunService.RenderStepped:Connect(function(delta)
    thing.CFrame += Vector3.new(delta,0,0)
    -- this will add +1 to the thing's CFrame.Position.X value every second
    -- to change the speed simply multiply delta * speed (e.g. delta * 2, would be 2 per second)
end)
1 Like

I tried combining this script with what I’m trying to acquire. The models now do not move at the same time anymore and there’s still a difference between framerates.

local collectionService: CollectionService = game:GetService("CollectionService")
local runService: RunService = game:GetService("RunService")

local glovesTable = {}
	
for _, v in collectionService:GetTagged("Gloves") do
	table.insert(glovesTable, v)
	v:SetAttribute("CanMove", true)
end

local function onRenderStepped(deltaTime: number)
	local FPS: number = 1 / deltaTime
	
	for _, gloves in collectionService:GetTagged("Gloves") do
		if gloves:GetAttribute("CanMove") then
			gloves:SetAttribute("CanMove", false)
			
			local increment: number = 1
			
			for i = 1, (50 * FPS) / 60 do
				gloves:PivotTo(gloves:GetPivot() * CFrame.Angles(0, math.rad((0.75 / FPS) * 60), 0) + Vector3.new(0, ((0.01 / FPS) * 60) * increment, 0))
				increment -= 0.02
				runService.RenderStepped:Wait()
			end
			
			increment = 1
			
			for i = 1, (50 * FPS) / 60 do
				gloves:PivotTo(gloves:GetPivot() * CFrame.Angles(0, math.rad((0.75 / FPS) * 60), 0) - Vector3.new(0, ((0.01 / FPS) * 60) * increment, 0))
				increment -= 0.02
				runService.RenderStepped:Wait()
			end
			
			gloves:SetAttribute("CanMove", true)
		end
	end
end

runService.RenderStepped:Connect(onRenderStepped)

Why is there yielding code in RunService event. You definitely don’t want that.

Otherwise the code looks good to me.