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