Custom Waypoint
Custom Waypoint is the lightweight runtime marker used for player-placed navigation pins. Where POIMarker is a persistent scene component backed by a PointOfInterest asset, CustomWaypoint is created and destroyed entirely at runtime — the player places one on the world map, it appears on the minimap and compass immediately, and it removes itself automatically when reached or after a configurable lifetime.
Because CustomWaypoint implements the same IPOITarget interface as POIMarker, every navigation surface (minimap, world map, compass) handles it identically without special-case code. From the map's perspective, a custom waypoint is just another icon with a position.
Custom waypoints are almost always created through POIManager.CreateWaypoint() rather than placed manually in the scene.
How Waypoints Are Created
The standard creation flow is:
The player double-clicks a location on the World Map.
WorldMapUIcallsPOIManager.CreateWaypoint(worldPosition, name).POIManagerinstantiates a new GameObject, adds aCustomWaypointcomponent, callsInitialize()on it, and optionally spawns the configured Marker Prefab as a child.The new waypoint is registered in POIManager's waypoint list and
OnPOIListChangedfires, causing all map surfaces to refresh.
The waypoint then persists — visible on the minimap, compass, and world map — until it is removed via RemoveSelf(), by POIManager.RemoveWaypoint(), or by POIManager.ClearAllWaypoints().
Inspector Sections
Waypoint Data
The identity and icon of this waypoint.
Waypoint Name
string
"Custom Waypoint"
Display name shown on map tooltips and compass labels. Writable at runtime via the WaypointName property.
Icon
Sprite
—
A single sprite used for both the minimap/world-map icon and the compass icon.
Color
Color
Yellow
Tint applied to the icon on all navigation surfaces. Also used to colour the scene gizmos.
Is Active
bool
true
When false, the waypoint is excluded from all navigation displays.
A live 32 × 32 icon preview (tinted by Color) is drawn beneath the icon slot when a sprite is assigned. The inspector warns if the name is empty or the icon is not assigned, as the waypoint will be invisible without an icon.
Display Settings
Show Distance
bool
true
Whether to append a distance readout to the waypoint label on the compass bar.
Fade Distance
float
200 m
The distance at which the waypoint icon begins to fade. The inspector confirms the active value (e.g. Waypoint will fade at 200 m).
Lifetime Settings
Controls how long the waypoint persists before removing itself.
Has Lifetime
bool
false
When enabled, the waypoint automatically calls RemoveSelf() after the specified duration.
Lifetime
float
60 s
Duration in seconds before auto-removal. Only shown when Has Lifetime is enabled.
Auto Remove on Reach
bool
true
When the player comes within the reach radius (5 m by default), OnWaypointReached fires and the waypoint removes itself.
Reach vs. Lifetime —
autoRemoveOnReachandhasLifetimeare independent. If either condition is met while the player is within range,RemoveSelf()is called. A waypoint with Has Lifetime enabled will also remove itself at the lifetime boundary even if the player never approached it.
In Play mode with Has Lifetime enabled, a progress bar is drawn showing the time remaining as it counts down in real time.
Events
On Waypoint Reached
UnityEvent
The player's distance drops to or below the reach radius (5 m). Fires once per waypoint lifetime — subsequent distance checks are skipped after isReached is set.
On Distance Updated
UnityEvent<float>
Every time UpdateDistance() is called (at POIManager.updateInterval, typically 0.1 s). Passes the current distance in world units.
Status & Testing
In edit mode: Validates that the waypoint name is set and an icon is assigned.
In Play mode, the section shows:
IsActivestateCurrent distance to the player
World-space position
Time remaining (if Has Lifetime is enabled)
Testing buttons (Play mode):
Remove
Calls RemoveSelf(), cleanly removing the waypoint through POIManager.
[Waypoint Name]
Selects the waypoint's GameObject in the Hierarchy and frames it in the Scene view.
IPOITarget Implementation
IPOITarget ImplementationCustomWaypoint implements the IPOITarget interface as follows:
WorldPosition
transform.position — no vertical offset (unlike POIMarker).
POIName
Returns waypointName.
MapIcon
Returns icon.
CompassIcon
Returns icon — the same sprite is used for both surfaces.
IconColor
Returns color.
IsActive
isActive && gameObject.activeInHierarchy — both the serialized flag and the GameObject must be active.
CurrentDistance
Cached distance to the player, updated by POIManager each interval.
ShowOnMinimap
Always true — custom waypoints always appear on the minimap.
ShowOnCompass
Always true — custom waypoints always appear on the compass.
Scene Gizmos
Unlike most components, CustomWaypoint draws gizmos via OnDrawGizmos (always visible, not just when selected) so placed waypoints are easy to locate in the Scene view.
Wire sphere (0.5 m)
Drawn at the waypoint's position in the icon color.
Vertical line
10 units tall, acting as a scene beacon.
Reach radius sphere
Semi-transparent wire sphere at the reach distance (5 m by default). Represents the proximity that triggers OnWaypointReached.
The OnSceneGUI handler (selected only) draws the same beacon shapes via Handles, adds a semi-transparent disc at the Fade Distance radius, and renders the waypoint name as a coloured bold label at the top of the vertical line.
Public API
Lifecycle
Initialize(string name, Sprite icon, Color color, float reachDist = 5f)
Sets the waypoint's name, icon, colour, and reach radius. Called automatically by POIManager.CreateWaypoint() immediately after the component is added. Also resets the creation time, so a lifetime clock starts from this call.
RemoveSelf()
Cleanly removes this waypoint. Calls POIManager.RemoveWaypoint(this) if the manager is available (which fires OnWaypointRemoved and OnPOIListChanged), or falls back to Destroy(gameObject).
Runtime Updates
UpdateDistance(Vector3 playerPosition)
Recalculates CurrentDistance, fires OnDistanceUpdated, and checks whether the reach threshold has been crossed. Called by POIManager each update interval.
Post-Creation Configuration
SetIconAndColor(Sprite newIcon, Color newColor)
Updates the icon and colour after the waypoint has been created (e.g. after the player confirms a selection in a WaypointPickerUI). Fires POIManager.OnPOIListChanged so all navigation surfaces refresh their icons immediately.
SetLifetime(float seconds)
Enables the lifetime system and sets the duration. Resets the creation time to now, so the countdown begins from the moment this method is called rather than from when the component started.
Properties
WaypointName
string (get/set)
Read or write the display name at runtime. Setting the name does not automatically notify POIManager — call POIManager.OnPOIListChanged?.Invoke() manually if the name change needs to propagate to UI immediately.
TimeRemaining
float (read-only)
Seconds until auto-removal. Returns float.MaxValue when Has Lifetime is disabled. Never returns a negative value (Mathf.Max(0, …) is applied).
Workflow: Full Player-Placed Waypoint Flow
Player interaction — Player opens the World Map and double-clicks a location.
WorldMapUI— CallsPOIManager.CreateWaypoint(worldPosition, "Custom Waypoint").POIManager— Creates a new GameObject, addsCustomWaypoint, callsInitialize()with the default icon and colour from its Default Waypoint Icon and Waypoint Color settings, and optionally spawns the Marker Prefab in the world.Icon refresh —
OnPOIListChangedfires; minimap, compass, and world map rebuild their icon pools. The new pin appears on all surfaces.(Optional)
WaypointPickerUI— If a picker panel is configured, the player selects a custom icon and name before confirming. The panel callsSetIconAndColor()on the created waypoint, triggering another icon refresh.POIManager.SetActiveWaypoint(waypoint)— Marks this as the navigation target; minimap and world map draw a dotted path to it.Player navigates —
UpdateDistance()fires every 0.1 s. When the player reaches within 5 m,OnWaypointReachedfires and (ifautoRemoveOnReachis true)RemoveSelf()is called.Cleanup —
POIManager.RemoveWaypoint()destroys the GameObject and firesOnPOIListChanged. The icon disappears from all navigation surfaces.
Other Tips
Always create via
POIManager— Callingnew GameObject().AddComponent<CustomWaypoint>()directly bypasses the waypoint cap check, the marker prefab spawning, and theOnWaypointCreatedevent. Always usePOIManager.CreateWaypoint().Same icon for map and compass — Unlike
POIMarker,CustomWaypointuses a single sprite for both surfaces. If you need different icons per surface on a waypoint, use aPOIMarkerwithuseCustomSettings = trueandcustomCategory = Waypointinstead.WorldPositionhas no offset — The icon is placed at exactlytransform.position. There is noworldMarkerOffsetequivalent. The world marker prefab (if any) is parented to the waypoint's GameObject with local position zero.SetLifetime()restarts the clock — CallingSetLifetime()on an existing waypoint does not add time; it resets the countdown to start from the moment of the call. This is intentional for scripted "refresh" scenarios (e.g. a timed event extending a waypoint's life).TimeRemainingis not zero when lifetime expires — The Update loop callsRemoveSelf()the frame the condition is met;TimeRemainingis clamped to zero but the GameObject may persist until the end of that frame. Do not rely onTimeRemaining == 0as a reliable destroy signal; useOnWaypointRemovedonPOIManagerinstead.Reach detection requires
POIManagerto callUpdateDistance()— The reach check runs insideUpdateDistance(), not in the waypoint's own Update loop. If the waypoint is not registered withPOIManager(i.e. created manually),OnWaypointReachedwill never fire.
Last updated