34507f9043
- docs/mapmaking/00-index.md — SDK overview with workflow diagram - docs/mapmaking/01-getting-started.md — template setup & first map - docs/mapmaking/02-building-geometry.md — CSG guide & prefab reference - docs/mapmaking/03-lighting-and-env.md — LightmapGI baking guide - docs/mapmaking/04-validation.md — validator CLI & CI/CD usage - docs/mapmaking/05-packaging-and-shipping.md — .pck pipeline - docs/mapmaking/06-faq-and-troubleshooting.md — 30+ common issues - README.md — add mapmaking SDK link to features list
246 lines
7.9 KiB
Markdown
246 lines
7.9 KiB
Markdown
# 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
|