Grid Targeting


Runtime chain references:

Overview of the Grid Targeting subsystem and how cursor positions map to grid coordinates.

This page introduces the Grid Targeting subsystem used by the building workflow and explains how mouse/viewport positions become snapped grid coordinates other systems can use.

What it does

Grid Targeting is responsible for turning pointer input into a stable, snapped target that the building and validation pipelines can consume.

v5.0.0 Architectural Improvement: Clear separation between positioning and targeting:

  • GridPositioner2D: Pure input handling & positioning
  • TargetingShapeCast2D: Dedicated collision detection
  • IndicatorManager: Visual feedback & validation

6.0.0 Target Resolution Enhancement: Smart target resolution through collision objects:

  • Automatic Resolution: Collision objects now resolve to logical target nodes via metadata or Manipulatable components
  • Flexible Targeting: Collision shapes can be on child nodes while targeting parent objects
  • Metadata Support: Use "root_node" metadata to specify target relationships
  • Manipulatable Integration: Automatically detects Manipulatable components for target resolution

Core Responsibilities:

  • Convert viewport/world coordinates to grid-space
  • Apply snapping rules (cell, edge, corner) and epsilon filtering to avoid flicker at boundaries
  • Expose the current target info for other systems (validation, indicators, placement)

See also: Building System Process

Data flow

  1. Input is sampled from the active viewport (mouse/touch position)
  2. GridTargetingSystem computes a target using GridPositioner2D and settings from GridTargetingSettings
  3. Resulting target info is stored in GridTargetingState
  4. Downstream systems consume it:
    • Indicators highlight the hovered cell(s)
    • Placement validation evaluates rules against the target
    • Building system uses it to place or preview objects

Target Resolution (6.0.0+)

In 6.0.0, the Grid Targeting system introduces intelligent target resolution that separates collision detection from logical targeting. When a collision object is detected, the system automatically resolves the appropriate target node using a priority-based search strategy.

Resolution Priority

The system searches for the logical target in this order:

  1. Direct Metadata: Check the collision object for "root_node" metadata
    • Accepts Node2D directly or NodePath to resolve
  2. Manipulatable Siblings: Search sibling nodes for Manipulatable components
    • Uses Manipulatable.root as the target
  3. Manipulatable Children: Search direct children for Manipulatable components
  4. Fallback: Use the collision object itself if no resolution found

Usage Examples

Example 1: Metadata-based resolution

1
2
3
# Collision shape is on a child node, but target should be parent
var collision_shape: CollisionShape2D = $CollisionShape2D
collision_shape.set_meta("root_node", NodePath(".."))  # Target parent node

Example 2: Manipulatable-based resolution

1
2
3
4
5
# Collision area with Manipulatable child
var collision_area: Area2D = $BuildingArea
var manipulatable: Manipulatable = Manipulatable.new()
manipulatable.root = self  # Target is this node
collision_area.add_child(manipulatable)

Benefits

  • Flexible Architecture: Collision shapes can be positioned independently of logical targets
  • Clean Separation: Physics/collision concerns separated from game logic targeting
  • Backward Compatible: Objects without metadata use the collision object as before
  • Performance: Resolution happens only when collision objects change

Position calculation basics

  • World position β†’ grid coords: sampling the world-space cursor and converting to integer cell coordinates based on configured cell size/origin.
  • Snapping modes: center-of-cell, edge-aligned, or corner-snapping depending on your chosen settings.
  • Epsilon filtering: small movement within a cell won’t constantly resignal target changes; this prevents UI flicker.
πŸ’‘
Tip
Use [GridTargetingSettings](../api/GridTargetingSettings/) to fine-tune snapping behavior and epsilon values for your specific game requirements.

Consuming the current target

Most systems don’t compute targeting directlyβ€”they read it from state or receive updates.

  • Poll model/state: read the latest target info from GridTargetingState
  • Event-driven: connect to target update signals emitted by your coordination layer
  • Render-time: indicators query the state and render highlights for hovered cells

Typical consumers:

TargetInformer UI Component (v5.0.0+)

The TargetInformer is a dynamic UI component that displays object information with intelligent priority handling across different game states.

Features

  • Responsive to Targeting: Shows info immediately when hovering over objects via GridTargetingState.target_changed signal
  • Manipulation Priority: Automatically switches to show manipulated objects when manipulation is active
  • Building Preview: Displays info for building preview objects during placement
  • Graceful Fallbacks: Handles missing settings and null targets without errors

Priority System

The TargetInformer implements a three-tier priority system:

PriorityContextSignal SourceUse Case
1. HighestManipulationManipulationState.active_target_node_changedShows info for objects being moved/demolished
2. MiddleBuildingBuildingState.preview_changedShows info for building preview objects
3. LowestTargetingGridTargetingState.target_changedShows info for hovered objects (passive targeting)

Example Behavior:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Scenario 1: Just hovering over objects
# Player moves mouse over smithy β†’ TargetInformer shows "Smithy" info

# Scenario 2: Start manipulation
# Player selects smithy for move β†’ TargetInformer switches to show manipulation info

# Scenario 3: Hover another object while manipulating
# Player hovers over house while still moving smithy
# TargetInformer STAYS on smithy (manipulation has priority)

# Scenario 4: End manipulation
# Player completes move β†’ TargetInformer returns to showing hovered object

Setup

The TargetInformer connects automatically to all required signals when you call resolve_gb_dependencies():

1
2
3
4
5
6
7
8
var informer = TargetInformer.new()
informer.info_parent = Control.new()  # Container for info labels
add_child(informer)
informer.add_child(informer.info_parent)

# Connect to composition container
informer.resolve_gb_dependencies(composition_container)
# Now responds to targeting, manipulation, and building state changes

Configuration

The TargetInformer uses TargetInfoSettings for display formatting:

1
2
3
4
5
6
# These settings are typically configured in your GBSettings resource
target_info.position_format = "Position: (%s, %s)"
target_info.position_decimals = 2

# The TargetInformer automatically uses these settings when available
# Falls back to default formatting if settings are null

Integration with Info Mode

The TargetInformer works seamlessly with the Info mode toggle:

1
2
3
4
5
6
7
# When mode changes to INFO
mode_state.current = GBEnums.Mode.INFO
# TargetInformer becomes visible (if mode_state is connected)

# When mode changes to OFF
mode_state.current = GBEnums.Mode.OFF  
# TargetInformer hides automatically

Custom Object Names

Override _to_string() on your object nodes to customize the display name:

1
2
3
# On your placeable object script
func _to_string() -> String:
	return "Smithy (Level 2)"  # Shows in TargetInformer
πŸ’‘
Best Practice
Connect the TargetInformer early in your scene setup (usually in `_ready()`) so it's ready to respond to targeting changes immediately when the game starts.

Configuration

Use GridTargetingSettings to control:

  • Cell size and origin
  • Snapping mode and tolerance (epsilon)
  • Edge/corner behavior for non-centered snapping

These settings are typically provided via your composition container and shared with the GridPositioner2D.

Debugging and validation

  • Visualize: enable an indicator layer to color the active cell and neighbors.
  • Inspect text: add GridTargetingDebugText to render current cell, world pos, and snap mode.
  • Validate: run your rule set through PlacementValidator using the current target to confirm expected acceptance/rejection.

Visibility Behavior

The Grid Targeting system controls when the positioner is visible based on multiple interaction factors:

Basic Visibility Rules

  1. Mouse Input Enabled: When enable_mouse_input is true, positioner follows mouse and respects all visibility settings
  2. Mouse Input Disabled: When enable_mouse_input is false, positioner operates without mouse interaction and ignores mouse-specific visibility rules

Hide on Handled Behavior

The hide_on_handled setting provides smart visibility management:

Mouse Inputhide_on_handledUI Element HoveredPositioner Visible
βœ… Enabledβœ… true❌ Noβœ… Yes
βœ… Enabledβœ… trueβœ… Yes❌ No (hidden)
βœ… Enabled❌ false❌ Noβœ… Yes
βœ… Enabled❌ falseβœ… Yesβœ… Yes (visible)
❌ Disabledβœ… trueAnyβœ… Yes (ignores UI)
❌ Disabled❌ falseAnyβœ… Yes

Practical Examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Example 1: Mouse-driven with auto-hide
settings.enable_mouse_input = true
settings.hide_on_handled = true
# Result: Positioner follows mouse, hides when hovering UI elements

# Example 2: Keyboard-only mode
settings.enable_mouse_input = false
settings.hide_on_handled = true  # This setting is ignored
# Result: Positioner stays visible, controlled by keyboard/code

# Example 3: Always visible mode
settings.enable_mouse_input = true
settings.hide_on_handled = false
# Result: Positioner follows mouse, always visible even over UI