Navigation links: transitions and limitations
Connect separate map areas and handle the transition correctly.
NavigationLink2D and NavigationLink3D add a transition between navigation surfaces, such as a ladder, jump or teleport. A link participates in pathfinding but does not perform movement. Your game implements animation, relocation, door waiting and transition validation.
Configure a 2D link
Use an active map with two prepared navigation regions. First establish that they are disconnected without the link: a large edge-connection margin may already connect nearby regions.
- Add a
NavigationLink2Dto the level and assign its intended navigation map if different from the world map. - Place its start near the first region and end near the second. The Entity
StartPositionandEndPositionare local to the link. NavigationServer endpoints are global. - Check the map radius with
MapSetLinkConnectionRadius: it selects nearby surfaces around each endpoint, rather than limiting transition length. A missing polygon near either endpoint prevents a complete path. - Enable
Bidirectionalfor travel both ways. Withfalse, the allowed direction is from the link start to its end. - Align region, link and query navigation layers. Regions on layer 1 and a link on layer 2 require query mask 3; mask 1 alone is insufficient.
- Wait for map changes to be published and query both directions. Compare returned endpoints with the requested positions: see path queries.
The fixture has regions at x=0–10 and x=20–30, y=0–10. A link connects global points (9, 5) and (21, 5). Adding it completes the route from (1, 5) to (29, 5). Disabling it or moving its endpoint outside the connection radius breaks the route again.
Create through the server
For a procedural level, save NavigationConnection2D.cs in a Reckfell 1.0.0 C# project:
using Reckfell;
using System;
public sealed class NavigationConnection2D : IDisposable
{
public Rid Handle { get; private set; }
public NavigationConnection2D(Rid map, Vector2 start, Vector2 end,
uint layers = 1, bool bidirectional = true, ulong ownerId = 0)
{
if (!map.IsValid) throw new ArgumentException("A live map is required.", nameof(map));
Handle = NavigationServer2D.LinkCreate();
NavigationServer2D.LinkSetStartPosition(Handle, start);
NavigationServer2D.LinkSetEndPosition(Handle, end);
NavigationServer2D.LinkSetNavigationLayers(Handle, layers);
NavigationServer2D.LinkSetBidirectional(Handle, bidirectional);
NavigationServer2D.LinkSetOwnerId(Handle, ownerId);
NavigationServer2D.LinkSetMap(Handle, map);
NavigationServer2D.LinkSetEnabled(Handle, true);
}
private void EnsureAlive()
{
if (!Handle.IsValid) throw new ObjectDisposedException(nameof(NavigationConnection2D));
}
public void SetEnabled(bool enabled)
{
EnsureAlive();
NavigationServer2D.LinkSetEnabled(Handle, enabled);
}
public void SetBidirectional(bool enabled)
{
EnsureAlive();
NavigationServer2D.LinkSetBidirectional(Handle, enabled);
}
public void SetLayers(uint layers)
{
EnsureAlive();
NavigationServer2D.LinkSetNavigationLayers(Handle, layers);
}
public void Dispose()
{
if (!Handle.IsValid) return;
NavigationServer2D.FreeRid(Handle);
Handle = default;
}
}Pass the live map RID and global endpoints to the constructor. Keep the helper with its procedural transition owner and call Dispose() when removing it, before freeing the map. Repeated disposal is safe; subsequent method calls are rejected. Do not free Handle separately: the helper owns it.
An ordinary NavigationLink2D Entity already manages its own RID lifecycle. Do not mix both ownership approaches for one link. Moving the Entity transforms its local endpoints into new server-global coordinates; this was verified at runtime.
Perform the transition
Enable result metadata. PathTypes distinguishes region and link segments; PathRids identifies a point owner RID, while PathOwnerIds identifies its object owner when assigned. Pass GetInstanceId() of the transition controller to the helper constructor if needed.
When a character reaches the transition entrance, hand control to game logic: jump, wait for a platform or relocate the character. Then resume normal path following. Path points do not establish that a floor exists or validate a physically safe trajectory. A zero owner ID must not be treated as an existing Entity.
EnterCost and TravelCost affect pathfinding cost, rather than movement speed or animation duration. The checked server link defaults are 0 and 1. Test selection among alternative links separately on your map.
IncludedRegions limitation in 1.0.0
In the installed build, a nonempty IncludedRegions blocks the tested NavigationLink route even when both connected regions are included. Clearing that list restores the path. This is a reproduced limitation rather than a layer configuration mistake.
For this case, leave IncludedRegions empty and restrict access through navigation layers. Verify that the masks still exclude every forbidden area. Do not add the required destination region to ExcludedRegions as a workaround: exclusion also breaks the path. This suite does not establish 3D link filter behavior.
Diagnose problems
- Forward travel works but reverse travel fails: check
Bidirectionaland endpoint direction. - A visible link is unused: check the map, masks, endpoint connections and
IncludedRegions. - Endpoints look correct in the editor but code offsets them: distinguish Entity-local and NavigationServer-global coordinates.
- A character walks through the air: the link supplied a route, but the game did not implement special movement.
Executed checks cover the server helper, both directions, layers, disabling, endpoint radius, metadata RID/ID, disposal, Entity local/global positions and the filter limitation. Movement animation, avoidance, editor placement, baking, 3D links and cost-based selection were not tested.