Lerp Coaster System

Attempt:

Making my coaster run smooth in game play with other players

  • Current State: Stutters a lot when riding. (The cart stutters, not the players or the players camera)

Question:

Is there a more efficient way to run the coaster following a path of bricks and is there a way to stop the stuttering?

Key Notes:
Here is the script I am running:

local c = script.Parent.Cart3:WaitForChild("CartA")
local t = script.Parent.Parent.Parent["Tracks/System"]:WaitForChild("Track")
local lastknownspeed = 0.05
local ct = 424
--[[local titab = t:GetChildren()
local t_tab = {}
for i,v in pairs(titab) do
	table.insert(t_tab,tonumber(v.Name),v)
end]]

local speedslib = require(script.Parent:WaitForChild("TrackSpeeds"))

--[[print()
warn("BEGIN TEST TABLE")
print()
for i,v in pairs(t_tab) do
	print("#"..i.." = "..v.Name)
	wait(0.01)
end
print()
warn("END TEST TABLE")
print()]]

local function locationToCFrame(location)
	local pos = location
	if not pcall(function() local a = location.p end) then pos = CFrame.new(location) end
	return pos
end

local function moveModel(model, location)
	model:SetPrimaryPartCFrame(locationToCFrame(location))
end

local function newLerp(cf1, cf2, alpha)
	return cf1:lerp(cf2, alpha)
end

local count = 50
local cP = 1

moveModel(c, t[50].CFrame)
print("Location Placed")
wait()

while wait() do
	warn("Counting...")
	print("count")
	local nP
	if t:FindFirstChild(count) ~= nil then
		count = count + 1
	else
		count = 1
	end
	if not t:FindFirstChild(count+1) then
		nP = 1
	else
		nP = count+1
	end

po = t:FindFirstChild(count)
pn = t:FindFirstChild(nP)

x = 0
y = 1
--v = script.Parent.Speed.Value
v = speedslib[tonumber(pn.Name)]
warn(type(v))
if v ~= nil then
	lastknownspeed = v
	print("SET LKS")
else
	v = lastknownspeed
	print("USING LKS")
end
print("TYPE OF V IS: "..type(v))

if po and pn then
	for i = x,y,v do
		wait(-1)
			moveModel(c, newLerp(po.CFrame, pn.CFrame, i))
	end
end
end
local speedslib = {
	[1] = 0.025,
	[7] = 0.005,
	[9] = 0.025,
	[10] = 0.045,
	[20] = 0.035,
	[53] = 0.45,
	[70] = 0.55,
	[200] = 0.65,
	[250] = 0.55,
	[381] = 0.05,
	[415] = 0.005,
	[416] = 0.055,
}

return speedslib
  • The script works with a Module that has speeds connected with the part number in the track.
  • The track is in number order.
  • In the client, it seems to stutter but in the server camera in studio while watching my two test clients, its run better than the clients, but slightly still stutters.
  • When the coaster runs fast, it seems to stutter a lot while when it moving slow, it stutters very ‘light’.
  • The cart is anchored while running, and the seats are welded to make sure the player stays on the cart and does not end up just floating in mid air.

Server:
Here is a gif of the Server.
https://gyazo.com/1620d987b1b519dbac4574abe3fdcb9d

Client:
Here is a gif of one of the clients.
https://gyazo.com/69cb4b8283cf78ef2805e11473b6a75a

Bezier Curves
I know there is another alternative, which is Bezier Curves, but I am looking for just a coaster following a path I can make quickly, which is using the coaster creator plugin.

Thank you if you can help!

1 Like

Have you tried constantly setting the cart’s Network Owner to nil?
This should stop the stuttering, if it’s network ownership that’s the problem.

How would I be able to set the network ownership if the cart is anchored?

Oh, sorry, my mistake. I didn’t realize the cart was anchored.

Its fine, I will add that into the document now to make sure others don’t also conclude to that.

If you just CFrame an anchored model on the server continually, then you’re never going to get very smooth movement on the clients. Any stutter at all in the network send rate or network processing rate on the client will cause the client to stutter as it misses “frames” of the animation.

If you’re not going to use Roblox’s physics, then either you’ll need to have each client move the coaster locally or you’ll have to use something with interpolation built in like animations (If you really don’t want to animate things yourself on the client I think you could make tooling to generate an animation for the coaster’s movement along the track if it’s a fixed known track).

2 Likes

In addition to running things on the client, you might want to try welding the parts together and setting the CFrame of a base part instead of using SetPrimaryPartCFrame.

I don’t think Roblox is optimized for using SetPrimaryPartCFrame constantly on groups of parts. The movement of welded parts as a group, on the other hand, has probably been optimized a lot more.

If you create a joint structure like this, then you can move every part of the coaster by moving only one part joined to others:

Root Part (Anchored)
    Motor6D -> Base Part (Unanchored)
        Weld -> Coaster Parts (Unanchored)

When you move the Root Part, all of the other parts will move too.


Additionally, SetPrimaryPartCFrame will, over time, cause parts to drift away from each other as the imprecision between parts are exaggerated on each use. You won’t notice this if you use it once, but when it’s used thousands of times, parts will drift.

Example

https://gfycat.com/IllfatedDisguisedBug

Code:

local model = workspace.Model

local angle = 0

while true do
	for i = 1, 100 do  -- repeat 100 time to exaggerate the effect so it can be seen in a 30 sec video
		model:SetPrimaryPartCFrame(CFrame.new(0, 10, 0)*CFrame.Angles(0, math.rad(angle), 0))
		angle = (angle + 0.1)%360
	end
	wait()
end

If you set up a joint-based system like shown above, this drift won’t happen. The joints store the original offsets between parts, so the imprecision does not build up like it does with SetPrimaryPartCFrame.


You absolutely should run the coasters on the client, anyway. It will only be smooth once you do. If you run it on the client then you can run it at 60 FPS in RenderStepped. I think the network send rate is 20 FPS, so right now that’s your limit.

9 Likes