You can try having specific dots to change the speed, and not every blue dot. For example, you can change the speed of the coaster from dot1 to dot5 instead of dot1, dot2, dot3, dot4, and dot5. You would also use a Sine easing style to increase speed for realism.

local speedDots = {dot1 = 1, dot5 = 5} -- {dotNumber = speed}
local trainSpeed = 0.5
local function easeInSine(x) -- For speeding up or slowing down
return 1 - math.cos((x * math.pi) / 2)
end
local function easeOutSine(x) -- For braking
return math.sin((x * math.pi) / 2);
end
dot1.Touched:Connect(function()
local x = -- The percent traveled by the train from dot1 to dot 5 (from 0% - 100%, or 0 - 1)
local currentdot = speedDots.dot1 -- The current dot
local nextDot = speedDots.dot5 -- The next dot
trainSpeed = currentDot + easeInSine(x) * (nextDot - currentDot) -- Speeding up the train
end

If the next position is higher, then theoretically, the carts should move slower.

If the next position is lower, then it’s vice-versa; move faster.

As for a flat plane, you still have to bear in mind the laws of acceleration, which state that friction will cause you to slow down.

It’s basically a case where you need to bear in mind acceleration, gravity, and other underlying factors. Putting them into play, and making movement non-linear, will help smooth-out your coaster.

The only issue with that would be the distancing from each cart. Each cart follows one node behind the cart infront. so if it was one long stretch, it wouldn’t work too well.

if LASTNODE.Position.Y > node.Position.Y then
-- GOING DOWN
if SPEED <= 0.1 then
SPEED = 0.1
else
SPEED -= 0.025
end
elseif LASTNODE.Position.Y < node.Position.Y then
-- GOING UP
if SPEED >= 0.5 then
SPEED = 0.5
else
SPEED += 0.0125
end
elseif LASTNODE.Position.Y == node.Position.Y then
-- EVEN
end

It makes it a little bit better, but it accelerates too fast when its going downhill. I wanted to try dividing instead of subtracting. Lemme know what you think.

I’ve edited my previous post for a more in-depth explanation.

To solve that, you can either make the speed of each cart the same as the speed of the cart in front, or make the speed the average speed of the first and last cart.

local speedDots = {dot1 = 1, dot5 = 5} -- {dotNumber = speed}
local trainSpeed = 0.5
local function easeInSine(x) -- For speeding up or slowing down
return 1 - math.cos((x * math.pi) / 2)
end
local function easeOutSine(x) -- For braking
return math.sin((x * math.pi) / 2);
end
dot1.Touched:Connect(function()
local x = -- The percent traveled by the train from dot1 to dot 5 (from 0% - 100%, or 0 - 1)
local currentdot = speedDots.dot1 -- The current dot
local nextDot = speedDots.dot5 -- The next dot
trainSpeed = currentDot + easeInSine(x) * (nextDot - currentDot) -- Speeding up the train
end

What this code is doing is to make it so that It slowly increases speed from one point to another instead of every single point which can cause jankiness. Instead of defining the speed, try defining the change in y level, then calculate the speed based off the distance.

How can I add this onto my code? Here’s what I have currently:

--// SERVICES \\--
local TS = game:GetService("TweenService")
--// MODULES \\--
local EasyTween = require(game.ReplicatedStorage:WaitForChild("EasyClientTween"))
local tweenHandler = EasyTween.new()
--// VARIABLES \\--
local CARTS = script.Parent.Carts
local NODES = script.Parent.Nodes
local START_NODE = 5
local CURRENT_NODE = START_NODE
local SPEED = 0.2
--// OTHER STUFF \\--
local NEW_SPEED = false
local LASTNODE = NODES.Node0
local function tweenRide(ride,node)
local Goal = {["CFrame"] = node.CFrame}
local TI = TweenInfo.new(
SPEED,
Enum.EasingStyle.Linear,
Enum.EasingDirection.InOut,
0,
false,
0
)
local RideTween = TS:Create(ride,TI,Goal)
RideTween:Play()
end
local function setupRide(ride,node)
if NEW_SPEED == false then
--if node and node:FindFirstChild("Speed") then
-- SPEED = node.Speed.Value
--end
if LASTNODE.Position.Y > node.Position.Y then
-- GOING DOWN
if SPEED <= 0.1 then
SPEED = 0.1
else
SPEED -= 0.025
end
elseif LASTNODE.Position.Y < node.Position.Y then
-- GOING UP
if SPEED >= 0.5 then
SPEED = 0.5
else
SPEED += 0.0125
end
elseif LASTNODE.Position.Y == node.Position.Y then
-- EVEN
end
print(SPEED)
LASTNODE = node
NEW_SPEED = true
end
if not node then
CURRENT_NODE = START_NODE
end
tweenRide(ride.CartNode,node)
end
wait(5)
while wait() do
if NODES:FindFirstChild("Node"..CURRENT_NODE) then
setupRide(CARTS.Cart1,NODES:FindFirstChild("Node"..CURRENT_NODE))
else
CURRENT_NODE = START_NODE
end
if NODES:FindFirstChild("Node"..CURRENT_NODE - 2) then
setupRide(CARTS.Cart2,NODES:FindFirstChild("Node"..CURRENT_NODE - 2))
else
CURRENT_NODE = START_NODE
end
if NODES:FindFirstChild("Node"..CURRENT_NODE - 4) then
setupRide(CARTS.Cart3,NODES:FindFirstChild("Node"..CURRENT_NODE - 4))
else
CURRENT_NODE = START_NODE
end
wait(SPEED - 0.05)
CURRENT_NODE += 1
NEW_SPEED = false
end

I know it’s really messy, I plan to simplify it at some point.
EDIT: Sorry for bugging you a bunch.