Chris' Tutorials
Docs/Grid Placement

Grid Placement v6.0

Placement Rules

Configure runtime placement validation rules and understand why placement succeeds or fails.

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.

Placement rules decide whether a placement action is allowed.

Use this guide when you want to understand why placement succeeds/fails, where to put rules, and how rules connect to object placement, terrain, inventory costs, and manipulation.

Version note: This guide is for Grid Placement 6.0.0. For custom rule authoring details, see Custom Placement Rules. For startup/readiness checks, see Validation: Configuration.


What a Rule Does

A placement rule is a Resource that participates in the runtime placement loop.

A rule can:

  • Inspect the active placement target.
  • Return pass/fail validation with a user-facing issue.
  • Mark one or more indicators invalid.
  • Run side effects after a successful placement, such as spending materials.

Rules are not just editor settings. They run while the player is trying to place something.


Beginner Mental Model

selected object/terrain
→ preview appears
→ rules validate the current target
→ UI shows valid/invalid feedback
→ player confirms
→ rules validate again
→ successful placement mutates the world

A valid preview is not a completed placement. Spend inventory, save state, achievements, and other irreversible effects should happen only after successful placement.


Rule Types

Type Use for
PlacementRule General rules that do not need per-tile indicators, such as inventory/material checks.
TileCheckRule Rules that depend on tile/indicator positions, such as bounds, collisions, or tile custom data.
RuleResult The pass/fail result returned by rule validation.

If your rule needs to know which cells an object covers, it probably belongs on TileCheckRule. If your rule checks player state, inventory, unlocks, or quest state, it can usually extend PlacementRule directly.


Where Rules Come From

Grid Placement 6.0 combines rules from multiple places.

Source Scope Use for
PlacementSettings.placement_rules Global/default rules Rules every placement should usually follow, such as bounds or collision checks.
PlacementProfile.placement_rules Category/profile rules Shared behavior for groups such as buildings, fences, decorations, or doodads.
ScenePlacementEntry.placement_rules One object entry Special rules for one object, such as "must be near water".

The effective rule set is resolved when the object/terrain workflow prepares its preview and validation state.


Ignoring Base Rules

Some objects intentionally need different rules.

Examples:

  • A decorative flower should be free-form and overlap allowed.
  • A debug/test object should ignore normal restrictions.
  • A fence might use line placement and adjacency rules instead of building rules.

Use ignore_base_rules carefully:

Setting Effect
PlacementProfile.ignore_base_rules Objects with this profile can skip global/base rules.
ScenePlacementEntry.ignore_base_rules This specific entry can skip inherited rule tiers.

If multiple profiles are present and any profile ignores base rules, the object can bypass the global base rules. Keep profile names clear so designers understand why an object behaves differently.


Built-In Rules Plugin Users Should Know

Rule Purpose
WithinTileMapBoundsRule Keeps placement inside valid cells of the active TileMapLayer.
CollisionsCheckRule Checks whether placement overlaps physics objects according to the configured masks.
ValidPlacementTileRule Checks tile custom data or tile validity expectations.
SpendMaterialsRuleById Canonical id-keyed cost rule for spending materials after successful validation.
SpendMaterialsRuleGeneric Legacy ResourceStack-keyed spend rule kept for existing projects. Prefer SpendMaterialsRuleById for new work.

Collision Shapes and Indicators

Tile-based rules need positions to check. Those positions usually come from collision shapes on the object scene.

Recommended object shape:

ObjectRoot (Node2D)
├── Sprite2D
└── StaticBody2D or Area2D
    └── CollisionShape2D

The pipeline is roughly:

placeable scene
→ preview instance
→ collision shapes are inspected
→ covered tile positions are calculated
→ rule indicators are created
→ TileCheckRule rules validate those indicators

If a placeable has no collision shapes, some tile-based rules may have no tile positions to evaluate. That can be intentional for purely visual objects, but it is surprising for buildings. Add collision shapes when you want reliable bounds, collision, and tile-data validation.


Collision Layer vs Collision Mask

This is the most common source of confusing rule behavior.

  • collision_layer = what the object is.
  • collision_mask = what the detector or rule looks for.

For CollisionsCheckRule to detect an existing object, the existing object must be on a collision layer that the rule's mask checks.

Existing object:
  collision_layer includes layer 10

Collision rule / shapecast:
  collision_mask includes layer 10

If the object is only on layer 1 but the rule checks layer 10, the rule will not see it.


Placement vs Manipulation Rules

Placement and manipulation share much of the validation infrastructure, but their rule sources differ.

Workflow Rule source
New object placement Rules from settings, profiles, and ScenePlacementEntry.
Move/manipulation Rules from the selected Manipulatable / manipulation settings path.
Terrain painting Terrain placement rules and tile/terrain validation path.

For manipulation, make sure the object has a Manipulatable component and targeting can detect the object. A perfectly written rule will not help if the object cannot be targeted.


Inventory and Cost Rules

Preferred: SpendMaterialsRuleById

Use SpendMaterialsRuleById for new projects.

It uses a Dictionary[StringName, int] of item id to amount, for example:

{
    &"Wood": 10,
    &"Stone": 4,
}

The located inventory/container bridge should implement:

Method Purpose
get_count_by_id(id: StringName) -> int Check whether enough material exists during validation.
try_remove_by_id(id: StringName, amount: int) -> int Spend after successful validation.
try_add_by_id(id: StringName, amount: int) -> int Roll back partial spends when needed.

The rule should own the spend. Do not also subtract materials in a success signal handler, or you will double-spend.

Legacy: SpendMaterialsRuleGeneric

SpendMaterialsRuleGeneric is the older ResourceStack-keyed rule. Keep it for existing projects that already depend on it. For new projects, prefer the id-keyed rule so your placement costs do not depend on a specific inventory resource class.


Locating an Inventory Container

Spend/refund rules locate an inventory bridge from the placement owner.

Search root is normally:

PlacementOwner.owner_root

The locator does not magically search every autoload or every node in the scene tree. Put a bridge node under the owner root, or intentionally point owner_root at a node that can reach the bridge.

Common locator methods include matching by:

  • Node name.
  • Script file name.
  • Godot group.

Group-based lookup is often the most refactor-friendly option.


Don't Duplicate Rule Logic in UI

Your UI should display rule results, not re-implement them.

Good UI behavior:

  • Read the placement report/action data.
  • Show the first issue or list of issues.
  • Refresh inventory display after placement succeeds.
  • Keep buttons disabled when the session says the entry is unavailable.

Bad UI behavior:

  • Rechecking collision rules separately.
  • Spending inventory in both the rule and a success signal.
  • Assuming a green-looking preview means the world has already changed.

Custom Rule Authoring Checklist

When writing a custom rule:

  1. Choose PlacementRule or TileCheckRule based on whether you need tile/indicator positions.
  2. Override the validation method expected by that base class.
  3. Return clear issue text for failure cases.
  4. Keep irreversible side effects in the post-success/apply path.
  5. Call the base setup/runtime issue methods when extending an existing rule.
  6. Test both success and failure cases.

See Custom Placement Rules for detailed examples.


Practical Guidance

  • Put project-wide defaults in PlacementSettings.placement_rules.
  • Put category behavior in PlacementProfile.
  • Put unique object requirements on the ScenePlacementEntry.
  • Use collision shapes for buildings and other objects with a footprint.
  • Use SpendMaterialsRuleById for new material-cost rules.
  • Keep rule failure messages beginner-readable; they often become player-facing UI text.

Related Guides


Source

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

Plugin docs root:gdscript/plugins/grid_placement_dev/docs