Development ⚠️ GridPlacement 6.0 documentation is in active development. APIs and content may change, and the site may be temporarily unstable.

Grid Targeting


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