Update Rendering and Visuals

John McCardle 2025-12-02 03:16:49 +00:00
parent 973108f14d
commit 07c41c4f7b
1 changed files with 385 additions and 385 deletions

@ -1,386 +1,386 @@
# Rendering and Visuals # Rendering and Visuals
How to create and display visual elements in McRogueFace. How to create and display visual elements in McRogueFace.
## Quick Reference ## Quick Reference
**Systems:** [[UI-Component-Hierarchy]], [[Grid-System]], [[Animation-System]] **Systems:** [[UI-Component-Hierarchy]], [[Grid-System]], [[Animation-System]]
**Key Types:** **Key Types:**
- `Frame` - Rectangles and containers - `Frame` - Rectangles and containers
- `Caption` - Text rendering - `Caption` - Text rendering
- `Sprite` - Images and sprite sheets - `Sprite` - Images and sprite sheets
- `Grid` - Tilemaps - `Grid` - Tilemaps
- `Entity` - Grid-based sprites - `Entity` - Grid-based sprites
--- ---
## Basic Rendering ## Basic Rendering
### Creating UI Elements ### Creating UI Elements
```python ```python
import mcrfpy import mcrfpy
# Create scene # Create scene
mcrfpy.createScene("game") mcrfpy.createScene("game")
# Rectangle/Frame # Rectangle/Frame
frame = mcrfpy.Frame(100, 100, 200, 150) frame = mcrfpy.Frame(100, 100, 200, 150)
frame.fill_color = mcrfpy.Color(50, 50, 50) frame.fill_color = mcrfpy.Color(50, 50, 50)
frame.outline_color = mcrfpy.Color(255, 255, 255) frame.outline_color = mcrfpy.Color(255, 255, 255)
frame.outline_thickness = 2 frame.outline_thickness = 2
# Text # Text
label = mcrfpy.Caption((10, 10), "Hello World!") label = mcrfpy.Caption((10, 10), "Hello World!")
label.font_size = 24 label.font_size = 24
label.fill_color = mcrfpy.Color(255, 255, 255) label.fill_color = mcrfpy.Color(255, 255, 255)
# Sprite # Sprite
sprite = mcrfpy.Sprite("player.png", 50, 50) sprite = mcrfpy.Sprite("player.png", 50, 50)
sprite.scale_x = 2.0 sprite.scale_x = 2.0
sprite.scale_y = 2.0 sprite.scale_y = 2.0
# Add to scene # Add to scene
scene_ui = mcrfpy.sceneUI("game") scene_ui = mcrfpy.sceneUI("game")
scene_ui.append(frame) scene_ui.append(frame)
scene_ui.append(label) scene_ui.append(label)
scene_ui.append(sprite) scene_ui.append(sprite)
``` ```
--- ---
## Textures and Sprite Sheets ## Textures and Sprite Sheets
### Loading Textures ### Loading Textures
```python ```python
# Load single image # Load single image
texture = mcrfpy.createTexture("sprites/player.png") texture = mcrfpy.createTexture("sprites/player.png")
# Use with sprite # Use with sprite
sprite = mcrfpy.Sprite("dummy.png", 0, 0) # Path doesn't matter sprite = mcrfpy.Sprite("dummy.png", 0, 0) # Path doesn't matter
sprite.texture = texture sprite.texture = texture
``` ```
### Sprite Sheets ### Sprite Sheets
```python ```python
# Load sprite sheet (multiple sprites in one image) # Load sprite sheet (multiple sprites in one image)
sheet = mcrfpy.createTexture("spritesh eet.png") sheet = mcrfpy.createTexture("spritesh eet.png")
# Use specific sprite from sheet # Use specific sprite from sheet
sprite = mcrfpy.Sprite("dummy.png", 100, 100) sprite = mcrfpy.Sprite("dummy.png", 100, 100)
sprite.texture = sheet sprite.texture = sheet
sprite.sprite_index = 5 # Use 6th sprite (0-indexed) sprite.sprite_index = 5 # Use 6th sprite (0-indexed)
# Grid with tileset # Grid with tileset
grid = mcrfpy.Grid(50, 50, 16, 16) # Each tile is 16x16 grid = mcrfpy.Grid(50, 50, 16, 16) # Each tile is 16x16
grid.texture = mcrfpy.createTexture("tileset.png") grid.texture = mcrfpy.createTexture("tileset.png")
# Set tiles # Set tiles
for x in range(50): for x in range(50):
for y in range(50): for y in range(50):
grid.at((x, y)).tilesprite = 0 # Floor tile grid.at((x, y)).tilesprite = 0 # Floor tile
``` ```
--- ---
## Z-Order Layering ## Z-Order Layering
Control render order with `z_index` (higher = front): Control render order with `z_index` (higher = front):
```python ```python
# Background layer (z=0) # Background layer (z=0)
background = mcrfpy.Sprite("bg.png", 0, 0) background = mcrfpy.Sprite("bg.png", 0, 0)
background.z_index = 0 background.z_index = 0
# Game layer (z=10) # Game layer (z=10)
grid = mcrfpy.Grid(50, 50, 16, 16) grid = mcrfpy.Grid(50, 50, 16, 16)
grid.z_index = 10 grid.z_index = 10
# UI layer (z=100) # UI layer (z=100)
hud = mcrfpy.Frame(0, 0, 800, 50) hud = mcrfpy.Frame(0, 0, 800, 50)
hud.z_index = 100 hud.z_index = 100
# Add to scene (order doesn't matter, z_index controls rendering) # Add to scene (order doesn't matter, z_index controls rendering)
ui = mcrfpy.sceneUI("game") ui = mcrfpy.sceneUI("game")
ui.append(hud) ui.append(hud)
ui.append(background) ui.append(background)
ui.append(grid) ui.append(grid)
# Renders: background → grid → hud # Renders: background → grid → hud
``` ```
**Implementation:** Automatic sorting by z_index in `src/Scene.cpp::render()` **Implementation:** Automatic sorting by z_index in `src/Scene.cpp::render()`
--- ---
## Colors ## Colors
### Color Creation ### Color Creation
```python ```python
# RGB # RGB
red = mcrfpy.Color(255, 0, 0) red = mcrfpy.Color(255, 0, 0)
# RGBA (with alpha/transparency) # RGBA (with alpha/transparency)
semi_transparent = mcrfpy.Color(255, 255, 255, 128) semi_transparent = mcrfpy.Color(255, 255, 255, 128)
# Access components # Access components
color = mcrfpy.Color(100, 150, 200, 255) color = mcrfpy.Color(100, 150, 200, 255)
print(f"R: {color.r}, G: {color.g}, B: {color.b}, A: {color.a}") print(f"R: {color.r}, G: {color.g}, B: {color.b}, A: {color.a}")
``` ```
### Color Application ### Color Application
```python ```python
# Frame colors # Frame colors
frame.fill_color = mcrfpy.Color(50, 50, 50) frame.fill_color = mcrfpy.Color(50, 50, 50)
frame.outline_color = mcrfpy.Color(255, 255, 255) frame.outline_color = mcrfpy.Color(255, 255, 255)
# Text color # Text color
caption.fill_color = mcrfpy.Color(255, 255, 0) # Yellow text caption.fill_color = mcrfpy.Color(255, 255, 0) # Yellow text
# Grid point colors # Grid point colors
grid.at((x, y)).color = mcrfpy.Color(255, 0, 0) # Red tint grid.at((x, y)).color = mcrfpy.Color(255, 0, 0) # Red tint
# Opacity # Opacity
sprite.opacity = 0.5 # 50% transparent sprite.opacity = 0.5 # 50% transparent
``` ```
--- ---
## Visual Effects ## Visual Effects
### Animations ### Animations
See [[Animation-System]] for complete animation documentation. See [[Animation-System]] for complete animation documentation.
```python ```python
# Fade in # Fade in
mcrfpy.animate(sprite, "opacity", 1.0, 1000, "ease_in_quad") mcrfpy.animate(sprite, "opacity", 1.0, 1000, "ease_in_quad")
# Color transition # Color transition
mcrfpy.animate(frame, "fill_color", mcrfpy.Color(255, 0, 0), 500, "linear") mcrfpy.animate(frame, "fill_color", mcrfpy.Color(255, 0, 0), 500, "linear")
# Movement # Movement
mcrfpy.animate(entity, "x", target_x, 300, "ease_out_cubic") mcrfpy.animate(entity, "x", target_x, 300, "ease_out_cubic")
mcrfpy.animate(entity, "y", target_y, 300, "ease_out_cubic") mcrfpy.animate(entity, "y", target_y, 300, "ease_out_cubic")
# Scaling # Scaling
mcrfpy.animate(sprite, "scale_x", 2.0, 200, "bounce_out") mcrfpy.animate(sprite, "scale_x", 2.0, 200, "bounce_out")
``` ```
### Visibility ### Visibility
```python ```python
# Show/hide elements # Show/hide elements
sprite.visible = False # Hidden sprite.visible = False # Hidden
sprite.visible = True # Visible sprite.visible = True # Visible
# Opacity # Opacity
sprite.opacity = 0.0 # Invisible sprite.opacity = 0.0 # Invisible
sprite.opacity = 0.5 # Semi-transparent sprite.opacity = 0.5 # Semi-transparent
sprite.opacity = 1.0 # Opaque sprite.opacity = 1.0 # Opaque
``` ```
--- ---
## Common Patterns ## Common Patterns
### HUD/UI Overlay ### HUD/UI Overlay
```python ```python
def create_hud(): def create_hud():
# HUD container # HUD container
hud = mcrfpy.Frame(0, 0, 800, 60) hud = mcrfpy.Frame(0, 0, 800, 60)
hud.fill_color = mcrfpy.Color(30, 30, 30, 200) hud.fill_color = mcrfpy.Color(30, 30, 30, 200)
hud.z_index = 100 # Front layer hud.z_index = 100 # Front layer
# Health text # Health text
health_label = mcrfpy.Caption((10, 10), "HP: 100/100") health_label = mcrfpy.Caption((10, 10), "HP: 100/100")
health_label.font_size = 18 health_label.font_size = 18
health_label.fill_color = mcrfpy.Color(255, 255, 255) health_label.fill_color = mcrfpy.Color(255, 255, 255)
hud.children.append(health_label) hud.children.append(health_label)
return hud, health_label return hud, health_label
# Update HUD # Update HUD
def update_hud(health_label, current_hp, max_hp): def update_hud(health_label, current_hp, max_hp):
health_label.text = f"HP: {current_hp}/{max_hp}" health_label.text = f"HP: {current_hp}/{max_hp}"
# Color code health # Color code health
if current_hp < max_hp * 0.3: if current_hp < max_hp * 0.3:
health_label.fill_color = mcrfpy.Color(255, 0, 0) # Red health_label.fill_color = mcrfpy.Color(255, 0, 0) # Red
elif current_hp < max_hp * 0.6: elif current_hp < max_hp * 0.6:
health_label.fill_color = mcrfpy.Color(255, 255, 0) # Yellow health_label.fill_color = mcrfpy.Color(255, 255, 0) # Yellow
else: else:
health_label.fill_color = mcrfpy.Color(0, 255, 0) # Green health_label.fill_color = mcrfpy.Color(0, 255, 0) # Green
``` ```
### Particle-Like Effects ### Particle-Like Effects
```python ```python
def create_explosion(x, y): def create_explosion(x, y):
"""Create explosion effect using animated sprites.""" """Create explosion effect using animated sprites."""
particles = [] particles = []
for i in range(10): for i in range(10):
particle = mcrfpy.Sprite("particle.png", x, y) particle = mcrfpy.Sprite("particle.png", x, y)
particle.z_index = 50 particle.z_index = 50
# Random direction # Random direction
import random import random
target_x = x + random.randint(-50, 50) target_x = x + random.randint(-50, 50)
target_y = y + random.randint(-50, 50) target_y = y + random.randint(-50, 50)
# Animate outward # Animate outward
mcrfpy.animate(particle, "x", target_x, 500, "ease_out_quad") mcrfpy.animate(particle, "x", target_x, 500, "ease_out_quad")
mcrfpy.animate(particle, "y", target_y, 500, "ease_out_quad") mcrfpy.animate(particle, "y", target_y, 500, "ease_out_quad")
mcrfpy.animate(particle, "opacity", 0.0, 500, "linear") mcrfpy.animate(particle, "opacity", 0.0, 500, "linear")
particles.append(particle) particles.append(particle)
mcrfpy.sceneUI("game").append(particle) mcrfpy.sceneUI("game").append(particle)
# Remove after animation # Remove after animation
def cleanup(runtime_ms): def cleanup(runtime_ms):
for p in particles: for p in particles:
mcrfpy.sceneUI("game").remove(p) mcrfpy.sceneUI("game").remove(p)
mcrfpy.setTimer("explosion_cleanup", cleanup, 600) mcrfpy.setTimer("explosion_cleanup", cleanup, 600)
``` ```
### Health Bars ### Health Bars
```python ```python
class HealthBar: class HealthBar:
def __init__(self, x, y, width, height, max_hp): def __init__(self, x, y, width, height, max_hp):
self.max_hp = max_hp self.max_hp = max_hp
self.current_hp = max_hp self.current_hp = max_hp
# Background (red) # Background (red)
self.bg = mcrfpy.Frame(x, y, width, height) self.bg = mcrfpy.Frame(x, y, width, height)
self.bg.fill_color = mcrfpy.Color(255, 0, 0) self.bg.fill_color = mcrfpy.Color(255, 0, 0)
self.bg.z_index = 90 self.bg.z_index = 90
# Foreground (green) # Foreground (green)
self.fg = mcrfpy.Frame(x, y, width, height) self.fg = mcrfpy.Frame(x, y, width, height)
self.fg.fill_color = mcrfpy.Color(0, 255, 0) self.fg.fill_color = mcrfpy.Color(0, 255, 0)
self.fg.z_index = 91 self.fg.z_index = 91
def set_hp(self, current): def set_hp(self, current):
self.current_hp = max(0, min(current, self.max_hp)) self.current_hp = max(0, min(current, self.max_hp))
# Scale foreground to represent HP # Scale foreground to represent HP
ratio = self.current_hp / self.max_hp ratio = self.current_hp / self.max_hp
target_width = int(self.bg.w * ratio) target_width = int(self.bg.w * ratio)
# Animate width change # Animate width change
mcrfpy.animate(self.fg, "w", target_width, 200, "ease_out_quad") mcrfpy.animate(self.fg, "w", target_width, 200, "ease_out_quad")
# Color code # Color code
if ratio < 0.3: if ratio < 0.3:
self.fg.fill_color = mcrfpy.Color(255, 0, 0) self.fg.fill_color = mcrfpy.Color(255, 0, 0)
elif ratio < 0.6: elif ratio < 0.6:
self.fg.fill_color = mcrfpy.Color(255, 255, 0) self.fg.fill_color = mcrfpy.Color(255, 255, 0)
``` ```
--- ---
## Grid Rendering ## Grid Rendering
See [[Grid-System]] for complete grid documentation. See [[Grid-System]] for complete grid documentation.
### Basic Grid ### Basic Grid
```python ```python
# Create grid # Create grid
grid = mcrfpy.Grid(50, 50, 16, 16) grid = mcrfpy.Grid(50, 50, 16, 16)
grid.texture = mcrfpy.createTexture("tiles.png") grid.texture = mcrfpy.createTexture("tiles.png")
grid.pos = (100, 100) grid.pos = (100, 100)
# Set tiles # Set tiles
for x in range(50): for x in range(50):
for y in range(50): for y in range(50):
if x == 0 or x == 49 or y == 0 or y == 49: if x == 0 or x == 49 or y == 0 or y == 49:
grid.at((x, y)).tilesprite = 1 # Wall grid.at((x, y)).tilesprite = 1 # Wall
else: else:
grid.at((x, y)).tilesprite = 0 # Floor grid.at((x, y)).tilesprite = 0 # Floor
``` ```
### Grid Colors ### Grid Colors
```python ```python
# Tint specific tiles # Tint specific tiles
grid.at((10, 10)).color = mcrfpy.Color(255, 0, 0) # Red highlight grid.at((10, 10)).color = mcrfpy.Color(255, 0, 0) # Red highlight
# Background color # Background color
grid.background_color = mcrfpy.Color(8, 8, 8) # Dark background grid.background_color = mcrfpy.Color(8, 8, 8) # Dark background
``` ```
### Grid Viewport ### Grid Viewport
```python ```python
# Zoom # Zoom
grid.zoom = 2.0 # 2x zoom grid.zoom = 2.0 # 2x zoom
# Pan/scroll # Pan/scroll
grid.left_edge = 10 # Start viewing from tile (10, 0) grid.left_edge = 10 # Start viewing from tile (10, 0)
grid.top_edge = 5 # Start viewing from tile (0, 5) grid.top_edge = 5 # Start viewing from tile (0, 5)
# Animate viewport # Animate viewport
mcrfpy.animate(grid, "zoom", 1.5, 1000, "ease_in_out_quad") mcrfpy.animate(grid, "zoom", 1.5, 1000, "ease_in_out_quad")
mcrfpy.animate(grid, "left_edge", 20, 1000, "ease_in_out_quad") mcrfpy.animate(grid, "left_edge", 20, 1000, "ease_in_out_quad")
``` ```
--- ---
## Performance Tips ## Performance Tips
### Minimize Draw Calls ### Minimize Draw Calls
```python ```python
# Good: Group related UI in Frames # Good: Group related UI in Frames
hud_frame = mcrfpy.Frame(0, 0, 800, 600) hud_frame = mcrfpy.Frame(0, 0, 800, 600)
hud_frame.children.append(label1) hud_frame.children.append(label1)
hud_frame.children.append(label2) hud_frame.children.append(label2)
hud_frame.children.append(label3) hud_frame.children.append(label3)
# Avoid: Many top-level UI elements # Avoid: Many top-level UI elements
# (Each top-level element is a separate draw call) # (Each top-level element is a separate draw call)
``` ```
### Use Visibility ### Use Visibility
```python ```python
# Hide off-screen elements # Hide off-screen elements
for element in all_elements: for element in all_elements:
if not in_viewport(element): if not in_viewport(element):
element.visible = False element.visible = False
``` ```
### Sprite Sheet Benefits ### Sprite Sheet Benefits
```python ```python
# Good: One texture, many sprites # Good: One texture, many sprites
texture = mcrfpy.createTexture("all_sprites.png") texture = mcrfpy.createTexture("all_sprites.png")
for i in range(100): for i in range(100):
sprite = mcrfpy.Sprite("dummy.png", x, y) sprite = mcrfpy.Sprite("dummy.png", x, y)
sprite.texture = texture # Reuse texture sprite.texture = texture # Reuse texture
sprite.sprite_index = i sprite.sprite_index = i
# Avoid: Loading same texture multiple times # Avoid: Loading same texture multiple times
# (Wastes memory and loading time) # (Wastes memory and loading time)
``` ```
--- ---
## Related Documentation ## Related Documentation
- [[UI-Component-Hierarchy]] - UI element details - [[UI-Component-Hierarchy]] - UI element details
- [[Grid-System]] - Grid rendering details - [[Grid-System]] - Grid rendering details
- [[Animation-System]] - Animating visual properties - [[Animation-System]] - Animating visual properties
- [[Performance-and-Profiling]] - Rendering performance - [[Performance-and-Profiling]] - Rendering performance
**API Reference:** [mcrfpy UI Classes](../../docs/api_reference_dynamic.html) **API Reference:** [mcrfpy UI Classes](../../docs/api_reference_dynamic.html)