This guide explains how to capture tile coordinates such as Vector2i(5, 3) when an object is placed with Grid Placement.
This is useful for:
- isometric pathfinding and movement
- occupancy maps
- save/load of grid-aligned gameplay state
- associating placed objects with one or more covered cells
Version note: This guide is for Grid Placement 6.0.0.
Accessing the Current Tile at Runtime
To get the tile coordinate currently hovered by the targeting system, read the active targeting state and convert the GridPositioner2D world position into a map cell.
# Inside a node that has been injected with the container.
func _process(_delta: float) -> void:
var targeting_state: GridTargetingState = container.get_states().targeting
var target_map: TileMapLayer = targeting_state.target_map
var positioner: Node2D = targeting_state.positioner
if positioner != null and target_map != null:
var current_tile: Vector2i = PlacementPositioning2DUtils.get_tile_from_global_position(
positioner.global_position,
target_map
)
print("Hovering over tile: ", current_tile)
Capturing Positions from Placement Results
The most common time to capture a tile position is after an object is successfully placed.
For new code, listen to PlacementState.action_performed. The payload is PlacementActionData, and success/failure lives on data.report.
func _ready() -> void:
var placement_state: PlacementState = container.get_building_state()
placement_state.action_performed.connect(_on_action_performed)
func _on_action_performed(data: PlacementActionData) -> void:
if data == null or data.report == null:
return
if not data.report.is_successful():
return
var placed: Node = data.report.placed
var map: TileMapLayer = container.get_states().targeting.target_map
if placed == null or map == null:
return
var tile: Vector2i = PlacementPositioning2DUtils.get_tile_from_global_position(
placed.global_position,
map
)
print("Object placed at: ", tile)
Do not read data.action, data.status, or data.placed; those are not the 6.0 PlacementActionData API. Read the PlacementReport stored at data.report.
Capturing Terrain Paint Cells
Terrain paint signals carry the target cell directly.
func _ready() -> void:
var placement_state: PlacementState = container.get_building_state()
placement_state.post_terrain_paint.connect(_on_post_terrain_paint)
func _on_post_terrain_paint(data: TerrainPaintData) -> void:
print("Terrain %s painted at cell %s" % [data.terrain_name, data.target_cell])
For multi-cell brushes, use the terrain paint/removal data exposed by the terrain workflow you are consuming. Do not infer a whole brush result from the cursor cell alone.
Best Object Hook: pre_instance_added
PlacementState.pre_instance_added is emitted after the scene is instantiated but before it is added to the tree. This is the best place to stamp tile data onto the placed instance.
func _ready() -> void:
var placement_state: PlacementState = container.get_building_state()
placement_state.pre_instance_added.connect(_on_pre_instance_added)
func _on_pre_instance_added(node: Node2D) -> void:
var map: TileMapLayer = container.get_states().targeting.target_map
if map == null:
return
var tile: Vector2i = PlacementPositioning2DUtils.get_tile_from_global_position(
node.global_position,
map
)
node.set_meta("anchor_tile", tile)
This works well when your save system needs a stable anchor cell for each placed object.
Multi-Tile Footprint Pattern
If the placed object covers multiple cells, store an array of Vector2i values.
Option A: capture rule/indicator tiles
If your placement rules already generate the exact footprint you care about, use those tile positions.
func get_rule_tiles(rule: TileCheckRule) -> Array[Vector2i]:
return rule.get_tile_positions()
Option B: derive from a rectangular footprint
func get_rect_tiles(map: TileMapLayer, center_world: Vector2, size_world: Vector2) -> Array[Vector2i]:
return CollisionUtilities.get_rect_tile_positions(map, center_world, size_world)
Use collision/rule-derived footprints for production buildings when possible; a visual rectangle can include transparent pixels or decorative overhangs.
Save/Load Recommendation
PlaceableInstance.save() stores the instance name, transform, and placeable reference. It does not automatically store tile positions. If tile coordinates matter to your game state, merge them into your own save payload.
func save_with_tiles(instance: PlaceableInstance) -> Dictionary:
var data := instance.save(true)
var parent := instance.get_parent()
if parent != null and parent.has_meta("anchor_tile"):
data["anchor_tile"] = var_to_str(parent.get_meta("anchor_tile"))
return data
On load, restore your custom anchor_tile after PlaceableInstance.instance_from_save() creates the object.
Related Guides
Source
docs/v6-0/guides/capturing-tile-positions.md
Plugin docs root:gdscript/plugins/grid_placement_dev/docs