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.
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.
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.
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.
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:
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
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
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
POICategoryPlayer found — confirms which GameObject is being used as the player reference, or warns if none is assigned
Testing Buttons (Play mode):
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:
OnEnable / Awake →
POIManager.Instance.RegisterPOI(this)— the marker is added to the flat list and the category index.OnPOIRegisteredandOnPOIListChangedfire.OnDisable / OnDestroy →
POIManager.Instance.UnregisterPOI(this)— the marker is removed from both collections.OnPOIUnregisteredandOnPOIListChangedfire.
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
IPOITarget InterfaceDefined 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.
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
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
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
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
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
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
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. CallUpdateAllElevationData()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 — BothRegisteredPOIsandCustomWaypointsreturn 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-builtDictionary<string, List<POIMarker>>rather than iterating all POIs. Use this instead ofRegisteredPOIs.Where(…)in performance-sensitive code.
Last updated