[Tutorial] The complete guide: how to make a train

Jawesome99

L1: Registered
Aug 29, 2015
5
1
Make sure that the last path_track has this output, as mentioned in the tutorial


As for the infinite noise, you'll need something to trigger it to stop. I haven't mentioned it (I would fix it in a second), I'll recommend adding another output for that logic_timer I called "timer", which would be set as follows:

I've been able to get the trains working properly, but the sound doesn't stop looping. I've tried FireUser1 and OnUser1 StopSound, doesn't work, probably a stupid method anyway... I'll try the timer method.

Edit: Didn't work, if i did it right. Your thought is to create another output for the same timer to turn off the sound (StopSound) after ~6 seconds? Also ambient_generic has the following flags:
Code:
[ ] Play everywhere
[X] Start silent
[X] Is NOT looped

Edit: Fixed it. Solution was to disable
Code:
[ ] Is NOT looped
in the flags of ambient_generic.
 
Last edited:

Superjoe224

L1: Registered
Oct 4, 2015
16
4
So how fast can I make my train go without it breaking something? In my map I want this thing to tear ass, but I dont want to break a server because I didn't know of some limit I should follow.
 

SnickerPuffs

(*single chuckle*)
aa
Apr 10, 2014
1,325
1,866
So how fast can I make my train go without it breaking something? In my map I want this thing to tear ass, but I dont want to break a server because I didn't know of some limit I should follow.

(Nice Bump™)

Jokes aside, just set it at 400hu to be safe. It'll "tear ass" as you so beautifully put it, but be on the somewhat safe side of ass-tearing. A nice, quick ass tear so the suffering is minimal, as opposed to a slow, dick-spanking-ly painful ass tear.
 

Arceus

The equine creator everyone takes for granted.
Apr 19, 2016
42
3
I followed this tutorial, word for word.
Here are my issues currently:
  • The train does not render. A force "pushes" the player, but the model is not visible. The train model used is urban_subwaycar.mdl . There are multiple train cars, each are the same model. Could this be due to the NoDraw not being rendered?
  • As mentioned above, the player is "pushed" along the track, but the train does not kill the player or cause damage. I have the ABS pack installed, so the damage mode is set to Train and the amount is 9999.
  • No sounds play. The train does not play its ambient sound (wheels moving, etc.) neither does the warning bell sound play. Both sounds are custom .wav files I created via Audacity, moved to the ambient sound folder for TF2.

Please help diagnose what is happening here.
Pictures, specifications, etc. provided upon request.

Thank you.
 

Jebehdebehhuh

L1: Registered
Mar 17, 2018
3
0
there are problems with my train:
1.The train is REALLY slow, even if I set the max speed to like 5000.
2.The train sound wont play.
3.The train appears on the left of the track, not on it properly.
Please help!
 

Shisho

L1: Registered
Mar 12, 2023
17
0
Introduction

The question "how do I make a train?" is asked a lot. Everybody wants to have a train in their map, because dynamic elements are cool, and trains are the best dynamic element in tf2. (that's a fact, not an opinion). From ctf_well and cp_freight, to cp_snowplow and koth_trainsawlazer- Many of the maps in the tf2 world feature trains. In this tutorial I'll go over creating a train and fitting it to your needs. This tutorial is very long, because I'll give in depth information and tips about all the entities we're using, so that you'll understand exactly what you're doing, and can later use that understanding to create your own train, or better- a whole new setup for something completely different! (I used it to make an elevator for my sd_ map, for example).

Freight3.png


What entities we'll be using?

Let's begin!

Now we'll build a basic train, like featured in cp_well, or cp_freight. It would only go in a straight line. We'll go later over curved tracks and how those work.
First, make a prop_dynamic. This would be your train model (the train you'll see in-game).
Set it's world model to a train engine. You can make more prop dynamic entities that would be the train cars, if you want to.

:cordonenable: IMPORTANT! :cordonenable: The train must be built facing from left to right. However, that won't define it's in-game position, but rather it's orientation relative to the tracks we'll soon place. So you don't need to rotate your entire map. You just need to build the tracks in the right direction (we'll soon talk about how to do that), and the train- facing right. Don't forget this tip!

tut1_zpswbfm3d1a.png


Next, make a brush, textured nodraw. it's height should be from the ground to the top of the lowest train part (car or engine), the length should be the train's lenght, and it's width- the train width. Place it over the train props.
Tie the brush to an entity (ctrl+t). Set the entity to "func_tracktrain". That's our train entity! Give it a name, like "train" (w/o quotations). Set all the train prop_dynamic props, so their "parent" property would be set to train. Child entities move together with their parents, so now all the train props would move together with the func_tracktrain entity.
We now need to set some properties for the func_tracktrain. double click it, and set the render mode to "don't render" (that way it would be invisible and won't cast shadows on your beautiful train). Set "max speed" to whatever speed you want your train to have (trains tend to have only one speed- the max speed. "Those drivers never lift their foot off the pedal, I'm telling ya"). I personally use 800. Set damage on crush to a very high number (like 99999).
Set the Move sound property to something like ambient\train.wav or ambient\slow_train.wav, or whatever you want. (in the sound browser window, you can search by putting keywords like "train" in the "filter" textbox, just like in the texture browser).
Then head to the "flags" tab and check "fixed orientation" and "Is unblockable by player".

tut2_zpssba2glmc.png


:helpers: NOTE :helpers: You will need to change another property, if you use a different sized track prop than the usual track props in tf2. You see, by default, the tracks in tf2 are 4 hammer units high (and by track I mean the track prop, not the actual path_track). If yours have a different height, you'll need to change the "Height above track" property to that height.

And now add a brush in front of the train, textured with trigger texture, and tie it to an entity (ctrl+t). Set the entity class to trigger_hurt, set the damage type to train. That would set the kill icon to the train one.
Trainico.png

Set the "damage" property to a very big number (like 9999999). That would kill all players touching the front end of the train, no matter how much they are healed.
Parent the trigger to the func_tracktrain. Then open the flags tab, and check the flag "Everything (not including physics debris)". That would be used so that the trigger also damages engineer machinery. (And I don't remember for sure, but I think it also has to do with killing Ubered players)

tut3_zpstkyalzqk.png


Now the train needs to move. For that, we'll have to define a track. Place an entity, and set it's class to "path_track". This is an entity used to define the path of objects that move, in the source engine (like rd_ bots, payload carts, etc.) The way path tracks work, is by "connecting" them. Two connected path tracks would form a path. Payloads might have hundreds of path_tracks, but we'll only need two for now.
The path_track needs to be located where you want the train to start, but you must remember that the train is not a real life train, it's a brush entity. Unlike real life trains, brush entity trains move from their origin. (marked with a little red circle when selected, by default it's set to the center of the brush). So you must think where you want the origin to be when the train starts, Not the front!!! Take that into consideration when planning the train area in hammer. Also remember to put the path_track in the proper height- the height should be the func_tracktrain origin's height.

:cordonenable: IMPORTANT! :cordonenable: The train's start and end spots should be well hidden in your map. (In a tunnel like cp_freight, or a warehouse like cp_well. It's up to you). If it won't be hidden, people would see your train suddenly appear, or disappear.

tut4_zpsc807f3pp.png


Set the path track name to something simple, but for ease of usage later, make it end with "_01". (I'll name mine "path_train_01"). Now, all the default properties are good for us.

Now, here's a cool trick- If you shift+drag your path track, hammer would automatically assume that the new path track is the next path_track for this path, and would connect them without you having to do a thing! It would also automatically rename the new path track, so that's cool too. Shift+drag a new path_track, and place it where you want the train to end it's track. (Same as before- end=where the origin should be at the end)

After you've done that, open the 1st path_track properties, and in the "flags" tab, check "teleport to THIS path_track". That marks this path_track as the first.
Open the func_tracktrain properties again, and set the "first stop target" to the first path_track name. That tells the func_tracktrain what is the path_track path it should follow.

And now for the final setup before we are finished with the basic train components- we'll need to set an output for the train to go back to the first path_track, after it reached the end. (Otherwise it would just stay at the edge of the path, and won't go again)
Open the last path_track's properties window, select the "outputs" tab, and make a new output-

tut5_zps5qlws70l.png


That's it! you have a train! but the train won't yet work, because you never told it when to start. And here's a great part- Everything can cause a train to start! (And I mean everything). From picking up an intel or capping a point, to stepping into a trigger volume. But for staying consistent with ctf_well, cp_freight and the rest of the maps, we'll use a timer.

Place an entity somewhere in your map (it doesn't matter where, but I reccomend putting it near the train for ease of access). Set it's class to logic_timer. Give it a name ("timer"). Now you'll need to chose how you want the timer to work- using random times, or pre-set times. You will set the "Use random times" property accordingly. Then you'll set the refire interval if you chose pre-set times, or the minimum/maximum time if you chose random times. (times are in seconds obviously).

tut6_zpsdmoce9i3.png


Then, on the outputs tab, add an output to the timer.

That will tell the train to start driving. You can trigger this output (StartForward) from wherever you want- as I said, it can be a control point, a trigger, or anything else.
You may want to set the delay of the output to a few seconds, if you want to add the hazard bells sound to activate before the train comes, like in ctf_well. In that case, you'll need to add an ambient_generic entity (the entity used to play sound files in your map) with a name ("train_bells") and the sound property set to the ringing bells sound (ambient/railroad_bells.wav), and then add an output from the timer,
To make sure that the bells don't play forever, add another output:

Make sure you set the delay properly. The delay means how much time the output will wait between the time it was triggered (in this case-triggered by the clock) until it gets "sent". You want to give the train something around ~1 second and the bells StopSound something around ~5 seconds.
tut7_zpseaaeadat.png


Finishing up

Well, from here, you just need to compile. (F9). Make sure everything works, and enjoy your train!

533DB7CDEF762032E1309632B4E5DA6C2F714083


And just to sum this tutorial up, you've just learned how to make elevators, lifts, moving spaceships, or anything that needs to move around in the map.
Yes that's right. ITS THE SAME BASIC SETUP FOR ALL MOVING THINGS. (not including doors, which are done differently)
You just need to change the things you parent to the func_tracktrain (an elevator or a spaceship, in this case), and the trigger for the movement starting (a trigger brush for the elevator, a logic_auto for the spaceship).
What are you waiting for? Open hammer and fill your map with dynamic moving things!

If you have a question, a suggestion, If you found a mistake, or suddenly got an urge to show off your amazing train, be sure to add those in the comments below.

Useful train links:
Freyja's lazy train prefab. Also featuring gates, which I didn't go over.
Another tutorial, which is more Half-Life oriented, and less complete IMO, but still relevant
what track props do i use for the train? all the ones i tried dont fit the train.
 

PyraXx | #updatetf2

L1: Registered
Jun 6, 2024
22
5
Introduction

The question "how do I make a train?" is asked a lot. Everybody wants to have a train in their map, because dynamic elements are cool, and trains are the best dynamic element in tf2. (that's a fact, not an opinion). From ctf_well and cp_freight, to cp_snowplow and koth_trainsawlazer- Many of the maps in the tf2 world feature trains. In this tutorial I'll go over creating a train and fitting it to your needs. This tutorial is very long, because I'll give in depth information and tips about all the entities we're using, so that you'll understand exactly what you're doing, and can later use that understanding to create your own train, or better- a whole new setup for something completely different! (I used it to make an elevator for my sd_ map, for example).

Freight3.png


What entities we'll be using?

Let's begin!

Now we'll build a basic train, like featured in cp_well, or cp_freight. It would only go in a straight line. We'll go later over curved tracks and how those work.
First, make a prop_dynamic. This would be your train model (the train you'll see in-game).
Set it's world model to a train engine. You can make more prop dynamic entities that would be the train cars, if you want to.

:cordonenable: IMPORTANT! :cordonenable: The train must be built facing from left to right. However, that won't define it's in-game position, but rather it's orientation relative to the tracks we'll soon place. So you don't need to rotate your entire map. You just need to build the tracks in the right direction (we'll soon talk about how to do that), and the train- facing right. Don't forget this tip!

tut1_zpswbfm3d1a.png


Next, make a brush, textured nodraw. it's height should be from the ground to the top of the lowest train part (car or engine), the length should be the train's lenght, and it's width- the train width. Place it over the train props.
Tie the brush to an entity (ctrl+t). Set the entity to "func_tracktrain". That's our train entity! Give it a name, like "train" (w/o quotations). Set all the train prop_dynamic props, so their "parent" property would be set to train. Child entities move together with their parents, so now all the train props would move together with the func_tracktrain entity.
We now need to set some properties for the func_tracktrain. double click it, and set the render mode to "don't render" (that way it would be invisible and won't cast shadows on your beautiful train). Set "max speed" to whatever speed you want your train to have (trains tend to have only one speed- the max speed. "Those drivers never lift their foot off the pedal, I'm telling ya"). I personally use 800. Set damage on crush to a very high number (like 99999).
Set the Move sound property to something like ambient\train.wav or ambient\slow_train.wav, or whatever you want. (in the sound browser window, you can search by putting keywords like "train" in the "filter" textbox, just like in the texture browser).
Then head to the "flags" tab and check "fixed orientation" and "Is unblockable by player".

tut2_zpssba2glmc.png


:helpers: NOTE :helpers: You will need to change another property, if you use a different sized track prop than the usual track props in tf2. You see, by default, the tracks in tf2 are 4 hammer units high (and by track I mean the track prop, not the actual path_track). If yours have a different height, you'll need to change the "Height above track" property to that height.

And now add a brush in front of the train, textured with trigger texture, and tie it to an entity (ctrl+t). Set the entity class to trigger_hurt, set the damage type to train. That would set the kill icon to the train one.
Trainico.png

Set the "damage" property to a very big number (like 9999999). That would kill all players touching the front end of the train, no matter how much they are healed.
Parent the trigger to the func_tracktrain. Then open the flags tab, and check the flag "Everything (not including physics debris)". That would be used so that the trigger also damages engineer machinery. (And I don't remember for sure, but I think it also has to do with killing Ubered players)

tut3_zpstkyalzqk.png


Now the train needs to move. For that, we'll have to define a track. Place an entity, and set it's class to "path_track". This is an entity used to define the path of objects that move, in the source engine (like rd_ bots, payload carts, etc.) The way path tracks work, is by "connecting" them. Two connected path tracks would form a path. Payloads might have hundreds of path_tracks, but we'll only need two for now.
The path_track needs to be located where you want the train to start, but you must remember that the train is not a real life train, it's a brush entity. Unlike real life trains, brush entity trains move from their origin. (marked with a little red circle when selected, by default it's set to the center of the brush). So you must think where you want the origin to be when the train starts, Not the front!!! Take that into consideration when planning the train area in hammer. Also remember to put the path_track in the proper height- the height should be the func_tracktrain origin's height.

:cordonenable: IMPORTANT! :cordonenable: The train's start and end spots should be well hidden in your map. (In a tunnel like cp_freight, or a warehouse like cp_well. It's up to you). If it won't be hidden, people would see your train suddenly appear, or disappear.

tut4_zpsc807f3pp.png


Set the path track name to something simple, but for ease of usage later, make it end with "_01". (I'll name mine "path_train_01"). Now, all the default properties are good for us.

Now, here's a cool trick- If you shift+drag your path track, hammer would automatically assume that the new path track is the next path_track for this path, and would connect them without you having to do a thing! It would also automatically rename the new path track, so that's cool too. Shift+drag a new path_track, and place it where you want the train to end it's track. (Same as before- end=where the origin should be at the end)

After you've done that, open the 1st path_track properties, and in the "flags" tab, check "teleport to THIS path_track". That marks this path_track as the first.
Open the func_tracktrain properties again, and set the "first stop target" to the first path_track name. That tells the func_tracktrain what is the path_track path it should follow.

And now for the final setup before we are finished with the basic train components- we'll need to set an output for the train to go back to the first path_track, after it reached the end. (Otherwise it would just stay at the edge of the path, and won't go again)
Open the last path_track's properties window, select the "outputs" tab, and make a new output-

tut5_zps5qlws70l.png


That's it! you have a train! but the train won't yet work, because you never told it when to start. And here's a great part- Everything can cause a train to start! (And I mean everything). From picking up an intel or capping a point, to stepping into a trigger volume. But for staying consistent with ctf_well, cp_freight and the rest of the maps, we'll use a timer.

Place an entity somewhere in your map (it doesn't matter where, but I reccomend putting it near the train for ease of access). Set it's class to logic_timer. Give it a name ("timer"). Now you'll need to chose how you want the timer to work- using random times, or pre-set times. You will set the "Use random times" property accordingly. Then you'll set the refire interval if you chose pre-set times, or the minimum/maximum time if you chose random times. (times are in seconds obviously).

tut6_zpsdmoce9i3.png


Then, on the outputs tab, add an output to the timer.

That will tell the train to start driving. You can trigger this output (StartForward) from wherever you want- as I said, it can be a control point, a trigger, or anything else.
You may want to set the delay of the output to a few seconds, if you want to add the hazard bells sound to activate before the train comes, like in ctf_well. In that case, you'll need to add an ambient_generic entity (the entity used to play sound files in your map) with a name ("train_bells") and the sound property set to the ringing bells sound (ambient/railroad_bells.wav), and then add an output from the timer,
To make sure that the bells don't play forever, add another output:

Make sure you set the delay properly. The delay means how much time the output will wait between the time it was triggered (in this case-triggered by the clock) until it gets "sent". You want to give the train something around ~1 second and the bells StopSound something around ~5 seconds.
tut7_zpseaaeadat.png


Finishing up

Well, from here, you just need to compile. (F9). Make sure everything works, and enjoy your train!

533DB7CDEF762032E1309632B4E5DA6C2F714083


And just to sum this tutorial up, you've just learned how to make elevators, lifts, moving spaceships, or anything that needs to move around in the map.
Yes that's right. ITS THE SAME BASIC SETUP FOR ALL MOVING THINGS. (not including doors, which are done differently)
You just need to change the things you parent to the func_tracktrain (an elevator or a spaceship, in this case), and the trigger for the movement starting (a trigger brush for the elevator, a logic_auto for the spaceship).
What are you waiting for? Open hammer and fill your map with dynamic moving things!

If you have a question, a suggestion, If you found a mistake, or suddenly got an urge to show off your amazing train, be sure to add those in the comments below.

Useful train links:
Freyja's lazy train prefab. Also featuring gates, which I didn't go over.
Another tutorial, which is more Half-Life oriented, and less complete IMO, but still relevant

yeah i followed the tutorial step by step but it says this:


-------------------------------------------------------------------------------
Running command:

cd "X:\SteamLibrary\steamapps\common\Team Fortress 2\bin\x64"
-------------------------------------------------------------------------------


-------------------------------------------------------------------------------
Running command:

"X:\SteamLibrary\steamapps\common\Team Fortress 2\bin\x64\vbsp.exe" -game "X:\SteamLibrary\steamapps\common\Team Fortress 2\tf" "x:\steamlibrary\steamapps\common\team fortress 2\bin\x64\hammerplusplus\maps\koth_traintest"
-------------------------------------------------------------------------------

Valve Software - vbsp.exe (Apr 22 2024)
8 threads
Using shader api: shaderapiempty.dll
materialPath: X:\SteamLibrary\steamapps\common\Team Fortress 2\tf\materials
Loading x:\steamlibrary\steamapps\common\team fortress 2\bin\x64\hammerplusplus\maps\koth_traintest.vmf
fixing up env_cubemap materials on brush sides...
ProcessBlock_Thread: 0...1...2...3...4...5...6...7...8...9...10 (0)
** leaked **
Entity path_track (-704.00 0.00 160.00) leaked!
Processing areas...done (0)
Building Faces...done (0)
FixTjuncs...
PruneNodes...
WriteBSP...
done (0)
*** Error: Skybox vtf files for skybox/sky_tf2_04 weren't compiled with the same size texture and/or same flags!
Can't load skybox file skybox/sky_tf2_04 to build the default cubemap!
*** Error: Skybox vtf files for skybox/sky_tf2_04 weren't compiled with the same size texture and/or same flags!
Can't load skybox file skybox/sky_tf2_04 to build the default cubemap!
Finding displacement neighbors...
Finding lightmap sample positions...
Displacement Alpha : 0...1...2...3...4...5...6...7...8...9...10
Building Physics collision data...
done (0) (5348 bytes)
Placing detail props : 0...1...2...3...4...5...6...7...8...9...10
Compacting texture/material tables...
Reduced 24 texinfos to 12
Reduced 5 texdatas to 5 (85 bytes to 85)
Writing x:\steamlibrary\steamapps\common\team fortress 2\bin\x64\hammerplusplus\maps\koth_traintest.bsp
ZIP Output overshot buffer estimate: Estimated 0, actual 54
0 seconds elapsed

-------------------------------------------------------------------------------
Running command:

cd "X:\SteamLibrary\steamapps\common\Team Fortress 2\bin\x64"
-------------------------------------------------------------------------------


-------------------------------------------------------------------------------
Running command:

"X:\SteamLibrary\steamapps\common\Team Fortress 2\bin\x64\vvis.exe" -game "X:\SteamLibrary\steamapps\common\Team Fortress 2\tf" "x:\steamlibrary\steamapps\common\team fortress 2\bin\x64\hammerplusplus\maps\koth_traintest"
-------------------------------------------------------------------------------

Valve Software - vvis.exe (Apr 22 2024)
8 threads
reading x:\steamlibrary\steamapps\common\team fortress 2\bin\x64\hammerplusplus\maps\koth_traintest.bsp
reading x:\steamlibrary\steamapps\common\team fortress 2\bin\x64\hammerplusplus\maps\koth_traintest.prt
LoadPortals: couldn't read x:\steamlibrary\steamapps\common\team fortress 2\bin\x64\hammerplusplus\maps\koth_traintest.prt


-------------------------------------------------------------------------------
Command failed with return code 0x1! Scroll up and check if you have a leak or error in VBSP.

Please screenshot the WHOLE window when showing this compile log
Or upload the .log file generated beside your VMF
-------------------------------------------------------------------------------


4 command(s) finished in 0 seconds

Press a key to close.

it says that my first track is leaked, but idk what that means. here its a screenshot from the track:
1717706556714.png

Its literally inside of the train

1717706620811.png

i like trains

please how do i fix i wanna be hit by a train (in tf2)