Grid Placement
Development ⚠️ GridPlacement 6.0 (GECS) is in active development. This is the GDScript ECS architecture.

Manipulation Workflows

How move/rotate/place/remove manipulation flows work in GridPlacement 6.0.

Manipulation in 6.0 is split into focused systems with a thin facade API.

Architecture Overview

The manipulation system uses a facade pattern that delegates to specialized systems:

ManipulationSystem (facade)
    ├── MovementManipulationSystem  — Handle entity repositioning
    ├── RotationManipulationSystem  — Handle entity rotation
    ├── PlacementManipulationSystem — Handle entity placement updates
    └── RemovalManipulationSystem   — Handle entity demolition/removal

Primary APIs

Use ManipulationSystem static helpers for common operations:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var result = ManipulationSystem.try_move(entity, target_position)
# Returns: Dictionary with success status and any issues

# Rotation  
var result = ManipulationSystem.try_rotate(entity, angle_degrees)
# Supports 90-degree increments or custom angles

# Placement update
var result = ManipulationSystem.try_place(entity, new_position)

# Demolition
var result = ManipulationSystem.try_demolish(entity)

Required Components

Entities must have the following components for manipulation:

1
2
3
4
5
# Minimum required components for manipulation
- ManipulationComponent     # Tracks operation mode and state
- GridPositionComponent    # Current grid position
- PlacementComponent       # Placement state and status
- PlaceableComponent       # Placeable definition and settings

Manipulation Flow

1) Movement Flow

1
2
3
4
5
6
7
8
# Check if entity can move
if ManipulationSystem.can_move(entity):
    # Attempt movement
    var result = ManipulationSystem.try_move(entity, target_position)
    
    if result.success:
        # Listen for completion
        ManipulationSignalBus.entity_moved.emit(entity, target_position)

2) Rotation Flow

1
2
3
4
5
# Rotate by 90 degrees
var result = ManipulationSystem.try_rotate(entity, 90)

# Or use enum for cardinal directions
var result = ManipulationSystem.try_rotate_to_cardinal(entity, Direction.NORTH)

3) Demolition Flow

1
2
3
4
5
6
# Initiate demolition
var result = ManipulationSystem.try_demolish(entity)

if result.success:
    # Demolition queued - listen for completion
    PlacementSignalBus.placement_demolished.emit(entity)

Operation States

ManipulationComponent tracks the current operation state:

1
2
3
4
5
6
7
enum OperationMode {
    IDLE,           # No active operation
    PREVIEW_MOVE,  # Previewing potential move
    PREVIEW_ROTATE,# Previewing potential rotation
    EXECUTING,     # Operation in progress
    CANCELING      # Canceling current operation
}

Constraint System

Manipulation can be constrained via templates:

1
2
3
4
5
6
# Load constraints from template
var template: PlaceableTemplate = load("res://templates/building.tres")
var constraints = template.manipulation_constraints

# Apply to manipulation
MovementManipulationSystem.apply_constraints(entity, constraints)

Common constraints:

  • Movement bounds: Limit how far an entity can move
  • Rotation limits: Restrict rotation angles
  • Overlap prevention: Block manipulation if collisions would result

Preview Integration

Manipulation workflows integrate with preview systems:

1
2
3
4
5
6
7
# Enable preview during manipulation
PreviewSystem.enable_for_entity(entity)

# Update preview based on potential manipulation
var preview_state = PreviewSystem.calculate_preview(entity, target_position)

# Preview states: NEUTRAL | VALID | INVALID

Error Handling

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var result = ManipulationSystem.try_move(entity, target_position)

if not result.success:
    # Handle specific error types
    match result.error_code:
        ResultCode.OUT_OF_BOUNDS:
            show_ui_message("Cannot move outside grid bounds")
        ResultCode.COLLISION:
            show_ui_message("Space is occupied")
        ResultCode.INSUFFICIENT_RESOURCES:
            show_ui_message("Not enough resources")
  1. Ensure entity has ManipulationComponent + required placement/grid components.
  2. Trigger operation via facade or specific manipulation system.
  3. Listen to manipulation/placement signal buses for outcomes.
  4. Reflect results in UI and selection state.

Test Verification

This guide’s manipulation workflows are validated by test suites:

  • /e2e/test_manipulation_workflow.gd — End-to-end manipulation workflow tests
  • /e2e/test_preview_manipulation_workflow.gd — Preview manipulation workflow tests
  • /systems/manipulation/test_movement_manipulation_system.gd — Movement manipulation system tests
  • /systems/manipulation/test_rotation_manipulation_system.gd — Rotation manipulation system tests
  • /systems/manipulation/test_removal_manipulation_system.gd — Removal manipulation system tests
  • /systems/manipulation/test_placement_manipulation_system.gd — Placement manipulation system tests
  • /integration/manipulation/test_manipulation_workflow_e2e.gd — Manipulation E2E integration tests
  • /integration/manipulation/test_manipulation_constraints_from_template.gd — Constraint validation