reckfellENGINE

Navigation maps: isolation and ownership

Select a map, migrate a region and release owned RIDs.

On this page

A navigation map groups regions, links and navigation data for one space. It is a NavigationServer object identified by a RID, rather than an Entity, a level image or a navigation mesh. Touching regions on different maps do not connect.

World map or custom map

Inside the tree, an Entity2D obtains its world map through GetWorld2D().NavigationMap; an Entity3D uses GetWorld3D().NavigationMap. The world owns that map: do not free it manually. For a region assigned a custom map, use its GetNavigationMap() to avoid querying another world.

Use a separate map for genuinely separate navigation, such as different traversable geometry sets. Different access permissions alone are often better represented by navigation layers. Use 2D maps and RIDs with NavigationServer2D, and 3D equivalents with NavigationServer3D.

Create an explicitly owned 2D map

Save NavigationMapOwner2D.cs in a Reckfell 1.0.0 C# project:

C#
using Reckfell;
using System;
using System.Collections.Generic;

public sealed class NavigationMapOwner2D : IDisposable
{
    public Rid Map { get; private set; }
    private readonly List<Rid> _regions = new();
    private readonly List<NavigationPolygon> _polygons = new();

    public NavigationMapOwner2D()
    {
        Map = NavigationServer2D.MapCreate();
        NavigationServer2D.MapSetActive(Map, true);
    }

    public Rid AddRectangle(Rect2 bounds, uint layers = 1)
    {
        if (!Map.IsValid) throw new ObjectDisposedException(nameof(NavigationMapOwner2D));
        if (bounds.Size.X <= 0 || bounds.Size.Y <= 0)
            throw new ArgumentException("Rectangle size must be positive.", nameof(bounds));
        Vector2 a = bounds.Position, b = bounds.End;
        var polygon = new NavigationPolygon
        {
            Vertices = new[] { a, new Vector2(b.X, a.Y), b, new Vector2(a.X, b.Y) }
        };
        polygon.AddPolygon(new[] { 0, 1, 2, 3 });
        Rid region = NavigationServer2D.RegionCreate();
        _regions.Add(region);
        _polygons.Add(polygon);
        NavigationServer2D.RegionSetNavigationPolygon(region, polygon);
        NavigationServer2D.RegionSetNavigationLayers(region, layers);
        NavigationServer2D.RegionSetMap(region, Map);
        return region;
    }

    public void Dispose()
    {
        if (!Map.IsValid) return;
        foreach (Rid region in _regions) NavigationServer2D.FreeRid(region);
        NavigationServer2D.FreeRid(Map);
        Map = default;
        foreach (var polygon in _polygons) polygon.Dispose();
        _regions.Clear(); _polygons.Clear();
    }
}

Create a helper instance, then add rectangles with AddRectangle(new Rect2(0, 0, 10, 10)). Coordinates define map navigation surfaces, not visible graphics or physics collisions. Sizes must be positive. The helper owns the map, regions and polygon resources and releases them through Dispose().

The returned region RID may be used for configuration, but the helper retains ownership. Do not call FreeRid for it separately or use the map after disposal. Moving a region to another map does not transfer ownership: the original helper will still free that region on disposal.

Synchronization and migration

RegionSetMap(region, map) queues map assignment. In the check, an immediate getter still returned the old value; after synchronization it returned the new one. A region belongs to one map: migration removes old membership and adds the new membership.

RegionSetMap(region, default) detaches a region without freeing it. It can be assigned again later. Wait for geometry publication after changes and issue a new query, as described in server usage.

What Active means

MapSetActive(map, true) includes the map in server processing. Setting false does not prohibit queries: the installed build still returns an already published route for an inactive map. To pause a character, stop movement logic and new gameplay commands rather than relying only on this flag.

MapGetIterationId(map) == 0 means no first version has been published. A nonzero ID does not prove the most recent change has been processed. RID creation, region assignment and path readiness are separate stages.

Verify the result

The executed fixture puts rectangle x=0–10 on the first map and x=10–20 on the second. A first-map query does not reach (19, 5), even though the surfaces touch. Moving the second region to the first map makes the target reachable.

For an empty map, inspect MapGetRegions, region assignment and polygon data. For stale paths, check synchronization. For RID errors, inspect ownership and disposal timing. Freeing a map does not replace freeing separately created regions and links; the helper performs both explicitly.

Executed checks cover creation, map isolation, region migration/detachment, querying an inactive published map and helper disposal. Automatic world-map creation was checked against source. Baking, avoidance, editor UI and isolation of multiple 3D maps were not separately executed.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.