Don’t believe everything you see on the internet, using task.wait(x) is fine if you actually need something to wait without something happening in-between.
Besides, letting a script wait actually gives other scripts more room to execute code.
Everything in a game runs on a single-thread (that includes coroutines, creating a coroutine is basically just creating another script without creating another script).
Computers generally can execute like billions of instructions in mere seconds so it actually doesn’t matter much if your game is completely single-threaded,
it’s rarely ever a problem unless you’re doing some unconventional/super heavy math that takes multiple frames to complete.
The only TRULY multi-threaded logic is if you use actors with parralel Luau.
If your train doesn’t need to do anything, just use a simple task.wait().
IF for some reason you REALLY want to avoid using task.wait() then use RunService instead and tie everything to .HeartBeat or .Stepped and use tick() to measure if enough time has passed.
Though, that’s basically just a loop, but it’ll be synchronized with the physics engine / update of the game.
If your game only has a few trains though, this won’t matter at all.
You could do this for like 10 trains if you wanted.
I’m not entirely sure what exactly you’re trying to do with trains, but it looks like you’ve read too many posts and articles on the internet and are somehow worried about non-existent performance issues.
It’ll be a different story if you’re running 500 trains at the same time for instance.
But using task.wait() is not going to make your game run worse.
There is no correct way of scripting something, just as long as it works and as long as you know how it works and can maintain it.