This guide explains how the targeting system works in 5.0.8, including the relationship between TargetingSystem, GridTargetingSystem, GridPositioner2D, and GridTargetingState.
Later versions (6.0) improve targeting using ECS components/systems with signal data emitted through TargetingSignalBus.
Core Targeting Components
| Component | Purpose |
|---|---|
| TargetingSystem | Owns input processing and determines what the player is targeting |
| GridTargetingSystem | Processes grid-specific targeting logic |
| TargetingShapeCast2D | ShapeCast2D used to query objects under the cursor |
| GridPositioner2D | Node2D positioning on the grid (separate from ShapeCast) |
| GridTargetingState | Holds the current targeting state (target cell, object, etc.) |
Input Ownership
TargetingSystem owns all input processing for the building system. It:
- Receives input events (mouse movement, clicks)
- Determines the target position
- Updates GridTargetingState with results
# 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:
# 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
# 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:
# 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:
- World-to-Grid conversion: Converts mouse position to grid coordinates
- ShapeCast queries: Finds objects at the target position
- Grid cell evaluation: Determines what's on each cell (tilemap, objects, etc.)
# 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:
| Issue | Cause | Solution |
|---|---|---|
| Preview flickers | Rapid state changes | Debounce targeting updates |
| Preview disappears | Invalid target computed | Check is_valid flag |
| Preview at wrong position | Grid/world conversion error | Verify cell_size matches |
Debugging Targeting
# 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_placement/test/building/placement/rect4x2_bounds_validation_unit_test.gd (bounds validation)
- Validation semantics: res://addons/grid_placement/test/building/placement/drag_manager_unit_test.gd (targeting updates)
- Scene-driven verification: environment and workflow guides under
v5-0/guides/
Related Guides
Validated By
The targeting system's behavior and integration are validated by the following test suites:
- Targeting Logic: res://addons/grid_placement/test/unit/grid_targeting_system_test.gd — Core unit tests for targeting state updates and math utils.
- Physics Queries: res://addons/grid_placement/test/positioning/targeting/targeting_shape_cast_2d_unit_test.gd — Validates
TargetingShapeCast2Dcollision detection and target promotion logic. - Bounds Validation: res://addons/grid_placement/test/building/placement/rect4x2_bounds_validation_unit_test.gd — Validates grid bounds checking and cell position calculations.
- Integration: res://addons/grid_placement/test/positioning/targeting/targeting_integration_test.gd — Full integration tests for targeting within a scene environment.
Source
docs/v5-0/guides/targeting-flow.md
Plugin docs root:gdscript/plugins/grid_placement_dev/docs