Update comprehensive documentation for Alpha release (Issue #47)
- 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 <noreply@anthropic.com>
This commit is contained in:
parent
0d26d51bc3
commit
05bddae511
99
README.md
99
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
|
|
@ -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)
|
|
@ -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...")
|
|
@ -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...")
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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...")
|
Loading…
Reference in New Issue