Targeting Flow
This guide explains how targeting works in 5.0.8, including the relationship between GridTargetingSystem, GridPositioner2D, TargetingShapeCast2D, and GridTargetingState.
Version note: This guide is validated for Grid Building 5.0.8.
In the current 5.0.8 runtime, GridPositioner2D owns the main cursor/grid input handling. It:
- Receives input events.
- Converts screen coordinates into world coordinates.
- Converts world coordinates into target tiles.
- Moves itself to the active tile center.
- Updates visibility based on mode/settings/input state.
| |
GridTargetingSystem still matters, but it is not the node that directly owns mouse-follow behavior.
TargetingShapeCast2D
TargetingShapeCast2D is the collision-query layer. Its job is to update GridTargetingState.target from the current shapecast result.
| |
- If
GridTargetingState.is_manual_targeting_activeis true, automatic target updates are skipped. - When a collider is found, the raw collider may be promoted to a targetable root
Area2D. - When no collider is found, the current target is cleared.
GridPositioner2D
GridPositioner2D is responsible for:
- Mouse movement.
- Keyboard tile movement.
- Recenter behavior.
- Visibility behavior.
- Assigning itself into
GridTargetingState.positioner.
It does not own:
- Shapecast collision targeting.
- Rotation/flip behavior.
- Manipulation transforms.
5.0.4 update: _on_mode_changed now has an explicit -> void return type (fixed parse warning).
Target Highlighting
TargetHighlighter is the visual feedback layer for targeting. It does not move the cursor or decide which object is targetable. Its job is to read the current targeting result and highlight the target so players can see what the placement or manipulation flow is acting on.
Use it when you want feedback for:
- Build mode selection.
- Move-mode target hover.
- Demolish or inspect previews.
Practical guidance:
- Keep highlighting separate from cursor movement so targeting stays easy to reason about.
- Wire the highlighter as a visual/UI concern, not as the source of targeting truth.
- If highlighting looks wrong, check the targetable object setup and the visual settings used by the highlighter.
5.0.4 update: Fixed null dereference crashes in TargetHighlighter.current_target setter and _on_started(). These now guard against null before accessing properties.
GridTargetingState
The targeting state is the shared contract other systems consume. In practice it includes references such as:
| |
Processing Flow
| |
Recenter and Visibility Behavior
GridPositioner2D also owns several user-visible behaviors:
- Recenter on enable.
- Manual recenter action.
- Visibility changes when mode changes.
- Hide/show behavior based on input and targeting settings.
- OFF-mode gating via
remain_active_in_off_mode.
Essential Setup for Plugin Users
If targeting looks broken, check these first:
GBLevelContext.target_mapis assigned.GridPositioner2Dwas injected successfully.TargetingShapeCast2Dwas injected successfully.- Your shapecast collision mask matches the targetable layers.
- The mode allows the positioner to stay active/visible.
- Your UI is not consuming the input path you expect.
Collision Layer vs Collision Mask for Targeting
TargetingShapeCast2D uses Godot’s collision system to detect objects:
| Property | What it means | Used by Shapecast2D to… |
|---|---|---|
collision_mask on TargetingShapeCast2D | Which layers to check | Find objects |
collision_layer on target objects | Which layers the object is on | Must overlap with shapecast mask to be detected |
How detection works:
TargetingShapeCast2D.collision_mask(e.g.,10) determines which physics layers the shapecast looks for- Placed objects are detected if their
collision_layerincludes that same layer (e.g., layer 10)
For placed objects to be detected by TargetingShapeCast2D:
- Set
TargetingShapeCast2D.collision_maskto your targeting layer (e.g.,10) - Set ONLY the root scene node’s
collision_layerto include that layer (e.g.,1, 10) - Child physics bodies (StaticBody2D, Area2D) should NOT have the targeting layer
IMPORTANT: Only the scene root should own the targeting layer. If multiple nodes in the hierarchy have the targeting layer, the shapecast may detect the wrong one (e.g., a child collider instead of the intended root target).
| |
When the shapecast detects the scene, it will find whichever node is closest/first - if a child has the targeting layer, the shapecast may target that child instead of the root you intended.
| |
Common mistake: Setting only
collision_mask = 10on placed objects. This allows the object to detect layer 10 things, but Shapecast2D cannot find the object because the object’scollision_layerdoesn’t include 10.
CRITICAL: Shapecast Collision Flags
TargetingShapeCast2D will NOT detect any objects unless you set the collision flags. Godot ShapeCast2D defaults to collide_with_areas = false and collide_with_bodies = false.
In your GridPositioner scene (e.g., grid_positioner_stack_2d.tscn), set BOTH:
| |
If only collide_with_areas = true is set, the shapecast will detect Area2D nodes but NOT StaticBody2D nodes. Most placed game objects use StaticBody2D, so you need collide_with_bodies = true as well.
Quick diagnostic: Add this to your scene and check the Output panel when running:
| |
If either shows false, that type of object will not be detected.
Preview Stability and Manual Targeting
During active building/manipulation flows:
TargetingShapeCast2Dintentionally stops auto-updating when manual targeting is active.- Collision exclusions can be applied so previews do not block their own placement validation.
- Manipulation visuals are handled by
ManipulationParent, not the positioner.
Common Targeting Problems
- Positioner never appears
- Check mode/state injection.
- Check targeting settings visibility rules.
- Target object never updates / Move/Demolish/Highlight not working
- FIRST: Check collide_with_areas and collide_with_bodies - see “CRITICAL: Shapecast Collision Flags” above. This is the most common cause.
- Check
TargetingShapeCast2D.collision_maskmatches your targeting layer. - Check that the targetable object has
collision_layerincluding that same layer. - Enable
TargetingShapeCast2D.debug_log_collisions = trueto see what the shapecast is detecting.
- Cursor does not move
- Check
GridPositioner2Dinput settings and target map wiring.
- Check
- Move/build targeting acts frozen
- Check whether manual targeting is intentionally active.