Grid Placement supports two main 2D placement surfaces:
- Terrain painting into
TileMapLayercells. - Scene object placement for instantiating
PackedScenenodes.
Use this guide when you are deciding whether something in your game should be a tile or a placed object.
Version note: This guide is for Grid Placement 6.0.0. The beginner path is 2D
TileMapLayerplacement.
For the release-facing support boundary, shipped demo list, brush commit semantics, and terrain brush cell cap, see 6.0 Surface and Brush Reference.
The Decision Rule
| If your thing… | Use | Why |
|---|---|---|
| Visually connects to neighbors, such as roads, floors, pipes, fences, hedges, or walls | Terrain tiles | Godot terrain/tileset workflows handle connected visuals well. |
| Is a standalone entity, such as a building, lamp, crate, or NPC | Scene objects | Each instance gets its own node and state. |
| Needs per-instance scripts, selection, movement, rotation, flip, or object-level removal | Scene objects | Terrain cells have no per-cell scene identity. |
| Is purely visual plus static collision | Terrain tiles | TileMapLayer collision is lower overhead than many scene instances. |
| Needs the full object placement rules pipeline | Scene objects | Object rules work on scene instances, footprints, and placeable resources. |
| Needs free-form placement without grid snapping | Scene objects | Terrain tiles are cell-aligned. |
Terrain Tiles
Terrain tiles are anonymous paint in a TileMapLayer.
Use terrain for content where neighboring cells matter more than per-piece identity:
- roads
- floors
- hedges
- fences
- walls
- connected ground areas
Terrain tiles are excellent for visuals and static collision, but they do not become separate scene instances. A painted cell has no script, no _process(), no per-instance node identity, and no object-level Manipulatable component.
Scene Objects
Scene objects are real nodes instantiated into the scene tree.
Use scene objects when the placed thing needs:
- a script
- individual state
- selection
- movement
- rotation or flipping
- object-level removal
- per-instance save/load data
- the full object placement rules pipeline
Buildings, lamps, crates, NPCs, and interactable props usually belong here.
The Fence Middle Ground
Fences are the classic confusing case.
If the fence is mostly visual/static, make it terrain. Paint fence/wall tiles into a TileMapLayer and let your TileSet handle the connected appearance.
If the fence also needs gameplay interaction, use a hybrid pattern:
TileMapLayer (Fence visuals + static collision)
Interaction overlay or per-cell dictionary (game-owned behavior)
The plugin owns terrain placement. Your game owns extra behavior such as opening a gate, tracking durability, showing state-specific visuals, or handling click selection.
Hybrid Pattern Example
For many collision-based interactions, no overlay is required. The TileMapLayer already participates in physics.
A game-side interaction can:
- Detect the
TileMapLayer. - Convert the world position to a cell with
tile_map.local_to_map(position). - Query the tile with
tile_map.get_cell_source_id(cell)or terrain data. - Track per-cell gameplay state in a game-owned dictionary.
- Erase or replace the tile when your game decides the cell should change.
Use an overlay only when you need per-cell click events, per-segment visual effects, or scripts that run every frame.
Terrain hooks make this easier:
pre_terrain_paint— inspect or veto a planned paint before it commits.post_terrain_paint— react after paint lands.pre_terrain_demolish— veto terrain removal.post_terrain_demolish/post_terrain_removed— react after removal.
Terrain Rules vs Object Rules
Objects use the object placement rules pipeline because each object is an instance the validator can reason about.
Terrain uses terrain validation, paint gates, and terrain hooks instead. This is intentional:
- A tile cell has no scene instance.
- There is no
Manipulatabletarget for an object rule to inspect. - Many object rules assume an object footprint, collision body, cost rule, or instance identity.
For game-specific terrain checks, connect to pre_terrain_paint or pre_terrain_demolish and veto the operation when needed.
Examples:
- Block painting while a game mode is locked.
- Require a resource or stamina cost to paint terrain.
- Reject terrain in protected zones.
- Prevent terrain removal under a placed interactable.
- Spawn or update overlays after terrain changes.
Brush Shape Rule
Brush shapes are split by whether the shape makes sense for anonymous terrain cells or for separate scene objects.
| Brush Shape | Terrain | Objects | Why |
|---|---|---|---|
SINGLE |
Yes | Yes | One cell / one instance. |
LINE |
Yes | Opt-in | Terrain: fences, roads, pipes. Objects: repeated props such as lamps, posts, crates. |
RECTANGLE_FILL |
Yes | No | Filling an area with terrain makes sense; filling with separate nodes rarely does. |
RECTANGLE_OUTLINE |
Yes | No | Fence/wall perimeters usually belong in terrain. |
FLOOD_FILL |
Yes | No | Flood-fill is a terrain-region operation. |
Object LINE placement is opt-in per category/profile so ordinary objects remain single-placement by default.
For exact press/drag/release and flood-fill second-confirm semantics, see 6.0 Surface and Brush Reference.
Grid Type Compatibility
| Grid Type | Terrain Tiles | Brush Shapes | Notes |
|---|---|---|---|
| Square / top-down | Supported | Supported terrain shapes | Recommended beginner path. |
| Isometric 2D | Supported through 2D TileMapLayer workflows |
Supported in cell space | Verify masks, transforms, and visuals against your project. |
| Hexagonal 2D | Supported advanced 2D terrain path | Supported terrain shapes | 6.0 proof covers the shipped hex tileset; still verify masks, transforms, and visuals in your project. |
Comparison Table
| Characteristic | Terrain Tiles | Scene Objects |
|---|---|---|
| Placement target | TileMapLayer cell |
Scene tree under objects_parent |
| Identity | Anonymous paint | Full Node with scripts, signals, properties |
| Auto-tiling / connected visuals | TileSet-owned | Game-owned |
| Per-instance state | Game-owned dictionary or overlay required | Built into the instance |
| Select / move / rotate | No object identity | Via object manipulation services |
| Terrain removal | Through terrain removal hooks | N/A |
| Object removal | N/A | Via the host / manipulation path |
| Collision | Baked into TileMapLayer |
Per-body collision shape |
| Rules pipeline | Terrain validation / paint gates + hooks | Object placement validator |
| Cost / resource spend | Game-owned through terrain hooks unless you build a terrain-specific bridge | Via object cost/refund path |
| Save / load | Save as tilemap state or game-owned per-cell data | Save per placed object / instance |
| Brush shapes | SINGLE, LINE, RECTANGLE_FILL, RECTANGLE_OUTLINE, FLOOD_FILL |
SINGLE; LINE opt-in per category |
| Preview | TerrainPreview ghost layer |
Scene instance ghost |
| Pre-placement veto | pre_terrain_paint |
Placement rule failure |
Practical Guidance
Use terrain tiles when
- The thing forms connected lines or areas.
- The thing's appearance depends on neighbors.
- You do not need per-piece object identity.
- You want maximum performance.
- Static collision is enough.
Use scene objects when
- Each instance needs scripts, signals, or properties.
- The player can select, move, rotate, flip, or remove the individual piece.
- The thing is a standalone entity.
- You need the object placement rule pipeline.
Use the hybrid pattern when
- The thing visually connects to neighbors and needs some per-piece interaction.
- Paint terrain for connected visuals + static collision.
- Add a game-owned overlay node or per-cell state only for the gameplay part.
Related Guides
- Placement Workflow — end-to-end object and terrain placement flow.
- 6.0 Surface and Brush Reference — support boundary, brush matrix, and terrain brush cell cap.
- Placement Rules — object validation rules.
- Refund on Demolish — object refunding.
- Architecture Overview — how the core runtime fits together.
Source
docs/v6-0/guides/choosing-terrain-vs-objects.md
Plugin docs root:gdscript/plugins/grid_placement_dev/docs