Level Transitions

How It Works

Level transitions work similarly to Half-Life 2. When a transition fires, the engine snapshots the current map's state, loads the destination map, and carries any entities that were inside a designated transition volume across to the new level. The player's position in the new map is determined by a LogicTransitionLevel anchor entity placed in both maps. The engine calculates the offset between the two anchors and shifts all transitioning entities by that amount, so the player lands in the right spot without any manual coordinate work. This also means that it doesn't matter where in actual space the anchors are, just as long as their relative positions compared to whatever room you put them in are the same.

Maps you've already visited are cached in memory for the session. If you transition back to a map you've been to before, it restores to the state it was in when you left rather than resetting to its original map file state.

Setting Up the Transition in Map A

Every transition needs three things in the source map: a transition volume, a LogicTransitionLevel entity, and a trigger to fire it.

1
Create the transition volume

Draw a large func_trigger brush that covers the area where entities need to be in order to carry over. This should be big enough to contain the player and any NPCs you want to bring along. Give it a target name like level_transition_volume. Apply the tool_trigger texture to all faces.

2
Place a LogicTransitionLevel entity

Place a LogicTransitionLevel entity somewhere meaningful in the transition area, typically at the threshold between the two spaces. Give it a target name so it can be targeted by outputs, for example transition_a_to_b. Set its properties:

Transition Volume

The target name of your func_trigger volume, e.g. level_transition_volume.

Destination Anchor

The target name of the matching LogicTransitionLevel in the destination map.

3
Create the fire trigger

Place a second smaller func_trigger brush at the actual threshold point where you want the load to happen, for example in a doorway or at the end of a corridor. This is separate from the transition volume. Set up an output on it:

From My Output

OnTriggerEnter

To Entity

Your LogicTransitionLevel entity name.

Input Target

TransitionLevel

Input Parameter

The destination map name, relative to the current map's folder. No file extension, e.g. level_b. Since you'll probably never have maps transitioning from different folders, this is usually just the plain name of the next map.

4
Add a class filter to the fire trigger

Without a filter, any entity walking through the fire trigger will set off the transition. Place a LogicClassFilter entity and set its Classname property to your player class, e.g. Player. Then set the fire trigger's Filter Name property to the target name of this filter entity. Now only the player can fire the transition.

Setting Up the Receiving End in Map B

The destination map needs a matching LogicTransitionLevel placed at the same relative position as the one in Map A. The engine uses the offset between the two anchors to reposition the entities, so the geometry around it should look the same from the player's perspective.

Give this entity the same target name as the one you set in Destination Anchor back in Map A. That's all the engine needs to find it.

You'll also typically want to set up the reverse transition here using the same steps, so the player can walk back into Map A. Make sure the fire trigger for the return transition is not placed right on top of where the player arrives. If the player transitions in and immediately steps on the return trigger, they'll bounce back and forth forever. Leave enough space between the arrival point and the return trigger that the player has to deliberately walk back.

Note Use a LogicClassFilter on the return trigger too. The same issue with non-player entities firing the transition applies in both directions.

What Carries Over

Any entity that is physically inside the transition volume at the moment the transition fires will be carried to the new map. This includes the player and any NPCs or physics objects that happen to be in that space. Their position, rotation, velocity, and custom controller data all transfer over.

It's important to note that this system is heavily based on the save & load system. This matters because technically when entities transfer between maps they are entirely respawned exactly the same as the load system, so anything you want to transfer over needs to be saved and loaded via custom data as explained on the save page. Everything else will reset to default values.

Entities that are not inside the volume stay behind in the cached map state. If you return to that map later in the session they will be right where you left them.

Global state flags set via GlobalState are also preserved across transitions, so any one-time events or flags you've set will still be active in the new map.

Note In the FPS template, you can actually have a player entity in both map A and B. Whenever the player is spawned in the FPS template, it will remove any other existing player entities, leaving only the one that transferred over. This is useful both for testing, and also if you want to implement a "chapter" system like Half-Life 2.

Saving Across Transitions

The session map cache is included in save files. If the player saves after having visited multiple maps, all of those cached states are written to disk and restored on load. This means a player can save in Map B, load, and return to Map A and find it in exactly the state they left it.

Starting a new game should call SaveManager.ClearSessionMapStates() to wipe any cached states from a previous session. The map console command does this automatically.