Targeting Flow (5.0.3)

This guide explains how targeting works in 5.0.3, including the relationship between GridTargetingSystem, GridPositioner2D, TargetingShapeCast2D, and GridTargetingState.

Core Targeting Components

ComponentPurpose
GridTargetingSystemCentral targeting-side coordinator for targeting state/settings/path manager validation
GridPositioner2DOwns mouse/keyboard input for cursor-to-grid positioning
TargetingShapeCast2DShapeCast2D that updates GridTargetingState.target from collisions
GridTargetingStateHolds target object, tilemap references, positioner, target map, and manual targeting flags

Input Ownership

In the current 5.0.3 runtime, GridPositioner2D owns the main cursor/grid input handling. It:

  1. receives input events
  2. converts screen coordinates into world coordinates
  3. converts world coordinates into target tiles
  4. moves itself to the active tile center
  5. updates visibility based on mode/settings/input state
1
2
3
func _input(event: InputEvent) -> void:
    if event is InputEventMouseMotion:
        _handle_mouse_motion_event(event, _mode_state.current)

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.

1
2
func _physics_process(_delta: float) -> void:
    update_target()
  • if GridTargetingState.is_manual_targeting_active is 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

GridTargetingState

The targeting state is the shared contract other systems consume. In practice it includes references such as:

1
2
3
4
5
6
var target: Node2D
var target_map: TileMapLayer
var maps: Array[TileMapLayer]
var positioner: Node2D
var is_manual_targeting_active: bool
var collision_exclusions: Array[Node]

Processing Flow

1
2
3
4
5
6
7
8
9
Mouse / keyboard input
    ->
GridPositioner2D moves to tile center
    ->
TargetingShapeCast2D queries collisions
    ->
GridTargetingState.target and positioner references are updated
    ->
Building / manipulation / UI systems consume targeting state

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_map is assigned
  • GridPositioner2D was injected successfully
  • TargetingShapeCast2D was 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

Preview stability and manual targeting

During active building/manipulation flows:

  • TargetingShapeCast2D intentionally 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
    • check TargetingShapeCast2D.collision_mask
    • check that the targetable object is actually collidable
  • Cursor does not move
    • check GridPositioner2D input settings and target map wiring
  • Move/build targeting acts frozen
    • check whether manual targeting is intentionally active