Update Grid Rendering Pipeline
parent
fe7b626c14
commit
0816bb4b98
|
|
@ -1,374 +1,374 @@
|
||||||
# Grid Rendering Pipeline
|
# Grid Rendering Pipeline
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The Grid rendering pipeline handles multi-layer tilemap rendering with chunk-based caching for optimal performance. It supports arbitrary numbers of rendering layers, viewport culling, zoom, and entity rendering.
|
The Grid rendering pipeline handles multi-layer tilemap rendering with chunk-based caching for optimal performance. It supports arbitrary numbers of rendering layers, viewport culling, zoom, and entity rendering.
|
||||||
|
|
||||||
**Parent Page:** [[Grid-System]]
|
**Parent Page:** [[Grid-System]]
|
||||||
|
|
||||||
**Related Pages:**
|
**Related Pages:**
|
||||||
- [[Performance-and-Profiling]] - Metrics and profiling tools
|
- [[Performance-and-Profiling]] - Metrics and profiling tools
|
||||||
- [[Entity-Management]] - Entity rendering within grids
|
- [[Entity-Management]] - Entity rendering within grids
|
||||||
- [[Grid-TCOD-Integration]] - FOV and pathfinding (partially in transition)
|
- [[Grid-TCOD-Integration]] - FOV and pathfinding (partially in transition)
|
||||||
|
|
||||||
**Key Files:**
|
**Key Files:**
|
||||||
- `src/UIGrid.cpp::render()` - Main rendering orchestration
|
- `src/UIGrid.cpp::render()` - Main rendering orchestration
|
||||||
- `src/GridLayers.cpp` - ColorLayer and TileLayer rendering
|
- `src/GridLayers.cpp` - ColorLayer and TileLayer rendering
|
||||||
- `src/UIGrid.cpp::renderChunk()` - Per-chunk RenderTexture management
|
- `src/UIGrid.cpp::renderChunk()` - Per-chunk RenderTexture management
|
||||||
|
|
||||||
**Related Issues:**
|
**Related Issues:**
|
||||||
- [#123](../../issues/123) - Chunk-based Grid Rendering (Closed - Implemented)
|
- [#123](../../issues/123) - Chunk-based Grid Rendering (Closed - Implemented)
|
||||||
- [#148](../../issues/148) - Dirty Flag RenderTexture Caching (Closed - Implemented)
|
- [#148](../../issues/148) - Dirty Flag RenderTexture Caching (Closed - Implemented)
|
||||||
- [#147](../../issues/147) - Dynamic Layer System (Closed - Implemented)
|
- [#147](../../issues/147) - Dynamic Layer System (Closed - Implemented)
|
||||||
- [#113](../../issues/113) - Batch Operations API (Open - includes FOV access discussion)
|
- [#113](../../issues/113) - Batch Operations API (Open - includes FOV access discussion)
|
||||||
- [#115](../../issues/115) - SpatialHash for entity culling (Open)
|
- [#115](../../issues/115) - SpatialHash for entity culling (Open)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Architecture Overview
|
## Architecture Overview
|
||||||
|
|
||||||
### Layer-Based Rendering
|
### Layer-Based Rendering
|
||||||
|
|
||||||
Grids render content through **layers** rather than per-cell properties. Each layer is either a `ColorLayer` (solid colors) or `TileLayer` (texture sprites).
|
Grids render content through **layers** rather than per-cell properties. Each layer is either a `ColorLayer` (solid colors) or `TileLayer` (texture sprites).
|
||||||
|
|
||||||
**Render order is determined by z_index:**
|
**Render order is determined by z_index:**
|
||||||
- Layers with `z_index < 0` render **below** entities
|
- Layers with `z_index < 0` render **below** entities
|
||||||
- Entities render at the z=0 boundary
|
- Entities render at the z=0 boundary
|
||||||
- Layers with `z_index >= 0` render **above** entities (overlays)
|
- Layers with `z_index >= 0` render **above** entities (overlays)
|
||||||
|
|
||||||
Within each group, lower z_index values render first (behind higher values).
|
Within each group, lower z_index values render first (behind higher values).
|
||||||
|
|
||||||
```
|
```
|
||||||
z_index: -3 -2 -1 0 +1 +2
|
z_index: -3 -2 -1 0 +1 +2
|
||||||
↓ ↓ ↓ ↓ ↓ ↓
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
[background] [tiles] [ENTITIES] [fog] [UI overlay]
|
[background] [tiles] [ENTITIES] [fog] [UI overlay]
|
||||||
```
|
```
|
||||||
|
|
||||||
**Implementation:** See `UIGrid::render()` which iterates layers in z_index order, inserting entity rendering at the 0 boundary.
|
**Implementation:** See `UIGrid::render()` which iterates layers in z_index order, inserting entity rendering at the 0 boundary.
|
||||||
|
|
||||||
### Chunk-Based Caching
|
### Chunk-Based Caching
|
||||||
|
|
||||||
Large grids are divided into **chunks** (regions of cells). Each chunk maintains its own `sf::RenderTexture` that caches the rendered result.
|
Large grids are divided into **chunks** (regions of cells). Each chunk maintains its own `sf::RenderTexture` that caches the rendered result.
|
||||||
|
|
||||||
**Key concepts:**
|
**Key concepts:**
|
||||||
- Chunk size is implementation-defined (currently ~256 cells per dimension)
|
- Chunk size is implementation-defined (currently ~256 cells per dimension)
|
||||||
- Only chunks intersecting the viewport are considered for rendering
|
- Only chunks intersecting the viewport are considered for rendering
|
||||||
- Each chunk tracks whether its content is "dirty" (needs redraw)
|
- Each chunk tracks whether its content is "dirty" (needs redraw)
|
||||||
- Static content renders once, then the cached texture is reused
|
- Static content renders once, then the cached texture is reused
|
||||||
|
|
||||||
**Implementation:** See `UIGrid::renderChunk()` for chunk texture management.
|
**Implementation:** See `UIGrid::renderChunk()` for chunk texture management.
|
||||||
|
|
||||||
### Dirty Flag Propagation
|
### Dirty Flag Propagation
|
||||||
|
|
||||||
When layer content changes, only affected chunks are marked dirty:
|
When layer content changes, only affected chunks are marked dirty:
|
||||||
|
|
||||||
1. `layer.set(x, y, value)` marks the containing chunk as dirty
|
1. `layer.set(x, y, value)` marks the containing chunk as dirty
|
||||||
2. On next render, dirty chunks redraw to their RenderTexture
|
2. On next render, dirty chunks redraw to their RenderTexture
|
||||||
3. Clean chunks simply blit their cached texture
|
3. Clean chunks simply blit their cached texture
|
||||||
|
|
||||||
This means a 1000x1000 grid with one changing cell redraws only ~1 chunk, not 1,000,000 cells.
|
This means a 1000x1000 grid with one changing cell redraws only ~1 chunk, not 1,000,000 cells.
|
||||||
|
|
||||||
**Implementation:** Dirty flags propagate through `UIGrid::markDirty()` and are checked in `UIGrid::render()`.
|
**Implementation:** Dirty flags propagate through `UIGrid::markDirty()` and are checked in `UIGrid::render()`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Render Pipeline Stages
|
## Render Pipeline Stages
|
||||||
|
|
||||||
### Stage 1: Viewport Calculation
|
### Stage 1: Viewport Calculation
|
||||||
|
|
||||||
Calculate which chunks and cells are visible based on camera position, zoom, and grid dimensions.
|
Calculate which chunks and cells are visible based on camera position, zoom, and grid dimensions.
|
||||||
|
|
||||||
**Key properties:**
|
**Key properties:**
|
||||||
- `center` / `center_x`, `center_y` - Camera position in pixel coordinates (within grid space)
|
- `center` / `center_x`, `center_y` - Camera position in pixel coordinates (within grid space)
|
||||||
- `zoom` - Scale factor (1.0 = normal, 2.0 = 2x magnification)
|
- `zoom` - Scale factor (1.0 = normal, 2.0 = 2x magnification)
|
||||||
- `size` - Viewport dimensions in screen pixels
|
- `size` - Viewport dimensions in screen pixels
|
||||||
|
|
||||||
**Implementation:** Viewport bounds calculated at start of `UIGrid::render()`.
|
**Implementation:** Viewport bounds calculated at start of `UIGrid::render()`.
|
||||||
|
|
||||||
### Stage 2: Below-Entity Layers
|
### Stage 2: Below-Entity Layers
|
||||||
|
|
||||||
For each layer with `z_index < 0`, sorted by z_index:
|
For each layer with `z_index < 0`, sorted by z_index:
|
||||||
1. Determine which chunks intersect viewport
|
1. Determine which chunks intersect viewport
|
||||||
2. For each visible chunk:
|
2. For each visible chunk:
|
||||||
- If dirty: redraw layer content to chunk's RenderTexture
|
- If dirty: redraw layer content to chunk's RenderTexture
|
||||||
- Draw chunk's cached texture to output
|
- Draw chunk's cached texture to output
|
||||||
|
|
||||||
### Stage 3: Entity Rendering
|
### Stage 3: Entity Rendering
|
||||||
|
|
||||||
Entities render at the z=0 boundary:
|
Entities render at the z=0 boundary:
|
||||||
1. Iterate entity collection
|
1. Iterate entity collection
|
||||||
2. Cull entities outside viewport bounds
|
2. Cull entities outside viewport bounds
|
||||||
3. Draw visible entity sprites at interpolated positions
|
3. Draw visible entity sprites at interpolated positions
|
||||||
|
|
||||||
**Note:** Entity culling is currently O(n). SpatialHash optimization planned in [#115](../../issues/115).
|
**Note:** Entity culling is currently O(n). SpatialHash optimization planned in [#115](../../issues/115).
|
||||||
|
|
||||||
### Stage 4: Above-Entity Layers
|
### Stage 4: Above-Entity Layers
|
||||||
|
|
||||||
For each layer with `z_index >= 0`, sorted by z_index:
|
For each layer with `z_index >= 0`, sorted by z_index:
|
||||||
- Same chunk-based rendering as Stage 2
|
- Same chunk-based rendering as Stage 2
|
||||||
- These layers appear as overlays (fog, highlights, UI elements)
|
- These layers appear as overlays (fog, highlights, UI elements)
|
||||||
|
|
||||||
### Stage 5: Final Compositing
|
### Stage 5: Final Compositing
|
||||||
|
|
||||||
All rendered content exists in the grid's output RenderTexture, which is drawn to the window in a single operation.
|
All rendered content exists in the grid's output RenderTexture, which is drawn to the window in a single operation.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Performance Characteristics
|
## Performance Characteristics
|
||||||
|
|
||||||
**Static Grids:**
|
**Static Grids:**
|
||||||
- Near-zero CPU cost after initial render
|
- Near-zero CPU cost after initial render
|
||||||
- Cached chunk textures reused frame-to-frame
|
- Cached chunk textures reused frame-to-frame
|
||||||
- Only viewport calculation and texture blitting
|
- Only viewport calculation and texture blitting
|
||||||
|
|
||||||
**Dynamic Grids:**
|
**Dynamic Grids:**
|
||||||
- Cost proportional to number of dirty chunks
|
- Cost proportional to number of dirty chunks
|
||||||
- Single-cell changes affect only one chunk
|
- Single-cell changes affect only one chunk
|
||||||
- Bulk operations should batch changes before render
|
- Bulk operations should batch changes before render
|
||||||
|
|
||||||
**Large Grids:**
|
**Large Grids:**
|
||||||
- 1000x1000+ grids render efficiently
|
- 1000x1000+ grids render efficiently
|
||||||
- Only visible chunks processed
|
- Only visible chunks processed
|
||||||
- Memory scales with grid size (chunk textures)
|
- Memory scales with grid size (chunk textures)
|
||||||
|
|
||||||
**Profiling:** Use `mcrfpy.getMetrics()` or the F3 overlay to see render times. See [[Performance-and-Profiling]].
|
**Profiling:** Use `mcrfpy.getMetrics()` or the F3 overlay to see render times. See [[Performance-and-Profiling]].
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## FOV and Perspective System (In Transition)
|
## FOV and Perspective System (In Transition)
|
||||||
|
|
||||||
**Current Status:** The FOV computation (`compute_fov()`, `is_in_fov()`) works correctly for pathfinding and visibility queries. However, the automatic fog-of-war overlay system is **not currently connected** to the new layer architecture.
|
**Current Status:** The FOV computation (`compute_fov()`, `is_in_fov()`) works correctly for pathfinding and visibility queries. However, the automatic fog-of-war overlay system is **not currently connected** to the new layer architecture.
|
||||||
|
|
||||||
**What works:**
|
**What works:**
|
||||||
- `grid.compute_fov(x, y, radius)` - Computes which cells are visible
|
- `grid.compute_fov(x, y, radius)` - Computes which cells are visible
|
||||||
- `grid.is_in_fov(x, y)` - Queries visibility of a specific cell
|
- `grid.is_in_fov(x, y)` - Queries visibility of a specific cell
|
||||||
- Pathfinding uses walkable/transparent properties correctly
|
- Pathfinding uses walkable/transparent properties correctly
|
||||||
|
|
||||||
**What's in transition:**
|
**What's in transition:**
|
||||||
- Per-entity perspective (`UIGridPointState`) not yet exposed to Python
|
- Per-entity perspective (`UIGridPointState`) not yet exposed to Python
|
||||||
- Automatic fog overlay rendering disconnected from layer system
|
- Automatic fog overlay rendering disconnected from layer system
|
||||||
- Batch FOV data access being designed ([#113 discussion](../../issues/113))
|
- Batch FOV data access being designed ([#113 discussion](../../issues/113))
|
||||||
|
|
||||||
**Current workaround - Manual fog layer:**
|
**Current workaround - Manual fog layer:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Create a fog overlay layer (positive z_index = above entities)
|
# Create a fog overlay layer (positive z_index = above entities)
|
||||||
fog_layer = grid.add_layer("color", z_index=1)
|
fog_layer = grid.add_layer("color", z_index=1)
|
||||||
|
|
||||||
# After computing FOV, update fog colors
|
# After computing FOV, update fog colors
|
||||||
grid.compute_fov(player.grid_x, player.grid_y, radius=10)
|
grid.compute_fov(player.grid_x, player.grid_y, radius=10)
|
||||||
|
|
||||||
for x in range(grid.grid_x):
|
for x in range(grid.grid_x):
|
||||||
for y in range(grid.grid_y):
|
for y in range(grid.grid_y):
|
||||||
if not grid.is_in_fov(x, y):
|
if not grid.is_in_fov(x, y):
|
||||||
# Dim color for non-visible cells
|
# Dim color for non-visible cells
|
||||||
fog_layer.set(x, y, mcrfpy.Color(0, 0, 0, 192))
|
fog_layer.set(x, y, mcrfpy.Color(0, 0, 0, 192))
|
||||||
else:
|
else:
|
||||||
# Transparent for visible cells
|
# Transparent for visible cells
|
||||||
fog_layer.set(x, y, mcrfpy.Color(0, 0, 0, 0))
|
fog_layer.set(x, y, mcrfpy.Color(0, 0, 0, 0))
|
||||||
```
|
```
|
||||||
|
|
||||||
**Limitation:** This O(n²) iteration is inefficient for large grids. Batch operations ([#113](../../issues/113)) will address this with patterns like `cells_in_radius()` iterators.
|
**Limitation:** This O(n²) iteration is inefficient for large grids. Batch operations ([#113](../../issues/113)) will address this with patterns like `cells_in_radius()` iterators.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Layer Techniques
|
## Layer Techniques
|
||||||
|
|
||||||
### Multiple Overlay Layers
|
### Multiple Overlay Layers
|
||||||
|
|
||||||
You can pre-create multiple overlay layers and toggle between them:
|
You can pre-create multiple overlay layers and toggle between them:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Create several overlay options
|
# Create several overlay options
|
||||||
highlight_layer = grid.add_layer("color", z_index=1)
|
highlight_layer = grid.add_layer("color", z_index=1)
|
||||||
danger_layer = grid.add_layer("color", z_index=2)
|
danger_layer = grid.add_layer("color", z_index=2)
|
||||||
fog_layer = grid.add_layer("color", z_index=3)
|
fog_layer = grid.add_layer("color", z_index=3)
|
||||||
|
|
||||||
# Populate each with different data...
|
# Populate each with different data...
|
||||||
# highlight_layer shows selected cells
|
# highlight_layer shows selected cells
|
||||||
# danger_layer shows enemy threat zones
|
# danger_layer shows enemy threat zones
|
||||||
# fog_layer shows visibility
|
# fog_layer shows visibility
|
||||||
|
|
||||||
# Toggle visibility to switch which overlay shows
|
# Toggle visibility to switch which overlay shows
|
||||||
def show_danger_zones():
|
def show_danger_zones():
|
||||||
highlight_layer.visible = False
|
highlight_layer.visible = False
|
||||||
danger_layer.visible = True
|
danger_layer.visible = True
|
||||||
fog_layer.visible = False
|
fog_layer.visible = False
|
||||||
|
|
||||||
def show_fog_of_war():
|
def show_fog_of_war():
|
||||||
highlight_layer.visible = False
|
highlight_layer.visible = False
|
||||||
danger_layer.visible = False
|
danger_layer.visible = False
|
||||||
fog_layer.visible = True
|
fog_layer.visible = True
|
||||||
```
|
```
|
||||||
|
|
||||||
### Z-Index Reordering
|
### Z-Index Reordering
|
||||||
|
|
||||||
Change layer order at runtime by modifying z_index:
|
Change layer order at runtime by modifying z_index:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Bring a layer to front
|
# Bring a layer to front
|
||||||
important_layer.z_index = 100
|
important_layer.z_index = 100
|
||||||
|
|
||||||
# Send a layer behind entities
|
# Send a layer behind entities
|
||||||
background_layer.z_index = -10
|
background_layer.z_index = -10
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** Changing z_index marks the layer dirty, triggering re-render of affected chunks.
|
**Note:** Changing z_index marks the layer dirty, triggering re-render of affected chunks.
|
||||||
|
|
||||||
### Constructor `layers={}` Limitations
|
### Constructor `layers={}` Limitations
|
||||||
|
|
||||||
The `layers={}` constructor argument is convenient but limited:
|
The `layers={}` constructor argument is convenient but limited:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# This creates layers, but ALL get negative z_index (below entities)
|
# This creates layers, but ALL get negative z_index (below entities)
|
||||||
grid = mcrfpy.Grid(
|
grid = mcrfpy.Grid(
|
||||||
grid_size=(50, 50),
|
grid_size=(50, 50),
|
||||||
layers={"ground": "color", "terrain": "tile", "overlay": "color"}
|
layers={"ground": "color", "terrain": "tile", "overlay": "color"}
|
||||||
)
|
)
|
||||||
# Result: ground=-3, terrain=-2, overlay=-1 (all below entities!)
|
# Result: ground=-3, terrain=-2, overlay=-1 (all below entities!)
|
||||||
```
|
```
|
||||||
|
|
||||||
**For overlays above entities, use `add_layer()` explicitly:**
|
**For overlays above entities, use `add_layer()` explicitly:**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
grid = mcrfpy.Grid(grid_size=(50, 50), layers={})
|
grid = mcrfpy.Grid(grid_size=(50, 50), layers={})
|
||||||
ground = grid.add_layer("color", z_index=-2)
|
ground = grid.add_layer("color", z_index=-2)
|
||||||
terrain = grid.add_layer("tile", z_index=-1)
|
terrain = grid.add_layer("tile", z_index=-1)
|
||||||
overlay = grid.add_layer("color", z_index=1) # Above entities!
|
overlay = grid.add_layer("color", z_index=1) # Above entities!
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Migration from Legacy API
|
## Migration from Legacy API
|
||||||
|
|
||||||
Prior to the layer system, grids had built-in per-cell rendering via `UIGridPoint` properties. Here's how to recreate that behavior:
|
Prior to the layer system, grids had built-in per-cell rendering via `UIGridPoint` properties. Here's how to recreate that behavior:
|
||||||
|
|
||||||
### Legacy Pattern (Pre-November 2025)
|
### Legacy Pattern (Pre-November 2025)
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# OLD API (no longer works):
|
# OLD API (no longer works):
|
||||||
grid = mcrfpy.Grid(50, 50, 16, 16)
|
grid = mcrfpy.Grid(50, 50, 16, 16)
|
||||||
cell = grid.at(x, y)
|
cell = grid.at(x, y)
|
||||||
cell.tilesprite = 42 # Sprite index
|
cell.tilesprite = 42 # Sprite index
|
||||||
cell.color = (255, 0, 0) # Background color
|
cell.color = (255, 0, 0) # Background color
|
||||||
```
|
```
|
||||||
|
|
||||||
### Equivalent Modern Pattern
|
### Equivalent Modern Pattern
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# NEW API - explicit layers:
|
# NEW API - explicit layers:
|
||||||
grid = mcrfpy.Grid(grid_size=(50, 50), pos=(0, 0), size=(400, 400))
|
grid = mcrfpy.Grid(grid_size=(50, 50), pos=(0, 0), size=(400, 400))
|
||||||
|
|
||||||
# Grid creates a default TileLayer; access it:
|
# Grid creates a default TileLayer; access it:
|
||||||
tile_layer = grid.layers[0]
|
tile_layer = grid.layers[0]
|
||||||
tile_layer.set(x, y, 42) # Sprite index
|
tile_layer.set(x, y, 42) # Sprite index
|
||||||
|
|
||||||
# For background colors, add a ColorLayer behind tiles:
|
# For background colors, add a ColorLayer behind tiles:
|
||||||
color_layer = grid.add_layer("color", z_index=-2) # Behind default tile layer
|
color_layer = grid.add_layer("color", z_index=-2) # Behind default tile layer
|
||||||
color_layer.set(x, y, mcrfpy.Color(255, 0, 0))
|
color_layer.set(x, y, mcrfpy.Color(255, 0, 0))
|
||||||
```
|
```
|
||||||
|
|
||||||
### Recreating Old Three-Layer Rendering
|
### Recreating Old Three-Layer Rendering
|
||||||
|
|
||||||
The legacy system rendered: background color → tile sprite → FOV overlay.
|
The legacy system rendered: background color → tile sprite → FOV overlay.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Create grid with no default layers
|
# Create grid with no default layers
|
||||||
grid = mcrfpy.Grid(
|
grid = mcrfpy.Grid(
|
||||||
grid_size=(50, 50),
|
grid_size=(50, 50),
|
||||||
pos=(100, 100),
|
pos=(100, 100),
|
||||||
size=(400, 400),
|
size=(400, 400),
|
||||||
texture=tileset,
|
texture=tileset,
|
||||||
layers={}
|
layers={}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Layer 1: Background colors (z=-2, behind everything)
|
# Layer 1: Background colors (z=-2, behind everything)
|
||||||
background = grid.add_layer("color", z_index=-2)
|
background = grid.add_layer("color", z_index=-2)
|
||||||
|
|
||||||
# Layer 2: Tile sprites (z=-1, above background, below entities)
|
# Layer 2: Tile sprites (z=-1, above background, below entities)
|
||||||
tiles = grid.add_layer("tile", z_index=-1, texture=tileset)
|
tiles = grid.add_layer("tile", z_index=-1, texture=tileset)
|
||||||
|
|
||||||
# Layer 3: FOV overlay (z=+1, above entities)
|
# Layer 3: FOV overlay (z=+1, above entities)
|
||||||
fog = grid.add_layer("color", z_index=1)
|
fog = grid.add_layer("color", z_index=1)
|
||||||
|
|
||||||
# Now populate layers as needed
|
# Now populate layers as needed
|
||||||
background.fill(mcrfpy.Color(20, 20, 30)) # Dark blue background
|
background.fill(mcrfpy.Color(20, 20, 30)) # Dark blue background
|
||||||
|
|
||||||
for x in range(50):
|
for x in range(50):
|
||||||
for y in range(50):
|
for y in range(50):
|
||||||
tiles.set(x, y, calculate_tile_index(x, y))
|
tiles.set(x, y, calculate_tile_index(x, y))
|
||||||
|
|
||||||
# FOV overlay updated after compute_fov() calls
|
# FOV overlay updated after compute_fov() calls
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Common Issues
|
## Common Issues
|
||||||
|
|
||||||
### Issue: Layer Changes Don't Appear
|
### Issue: Layer Changes Don't Appear
|
||||||
|
|
||||||
**Cause:** Layer content changed but chunk not marked dirty.
|
**Cause:** Layer content changed but chunk not marked dirty.
|
||||||
|
|
||||||
**Fix:** Use layer methods (`set()`, `fill()`) which automatically mark dirty. Direct property manipulation may bypass dirty flagging.
|
**Fix:** Use layer methods (`set()`, `fill()`) which automatically mark dirty. Direct property manipulation may bypass dirty flagging.
|
||||||
|
|
||||||
### Issue: Overlay Appears Behind Entities
|
### Issue: Overlay Appears Behind Entities
|
||||||
|
|
||||||
**Cause:** Layer z_index is negative.
|
**Cause:** Layer z_index is negative.
|
||||||
|
|
||||||
**Fix:** Use `z_index >= 0` for overlays:
|
**Fix:** Use `z_index >= 0` for overlays:
|
||||||
```python
|
```python
|
||||||
overlay = grid.add_layer("color", z_index=1) # Not z_index=-1
|
overlay = grid.add_layer("color", z_index=1) # Not z_index=-1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Issue: Performance Degrades with Many Changes
|
### Issue: Performance Degrades with Many Changes
|
||||||
|
|
||||||
**Cause:** Each `set()` call can mark a chunk dirty; many scattered changes = many chunk redraws.
|
**Cause:** Each `set()` call can mark a chunk dirty; many scattered changes = many chunk redraws.
|
||||||
|
|
||||||
**Fix:** Batch logically-related changes. For bulk updates, consider:
|
**Fix:** Batch logically-related changes. For bulk updates, consider:
|
||||||
```python
|
```python
|
||||||
# Less efficient: 10,000 individual calls
|
# Less efficient: 10,000 individual calls
|
||||||
for x in range(100):
|
for x in range(100):
|
||||||
for y in range(100):
|
for y in range(100):
|
||||||
layer.set(x, y, value)
|
layer.set(x, y, value)
|
||||||
|
|
||||||
# More efficient when available: bulk fill
|
# More efficient when available: bulk fill
|
||||||
layer.fill(mcrfpy.Color(0, 0, 0)) # Single operation
|
layer.fill(mcrfpy.Color(0, 0, 0)) # Single operation
|
||||||
```
|
```
|
||||||
|
|
||||||
Batch operations API ([#113](../../issues/113)) will provide more patterns.
|
Batch operations API ([#113](../../issues/113)) will provide more patterns.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## API Quick Reference
|
## API Quick Reference
|
||||||
|
|
||||||
**Grid Properties:**
|
**Grid Properties:**
|
||||||
- `center`, `center_x`, `center_y` - Camera position (pixels in grid space)
|
- `center`, `center_x`, `center_y` - Camera position (pixels in grid space)
|
||||||
- `zoom` - Scale factor
|
- `zoom` - Scale factor
|
||||||
- `layers` - List of layer objects, sorted by z_index
|
- `layers` - List of layer objects, sorted by z_index
|
||||||
- `fill_color` - Grid background (behind all layers)
|
- `fill_color` - Grid background (behind all layers)
|
||||||
|
|
||||||
**Grid Methods:**
|
**Grid Methods:**
|
||||||
- `add_layer(type, z_index, texture)` - Create new layer
|
- `add_layer(type, z_index, texture)` - Create new layer
|
||||||
- `remove_layer(layer)` - Remove a layer
|
- `remove_layer(layer)` - Remove a layer
|
||||||
|
|
||||||
**Layer Properties:**
|
**Layer Properties:**
|
||||||
- `z_index` - Render order
|
- `z_index` - Render order
|
||||||
- `visible` - Show/hide layer
|
- `visible` - Show/hide layer
|
||||||
- `grid_size` - Dimensions (read-only)
|
- `grid_size` - Dimensions (read-only)
|
||||||
|
|
||||||
**Layer Methods:**
|
**Layer Methods:**
|
||||||
- `set(x, y, value)` - Set cell (color or sprite index)
|
- `set(x, y, value)` - Set cell (color or sprite index)
|
||||||
- `at(x, y)` - Get cell value
|
- `at(x, y)` - Get cell value
|
||||||
- `fill(value)` - Fill all cells
|
- `fill(value)` - Fill all cells
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Navigation:**
|
**Navigation:**
|
||||||
- [[Grid-System]] - Parent page, layer concepts
|
- [[Grid-System]] - Parent page, layer concepts
|
||||||
- [[Grid-TCOD-Integration]] - FOV computation details
|
- [[Grid-TCOD-Integration]] - FOV computation details
|
||||||
- [[Performance-and-Profiling]] - Metrics and optimization
|
- [[Performance-and-Profiling]] - Metrics and optimization
|
||||||
- [[Entity-Management]] - Entity rendering
|
- [[Entity-Management]] - Entity rendering
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*Last updated: 2025-11-29*
|
*Last updated: 2025-11-29*
|
||||||
Loading…
Reference in New Issue