Historical 5.x guide. This page describes a legacy API and is not current integration guidance. For new projects, start with Getting Started.
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 eventis 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 iin range(colliders):
var collider= shape_cast.get_collision_object(i)
# Process collided objectConfiguration
# 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= 10GridPositioner2D: 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 stateTargeting 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.
Using this in a game?
Grid Placement v6.3.0 — full source, playable demos, commercial license
The guide above is the same setup the shipped demos use. Try the build in your browser before you buy it.