Grid Placement

Targeting Flow (5.0.2)

How the targeting system works in GridBuilding 5.0.2: input ownership, TargetingShapeCast2D, GridPositioner2D, GridTargetingState, and processing flow.

This guide explains how the targeting system works in 5.0.2, including the relationship between TargetingSystem, GridTargetingSystem, GridPositioner2D, and GridTargetingState.

Core Targeting Components

ComponentPurpose
TargetingSystemOwns input processing and determines what the player is targeting
GridTargetingSystemProcesses grid-specific targeting logic
TargetingShapeCast2DShapeCast2D used to query objects under the cursor
GridPositioner2DNode2D positioning on the grid (separate from ShapeCast)
GridTargetingStateHolds the current targeting state (target cell, object, etc.)

Input Ownership

TargetingSystem owns all input processing for the building system. It:

  1. Receives input events (mouse movement, clicks)
  2. Determines the target position
  3. Updates GridTargetingState with results
1
2
3
4
# TargetingSystem processes input and updates state
func _input(event: InputEvent) -> void:
    if event is InputEventMouseMotion:
        _update_target_from_mouse(event.position)

The GridTargetingSystem then processes this targeting data to determine:

  • Which grid cell is targeted
  • What object (if any) is at that position
  • Whether placement is valid

TargetingShapeCast2D: ShapeCast2D

TargetingShapeCast2D is a ShapeCast2D node that queries for objects under the cursor:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# TargetingShapeCast2D uses ShapeCast2D to detect objects
@onready var shape_cast: ShapeCast2D = $ShapeCast2D

func _physics_process(delta: float) -> void:
    # Update shape cast parameters
    shape_cast.position = global_mouse_position
    shape_cast.force_shapecast_update()
    
    # Get collision results
    var colliders = shape_cast.get_collision_count()
    for i in range(colliders):
        var collider = shape_cast.get_collision_object(i)
        # Process collided object

Configuration

1
2
3
4
5
6
# Configure TargetingShapeCast2D in editor or code
shape_cast.shape = RectangleShape2D.new()  # Query shape
shape_cast.target_position = Vector2.ZERO
shape_cast.collide_with_areas = true
shape_cast.collide_with_bodies = true
shape_cast.max_results = 10

GridPositioner2D: Node Positioning

GridPositioner2D is a separate Node2D component used for grid positioning. It is not the ShapeCast - that’s handled by TargetingShapeCast2D.

GridTargetingState

The GridTargetingState holds all targeting information:

1
2
3
4
5
6
# GridTargetingState contains:
var target_cell: Vector2i           # Grid cell being targeted
var target_position: Vector2          # World position
var target_object: Node2D             # Object at target (if any)
var is_valid: bool                    # Whether target is valid
var target_placeable: Placeable       # Placeable being targeted (if any)

Processing Flow

Input Event (Mouse)
    โ†“
GridTargetingSystem processes input
    โ†“
TargetingShapeCast2D queries scene for colliders
    โ†“
GridPositioner2D positions preview node on grid
    โ†“
GridTargetingState updated
    โ†“
Preview/Indicator system reacts to state

Targeting in 2D

The 2D targeting system uses:

  1. World-to-Grid conversion: Converts mouse position to grid coordinates
  2. ShapeCast queries: Finds objects at the target position
  3. Grid cell evaluation: Determines what’s on each cell (tilemap, objects, etc.)
1
2
3
4
5
# Convert world position to grid cell
var grid_position := GridMathUtils.world_to_grid(world_position, cell_size)

# Check what's on that cell
var cell_content = grid_system.get_cell_content(grid_position)

Preview Stability

Preview stability depends on GridTargetingState remaining consistent. Common issues:

IssueCauseSolution
Preview flickersRapid state changesDebounce targeting updates
Preview disappearsInvalid target computedCheck is_valid flag
Preview at wrong positionGrid/world conversion errorVerify cell_size matches

Debugging Targeting

1
2
3
4
5
6
7
# Debug targeting state
func _debug_targeting() -> void:
    var state = grid_targeting_state
    print(\"Target cell: \", state.target_cell)
    print(\"Target position: \", state.target_position)
    print(\"Is valid: \", state.is_valid)
    print(\"Target object: \", state.target_object)

Cross Test Validation

Targeting behavior is cross-validated across unit and integration suites to ensure the same targeting state and collision semantics in isolated and scene-driven tests.

  • Unit validation: res://addons/grid_building/test/building/placement/rect4x2_bounds_validation_unit_test.gd (bounds validation)
  • Validation semantics: res://addons/grid_building/test/building/placement/drag_manager_unit_test.gd (targeting updates)
  • Scene-driven verification: environment and workflow guides under v5-0/guides/

Validated By

The targeting system’s behavior and integration are validated by the following test suites:

  • Targeting Logic: res://addons/grid_building/test/unit/grid_targeting_system_test.gd โ€” Core unit tests for targeting state updates and math utils.
  • Physics Queries: res://addons/grid_building/test/positioning/targeting/targeting_shape_cast_2d_unit_test.gd โ€” Validates TargetingShapeCast2D collision detection and target promotion logic.
  • Bounds Validation: res://addons/grid_building/test/building/placement/rect4x2_bounds_validation_unit_test.gd โ€” Validates grid bounds checking and cell position calculations.
  • Integration: res://addons/grid_building/test/positioning/targeting/targeting_integration_test.gd โ€” Full integration tests for targeting within a scene environment.