POI Manager

Overview

POI Manager is the central singleton that orchestrates every Point of Interest in the game. It maintains the authoritative list of all active POIMarker components and CustomWaypoint objects, runs a timed distance-update loop, and exposes query, creation, and navigation APIs consumed by the Minimap, World Map, and Compass systems.

Every POIMarker in the scene self-registers with POI Manager on Awake and unregisters when disabled or destroyed — no manual wiring is required. POI Manager then notifies the map systems of the change so icons appear or disappear immediately.

A single POI Manager instance persists for the lifetime of the game session (DontDestroyOnLoad). If none exists in a scene, one is created automatically at runtime. Only one scene in the project needs to contain a configured POI Manager GameObject.


Scene Setup (ONLY IF NOT USING THE ONE-CLICK SETUP!)

Add a single POI Manager component to a persistent GameObject (e.g. your _Managers object). Mark it DontDestroyOnLoad implicitly — the component handles this itself. Do not place additional POI Manager components in other scenes; duplicate instances are destroyed on Awake.


Inspector Sections

Settings

Core runtime behaviour of the manager.

Property
Type
Default
Description

Auto Find Player

bool

true

On Start, searches for a GameObject tagged Player and assigns its transform automatically. Disable to use a manual reference instead.

Player Transform

TransformReference

The transform used for all distance and elevation calculations. Shown only when Auto Find Player is off, or when a constant value is already assigned. Accepts either a direct scene reference or a Malbers TransformVariable ScriptableObject.

Update Interval

float

0.1 s

How often (in seconds) distances are recalculated for all registered POIs and custom waypoints. Lower values increase accuracy at the cost of CPU. The inspector warns if the value drops below 0.05 s.

Auto Find Player uses GameObject.FindGameObjectWithTag("Player") during Start. If the player spawns after Start (e.g. from a loading system), disable Auto Find Player and assign the reference manually or via script once the player exists.


Default Icons

Fallback sprites used when a POI or waypoint has no icon assigned to its asset.

Property
Type
Description

Default Map Icon

Sprite

Fallback icon displayed on the minimap and world map for any POI whose PointOfInterest asset has no Map Icon assigned.

Default Compass Icon

Sprite

Fallback icon for the compass bar.

Default Waypoint Icon

Sprite

Icon used for all player-created custom waypoints. If not assigned, falls back to Default Map Icon.

The inspector warns in edit mode if Default Map Icon or Default Compass Icon is empty, as this will cause POIs to be invisible.


Custom Waypoints

Controls the runtime waypoint system that lets players (or systems) place navigation markers in the world.

Property
Type
Default
Description

Max Waypoints

int

10

The hard cap on how many custom waypoints can exist simultaneously. CreateWaypoint() returns null and logs a warning once this limit is reached.

Marker Prefab

GameObject

An optional 3D prefab instantiated as a child of each waypoint's GameObject at the world-space position. Use for visible in-world pins or flags. Leave empty for map-only waypoints.

Waypoint Color

Color

Yellow

The default IconColor assigned to newly created waypoints.

In Play mode the inspector shows a live Current Waypoints: X / N counter and confirms how many more can be created.


POI Elevation Tracking

POI Manager maintains an elevation system that calculates the vertical height difference between the player and each POI. The compass bar can display an up/down indicator and a distance label coloured by severity.

Property
Type
Default
Description

Enable Elevation Tracking

bool

true

Master toggle. When off, GetElevationData() always returns ElevationData.None.

Min Elevation Threshold

float

3 m

Height differences smaller than this are treated as "same level" — no indicator is shown. Prevents jitter from minor terrain undulation.

Show Elevation on Compass

bool

true

Whether the elevation indicator is shown on the compass bar.

Elevation Format

string

"0"

C# number format string controlling how the elevation distance is displayed. "0" = whole metres (e.g. 15m); "0.0" = one decimal place (e.g. 15.5m).

Elevation Ranges define the colour-coding thresholds:

Property
Default
Meaning

Close Elevation Range

10 m

Differences up to this value use Close Elevation Color (default green).

Medium Elevation Range

30 m

Differences up to this value use Medium Elevation Color (default yellow).

(above medium)

Uses Far Elevation Color (default red).

The elevation cache is keyed by IPOITarget reference and capped at 200 entries. Dead or inactive entries are pruned automatically when the cap is reached.


Events

Fired at runtime as the POI and waypoint lists change. Wire these to UI, audio, or quest systems that need to react to navigation changes.

POI Events

Event
Signature
Fires When

On POI Registered

UnityEvent<POIMarker>

A POIMarker calls RegisterPOI() on Awake or re-enable.

On POI Unregistered

UnityEvent<POIMarker>

A POIMarker calls UnregisterPOI() on disable or destroy.

On POI Updated

UnityEvent<POIMarker>

Any system calls UpdatePOI() for a state change on a specific marker.

On POI List Changed

MEvent (no args)

The full list changes — registration, unregistration, waypoint creation/removal, or active waypoint selection. MinimapUI and WorldMapUI subscribe to this to trigger an icon pool refresh.

Waypoint Events

Event
Signature
Fires When

On Waypoint Created

UnityEvent<CustomWaypoint>

CreateWaypoint() successfully creates a new waypoint.

On Waypoint Removed

UnityEvent<CustomWaypoint>

RemoveWaypoint() destroys a waypoint.


Status & Debug (Play mode only)

The bottom section of the inspector is a live dashboard visible during Play mode:

  • Registered POIs — total count of active POIMarkers

  • Custom Waypoints — current count vs. the max cap

  • Total Targets — combined POI + waypoint count

  • POIs by Category — a breakdown of registered POIs grouped by their POICategory

  • Player found — confirms which GameObject is being used as the player reference, or warns if none is assigned

Testing Buttons (Play mode):

Button
Behaviour

Clear All Waypoints

Opens a confirmation dialog, then calls ClearAllWaypoints().

Create Test Waypoint at Player

Calls CreateWaypoint() 10 world units in front of the player. Only shown when a player reference is present and the waypoint cap has not been reached.


How POI Registration Works

POIMarker components self-manage their own registration lifecycle:

  1. OnEnable / AwakePOIManager.Instance.RegisterPOI(this) — the marker is added to the flat list and the category index. OnPOIRegistered and OnPOIListChanged fire.

  2. OnDisable / OnDestroyPOIManager.Instance.UnregisterPOI(this) — the marker is removed from both collections. OnPOIUnregistered and OnPOIListChanged fire.

Map and compass UIs subscribe to OnPOIListChanged and rebuild their icon pools whenever it fires. This means enabling or disabling a POIMarker at runtime automatically updates every navigation UI with no additional scripting.


Active Navigation Waypoint

POI Manager tracks a single active navigation waypoint — the destination the player is currently navigating toward. Both MinimapUI and WorldMapUI draw a distinct dotted path to this target.

Only one waypoint can be active at a time. Setting a new one automatically replaces the previous selection.


The IPOITarget Interface

Defined alongside POI Manager, this interface is the shared contract implemented by both POIMarker and CustomWaypoint. Map and compass systems operate exclusively on IPOITarget so they are agnostic to whether a target is a scene-placed POI or a player-created waypoint.

Member
Description

WorldPosition

The 3D world-space position of the target.

POIName

Display name.

MapIcon

Sprite shown on minimap and world map.

CompassIcon

Sprite shown on the compass bar.

IconColor

Tint colour.

IsActive

Whether the target should currently be visible.

CurrentDistance

Cached distance to the player (updated each interval).

ShowOnMinimap

Whether to display on the minimap.

ShowOnCompass

Whether to display on the compass.


Public API

POI Registration

Method
Description

RegisterPOI(POIMarker poi)

Adds a marker to the managed list and fires events. Called automatically by POIMarker — rarely needed manually.

UnregisterPOI(POIMarker poi)

Removes a marker and fires events. Called automatically by POIMarker.

UpdatePOI(POIMarker poi)

Fires OnPOIUpdated for the given marker. Call when the marker's state changes and you need listeners to react.

Query Methods

Method
Returns
Description

GetPOIsInRange(float maxDistance)

List<POIMarker>

All active POIs within maxDistance world units of the player, sorted nearest-first.

GetPOIsByCategory(POICategory category)

List<POIMarker>

All active POIs matching the given category, using the pre-built category index for O(1) lookup.

GetNearestPOI(POICategory? category)

POIMarker

The closest active POI overall, or within a specific category if provided. Returns null if none found.

GetAllTargets()

List<IPOITarget>

Combined list of all active POIMarker and CustomWaypoint objects via the shared IPOITarget interface.

Custom Waypoints

Method
Returns
Description

CreateWaypoint(Vector3 position, string name)

CustomWaypoint

Creates a new waypoint at position with the given name. Spawns waypointMarkerPrefab as a child if assigned. Returns null if the waypoint cap has been reached.

RemoveWaypoint(CustomWaypoint waypoint)

void

Removes the waypoint from the list, destroys its GameObject, and clears the active waypoint if it was the removed one.

ClearAllWaypoints()

void

Removes and destroys all custom waypoints and clears the active navigation target.

Active Navigation

Method / Property
Description

ActiveWaypoint

Read-only. The currently selected navigation target, or null.

SetActiveWaypoint(CustomWaypoint waypoint)

Sets the active navigation target and fires OnPOIListChanged to trigger a map/minimap path refresh.

ClearActiveWaypoint()

Clears the active target and fires OnPOIListChanged.

Elevation

Method
Returns
Description

GetElevationData(IPOITarget target)

ElevationData

Returns cached elevation data for the target, calculating and caching it on first access.

UpdateAllElevationData()

void

Clears the entire elevation cache, forcing recalculation on the next GetElevationData() call. Call after a significant player position change (e.g. teleport or fast travel).

ShouldShowElevation(IPOITarget target)

bool

Convenience method; returns GetElevationData(target).showIndicator.

Properties

Property
Type
Description

RegisteredPOIs

List<POIMarker>

A copy of the current POI list (safe to iterate without modification risk).

CustomWaypoints

List<CustomWaypoint>

A copy of the current waypoint list.

PlayerTransform

Transform

The resolved player transform, or null if not yet found.

CustomWaypointCount

int

Current number of active custom waypoints.

CanCreateWaypoint

bool

True when CustomWaypointCount < maxCustomWaypoints.


Other Tips

  • One POI Manager per project, one scene — Because the component calls DontDestroyOnLoad, placing it in multiple scenes will result in the duplicate being silently destroyed. Place it in your initial loading or persistent scene only.

  • Auto-create fallback — If no POI Manager exists in the scene at runtime, one is created automatically with default settings. This is safe for quick tests but provides no default icons or configured prefabs. Always have a properly configured instance in your persistent scene for a shipping game.

  • Update Interval vs. accuracy — The 0.1 s default means distance values are up to 100 ms stale. For fast-moving targets or tight distance checks, lower the interval. For ambient decoration POIs, 0.5 s is perfectly sufficient.

  • Elevation cache lifetime — The elevation cache is only cleared by UpdateAllElevationData() or when it exceeds 200 entries. Call UpdateAllElevationData() after any fast travel or scene teleport where the player moves a large vertical distance instantly, otherwise compass indicators will show stale elevation data until the cache naturally refreshes.

  • GetAllTargets() returns copies — Both RegisteredPOIs and CustomWaypoints return new list copies. Storing the result across frames is safe, but the values won't auto-update when new POIs register. Re-call as needed.

  • Category index is O(1)GetPOIsByCategory() queries a pre-built Dictionary<string, List<POIMarker>> rather than iterating all POIs. Use this instead of RegisteredPOIs.Where(…) in performance-sensitive code.

Last updated