284 lines
7.9 KiB
Markdown
284 lines
7.9 KiB
Markdown
# Grid-Based Collision System
|
|
|
|
## How It Works
|
|
|
|
The building system uses **grid-based collision detection**, NOT the actual colliders on building prefabs.
|
|
|
|
### Grid Bounds vs Collider Bounds
|
|
|
|
```
|
|
❌ OLD WAY (Collider-based):
|
|
Building A has BoxCollider (2.5 x 3.7 x 4.2)
|
|
Building B has MeshCollider (complex shape)
|
|
→ Hard to predict, inconsistent placement
|
|
|
|
✅ NEW WAY (Grid-based):
|
|
Building A has width=2, length=3, height=2 in BuildingData
|
|
Building B has width=1, length=4, height=3 in BuildingData
|
|
→ Predictable, consistent grid placement
|
|
```
|
|
|
|
## Why Grid-Based?
|
|
|
|
### Advantages
|
|
1. **Predictable**: Buildings snap to grid, easy to understand
|
|
2. **Consistent**: Same rules for all buildings, regardless of visual model
|
|
3. **Flexible**: Visual model can be any size/shape
|
|
4. **Network-Friendly**: Simple data to sync (just grid position + rotation)
|
|
5. **Performance**: Fast AABB (Axis-Aligned Bounding Box) checks
|
|
|
|
### Comparison
|
|
|
|
| Aspect | Collider-Based | Grid-Based |
|
|
|--------|---------------|------------|
|
|
| Placement | Visual, complex shapes | Predictable grid cells |
|
|
| Performance | Slower (physics queries) | Faster (simple bounds check) |
|
|
| Network Sync | Complex mesh data | Simple int coordinates |
|
|
| Rotation | Complex recalculation | Swap width/length |
|
|
| Debugging | Hard to visualize | Easy (grid gizmos) |
|
|
|
|
## How Grid Size Works
|
|
|
|
### BuildingData Settings
|
|
|
|
```csharp
|
|
[Header("Grid Size")]
|
|
public int width = 2; // X-axis grid cells
|
|
public int length = 3; // Z-axis grid cells
|
|
public float height = 2f; // Y-axis size (can be float)
|
|
```
|
|
|
|
### Rotation Effect
|
|
|
|
```
|
|
Building: width=2, length=3
|
|
|
|
Rotation 0° (0): Rotation 90° (1):
|
|
┌─────┐ ┌───────┐
|
|
│ 2 │ │ 3 │
|
|
│ x │ │ x │
|
|
│ 3 │ └───────┘
|
|
└─────┘ 2
|
|
|
|
Rotation 180° (2): Rotation 270° (3):
|
|
┌─────┐ ┌───────┐
|
|
│ 3 │ │ 2 │
|
|
│ x │ │ x │
|
|
│ 2 │ └───────┘
|
|
└─────┘ 3
|
|
```
|
|
|
|
The `GetSize(rotation)` method automatically swaps width/length for 90° and 270° rotations.
|
|
|
|
## Visual Examples
|
|
|
|
### Example 1: Small House
|
|
```yaml
|
|
BuildingData:
|
|
width: 2
|
|
length: 2
|
|
height: 3
|
|
|
|
Grid Footprint (top view):
|
|
┌─┬─┐
|
|
├─┼─┤ Occupies 4 grid cells (2x2)
|
|
└─┴─┘
|
|
|
|
Visual Model: Can be any size!
|
|
- Model might be 1.8 x 1.8 (smaller than grid)
|
|
- Model might be 2.3 x 2.3 (larger than grid)
|
|
- Collision still uses 2x2 grid
|
|
```
|
|
|
|
### Example 2: Wall Segment
|
|
```yaml
|
|
BuildingData:
|
|
width: 1
|
|
length: 4
|
|
height: 2
|
|
|
|
Grid Footprint:
|
|
┌───────────┐
|
|
│ 1 x 4 │ Occupies 4 grid cells (1x4)
|
|
└───────────┘
|
|
|
|
When rotated 90°:
|
|
┌─┐
|
|
├─┤
|
|
├─┤ Becomes 4x1
|
|
├─┤
|
|
└─┘
|
|
```
|
|
|
|
### Example 3: Large Building
|
|
```yaml
|
|
BuildingData:
|
|
width: 4
|
|
length: 5
|
|
height: 4
|
|
|
|
Grid Footprint:
|
|
┌─┬─┬─┬─┬─┐
|
|
├─┼─┼─┼─┼─┤
|
|
├─┼─┼─┼─┼─┤ Occupies 20 grid cells (4x5)
|
|
├─┼─┼─┼─┼─┤
|
|
└─┴─┴─┴─┴─┘
|
|
```
|
|
|
|
## Collision Detection Code
|
|
|
|
### IsValidPlacement (BuildingManager.cs)
|
|
|
|
```csharp
|
|
// Get grid size from BuildingData (NOT collider)
|
|
Vector3 gridSize = data.GetSize(rotation);
|
|
|
|
// Shrink bounds slightly to allow adjacent placement
|
|
// Without this, Bounds.Intersects() returns true for touching bounds
|
|
Vector3 shrunkSize = gridSize - Vector3.one * 0.01f;
|
|
Bounds checkBounds = new Bounds(
|
|
groundPosition + Vector3.up * gridSize.y * 0.5f,
|
|
shrunkSize
|
|
);
|
|
|
|
// Check against all placed buildings' GRID bounds
|
|
foreach (var building in placedBuildings)
|
|
{
|
|
Bounds buildingGridBounds = building.GetGridBounds();
|
|
if (checkBounds.Intersects(buildingGridBounds))
|
|
return false; // Overlap detected
|
|
}
|
|
```
|
|
|
|
**Why shrink by 0.01f?**
|
|
Unity's `Bounds.Intersects()` returns `true` when bounds are touching (edge-to-edge), not just overlapping. By shrinking the bounds by a tiny amount (0.01 units), we allow buildings to be placed directly adjacent without triggering a false overlap detection.
|
|
|
|
### GetGridBounds (Building.cs)
|
|
|
|
```csharp
|
|
public Bounds GetGridBounds()
|
|
{
|
|
// Uses BuildingData size, not collider
|
|
Vector3 gridSize = buildingData.GetSize(rotation);
|
|
|
|
// Shrink slightly to allow adjacent buildings
|
|
Vector3 shrunkSize = gridSize - Vector3.one * 0.01f;
|
|
return new Bounds(
|
|
transform.position + Vector3.up * gridSize.y * 0.5f,
|
|
shrunkSize
|
|
);
|
|
}
|
|
```
|
|
|
|
**Note:** The 0.01f shrink is tiny and not visible, but prevents false overlap detection for adjacent buildings.
|
|
|
|
## Visualizing Grid Bounds
|
|
|
|
### In Scene View
|
|
|
|
1. **Enter Build Mode** (Press B)
|
|
2. **Look at Scene View** (not Game view)
|
|
3. You'll see:
|
|
- **Green/Red Wire Cube**: Preview's grid bounds
|
|
- **Yellow Grid Cells**: Individual cells
|
|
- **Cyan Wire Cubes**: Placed buildings' grid bounds
|
|
|
|
### Debug Settings
|
|
|
|
**BuildingPlacement:**
|
|
- `Show Grid Bounds` - Shows preview grid visualization
|
|
|
|
**Building:**
|
|
- `Show Grid Bounds` - Shows cyan wire cube for this building
|
|
- `Grid Bounds Color` - Customize visualization color
|
|
|
|
### Example Scene
|
|
|
|
```
|
|
Scene View:
|
|
Preview (Green)
|
|
┌─────┐
|
|
│ 2x3 │
|
|
└─────┘
|
|
Placed Building (Cyan)
|
|
┌───┐
|
|
│1x2│
|
|
└───┘
|
|
|
|
Grid Cells (Yellow):
|
|
┌─┬─┬─┬─┬─┬─┐
|
|
├─┼─┼─┼─┼─┼─┤
|
|
└─┴─┴─┴─┴─┴─┘
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### 1. Match Grid Size to Gameplay
|
|
```csharp
|
|
// Small decorations
|
|
width: 1, length: 1, height: 1
|
|
|
|
// Medium buildings
|
|
width: 2-3, length: 2-3, height: 2-3
|
|
|
|
// Large buildings
|
|
width: 4-6, length: 4-6, height: 3-5
|
|
```
|
|
|
|
### 2. Visual Model Can Differ
|
|
The visual model doesn't need to match grid size exactly:
|
|
- Overhang/decorations can extend beyond grid
|
|
- Model can be smaller, leaving empty grid space
|
|
- Use `placementOffset` to adjust visual alignment
|
|
|
|
### 3. Height Consideration
|
|
```csharp
|
|
height: 2f // Building is 2 units tall
|
|
```
|
|
- Used for vertical bounds checking
|
|
- Prevents buildings on top of each other
|
|
- Can be float (e.g., 2.5f for tall buildings)
|
|
|
|
### 4. Colliders Still Needed
|
|
Building prefabs should still have colliders for:
|
|
- Player/entity collision during gameplay
|
|
- Physics interactions
|
|
- Raycast detection
|
|
|
|
But these are NOT used for placement validation!
|
|
|
|
## Common Questions
|
|
|
|
**Q: Why is my small model blocking a large area?**
|
|
A: Check the `width` and `length` in BuildingData. The grid size determines collision, not the visual model.
|
|
|
|
**Q: Buildings overlap visually but can't place?**
|
|
A: Grid bounds are overlapping. Check Scene view with "Show Grid Bounds" enabled.
|
|
|
|
**Q: How do I make a building take less space?**
|
|
A: Reduce `width` and `length` in BuildingData. The visual model size doesn't matter.
|
|
|
|
**Q: Can I use fractional grid sizes?**
|
|
A: `width` and `length` are integers (whole grid cells). Only `height` can be a float.
|
|
|
|
**Q: What if my model is rotated strangely?**
|
|
A: Grid rotation is separate from model rotation. Grid always aligns to world axes. Adjust model's prefab rotation or use `placementOffset`.
|
|
|
|
**Q: Can buildings be placed directly next to each other with no gap?**
|
|
A: Yes! The system shrinks bounds by 0.01f to allow adjacent placement. Buildings can touch edge-to-edge.
|
|
|
|
**Q: I want a gap between buildings. How?**
|
|
A: Increase the `width` and `length` values in BuildingData by 1. For example, change a 2x2 building to 3x3 to add a 1-cell buffer zone.
|
|
|
|
## Summary
|
|
|
|
✅ **Use BuildingData grid size** for collision
|
|
✅ **Visual model can be any size**
|
|
✅ **Predictable, grid-aligned placement**
|
|
✅ **Easy debugging with gizmos**
|
|
✅ **Fast performance**
|
|
|
|
❌ **Don't rely on collider size**
|
|
❌ **Don't expect pixel-perfect visual collision**
|
|
❌ **Don't use colliders for placement validation**
|