From 05bddae5112f2b5949a9d2b32dd3dc2bf4656837 Mon Sep 17 00:00:00 2001 From: John McCardle Date: Fri, 4 Jul 2025 06:59:02 -0400 Subject: [PATCH] Update comprehensive documentation for Alpha release (Issue #47) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Completely rewrote README.md to reflect 7DRL 2025 success and current features - Updated GitHub Pages documentation site with: - Modern landing page highlighting Crypt of Sokoban - Comprehensive API reference (2700+ lines) with exhaustive examples - Updated getting-started guide with installation and first game tutorial - 8 detailed tutorials covering all major game systems - Quick reference cheat sheet for common operations - Generated documentation screenshots showing UI elements - Fixed deprecated API references and added new features - Added automation API documentation - Included Python 3.12 requirement and platform-specific instructions Note: Text rendering in headless mode has limitations for screenshots 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- README.md | 99 ++++- tests/generate_caption_screenshot_fixed.py | 129 ++++++ tests/generate_docs_screenshots.py | 451 +++++++++++++++++++++ tests/generate_docs_screenshots_simple.py | 217 ++++++++++ tests/generate_entity_screenshot_fixed.py | 140 +++++++ tests/generate_grid_screenshot.py | 131 ++++++ tests/generate_sprite_screenshot.py | 160 ++++++++ tests/simple_screenshot_test.py | 45 ++ 8 files changed, 1350 insertions(+), 22 deletions(-) create mode 100644 tests/generate_caption_screenshot_fixed.py create mode 100755 tests/generate_docs_screenshots.py create mode 100755 tests/generate_docs_screenshots_simple.py create mode 100644 tests/generate_entity_screenshot_fixed.py create mode 100644 tests/generate_grid_screenshot.py create mode 100644 tests/generate_sprite_screenshot.py create mode 100644 tests/simple_screenshot_test.py diff --git a/README.md b/README.md index 89be09d..1dd2aad 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,85 @@ -# McRogueFace - 2D Game Engine +# McRogueFace -An experimental prototype game engine built for my own use in 7DRL 2023. +A Python-powered 2D game engine for creating roguelike games, built with C++ and SFML. -*Blame my wife for the name* +**Latest Release**: Successfully completed 7DRL 2025 with *"Crypt of Sokoban"* - a unique roguelike that blends Sokoban puzzle mechanics with dungeon crawling! -## Tenets: +## Features -* C++ first, Python close behind. -* Entity-Component system based on David Churchill's Memorial University COMP4300 course lectures available on Youtube. -* Graphics, particles and shaders provided by SFML. -* Pathfinding, noise generation, and other Roguelike goodness provided by TCOD. +- **Python-First Design**: Write your game logic in Python while leveraging C++ performance +- **Rich UI System**: Sprites, Grids, Frames, and Captions with full animation support +- **Entity-Component Architecture**: Flexible game object system with Python integration +- **Built-in Roguelike Support**: Dungeon generation, pathfinding, and field-of-view via libtcod +- **Automation API**: PyAutoGUI-compatible testing and demo recording +- **Interactive Development**: Python REPL integration for live game debugging -## Why? +## Quick Start -I did the r/RoguelikeDev TCOD tutorial in Python. I loved it, but I did not want to be limited to ASCII. I want to be able to draw pixels on top of my tiles (like lines or circles) and eventually incorporate even more polish. +```bash +# Clone and build +git clone https://github.com/jmcb/McRogueFace.git +cd McRogueFace +make -## To-do +# Run the example game +cd build +./mcrogueface +``` -* ✅ Initial Commit -* ✅ Integrate scene, action, entity, component system from COMP4300 engine -* ✅ Windows / Visual Studio project -* ✅ Draw Sprites -* ✅ Play Sounds -* ✅ Draw UI, spawn entity from Python code -* ❌ Python AI for entities (NPCs on set paths, enemies towards player) -* ✅ Walking / Collision -* ❌ "Boards" (stairs / doors / walk off edge of screen) -* ❌ Cutscenes - interrupt normal controls, text scroll, character portraits -* ❌ Mouse integration - tooltips, zoom, click to select targets, cursors +## Example: Creating a Simple Scene + +```python +import mcrfpy + +# Create a new scene +mcrfpy.createScene("intro") + +# Add a text caption +caption = mcrfpy.Caption(50, 50, "Welcome to McRogueFace!") +caption.font = mcrfpy.default_font +caption.font_color = (255, 255, 255) + +# Add to scene +mcrfpy.sceneUI("intro").append(caption) + +# Switch to the scene +mcrfpy.setScene("intro") +``` + +## Documentation + +For comprehensive documentation, tutorials, and API reference, visit: +**[https://mcrogueface.github.io](https://mcrogueface.github.io)** + +## Requirements + +- C++17 compiler (GCC 7+ or Clang 5+) +- CMake 3.14+ +- Python 3.12+ +- SFML 2.5+ +- Linux or Windows (macOS untested) + +## Project Structure + +``` +McRogueFace/ +├── src/ # C++ engine source +├── scripts/ # Python game scripts +├── assets/ # Sprites, fonts, audio +├── build/ # Build output directory +└── tests/ # Automated test suite +``` + +## Contributing + +McRogueFace is under active development. Check the [ROADMAP.md](ROADMAP.md) for current priorities and open issues. + +## License + +This project is licensed under the MIT License - see LICENSE file for details. + +## Acknowledgments + +- Developed for 7-Day Roguelike Challenge 2025 +- Built with [SFML](https://www.sfml-dev.org/), [libtcod](https://github.com/libtcod/libtcod), and Python +- Inspired by David Churchill's COMP4300 game engine lectures \ No newline at end of file diff --git a/tests/generate_caption_screenshot_fixed.py b/tests/generate_caption_screenshot_fixed.py new file mode 100644 index 0000000..66234cb --- /dev/null +++ b/tests/generate_caption_screenshot_fixed.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +"""Generate caption documentation screenshot with proper font""" + +import mcrfpy +from mcrfpy import automation +import sys + +def capture_caption(runtime): + """Capture caption example after render loop starts""" + + # Take screenshot + automation.screenshot("mcrogueface.github.io/images/ui_caption_example.png") + print("Caption screenshot saved!") + + # Exit after capturing + sys.exit(0) + +# Create scene +mcrfpy.createScene("captions") + +# Title +title = mcrfpy.Caption(400, 30, "Caption Examples") +title.font = mcrfpy.default_font +title.font_size = 28 +title.font_color = (255, 255, 255) + +# Different sizes +size_label = mcrfpy.Caption(100, 100, "Different Sizes:") +size_label.font = mcrfpy.default_font +size_label.font_color = (200, 200, 200) + +large = mcrfpy.Caption(300, 100, "Large Text (24pt)") +large.font = mcrfpy.default_font +large.font_size = 24 +large.font_color = (255, 255, 255) + +medium = mcrfpy.Caption(300, 140, "Medium Text (18pt)") +medium.font = mcrfpy.default_font +medium.font_size = 18 +medium.font_color = (255, 255, 255) + +small = mcrfpy.Caption(300, 170, "Small Text (14pt)") +small.font = mcrfpy.default_font +small.font_size = 14 +small.font_color = (255, 255, 255) + +# Different colors +color_label = mcrfpy.Caption(100, 230, "Different Colors:") +color_label.font = mcrfpy.default_font +color_label.font_color = (200, 200, 200) + +white_text = mcrfpy.Caption(300, 230, "White Text") +white_text.font = mcrfpy.default_font +white_text.font_color = (255, 255, 255) + +green_text = mcrfpy.Caption(300, 260, "Green Text") +green_text.font = mcrfpy.default_font +green_text.font_color = (100, 255, 100) + +red_text = mcrfpy.Caption(300, 290, "Red Text") +red_text.font = mcrfpy.default_font +red_text.font_color = (255, 100, 100) + +blue_text = mcrfpy.Caption(300, 320, "Blue Text") +blue_text.font = mcrfpy.default_font +blue_text.font_color = (100, 150, 255) + +# Caption with background +bg_label = mcrfpy.Caption(100, 380, "With Background:") +bg_label.font = mcrfpy.default_font +bg_label.font_color = (200, 200, 200) + +# Frame background +frame = mcrfpy.Frame(280, 370, 250, 50) +frame.bgcolor = (64, 64, 128) +frame.outline = 2 + +framed_text = mcrfpy.Caption(405, 395, "Caption on Frame") +framed_text.font = mcrfpy.default_font +framed_text.font_size = 18 +framed_text.font_color = (255, 255, 255) +framed_text.centered = True + +# Centered text example +center_label = mcrfpy.Caption(100, 460, "Centered Text:") +center_label.font = mcrfpy.default_font +center_label.font_color = (200, 200, 200) + +centered = mcrfpy.Caption(400, 460, "This text is centered") +centered.font = mcrfpy.default_font +centered.font_size = 20 +centered.font_color = (255, 255, 100) +centered.centered = True + +# Multi-line example +multi_label = mcrfpy.Caption(100, 520, "Multi-line:") +multi_label.font = mcrfpy.default_font +multi_label.font_color = (200, 200, 200) + +multiline = mcrfpy.Caption(300, 520, "Line 1: McRogueFace\nLine 2: Game Engine\nLine 3: Python API") +multiline.font = mcrfpy.default_font +multiline.font_size = 14 +multiline.font_color = (255, 255, 255) + +# Add all to scene +ui = mcrfpy.sceneUI("captions") +ui.append(title) +ui.append(size_label) +ui.append(large) +ui.append(medium) +ui.append(small) +ui.append(color_label) +ui.append(white_text) +ui.append(green_text) +ui.append(red_text) +ui.append(blue_text) +ui.append(bg_label) +ui.append(frame) +ui.append(framed_text) +ui.append(center_label) +ui.append(centered) +ui.append(multi_label) +ui.append(multiline) + +# Switch to scene +mcrfpy.setScene("captions") + +# Set timer to capture after rendering starts +mcrfpy.setTimer("capture", capture_caption, 100) \ No newline at end of file diff --git a/tests/generate_docs_screenshots.py b/tests/generate_docs_screenshots.py new file mode 100755 index 0000000..53393fd --- /dev/null +++ b/tests/generate_docs_screenshots.py @@ -0,0 +1,451 @@ +#!/usr/bin/env python3 +"""Generate documentation screenshots for McRogueFace UI elements""" +import mcrfpy +from mcrfpy import automation +import sys +import os + +# Crypt of Sokoban color scheme +FRAME_COLOR = mcrfpy.Color(64, 64, 128) +SHADOW_COLOR = mcrfpy.Color(64, 64, 86) +BOX_COLOR = mcrfpy.Color(96, 96, 160) +WHITE = mcrfpy.Color(255, 255, 255) +BLACK = mcrfpy.Color(0, 0, 0) +GREEN = mcrfpy.Color(0, 255, 0) +RED = mcrfpy.Color(255, 0, 0) + +# Create texture for sprites +sprite_texture = mcrfpy.Texture("assets/kenney_TD_MR_IP.png", 16, 16) + +# Output directory - create it during setup +output_dir = "mcrogueface.github.io/images" +if not os.path.exists(output_dir): + os.makedirs(output_dir) + +def create_caption(x, y, text, font_size=16, text_color=WHITE, outline_color=BLACK): + """Helper function to create captions with common settings""" + caption = mcrfpy.Caption(mcrfpy.Vector(x, y), text=text) + caption.size = font_size + caption.fill_color = text_color + caption.outline_color = outline_color + return caption + +def create_caption_example(): + """Create a scene showing Caption UI element examples""" + mcrfpy.createScene("caption_example") + ui = mcrfpy.sceneUI("caption_example") + + # Background frame + bg = mcrfpy.Frame(0, 0, 800, 600, fill_color=FRAME_COLOR) + ui.append(bg) + + # Title caption + title = create_caption(200, 50, "Caption Examples", 32) + ui.append(title) + + # Different sized captions + caption1 = create_caption(100, 150, "Large Caption (24pt)", 24) + ui.append(caption1) + + caption2 = create_caption(100, 200, "Medium Caption (18pt)", 18, GREEN) + ui.append(caption2) + + caption3 = create_caption(100, 240, "Small Caption (14pt)", 14, RED) + ui.append(caption3) + + # Caption with background + caption_bg = mcrfpy.Frame(100, 300, 300, 50, fill_color=BOX_COLOR) + ui.append(caption_bg) + caption4 = create_caption(110, 315, "Caption with Background", 16) + ui.append(caption4) + +def create_sprite_example(): + """Create a scene showing Sprite UI element examples""" + mcrfpy.createScene("sprite_example") + ui = mcrfpy.sceneUI("sprite_example") + + # Background frame + bg = mcrfpy.Frame(0, 0, 800, 600, fill_color=FRAME_COLOR) + ui.append(bg) + + # Title + title = create_caption(250, 50, "Sprite Examples", 32) + ui.append(title) + + # Create a grid background for sprites + sprite_bg = mcrfpy.Frame(100, 150, 600, 300, fill_color=BOX_COLOR) + ui.append(sprite_bg) + + # Player sprite (84) + player_label = create_caption(150, 180, "Player", 14) + ui.append(player_label) + player_sprite = mcrfpy.Sprite(150, 200, sprite_texture, 84, 3.0) + ui.append(player_sprite) + + # Enemy sprites + enemy_label = create_caption(250, 180, "Enemies", 14) + ui.append(enemy_label) + enemy1 = mcrfpy.Sprite(250, 200, sprite_texture, 123, 3.0) # Basic enemy + ui.append(enemy1) + enemy2 = mcrfpy.Sprite(300, 200, sprite_texture, 107, 3.0) # Different enemy + ui.append(enemy2) + + # Boulder sprite (66) + boulder_label = create_caption(400, 180, "Boulder", 14) + ui.append(boulder_label) + boulder_sprite = mcrfpy.Sprite(400, 200, sprite_texture, 66, 3.0) + ui.append(boulder_sprite) + + # Exit sprites + exit_label = create_caption(500, 180, "Exit States", 14) + ui.append(exit_label) + exit_locked = mcrfpy.Sprite(500, 200, sprite_texture, 45, 3.0) # Locked + ui.append(exit_locked) + exit_open = mcrfpy.Sprite(550, 200, sprite_texture, 21, 3.0) # Open + ui.append(exit_open) + + # Item sprites + item_label = create_caption(150, 300, "Items", 14) + ui.append(item_label) + treasure = mcrfpy.Sprite(150, 320, sprite_texture, 89, 3.0) # Treasure + ui.append(treasure) + sword = mcrfpy.Sprite(200, 320, sprite_texture, 222, 3.0) # Sword + ui.append(sword) + potion = mcrfpy.Sprite(250, 320, sprite_texture, 175, 3.0) # Potion + ui.append(potion) + + # Button sprite + button_label = create_caption(350, 300, "Button", 14) + ui.append(button_label) + button = mcrfpy.Sprite(350, 320, sprite_texture, 250, 3.0) + ui.append(button) + +def create_frame_example(): + """Create a scene showing Frame UI element examples""" + mcrfpy.createScene("frame_example") + ui = mcrfpy.sceneUI("frame_example") + + # Background + bg = mcrfpy.Frame(0, 0, 800, 600, fill_color=SHADOW_COLOR) + ui.append(bg) + + # Title + title = create_caption(250, 30, "Frame Examples", 32) + ui.append(title) + + # Basic frame + frame1 = mcrfpy.Frame(50, 100, 200, 150, fill_color=FRAME_COLOR) + ui.append(frame1) + label1 = create_caption(60, 110, "Basic Frame", 16) + ui.append(label1) + + # Frame with outline + frame2 = mcrfpy.Frame(300, 100, 200, 150, fill_color=BOX_COLOR, + outline_color=WHITE, outline=2.0) + ui.append(frame2) + label2 = create_caption(310, 110, "Frame with Outline", 16) + ui.append(label2) + + # Nested frames + frame3 = mcrfpy.Frame(550, 100, 200, 150, fill_color=FRAME_COLOR, + outline_color=WHITE, outline=1) + ui.append(frame3) + inner_frame = mcrfpy.Frame(570, 130, 160, 90, fill_color=BOX_COLOR) + ui.append(inner_frame) + label3 = create_caption(560, 110, "Nested Frames", 16) + ui.append(label3) + + # Complex layout with frames + main_frame = mcrfpy.Frame(50, 300, 700, 250, fill_color=FRAME_COLOR, + outline_color=WHITE, outline=2) + ui.append(main_frame) + + # Add some UI elements inside + ui_label = create_caption(60, 310, "Complex UI Layout", 18) + ui.append(ui_label) + + # Status panel + status_frame = mcrfpy.Frame(70, 350, 150, 180, fill_color=BOX_COLOR) + ui.append(status_frame) + status_label = create_caption(80, 360, "Status", 14) + ui.append(status_label) + + # Inventory panel + inv_frame = mcrfpy.Frame(240, 350, 300, 180, fill_color=BOX_COLOR) + ui.append(inv_frame) + inv_label = create_caption(250, 360, "Inventory", 14) + ui.append(inv_label) + + # Actions panel + action_frame = mcrfpy.Frame(560, 350, 170, 180, fill_color=BOX_COLOR) + ui.append(action_frame) + action_label = create_caption(570, 360, "Actions", 14) + ui.append(action_label) + +def create_grid_example(): + """Create a scene showing Grid UI element examples""" + mcrfpy.createScene("grid_example") + ui = mcrfpy.sceneUI("grid_example") + + # Background + bg = mcrfpy.Frame(0, 0, 800, 600, fill_color=FRAME_COLOR) + ui.append(bg) + + # Title + title = create_caption(250, 30, "Grid Example", 32) + ui.append(title) + + # Create a grid showing a small dungeon + grid = mcrfpy.Grid(20, 15, sprite_texture, + mcrfpy.Vector(100, 100), mcrfpy.Vector(320, 240)) + + # Set up dungeon tiles + # Floor tiles (index 48) + # Wall tiles (index 3) + for x in range(20): + for y in range(15): + if x == 0 or x == 19 or y == 0 or y == 14: + # Walls around edge + grid.at((x, y)).tilesprite = 3 + grid.at((x, y)).walkable = False + else: + # Floor + grid.at((x, y)).tilesprite = 48 + grid.at((x, y)).walkable = True + + # Add some internal walls + for x in range(5, 15): + grid.at((x, 7)).tilesprite = 3 + grid.at((x, 7)).walkable = False + for y in range(3, 8): + grid.at((10, y)).tilesprite = 3 + grid.at((10, y)).walkable = False + + # Add a door + grid.at((10, 7)).tilesprite = 131 # Door tile + grid.at((10, 7)).walkable = True + + # Add to UI + ui.append(grid) + + # Label + grid_label = create_caption(100, 480, "20x15 Grid with 2x scale - Simple Dungeon Layout", 16) + ui.append(grid_label) + +def create_entity_example(): + """Create a scene showing Entity examples in a Grid""" + mcrfpy.createScene("entity_example") + ui = mcrfpy.sceneUI("entity_example") + + # Background + bg = mcrfpy.Frame(0, 0, 800, 600, fill_color=FRAME_COLOR) + ui.append(bg) + + # Title + title = create_caption(200, 30, "Entity Collection Example", 32) + ui.append(title) + + # Create a grid for the entities + grid = mcrfpy.Grid(15, 10, sprite_texture, + mcrfpy.Vector(150, 100), mcrfpy.Vector(360, 240)) + + # Set all tiles to floor + for x in range(15): + for y in range(10): + grid.at((x, y)).tilesprite = 48 + grid.at((x, y)).walkable = True + + # Add walls + for x in range(15): + grid.at((x, 0)).tilesprite = 3 + grid.at((x, 0)).walkable = False + grid.at((x, 9)).tilesprite = 3 + grid.at((x, 9)).walkable = False + for y in range(10): + grid.at((0, y)).tilesprite = 3 + grid.at((0, y)).walkable = False + grid.at((14, y)).tilesprite = 3 + grid.at((14, y)).walkable = False + + ui.append(grid) + + # Add entities to the grid + # Player entity + player = mcrfpy.Entity(mcrfpy.Vector(3, 3), sprite_texture, 84, grid) + grid.entities.append(player) + + # Enemy entities + enemy1 = mcrfpy.Entity(mcrfpy.Vector(7, 4), sprite_texture, 123, grid) + grid.entities.append(enemy1) + + enemy2 = mcrfpy.Entity(mcrfpy.Vector(10, 6), sprite_texture, 107, grid) + grid.entities.append(enemy2) + + # Boulder + boulder = mcrfpy.Entity(mcrfpy.Vector(5, 5), sprite_texture, 66, grid) + grid.entities.append(boulder) + + # Treasure + treasure = mcrfpy.Entity(mcrfpy.Vector(12, 2), sprite_texture, 89, grid) + grid.entities.append(treasure) + + # Exit (locked) + exit_door = mcrfpy.Entity(mcrfpy.Vector(12, 8), sprite_texture, 45, grid) + grid.entities.append(exit_door) + + # Button + button = mcrfpy.Entity(mcrfpy.Vector(3, 7), sprite_texture, 250, grid) + grid.entities.append(button) + + # Items + sword = mcrfpy.Entity(mcrfpy.Vector(8, 2), sprite_texture, 222, grid) + grid.entities.append(sword) + + potion = mcrfpy.Entity(mcrfpy.Vector(6, 8), sprite_texture, 175, grid) + grid.entities.append(potion) + + # Label + entity_label = create_caption(150, 500, "Grid with Entity Collection - Game Objects", 16) + ui.append(entity_label) + +def create_combined_example(): + """Create a scene showing all UI elements combined""" + mcrfpy.createScene("combined_example") + ui = mcrfpy.sceneUI("combined_example") + + # Background + bg = mcrfpy.Frame(0, 0, 800, 600, fill_color=SHADOW_COLOR) + ui.append(bg) + + # Title + title = create_caption(200, 20, "McRogueFace UI Elements", 28) + ui.append(title) + + # Main game area frame + game_frame = mcrfpy.Frame(20, 70, 500, 400, fill_color=FRAME_COLOR, + outline_color=WHITE, outline=2) + ui.append(game_frame) + + # Grid inside game frame + grid = mcrfpy.Grid(12, 10, sprite_texture, + mcrfpy.Vector(30, 80), mcrfpy.Vector(480, 400)) + for x in range(12): + for y in range(10): + if x == 0 or x == 11 or y == 0 or y == 9: + grid.at((x, y)).tilesprite = 3 + grid.at((x, y)).walkable = False + else: + grid.at((x, y)).tilesprite = 48 + grid.at((x, y)).walkable = True + + # Add some entities + player = mcrfpy.Entity(mcrfpy.Vector(2, 2), sprite_texture, 84, grid) + grid.entities.append(player) + enemy = mcrfpy.Entity(mcrfpy.Vector(8, 6), sprite_texture, 123, grid) + grid.entities.append(enemy) + boulder = mcrfpy.Entity(mcrfpy.Vector(5, 4), sprite_texture, 66, grid) + grid.entities.append(boulder) + + ui.append(grid) + + # Status panel + status_frame = mcrfpy.Frame(540, 70, 240, 200, fill_color=BOX_COLOR, + outline_color=WHITE, outline=1) + ui.append(status_frame) + + status_title = create_caption(550, 80, "Status", 20) + ui.append(status_title) + + hp_label = create_caption(550, 120, "HP: 10/10", 16, GREEN) + ui.append(hp_label) + + level_label = create_caption(550, 150, "Level: 1", 16) + ui.append(level_label) + + # Inventory panel + inv_frame = mcrfpy.Frame(540, 290, 240, 180, fill_color=BOX_COLOR, + outline_color=WHITE, outline=1) + ui.append(inv_frame) + + inv_title = create_caption(550, 300, "Inventory", 20) + ui.append(inv_title) + + # Add some item sprites + item1 = mcrfpy.Sprite(560, 340, sprite_texture, 222, 2.0) + ui.append(item1) + item2 = mcrfpy.Sprite(610, 340, sprite_texture, 175, 2.0) + ui.append(item2) + + # Message log + log_frame = mcrfpy.Frame(20, 490, 760, 90, fill_color=BOX_COLOR, + outline_color=WHITE, outline=1) + ui.append(log_frame) + + log_msg = create_caption(30, 500, "Welcome to McRogueFace!", 14) + ui.append(log_msg) + +# Set up all the scenes +print("Creating UI example scenes...") +create_caption_example() +create_sprite_example() +create_frame_example() +create_grid_example() +create_entity_example() +create_combined_example() + +# Screenshot state +current_screenshot = 0 +screenshots = [ + ("caption_example", "ui_caption_example.png"), + ("sprite_example", "ui_sprite_example.png"), + ("frame_example", "ui_frame_example.png"), + ("grid_example", "ui_grid_example.png"), + ("entity_example", "ui_entity_example.png"), + ("combined_example", "ui_combined_example.png") +] + +def take_screenshots(runtime): + """Timer callback to take screenshots sequentially""" + global current_screenshot + + if current_screenshot >= len(screenshots): + print("\nAll screenshots captured successfully!") + print(f"Screenshots saved to: {output_dir}/") + mcrfpy.exit() + return + + scene_name, filename = screenshots[current_screenshot] + + # Switch to the scene + mcrfpy.setScene(scene_name) + + # Take screenshot after a short delay to ensure rendering + def capture(): + global current_screenshot + full_path = f"{output_dir}/{filename}" + result = automation.screenshot(full_path) + print(f"Screenshot {current_screenshot + 1}/{len(screenshots)}: {filename} - {'Success' if result else 'Failed'}") + + current_screenshot += 1 + + # Schedule next screenshot + mcrfpy.setTimer("next_screenshot", take_screenshots, 200) + + # Give scene time to render + mcrfpy.setTimer("capture", lambda r: capture(), 100) + +# Start with the first scene +mcrfpy.setScene("caption_example") + +# Start the screenshot process +print(f"\nStarting screenshot capture of {len(screenshots)} scenes...") +mcrfpy.setTimer("start", take_screenshots, 500) + +# Safety timeout +def safety_exit(runtime): + print("\nERROR: Safety timeout reached! Exiting...") + mcrfpy.exit() + +mcrfpy.setTimer("safety", safety_exit, 30000) + +print("Setup complete. Game loop starting...") \ No newline at end of file diff --git a/tests/generate_docs_screenshots_simple.py b/tests/generate_docs_screenshots_simple.py new file mode 100755 index 0000000..75712f4 --- /dev/null +++ b/tests/generate_docs_screenshots_simple.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 +"""Generate documentation screenshots for McRogueFace UI elements - Simple version""" +import mcrfpy +from mcrfpy import automation +import sys +import os + +# Crypt of Sokoban color scheme +FRAME_COLOR = mcrfpy.Color(64, 64, 128) +SHADOW_COLOR = mcrfpy.Color(64, 64, 86) +BOX_COLOR = mcrfpy.Color(96, 96, 160) +WHITE = mcrfpy.Color(255, 255, 255) +BLACK = mcrfpy.Color(0, 0, 0) +GREEN = mcrfpy.Color(0, 255, 0) +RED = mcrfpy.Color(255, 0, 0) + +# Create texture for sprites +sprite_texture = mcrfpy.Texture("assets/kenney_TD_MR_IP.png", 16, 16) + +# Output directory +output_dir = "mcrogueface.github.io/images" +if not os.path.exists(output_dir): + os.makedirs(output_dir) + +def create_caption(x, y, text, font_size=16, text_color=WHITE, outline_color=BLACK): + """Helper function to create captions with common settings""" + caption = mcrfpy.Caption(mcrfpy.Vector(x, y), text=text) + caption.size = font_size + caption.fill_color = text_color + caption.outline_color = outline_color + return caption + +# Screenshot counter +screenshot_count = 0 +total_screenshots = 4 + +def screenshot_and_continue(runtime): + """Take a screenshot and move to the next scene""" + global screenshot_count + + if screenshot_count == 0: + # Caption example + print("Creating Caption example...") + mcrfpy.createScene("caption_example") + ui = mcrfpy.sceneUI("caption_example") + + bg = mcrfpy.Frame(0, 0, 800, 600, fill_color=FRAME_COLOR) + ui.append(bg) + + title = create_caption(200, 50, "Caption Examples", 32) + ui.append(title) + + caption1 = create_caption(100, 150, "Large Caption (24pt)", 24) + ui.append(caption1) + + caption2 = create_caption(100, 200, "Medium Caption (18pt)", 18, GREEN) + ui.append(caption2) + + caption3 = create_caption(100, 240, "Small Caption (14pt)", 14, RED) + ui.append(caption3) + + caption_bg = mcrfpy.Frame(100, 300, 300, 50, fill_color=BOX_COLOR) + ui.append(caption_bg) + caption4 = create_caption(110, 315, "Caption with Background", 16) + ui.append(caption4) + + mcrfpy.setScene("caption_example") + mcrfpy.setTimer("next1", lambda r: capture_screenshot("ui_caption_example.png"), 200) + + elif screenshot_count == 1: + # Sprite example + print("Creating Sprite example...") + mcrfpy.createScene("sprite_example") + ui = mcrfpy.sceneUI("sprite_example") + + bg = mcrfpy.Frame(0, 0, 800, 600, fill_color=FRAME_COLOR) + ui.append(bg) + + title = create_caption(250, 50, "Sprite Examples", 32) + ui.append(title) + + sprite_bg = mcrfpy.Frame(100, 150, 600, 300, fill_color=BOX_COLOR) + ui.append(sprite_bg) + + player_label = create_caption(150, 180, "Player", 14) + ui.append(player_label) + player_sprite = mcrfpy.Sprite(150, 200, sprite_texture, 84, 3.0) + ui.append(player_sprite) + + enemy_label = create_caption(250, 180, "Enemies", 14) + ui.append(enemy_label) + enemy1 = mcrfpy.Sprite(250, 200, sprite_texture, 123, 3.0) + ui.append(enemy1) + enemy2 = mcrfpy.Sprite(300, 200, sprite_texture, 107, 3.0) + ui.append(enemy2) + + boulder_label = create_caption(400, 180, "Boulder", 14) + ui.append(boulder_label) + boulder_sprite = mcrfpy.Sprite(400, 200, sprite_texture, 66, 3.0) + ui.append(boulder_sprite) + + exit_label = create_caption(500, 180, "Exit States", 14) + ui.append(exit_label) + exit_locked = mcrfpy.Sprite(500, 200, sprite_texture, 45, 3.0) + ui.append(exit_locked) + exit_open = mcrfpy.Sprite(550, 200, sprite_texture, 21, 3.0) + ui.append(exit_open) + + mcrfpy.setScene("sprite_example") + mcrfpy.setTimer("next2", lambda r: capture_screenshot("ui_sprite_example.png"), 200) + + elif screenshot_count == 2: + # Frame example + print("Creating Frame example...") + mcrfpy.createScene("frame_example") + ui = mcrfpy.sceneUI("frame_example") + + bg = mcrfpy.Frame(0, 0, 800, 600, fill_color=SHADOW_COLOR) + ui.append(bg) + + title = create_caption(250, 30, "Frame Examples", 32) + ui.append(title) + + frame1 = mcrfpy.Frame(50, 100, 200, 150, fill_color=FRAME_COLOR) + ui.append(frame1) + label1 = create_caption(60, 110, "Basic Frame", 16) + ui.append(label1) + + frame2 = mcrfpy.Frame(300, 100, 200, 150, fill_color=BOX_COLOR, + outline_color=WHITE, outline=2.0) + ui.append(frame2) + label2 = create_caption(310, 110, "Frame with Outline", 16) + ui.append(label2) + + frame3 = mcrfpy.Frame(550, 100, 200, 150, fill_color=FRAME_COLOR, + outline_color=WHITE, outline=1) + ui.append(frame3) + inner_frame = mcrfpy.Frame(570, 130, 160, 90, fill_color=BOX_COLOR) + ui.append(inner_frame) + label3 = create_caption(560, 110, "Nested Frames", 16) + ui.append(label3) + + mcrfpy.setScene("frame_example") + mcrfpy.setTimer("next3", lambda r: capture_screenshot("ui_frame_example.png"), 200) + + elif screenshot_count == 3: + # Grid example + print("Creating Grid example...") + mcrfpy.createScene("grid_example") + ui = mcrfpy.sceneUI("grid_example") + + bg = mcrfpy.Frame(0, 0, 800, 600, fill_color=FRAME_COLOR) + ui.append(bg) + + title = create_caption(250, 30, "Grid Example", 32) + ui.append(title) + + grid = mcrfpy.Grid(20, 15, sprite_texture, + mcrfpy.Vector(100, 100), mcrfpy.Vector(320, 240)) + + # Set up dungeon tiles + for x in range(20): + for y in range(15): + if x == 0 or x == 19 or y == 0 or y == 14: + # Walls + grid.at((x, y)).tilesprite = 3 + grid.at((x, y)).walkable = False + else: + # Floor + grid.at((x, y)).tilesprite = 48 + grid.at((x, y)).walkable = True + + # Add some internal walls + for x in range(5, 15): + grid.at((x, 7)).tilesprite = 3 + grid.at((x, 7)).walkable = False + for y in range(3, 8): + grid.at((10, y)).tilesprite = 3 + grid.at((10, y)).walkable = False + + # Add a door + grid.at((10, 7)).tilesprite = 131 + grid.at((10, 7)).walkable = True + + ui.append(grid) + + grid_label = create_caption(100, 480, "20x15 Grid - Simple Dungeon Layout", 16) + ui.append(grid_label) + + mcrfpy.setScene("grid_example") + mcrfpy.setTimer("next4", lambda r: capture_screenshot("ui_grid_example.png"), 200) + + else: + print("\nAll screenshots captured successfully!") + print(f"Screenshots saved to: {output_dir}/") + mcrfpy.exit() + return + +def capture_screenshot(filename): + """Capture a screenshot""" + global screenshot_count + full_path = f"{output_dir}/{filename}" + result = automation.screenshot(full_path) + print(f"Screenshot {screenshot_count + 1}/{total_screenshots}: {filename} - {'Success' if result else 'Failed'}") + screenshot_count += 1 + + # Schedule next scene + mcrfpy.setTimer("continue", screenshot_and_continue, 300) + +# Start the process +print("Starting screenshot generation...") +mcrfpy.setTimer("start", screenshot_and_continue, 500) + +# Safety timeout +mcrfpy.setTimer("safety", lambda r: mcrfpy.exit(), 30000) + +print("Setup complete. Game loop starting...") \ No newline at end of file diff --git a/tests/generate_entity_screenshot_fixed.py b/tests/generate_entity_screenshot_fixed.py new file mode 100644 index 0000000..2f6f433 --- /dev/null +++ b/tests/generate_entity_screenshot_fixed.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +"""Generate entity documentation screenshot with proper font loading""" + +import mcrfpy +from mcrfpy import automation +import sys + +def capture_entity(runtime): + """Capture entity example after render loop starts""" + + # Take screenshot + automation.screenshot("mcrogueface.github.io/images/ui_entity_example.png") + print("Entity screenshot saved!") + + # Exit after capturing + sys.exit(0) + +# Create scene +mcrfpy.createScene("entities") + +# Use the default font which is already loaded +# Instead of: font = mcrfpy.Font("assets/JetbrainsMono.ttf") +# We use: mcrfpy.default_font (which is already loaded by the engine) + +# Title +title = mcrfpy.Caption(400, 30, "Entity Example - Roguelike Characters") +title.font = mcrfpy.default_font +title.font_size = 24 +title.font_color = (255, 255, 255) + +# Create a grid background +texture = mcrfpy.Texture("assets/kenney_TD_MR_IP.png", 16, 16) + +# Create grid with entities - using 2x scale (32x32 pixel tiles) +grid = mcrfpy.Grid(100, 100, 20, 15, texture, 32, 32) +grid.texture = texture + +# Define tile types +FLOOR = 58 # Stone floor +WALL = 11 # Stone wall + +# Fill with floor +for x in range(20): + for y in range(15): + grid.set_tile(x, y, FLOOR) + +# Add walls around edges +for x in range(20): + grid.set_tile(x, 0, WALL) + grid.set_tile(x, 14, WALL) +for y in range(15): + grid.set_tile(0, y, WALL) + grid.set_tile(19, y, WALL) + +# Create entities +# Player at center +player = mcrfpy.Entity(10, 7) +player.texture = texture +player.sprite_index = 84 # Player sprite + +# Enemies +rat1 = mcrfpy.Entity(5, 5) +rat1.texture = texture +rat1.sprite_index = 123 # Rat + +rat2 = mcrfpy.Entity(15, 5) +rat2.texture = texture +rat2.sprite_index = 123 # Rat + +big_rat = mcrfpy.Entity(7, 10) +big_rat.texture = texture +big_rat.sprite_index = 130 # Big rat + +cyclops = mcrfpy.Entity(13, 10) +cyclops.texture = texture +cyclops.sprite_index = 109 # Cyclops + +# Items +chest = mcrfpy.Entity(3, 3) +chest.texture = texture +chest.sprite_index = 89 # Chest + +boulder = mcrfpy.Entity(10, 5) +boulder.texture = texture +boulder.sprite_index = 66 # Boulder + +key = mcrfpy.Entity(17, 12) +key.texture = texture +key.sprite_index = 384 # Key + +# Add all entities to grid +grid.entities.append(player) +grid.entities.append(rat1) +grid.entities.append(rat2) +grid.entities.append(big_rat) +grid.entities.append(cyclops) +grid.entities.append(chest) +grid.entities.append(boulder) +grid.entities.append(key) + +# Labels +entity_label = mcrfpy.Caption(100, 580, "Entities move independently on the grid. Grid scale: 2x (32x32 pixels)") +entity_label.font = mcrfpy.default_font +entity_label.font_color = (255, 255, 255) + +info = mcrfpy.Caption(100, 600, "Player (center), Enemies (rats, cyclops), Items (chest, boulder, key)") +info.font = mcrfpy.default_font +info.font_size = 14 +info.font_color = (200, 200, 200) + +# Legend frame +legend_frame = mcrfpy.Frame(50, 50, 200, 150) +legend_frame.bgcolor = (64, 64, 128) +legend_frame.outline = 2 + +legend_title = mcrfpy.Caption(150, 60, "Entity Types") +legend_title.font = mcrfpy.default_font +legend_title.font_color = (255, 255, 255) +legend_title.centered = True + +legend_text = mcrfpy.Caption(60, 90, "Player: @\nRat: r\nBig Rat: R\nCyclops: C\nChest: $\nBoulder: O\nKey: k") +legend_text.font = mcrfpy.default_font +legend_text.font_size = 12 +legend_text.font_color = (255, 255, 255) + +# Add all to scene +ui = mcrfpy.sceneUI("entities") +ui.append(grid) +ui.append(title) +ui.append(entity_label) +ui.append(info) +ui.append(legend_frame) +ui.append(legend_title) +ui.append(legend_text) + +# Switch to scene +mcrfpy.setScene("entities") + +# Set timer to capture after rendering starts +mcrfpy.setTimer("capture", capture_entity, 100) \ No newline at end of file diff --git a/tests/generate_grid_screenshot.py b/tests/generate_grid_screenshot.py new file mode 100644 index 0000000..706b704 --- /dev/null +++ b/tests/generate_grid_screenshot.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +"""Generate grid documentation screenshot for McRogueFace""" + +import mcrfpy +from mcrfpy import automation +import sys + +def capture_grid(runtime): + """Capture grid example after render loop starts""" + + # Take screenshot + automation.screenshot("mcrogueface.github.io/images/ui_grid_example.png") + print("Grid screenshot saved!") + + # Exit after capturing + sys.exit(0) + +# Create scene +mcrfpy.createScene("grid") + +# Load texture +texture = mcrfpy.Texture("assets/kenney_TD_MR_IP.png", 16, 16) + +# Title +title = mcrfpy.Caption(400, 30, "Grid Example - Dungeon View") +title.font = mcrfpy.default_font +title.font_size = 24 +title.font_color = (255, 255, 255) + +# Create main grid (20x15 tiles, each 32x32 pixels) +grid = mcrfpy.Grid(100, 100, 20, 15, texture, 32, 32) +grid.texture = texture + +# Define tile types from Crypt of Sokoban +FLOOR = 58 # Stone floor +WALL = 11 # Stone wall +DOOR = 28 # Closed door +CHEST = 89 # Treasure chest +BUTTON = 250 # Floor button +EXIT = 45 # Locked exit +BOULDER = 66 # Boulder + +# Create a simple dungeon room layout +# Fill with walls first +for x in range(20): + for y in range(15): + grid.set_tile(x, y, WALL) + +# Carve out room +for x in range(2, 18): + for y in range(2, 13): + grid.set_tile(x, y, FLOOR) + +# Add door +grid.set_tile(10, 2, DOOR) + +# Add some features +grid.set_tile(5, 5, CHEST) +grid.set_tile(15, 10, BUTTON) +grid.set_tile(10, 12, EXIT) +grid.set_tile(8, 8, BOULDER) +grid.set_tile(12, 8, BOULDER) + +# Create some entities on the grid +# Player entity +player = mcrfpy.Entity(5, 7) +player.texture = texture +player.sprite_index = 84 # Player sprite + +# Enemy entities +rat1 = mcrfpy.Entity(12, 5) +rat1.texture = texture +rat1.sprite_index = 123 # Rat + +rat2 = mcrfpy.Entity(14, 9) +rat2.texture = texture +rat2.sprite_index = 123 # Rat + +cyclops = mcrfpy.Entity(10, 10) +cyclops.texture = texture +cyclops.sprite_index = 109 # Cyclops + +# Add entities to grid +grid.entities.append(player) +grid.entities.append(rat1) +grid.entities.append(rat2) +grid.entities.append(cyclops) + +# Create a smaller grid showing tile palette +palette_label = mcrfpy.Caption(100, 600, "Tile Types:") +palette_label.font = mcrfpy.default_font +palette_label.font_color = (255, 255, 255) + +palette = mcrfpy.Grid(250, 580, 7, 1, texture, 32, 32) +palette.texture = texture +palette.set_tile(0, 0, FLOOR) +palette.set_tile(1, 0, WALL) +palette.set_tile(2, 0, DOOR) +palette.set_tile(3, 0, CHEST) +palette.set_tile(4, 0, BUTTON) +palette.set_tile(5, 0, EXIT) +palette.set_tile(6, 0, BOULDER) + +# Labels for palette +labels = ["Floor", "Wall", "Door", "Chest", "Button", "Exit", "Boulder"] +for i, label in enumerate(labels): + l = mcrfpy.Caption(250 + i * 32, 615, label) + l.font = mcrfpy.default_font + l.font_size = 10 + l.font_color = (255, 255, 255) + mcrfpy.sceneUI("grid").append(l) + +# Add info caption +info = mcrfpy.Caption(100, 680, "Grid supports tiles and entities. Entities can move independently of the tile grid.") +info.font = mcrfpy.default_font +info.font_size = 14 +info.font_color = (200, 200, 200) + +# Add all elements to scene +ui = mcrfpy.sceneUI("grid") +ui.append(title) +ui.append(grid) +ui.append(palette_label) +ui.append(palette) +ui.append(info) + +# Switch to scene +mcrfpy.setScene("grid") + +# Set timer to capture after rendering starts +mcrfpy.setTimer("capture", capture_grid, 100) \ No newline at end of file diff --git a/tests/generate_sprite_screenshot.py b/tests/generate_sprite_screenshot.py new file mode 100644 index 0000000..3a314bb --- /dev/null +++ b/tests/generate_sprite_screenshot.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 +"""Generate sprite documentation screenshots for McRogueFace""" + +import mcrfpy +from mcrfpy import automation +import sys + +def capture_sprites(runtime): + """Capture sprite examples after render loop starts""" + + # Take screenshot + automation.screenshot("mcrogueface.github.io/images/ui_sprite_example.png") + print("Sprite screenshot saved!") + + # Exit after capturing + sys.exit(0) + +# Create scene +mcrfpy.createScene("sprites") + +# Load texture +texture = mcrfpy.Texture("assets/kenney_TD_MR_IP.png", 16, 16) + +# Title +title = mcrfpy.Caption(400, 30, "Sprite Examples") +title.font = mcrfpy.default_font +title.font_size = 24 +title.font_color = (255, 255, 255) + +# Create a frame background +frame = mcrfpy.Frame(50, 80, 700, 500) +frame.bgcolor = (64, 64, 128) +frame.outline = 2 + +# Player sprite +player_label = mcrfpy.Caption(100, 120, "Player") +player_label.font = mcrfpy.default_font +player_label.font_color = (255, 255, 255) + +player = mcrfpy.Sprite(120, 150) +player.texture = texture +player.sprite_index = 84 # Player sprite +player.scale = (3.0, 3.0) + +# Enemy sprites +enemy_label = mcrfpy.Caption(250, 120, "Enemies") +enemy_label.font = mcrfpy.default_font +enemy_label.font_color = (255, 255, 255) + +rat = mcrfpy.Sprite(250, 150) +rat.texture = texture +rat.sprite_index = 123 # Rat +rat.scale = (3.0, 3.0) + +big_rat = mcrfpy.Sprite(320, 150) +big_rat.texture = texture +big_rat.sprite_index = 130 # Big rat +big_rat.scale = (3.0, 3.0) + +cyclops = mcrfpy.Sprite(390, 150) +cyclops.texture = texture +cyclops.sprite_index = 109 # Cyclops +cyclops.scale = (3.0, 3.0) + +# Items row +items_label = mcrfpy.Caption(100, 250, "Items") +items_label.font = mcrfpy.default_font +items_label.font_color = (255, 255, 255) + +# Boulder +boulder = mcrfpy.Sprite(100, 280) +boulder.texture = texture +boulder.sprite_index = 66 # Boulder +boulder.scale = (3.0, 3.0) + +# Chest +chest = mcrfpy.Sprite(170, 280) +chest.texture = texture +chest.sprite_index = 89 # Closed chest +chest.scale = (3.0, 3.0) + +# Key +key = mcrfpy.Sprite(240, 280) +key.texture = texture +key.sprite_index = 384 # Key +key.scale = (3.0, 3.0) + +# Button +button = mcrfpy.Sprite(310, 280) +button.texture = texture +button.sprite_index = 250 # Button +button.scale = (3.0, 3.0) + +# UI elements row +ui_label = mcrfpy.Caption(100, 380, "UI Elements") +ui_label.font = mcrfpy.default_font +ui_label.font_color = (255, 255, 255) + +# Hearts +heart_full = mcrfpy.Sprite(100, 410) +heart_full.texture = texture +heart_full.sprite_index = 210 # Full heart +heart_full.scale = (3.0, 3.0) + +heart_half = mcrfpy.Sprite(170, 410) +heart_half.texture = texture +heart_half.sprite_index = 209 # Half heart +heart_half.scale = (3.0, 3.0) + +heart_empty = mcrfpy.Sprite(240, 410) +heart_empty.texture = texture +heart_empty.sprite_index = 208 # Empty heart +heart_empty.scale = (3.0, 3.0) + +# Armor +armor = mcrfpy.Sprite(340, 410) +armor.texture = texture +armor.sprite_index = 211 # Armor +armor.scale = (3.0, 3.0) + +# Scale demonstration +scale_label = mcrfpy.Caption(500, 120, "Scale Demo") +scale_label.font = mcrfpy.default_font +scale_label.font_color = (255, 255, 255) + +# Same sprite at different scales +for i, scale in enumerate([1.0, 2.0, 3.0, 4.0]): + s = mcrfpy.Sprite(500 + i * 60, 150) + s.texture = texture + s.sprite_index = 84 # Player + s.scale = (scale, scale) + mcrfpy.sceneUI("sprites").append(s) + +# Add all elements to scene +ui = mcrfpy.sceneUI("sprites") +ui.append(frame) +ui.append(title) +ui.append(player_label) +ui.append(player) +ui.append(enemy_label) +ui.append(rat) +ui.append(big_rat) +ui.append(cyclops) +ui.append(items_label) +ui.append(boulder) +ui.append(chest) +ui.append(key) +ui.append(button) +ui.append(ui_label) +ui.append(heart_full) +ui.append(heart_half) +ui.append(heart_empty) +ui.append(armor) +ui.append(scale_label) + +# Switch to scene +mcrfpy.setScene("sprites") + +# Set timer to capture after rendering starts +mcrfpy.setTimer("capture", capture_sprites, 100) \ No newline at end of file diff --git a/tests/simple_screenshot_test.py b/tests/simple_screenshot_test.py new file mode 100644 index 0000000..42815a4 --- /dev/null +++ b/tests/simple_screenshot_test.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +"""Simple screenshot test to verify automation API""" + +import mcrfpy +from mcrfpy import automation +import sys +import time + +def take_screenshot(runtime): + """Take screenshot after render starts""" + print(f"Timer callback fired at runtime: {runtime}") + + # Try different paths + paths = [ + "test_screenshot.png", + "./test_screenshot.png", + "mcrogueface.github.io/images/test_screenshot.png" + ] + + for path in paths: + try: + print(f"Trying to save to: {path}") + automation.screenshot(path) + print(f"Success: {path}") + except Exception as e: + print(f"Failed {path}: {e}") + + sys.exit(0) + +# Create minimal scene +mcrfpy.createScene("test") + +# Add a visible element +caption = mcrfpy.Caption(100, 100, "Screenshot Test") +caption.font = mcrfpy.default_font +caption.font_color = (255, 255, 255) +caption.font_size = 24 + +mcrfpy.sceneUI("test").append(caption) +mcrfpy.setScene("test") + +# Use timer to ensure rendering has started +print("Setting timer...") +mcrfpy.setTimer("screenshot", take_screenshot, 500) # Wait 0.5 seconds +print("Timer set, entering game loop...") \ No newline at end of file