There is a number of ways to move a part (or model).
CFrame transformation
The most common one is associated with CFrames and either tweens or linear interpolation (lerp) combined with a loop. It usually performs very smoothly without any serious performance issues and is secure. In case you decide to use tweens, weld all parts to the part you are transforming:
--[[
Root part is the part you are changing
CFrame of (primary part).
]]
local weld = Instance.new("WeldConstraint")
local rootPart
for i, v in pairs(model:GetDescendants()) do
if (v:IsA("BasePart")) then
local clone = weld:Clone()
clone.Part0 = rootPart
clone.Part1 = v
clone.Parent = v
end
end
Prismatic constraints
Personally, I would consider choosing prismatic constraints, because they seem less performance demanding, are very smooth, and Roblox physics engine takes care of movement. As opposed to the previous approach, parts have to be unanchored. Repeat the welding process above. Bind all those parts to one primary part - another unanchored part - that is connected to two anchored parts (start and finish). Set actuator type of the constraint to motor. In a nutshell, prismatic constraints are used to move a part along one axis. Instead of me explaining steps, it’s probably better if you take a look at an example. This is a link to uncopyloced place by EgoMoose, which has a lot of useful content, but you should focus on the moving platform. Take a look at how it’s assembled. Link here.
I just got tons of information about PrismaticConstraints on Roblox Developer Hub. Visit Roblox Developer hub to expand your knowledge immediately.
Jokes aside, you may ask about security against exploiters. I am pretty sure that exploiters can’t hurt here. Why? Because all parts are bound to one unanchored root part, and the root part is bound to two anchored parts. Perhaps you can set network ownership to server for this particular case, although physics simulation generally relies on nearest clients for a good reason, which is stuttering.
-- Setting network ownership to nil gives server
-- primary control over simulation of part's physics.
BasePart:SetNetworkOwnership(nil)
I think @colbert2677, who wrote a very comprehensive post about tweening models (link), could confirm this and perhaps explain more about security.
At the same time, as colber2677 has already said, tweening combined with :SetPrimaryPartCFrame() is not adviced for the reason explained in their post. Rather use welds.
As for train respawning, I don't think regular spawning is a good idea. A much better way would be simply changing coordinates (CFrames). It's more efficient, easier, and less performance demanding.