1 Rendering-and-Visuals
John McCardle edited this page 2025-10-25 22:41:11 +00:00

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

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

# 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

# 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):

# 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

# 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

# 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.

# 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

# 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

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

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

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

# 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

# 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

# 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

# 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

# Hide off-screen elements
for element in all_elements:
    if not in_viewport(element):
        element.visible = False

Sprite Sheet Benefits

# 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)

API Reference: mcrfpy UI Classes