Chris' Tutorials
Docs/Grid Placement

Grid Placement v6.0

Placement Workflow

Understand the end-to-end placement flow for objects and terrain.

StatusDraft
Versionv6.0
UpdatedDevelopment docs generated from GDScript source

This is unreleased documentation in active development. APIs, class names, and behavior may change before the final release.

Draft — Unreleased:This page is in active development. APIs, class names, and behavior may change before the release is finalized. Use it as a preview of what's coming — not as a stable integration target.

This guide explains what happens after a player selects something to place.

Version note: This guide is for Grid Placement 6.0.0. The supported buyer-facing path is 2D placement on TileMapLayer. New scenes should use GridPlacementHost and PlacementSession as the main runtime model; PlacementSystem remains in the codebase as part of the compatibility/service path, but the host/session model is the recommended mental model.

For the release-support boundary and a compact brush mode matrix, see 6.0 Surface and Brush Reference.


The Short Version

Object placement and terrain painting share the same basic loop:

Player selects object or terrain
-> session stores the selection
-> GridPositioner2D updates the target cell
-> preview/validation updates while the cursor moves
-> player confirms
-> rules run one final time
-> object is added or terrain cells are painted
-> success/failure is reported through placement state/action data

Nothing should be added to the real world until the placement action succeeds.


Object Placement

Object placement instantiates a PackedScene from a ScenePlacementEntry.

1. Selection

A UI such as PlaceableSelectionUI selects a ScenePlacementEntry for the active PlacementSession.

The entry defines the object scene and can also provide profiles/rules. PlacementProfile resources are the reusable category/settings surface for things like supported tools and category behavior.

2. Preview

After an object is selected, the plugin creates or updates a preview object. The preview follows the target cell reported by GridPositioner2D.

The preview is not the final placed object. Save/load code should ignore preview/manipulation copies and only persist real placed objects.

3. Validation

Validation runs while the cursor moves and again before final placement.

Common rule checks include:

  • Bounds checks against the target TileMapLayer.
  • Collision checks against existing objects.
  • Tile-validity checks.
  • Optional gameplay rules such as material/cost checks.
  • Entry/profile-specific rules.

Rules should report clear failure reasons. UI should display the current result instead of duplicating validation logic.

4. Commit

When the player confirms placement:

  1. The active placement is validated again.
  2. The final scene instance is created.
  3. PlacementState.pre_instance_added can run before the node is added to the scene tree.
  4. The object is added under PlacementLevelContext.objects_parent.
  5. Success/failure is reported through placement state/action data.
  6. Preview state is cleaned up.

If objects_parent is missing, the plugin has nowhere to put the final instance.


Object LINE Placement

Some objects can support LINE placement through their profile/entry-supported tools.

The flow is:

press/hold to start line
-> drag across cells
-> release to attempt placement along the generated line
-> each cell is validated and placed or skipped

Use LINE for repeatable objects such as fences, walls, paths, or decorations that are meant to be placed in a row.

Do not enable LINE for objects that need custom one-off setup unless you have tested the partial-success behavior.


Terrain Painting

Terrain painting mutates cells on a TileMapLayer. It uses terrain entries/palettes and the active session's selected terrain.

Add one TerrainPreview node under the same injected scene scope as the host and target map. Do not manually add TerrainPreviewLayer, TerrainInvalidPreviewLayer, or preview groups. TerrainPreview owns that runtime plumbing.

SINGLE

SINGLE paints one cell on confirm.

hover cell
-> preview shows target cell
-> click/confirm
-> one real TileMapLayer cell is painted

LINE / RECTANGLE_FILL / RECTANGLE_OUTLINE

These shapes use a press-hold-drag-release flow.

press at cell A
-> drag to cell B
-> preview shows generated cells
-> release
-> generated cells are painted after validation

The real TileMapLayer should not change during the drag preview.

The release decision is the hybrid model: ghost preview updates during hover/drag, but the real target TileMapLayer recalculates terrain connections only at commit. See Terrain Recalculation Timing.

FLOOD_FILL

FLOOD_FILL uses an anchor/commit flow so the player can see the region before applying it.

hover region
-> first click anchors the flood-fill preview
-> second click commits the anchored cells
-> cancel clears the pending region without painting

Flood fill is intentionally more deliberate because it can affect many cells.

Large terrain brush operations are capped by PlacementSettings.max_terrain_brush_cells (default 4096, runtime ceiling 16384). If the generated cell set exceeds the cap, reduce the drag/region size or raise the setting within the supported ceiling.


Cancel and Cleanup

Pending placement should cancel without mutating the real world when the user:

  • Cancels placement input.
  • Changes selected object/terrain.
  • Switches away from placement mode.
  • Switches between object placement and terrain painting.
  • Exits the scene or unregisters the session/controller.

After canceling, previews should clear and the real placed objects/terrain should remain unchanged.


Manipulation

Manipulation works on already placed objects.

To make an object manipulatable:

  1. Add a Manipulatable component to the placed object scene.
  2. Configure ManipulatableSettings for move, rotate, flip, and demolish support.
  3. Make sure targeting collision layers allow the object to be detected.

Move/rotate/flip should operate through manipulation services and state, not through one-off UI scripts that directly mutate objects and bypass validation.


Where Side Effects Belong

Keep side effects after successful validation.

Good places for side effects:

  • Rule apply() paths after a successful placement.
  • Placement success/action signals.
  • pre_instance_added when configuring a new instance before _ready().
  • Refund hooks during demolish.

Avoid spending inventory, saving state, or changing game progression just because a preview is valid. A valid preview is not a committed placement.


Common Pitfalls

  • Missing target_map: the plugin cannot convert cursor position into map cells.
  • Missing objects_parent: object placement has nowhere to add final instances.
  • UI eats input: full-screen Control nodes can block placement clicks.
  • Collision layer vs mask confusion: the target must be on a layer the shapecast mask can see.
  • Saving previews: previews/manipulation copies are temporary and should not be persisted.
  • Duplicating validation in UI: the placement rules/state should be the source of truth.

What Plugin Users Should Remember

  • Selection lives in the active session.
  • GridPlacementHost owns runtime dispatch.
  • PlacementLevelContext connects the plugin to your level.
  • A preview is not a placed object.
  • Rules run before world mutation.
  • Terrain previews should not paint the real TileMapLayer until commit.

Related Guides


Source

docs/v6-0/guides/placement-workflow.md

Plugin docs root:gdscript/plugins/grid_placement_dev/docs