# Building Geometry with CSG

Tactical Shooter maps are built with Godot's **CSG** (Constructive Solid
Geometry) system — the same tool you'd use in a 3D modeller, but inside the
Godot editor. CSG nodes let you cut, join, and extrude geometry in real-time
with instant visual feedback.

## CSG Basics

### CSG Node Types

| Node | Use | Shape |
|------|-----|-------|
| `CSGBox3D` | Walls, floors, ceilings, pillars | Rectangular prism |
| `CSGSphere3D` | Domes, curved edges | Sphere |
| `CSGCylinder3D` | Columns, pipes | Cylinder |
| `CSGCombiner3D` | Group container, non-collidable parent | — |
| `CSGPolygon3D` | Extruded 2D path | Custom shape |

### CSG Operations

Each CSG node has an **Operation** property that determines how it combines
with sibling CSG nodes in the same parent:

| Value | Operation | Effect |
|-------|-----------|--------|
| 0 | **Union** | Adds to existing geometry (default) |
| 1 | **Subtraction** | Cuts a hole through parent |
| 2 | **Intersection** | Keeps only overlapping volume |

**Example — a window cutout:**

```
Wall (CSGBox3D, Union)
└── WindowCutout (CSGBox3D, Subtraction)
```

This subtracts the window shape from the wall. Move/resize the subtraction
child to reposition the window.

### Key Properties

- **`use_collision`** (bool) — Must be `true` on all floor/wall/ceiling CSG
  nodes so players and bullets collide with them
- **`use_shadows`** (bool) — Enable shadow-casting on geometry
- **`material`** — Assign placeholder materials during construction; final
  materials come from the main game project library
- **`snap_mode`** — Controls vertex snapping (useful for aligning geometry)

## Building a Room

A basic room needs 3 CSG layers:

```
Room (CSGCombiner3D)
├── Floor (CSGBox3D, Union, use_collision=true)
├── Walls (CSGCombiner3D)
│   ├── Wall_North (CSGBox3D, Union)
│   ├── Wall_South (CSGBox3D, Union)
│   ├── Wall_East (CSGBox3D, Union)
│   └── Wall_West (CSGBox3D, Union)
└── Ceiling (CSGBox3D, Union, use_collision=true)
```

### CSG Building Tips

1. **Overlap slightly** — Walls should extend past the floor edge by ~0.1 units
   to prevent light leaks (thin gaps let light bleed through)
2. **Keep CSG simple** — Use as few CSG nodes as possible. A wall panel is one
   CSGBox3D, not 4 extruded edges
3. **Convert to Mesh when done** — Once geometry is final, select all CSG
   nodes → right-click → **Convert CSG to Mesh**. This bakes them into static
   MeshInstance3D nodes that perform much better
4. **Avoid curved CSG for floor/walls** — CSGSphere3D and CSGCylinder3D are
   expensive. Use them sparingly

## Prefab Reference

The template provides 6 drag-and-drop prefab nodes. Each is an `assets/prefabs/*.tscn`
file that you instantiate into your scene.

### ct_spawn.tscn

| Property | Value |
|----------|-------|
| Type | `Marker3D` (green pad + arrow) |
| Group | `ct_spawn` |
| Purpose | CT team spawn position |
| Quantity | 5 (one per player) |

The +Z arrow (blue axis) shows the direction players face when they spawn.
Position the pad at floor level — make it flush with the floor surface.

**Customisation:** Duplicate instances rather than editing the prefab. Adjust
only position and rotation. The green pad is cosmetic.

### t_spawn.tscn

| Property | Value |
|----------|-------|
| Type | `Marker3D` (red pad + arrow) |
| Group | `t_spawn` |
| Purpose | Terrorist team spawn position |
| Quantity | 5 |

Same usage as `ct_spawn` but red. Place at the opposite end of the map.

### buy_zone.tscn

| Property | Value |
|----------|-------|
| Type | `Area3D` with `CollisionShape3D` |
| Group | `buy_zone` |
| Purpose | Purchase-eligible zone |
| Quantity | 1–2 |

The game monitors `body_entered` / `body_exited` on these areas to show/hide
the buy menu. Resize the child CollisionShape3D to match the room shape.

**Additional groups (optional):**
- `ct_buy` — Only CT team can buy in this zone
- `t_buy` — Only T team can buy in this zone

If omitted, any player inside a `buy_zone` can buy (suitable for shared mid areas).

### bomb_site.tscn

| Property | Value |
|----------|-------|
| Type | `Area3D` with `CollisionShape3D` |
| Group | `bomb_site` |
| Purpose | Bomb plant zone |
| Quantity | 2 (A and B) |

Rename instances to `BombsiteA` and `BombsiteB`. Resize the CollisionShape3D
to cover the plantable area. Visual: semi-transparent orange floor panel.

**Additional groups (strongly recommended):**
- `bombsite_a` — Identifies this as site A
- `bombsite_b` — Identifies this as site B

### cubemap_origin.tscn

| Property | Value |
|----------|-------|
| Type | `Node3D` (blue sphere marker) |
| Group | `cubemap_origin` |
| Purpose | Marks ReflectionProbe capture position |
| Quantity | 1 |

Place at eye height ≈ 1.6 units above the floor in the most visually prominent
area (usually mid-map or the central choke point). The ReflectionProbe is a
separate node that should be placed at this marker's position after geometry
is finalised.

### map_bounds.tscn

| Property | Value |
|----------|-------|
| Type | `Area3D` with `CollisionShape3D` |
| Group | `map_bounds` |
| Purpose | Out-of-bounds kill wall |
| Quantity | 4–8 (enclose the perimeter) |

**Usage:**
- Place one instance per perimeter face (north, south, east, west)
- Resize each CollisionShape3D to form a closed box around the playable area
- Make the floor-bound wall tall enough that players can't jump over it
- The game detects `body_exited` from these areas and teleports/kills
  out-of-bounds players

> **Performance tip:** `map_bounds` nodes should be as thin as practical —
> these are just detection triggers, not visual geometry. A thickness of 0.5
> units is sufficient.

## Advanced Geometry Techniques

### Corridors and Hallways

Build a corridor as a CSGCombiner3D with union floor + walls + ceiling and
subtraction nodes for doors/windows:

```
Corridor (CSGCombiner3D)
├── Floor (CSGBox3D, Union)
├── LeftWall (CSGBox3D, Union)
│   └── Door1 (CSGBox3D, Subtraction)
├── RightWall (CSGBox3D, Union)
│   └── Window1 (CSGBox3D, Subtraction)
└── Ceiling (CSGBox3D, Union)
```

### Ramps and Stairs

Use multiple CSGBox3D nodes at increasing heights. Stack them like steps and
wrap in a CSGCombiner3D for a clean hierarchy:

```
Stairs (CSGCombiner3D)
├── Step1 (CSGBox3D, Union, pos=(0, 0, 0))
├── Step2 (CSGBox3D, Union, pos=(0, 0.5, 1))
├── Step3 (CSGBox3D, Union, pos=(0, 1.0, 2))
└── Step4 (CSGBox3D, Union, pos=(0, 1.5, 3))
```

For ramps, rotate a CSGBox3D or use CSGPolygon3D with an extruded triangle shape.

### Map Scale Reference

| Element | Size (units) | Notes |
|---------|-------------|-------|
| Player height | 1.8 | Eye level ≈ 1.6 |
| Player width | 0.5 | Collision capsule radius |
| Doorway | 1.5 × 2.5 | Wide enough for 2 players |
| Corridor | 3–4 wide | Comfortable movement |
| Bombsite | 8×8 minimum | Playable site area |
| Spawn room | 6×8 | 5 players need space |
| Mid area | 6–8 wide | Main chokepoint |

## From CSG to MeshInstance3D (Baking)

When your geometry is **final** (no more changes expected):

1. Select all CSG nodes in the scene tree
2. Right-click → **Convert CSG to Mesh**
3. This replaces CSG nodes with static `MeshInstance3D` nodes
4. The mesh instances are much more performant

**Don't convert until you're done** — CSG is editable, MeshInstance3D is not.
Keep working in CSG mode; convert only for final optimisation before packaging.

## Performance Budget

See the [Validator guide](04-validation.md) for detailed numbers, but the key
geometry rules are:

- **≤ 50,000 triangles** total across all meshes
- **≤ 5,000 triangles** per individual mesh (recommended; enforced as warning)
- Use CSG for blockout only — convert to mesh before shipping
- Avoid CSGSphere3D in visible areas; use hand-modelled meshes

## Next Steps

- [Lighting & Environment Setup](03-lighting-and-env.md) — light your map
- [Map Validation](04-validation.md) — run the validator on your scene
