From 2146c1e1832e89f9b1d628164906ddf084c354c9 Mon Sep 17 00:00:00 2001 From: Gperez88 Date: Fri, 30 Jan 2026 16:39:12 -0400 Subject: [PATCH 1/7] feat(docs): add resolution scaling documentation and update display config - Add comprehensive resolution scaling guide explaining logical vs physical resolution - Update DisplayConfig API to support separate logical and physical dimensions - Enhance Renderer documentation to clarify logical coordinate space usage - Expand troubleshooting guide with resolution scaling issues section - Update performance tuning guide highlighting resolution scaling benefits - Extend FPS overlay to debug statistics overlay with RAM and CPU metrics - Update example configurations to demonstrate resolution scaling usage - Regenerate sitemap to include new resolution scaling documentation page --- docs/api_reference/core/engine.md | 29 +-- docs/api_reference/graphics/display_config.md | 129 +++++++++---- docs/api_reference/graphics/renderer.md | 81 +++++--- docs/getting_started/fundamental_concepts.md | 9 + docs/getting_started/your_first_project.md | 11 +- .../advanced_graphics/resolution_scaling.md | 103 +++++++++++ .../game_development/basic_rendering.md | 3 +- .../manual/optimization/performance_tuning.md | 17 +- .../optimization/platforms_and_drivers.md | 16 +- docs/resources/troubleshooting.md | 22 +++ mkdocs.yml | 1 + site/404.html | 2 +- .../audio/audio_config/index.html | 4 +- .../audio/audio_engine/index.html | 4 +- .../audio/audio_types/index.html | 4 +- .../audio/music_player/index.html | 4 +- site/api_reference/core/actor/index.html | 4 +- site/api_reference/core/engine/index.html | 18 +- site/api_reference/core/entity/index.html | 4 +- .../core/input_config/index.html | 4 +- .../core/input_manager/index.html | 4 +- .../core/physics_actor/index.html | 4 +- site/api_reference/core/scene/index.html | 4 +- .../graphics/camera2d/index.html | 4 +- site/api_reference/graphics/color/index.html | 4 +- .../graphics/display_config/index.html | 175 +++++++++--------- site/api_reference/graphics/font/index.html | 4 +- .../graphics/renderer/index.html | 47 ++--- site/api_reference/graphics/sprite/index.html | 4 +- .../api_reference/graphics/tilemap/index.html | 4 +- .../physics/collision_system/index.html | 4 +- .../physics/collision_types/index.html | 4 +- site/api_reference/ui/ui_button/index.html | 4 +- site/api_reference/ui/ui_checkbox/index.html | 4 +- site/api_reference/ui/ui_element/index.html | 4 +- site/api_reference/ui/ui_label/index.html | 4 +- site/api_reference/ui/ui_layout/index.html | 4 +- .../ui/ui_layouts/anchor_layout/index.html | 4 +- .../ui/ui_layouts/grid_layout/index.html | 4 +- .../ui_layouts/horizontal_layout/index.html | 4 +- .../ui_layouts/padding_container/index.html | 4 +- .../ui/ui_layouts/panel/index.html | 4 +- .../ui/ui_layouts/vertical_layout/index.html | 4 +- .../fundamental_concepts/index.html | 6 +- site/getting_started/installation/index.html | 4 +- .../what_is_pixelroot32/index.html | 2 +- .../why_pixelroot32/index.html | 2 +- .../your_first_project/index.html | 99 +++++----- site/index.html | 2 +- .../cameras_and_scrolling/index.html | 4 +- .../color_palettes/index.html | 4 +- .../particles_and_effects/index.html | 4 +- .../resolution_scaling/index.html | 28 +++ .../sprites_and_animation/index.html | 4 +- .../advanced_graphics/tilemaps/index.html | 4 +- site/manual/game_development/audio/index.html | 4 +- .../basic_rendering/index.html | 9 +- .../input_and_control/index.html | 4 +- .../physics_and_collisions/index.html | 4 +- .../scenes_and_entities/index.html | 4 +- .../user_interface/index.html | 4 +- .../optimization/extensibility/index.html | 4 +- .../optimization/memory_management/index.html | 4 +- .../performance_tuning/index.html | 10 +- .../platforms_and_drivers/index.html | 31 ++-- site/reference/api_overview/index.html | 4 +- site/reference/code_examples/index.html | 4 +- site/reference/game_examples_guide/index.html | 4 +- site/resources/available_tools/index.html | 4 +- site/resources/faq/index.html | 4 +- .../limitations_and_considerations/index.html | 2 +- site/resources/troubleshooting/index.html | 6 +- site/search/search_index.json | 2 +- site/sitemap.xml | 136 +++++++------- site/sitemap.xml.gz | Bin 858 -> 872 bytes .../advanced_features/index.html | 4 +- .../sprite_compiler/installation/index.html | 4 +- .../tools/sprite_compiler/overview/index.html | 4 +- .../sprite_compiler/usage_guide/index.html | 4 +- .../tilemap_editor/installation/index.html | 4 +- site/tools/tilemap_editor/overview/index.html | 2 +- .../tilemap_editor/usage_guide/index.html | 2 +- 82 files changed, 743 insertions(+), 463 deletions(-) create mode 100644 docs/manual/advanced_graphics/resolution_scaling.md create mode 100644 site/manual/advanced_graphics/resolution_scaling/index.html diff --git a/docs/api_reference/core/engine.md b/docs/api_reference/core/engine.md index 77a76de..6d6ddf8 100644 --- a/docs/api_reference/core/engine.md +++ b/docs/api_reference/core/engine.md @@ -42,8 +42,8 @@ Creates a new engine instance with custom display, input, and audio configuratio #include "audio/AudioConfig.h" pixelroot32::graphics::DisplayConfig displayConfig; -displayConfig.width = 128; -displayConfig.height = 128; +displayConfig.logicalWidth = 128; +displayConfig.logicalHeight = 128; pixelroot32::input::InputConfig inputConfig; // Configure input pins... @@ -278,18 +278,25 @@ void playMusic() { } ``` -## Optional: FPS overlay +## Optional: Debug Statistics Overlay -When the engine is built with the preprocessor define **`PIXELROOT32_ENABLE_FPS_DISPLAY`**, an on-screen FPS counter is drawn each frame. +When the engine is built with the preprocessor define **`PIXELROOT32_ENABLE_DEBUG_OVERLAY`**, an on-screen technical overlay is drawn each frame. + +**Metrics Included:** + +- **FPS**: Frames per second (Green). +- **RAM**: Used heap memory in KB (Cyan). +- **CPU**: Estimated processor load percentage (Yellow). **Behavior:** -- A green text string `"FPS xxx"` is drawn in the top-right area (position from `Renderer::getWidth()` and a fixed Y offset). -- The value is derived from frame delta time (FPS = 1000 / deltaTime ms), clamped to 0–999. +- The overlay is drawn in the top-right area of the screen. +- It is rendered after the scene, making it fixed and independent of the camera. **Performance:** -- The numeric value is recalculated and formatted only every **8 frames**; the cached string is drawn every frame to keep the overlay visible without extra per-frame cost (division and `snprintf` are done at most once every 8 frames). +- Metric values are recalculated and formatted only every **16 frames** (`DEBUG_UPDATE_INTERVAL`). +- Cached strings are drawn every frame to minimize per-frame cost (division and `snprintf`). **How to enable:** @@ -297,10 +304,10 @@ In `platformio.ini`, add to your environment's `build_flags`: ```ini build_flags = - -D PIXELROOT32_ENABLE_FPS_DISPLAY + -D PIXELROOT32_ENABLE_DEBUG_OVERLAY ``` -No code changes are required; the overlay is drawn automatically after the scene in `Engine::draw()`. The implementation uses the private method `drawFpsOverlay(Renderer& r)`, which is only compiled when the define is set. +Alternatively, you can enable it in `EngineConfig.h`. The implementation uses the private method `drawDebugOverlay(Renderer& r)`, which is only compiled when the define is set. See also: [Performance Tuning - Profiling](../../manual/optimization/performance_tuning.md) and [Platforms and Drivers - Build flags](../../manual/optimization/platforms_and_drivers.md). @@ -314,8 +321,8 @@ See also: [Performance Tuning - Profiling](../../manual/optimization/performance void setup() { // Configure display pixelroot32::graphics::DisplayConfig displayConfig; - displayConfig.width = 128; - displayConfig.height = 128; + displayConfig.logicalWidth = 128; + displayConfig.logicalHeight = 128; displayConfig.rotation = 0; // Create engine diff --git a/docs/api_reference/graphics/display_config.md b/docs/api_reference/graphics/display_config.md index 0be6900..e6414c9 100644 --- a/docs/api_reference/graphics/display_config.md +++ b/docs/api_reference/graphics/display_config.md @@ -53,33 +53,60 @@ Display rotation in degrees. - Rotation is applied during initialization - Some displays may not support all rotations -### uint16_t width +### uint16_t physicalWidth -Display width in pixels. +Physical hardware width of the display. **Type:** `uint16_t` **Access:** Read-write -**Default:** `240` +**Notes:** +- Defines the actual resolution of the display hardware. + +### uint16_t physicalHeight + +Physical hardware height of the display. + +**Type:** `uint16_t` + +**Access:** Read-write **Notes:** -- Should match actual display width -- Used for viewport and camera calculations +- Defines the actual resolution of the display hardware. -### uint16_t height +### uint16_t logicalWidth -Display height in pixels. +Logical rendering width. This is the resolution the game "sees" and draws to. **Type:** `uint16_t` **Access:** Read-write -**Default:** `240` +**Notes:** +- If smaller than `physicalWidth`, the image will be scaled up. +- Used for clipping, camera, and UI calculations. +- Recommended values for ESP32: 160, 128, 96 (for 240 physical). + +### uint16_t logicalHeight + +Logical rendering height. This is the resolution the game "sees" and draws to. + +**Type:** `uint16_t` + +**Access:** Read-write **Notes:** -- Should match actual display height -- Used for viewport and camera calculations +- If smaller than `physicalHeight`, the image will be scaled up. +- Used for clipping, camera, and UI calculations. + +### uint16_t width() (Deprecated) + +Alias for `logicalWidth`. Maintained for backward compatibility. + +### uint16_t height() (Deprecated) + +Alias for `logicalHeight`. Maintained for backward compatibility. ### int xOffset @@ -121,19 +148,53 @@ Gets the underlying DrawSurface implementation. - Provides access to low-level display driver - Platform-specific implementation +## Resolution Helpers + +### bool needsScaling() const + +Checks if the logical resolution differs from the physical resolution. + +**Returns:** +- `bool`: `true` if scaling is active. + +### float getScaleX() const + +Gets the horizontal scaling factor (`physicalWidth / logicalWidth`). + +### float getScaleY() const + +Gets the vertical scaling factor (`physicalHeight / logicalHeight`). + ## Constructors -### DisplayConfig(DisplayType type, const int rot = 0, uint16_t w = 240, uint16_t h = 240, const int xOffset = 0, const int yOffset = 0) +### DisplayConfig(DisplayType type, const int rot, uint16_t physW, uint16_t physH, uint16_t logW, uint16_t logH, const int xOff = 0, const int yOff = 0) -Constructs a DisplayConfig with specified parameters. +Extended constructor that allows defining separate physical and logical resolutions. **Parameters:** -- `type` (`DisplayType`): The display type -- `rot` (int, optional): Rotation in degrees. Default: `0` -- `w` (uint16_t, optional): Width in pixels. Default: `240` -- `h` (uint16_t, optional): Height in pixels. Default: `240` -- `xOffset` (int, optional): X offset. Default: `0` -- `yOffset` (int, optional): Y offset. Default: `0` +- `type` (`DisplayType`): The display type. +- `rot` (int): Rotation (0-3 or degrees depending on implementation). +- `physW` (uint16_t): Physical hardware width. +- `physH` (uint16_t): Physical hardware height. +- `logW` (uint16_t): Logical rendering width (0 = same as physical). +- `logH` (uint16_t): Logical rendering height (0 = same as physical). +- `xOff` (int, optional): X alignment offset. +- `yOff` (int, optional): Y alignment offset. + +**Example:** +```cpp +// 128x128 game logic scaled to 240x240 display +pixelroot32::graphics::DisplayConfig config( + pixelroot32::graphics::DisplayType::ST7789, + 0, // rotation + 240, 240, // physical + 128, 128 // logical +); +``` + +### DisplayConfig(DisplayType type, const int rot = 0, uint16_t w = 240, uint16_t h = 240, const int xOffset = 0, const int yOffset = 0) + +Legacy constructor for backward compatibility. Sets both logical and physical resolutions to the same values. **Notes:** - Automatically creates the appropriate `DrawSurface` for the platform @@ -151,16 +212,18 @@ pixelroot32::graphics::DisplayConfig config( pixelroot32::graphics::DisplayConfig config( pixelroot32::graphics::DisplayType::ST7735, 90, // rotation - 128, // width - 128 // height + 128, // physical width + 128, // physical height + 128, // logical width + 128 // logical height ); // Native/SDL2 (no specific display type) pixelroot32::graphics::DisplayConfig config( pixelroot32::graphics::DisplayType::NONE, 0, // rotation - 128, // width - 128 // height + 128, 128, // physical + 128, 128 // logical ); ``` @@ -173,12 +236,12 @@ pixelroot32::graphics::DisplayConfig config( #include "graphics/DisplayConfig.h" void setup() { - // Configure ST7789 display (240x240) + // Configure ST7789 display (240x240 physical, 128x128 logical) pixelroot32::graphics::DisplayConfig displayConfig( pixelroot32::graphics::DisplayType::ST7789, 0, // rotation - 240, // width - 240 // height + 240, 240, // physical + 128, 128 // logical ); // Use with Engine @@ -197,8 +260,7 @@ void setup() { pixelroot32::graphics::DisplayConfig displayConfig( pixelroot32::graphics::DisplayType::ST7735, 0, // rotation - 128, // width - 128 // height + 128, 128 // physical & logical ); #endif ``` @@ -211,8 +273,7 @@ void setup() { pixelroot32::graphics::DisplayConfig displayConfig( pixelroot32::graphics::DisplayType::NONE, 0, // rotation - 128, // width - 128 // height + 240, 240 // logical & physical ); #endif ``` @@ -228,12 +289,14 @@ void setup() { #ifdef PLATFORM_ESP32 displayConfig.type = pixelroot32::graphics::DisplayType::ST7789; - displayConfig.width = 240; - displayConfig.height = 240; + displayConfig.physicalWidth = 240; + displayConfig.physicalHeight = 240; + displayConfig.logicalWidth = 160; // 160x160 logic + displayConfig.logicalHeight = 160; #elif PLATFORM_NATIVE displayConfig.type = pixelroot32::graphics::DisplayType::NONE; - displayConfig.width = 128; - displayConfig.height = 128; + displayConfig.logicalWidth = 128; + displayConfig.logicalHeight = 128; #endif displayConfig.rotation = 0; diff --git a/docs/api_reference/graphics/renderer.md b/docs/api_reference/graphics/renderer.md index 23aff1e..2ef5c15 100644 --- a/docs/api_reference/graphics/renderer.md +++ b/docs/api_reference/graphics/renderer.md @@ -4,7 +4,9 @@ High-level graphics rendering system for drawing shapes, text, sprites, and tile ## Description -The `Renderer` class provides a unified API for drawing shapes, text, and images. It abstracts the underlying hardware implementation (`DrawSurface`) and manages display configuration, including rotation and offsets. +The `Renderer` class provides a unified API for drawing shapes, text, and images. It abstracts the underlying hardware implementation (`DrawSurface`) and manages display configuration, including rotation and resolution scaling. + +All drawing operations are performed in **logical screen space**. If the logical resolution differs from the physical resolution, the renderer will automatically scale the output to fit the display using a high-performance nearest-neighbor algorithm. The renderer uses integer-only math for optimal performance on ESP32 and supports multiple sprite formats (1bpp, 2bpp, 4bpp) and multi-layer sprites. @@ -37,10 +39,13 @@ Constructs the Renderer with a specific display configuration. #include "graphics/Renderer.h" #include "graphics/DisplayConfig.h" -pixelroot32::graphics::DisplayConfig config; -config.width = 128; -config.height = 128; -config.rotation = 0; +// 128x128 game logic scaled to 240x240 display +pixelroot32::graphics::DisplayConfig config( + pixelroot32::graphics::DisplayType::ST7789, + 0, // rotation + 240, 240, // physical resolution + 128, 128 // logical resolution (rendering space) +); pixelroot32::graphics::Renderer renderer(config); renderer.init(); @@ -112,19 +117,18 @@ Gets the underlying DrawSurface implementation. ### void drawText(const char* text, int16_t x, int16_t y, Color color, uint8_t size) -Draws a string of text using the default font. +Draws a string of text using the default font and scaling. **Parameters:** - `text` (const char*): The text to draw (null-terminated string) - `x` (int16_t): X coordinate (top-left corner of text) - `y` (int16_t): Y coordinate (top-left corner of text) - `color` (`Color`): Text color -- `size` (uint8_t): Text size multiplier (1 = normal, 2 = double, etc.) +- `size` (uint8_t): Text size multiplier (1 = 5x7 pixels, 2 = 10x14 pixels, etc.) **Performance Notes:** - Efficient for small amounts of text -- Avoid calling in tight loops with long strings -- Use static buffers for text formatting +- Uses integer-only scaling (no floats) **Example:** ```cpp @@ -134,7 +138,7 @@ renderer.drawText("Score: 100", 10, 30, Color::Yellow, 2); ### void drawText(const char* text, int16_t x, int16_t y, Color color, uint8_t size, const Font* font) -Draws a string of text using a specific font. +Draws a string of text using a specific font and scaling. **Parameters:** - `text` (const char*): The text to draw @@ -280,54 +284,61 @@ Draws a 1bpp monochrome sprite using the Sprite descriptor. - `sprite` (const `Sprite&`): Sprite descriptor (data, width, height) - `x` (int): Top-left X coordinate in logical screen space - `y` (int): Top-left Y coordinate in logical screen space -- `color` (`Color`): Color used for "on" pixels. Default: uses sprite palette context +- `color` (`Color`): Color used for "on" pixels - `flipX` (bool, optional): If `true`, sprite is mirrored horizontally. Default: `false` **Performance Notes:** - Very efficient for 1bpp sprites (integer-only operations) - Sprite data should be stored in flash (const/constexpr) for best performance -- Avoid calling in tight loops; batch similar operations when possible **Example:** ```cpp -static const uint16_t playerData[] = { - 0b00111100, - 0b01111110, - // ... more rows -}; - -static const Sprite playerSprite = { - playerData, - 8, // width - 8 // height -}; - renderer.drawSprite(playerSprite, 100, 100, Color::White); renderer.drawSprite(playerSprite, 120, 100, Color::White, true); // Flipped ``` ### void drawSprite(const Sprite& sprite, int x, int y, float scaleX, float scaleY, Color color, bool flipX = false) -Draws a scaled 1bpp monochrome sprite. +Draws a scaled 1bpp monochrome sprite using nearest-neighbor scaling. **Parameters:** - `sprite` (const `Sprite&`): Sprite descriptor - `x` (int): Top-left X coordinate - `y` (int): Top-left Y coordinate -- `scaleX` (float): Horizontal scaling factor (e.g., 1.25 for 25% larger) +- `scaleX` (float): Horizontal scaling factor (e.g., 2.0 for double width) - `scaleY` (float): Vertical scaling factor - `color` (`Color`): Color used for "on" pixels - `flipX` (bool, optional): If `true`, sprite is mirrored horizontally before scaling. Default: `false` **Performance Notes:** - Slower than non-scaled version due to scaling calculations -- Use integer scaling factors when possible (1.0, 2.0, etc.) for better performance +- The destination size is calculated as `ceil(width * scaleX) x ceil(height * scaleY)` **Example:** ```cpp renderer.drawSprite(playerSprite, 100, 100, 2.0f, 2.0f, Color::White); // 2x size ``` +### void drawSprite(const Sprite2bpp& sprite, int x, int y, bool flipX = false) + +Draws a 2bpp sprite. Available when `PIXELROOT32_ENABLE_2BPP_SPRITES` is defined. + +**Parameters:** +- `sprite` (const `Sprite2bpp&`): 2bpp sprite descriptor +- `x` (int): X coordinate +- `y` (int): Y coordinate +- `flipX` (bool, optional): Horizontal flip. Default: `false` + +### void drawSprite(const Sprite4bpp& sprite, int x, int y, bool flipX = false) + +Draws a 4bpp sprite. Available when `PIXELROOT32_ENABLE_4BPP_SPRITES` is defined. + +**Parameters:** +- `sprite` (const `Sprite4bpp&`): 4bpp sprite descriptor +- `x` (int): X coordinate +- `y` (int): Y coordinate +- `flipX` (bool, optional): Horizontal flip. Default: `false` + ### void drawMultiSprite(const MultiSprite& sprite, int x, int y) Draws a multi-layer sprite composed of several 1bpp layers. @@ -425,6 +436,22 @@ static const TileMap levelMap = { renderer.drawTileMap(levelMap, 0, 0, Color::White); ``` +### int getLogicalWidth() const + +Gets the logical rendering width. + +**Returns:** +- `int`: The width of the logical screen space. + +### int getLogicalHeight() const + +Gets the logical rendering height. + +**Returns:** +- `int`: The height of the logical screen space. + +> **Note**: These methods replace the deprecated `getWidth()` and `getHeight()`. + ### void setDisplayOffset(int x, int y) Sets a global offset for all drawing operations. Useful for camera/parallax effects. diff --git a/docs/getting_started/fundamental_concepts.md b/docs/getting_started/fundamental_concepts.md index 56e7397..03a2589 100644 --- a/docs/getting_started/fundamental_concepts.md +++ b/docs/getting_started/fundamental_concepts.md @@ -98,6 +98,15 @@ Layers are drawn in order: first 0, then 1, and finally 2. This ensures the back Each entity has a `renderLayer` property that indicates which layer it should be drawn on. You can change this property to move entities between layers. +### Resolution Scaling + +PixelRoot32 supports **Independent Resolution Scaling**. This means your game logic can run at a different resolution (the **logical resolution**) than the physical screen (**physical resolution**). + +- **Logical Resolution**: The resolution you program for (e.g., 128x128). All coordinates and sizes in your code refer to this space. +- **Physical Resolution**: The actual number of pixels on your display (e.g., 240x240). + +The engine automatically handles the scaling using an optimized hardware-accelerated process, allowing you to create low-resolution retro games that look crisp on modern high-resolution micro-displays. + ### Rendering Pipeline The rendering process works like this: diff --git a/docs/getting_started/your_first_project.md b/docs/getting_started/your_first_project.md index ae1ca8b..591b6a7 100644 --- a/docs/getting_started/your_first_project.md +++ b/docs/getting_started/your_first_project.md @@ -220,12 +220,12 @@ const int DAC_PIN = 25; // GPIO 25 or 26 pr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025); // Display configuration -// ST7789, rotation 0, 240x240 resolution +// 128x128 game logic scaled to 240x240 display pr32::graphics::DisplayConfig displayConfig( pr32::graphics::DisplayType::ST7789, 0, // rotation - 240, // width - 240 // height + 240, 240, // physical resolution (hardware) + 128, 128 // logical resolution (rendering space) ); // Input configuration (6 buttons: UP, DOWN, LEFT, RIGHT, A, B) @@ -286,11 +286,12 @@ namespace pr32 = pixelroot32; pr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024); // Display configuration (NONE defaults to SDL2 on Native) +// 128x128 game logic scaled to 240x240 display pr32::graphics::DisplayConfig displayConfig( pr32::graphics::DisplayType::NONE, 0, // rotation - 240, // width - 240 // height + 240, 240, // physical resolution + 128, 128 // logical resolution ); // Input configuration (SDL scancodes) diff --git a/docs/manual/advanced_graphics/resolution_scaling.md b/docs/manual/advanced_graphics/resolution_scaling.md new file mode 100644 index 0000000..52549a5 --- /dev/null +++ b/docs/manual/advanced_graphics/resolution_scaling.md @@ -0,0 +1,103 @@ +# Resolution Scaling + +PixelRoot32 features a powerful **Independent Resolution Scaling** system. This allows the engine to render internally at a lower resolution (Logical Resolution) and then scale the final image to the display's actual hardware resolution (Physical Resolution). + +## Why use Resolution Scaling? + +On microcontrollers like the ESP32, memory and processing power are limited. Rendering at a full 240x240 resolution consumes significant RAM and CPU cycles for every pixel drawn. + +By using a lower logical resolution (e.g., 128x128): +1. **Memory Savings**: A 128x128 8bpp buffer uses ~16KB, while 240x240 uses ~57KB (72% reduction). +2. **Performance Boost**: Fewer pixels to process means more complex scenes and higher FPS. +3. **Retro Aesthetic**: Nearest-neighbor scaling preserves the pixel-art look perfectly. + +## Logical vs Physical Resolution + +- **Logical Resolution**: The virtual canvas where your game logic, sprites, and UI are drawn. +- **Physical Resolution**: The actual pixel dimensions of your hardware display. + +```mermaid +flowchart LR + subgraph Logical [Logical Resolution 128x128] + A[Game Logic] --> B[Renderer API] + B --> C[Internal Framebuffer] + end + + subgraph Scaling [Hardware Scaling] + C --> D[Nearest Neighbor Scaler] + end + + subgraph Physical [Physical Display 240x240] + D --> E[SPI/DMA Transfer] + E --> F[LCD Hardware] + end +``` + +## Configuration + +### Using Presets + +The easiest way to configure scaling is using the `ResolutionPresets` helper. + +```cpp +#include + +// Create a config for 128x128 logical resolution scaled to 240x240 physical +auto config = pr32::graphics::ResolutionPresets::create( + pr32::graphics::RES_128x128, + pr32::graphics::ST7789 +); +``` + +### Manual Configuration + +You can also specify custom dimensions in the `DisplayConfig` constructor. + +```cpp +pr32::graphics::DisplayConfig config( + pr32::graphics::ST7789, // Driver + 0, // Rotation + 240, 240, // Physical Width, Physical Height + 160, 160 // Logical Width, Logical Height +); +``` + +## Performance Impact + +The following table shows estimated savings on an ESP32 for a standard 240x240 display: + +| Logical Resolution | Memory (8bpp) | RAM Savings | FPS Gain (est.) | +| :--- | :--- | :--- | :--- | +| **240x240** (Full) | 57.6 KB | 0% | Baseline | +| **160x160** | 25.6 KB | ~55% | +30% | +| **128x128** | 16.4 KB | ~72% | +60% | +| **96x96** | 9.2 KB | ~84% | +100% | + +## Implementation Details + +### Nearest Neighbor Scaling +The engine uses a **Nearest Neighbor** algorithm optimized for ESP32. It avoids floating-point math by using pre-calculated Lookup Tables (LUTs). + +### On-the-fly Scaling +To save even more RAM, the engine does not maintain a physical-sized buffer. Instead, it scales the image **line-by-line** during the SPI DMA transfer. This means the only large buffer in memory is the small logical one. + +### Profiling + +You can measure the performance of the scaling system by enabling the **Debug Statistics Overlay**. This provides real-time data on FPS, CPU load, and RAM usage directly on the screen. + +See [Engine - Debug Overlay](../../api_reference/core/engine.md#optional-debug-statistics-overlay) for instructions on how to enable it. + +Alternatively, you can enable low-level profiling in `EngineConfig.h`: + +```cpp +#define PIXELROOT32_ENABLE_PROFILING +``` + +This will output the time taken for scaling and transfer to the Serial monitor: +`[PROFILING] Scaled Transfer: 12450 us (80 FPS max)` + +## Best Practices + +1. **Aspect Ratio**: Keep the logical aspect ratio the same as the physical one to avoid stretching. +2. **Integer Multiples**: For the sharpest results, try to use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen). +3. **UI Positioning**: Use [UIAnchorLayout](file:///c:/Users/gperez88/Documents/Proyects/Games/pixelroot32%20workspace/PixelRoot32-Docs/docs/api_reference/ui/ui_layouts/anchor_layout.md) to ensure your UI elements stay correctly positioned regardless of the logical resolution chosen. diff --git a/docs/manual/game_development/basic_rendering.md b/docs/manual/game_development/basic_rendering.md index 46d8e8f..a62ec57 100644 --- a/docs/manual/game_development/basic_rendering.md +++ b/docs/manual/game_development/basic_rendering.md @@ -17,7 +17,8 @@ auto& renderer = engine.getRenderer(); ```cpp void MyScene::draw(pixelroot32::graphics::Renderer& renderer) override { // renderer is passed as parameter - renderer.drawFilledRectangle(0, 0, 240, 240, Color::Black); + // Drawing covers the entire logical screen (e.g., 128x128) + renderer.drawFilledRectangle(0, 0, renderer.getLogicalWidth(), renderer.getLogicalHeight(), Color::Black); } ``` diff --git a/docs/manual/optimization/performance_tuning.md b/docs/manual/optimization/performance_tuning.md index a8323ba..6ab8ac8 100644 --- a/docs/manual/optimization/performance_tuning.md +++ b/docs/manual/optimization/performance_tuning.md @@ -23,7 +23,16 @@ This guide covers techniques to improve game performance on ESP32, including ren El motor utiliza varias técnicas para maximizar los FPS, especialmente en hardware limitado como el ESP32. -### 1. Viewport Culling (Recorte de Cámara) +### 1. Independent Resolution Scaling (Escalado de Resolución) +Esta es probablemente la optimización más impactante para el ESP32. Permite renderizar el juego a una resolución lógica menor (ej: 128x128) y reescalarla automáticamente a la resolución física de la pantalla (ej: 240x240). + +- **Reducción de Memoria**: Un buffer de 128x128 (8bpp) consume solo **16KB**, comparado con los **57KB** de uno de 240x240. +- **Aumento de FPS**: Al haber menos píxeles que procesar por cada primitiva o sprite, el rendimiento puede duplicarse. +- **Implementación**: Se realiza mediante Hardware-accelerated Nearest Neighbor durante la transferencia DMA. + +Consulta la guía completa de [Resolution Scaling](../advanced_graphics/resolution_scaling.md) para aprender a configurarlo. + +### 2. Viewport Culling (Recorte de Cámara) No proceses objetos que están fuera de la pantalla. El motor lo hace automáticamente en `drawTileMap`, pero debes implementarlo en tu lógica de actualización: ```cpp @@ -31,8 +40,8 @@ bool isOnScreen(float x, float y, int width, int height, const Camera2D& camera) { float cameraX = camera.getX(); float cameraY = camera.getY(); - int screenWidth = engine.getRenderer().getWidth(); - int screenHeight = engine.getRenderer().getHeight(); + int screenWidth = engine.getRenderer().getLogicalWidth(); + int screenHeight = engine.getRenderer().getLogicalHeight(); return !(x + width < cameraX || x > cameraX + screenWidth || @@ -71,7 +80,7 @@ if (levelMap.data[tileY * levelMap.width + tileX] != 0) { - **Sprites Indexados**: Prefiere `Sprite2bpp` (4 colores) o `Sprite4bpp` (16 colores) sobre `Sprite` (1bpp) si necesitas color, ya que están altamente optimizados. - **Evitar `std::string` en el Loop**: Las concatenaciones de strings generan fragmentación de memoria. Usa buffers estáticos o `char[]` para textos dinámicos. -- **Perfilado**: Activa el overlay de FPS compilando con `PIXELROOT32_ENABLE_FPS_DISPLAY` (ver [Engine - FPS overlay](../../api_reference/core/engine.md#optional-fps-overlay)) para monitorear el impacto de tus cambios en tiempo real. +- **Perfilado**: Activa el overlay de estadísticas de depuración compilando con `PIXELROOT32_ENABLE_DEBUG_OVERLAY` (ver [Engine - Debug Overlay](../../api_reference/core/engine.md#optional-debug-statistics-overlay)) para monitorear FPS, RAM y carga de CPU en tiempo real. ## Common Optimization Patterns diff --git a/docs/manual/optimization/platforms_and_drivers.md b/docs/manual/optimization/platforms_and_drivers.md index 88b22c7..18647b6 100644 --- a/docs/manual/optimization/platforms_and_drivers.md +++ b/docs/manual/optimization/platforms_and_drivers.md @@ -48,6 +48,7 @@ TFT_eSPI is the display driver for ESP32, supporting many TFT displays. Para maximizar el rendimiento en ESP32, PixelRoot32 utiliza: - **DMA (Direct Memory Access)**: Las transferencias al display se realizan en segundo plano, permitiendo que la CPU prepare el siguiente frame mientras se envía el actual. +- **Independent Resolution Scaling**: El driver soporta resoluciones lógicas menores que las físicas, realizando el escalado Nearest-Neighbor on-the-fly durante la transferencia DMA para ahorrar RAM y ganar FPS. - **Doble Buffer con IRAM**: El motor utiliza un buffer de pantalla (Sprite de TFT_eSPI) optimizado para transferencias rápidas. - **Alineación de 16 bits**: Los datos de sprites 2bpp/4bpp están alineados a palabras de 16 bits para aprovechar la arquitectura Xtensa. - **IRAM_ATTR**: Las funciones críticas de renderizado están marcadas para residir en la RAM de instrucciones, evitando cuellos de botella por acceso a la Flash. @@ -83,11 +84,12 @@ build_flags = #include // Display configuration +// 128x128 logic scaled to 240x240 hardware pixelroot32::graphics::DisplayConfig displayConfig( pixelroot32::graphics::DisplayType::ST7789, 0, // rotation - 240, // width - 240 // height + 240, 240, // physical width, height + 128, 128 // logical width, height ); // TFT_eSPI_Drawer is created automatically by Engine @@ -216,14 +218,14 @@ Enable experimental features with build flags: [env:esp32dev] build_flags = -D PIXELROOT32_ENABLE_2BPP_SPRITES # Enable 2bpp sprite format - -D PIXELROOT32_ENABLE_4BPP_SPRITES # Enable 4bpp sprite format - -D PIXELROOT32_ENABLE_SCENE_ARENA # Enable Scene Arena (experimental) - -D PIXELROOT32_ENABLE_FPS_DISPLAY # On-screen FPS counter (green, top-right; value updated every 8 frames) + - D PIXELROOT32_ENABLE_4BPP_SPRITES # Enable 4bpp sprite format + - D PIXELROOT32_ENABLE_SCENE_ARENA # Enable Scene Arena (experimental) + - D PIXELROOT32_ENABLE_DEBUG_OVERLAY # On-screen debug statistics (FPS, RAM, CPU load; throttled update) ``` -### FPS overlay (PIXELROOT32_ENABLE_FPS_DISPLAY) +### Debug Statistics Overlay (PIXELROOT32_ENABLE_DEBUG_OVERLAY) -When defined, the engine draws an on-screen FPS counter (green text, top-right) each frame. The value is recalculated every 8 frames to keep per-frame cost low. No code changes are required; the overlay is drawn automatically after the scene. See [API Reference - Engine - Optional: FPS overlay](../../api_reference/core/engine.md#optional-fps-overlay) for details. +When defined, the engine draws a technical overlay (FPS, RAM, CPU load) in the top-right area of the screen each frame. Values are updated every 16 frames to maintain performance. No code changes are required. See [API Reference - Engine - Optional: Debug Overlay](../../api_reference/core/engine.md#optional-debug-statistics-overlay) for details. ### Scene limits (MAX_LAYERS / MAX_ENTITIES) diff --git a/docs/resources/troubleshooting.md b/docs/resources/troubleshooting.md index 0f33bcf..395a367 100644 --- a/docs/resources/troubleshooting.md +++ b/docs/resources/troubleshooting.md @@ -80,6 +80,28 @@ Solution: Verify build flag syntax - Check display width/height settings - Verify TFT_eSPI driver is correct +### Resolution Scaling Issues + +**Symptoms:** +- Image is not scaled to full screen +- Visual artifacts (jittery pixels) +- Frame rate drops when scaling is enabled + +**Solutions:** +1. **Verify DisplayConfig:** + - Ensure `physicalWidth` and `physicalHeight` match your hardware resolution (e.g., 240x240). + - Check that `logicalWidth` and `logicalHeight` are set correctly (e.g., 128x128). + - Use `displayConfig.needsScaling()` to check if the engine thinks scaling is required. + +2. **Check Scaling Performance:** + - Enabling scaling is generally faster than native high resolution, but still has some overhead. + - Use the **Debug Statistics Overlay** to check CPU load. + - Ensure you are using integer-only coordinates for drawing. + +3. **Visual Quality:** + - The engine uses nearest-neighbor scaling. Some aspect ratios might look "blocky" or have uneven pixel sizes. + - For best results, use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen). + ### Buttons Not Responding **Symptoms:** diff --git a/mkdocs.yml b/mkdocs.yml index 9f85332..dcc7803 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -23,6 +23,7 @@ nav: - Advanced Graphics: - Sprites and Animation: manual/advanced_graphics/sprites_and_animation.md - Color Palettes: manual/advanced_graphics/color_palettes.md + - Resolution Scaling: manual/advanced_graphics/resolution_scaling.md - Cameras and Scrolling: manual/advanced_graphics/cameras_and_scrolling.md - Tilemaps: manual/advanced_graphics/tilemaps.md - Particles and Effects: manual/advanced_graphics/particles_and_effects.md diff --git a/site/404.html b/site/404.html index 8ff2c8f..8efb6b3 100644 --- a/site/404.html +++ b/site/404.html @@ -1 +1 @@ - PixelRoot32 Documentation
\ No newline at end of file + PixelRoot32 Documentation
\ No newline at end of file diff --git a/site/api_reference/audio/audio_config/index.html b/site/api_reference/audio/audio_config/index.html index 5e06d79..24db741 100644 --- a/site/api_reference/audio/audio_config/index.html +++ b/site/api_reference/audio/audio_config/index.html @@ -1,4 +1,4 @@ - AudioConfig - PixelRoot32 Documentation
Skip to content

AudioConfig

Configuration for the Audio subsystem.

Description

AudioConfig is a simple struct that holds configuration settings for the audio system, including the audio backend and sample rate. It is passed to AudioEngine during construction.

Namespace

namespace pixelroot32::audio {
+ AudioConfig - PixelRoot32 Documentation      

AudioConfig

Configuration for the Audio subsystem.

Description

AudioConfig is a simple struct that holds configuration settings for the audio system, including the audio backend and sample rate. It is passed to AudioEngine during construction.

Namespace

namespace pixelroot32::audio {
     struct AudioConfig {
         // ...
     };
@@ -84,4 +84,4 @@
     engine.init();
     engine.run();
 }
-

Platform-Specific Considerations

ESP32 DAC Backend

  • Sample rate: 11025 Hz recommended (lower CPU usage)
  • Quality: Lower quality, but simple setup
  • Pin: Uses GPIO 25 or 26
  • Hardware: Requires simple amplifier circuit

ESP32 I2S Backend

  • Sample rate: 22050 Hz recommended
  • Quality: Higher quality than DAC
  • Pins: Requires I2S pins (BCLK, LRCK, DOUT)
  • Hardware: Requires external I2S DAC

Native SDL2 Backend

  • Sample rate: 44100 Hz typical
  • Quality: High quality
  • Setup: Requires SDL2 library installed
  • Platforms: Windows, Linux, macOS

Performance Considerations

  • Sample rate: Lower rates use less CPU and memory
  • Backend choice: DAC is simpler but lower quality than I2S
  • Buffer size: Configured in backend, affects latency vs stability

See Also

\ No newline at end of file +

Platform-Specific Considerations

ESP32 DAC Backend

  • Sample rate: 11025 Hz recommended (lower CPU usage)
  • Quality: Lower quality, but simple setup
  • Pin: Uses GPIO 25 or 26
  • Hardware: Requires simple amplifier circuit

ESP32 I2S Backend

  • Sample rate: 22050 Hz recommended
  • Quality: Higher quality than DAC
  • Pins: Requires I2S pins (BCLK, LRCK, DOUT)
  • Hardware: Requires external I2S DAC

Native SDL2 Backend

  • Sample rate: 44100 Hz typical
  • Quality: High quality
  • Setup: Requires SDL2 library installed
  • Platforms: Windows, Linux, macOS

Performance Considerations

  • Sample rate: Lower rates use less CPU and memory
  • Backend choice: DAC is simpler but lower quality than I2S
  • Buffer size: Configured in backend, affects latency vs stability

See Also

\ No newline at end of file diff --git a/site/api_reference/audio/audio_engine/index.html b/site/api_reference/audio/audio_engine/index.html index 08ef618..31088de 100644 --- a/site/api_reference/audio/audio_engine/index.html +++ b/site/api_reference/audio/audio_engine/index.html @@ -1,4 +1,4 @@ - AudioEngine - PixelRoot32 Documentation
Skip to content

AudioEngine

Core class for the NES-like audio subsystem.

Description

AudioEngine manages the audio channels (Pulse, Triangle, Noise), mixes their output, and provides the audio stream to the backend. It implements a NES-like audio system with 4 fixed channels: 2 Pulse channels, 1 Triangle channel, and 1 Noise channel.

The engine is event-driven: you trigger sound effects via playEvent(), and the engine automatically manages channel allocation and playback.

Namespace

namespace pixelroot32::audio {
+ AudioEngine - PixelRoot32 Documentation      

AudioEngine

Core class for the NES-like audio subsystem.

Description

AudioEngine manages the audio channels (Pulse, Triangle, Noise), mixes their output, and provides the audio stream to the backend. It implements a NES-like audio system with 4 fixed channels: 2 Pulse channels, 1 Triangle channel, and 1 Noise channel.

The engine is event-driven: you trigger sound effects via playEvent(), and the engine automatically manages channel allocation and playback.

Namespace

namespace pixelroot32::audio {
     class AudioEngine {
         // ...
     };
@@ -88,4 +88,4 @@
         }
     }
 };
-

Performance Considerations

  • Channel limit: Only 4 channels total; plan sound effects accordingly
  • Event dropping: If all channels are busy, new events are silently dropped
  • Update frequency: update() must be called every frame for proper timing
  • Sample generation: generateSamples() is called by backend at audio rate (not game rate)

ESP32 Considerations

  • Sample rate: Lower sample rates (11025 Hz) use less CPU and memory
  • Backend choice: DAC backend is simpler but lower quality than I2S
  • Buffer size: Larger buffers reduce underruns but increase latency
  • Channel management: Limit simultaneous sounds to avoid channel conflicts

See Also

\ No newline at end of file +

Performance Considerations

  • Channel limit: Only 4 channels total; plan sound effects accordingly
  • Event dropping: If all channels are busy, new events are silently dropped
  • Update frequency: update() must be called every frame for proper timing
  • Sample generation: generateSamples() is called by backend at audio rate (not game rate)

ESP32 Considerations

  • Sample rate: Lower sample rates (11025 Hz) use less CPU and memory
  • Backend choice: DAC backend is simpler but lower quality than I2S
  • Buffer size: Larger buffers reduce underruns but increase latency
  • Channel management: Limit simultaneous sounds to avoid channel conflicts

See Also

\ No newline at end of file diff --git a/site/api_reference/audio/audio_types/index.html b/site/api_reference/audio/audio_types/index.html index 6b8a9e6..566764e 100644 --- a/site/api_reference/audio/audio_types/index.html +++ b/site/api_reference/audio/audio_types/index.html @@ -1,4 +1,4 @@ - Audio Types - PixelRoot32 Documentation
Skip to content

Audio Types

Data structures and types for the audio system.

Description

This document describes the data structures used by the audio system, including wave types, audio events, and channel state.

Namespace

namespace pixelroot32::audio {
+ Audio Types - PixelRoot32 Documentation      

Audio Types

Data structures and types for the audio system.

Description

This document describes the data structures used by the audio system, including wave types, audio events, and channel state.

Namespace

namespace pixelroot32::audio {
     // Types and structures
 }
 

WaveType Enum

Defines the types of waveforms available.

Values: - WaveType::PULSE: Pulse wave (square wave with variable duty cycle) - WaveType::TRIANGLE: Triangle wave (smooth, melodic) - WaveType::NOISE: Noise wave (random, percussive)

Example:

pixelroot32::audio::WaveType wave = pixelroot32::audio::WaveType::PULSE;
@@ -97,4 +97,4 @@
         delay(50);  // Small delay between events
     }
 }
-

Performance Considerations

  • Event creation: Creating events is fast (just struct initialization)
  • Channel allocation: Events are queued and played when channels are available
  • Frequency range: Keep frequencies in reasonable range (100-5000 Hz) for best results
  • Duration: Shorter durations free channels faster

ESP32 Considerations

  • Memory: Events are small structs, safe to create frequently
  • CPU: Audio generation is efficient but limit simultaneous sounds
  • Quality: Lower sample rates reduce CPU usage

See Also

\ No newline at end of file +

Performance Considerations

  • Event creation: Creating events is fast (just struct initialization)
  • Channel allocation: Events are queued and played when channels are available
  • Frequency range: Keep frequencies in reasonable range (100-5000 Hz) for best results
  • Duration: Shorter durations free channels faster

ESP32 Considerations

  • Memory: Events are small structs, safe to create frequently
  • CPU: Audio generation is efficient but limit simultaneous sounds
  • Quality: Lower sample rates reduce CPU usage

See Also

\ No newline at end of file diff --git a/site/api_reference/audio/music_player/index.html b/site/api_reference/audio/music_player/index.html index 189d396..2a4f12c 100644 --- a/site/api_reference/audio/music_player/index.html +++ b/site/api_reference/audio/music_player/index.html @@ -1,4 +1,4 @@ - MusicPlayer - PixelRoot32 Documentation
Skip to content

MusicPlayer

Lightweight sequencer built on top of AudioEngine to play background melodies as tracks.

Description

MusicPlayer is a simple sequencer that plays MusicTrack structures. It advances notes based on game time, converts MusicNote entries to AudioEvent calls, and manages playback state (play, stop, pause, resume).

The player uses one audio channel (typically a Pulse channel) for music, leaving other channels available for sound effects.

Namespace

namespace pixelroot32::audio {
+ MusicPlayer - PixelRoot32 Documentation      

MusicPlayer

Lightweight sequencer built on top of AudioEngine to play background melodies as tracks.

Description

MusicPlayer is a simple sequencer that plays MusicTrack structures. It advances notes based on game time, converts MusicNote entries to AudioEvent calls, and manages playback state (play, stop, pause, resume).

The player uses one audio channel (typically a Pulse channel) for music, leaving other channels available for sound effects.

Namespace

namespace pixelroot32::audio {
     class MusicPlayer {
         // ...
     };
@@ -106,4 +106,4 @@
         music.stop();
     }
 };
-

Performance Considerations

  • One channel: Music uses one channel, leaving others for sound effects
  • Update frequency: update() must be called every frame
  • Track size: Larger tracks use more memory (store in flash)
  • Tempo factor: Changing tempo is fast (just a multiplier)

ESP32 Considerations

  • Memory: Store tracks in flash (const/constexpr) to save RAM
  • CPU: Music playback is lightweight (simple sequencing)
  • Channel conflict: Music and sound effects share channels; plan accordingly

See Also

\ No newline at end of file +

Performance Considerations

  • One channel: Music uses one channel, leaving others for sound effects
  • Update frequency: update() must be called every frame
  • Track size: Larger tracks use more memory (store in flash)
  • Tempo factor: Changing tempo is fast (just a multiplier)

ESP32 Considerations

  • Memory: Store tracks in flash (const/constexpr) to save RAM
  • CPU: Music playback is lightweight (simple sequencing)
  • Channel conflict: Music and sound effects share channels; plan accordingly

See Also

\ No newline at end of file diff --git a/site/api_reference/core/actor/index.html b/site/api_reference/core/actor/index.html index 62e0cdb..4fef897 100644 --- a/site/api_reference/core/actor/index.html +++ b/site/api_reference/core/actor/index.html @@ -1,4 +1,4 @@ - Actor - PixelRoot32 Documentation
Skip to content

Actor

An Entity capable of physical interaction and collision.

Description

Actor extends Entity with collision layers and masks. Actors are used for dynamic game objects like players, enemies, projectiles, and obstacles that need to interact with each other through collision detection.

Actors participate in the collision system and can detect collisions with other actors based on their collision layers and masks.

Namespace

namespace pixelroot32::core {
+ Actor - PixelRoot32 Documentation      

Actor

An Entity capable of physical interaction and collision.

Description

Actor extends Entity with collision layers and masks. Actors are used for dynamic game objects like players, enemies, projectiles, and obstacles that need to interact with each other through collision detection.

Actors participate in the collision system and can detect collisions with other actors based on their collision layers and masks.

Namespace

namespace pixelroot32::core {
     class Actor : public Entity {
         // ...
     };
@@ -126,4 +126,4 @@
         }
     }
 };
-

Performance Considerations

  • Collision layers: Use layers efficiently to reduce collision checks
  • Hitbox size: Keep hitboxes simple (AABB) for best performance
  • Collision callbacks: Keep onCollision() fast; avoid expensive operations
  • Layer organization: Group actors by layer to minimize checks

ESP32 Considerations

  • Collision checks: Collision system automatically optimizes using layers
  • Memory: Each actor consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse actors instead of creating/destroying frequently

See Also

\ No newline at end of file +

Performance Considerations

  • Collision layers: Use layers efficiently to reduce collision checks
  • Hitbox size: Keep hitboxes simple (AABB) for best performance
  • Collision callbacks: Keep onCollision() fast; avoid expensive operations
  • Layer organization: Group actors by layer to minimize checks

ESP32 Considerations

  • Collision checks: Collision system automatically optimizes using layers
  • Memory: Each actor consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse actors instead of creating/destroying frequently

See Also

\ No newline at end of file diff --git a/site/api_reference/core/engine/index.html b/site/api_reference/core/engine/index.html index 1bad076..a044ef4 100644 --- a/site/api_reference/core/engine/index.html +++ b/site/api_reference/core/engine/index.html @@ -1,4 +1,4 @@ - Engine - PixelRoot32 Documentation
Skip to content

Engine

The main engine class that manages the game loop and core subsystems.

Description

Engine acts as the central hub of the PixelRoot32 game engine. It initializes and manages the Renderer, InputManager, AudioEngine, and SceneManager. It runs the main game loop, handling timing (delta time), updating the current scene, and rendering frames.

The engine provides a unified interface for both ESP32 and Native (SDL2) platforms, abstracting platform-specific details while maintaining consistent behavior.

Namespace

namespace pixelroot32::core {
+ Engine - PixelRoot32 Documentation      

Engine

The main engine class that manages the game loop and core subsystems.

Description

Engine acts as the central hub of the PixelRoot32 game engine. It initializes and manages the Renderer, InputManager, AudioEngine, and SceneManager. It runs the main game loop, handling timing (delta time), updating the current scene, and rendering frames.

The engine provides a unified interface for both ESP32 and Native (SDL2) platforms, abstracting platform-specific details while maintaining consistent behavior.

Namespace

namespace pixelroot32::core {
     class Engine {
         // ...
     };
@@ -9,8 +9,8 @@
 #include "audio/AudioConfig.h"
 
 pixelroot32::graphics::DisplayConfig displayConfig;
-displayConfig.width = 128;
-displayConfig.height = 128;
+displayConfig.logicalWidth = 128;
+displayConfig.logicalHeight = 128;
 
 pixelroot32::input::InputConfig inputConfig;
 // Configure input pins...
@@ -85,17 +85,17 @@
     auto& music = engine.getMusicPlayer();
     music.playTrack(myMusicTrack);
 }
-

Optional: FPS overlay

When the engine is built with the preprocessor define PIXELROOT32_ENABLE_FPS_DISPLAY, an on-screen FPS counter is drawn each frame.

Behavior:

  • A green text string "FPS xxx" is drawn in the top-right area (position from Renderer::getWidth() and a fixed Y offset).
  • The value is derived from frame delta time (FPS = 1000 / deltaTime ms), clamped to 0–999.

Performance:

  • The numeric value is recalculated and formatted only every 8 frames; the cached string is drawn every frame to keep the overlay visible without extra per-frame cost (division and snprintf are done at most once every 8 frames).

How to enable:

In platformio.ini, add to your environment's build_flags:

build_flags =
-    -D PIXELROOT32_ENABLE_FPS_DISPLAY
-

No code changes are required; the overlay is drawn automatically after the scene in Engine::draw(). The implementation uses the private method drawFpsOverlay(Renderer& r), which is only compiled when the define is set.

See also: Performance Tuning - Profiling and Platforms and Drivers - Build flags.

Usage Example

#include "core/Engine.h"
+

Optional: Debug Statistics Overlay

When the engine is built with the preprocessor define PIXELROOT32_ENABLE_DEBUG_OVERLAY, an on-screen technical overlay is drawn each frame.

Metrics Included:

  • FPS: Frames per second (Green).
  • RAM: Used heap memory in KB (Cyan).
  • CPU: Estimated processor load percentage (Yellow).

Behavior:

  • The overlay is drawn in the top-right area of the screen.
  • It is rendered after the scene, making it fixed and independent of the camera.

Performance:

  • Metric values are recalculated and formatted only every 16 frames (DEBUG_UPDATE_INTERVAL).
  • Cached strings are drawn every frame to minimize per-frame cost (division and snprintf).

How to enable:

In platformio.ini, add to your environment's build_flags:

build_flags =
+    -D PIXELROOT32_ENABLE_DEBUG_OVERLAY
+

Alternatively, you can enable it in EngineConfig.h. The implementation uses the private method drawDebugOverlay(Renderer& r), which is only compiled when the define is set.

See also: Performance Tuning - Profiling and Platforms and Drivers - Build flags.

Usage Example

#include "core/Engine.h"
 #include "graphics/DisplayConfig.h"
 #include "MyScene.h"
 
 void setup() {
     // Configure display
     pixelroot32::graphics::DisplayConfig displayConfig;
-    displayConfig.width = 128;
-    displayConfig.height = 128;
+    displayConfig.logicalWidth = 128;
+    displayConfig.logicalHeight = 128;
     displayConfig.rotation = 0;
 
     // Create engine
@@ -111,4 +111,4 @@
     // Run game loop
     engine.run();
 }
-

Performance Considerations

  • Initialization: init() should be called once at startup, not in the game loop
  • Scene switching: Switching scenes is fast but avoid doing it every frame
  • Subsystem access: Getters are inline and very fast; safe to call every frame
  • Delta time: Use getDeltaTime() for frame-rate independent movement

ESP32 Considerations

  • Ensure init() completes before run() to avoid initialization issues
  • Monitor memory usage when switching scenes frequently
  • Use getDeltaTime() for consistent gameplay across different frame rates

See Also

\ No newline at end of file +

Performance Considerations

  • Initialization: init() should be called once at startup, not in the game loop
  • Scene switching: Switching scenes is fast but avoid doing it every frame
  • Subsystem access: Getters are inline and very fast; safe to call every frame
  • Delta time: Use getDeltaTime() for frame-rate independent movement

ESP32 Considerations

  • Ensure init() completes before run() to avoid initialization issues
  • Monitor memory usage when switching scenes frequently
  • Use getDeltaTime() for consistent gameplay across different frame rates

See Also

\ No newline at end of file diff --git a/site/api_reference/core/entity/index.html b/site/api_reference/core/entity/index.html index f63014a..47151c9 100644 --- a/site/api_reference/core/entity/index.html +++ b/site/api_reference/core/entity/index.html @@ -1,4 +1,4 @@ - Entity - PixelRoot32 Documentation
Skip to content

Entity

Abstract base class for all game objects.

Description

Entity is the fundamental building block of the scene. Entities have a position, size, and lifecycle methods (update, draw). All game objects inherit from Entity, including actors, UI elements, and custom game objects.

Entities are managed by Scene and are automatically updated and drawn each frame when enabled and visible.

Namespace

namespace pixelroot32::core {
+ Entity - PixelRoot32 Documentation      

Entity

Abstract base class for all game objects.

Description

Entity is the fundamental building block of the scene. Entities have a position, size, and lifecycle methods (update, draw). All game objects inherit from Entity, including actors, UI elements, and custom game objects.

Entities are managed by Scene and are automatically updated and drawn each frame when enabled and visible.

Namespace

namespace pixelroot32::core {
     class Entity {
         // ...
     };
@@ -84,4 +84,4 @@
 private:
     float rotation = 0.0f;
 };
-

Performance Considerations

  • Visibility: Use isVisible = false instead of removing entities when hiding
  • Enable state: Use isEnabled = false to pause entity logic
  • Render layers: Organize entities by layer to minimize layer switches
  • Direct access: Direct property access is fast (no function call overhead)

ESP32 Considerations

  • Memory: Each entity consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse entities instead of creating/destroying frequently
  • Update frequency: Disable entities that don't need to update every frame

See Also

\ No newline at end of file +

Performance Considerations

  • Visibility: Use isVisible = false instead of removing entities when hiding
  • Enable state: Use isEnabled = false to pause entity logic
  • Render layers: Organize entities by layer to minimize layer switches
  • Direct access: Direct property access is fast (no function call overhead)

ESP32 Considerations

  • Memory: Each entity consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse entities instead of creating/destroying frequently
  • Update frequency: Disable entities that don't need to update every frame

See Also

\ No newline at end of file diff --git a/site/api_reference/core/input_config/index.html b/site/api_reference/core/input_config/index.html index 2ae3e1e..3e08d9a 100644 --- a/site/api_reference/core/input_config/index.html +++ b/site/api_reference/core/input_config/index.html @@ -1,4 +1,4 @@ - InputConfig - PixelRoot32 Documentation
Skip to content

InputConfig

Configuration structure for the InputManager.

Description

InputConfig defines the mapping between logical inputs and physical pins (ESP32) or keyboard keys (Native/SDL2). It uses variadic arguments to allow flexible configuration of any number of inputs.

The configuration is platform-specific: ESP32 uses GPIO pin numbers, while Native uses SDL keyboard scancodes.

Namespace

namespace pixelroot32::input {
+ InputConfig - PixelRoot32 Documentation      

InputConfig

Configuration structure for the InputManager.

Description

InputConfig defines the mapping between logical inputs and physical pins (ESP32) or keyboard keys (Native/SDL2). It uses variadic arguments to allow flexible configuration of any number of inputs.

The configuration is platform-specific: ESP32 uses GPIO pin numbers, while Native uses SDL keyboard scancodes.

Namespace

namespace pixelroot32::input {
     struct InputConfig {
         // ...
     };
@@ -117,4 +117,4 @@
     SDL_SCANCODE_SPACE,    // Jump
     SDL_SCANCODE_RETURN    // Action
 );
-

Performance Considerations

  • Memory: Arrays are allocated dynamically (small overhead)
  • Configuration: Done once at startup, no runtime cost
  • Access: Button indices are fast (array access)

ESP32 Considerations

  • Pin configuration: Ensure pins are not used by other peripherals
  • Debouncing: Hardware debouncing recommended for reliable input
  • Power: Buttons should use pull-up resistors to avoid floating pins

See Also

\ No newline at end of file +

Performance Considerations

  • Memory: Arrays are allocated dynamically (small overhead)
  • Configuration: Done once at startup, no runtime cost
  • Access: Button indices are fast (array access)

ESP32 Considerations

  • Pin configuration: Ensure pins are not used by other peripherals
  • Debouncing: Hardware debouncing recommended for reliable input
  • Power: Buttons should use pull-up resistors to avoid floating pins

See Also

\ No newline at end of file diff --git a/site/api_reference/core/input_manager/index.html b/site/api_reference/core/input_manager/index.html index f85711e..5cf90a2 100644 --- a/site/api_reference/core/input_manager/index.html +++ b/site/api_reference/core/input_manager/index.html @@ -1,4 +1,4 @@ - InputManager - PixelRoot32 Documentation
Skip to content

InputManager

Handles input from physical buttons or keyboard (on PC).

Description

The InputManager polls configured pins (ESP32) or keyboard state (Native), handles debouncing, and tracks button states (Pressed, Released, Down, Clicked). It provides a unified input interface for both platforms.

The manager supports edge detection (just pressed/released) and continuous state (held down), making it suitable for both gameplay and UI navigation.

Namespace

namespace pixelroot32::input {
+ InputManager - PixelRoot32 Documentation      

InputManager

Handles input from physical buttons or keyboard (on PC).

Description

The InputManager polls configured pins (ESP32) or keyboard state (Native), handles debouncing, and tracks button states (Pressed, Released, Down, Clicked). It provides a unified input interface for both platforms.

The manager supports edge detection (just pressed/released) and continuous state (held down), making it suitable for both gameplay and UI navigation.

Namespace

namespace pixelroot32::input {
     class InputManager {
         // ...
     };
@@ -126,4 +126,4 @@
         }
     }
 };
-

Input State Comparison

Method Returns true when Use Case
isButtonPressed() Button just pressed this frame One-time actions (jump, shoot)
isButtonReleased() Button just released this frame Release events (stop charging)
isButtonClicked() Button pressed then released UI buttons, menu selection
isButtonDown() Button currently held Continuous actions (movement)

Performance Considerations

  • Update frequency: update() must be called every frame
  • Debouncing: Handled automatically, no performance impact
  • State queries: All query methods are fast (inline accessors)
  • Memory: Button state arrays are small and efficient

ESP32 Considerations

  • GPIO pins: Configure pins in InputConfig
  • Pull-up/pull-down: Ensure proper resistor configuration
  • Debouncing: Hardware debouncing recommended for noisy buttons
  • Pin limits: Some ESP32 pins have restrictions (check datasheet)

Native Considerations

  • Keyboard mapping: Uses SDL scancodes
  • Key detection: Automatically handles keyboard state
  • Multiple keys: Can detect multiple keys simultaneously

See Also

\ No newline at end of file +

Input State Comparison

Method Returns true when Use Case
isButtonPressed() Button just pressed this frame One-time actions (jump, shoot)
isButtonReleased() Button just released this frame Release events (stop charging)
isButtonClicked() Button pressed then released UI buttons, menu selection
isButtonDown() Button currently held Continuous actions (movement)

Performance Considerations

  • Update frequency: update() must be called every frame
  • Debouncing: Handled automatically, no performance impact
  • State queries: All query methods are fast (inline accessors)
  • Memory: Button state arrays are small and efficient

ESP32 Considerations

  • GPIO pins: Configure pins in InputConfig
  • Pull-up/pull-down: Ensure proper resistor configuration
  • Debouncing: Hardware debouncing recommended for noisy buttons
  • Pin limits: Some ESP32 pins have restrictions (check datasheet)

Native Considerations

  • Keyboard mapping: Uses SDL scancodes
  • Key detection: Automatically handles keyboard state
  • Multiple keys: Can detect multiple keys simultaneously

See Also

\ No newline at end of file diff --git a/site/api_reference/core/physics_actor/index.html b/site/api_reference/core/physics_actor/index.html index 46b7d6b..7e192a2 100644 --- a/site/api_reference/core/physics_actor/index.html +++ b/site/api_reference/core/physics_actor/index.html @@ -1,4 +1,4 @@ - PhysicsActor - PixelRoot32 Documentation
Skip to content

PhysicsActor

An actor with basic 2D physics properties.

Description

PhysicsActor extends the base Actor class by adding velocity, acceleration, friction, restitution (bounciness), and world boundary collision resolution. It is designed for objects that need to move and bounce within a defined area, such as balls, projectiles, or platformer characters.

PhysicsActor automatically handles: - Velocity-based movement - Friction application - World boundary collision and bouncing - Collision callbacks

Namespace

namespace pixelroot32::core {
+ PhysicsActor - PixelRoot32 Documentation      

PhysicsActor

An actor with basic 2D physics properties.

Description

PhysicsActor extends the base Actor class by adding velocity, acceleration, friction, restitution (bounciness), and world boundary collision resolution. It is designed for objects that need to move and bounce within a defined area, such as balls, projectiles, or platformer characters.

PhysicsActor automatically handles: - Velocity-based movement - Friction application - World boundary collision and bouncing - Collision callbacks

Namespace

namespace pixelroot32::core {
     class PhysicsActor : public Actor {
         // ...
     };
@@ -154,4 +154,4 @@
         playBounceSound();
     }
 };
-

Performance Considerations

  • Physics integration: Very efficient (simple velocity integration)
  • World bounds: Boundary checks are fast (AABB)
  • Friction: Applied every frame; keep friction values reasonable
  • Collision callbacks: Keep onCollision() and onWorldCollision() fast

ESP32 Considerations

  • Floating point: Uses float math; acceptable for ESP32 but integer math would be faster
  • Frame rate: Physics is frame-rate independent (uses deltaTime)
  • Memory: Each PhysicsActor consumes more memory than Actor (velocity, limits, etc.)

See Also

\ No newline at end of file +

Performance Considerations

  • Physics integration: Very efficient (simple velocity integration)
  • World bounds: Boundary checks are fast (AABB)
  • Friction: Applied every frame; keep friction values reasonable
  • Collision callbacks: Keep onCollision() and onWorldCollision() fast

ESP32 Considerations

  • Floating point: Uses float math; acceptable for ESP32 but integer math would be faster
  • Frame rate: Physics is frame-rate independent (uses deltaTime)
  • Memory: Each PhysicsActor consumes more memory than Actor (velocity, limits, etc.)

See Also

\ No newline at end of file diff --git a/site/api_reference/core/scene/index.html b/site/api_reference/core/scene/index.html index 0b7713d..ae5e58f 100644 --- a/site/api_reference/core/scene/index.html +++ b/site/api_reference/core/scene/index.html @@ -1,4 +1,4 @@ - Scene - PixelRoot32 Documentation
Skip to content

Scene

Represents a game level or screen containing entities.

Description

A Scene manages a collection of Entities and a CollisionSystem. It is responsible for updating and drawing all entities it contains. Scenes provide lifecycle hooks (init(), update(), draw()) to manage gameplay segments.

Scenes are the primary organizational unit in PixelRoot32, similar to levels or screens in other game engines. Each scene can contain up to MAX_ENTITIES (default 32; overridable via compiler flags) entities, and drawing uses up to MAX_LAYERS (default 3; overridable) render layers.

Namespace

namespace pixelroot32::core {
+ Scene - PixelRoot32 Documentation      

Scene

Represents a game level or screen containing entities.

Description

A Scene manages a collection of Entities and a CollisionSystem. It is responsible for updating and drawing all entities it contains. Scenes provide lifecycle hooks (init(), update(), draw()) to manage gameplay segments.

Scenes are the primary organizational unit in PixelRoot32, similar to levels or screens in other game engines. Each scene can contain up to MAX_ENTITIES (default 32; overridable via compiler flags) entities, and drawing uses up to MAX_LAYERS (default 3; overridable) render layers.

Namespace

namespace pixelroot32::core {
     class Scene {
         // ...
     };
@@ -128,4 +128,4 @@
         renderer.drawText(scoreText, 10, 10, Color::White, 1);
     }
 };
-

Performance Considerations

  • Entity limit: MAX_ENTITIES (default 32) can be overridden via compiler flags; plan accordingly
  • Add/Remove: Frequent add/remove operations can be expensive; use object pooling
  • Update order: Entities are updated in add order; consider order for dependencies
  • Collision checks: CollisionSystem automatically handles actor collisions efficiently

ESP32 Considerations

  • Memory: Each entity consumes memory; stay well below the limit
  • Object pooling: Essential for ESP32 to avoid memory fragmentation
  • Scene switching: Clearing and recreating scenes can fragment memory; reuse scenes when possible

See Also

\ No newline at end of file +

Performance Considerations

  • Entity limit: MAX_ENTITIES (default 32) can be overridden via compiler flags; plan accordingly
  • Add/Remove: Frequent add/remove operations can be expensive; use object pooling
  • Update order: Entities are updated in add order; consider order for dependencies
  • Collision checks: CollisionSystem automatically handles actor collisions efficiently

ESP32 Considerations

  • Memory: Each entity consumes memory; stay well below the limit
  • Object pooling: Essential for ESP32 to avoid memory fragmentation
  • Scene switching: Clearing and recreating scenes can fragment memory; reuse scenes when possible

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/camera2d/index.html b/site/api_reference/graphics/camera2d/index.html index abbddc2..917ce1f 100644 --- a/site/api_reference/graphics/camera2d/index.html +++ b/site/api_reference/graphics/camera2d/index.html @@ -1,4 +1,4 @@ - Camera2D - PixelRoot32 Documentation
Skip to content

Camera2D

2D camera for scrolling and viewport control.

Description

Camera2D controls viewport position and enables scrolling by shifting the renderer's display offset. It supports following targets, boundary constraints, and can be used for parallax effects.

The camera uses a dead-zone system: it only moves when the target is outside a central zone, creating smooth following behavior.

Namespace

namespace pixelroot32::graphics {
+ Camera2D - PixelRoot32 Documentation      

Camera2D

2D camera for scrolling and viewport control.

Description

Camera2D controls viewport position and enables scrolling by shifting the renderer's display offset. It supports following targets, boundary constraints, and can be used for parallax effects.

The camera uses a dead-zone system: it only moves when the target is outside a central zone, creating smooth following behavior.

Namespace

namespace pixelroot32::graphics {
     class Camera2D {
         // ...
     };
@@ -120,4 +120,4 @@
     renderer.setDisplayOffset(0, 0);
     renderer.drawText("Score: 100", 10, 10, Color::White, 1);
 }
-

Performance Considerations

  • Apply frequency: apply() is fast; safe to call every frame
  • Boundary checks: Boundary clamping is efficient
  • Following: Dead-zone calculations are lightweight

ESP32 Considerations

  • Float math: Uses floating point; acceptable but integer math would be faster
  • Memory: Camera is small (few floats); minimal memory usage

See Also

\ No newline at end of file +

Performance Considerations

  • Apply frequency: apply() is fast; safe to call every frame
  • Boundary checks: Boundary clamping is efficient
  • Following: Dead-zone calculations are lightweight

ESP32 Considerations

  • Float math: Uses floating point; acceptable but integer math would be faster
  • Memory: Camera is small (few floats); minimal memory usage

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/color/index.html b/site/api_reference/graphics/color/index.html index 75430fb..e0072e2 100644 --- a/site/api_reference/graphics/color/index.html +++ b/site/api_reference/graphics/color/index.html @@ -1,4 +1,4 @@ - Color - PixelRoot32 Documentation
Skip to content

Color

Color constants and palette management system.

Description

The Color enum provides color constants that map to palette indices. The engine supports both legacy mode (single global palette) and dual palette mode (separate palettes for backgrounds and sprites).

Colors are resolved to 16-bit RGB565 values based on the active palette(s).

Namespace

namespace pixelroot32::graphics {
+ Color - PixelRoot32 Documentation      

Color

Color constants and palette management system.

Description

The Color enum provides color constants that map to palette indices. The engine supports both legacy mode (single global palette) and dual palette mode (separate palettes for backgrounds and sprites).

Colors are resolved to 16-bit RGB565 values based on the active palette(s).

Namespace

namespace pixelroot32::graphics {
     enum class Color : uint8_t {
         // ...
     };
@@ -70,4 +70,4 @@
 pixelroot32::graphics::enableDualPaletteMode(true);
 pixelroot32::graphics::setBackgroundCustomPalette(CUSTOM_PALETTE);
 pixelroot32::graphics::setSpriteCustomPalette(CUSTOM_PALETTE);
-

Performance Considerations

  • Color resolution: Fast lookup operation
  • Palette switching: Changing palettes is fast (just pointer assignment)
  • Memory: Palettes are stored in flash (const arrays) for best performance
  • Dual mode: Slightly more overhead than legacy mode, but minimal

ESP32 Considerations

  • Flash storage: Store custom palettes in flash (const/constexpr)
  • Memory: Palettes are small (16 uint16_t = 32 bytes)
  • Palette switching: Avoid switching palettes every frame

See Also

\ No newline at end of file +

Performance Considerations

  • Color resolution: Fast lookup operation
  • Palette switching: Changing palettes is fast (just pointer assignment)
  • Memory: Palettes are stored in flash (const arrays) for best performance
  • Dual mode: Slightly more overhead than legacy mode, but minimal

ESP32 Considerations

  • Flash storage: Store custom palettes in flash (const/constexpr)
  • Memory: Palettes are small (16 uint16_t = 32 bytes)
  • Palette switching: Avoid switching palettes every frame

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/display_config/index.html b/site/api_reference/graphics/display_config/index.html index 9aa24d3..1251e64 100644 --- a/site/api_reference/graphics/display_config/index.html +++ b/site/api_reference/graphics/display_config/index.html @@ -1,90 +1,99 @@ - DisplayConfig - PixelRoot32 Documentation
Skip to content

DisplayConfig

Configuration settings for initializing the display.

Description

DisplayConfig holds display parameters used by the renderer and camera to draw correctly on the target device. It defines the display type, dimensions, rotation, and creates the appropriate DrawSurface implementation for the platform.

Namespace

namespace pixelroot32::graphics {
+ DisplayConfig - PixelRoot32 Documentation      

DisplayConfig

Configuration settings for initializing the display.

Description

DisplayConfig holds display parameters used by the renderer and camera to draw correctly on the target device. It defines the display type, dimensions, rotation, and creates the appropriate DrawSurface implementation for the platform.

Namespace

namespace pixelroot32::graphics {
     struct DisplayConfig {
         // ...
     };
 }
-

DisplayType Enum

Supported display types:

  • DisplayType::ST7789: 240x240 TFT display
  • DisplayType::ST7735: 128x128 TFT display
  • DisplayType::NONE: For SDL2 native (no driver needed)

Structure

DisplayType type

The type of display.

Type: DisplayType enum

Access: Read-write

Notes: - Determines which driver to use (ESP32) - NONE for Native/SDL2 platform

int rotation

Display rotation in degrees.

Type: int

Access: Read-write

Default: 0

Notes: - Common values: 0, 90, 180, 270 - Rotation is applied during initialization - Some displays may not support all rotations

uint16_t width

Display width in pixels.

Type: uint16_t

Access: Read-write

Default: 240

Notes: - Should match actual display width - Used for viewport and camera calculations

uint16_t height

Display height in pixels.

Type: uint16_t

Access: Read-write

Default: 240

Notes: - Should match actual display height - Used for viewport and camera calculations

int xOffset

X offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

int yOffset

Y offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

DrawSurface& getDrawSurface() const

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed - Provides access to low-level display driver - Platform-specific implementation

Constructors

DisplayConfig(DisplayType type, const int rot = 0, uint16_t w = 240, uint16_t h = 240, const int xOffset = 0, const int yOffset = 0)

Constructs a DisplayConfig with specified parameters.

Parameters: - type (DisplayType): The display type - rot (int, optional): Rotation in degrees. Default: 0 - w (uint16_t, optional): Width in pixels. Default: 240 - h (uint16_t, optional): Height in pixels. Default: 240 - xOffset (int, optional): X offset. Default: 0 - yOffset (int, optional): Y offset. Default: 0

Notes: - Automatically creates the appropriate DrawSurface for the platform - ESP32: Creates TFT_eSPI_Drawer based on display type - Native: Creates SDL2_Drawer

Example:

// ST7789 display, 240x240, no rotation
+

DisplayType Enum

Supported display types:

  • DisplayType::ST7789: 240x240 TFT display
  • DisplayType::ST7735: 128x128 TFT display
  • DisplayType::NONE: For SDL2 native (no driver needed)

Structure

DisplayType type

The type of display.

Type: DisplayType enum

Access: Read-write

Notes: - Determines which driver to use (ESP32) - NONE for Native/SDL2 platform

int rotation

Display rotation in degrees.

Type: int

Access: Read-write

Default: 0

Notes: - Common values: 0, 90, 180, 270 - Rotation is applied during initialization - Some displays may not support all rotations

uint16_t physicalWidth

Physical hardware width of the display.

Type: uint16_t

Access: Read-write

Notes: - Defines the actual resolution of the display hardware.

uint16_t physicalHeight

Physical hardware height of the display.

Type: uint16_t

Access: Read-write

Notes: - Defines the actual resolution of the display hardware.

uint16_t logicalWidth

Logical rendering width. This is the resolution the game "sees" and draws to.

Type: uint16_t

Access: Read-write

Notes: - If smaller than physicalWidth, the image will be scaled up. - Used for clipping, camera, and UI calculations. - Recommended values for ESP32: 160, 128, 96 (for 240 physical).

uint16_t logicalHeight

Logical rendering height. This is the resolution the game "sees" and draws to.

Type: uint16_t

Access: Read-write

Notes: - If smaller than physicalHeight, the image will be scaled up. - Used for clipping, camera, and UI calculations.

uint16_t width() (Deprecated)

Alias for logicalWidth. Maintained for backward compatibility.

uint16_t height() (Deprecated)

Alias for logicalHeight. Maintained for backward compatibility.

int xOffset

X offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

int yOffset

Y offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

DrawSurface& getDrawSurface() const

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed - Provides access to low-level display driver - Platform-specific implementation

Resolution Helpers

bool needsScaling() const

Checks if the logical resolution differs from the physical resolution.

Returns: - bool: true if scaling is active.

float getScaleX() const

Gets the horizontal scaling factor (physicalWidth / logicalWidth).

float getScaleY() const

Gets the vertical scaling factor (physicalHeight / logicalHeight).

Constructors

DisplayConfig(DisplayType type, const int rot, uint16_t physW, uint16_t physH, uint16_t logW, uint16_t logH, const int xOff = 0, const int yOff = 0)

Extended constructor that allows defining separate physical and logical resolutions.

Parameters: - type (DisplayType): The display type. - rot (int): Rotation (0-3 or degrees depending on implementation). - physW (uint16_t): Physical hardware width. - physH (uint16_t): Physical hardware height. - logW (uint16_t): Logical rendering width (0 = same as physical). - logH (uint16_t): Logical rendering height (0 = same as physical). - xOff (int, optional): X alignment offset. - yOff (int, optional): Y alignment offset.

Example:

// 128x128 game logic scaled to 240x240 display
 pixelroot32::graphics::DisplayConfig config(
-    pixelroot32::graphics::DisplayType::ST7789
-);
-
-// ST7735 display, 128x128, rotated 90 degrees
-pixelroot32::graphics::DisplayConfig config(
-    pixelroot32::graphics::DisplayType::ST7735,
-    90,   // rotation
-    128,  // width
-    128   // height
-);
-
-// Native/SDL2 (no specific display type)
-pixelroot32::graphics::DisplayConfig config(
-    pixelroot32::graphics::DisplayType::NONE,
-    0,    // rotation
-    128,  // width
-    128   // height
-);
-

Usage Examples

ESP32 with ST7789

#ifdef PLATFORM_ESP32
-#include "graphics/DisplayConfig.h"
-
-void setup() {
-    // Configure ST7789 display (240x240)
-    pixelroot32::graphics::DisplayConfig displayConfig(
-        pixelroot32::graphics::DisplayType::ST7789,
-        0,    // rotation
-        240,  // width
-        240   // height
-    );
-
-    // Use with Engine
-    pixelroot32::core::Engine engine(displayConfig);
-    engine.init();
-    engine.run();
-}
-#endif
-

ESP32 with ST7735

#ifdef PLATFORM_ESP32
-    // Configure ST7735 display (128x128)
-    pixelroot32::graphics::DisplayConfig displayConfig(
-        pixelroot32::graphics::DisplayType::ST7735,
-        0,    // rotation
-        128,  // width
-        128   // height
-    );
-#endif
-

Native/SDL2

#ifdef PLATFORM_NATIVE
-    // Native display (SDL2 window)
+    pixelroot32::graphics::DisplayType::ST7789,
+    0,    // rotation
+    240, 240, // physical
+    128, 128  // logical
+);
+

DisplayConfig(DisplayType type, const int rot = 0, uint16_t w = 240, uint16_t h = 240, const int xOffset = 0, const int yOffset = 0)

Legacy constructor for backward compatibility. Sets both logical and physical resolutions to the same values.

Notes: - Automatically creates the appropriate DrawSurface for the platform - ESP32: Creates TFT_eSPI_Drawer based on display type - Native: Creates SDL2_Drawer

Example:

// ST7789 display, 240x240, no rotation
+pixelroot32::graphics::DisplayConfig config(
+    pixelroot32::graphics::DisplayType::ST7789
+);
+
+// ST7735 display, 128x128, rotated 90 degrees
+pixelroot32::graphics::DisplayConfig config(
+    pixelroot32::graphics::DisplayType::ST7735,
+    90,   // rotation
+    128,  // physical width
+    128,  // physical height
+    128,  // logical width
+    128   // logical height
+);
+
+// Native/SDL2 (no specific display type)
+pixelroot32::graphics::DisplayConfig config(
+    pixelroot32::graphics::DisplayType::NONE,
+    0,    // rotation
+    128, 128, // physical
+    128, 128  // logical
+);
+

Usage Examples

ESP32 with ST7789

#ifdef PLATFORM_ESP32
+#include "graphics/DisplayConfig.h"
+
+void setup() {
+    // Configure ST7789 display (240x240 physical, 128x128 logical)
+    pixelroot32::graphics::DisplayConfig displayConfig(
+        pixelroot32::graphics::DisplayType::ST7789,
+        0,    // rotation
+        240, 240, // physical
+        128, 128  // logical
+    );
+
+    // Use with Engine
+    pixelroot32::core::Engine engine(displayConfig);
+    engine.init();
+    engine.run();
+}
+#endif
+

ESP32 with ST7735

#ifdef PLATFORM_ESP32
+    // Configure ST7735 display (128x128)
     pixelroot32::graphics::DisplayConfig displayConfig(
-        pixelroot32::graphics::DisplayType::NONE,
+        pixelroot32::graphics::DisplayType::ST7735,
         0,    // rotation
-        128,  // width
-        128   // height
-    );
-#endif
-

Platform-Agnostic Setup

#include "graphics/DisplayConfig.h"
-#include "core/Engine.h"
-
-void setup() {
-    pixelroot32::graphics::DisplayConfig displayConfig;
-
-    #ifdef PLATFORM_ESP32
-        displayConfig.type = pixelroot32::graphics::DisplayType::ST7789;
-        displayConfig.width = 240;
-        displayConfig.height = 240;
-    #elif PLATFORM_NATIVE
-        displayConfig.type = pixelroot32::graphics::DisplayType::NONE;
-        displayConfig.width = 128;
-        displayConfig.height = 128;
-    #endif
-
-    displayConfig.rotation = 0;
-
-    pixelroot32::core::Engine engine(displayConfig);
-    engine.init();
-    engine.run();
-}
-

Display Type Details

ST7789

  • Resolution: Typically 240x240 or 240x320
  • Interface: SPI
  • Driver: TFT_eSPI
  • Common sizes: 240x240, 240x320

ST7735

  • Resolution: Typically 128x128 or 128x160
  • Interface: SPI
  • Driver: TFT_eSPI
  • Common sizes: 128x128, 128x160

NONE (Native)

  • Platform: Native/SDL2
  • Driver: SDL2_Drawer
  • Resolution: Configurable (any size)
  • Window: Creates SDL2 window

Rotation

Display rotation values:

  • 0: Normal orientation
  • 90: Rotated 90 degrees clockwise
  • 180: Rotated 180 degrees
  • 270: Rotated 90 degrees counter-clockwise

Notes: - Rotation affects coordinate system - Some displays may not support all rotations - Test rotation on your specific hardware

Performance Considerations

  • Initialization: Display initialization happens once at startup
  • Driver selection: Automatic based on platform and type
  • Memory: DisplayConfig is small (few fields)

ESP32 Considerations

TFT_eSPI Configuration

DisplayConfig uses TFT_eSPI driver. Additional configuration may be needed in platformio.ini:

build_flags =
-    -DUSER_SETUP_LOADED=1
-    -DST7789_DRIVER=1
-    -DTFT_WIDTH=240
-    -DTFT_HEIGHT=240
-    # ... pin configuration
-

Pin Configuration

GPIO pins must be configured separately (not in DisplayConfig):

  • MOSI: Data pin
  • SCLK: Clock pin
  • DC: Data/Command pin
  • RST: Reset pin
  • CS: Chip select pin (optional)

See Also

\ No newline at end of file + 128, 128 // physical & logical + ); +#endif +

Native/SDL2

#ifdef PLATFORM_NATIVE
+    // Native display (SDL2 window)
+    pixelroot32::graphics::DisplayConfig displayConfig(
+        pixelroot32::graphics::DisplayType::NONE,
+        0,    // rotation
+        240, 240 // logical & physical
+    );
+#endif
+

Platform-Agnostic Setup

#include "graphics/DisplayConfig.h"
+#include "core/Engine.h"
+
+void setup() {
+    pixelroot32::graphics::DisplayConfig displayConfig;
+
+    #ifdef PLATFORM_ESP32
+        displayConfig.type = pixelroot32::graphics::DisplayType::ST7789;
+        displayConfig.physicalWidth = 240;
+        displayConfig.physicalHeight = 240;
+        displayConfig.logicalWidth = 160; // 160x160 logic
+        displayConfig.logicalHeight = 160;
+    #elif PLATFORM_NATIVE
+        displayConfig.type = pixelroot32::graphics::DisplayType::NONE;
+        displayConfig.logicalWidth = 128;
+        displayConfig.logicalHeight = 128;
+    #endif
+
+    displayConfig.rotation = 0;
+
+    pixelroot32::core::Engine engine(displayConfig);
+    engine.init();
+    engine.run();
+}
+

Display Type Details

ST7789

  • Resolution: Typically 240x240 or 240x320
  • Interface: SPI
  • Driver: TFT_eSPI
  • Common sizes: 240x240, 240x320

ST7735

  • Resolution: Typically 128x128 or 128x160
  • Interface: SPI
  • Driver: TFT_eSPI
  • Common sizes: 128x128, 128x160

NONE (Native)

  • Platform: Native/SDL2
  • Driver: SDL2_Drawer
  • Resolution: Configurable (any size)
  • Window: Creates SDL2 window

Rotation

Display rotation values:

  • 0: Normal orientation
  • 90: Rotated 90 degrees clockwise
  • 180: Rotated 180 degrees
  • 270: Rotated 90 degrees counter-clockwise

Notes: - Rotation affects coordinate system - Some displays may not support all rotations - Test rotation on your specific hardware

Performance Considerations

  • Initialization: Display initialization happens once at startup
  • Driver selection: Automatic based on platform and type
  • Memory: DisplayConfig is small (few fields)

ESP32 Considerations

TFT_eSPI Configuration

DisplayConfig uses TFT_eSPI driver. Additional configuration may be needed in platformio.ini:

build_flags =
+    -DUSER_SETUP_LOADED=1
+    -DST7789_DRIVER=1
+    -DTFT_WIDTH=240
+    -DTFT_HEIGHT=240
+    # ... pin configuration
+

Pin Configuration

GPIO pins must be configured separately (not in DisplayConfig):

  • MOSI: Data pin
  • SCLK: Clock pin
  • DC: Data/Command pin
  • RST: Reset pin
  • CS: Chip select pin (optional)

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/font/index.html b/site/api_reference/graphics/font/index.html index f62dc14..bcc80aa 100644 --- a/site/api_reference/graphics/font/index.html +++ b/site/api_reference/graphics/font/index.html @@ -1,4 +1,4 @@ - Font - PixelRoot32 Documentation
Skip to content

Font

Descriptor for a bitmap font using 1bpp sprites.

Description

A Font contains an array of Sprite structures, one for each character in the font's character set. Each glyph is rendered as a 1bpp sprite, allowing consistent rendering across platforms.

The font uses fixed-width glyphs for simplicity and performance. All glyphs share the same width and height, with spacing between characters controlled by the spacing field.

Namespace

namespace pixelroot32::graphics {
+ Font - PixelRoot32 Documentation      

Font

Descriptor for a bitmap font using 1bpp sprites.

Description

A Font contains an array of Sprite structures, one for each character in the font's character set. Each glyph is rendered as a 1bpp sprite, allowing consistent rendering across platforms.

The font uses fixed-width glyphs for simplicity and performance. All glyphs share the same width and height, with spacing between characters controlled by the spacing field.

Namespace

namespace pixelroot32::graphics {
     struct Font {
         // ...
     };
@@ -121,4 +121,4 @@
 int getTextHeight(const Font* font) {
     return font ? font->lineHeight : 8;
 }
-

Performance Considerations

  • Font storage: Store fonts in flash (const/constexpr) for best performance
  • Glyph lookup: Fast array access (character code - firstChar)
  • Fixed width: Fixed-width fonts are faster than variable-width
  • Font switching: Changing fonts is fast (just pointer assignment)

ESP32 Considerations

  • Memory: Store font data in flash, not RAM
  • Font size: Larger fonts use more flash memory
  • Character range: Limit character range to save memory if not needed

See Also

\ No newline at end of file +

Performance Considerations

  • Font storage: Store fonts in flash (const/constexpr) for best performance
  • Glyph lookup: Fast array access (character code - firstChar)
  • Fixed width: Fixed-width fonts are faster than variable-width
  • Font switching: Changing fonts is fast (just pointer assignment)

ESP32 Considerations

  • Memory: Store font data in flash, not RAM
  • Font size: Larger fonts use more flash memory
  • Character range: Limit character range to save memory if not needed

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/renderer/index.html b/site/api_reference/graphics/renderer/index.html index 7543b8d..1de607b 100644 --- a/site/api_reference/graphics/renderer/index.html +++ b/site/api_reference/graphics/renderer/index.html @@ -1,4 +1,4 @@ - Renderer - PixelRoot32 Documentation
Skip to content

Renderer

High-level graphics rendering system for drawing shapes, text, sprites, and tilemaps.

Description

The Renderer class provides a unified API for drawing shapes, text, and images. It abstracts the underlying hardware implementation (DrawSurface) and manages display configuration, including rotation and offsets.

The renderer uses integer-only math for optimal performance on ESP32 and supports multiple sprite formats (1bpp, 2bpp, 4bpp) and multi-layer sprites.

Namespace

namespace pixelroot32::graphics {
+ Renderer - PixelRoot32 Documentation      

Renderer

High-level graphics rendering system for drawing shapes, text, sprites, and tilemaps.

Description

The Renderer class provides a unified API for drawing shapes, text, and images. It abstracts the underlying hardware implementation (DrawSurface) and manages display configuration, including rotation and resolution scaling.

All drawing operations are performed in logical screen space. If the logical resolution differs from the physical resolution, the renderer will automatically scale the output to fit the display using a high-performance nearest-neighbor algorithm.

The renderer uses integer-only math for optimal performance on ESP32 and supports multiple sprite formats (1bpp, 2bpp, 4bpp) and multi-layer sprites.

Namespace

namespace pixelroot32::graphics {
     class Renderer {
         // ...
     };
@@ -6,13 +6,16 @@
 

Inheritance

  • Base class: None (standalone class)
  • Used by: Engine (manages renderer instance)

Constructors

Renderer(const DisplayConfig& config)

Constructs the Renderer with a specific display configuration.

Parameters: - config (const DisplayConfig&): The display configuration settings (width, height, rotation, etc.)

Example:

#include "graphics/Renderer.h"
 #include "graphics/DisplayConfig.h"
 
-pixelroot32::graphics::DisplayConfig config;
-config.width = 128;
-config.height = 128;
-config.rotation = 0;
-
-pixelroot32::graphics::Renderer renderer(config);
-renderer.init();
+// 128x128 game logic scaled to 240x240 display
+pixelroot32::graphics::DisplayConfig config(
+    pixelroot32::graphics::DisplayType::ST7789,
+    0,      // rotation
+    240, 240, // physical resolution
+    128, 128  // logical resolution (rendering space)
+);
+
+pixelroot32::graphics::Renderer renderer(config);
+renderer.init();
 

Public Methods

void init()

Initializes the renderer and the underlying draw surface.

Returns: - void

Notes: - Must be called after construction and before any drawing operations - Initializes the platform-specific DrawSurface implementation - Safe to call multiple times (idempotent)

Example:

Renderer renderer(displayConfig);
 renderer.init();  // Initialize before use
 

void beginFrame()

Prepares the buffer for a new frame (clears screen).

Returns: - void

Notes: - Should be called once at the start of each frame - Clears the display buffer - Typically called automatically by Engine, but can be called manually

Example:

void draw(Renderer& renderer) override {
@@ -20,9 +23,9 @@
     // Draw everything...
     renderer.endFrame();
 }
-

void endFrame()

Finalizes the frame and sends the buffer to the display.

Returns: - void

Notes: - Should be called once at the end of each frame - Sends the completed frame buffer to the display - Typically called automatically by Engine, but can be called manually

DrawSurface& getDrawSurface()

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed unless implementing custom drawing - Provides low-level access to the display driver

void drawText(const char* text, int16_t x, int16_t y, Color color, uint8_t size)

Draws a string of text using the default font.

Parameters: - text (const char*): The text to draw (null-terminated string) - x (int16_t): X coordinate (top-left corner of text) - y (int16_t): Y coordinate (top-left corner of text) - color (Color): Text color - size (uint8_t): Text size multiplier (1 = normal, 2 = double, etc.)

Performance Notes: - Efficient for small amounts of text - Avoid calling in tight loops with long strings - Use static buffers for text formatting

Example:

renderer.drawText("Hello World", 10, 10, Color::White, 1);
+

void endFrame()

Finalizes the frame and sends the buffer to the display.

Returns: - void

Notes: - Should be called once at the end of each frame - Sends the completed frame buffer to the display - Typically called automatically by Engine, but can be called manually

DrawSurface& getDrawSurface()

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed unless implementing custom drawing - Provides low-level access to the display driver

void drawText(const char* text, int16_t x, int16_t y, Color color, uint8_t size)

Draws a string of text using the default font and scaling.

Parameters: - text (const char*): The text to draw (null-terminated string) - x (int16_t): X coordinate (top-left corner of text) - y (int16_t): Y coordinate (top-left corner of text) - color (Color): Text color - size (uint8_t): Text size multiplier (1 = 5x7 pixels, 2 = 10x14 pixels, etc.)

Performance Notes: - Efficient for small amounts of text - Uses integer-only scaling (no floats)

Example:

renderer.drawText("Hello World", 10, 10, Color::White, 1);
 renderer.drawText("Score: 100", 10, 30, Color::Yellow, 2);
-

void drawText(const char text, int16_t x, int16_t y, Color color, uint8_t size, const Font font)

Draws a string of text using a specific font.

Parameters: - text (const char): The text to draw - x (int16_t): X coordinate - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size multiplier - font (const Font): Pointer to the font to use. If nullptr, uses the default font

Example:

const Font* customFont = &FONT_5X7;
+

void drawText(const char text, int16_t x, int16_t y, Color color, uint8_t size, const Font font)

Draws a string of text using a specific font and scaling.

Parameters: - text (const char): The text to draw - x (int16_t): X coordinate - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size multiplier - font (const Font): Pointer to the font to use. If nullptr, uses the default font

Example:

const Font* customFont = &FONT_5X7;
 renderer.drawText("Custom Font", 10, 10, Color::White, 1, customFont);
 

void drawTextCentered(const char* text, int16_t y, Color color, uint8_t size)

Draws text centered horizontally at a given Y coordinate using the default font.

Parameters: - text (const char*): The text to draw - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size

Example:

renderer.drawTextCentered("Game Over", 64, Color::White, 2);
 

void drawTextCentered(const char text, int16_t y, Color color, uint8_t size, const Font font)

Draws text centered horizontally at a given Y coordinate using a specific font.

Parameters: - text (const char): The text to draw - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size - font (const Font): Pointer to the font to use. If nullptr, uses the default font

void drawFilledCircle(int x, int y, int radius, Color color)

Draws a filled circle.

Parameters: - x (int): Center X coordinate - y (int): Center Y coordinate - radius (int): Radius of the circle in pixels - color (Color): Fill color

Example:

renderer.drawFilledCircle(64, 64, 20, Color::Red);
@@ -31,22 +34,10 @@
 

void drawFilledRectangle(int x, int y, int width, int height, Color color)

Draws a filled rectangle.

Parameters: - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - width (int): Width of the rectangle in pixels - height (int): Height of the rectangle in pixels - color (Color): Fill color

Example:

renderer.drawFilledRectangle(10, 10, 100, 50, Color::Green);
 

void drawLine(int x1, int y1, int x2, int y2, Color color)

Draws a line between two points.

Parameters: - x1 (int): Start X coordinate - y1 (int): Start Y coordinate - x2 (int): End X coordinate - y2 (int): End Y coordinate - color (Color): Line color

Example:

renderer.drawLine(0, 0, 128, 128, Color::White);
 

void drawPixel(int x, int y, Color color)

Draws a single pixel.

Parameters: - x (int): X coordinate - y (int): Y coordinate - color (Color): Pixel color

Performance Notes: - Very fast, but avoid calling thousands of times per frame - Use for special effects or debugging

Example:

renderer.drawPixel(64, 64, Color::Red);
-

void drawSprite(const Sprite& sprite, int x, int y, Color color, bool flipX = false)

Draws a 1bpp monochrome sprite using the Sprite descriptor.

Parameters: - sprite (const Sprite&): Sprite descriptor (data, width, height) - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space - color (Color): Color used for "on" pixels. Default: uses sprite palette context - flipX (bool, optional): If true, sprite is mirrored horizontally. Default: false

Performance Notes: - Very efficient for 1bpp sprites (integer-only operations) - Sprite data should be stored in flash (const/constexpr) for best performance - Avoid calling in tight loops; batch similar operations when possible

Example:

static const uint16_t playerData[] = {
-    0b00111100,
-    0b01111110,
-    // ... more rows
-};
-
-static const Sprite playerSprite = {
-    playerData,
-    8,  // width
-    8   // height
-};
-
-renderer.drawSprite(playerSprite, 100, 100, Color::White);
-renderer.drawSprite(playerSprite, 120, 100, Color::White, true);  // Flipped
-

void drawSprite(const Sprite& sprite, int x, int y, float scaleX, float scaleY, Color color, bool flipX = false)

Draws a scaled 1bpp monochrome sprite.

Parameters: - sprite (const Sprite&): Sprite descriptor - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - scaleX (float): Horizontal scaling factor (e.g., 1.25 for 25% larger) - scaleY (float): Vertical scaling factor - color (Color): Color used for "on" pixels - flipX (bool, optional): If true, sprite is mirrored horizontally before scaling. Default: false

Performance Notes: - Slower than non-scaled version due to scaling calculations - Use integer scaling factors when possible (1.0, 2.0, etc.) for better performance

Example:

renderer.drawSprite(playerSprite, 100, 100, 2.0f, 2.0f, Color::White);  // 2x size
-

void drawMultiSprite(const MultiSprite& sprite, int x, int y)

Draws a multi-layer sprite composed of several 1bpp layers.

Parameters: - sprite (const MultiSprite&): Multi-layer sprite descriptor - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space

Performance Notes: - Each layer is rendered separately, so more layers = more draw calls - Still efficient as each layer uses 1bpp format - Use for multi-color sprites without higher bit-depths

Example:

static const SpriteLayer layers[] = {
+

void drawSprite(const Sprite& sprite, int x, int y, Color color, bool flipX = false)

Draws a 1bpp monochrome sprite using the Sprite descriptor.

Parameters: - sprite (const Sprite&): Sprite descriptor (data, width, height) - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space - color (Color): Color used for "on" pixels - flipX (bool, optional): If true, sprite is mirrored horizontally. Default: false

Performance Notes: - Very efficient for 1bpp sprites (integer-only operations) - Sprite data should be stored in flash (const/constexpr) for best performance

Example:

renderer.drawSprite(playerSprite, 100, 100, Color::White);
+renderer.drawSprite(playerSprite, 120, 100, Color::White, true);  // Flipped
+

void drawSprite(const Sprite& sprite, int x, int y, float scaleX, float scaleY, Color color, bool flipX = false)

Draws a scaled 1bpp monochrome sprite using nearest-neighbor scaling.

Parameters: - sprite (const Sprite&): Sprite descriptor - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - scaleX (float): Horizontal scaling factor (e.g., 2.0 for double width) - scaleY (float): Vertical scaling factor - color (Color): Color used for "on" pixels - flipX (bool, optional): If true, sprite is mirrored horizontally before scaling. Default: false

Performance Notes: - Slower than non-scaled version due to scaling calculations - The destination size is calculated as ceil(width * scaleX) x ceil(height * scaleY)

Example:

renderer.drawSprite(playerSprite, 100, 100, 2.0f, 2.0f, Color::White);  // 2x size
+

void drawSprite(const Sprite2bpp& sprite, int x, int y, bool flipX = false)

Draws a 2bpp sprite. Available when PIXELROOT32_ENABLE_2BPP_SPRITES is defined.

Parameters: - sprite (const Sprite2bpp&): 2bpp sprite descriptor - x (int): X coordinate - y (int): Y coordinate - flipX (bool, optional): Horizontal flip. Default: false

void drawSprite(const Sprite4bpp& sprite, int x, int y, bool flipX = false)

Draws a 4bpp sprite. Available when PIXELROOT32_ENABLE_4BPP_SPRITES is defined.

Parameters: - sprite (const Sprite4bpp&): 4bpp sprite descriptor - x (int): X coordinate - y (int): Y coordinate - flipX (bool, optional): Horizontal flip. Default: false

void drawMultiSprite(const MultiSprite& sprite, int x, int y)

Draws a multi-layer sprite composed of several 1bpp layers.

Parameters: - sprite (const MultiSprite&): Multi-layer sprite descriptor - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space

Performance Notes: - Each layer is rendered separately, so more layers = more draw calls - Still efficient as each layer uses 1bpp format - Use for multi-color sprites without higher bit-depths

Example:

static const SpriteLayer layers[] = {
     { outlineData, Color::Black },
     { fillData, Color::Red },
     { highlightData, Color::Yellow }
@@ -77,7 +68,7 @@
 };
 
 renderer.drawTileMap(levelMap, 0, 0, Color::White);
-

void setDisplayOffset(int x, int y)

Sets a global offset for all drawing operations. Useful for camera/parallax effects.

Parameters: - x (int): X offset in pixels - y (int): Y offset in pixels

Notes: - All subsequent drawing operations are offset by this amount - Useful for camera scrolling and parallax effects - Reset to (0, 0) to disable offset

Example:

// Camera scrolling
+

int getLogicalWidth() const

Gets the logical rendering width.

Returns: - int: The width of the logical screen space.

int getLogicalHeight() const

Gets the logical rendering height.

Returns: - int: The height of the logical screen space.

Note: These methods replace the deprecated getWidth() and getHeight().

void setDisplayOffset(int x, int y)

Sets a global offset for all drawing operations. Useful for camera/parallax effects.

Parameters: - x (int): X offset in pixels - y (int): Y offset in pixels

Notes: - All subsequent drawing operations are offset by this amount - Useful for camera scrolling and parallax effects - Reset to (0, 0) to disable offset

Example:

// Camera scrolling
 camera.setPosition(playerX - 64, playerY - 64);
 renderer.setDisplayOffset(-camera.getX(), -camera.getY());
 renderer.drawTileMap(background, 0, 0, Color::White);
@@ -100,4 +91,4 @@
 
     renderer.endFrame();
 }
-

Performance Considerations

  • Integer-only math: All operations use integer arithmetic for ESP32 efficiency
  • Sprite storage: Store sprite data in flash (const/constexpr) for best performance
  • Batch operations: Group similar draw calls together
  • Tilemaps: Dibuja un mapa de tiles completo. Implementa viewport culling automático y caché de paleta para máximo rendimiento.
  • Sprites 2bpp/4bpp: Optimizado para ESP32 (IRAM + acceso de 16 bits).

ESP32 Considerations

  • Memory: Sprite data should be in flash, not RAM
  • Frame rate: Limit draw calls per frame for consistent FPS
  • Display offset: Use for scrolling instead of redrawing everything

See Also

\ No newline at end of file +

Performance Considerations

  • Integer-only math: All operations use integer arithmetic for ESP32 efficiency
  • Sprite storage: Store sprite data in flash (const/constexpr) for best performance
  • Batch operations: Group similar draw calls together
  • Tilemaps: Dibuja un mapa de tiles completo. Implementa viewport culling automático y caché de paleta para máximo rendimiento.
  • Sprites 2bpp/4bpp: Optimizado para ESP32 (IRAM + acceso de 16 bits).

ESP32 Considerations

  • Memory: Sprite data should be in flash, not RAM
  • Frame rate: Limit draw calls per frame for consistent FPS
  • Display offset: Use for scrolling instead of redrawing everything

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/sprite/index.html b/site/api_reference/graphics/sprite/index.html index 89b4e0c..47eb8ac 100644 --- a/site/api_reference/graphics/sprite/index.html +++ b/site/api_reference/graphics/sprite/index.html @@ -1,4 +1,4 @@ - Sprite - PixelRoot32 Documentation
Skip to content

Sprite

Low-level bitmap descriptor and multi-layer composition for retro rendering.

Description

Sprites are the fundamental graphics primitive in PixelRoot32. The engine supports multiple sprite formats:

  • 1bpp (Standard): Monochrome sprites, most memory-efficient
  • 2bpp (Experimental): 4 colors per sprite
  • 4bpp (Experimental): 16 colors per sprite
  • MultiSprite: Multi-layer 1bpp sprites for multi-color effects

Namespace

namespace pixelroot32::graphics {
+ Sprite - PixelRoot32 Documentation      

Sprite

Low-level bitmap descriptor and multi-layer composition for retro rendering.

Description

Sprites are the fundamental graphics primitive in PixelRoot32. The engine supports multiple sprite formats:

  • 1bpp (Standard): Monochrome sprites, most memory-efficient
  • 2bpp (Experimental): 4 colors per sprite
  • 4bpp (Experimental): 16 colors per sprite
  • MultiSprite: Multi-layer 1bpp sprites for multi-color effects

Namespace

namespace pixelroot32::graphics {
     struct Sprite {
         // ...
     };
@@ -153,4 +153,4 @@
 
 // Draw flipped
 renderer.drawSprite(sprite, 100, 100, Color::White, true);
-

Performance Considerations

  • 1bpp sprites: Most efficient (integer-only operations)
  • MultiSprite: Each layer is a separate draw call (still efficient)
  • 2bpp/4bpp: Experimental, uses more memory and CPU
  • Storage: Store sprite data in flash (const/constexpr) for best performance
  • Size limit: Sprites are limited to 16 pixels wide for 1bpp format

ESP32 Considerations

  • Memory: Store sprite data in flash, not RAM
  • Sprite size: Smaller sprites = faster drawing
  • Format choice: Use 1bpp when possible for best performance
  • MultiSprite: More layers = more draw calls (but acceptable)

See Also

\ No newline at end of file +

Performance Considerations

  • 1bpp sprites: Most efficient (integer-only operations)
  • MultiSprite: Each layer is a separate draw call (still efficient)
  • 2bpp/4bpp: Experimental, uses more memory and CPU
  • Storage: Store sprite data in flash (const/constexpr) for best performance
  • Size limit: Sprites are limited to 16 pixels wide for 1bpp format

ESP32 Considerations

  • Memory: Store sprite data in flash, not RAM
  • Sprite size: Smaller sprites = faster drawing
  • Format choice: Use 1bpp when possible for best performance
  • MultiSprite: More layers = more draw calls (but acceptable)

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/tilemap/index.html b/site/api_reference/graphics/tilemap/index.html index 2ca131e..0647253 100644 --- a/site/api_reference/graphics/tilemap/index.html +++ b/site/api_reference/graphics/tilemap/index.html @@ -1,4 +1,4 @@ - TileMap - PixelRoot32 Documentation
Skip to content

TileMap

Generic structure for tile-based background rendering.

Description

TileMapGeneric<T> is a template structure for rendering tile-based backgrounds efficiently. It supports multiple bit-depths (1bpp, 2bpp, 4bpp) by using the appropriate sprite type for tiles.

Tilemaps are ideal for large backgrounds, levels, and static environments. They support viewport culling (only visible tiles are drawn) for optimal performance.

Namespace

namespace pixelroot32::graphics {
+ TileMap - PixelRoot32 Documentation      

TileMap

Generic structure for tile-based background rendering.

Description

TileMapGeneric<T> is a template structure for rendering tile-based backgrounds efficiently. It supports multiple bit-depths (1bpp, 2bpp, 4bpp) by using the appropriate sprite type for tiles.

Tilemaps are ideal for large backgrounds, levels, and static environments. They support viewport culling (only visible tiles are drawn) for optimal performance.

Namespace

namespace pixelroot32::graphics {
     template<typename T>
     struct TileMapGeneric {
         // ...
@@ -182,4 +182,4 @@
         return (tile == 1);  // Wall tile
     }
 };
-

Performance Considerations

  • Viewport culling: Only visible tiles are drawn (automatic)
  • Tile reuse: Reuse tile sprites across the map
  • Index storage: Compact uint8_t indices (1 byte per tile)
  • Memory: Store indices and tiles in flash (const) for best performance
  • Tile size: Smaller tiles = more tiles to draw, but more detail

ESP32 Considerations

  • Memory: Store tilemap data in flash, not RAM
  • Map size: Large maps use more flash memory
  • Tile count: Limit unique tiles to save memory
  • Culling: Viewport culling is essential for large levels

See Also

\ No newline at end of file +

Performance Considerations

  • Viewport culling: Only visible tiles are drawn (automatic)
  • Tile reuse: Reuse tile sprites across the map
  • Index storage: Compact uint8_t indices (1 byte per tile)
  • Memory: Store indices and tiles in flash (const) for best performance
  • Tile size: Smaller tiles = more tiles to draw, but more detail

ESP32 Considerations

  • Memory: Store tilemap data in flash, not RAM
  • Map size: Large maps use more flash memory
  • Tile count: Limit unique tiles to save memory
  • Culling: Viewport culling is essential for large levels

See Also

\ No newline at end of file diff --git a/site/api_reference/physics/collision_system/index.html b/site/api_reference/physics/collision_system/index.html index 5bba407..ffdf9bc 100644 --- a/site/api_reference/physics/collision_system/index.html +++ b/site/api_reference/physics/collision_system/index.html @@ -1,4 +1,4 @@ - CollisionSystem - PixelRoot32 Documentation
Skip to content

CollisionSystem

Manages collision detection between entities.

Description

CollisionSystem iterates through registered entities, checks if they are Actors, and performs AABB (Axis-Aligned Bounding Box) collision checks based on their collision layers and masks.

The system automatically filters collisions using layers and masks, avoiding unnecessary checks. When a collision is detected, it triggers the onCollision() callback on both actors.

Namespace

namespace pixelroot32::physics {
+ CollisionSystem - PixelRoot32 Documentation      

CollisionSystem

Manages collision detection between entities.

Description

CollisionSystem iterates through registered entities, checks if they are Actors, and performs AABB (Axis-Aligned Bounding Box) collision checks based on their collision layers and masks.

The system automatically filters collisions using layers and masks, avoiding unnecessary checks. When a collision is detected, it triggers the onCollision() callback on both actors.

Namespace

namespace pixelroot32::physics {
     class CollisionSystem {
         // ...
     };
@@ -59,4 +59,4 @@
         Scene::update(deltaTime);
     }
 };
-

Performance Considerations

  • Layer filtering: Very efficient; avoids most collision checks
  • AABB checks: Fast (simple rectangle intersection)
  • Pair checking: O(n²) complexity, but n is limited (MAX_ENTITIES = 32)
  • Update frequency: Called every frame; keep hitboxes simple

ESP32 Considerations

  • Entity limit: MAX_ENTITIES = 32 limits collision pairs
  • Layer efficiency: Use layers effectively to minimize checks
  • Hitbox simplicity: Keep hitboxes as simple AABB for best performance

See Also

\ No newline at end of file +

Performance Considerations

  • Layer filtering: Very efficient; avoids most collision checks
  • AABB checks: Fast (simple rectangle intersection)
  • Pair checking: O(n²) complexity, but n is limited (MAX_ENTITIES = 32)
  • Update frequency: Called every frame; keep hitboxes simple

ESP32 Considerations

  • Entity limit: MAX_ENTITIES = 32 limits collision pairs
  • Layer efficiency: Use layers effectively to minimize checks
  • Hitbox simplicity: Keep hitboxes as simple AABB for best performance

See Also

\ No newline at end of file diff --git a/site/api_reference/physics/collision_types/index.html b/site/api_reference/physics/collision_types/index.html index e5ef454..7e05fef 100644 --- a/site/api_reference/physics/collision_types/index.html +++ b/site/api_reference/physics/collision_types/index.html @@ -1,4 +1,4 @@ - Collision Types - PixelRoot32 Documentation
Skip to content

Collision Types

Basic geometric types and collision layer definitions.

Description

This document describes the collision primitives (Rect, Circle, Segment) and collision layer system used by the collision detection system.

Namespace

namespace pixelroot32::physics {
+ Collision Types - PixelRoot32 Documentation      

Collision Types

Basic geometric types and collision layer definitions.

Description

This document describes the collision primitives (Rect, Circle, Segment) and collision layer system used by the collision detection system.

Namespace

namespace pixelroot32::physics {
     // Types and functions
 }
 

CollisionLayer Type

Collision layer type (bit flags).

Type: uint16_t (typedef)

Notes: - Uses bit flags for layer assignment - Actors can be on multiple layers (bitwise OR) - Masks define which layers an actor can collide with

DefaultLayers Namespace

Predefined collision layers.

kNone

No layer (0).

Value: 0

Usage:

actor->layer = pixelroot32::physics::DefaultLayers::kNone;
@@ -99,4 +99,4 @@
         return false;
     }
 };
-

Performance Considerations

  • AABB checks: Very fast (simple rectangle intersection)
  • Circle checks: Slightly slower (distance calculation)
  • Sweep tests: More expensive (use only for fast-moving objects)
  • Layer filtering: Essential for performance with many actors

ESP32 Considerations

  • Float math: Uses floating point; acceptable but integer math would be faster
  • Sweep tests: Use sparingly (more CPU intensive)
  • Layer efficiency: Use layers effectively to minimize checks

See Also

\ No newline at end of file +

Performance Considerations

  • AABB checks: Very fast (simple rectangle intersection)
  • Circle checks: Slightly slower (distance calculation)
  • Sweep tests: More expensive (use only for fast-moving objects)
  • Layer filtering: Essential for performance with many actors

ESP32 Considerations

  • Float math: Uses floating point; acceptable but integer math would be faster
  • Sweep tests: Use sparingly (more CPU intensive)
  • Layer efficiency: Use layers effectively to minimize checks

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_button/index.html b/site/api_reference/ui/ui_button/index.html index 89bb34e..ae5f75e 100644 --- a/site/api_reference/ui/ui_button/index.html +++ b/site/api_reference/ui/ui_button/index.html @@ -1,4 +1,4 @@ - UIButton - PixelRoot32 Documentation
Skip to content

UIButton

A clickable button UI element.

Description

UIButton is a clickable button that supports both physical (keyboard/gamepad) and touch input. It can trigger a callback function when pressed and integrates with UI layouts for automatic navigation.

Buttons support selection state (for D-pad navigation), custom styling, and text alignment.

Namespace

namespace pixelroot32::graphics::ui {
+ UIButton - PixelRoot32 Documentation      

UIButton

A clickable button UI element.

Description

UIButton is a clickable button that supports both physical (keyboard/gamepad) and touch input. It can trigger a callback function when pressed and integrates with UI layouts for automatic navigation.

Buttons support selection state (for D-pad navigation), custom styling, and text alignment.

Namespace

namespace pixelroot32::graphics::ui {
     class UIButton : public UIElement {
         // ...
     };
@@ -131,4 +131,4 @@
 // D-pad navigation is automatic
 // UP/DOWN moves selection
 // Action button (A) triggers selected button
-

Performance Considerations

  • Input handling: handleInput() is fast; safe to call every frame
  • Rendering: Simple rectangle and text; very efficient
  • Memory: Each button consumes memory (stay within MAX_ENTITIES)

ESP32 Considerations

  • String storage: Button labels use std::string; consider memory usage
  • Callback functions: Use function pointers or lambdas (both efficient)

See Also

\ No newline at end of file +

Performance Considerations

  • Input handling: handleInput() is fast; safe to call every frame
  • Rendering: Simple rectangle and text; very efficient
  • Memory: Each button consumes memory (stay within MAX_ENTITIES)

ESP32 Considerations

  • String storage: Button labels use std::string; consider memory usage
  • Callback functions: Use function pointers or lambdas (both efficient)

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_checkbox/index.html b/site/api_reference/ui/ui_checkbox/index.html index 73ad48f..0204b41 100644 --- a/site/api_reference/ui/ui_checkbox/index.html +++ b/site/api_reference/ui/ui_checkbox/index.html @@ -1,4 +1,4 @@ - UICheckBox - PixelRoot32 Documentation
Skip to content

UICheckBox

A clickable checkbox UI element.

Description

UICheckBox is a clickable checkbox that can be toggled between checked and unchecked states. It supports both physical (keyboard/gamepad) and touch input. It can trigger a callback function when its state changes and integrates with UI layouts for automatic navigation.

Namespace

namespace pixelroot32::graphics::ui {
+ UICheckBox - PixelRoot32 Documentation      

UICheckBox

A clickable checkbox UI element.

Description

UICheckBox is a clickable checkbox that can be toggled between checked and unchecked states. It supports both physical (keyboard/gamepad) and touch input. It can trigger a callback function when its state changes and integrates with UI layouts for automatic navigation.

Namespace

namespace pixelroot32::graphics::ui {
     class UICheckBox : public UIElement {
         // ...
     };
@@ -26,4 +26,4 @@
 

Public Methods

void setStyle(Color textCol, Color bgCol, bool drawBg = false)

Configures the checkbox's visual style.

Parameters: - textCol (Color): Color of the text - bgCol (Color): Color of the background - drawBg (bool, optional): Whether to draw the background rectangle. Default: false

Returns: - void

void setChecked(bool checked)

Sets the checked state.

Parameters: - checked (bool): True if checked

Returns: - void

bool isChecked() const

Checks if the checkbox is currently checked.

Returns: - bool: true if checked

void toggle()

Toggles the checkbox state and triggers the callback.

Returns: - void

void setSelected(bool selected)

Sets the selection state (e.g., focused via D-pad).

Parameters: - selected (bool): True if selected

Returns: - void

bool getSelected() const

Checks if the checkbox is currently selected.

Returns: - bool: true if selected

Callbacks

onCheckChanged

The onCheckChanged callback is a std::function<void(bool)> that is triggered whenever the checkbox state changes via setChecked() or toggle().

checkbox->onCheckChanged = [](bool isChecked) {
     Serial.println(isChecked ? "Checked!" : "Unchecked!");
 };
-

UICheckBox is designed to work seamlessly with UILayout containers (like UIVerticalLayout).

  • Focusable: Returns true for isFocusable(), allowing it to receive focus in a layout.
  • Input Handling: When selected (focused), it listens for the button index provided in the constructor (typically the 'A' button) to toggle its state.
  • Visual Feedback: When selected, it displays a selection indicator (usually a > character) if no background is drawn, or highlights its text/border.
\ No newline at end of file +

UICheckBox is designed to work seamlessly with UILayout containers (like UIVerticalLayout).

  • Focusable: Returns true for isFocusable(), allowing it to receive focus in a layout.
  • Input Handling: When selected (focused), it listens for the button index provided in the constructor (typically the 'A' button) to toggle its state.
  • Visual Feedback: When selected, it displays a selection indicator (usually a > character) if no background is drawn, or highlights its text/border.
\ No newline at end of file diff --git a/site/api_reference/ui/ui_element/index.html b/site/api_reference/ui/ui_element/index.html index 31cdb7f..7a468eb 100644 --- a/site/api_reference/ui/ui_element/index.html +++ b/site/api_reference/ui/ui_element/index.html @@ -1,4 +1,4 @@ - UIElement - PixelRoot32 Documentation
Skip to content

UIElement

Base class for all user interface elements.

Description

UIElement is the base class for all UI components (buttons, labels, panels, etc.). It inherits from Entity to integrate with the scene graph and automatically sets the entity type to UI_ELEMENT and render layer to 2 (UI layer).

Namespace

namespace pixelroot32::graphics::ui {
+ UIElement - PixelRoot32 Documentation      

UIElement

Base class for all user interface elements.

Description

UIElement is the base class for all UI components (buttons, labels, panels, etc.). It inherits from Entity to integrate with the scene graph and automatically sets the entity type to UI_ELEMENT and render layer to 2 (UI layer).

Namespace

namespace pixelroot32::graphics::ui {
     enum class UIElementType {
         GENERIC,
         BUTTON,
@@ -72,4 +72,4 @@
         h = static_cast<float>(height);
     }
 };
-

Performance Considerations

  • Render layer: UI elements are on layer 2, drawn after gameplay
  • Visibility: Use isVisible = false to hide elements efficiently
  • Layout integration: Layouts automatically manage element positioning

ESP32 Considerations

  • Memory: Each UI element consumes memory (stay within MAX_ENTITIES)
  • Object pooling: Reuse UI elements when possible
  • Update frequency: Disable UI elements that don't need to update

See Also

\ No newline at end of file +

Performance Considerations

  • Render layer: UI elements are on layer 2, drawn after gameplay
  • Visibility: Use isVisible = false to hide elements efficiently
  • Layout integration: Layouts automatically manage element positioning

ESP32 Considerations

  • Memory: Each UI element consumes memory (stay within MAX_ENTITIES)
  • Object pooling: Reuse UI elements when possible
  • Update frequency: Disable UI elements that don't need to update

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_label/index.html b/site/api_reference/ui/ui_label/index.html index c0181b4..e93f04f 100644 --- a/site/api_reference/ui/ui_label/index.html +++ b/site/api_reference/ui/ui_label/index.html @@ -1,4 +1,4 @@ - UILabel - PixelRoot32 Documentation
Skip to content

UILabel

A simple text label UI element.

Description

UILabel displays a string of text on the screen. It auto-calculates its bounds based on text length and font size, making it easy to create dynamic text displays.

Labels are useful for displaying scores, status messages, menu text, and other UI information.

Namespace

namespace pixelroot32::graphics::ui {
+ UILabel - PixelRoot32 Documentation      

UILabel

A simple text label UI element.

Description

UILabel displays a string of text on the screen. It auto-calculates its bounds based on text length and font size, making it easy to create dynamic text displays.

Labels are useful for displaying scores, status messages, menu text, and other UI information.

Namespace

namespace pixelroot32::graphics::ui {
     class UILabel : public UIElement {
         // ...
     };
@@ -96,4 +96,4 @@
 );
 title->centerX(128);  // Center on screen
 addEntity(title);
-

Performance Considerations

  • Text updates: setText() recalculates size; avoid calling every frame if text doesn't change
  • String storage: Uses std::string; consider memory on ESP32
  • Rendering: Simple text drawing; very efficient
  • Static text: For static text, create once and don't update

ESP32 Considerations

  • Memory: std::string uses heap memory; use static buffers when possible
  • Text updates: Limit frequency of text updates
  • String length: Keep text short to save memory

See Also

\ No newline at end of file +

Performance Considerations

  • Text updates: setText() recalculates size; avoid calling every frame if text doesn't change
  • String storage: Uses std::string; consider memory on ESP32
  • Rendering: Simple text drawing; very efficient
  • Static text: For static text, create once and don't update

ESP32 Considerations

  • Memory: std::string uses heap memory; use static buffers when possible
  • Text updates: Limit frequency of text updates
  • String length: Keep text short to save memory

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layout/index.html b/site/api_reference/ui/ui_layout/index.html index 3b6b5c7..317ef39 100644 --- a/site/api_reference/ui/ui_layout/index.html +++ b/site/api_reference/ui/ui_layout/index.html @@ -1,6 +1,6 @@ - UILayout - PixelRoot32 Documentation
Skip to content

UILayout

Base class for UI layout containers.

Description

UILayout is the base class for all layout containers. Layouts organize UI elements automatically, handling positioning, spacing, and optional scrolling. Layouts are themselves UI elements that can be added to scenes.

Namespace

namespace pixelroot32::graphics::ui {
+ UILayout - PixelRoot32 Documentation      

UILayout

Base class for UI layout containers.

Description

UILayout is the base class for all layout containers. Layouts organize UI elements automatically, handling positioning, spacing, and optional scrolling. Layouts are themselves UI elements that can be added to scenes.

Namespace

namespace pixelroot32::graphics::ui {
     class UILayout : public UIElement {
         // ...
     };
 }
-

Inheritance

  • Inherits from: UIElement
  • Inherited by: UIVerticalLayout, UIHorizontalLayout, UIGridLayout, UIAnchorLayout

ScrollBehavior Enum

Defines how scrolling behaves in layouts.

Values: - ScrollBehavior::NONE: No scrolling allowed - ScrollBehavior::SCROLL: Scroll freely within bounds - ScrollBehavior::CLAMP: Scroll but clamp to content bounds

Public Methods

virtual void addElement(UIElement* element) = 0

Adds a UI element to the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to add

virtual void removeElement(UIElement* element) = 0

Removes a UI element from the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to remove

virtual void updateLayout() = 0

Recalculates positions of all elements in the layout. Must be implemented by derived classes.

Returns: - void

Notes: - Should be called automatically when elements are added/removed

virtual void handleInput(const InputManager& input) = 0

Handles input for layout navigation (scroll, selection, etc.). Must be implemented by derived classes.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

void setPadding(float p)

Sets the padding (internal spacing) of the layout.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Layout is automatically recalculated

float getPadding() const

Gets the current padding.

Returns: - float: Padding value in pixels

void setSpacing(float s)

Sets the spacing between elements.

Parameters: - s (float): Spacing value in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Default: 4.0 pixels

float getSpacing() const

Gets the current spacing.

Returns: - float: Spacing value in pixels

size_t getElementCount() const

Gets the number of elements in the layout.

Returns: - size_t: Element count

UIElement* getElement(size_t index) const

Gets the element at a specific index.

Parameters: - index (size_t): Element index

Returns: - UIElement*: Pointer to the element, or nullptr if index is invalid

void clearElements()

Clears all elements from the layout.

Returns: - void

Notes: - Elements are not deleted (you must manage their lifetimes) - Layout is automatically recalculated

Protected Members

  • std::vector<UIElement*> elements: List of child elements
  • float padding: Internal padding
  • float spacing: Spacing between elements (default: 4.0)
  • float scrollOffset: Current scroll offset
  • bool enableScroll: Whether scrolling is enabled
  • ScrollBehavior scrollBehavior: Scroll behavior mode

See Also

\ No newline at end of file +

Inheritance

  • Inherits from: UIElement
  • Inherited by: UIVerticalLayout, UIHorizontalLayout, UIGridLayout, UIAnchorLayout

ScrollBehavior Enum

Defines how scrolling behaves in layouts.

Values: - ScrollBehavior::NONE: No scrolling allowed - ScrollBehavior::SCROLL: Scroll freely within bounds - ScrollBehavior::CLAMP: Scroll but clamp to content bounds

Public Methods

virtual void addElement(UIElement* element) = 0

Adds a UI element to the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to add

virtual void removeElement(UIElement* element) = 0

Removes a UI element from the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to remove

virtual void updateLayout() = 0

Recalculates positions of all elements in the layout. Must be implemented by derived classes.

Returns: - void

Notes: - Should be called automatically when elements are added/removed

virtual void handleInput(const InputManager& input) = 0

Handles input for layout navigation (scroll, selection, etc.). Must be implemented by derived classes.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

void setPadding(float p)

Sets the padding (internal spacing) of the layout.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Layout is automatically recalculated

float getPadding() const

Gets the current padding.

Returns: - float: Padding value in pixels

void setSpacing(float s)

Sets the spacing between elements.

Parameters: - s (float): Spacing value in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Default: 4.0 pixels

float getSpacing() const

Gets the current spacing.

Returns: - float: Spacing value in pixels

size_t getElementCount() const

Gets the number of elements in the layout.

Returns: - size_t: Element count

UIElement* getElement(size_t index) const

Gets the element at a specific index.

Parameters: - index (size_t): Element index

Returns: - UIElement*: Pointer to the element, or nullptr if index is invalid

void clearElements()

Clears all elements from the layout.

Returns: - void

Notes: - Elements are not deleted (you must manage their lifetimes) - Layout is automatically recalculated

Protected Members

  • std::vector<UIElement*> elements: List of child elements
  • float padding: Internal padding
  • float spacing: Spacing between elements (default: 4.0)
  • float scrollOffset: Current scroll offset
  • bool enableScroll: Whether scrolling is enabled
  • ScrollBehavior scrollBehavior: Scroll behavior mode

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/anchor_layout/index.html b/site/api_reference/ui/ui_layouts/anchor_layout/index.html index 44265a7..56adc1f 100644 --- a/site/api_reference/ui/ui_layouts/anchor_layout/index.html +++ b/site/api_reference/ui/ui_layouts/anchor_layout/index.html @@ -1,4 +1,4 @@ - Anchor Layout - PixelRoot32 Documentation
Skip to content

UIAnchorLayout

Layout that positions elements at fixed anchor points on the screen.

Description

UIAnchorLayout positions UI elements at fixed anchor points (corners, center, edges) without reflow. Very efficient for HUDs, debug UI, and fixed-position elements. Positions are calculated once or when screen size changes.

This layout is ideal for HUD elements like score, lives, health bars, and other fixed-position UI.

Namespace

namespace pixelroot32::graphics::ui {
+ Anchor Layout - PixelRoot32 Documentation      

UIAnchorLayout

Layout that positions elements at fixed anchor points on the screen.

Description

UIAnchorLayout positions UI elements at fixed anchor points (corners, center, edges) without reflow. Very efficient for HUDs, debug UI, and fixed-position elements. Positions are calculated once or when screen size changes.

This layout is ideal for HUD elements like score, lives, health bars, and other fixed-position UI.

Namespace

namespace pixelroot32::graphics::ui {
     class UIAnchorLayout : public UILayout {
         // ...
     };
@@ -89,4 +89,4 @@
         // HUD is drawn automatically (on layer 2)
     }
 };
-

Anchor Positioning

Elements are positioned based on their anchor:

  • TOP_LEFT: Element's top-left at screen top-left
  • TOP_RIGHT: Element's top-right at screen top-right
  • BOTTOM_LEFT: Element's bottom-left at screen bottom-left
  • BOTTOM_RIGHT: Element's bottom-right at screen bottom-right
  • CENTER: Element centered on screen
  • TOP_CENTER: Element centered horizontally, top-aligned
  • BOTTOM_CENTER: Element centered horizontally, bottom-aligned
  • LEFT_CENTER: Element centered vertically, left-aligned
  • RIGHT_CENTER: Element centered vertically, right-aligned

Performance Considerations

  • No reflow: Very efficient (positions calculated once)
  • Fixed positions: Ideal for HUD elements
  • Viewport independent: Elements stay in fixed screen positions

ESP32 Considerations

  • Memory: Very efficient (no complex calculations)
  • Update frequency: Positions only recalculate when screen size changes

See Also

\ No newline at end of file +

Anchor Positioning

Elements are positioned based on their anchor:

  • TOP_LEFT: Element's top-left at screen top-left
  • TOP_RIGHT: Element's top-right at screen top-right
  • BOTTOM_LEFT: Element's bottom-left at screen bottom-left
  • BOTTOM_RIGHT: Element's bottom-right at screen bottom-right
  • CENTER: Element centered on screen
  • TOP_CENTER: Element centered horizontally, top-aligned
  • BOTTOM_CENTER: Element centered horizontally, bottom-aligned
  • LEFT_CENTER: Element centered vertically, left-aligned
  • RIGHT_CENTER: Element centered vertically, right-aligned

Performance Considerations

  • No reflow: Very efficient (positions calculated once)
  • Fixed positions: Ideal for HUD elements
  • Viewport independent: Elements stay in fixed screen positions

ESP32 Considerations

  • Memory: Very efficient (no complex calculations)
  • Update frequency: Positions only recalculate when screen size changes

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/grid_layout/index.html b/site/api_reference/ui/ui_layouts/grid_layout/index.html index 9a4b89e..ae4064c 100644 --- a/site/api_reference/ui/ui_layouts/grid_layout/index.html +++ b/site/api_reference/ui/ui_layouts/grid_layout/index.html @@ -1,4 +1,4 @@ - Grid Layout - PixelRoot32 Documentation
Skip to content

UIGridLayout

Grid layout container for organizing elements in a matrix.

Description

UIGridLayout organizes UI elements in a fixed grid of rows and columns. It supports navigation in 4 directions (UP/DOWN/LEFT/RIGHT) and automatic positioning based on grid coordinates.

This layout is ideal for inventories, level selection screens, galleries, and any grid-based UI arrangement.

Namespace

namespace pixelroot32::graphics::ui {
+ Grid Layout - PixelRoot32 Documentation      

UIGridLayout

Grid layout container for organizing elements in a matrix.

Description

UIGridLayout organizes UI elements in a fixed grid of rows and columns. It supports navigation in 4 directions (UP/DOWN/LEFT/RIGHT) and automatic positioning based on grid coordinates.

This layout is ideal for inventories, level selection screens, galleries, and any grid-based UI arrangement.

Namespace

namespace pixelroot32::graphics::ui {
     class UIGridLayout : public UILayout {
         // ...
     };
@@ -39,4 +39,4 @@
         addEntity(inventory);
     }
 };
-

See Also

\ No newline at end of file +

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/horizontal_layout/index.html b/site/api_reference/ui/ui_layouts/horizontal_layout/index.html index b66c0f8..8962748 100644 --- a/site/api_reference/ui/ui_layouts/horizontal_layout/index.html +++ b/site/api_reference/ui/ui_layouts/horizontal_layout/index.html @@ -1,4 +1,4 @@ - Horizontal Layout - PixelRoot32 Documentation
Skip to content

UIHorizontalLayout

Horizontal layout container with scroll support.

Description

UIHorizontalLayout organizes UI elements horizontally, one next to another. It supports scrolling when content exceeds the visible viewport and handles keyboard/D-pad navigation automatically.

This layout is ideal for toolbars, tab bars, horizontal menus, and any horizontal arrangement of UI elements.

Namespace

namespace pixelroot32::graphics::ui {
+ Horizontal Layout - PixelRoot32 Documentation      

UIHorizontalLayout

Horizontal layout container with scroll support.

Description

UIHorizontalLayout organizes UI elements horizontally, one next to another. It supports scrolling when content exceeds the visible viewport and handles keyboard/D-pad navigation automatically.

This layout is ideal for toolbars, tab bars, horizontal menus, and any horizontal arrangement of UI elements.

Namespace

namespace pixelroot32::graphics::ui {
     class UIHorizontalLayout : public UILayout {
         // ...
     };
@@ -35,4 +35,4 @@
         addEntity(toolbar);
     }
 };
-

See Also

\ No newline at end of file +

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/padding_container/index.html b/site/api_reference/ui/ui_layouts/padding_container/index.html index 936454b..de8184c 100644 --- a/site/api_reference/ui/ui_layouts/padding_container/index.html +++ b/site/api_reference/ui/ui_layouts/padding_container/index.html @@ -1,4 +1,4 @@ - Padding Container - PixelRoot32 Documentation
Skip to content

UIPaddingContainer

Container that wraps a single UI element and applies padding.

Description

UIPaddingContainer adds padding/margin around a single child element without organizing multiple elements. Useful for adding spacing to individual elements or nesting layouts with custom padding.

This container is simpler than UIPanel (no background/border) and focuses only on spacing.

Namespace

namespace pixelroot32::graphics::ui {
+ Padding Container - PixelRoot32 Documentation      

UIPaddingContainer

Container that wraps a single UI element and applies padding.

Description

UIPaddingContainer adds padding/margin around a single child element without organizing multiple elements. Useful for adding spacing to individual elements or nesting layouts with custom padding.

This container is simpler than UIPanel (no background/border) and focuses only on spacing.

Namespace

namespace pixelroot32::graphics::ui {
     class UIPaddingContainer : public UIElement {
         // ...
     };
@@ -42,4 +42,4 @@
 auto* paddedLayout = new UIPaddingContainer(0, 0, 128, 128);
 paddedLayout->setPadding(10.0f, 10.0f, 20.0f, 20.0f);  // Asymmetric
 paddedLayout->setChild(layout);
-

Performance Considerations

  • Rendering: Very efficient (just draws child)
  • Position calculation: Fast (simple addition)
  • Memory: Minimal overhead

ESP32 Considerations

  • Memory: Very lightweight
  • Update frequency: Position only recalculates when padding/position changes

See Also

\ No newline at end of file +

Performance Considerations

  • Rendering: Very efficient (just draws child)
  • Position calculation: Fast (simple addition)
  • Memory: Minimal overhead

ESP32 Considerations

  • Memory: Very lightweight
  • Update frequency: Position only recalculates when padding/position changes

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/panel/index.html b/site/api_reference/ui/ui_layouts/panel/index.html index 341c25e..522574d 100644 --- a/site/api_reference/ui/ui_layouts/panel/index.html +++ b/site/api_reference/ui/ui_layouts/panel/index.html @@ -1,4 +1,4 @@ - Panel - PixelRoot32 Documentation
Skip to content

UIPanel

Visual container that draws a background and border around a child element.

Description

UIPanel provides a retro-style window/panel appearance with a background color and border. Typically contains a UILayout or other UI elements. Useful for dialogs, menus, and information panels.

The panel wraps a single child element and draws a background rectangle and border around it.

Namespace

namespace pixelroot32::graphics::ui {
+ Panel - PixelRoot32 Documentation      

UIPanel

Visual container that draws a background and border around a child element.

Description

UIPanel provides a retro-style window/panel appearance with a background color and border. Typically contains a UILayout or other UI elements. Useful for dialogs, menus, and information panels.

The panel wraps a single child element and draws a background rectangle and border around it.

Namespace

namespace pixelroot32::graphics::ui {
     class UIPanel : public UIElement {
         // ...
     };
@@ -64,4 +64,4 @@
         addEntity(dialog);
     }
 };
-

Performance Considerations

  • Rendering: Simple rectangles; very efficient
  • Child updates: Child element updates are fast
  • Memory: Small overhead (just colors and border width)

ESP32 Considerations

  • Memory: Panel is lightweight
  • Rendering: Two rectangles (background + border); minimal overhead

See Also

\ No newline at end of file +

Performance Considerations

  • Rendering: Simple rectangles; very efficient
  • Child updates: Child element updates are fast
  • Memory: Small overhead (just colors and border width)

ESP32 Considerations

  • Memory: Panel is lightweight
  • Rendering: Two rectangles (background + border); minimal overhead

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/vertical_layout/index.html b/site/api_reference/ui/ui_layouts/vertical_layout/index.html index 25e2c12..b235c16 100644 --- a/site/api_reference/ui/ui_layouts/vertical_layout/index.html +++ b/site/api_reference/ui/ui_layouts/vertical_layout/index.html @@ -1,4 +1,4 @@ - Vertical Layout - PixelRoot32 Documentation
Skip to content

UIVerticalLayout

Vertical layout container with scroll support.

Description

UIVerticalLayout organizes UI elements vertically, one below another. It supports scrolling when content exceeds the visible viewport and handles keyboard/D-pad navigation automatically.

This layout is ideal for menus, lists, and any vertical arrangement of UI elements.

Namespace

namespace pixelroot32::graphics::ui {
+ Vertical Layout - PixelRoot32 Documentation      

UIVerticalLayout

Vertical layout container with scroll support.

Description

UIVerticalLayout organizes UI elements vertically, one below another. It supports scrolling when content exceeds the visible viewport and handles keyboard/D-pad navigation automatically.

This layout is ideal for menus, lists, and any vertical arrangement of UI elements.

Namespace

namespace pixelroot32::graphics::ui {
     class UIVerticalLayout : public UILayout {
         // ...
     };
@@ -80,4 +80,4 @@
         Scene::draw(renderer);  // Draws layout and buttons
     }
 };
-

The layout handles D-pad navigation automatically:

  • UP button: Moves selection up
  • DOWN button: Moves selection down
  • Action button: Triggers selected button's callback
  • Scrolling: Automatically scrolls to keep selected element visible

Performance Considerations

  • Viewport culling: Only visible elements are drawn
  • Layout recalculation: Fast (simple positioning)
  • Scrolling: Smooth scrolling is efficient

ESP32 Considerations

  • Element count: Stay within MAX_ENTITIES limit
  • Scrolling: Smooth scrolling uses minimal CPU

See Also

\ No newline at end of file +

The layout handles D-pad navigation automatically:

  • UP button: Moves selection up
  • DOWN button: Moves selection down
  • Action button: Triggers selected button's callback
  • Scrolling: Automatically scrolls to keep selected element visible

Performance Considerations

  • Viewport culling: Only visible elements are drawn
  • Layout recalculation: Fast (simple positioning)
  • Scrolling: Smooth scrolling is efficient

ESP32 Considerations

  • Element count: Stay within MAX_ENTITIES limit
  • Scrolling: Smooth scrolling uses minimal CPU

See Also

\ No newline at end of file diff --git a/site/getting_started/fundamental_concepts/index.html b/site/getting_started/fundamental_concepts/index.html index 3924de4..6f4b5b3 100644 --- a/site/getting_started/fundamental_concepts/index.html +++ b/site/getting_started/fundamental_concepts/index.html @@ -1,7 +1,7 @@ - Fundamental Concepts - PixelRoot32 Documentation
Skip to content

Fundamental Concepts

Before you start programming, it's important to understand the basic concepts that form PixelRoot32's architecture. This section explains how the engine works at a conceptual level, without going into code details.

Engine Architecture

Engine: The Heart of the Engine

The Engine is the main class that orchestrates the entire system. Think of it as the conductor that coordinates all subsystems:

  • Renderer: Handles drawing everything on screen
  • InputManager: Reads and processes user input (buttons, keyboard)
  • AudioEngine: Generates and plays sounds and music
  • SceneManager: Manages game scenes (menus, levels, etc.)

The Engine runs the main game loop: an infinite cycle that updates game logic and draws each frame on screen. It also calculates delta time (time elapsed between frames) so the game runs at the same speed regardless of framerate.

Scene: Organizing Your Game

A Scene represents a screen or level in your game. For example: - A scene for the main menu - A scene for each game level - A scene for the game over screen - A scene for the pause menu

Each scene contains and manages a set of entities (characters, enemies, objects, etc.). The scene is responsible for: - Initializing its entities when loaded - Updating the logic of all its entities each frame - Drawing all its visible entities each frame - Managing collisions between entities that can collide

The Engine can only have one active scene at a time, but you can easily switch between scenes (for example, go from menu to game, or from game to pause menu).

Entity: The Fundamental Building Blocks

An Entity is any object in your game that has: - Position (x, y) in the world - Size (width and height) - Visibility (can be visible or not) - Active state (can be enabled or disabled) - Render layer (in what order it's drawn)

Entities are the foundation of everything in your game: the player, enemies, projectiles, objects, UI elements—everything is an entity or inherits from Entity.

Each entity has two main methods: - update(): Called each frame to update the entity's logic (movement, animation, etc.) - draw(): Called each frame to draw the entity on screen

Actor: Entities That Can Collide

An Actor is a special entity that can participate in the collision system. In addition to everything an Entity has, an Actor has: - Collision layer: Which group it belongs to (e.g., "player", "enemy", "projectile") - Collision mask: Which other groups it can collide with - Hitbox: The shape used to detect collisions (usually a rectangle)

For example, a player might be on the "player" layer and have a mask that allows it to collide with "enemies" and "obstacles", but not with "other players".

When two actors collide, the system calls their onCollision() method so they can react (e.g., player loses health, enemy is destroyed, etc.).

PhysicsActor: Entities with Physics

A PhysicsActor is an Actor that also has physical properties: - Velocity (vx, vy): Moves automatically according to its velocity - Gravity: Can fall automatically - Friction: Gradually loses velocity - Restitution: Bounces when it collides (like a ball)

The PhysicsActor updates automatically each frame, applying physics and moving the entity. It can also detect collisions with world boundaries (the walls of the play area).

Entity Hierarchy

The relationship between these classes is hierarchical:

Entity (base)
+ Fundamental Concepts - PixelRoot32 Documentation      

Fundamental Concepts

Before you start programming, it's important to understand the basic concepts that form PixelRoot32's architecture. This section explains how the engine works at a conceptual level, without going into code details.

Engine Architecture

Engine: The Heart of the Engine

The Engine is the main class that orchestrates the entire system. Think of it as the conductor that coordinates all subsystems:

  • Renderer: Handles drawing everything on screen
  • InputManager: Reads and processes user input (buttons, keyboard)
  • AudioEngine: Generates and plays sounds and music
  • SceneManager: Manages game scenes (menus, levels, etc.)

The Engine runs the main game loop: an infinite cycle that updates game logic and draws each frame on screen. It also calculates delta time (time elapsed between frames) so the game runs at the same speed regardless of framerate.

Scene: Organizing Your Game

A Scene represents a screen or level in your game. For example: - A scene for the main menu - A scene for each game level - A scene for the game over screen - A scene for the pause menu

Each scene contains and manages a set of entities (characters, enemies, objects, etc.). The scene is responsible for: - Initializing its entities when loaded - Updating the logic of all its entities each frame - Drawing all its visible entities each frame - Managing collisions between entities that can collide

The Engine can only have one active scene at a time, but you can easily switch between scenes (for example, go from menu to game, or from game to pause menu).

Entity: The Fundamental Building Blocks

An Entity is any object in your game that has: - Position (x, y) in the world - Size (width and height) - Visibility (can be visible or not) - Active state (can be enabled or disabled) - Render layer (in what order it's drawn)

Entities are the foundation of everything in your game: the player, enemies, projectiles, objects, UI elements—everything is an entity or inherits from Entity.

Each entity has two main methods: - update(): Called each frame to update the entity's logic (movement, animation, etc.) - draw(): Called each frame to draw the entity on screen

Actor: Entities That Can Collide

An Actor is a special entity that can participate in the collision system. In addition to everything an Entity has, an Actor has: - Collision layer: Which group it belongs to (e.g., "player", "enemy", "projectile") - Collision mask: Which other groups it can collide with - Hitbox: The shape used to detect collisions (usually a rectangle)

For example, a player might be on the "player" layer and have a mask that allows it to collide with "enemies" and "obstacles", but not with "other players".

When two actors collide, the system calls their onCollision() method so they can react (e.g., player loses health, enemy is destroyed, etc.).

PhysicsActor: Entities with Physics

A PhysicsActor is an Actor that also has physical properties: - Velocity (vx, vy): Moves automatically according to its velocity - Gravity: Can fall automatically - Friction: Gradually loses velocity - Restitution: Bounces when it collides (like a ball)

The PhysicsActor updates automatically each frame, applying physics and moving the entity. It can also detect collisions with world boundaries (the walls of the play area).

Entity Hierarchy

The relationship between these classes is hierarchical:

Entity (base)
   └── Actor (can collide)
        └── PhysicsActor (has physics)
-

This means: - Every Actor is also an Entity - Every PhysicsActor is also an Actor and an Entity - You can use Entity for simple objects that don't need collisions - You can use Actor for objects that need to detect collisions - You can use PhysicsActor for objects that need automatic physics

Rendering System

Render Layers

To control the order in which things are drawn, PixelRoot32 uses render layers:

  • Layer 0 (Background): Backgrounds, tilemaps, background elements
  • Layer 1 (Gameplay): Characters, enemies, projectiles, game objects
  • Layer 2 (UI): Menus, HUD, text, interface elements

Layers are drawn in order: first 0, then 1, and finally 2. This ensures the background is always behind, gameplay in the middle, and UI always visible in front.

Each entity has a renderLayer property that indicates which layer it should be drawn on. You can change this property to move entities between layers.

Rendering Pipeline

The rendering process works like this:

  1. beginFrame(): The screen is cleared (painted black or background color)
  2. Draw entities: All visible entities are traversed, organized by layer
  3. endFrame(): The complete frame is sent to the display

The Renderer abstracts hardware details, so the same code works on both ESP32 (TFT_eSPI) and PC (SDL2).

Coordinates and Space

PixelRoot32 uses a standard coordinate system: - Origin (0, 0): Top-left corner - X-axis: Increases to the right - Y-axis: Increases downward

Coordinates are in pixels. If your display is 240x240, coordinates range from (0, 0) to (239, 239).

Lifecycle

Initialization

When your game starts:

  1. Configuration: Configuration objects are created (DisplayConfig, InputConfig, AudioConfig)
  2. Engine: The Engine is created with these configurations
  3. init(): engine.init() is called to initialize all subsystems
  4. Scene: The initial scene is created and configured
  5. setScene(): The scene is assigned to the Engine

Game Loop

Once initialized, the Engine enters the game loop:

While the game is running:
+

This means: - Every Actor is also an Entity - Every PhysicsActor is also an Actor and an Entity - You can use Entity for simple objects that don't need collisions - You can use Actor for objects that need to detect collisions - You can use PhysicsActor for objects that need automatic physics

Rendering System

Render Layers

To control the order in which things are drawn, PixelRoot32 uses render layers:

  • Layer 0 (Background): Backgrounds, tilemaps, background elements
  • Layer 1 (Gameplay): Characters, enemies, projectiles, game objects
  • Layer 2 (UI): Menus, HUD, text, interface elements

Layers are drawn in order: first 0, then 1, and finally 2. This ensures the background is always behind, gameplay in the middle, and UI always visible in front.

Each entity has a renderLayer property that indicates which layer it should be drawn on. You can change this property to move entities between layers.

Resolution Scaling

PixelRoot32 supports Independent Resolution Scaling. This means your game logic can run at a different resolution (the logical resolution) than the physical screen (physical resolution).

  • Logical Resolution: The resolution you program for (e.g., 128x128). All coordinates and sizes in your code refer to this space.
  • Physical Resolution: The actual number of pixels on your display (e.g., 240x240).

The engine automatically handles the scaling using an optimized hardware-accelerated process, allowing you to create low-resolution retro games that look crisp on modern high-resolution micro-displays.

Rendering Pipeline

The rendering process works like this:

  1. beginFrame(): The screen is cleared (painted black or background color)
  2. Draw entities: All visible entities are traversed, organized by layer
  3. endFrame(): The complete frame is sent to the display

The Renderer abstracts hardware details, so the same code works on both ESP32 (TFT_eSPI) and PC (SDL2).

Coordinates and Space

PixelRoot32 uses a standard coordinate system: - Origin (0, 0): Top-left corner - X-axis: Increases to the right - Y-axis: Increases downward

Coordinates are in pixels. If your display is 240x240, coordinates range from (0, 0) to (239, 239).

Lifecycle

Initialization

When your game starts:

  1. Configuration: Configuration objects are created (DisplayConfig, InputConfig, AudioConfig)
  2. Engine: The Engine is created with these configurations
  3. init(): engine.init() is called to initialize all subsystems
  4. Scene: The initial scene is created and configured
  5. setScene(): The scene is assigned to the Engine

Game Loop

Once initialized, the Engine enters the game loop:

While the game is running:
   1. Calculate deltaTime (time since last frame)
   2. Update InputManager (read buttons/keyboard)
   3. Update AudioEngine (advance sounds and music)
@@ -9,4 +9,4 @@
   5. Detect collisions in the scene
   6. Draw the scene (draw all visible entities)
   7. Repeat
-

This cycle runs continuously, typically at 30-60 FPS on ESP32, or faster on PC.

Update

Each frame, all enabled entities receive a call to their update(deltaTime) method. This is where: - Entities move - Animations update - Game logic is processed - User input is read - Sound effects are played

The deltaTime is passed in milliseconds and represents how much time has passed since the last frame. This allows movement to be framerate-independent.

Rendering (Draw)

After updating, all visible entities receive a call to their draw(renderer) method. This is where: - Sprites are drawn - Text is drawn - Primitives are drawn (rectangles, circles, etc.)

The renderer is passed as a parameter so entities can draw themselves.

Cleanup

When you change scenes or end the game: - Entities from the previous scene can be cleaned up - Resources are freed - The new scene is initialized

Conceptual Summary

To summarize, PixelRoot32 works like this:

  1. Engine coordinates everything and runs the game loop
  2. Scene organizes your game into screens/levels
  3. Entity is any object in your game
  4. Actor is an entity that can collide
  5. PhysicsActor is an actor with automatic physics
  6. Renderer draws everything on screen using layers
  7. Each frame updates logic and then draws

All of this works automatically once you configure the Engine and create your scenes and entities. You don't need to worry about game loop details; you just need to implement update() and draw() in your entities.

Next Step

Now that you understand the fundamental concepts, you're ready to create your first project and see these concepts in action with real code.


See also: - What is PixelRoot32? - Why PixelRoot32? - Your First Project - Manual - Scenes and Entities

\ No newline at end of file +

This cycle runs continuously, typically at 30-60 FPS on ESP32, or faster on PC.

Update

Each frame, all enabled entities receive a call to their update(deltaTime) method. This is where: - Entities move - Animations update - Game logic is processed - User input is read - Sound effects are played

The deltaTime is passed in milliseconds and represents how much time has passed since the last frame. This allows movement to be framerate-independent.

Rendering (Draw)

After updating, all visible entities receive a call to their draw(renderer) method. This is where: - Sprites are drawn - Text is drawn - Primitives are drawn (rectangles, circles, etc.)

The renderer is passed as a parameter so entities can draw themselves.

Cleanup

When you change scenes or end the game: - Entities from the previous scene can be cleaned up - Resources are freed - The new scene is initialized

Conceptual Summary

To summarize, PixelRoot32 works like this:

  1. Engine coordinates everything and runs the game loop
  2. Scene organizes your game into screens/levels
  3. Entity is any object in your game
  4. Actor is an entity that can collide
  5. PhysicsActor is an actor with automatic physics
  6. Renderer draws everything on screen using layers
  7. Each frame updates logic and then draws

All of this works automatically once you configure the Engine and create your scenes and entities. You don't need to worry about game loop details; you just need to implement update() and draw() in your entities.

Next Step

Now that you understand the fundamental concepts, you're ready to create your first project and see these concepts in action with real code.


See also: - What is PixelRoot32? - Why PixelRoot32? - Your First Project - Manual - Scenes and Entities

\ No newline at end of file diff --git a/site/getting_started/installation/index.html b/site/getting_started/installation/index.html index 6b1027b..3088e92 100644 --- a/site/getting_started/installation/index.html +++ b/site/getting_started/installation/index.html @@ -1,3 +1,3 @@ - Installation - PixelRoot32 Documentation
Skip to content

Installation

This guide covers installing the PixelRoot32 documentation environment and preparing your development setup for ESP32 and Native (PC) targets.

Requirements

  • Python 3.11 or newer
  • Git (recommended for source management)
  • VS Code (or your preferred IDE)
  • For ESP32 targets: PlatformIO (VS Code extension) with ESP32 toolchain
  • For Native targets: a C++ build toolchain (CMake or your OS-native toolchain)

Install Documentation Tooling

To build and preview this documentation locally:

pip install mkdocs mkdocs-material mkdocs-minify-plugin mkdocs-git-revision-date-localized-plugin mike
+ Installation - PixelRoot32 Documentation      

Installation

This guide covers installing the PixelRoot32 documentation environment and preparing your development setup for ESP32 and Native (PC) targets.

Requirements

  • Python 3.11 or newer
  • Git (recommended for source management)
  • VS Code (or your preferred IDE)
  • For ESP32 targets: PlatformIO (VS Code extension) with ESP32 toolchain
  • For Native targets: a C++ build toolchain (CMake or your OS-native toolchain)

Install Documentation Tooling

To build and preview this documentation locally:

pip install mkdocs mkdocs-material mkdocs-minify-plugin mkdocs-git-revision-date-localized-plugin mike
 mkdocs serve
-

Open http://127.0.0.1:8000 in your browser to preview.

  1. Install VS Code
  2. Install PlatformIO IDE extension
  3. Install ESP32 platform/toolchain via PlatformIO
  4. Clone the engine repository:
  5. https://github.com/Gperez88/PixelRoot32-Game-Engine
  6. Open the engine or example project in VS Code (PlatformIO)
  7. Build and upload to your ESP32 board

Tip: Use boards based on ESP32-WROOM/WROVER for best compatibility. Ensure a reliable USB cable and correct serial port selection.

Native (PC) Setup

  1. Install a C++ toolchain (e.g., MSVC or MinGW on Windows)
  2. Install CMake (if the engine provides CMake build files)
  3. Clone the engine repository:
  4. https://github.com/Gperez88/PixelRoot32-Game-Engine
  5. Configure and build the native runtime:
  6. Follow the engine’s native build instructions (Development → Compiling)

Verify Your Environment

  • ESP32: Build and flash a minimal sample; confirm serial output and display if applicable
  • Native: Run the executable; confirm window output and input handling

Troubleshooting

  • If PlatformIO cannot find the ESP32 platform, update PlatformIO and retry
  • If native builds fail, verify compiler versions and CMake generator settings
  • Use Community → Troubleshooting for common issues and fixes

Next Steps

\ No newline at end of file +

Open http://127.0.0.1:8000 in your browser to preview.

  1. Install VS Code
  2. Install PlatformIO IDE extension
  3. Install ESP32 platform/toolchain via PlatformIO
  4. Clone the engine repository:
  5. https://github.com/Gperez88/PixelRoot32-Game-Engine
  6. Open the engine or example project in VS Code (PlatformIO)
  7. Build and upload to your ESP32 board

Tip: Use boards based on ESP32-WROOM/WROVER for best compatibility. Ensure a reliable USB cable and correct serial port selection.

Native (PC) Setup

  1. Install a C++ toolchain (e.g., MSVC or MinGW on Windows)
  2. Install CMake (if the engine provides CMake build files)
  3. Clone the engine repository:
  4. https://github.com/Gperez88/PixelRoot32-Game-Engine
  5. Configure and build the native runtime:
  6. Follow the engine’s native build instructions (Development → Compiling)

Verify Your Environment

  • ESP32: Build and flash a minimal sample; confirm serial output and display if applicable
  • Native: Run the executable; confirm window output and input handling

Troubleshooting

  • If PlatformIO cannot find the ESP32 platform, update PlatformIO and retry
  • If native builds fail, verify compiler versions and CMake generator settings
  • Use Community → Troubleshooting for common issues and fixes

Next Steps

\ No newline at end of file diff --git a/site/getting_started/what_is_pixelroot32/index.html b/site/getting_started/what_is_pixelroot32/index.html index 83f715c..259e538 100644 --- a/site/getting_started/what_is_pixelroot32/index.html +++ b/site/getting_started/what_is_pixelroot32/index.html @@ -1 +1 @@ - What is PixelRoot32? - PixelRoot32 Documentation
Skip to content

What is PixelRoot32?

PixelRoot32 is a lightweight, modular 2D game engine written in C++ designed specifically for ESP32 microcontrollers, with a native simulation layer for PC (SDL2) that allows you to develop and debug quickly on your desktop before deploying to hardware.

Simple Definition

PixelRoot32 is a game engine that lets you create retro-style 8-bit/16-bit video games directly on an ESP32 board, with the ability to develop and test on your PC before transferring code to hardware.

Key Features

🎮 Scene-Based Architecture

  • Scene system inspired by Godot Engine
  • Intuitive management of levels, menus, and screens
  • Simple transitions between scenes

🎨 Optimized Rendering

  • 1bpp (monochrome) sprites as the standard format
  • Support for multi-layer sprites (MultiSprite)
  • Experimental 2bpp and 4bpp formats for higher fidelity
  • Retro color palette system (NES, GameBoy, PICO-8, etc.)
  • Compact tilemaps for backgrounds and levels
  • 2D camera with dead-zone for smooth scrolling
  • Render layer system (background, gameplay, UI)

🔊 NES-like Audio

  • 4 audio channels (2 Pulse, 1 Triangle, 1 Noise)
  • Integrated sound effects system
  • Music player for background melodies
  • Backends for ESP32 (internal DAC or external I2S) and SDL2

🎯 Physics and Collisions

  • AABB (Axis-Aligned Bounding Box) collision system
  • PhysicsActor with gravity, friction, and restitution
  • Collision layers and masks for fine control
  • World boundary collision detection

🖥️ User Interface

  • Basic elements: Labels, Buttons, Panels
  • Automatic layouts: Vertical, Horizontal, Grid, Anchor
  • Integrated D-pad navigation
  • Scroll and viewport culling for long lists

⚡ Optimized for ESP32

  • Efficient memory management
  • Integrated object pooling
  • No dynamic allocations in the game loop
  • Performance optimized for limited hardware

Typical Use Cases

PixelRoot32 is ideal for creating:

  • Arcade Games: Space Invaders, Pong, Breakout
  • Platformers: Horizontal scrolling games with simple physics
  • Puzzles: Tetris, Snake, logic games
  • Simple RPGs: Basic role-playing games with tilemaps
  • Shooters: Vertical or horizontal shooting games
  • Rapid Prototypes: Quick development of game ideas

Supported Platforms

ESP32

  • Display: TFT_eSPI (ST7735, ILI9341, ST7789, etc.)
  • Audio: Internal DAC (GPIO 25/26) or external I2S (MAX98357A, PCM5102)
  • Input: Digital buttons, D-pad
  • Hardware: Any ESP32 board (ESP32-WROOM, ESP32-WROVER, etc.)

Desktop/Native (PC)

  • Display: SDL2 (Windows, Linux, macOS)
  • Audio: SDL2 Audio
  • Input: Keyboard, mouse
  • Usage: Development, debugging, testing

Note: Support for u8g2 (OLEDs) is planned for the future.

Project Status

Current Version: v0.2.0-dev

PixelRoot32 is under active development. APIs may change and some subsystems are still experimental. Occasional changes or breaking changes are expected, especially on less-tested configurations.

Stable Features

  • Scene and entity system
  • Basic rendering (1bpp sprites)
  • NES-like audio system
  • Basic physics and collisions
  • Basic UI system
  • ESP32 and Native support

Experimental Features

  • 2bpp and 4bpp sprites (require compilation flags)
  • Scene Arena (advanced memory management)

Planned Features

  • Support for u8g2 (OLEDs)
  • Music compiler
  • Tilemap compiler
  • Save/load system
  • Spatial partitioning for collisions

Quick Comparison

When to use PixelRoot32?

✅ Use PixelRoot32 if: - You want to create retro games on ESP32 - You need a lightweight and efficient engine - You prefer a simple and clear architecture - You want to develop on PC and deploy to ESP32 - You like 8-bit/16-bit style games

❌ Don't use PixelRoot32 if: - You need 3D graphics - You require advanced shaders - You need complex physics (advanced physics engines) - You want to create modern AAA games - You need support for multiple mobile platforms

Next Step

Now that you understand what PixelRoot32 is, discover why you should use it or go directly to your first project.


See also: - Fundamental Concepts - Installation - API Reference

\ No newline at end of file + What is PixelRoot32? - PixelRoot32 Documentation
Skip to content

What is PixelRoot32?

PixelRoot32 is a lightweight, modular 2D game engine written in C++ designed specifically for ESP32 microcontrollers, with a native simulation layer for PC (SDL2) that allows you to develop and debug quickly on your desktop before deploying to hardware.

Simple Definition

PixelRoot32 is a game engine that lets you create retro-style 8-bit/16-bit video games directly on an ESP32 board, with the ability to develop and test on your PC before transferring code to hardware.

Key Features

🎮 Scene-Based Architecture

  • Scene system inspired by Godot Engine
  • Intuitive management of levels, menus, and screens
  • Simple transitions between scenes

🎨 Optimized Rendering

  • 1bpp (monochrome) sprites as the standard format
  • Support for multi-layer sprites (MultiSprite)
  • Experimental 2bpp and 4bpp formats for higher fidelity
  • Retro color palette system (NES, GameBoy, PICO-8, etc.)
  • Compact tilemaps for backgrounds and levels
  • 2D camera with dead-zone for smooth scrolling
  • Render layer system (background, gameplay, UI)

🔊 NES-like Audio

  • 4 audio channels (2 Pulse, 1 Triangle, 1 Noise)
  • Integrated sound effects system
  • Music player for background melodies
  • Backends for ESP32 (internal DAC or external I2S) and SDL2

🎯 Physics and Collisions

  • AABB (Axis-Aligned Bounding Box) collision system
  • PhysicsActor with gravity, friction, and restitution
  • Collision layers and masks for fine control
  • World boundary collision detection

🖥️ User Interface

  • Basic elements: Labels, Buttons, Panels
  • Automatic layouts: Vertical, Horizontal, Grid, Anchor
  • Integrated D-pad navigation
  • Scroll and viewport culling for long lists

⚡ Optimized for ESP32

  • Efficient memory management
  • Integrated object pooling
  • No dynamic allocations in the game loop
  • Performance optimized for limited hardware

Typical Use Cases

PixelRoot32 is ideal for creating:

  • Arcade Games: Space Invaders, Pong, Breakout
  • Platformers: Horizontal scrolling games with simple physics
  • Puzzles: Tetris, Snake, logic games
  • Simple RPGs: Basic role-playing games with tilemaps
  • Shooters: Vertical or horizontal shooting games
  • Rapid Prototypes: Quick development of game ideas

Supported Platforms

ESP32

  • Display: TFT_eSPI (ST7735, ILI9341, ST7789, etc.)
  • Audio: Internal DAC (GPIO 25/26) or external I2S (MAX98357A, PCM5102)
  • Input: Digital buttons, D-pad
  • Hardware: Any ESP32 board (ESP32-WROOM, ESP32-WROVER, etc.)

Desktop/Native (PC)

  • Display: SDL2 (Windows, Linux, macOS)
  • Audio: SDL2 Audio
  • Input: Keyboard, mouse
  • Usage: Development, debugging, testing

Note: Support for u8g2 (OLEDs) is planned for the future.

Project Status

Current Version: v0.2.0-dev

PixelRoot32 is under active development. APIs may change and some subsystems are still experimental. Occasional changes or breaking changes are expected, especially on less-tested configurations.

Stable Features

  • Scene and entity system
  • Basic rendering (1bpp sprites)
  • NES-like audio system
  • Basic physics and collisions
  • Basic UI system
  • ESP32 and Native support

Experimental Features

  • 2bpp and 4bpp sprites (require compilation flags)
  • Scene Arena (advanced memory management)

Planned Features

  • Support for u8g2 (OLEDs)
  • Music compiler
  • Tilemap compiler
  • Save/load system
  • Spatial partitioning for collisions

Quick Comparison

When to use PixelRoot32?

✅ Use PixelRoot32 if: - You want to create retro games on ESP32 - You need a lightweight and efficient engine - You prefer a simple and clear architecture - You want to develop on PC and deploy to ESP32 - You like 8-bit/16-bit style games

❌ Don't use PixelRoot32 if: - You need 3D graphics - You require advanced shaders - You need complex physics (advanced physics engines) - You want to create modern AAA games - You need support for multiple mobile platforms

Next Step

Now that you understand what PixelRoot32 is, discover why you should use it or go directly to your first project.


See also: - Fundamental Concepts - Installation - API Reference

\ No newline at end of file diff --git a/site/getting_started/why_pixelroot32/index.html b/site/getting_started/why_pixelroot32/index.html index 1f753ff..ad5444a 100644 --- a/site/getting_started/why_pixelroot32/index.html +++ b/site/getting_started/why_pixelroot32/index.html @@ -1 +1 @@ - Why PixelRoot32? - PixelRoot32 Documentation
Skip to content

Why PixelRoot32?

PixelRoot32 is specifically designed to solve the unique challenges of creating video games on embedded hardware like the ESP32, while maintaining the simplicity and productivity of modern development.

Main Advantages

🎯 Optimized for ESP32

Memory Efficient - 1bpp sprite system that minimizes RAM and Flash usage - Integrated object pooling to avoid memory fragmentation - Compact tilemaps that reuse sprites - No dynamic allocations in the game loop

Performance Optimized - Rendering optimized for ESP32 limitations - Efficient render layer system - Viewport culling to reduce draw calls - Rendering pipeline designed for limited hardware

Real Hardware - Direct support for common TFT displays (ST7735, ILI9341, ST7789) - Integrated audio (internal DAC or external I2S) - Simple pin and hardware configuration

🖥️ Cross-Platform Development

Develop on PC, Deploy to ESP32 - Same code works on PC (SDL2) and ESP32 - Fast debugging on desktop - Testing without hardware needed - Rapid development iteration

Visual Consistency - Native bitmap font system (pixel-perfect) - Same rendering on PC and ESP32 - Consistent color palettes - No surprises when transferring to hardware

🎨 Retro Palette System

Authentic Style - Predefined palettes: NES, GameBoy, GameBoy Color, PICO-8 - Dual palette mode for visual contrasts - Custom palettes for unique styles - Automatic color resolution (RGB565)

Easy to Use - Change palette with one line of code - Consistent visualization across all sprites - No need to manually convert assets

🔊 Integrated Audio

Complete NES-like System - 4 audio channels (2 Pulse, 1 Triangle, 1 Noise) - Simple sound effects to create - Integrated music system - Backends for different hardware configurations

No External Dependencies - Software-generated audio - No heavy audio libraries required - Full control over sound - Deterministic and predictable

🏗️ Simple and Clear Architecture

Easy to Understand - Intuitive scene system (inspired by Godot) - Clear hierarchy: Entity → Actor → PhysicsActor - Consistent and predictable APIs - Clean and well-organized code

Quick to Learn - Familiar concepts for game developers - Clear documentation and complete examples - Smooth learning curve - Active community and support

🎮 Complete Features

Everything Needed for Games - Rendering (sprites, tilemaps, primitives) - Audio (effects and music) - Physics (gravity, collisions, basic physics) - UI (layouts, buttons, navigation) - Input (buttons, keyboard) - Camera (scroll, parallax)

No Bloat - Only the essentials, nothing more - No heavy dependencies - Small and maintainable codebase - Easy to understand and modify

🛠️ Tools and Ecosystem

Available Tools - Sprite Compiler to convert PNG to sprites - Complete game examples - Templates and starter code - Extensive documentation

Community and Support - Active and developing project - Open source (MIT License) - Feedback and contributions welcome - Examples available

Comparison with Alternatives

vs. Full Engines (Unity, Godot, etc.)

PixelRoot32 Advantages: - ✅ Much lighter (fits in ESP32) - ✅ No unnecessary overhead - ✅ Full control over code - ✅ Specifically optimized for limited hardware

Disadvantages: - ❌ Fewer advanced features - ❌ No visual editor - ❌ Fewer resources and community

vs. Writing Everything from Scratch

PixelRoot32 Advantages: - ✅ Rendering system already implemented - ✅ Integrated and working audio - ✅ Physics and collisions ready - ✅ Complete UI system - ✅ Saves months of development

Disadvantages: - ❌ Less control over internal implementation - ❌ You must learn the engine API

vs. Other ESP32 Engines

PixelRoot32 Advantages: - ✅ More modern and clear architecture - ✅ Better documentation - ✅ Unique palette system - ✅ Integrated NES-like audio - ✅ Real cross-platform development

Ideal Use Cases

PixelRoot32 is perfect for:

  1. Educational Projects
  2. Learn game development
  3. Understand engine architecture
  4. Student projects

  5. Rapid Prototypes

  6. Quickly validate game ideas
  7. Create demos and proof-of-concepts
  8. Test mechanics

  9. Retro Games

  10. 8-bit/16-bit style games
  11. Arcade games
  12. Games with retro aesthetics

  13. Hardware Projects

  14. Games on small displays
  15. DIY portable consoles
  16. Maker/retro projects

  17. C++ Learning

  18. Clean and well-structured code
  19. Good programming practices
  20. Real and functional examples

Limitations to Consider

To be honest, PixelRoot32 has limitations:

  • Limited Hardware: Designed for ESP32, not powerful PCs
  • Simple Graphics: No 3D, no advanced shaders
  • Basic Physics: Not a complete physics engine
  • Restricted Memory: MAX_ENTITIES = 32 per scene
  • In Development: Some features are experimental

If you need advanced features or powerful hardware, consider other engines. But for retro games on ESP32, PixelRoot32 is an excellent choice.

Conclusion

PixelRoot32 combines:

  • Simplicity of use
  • Efficiency for limited hardware
  • Completeness of essential features
  • Clarity of architecture
  • Productivity in development

If you want to create retro games on ESP32 without the complexity of large engines, PixelRoot32 is the right choice.

Next Step

Now that you understand why PixelRoot32 is a good option, learn the fundamental concepts or start directly with your first project.


See also: - What is PixelRoot32? - Fundamental Concepts - Your First Project

\ No newline at end of file + Why PixelRoot32? - PixelRoot32 Documentation
Skip to content

Why PixelRoot32?

PixelRoot32 is specifically designed to solve the unique challenges of creating video games on embedded hardware like the ESP32, while maintaining the simplicity and productivity of modern development.

Main Advantages

🎯 Optimized for ESP32

Memory Efficient - 1bpp sprite system that minimizes RAM and Flash usage - Integrated object pooling to avoid memory fragmentation - Compact tilemaps that reuse sprites - No dynamic allocations in the game loop

Performance Optimized - Rendering optimized for ESP32 limitations - Efficient render layer system - Viewport culling to reduce draw calls - Rendering pipeline designed for limited hardware

Real Hardware - Direct support for common TFT displays (ST7735, ILI9341, ST7789) - Integrated audio (internal DAC or external I2S) - Simple pin and hardware configuration

🖥️ Cross-Platform Development

Develop on PC, Deploy to ESP32 - Same code works on PC (SDL2) and ESP32 - Fast debugging on desktop - Testing without hardware needed - Rapid development iteration

Visual Consistency - Native bitmap font system (pixel-perfect) - Same rendering on PC and ESP32 - Consistent color palettes - No surprises when transferring to hardware

🎨 Retro Palette System

Authentic Style - Predefined palettes: NES, GameBoy, GameBoy Color, PICO-8 - Dual palette mode for visual contrasts - Custom palettes for unique styles - Automatic color resolution (RGB565)

Easy to Use - Change palette with one line of code - Consistent visualization across all sprites - No need to manually convert assets

🔊 Integrated Audio

Complete NES-like System - 4 audio channels (2 Pulse, 1 Triangle, 1 Noise) - Simple sound effects to create - Integrated music system - Backends for different hardware configurations

No External Dependencies - Software-generated audio - No heavy audio libraries required - Full control over sound - Deterministic and predictable

🏗️ Simple and Clear Architecture

Easy to Understand - Intuitive scene system (inspired by Godot) - Clear hierarchy: Entity → Actor → PhysicsActor - Consistent and predictable APIs - Clean and well-organized code

Quick to Learn - Familiar concepts for game developers - Clear documentation and complete examples - Smooth learning curve - Active community and support

🎮 Complete Features

Everything Needed for Games - Rendering (sprites, tilemaps, primitives) - Audio (effects and music) - Physics (gravity, collisions, basic physics) - UI (layouts, buttons, navigation) - Input (buttons, keyboard) - Camera (scroll, parallax)

No Bloat - Only the essentials, nothing more - No heavy dependencies - Small and maintainable codebase - Easy to understand and modify

🛠️ Tools and Ecosystem

Available Tools - Sprite Compiler to convert PNG to sprites - Complete game examples - Templates and starter code - Extensive documentation

Community and Support - Active and developing project - Open source (MIT License) - Feedback and contributions welcome - Examples available

Comparison with Alternatives

vs. Full Engines (Unity, Godot, etc.)

PixelRoot32 Advantages: - ✅ Much lighter (fits in ESP32) - ✅ No unnecessary overhead - ✅ Full control over code - ✅ Specifically optimized for limited hardware

Disadvantages: - ❌ Fewer advanced features - ❌ No visual editor - ❌ Fewer resources and community

vs. Writing Everything from Scratch

PixelRoot32 Advantages: - ✅ Rendering system already implemented - ✅ Integrated and working audio - ✅ Physics and collisions ready - ✅ Complete UI system - ✅ Saves months of development

Disadvantages: - ❌ Less control over internal implementation - ❌ You must learn the engine API

vs. Other ESP32 Engines

PixelRoot32 Advantages: - ✅ More modern and clear architecture - ✅ Better documentation - ✅ Unique palette system - ✅ Integrated NES-like audio - ✅ Real cross-platform development

Ideal Use Cases

PixelRoot32 is perfect for:

  1. Educational Projects
  2. Learn game development
  3. Understand engine architecture
  4. Student projects

  5. Rapid Prototypes

  6. Quickly validate game ideas
  7. Create demos and proof-of-concepts
  8. Test mechanics

  9. Retro Games

  10. 8-bit/16-bit style games
  11. Arcade games
  12. Games with retro aesthetics

  13. Hardware Projects

  14. Games on small displays
  15. DIY portable consoles
  16. Maker/retro projects

  17. C++ Learning

  18. Clean and well-structured code
  19. Good programming practices
  20. Real and functional examples

Limitations to Consider

To be honest, PixelRoot32 has limitations:

  • Limited Hardware: Designed for ESP32, not powerful PCs
  • Simple Graphics: No 3D, no advanced shaders
  • Basic Physics: Not a complete physics engine
  • Restricted Memory: MAX_ENTITIES = 32 per scene
  • In Development: Some features are experimental

If you need advanced features or powerful hardware, consider other engines. But for retro games on ESP32, PixelRoot32 is an excellent choice.

Conclusion

PixelRoot32 combines:

  • Simplicity of use
  • Efficiency for limited hardware
  • Completeness of essential features
  • Clarity of architecture
  • Productivity in development

If you want to create retro games on ESP32 without the complexity of large engines, PixelRoot32 is the right choice.

Next Step

Now that you understand why PixelRoot32 is a good option, learn the fundamental concepts or start directly with your first project.


See also: - What is PixelRoot32? - Fundamental Concepts - Your First Project

\ No newline at end of file diff --git a/site/getting_started/your_first_project/index.html b/site/getting_started/your_first_project/index.html index c6bf7ec..0f8e497 100644 --- a/site/getting_started/your_first_project/index.html +++ b/site/getting_started/your_first_project/index.html @@ -1,4 +1,4 @@ - Your First Project - PixelRoot32 Documentation
Skip to content

Your First Project

This guide will walk you through creating and running your first PixelRoot32 project step by step. By the end, you'll have a working project that displays a simple scene on both ESP32 and PC.

Prerequisites

Required Software

  • PlatformIO: Install the PlatformIO IDE extension in VS Code
  • Open VS Code
  • Go to Extensions (Ctrl+Shift+X)
  • Search for "PlatformIO IDE"
  • Install and restart VS Code

  • Python 3.8+: Required for PlatformIO (usually installed automatically)

For ESP32 Development

  • ESP32 Board: Any ESP32 development board (ESP32-WROOM, ESP32-WROVER, etc.)
  • USB Cable: To connect and program your ESP32
  • TFT Display: Compatible display (ST7735, ST7789, ILI9341, etc.)
  • Buttons: 5-6 digital buttons for input (optional for first project)
  • Audio Hardware (optional): Speaker + amplifier (PAM8302A) or I2S DAC (MAX98357A)

For Native (PC) Development

  • SDL2: Development libraries
  • Windows (MSYS2): pacman -S mingw-w64-x86_64-SDL2
  • Linux: sudo apt-get install libsdl2-dev
  • macOS: brew install sdl2

Step 1: Create a New PlatformIO Project

  1. Open VS Code with PlatformIO installed

  2. Create New Project:

  3. Click on the PlatformIO icon in the sidebar
  4. Click "New Project"
  5. Name: my-first-pixelroot32-game
  6. Board: Select "ESP32 Dev Module" (or your specific board)
  7. Framework: Arduino
  8. Location: Choose your workspace folder
  9. Click "Finish"

  10. Project Structure: Your project should now have this structure:

    my-first-pixelroot32-game/
    + Your First Project - PixelRoot32 Documentation      

    Your First Project

    This guide will walk you through creating and running your first PixelRoot32 project step by step. By the end, you'll have a working project that displays a simple scene on both ESP32 and PC.

    Prerequisites

    Required Software

    • PlatformIO: Install the PlatformIO IDE extension in VS Code
    • Open VS Code
    • Go to Extensions (Ctrl+Shift+X)
    • Search for "PlatformIO IDE"
    • Install and restart VS Code

    • Python 3.8+: Required for PlatformIO (usually installed automatically)

    For ESP32 Development

    • ESP32 Board: Any ESP32 development board (ESP32-WROOM, ESP32-WROVER, etc.)
    • USB Cable: To connect and program your ESP32
    • TFT Display: Compatible display (ST7735, ST7789, ILI9341, etc.)
    • Buttons: 5-6 digital buttons for input (optional for first project)
    • Audio Hardware (optional): Speaker + amplifier (PAM8302A) or I2S DAC (MAX98357A)

    For Native (PC) Development

    • SDL2: Development libraries
    • Windows (MSYS2): pacman -S mingw-w64-x86_64-SDL2
    • Linux: sudo apt-get install libsdl2-dev
    • macOS: brew install sdl2

    Step 1: Create a New PlatformIO Project

    1. Open VS Code with PlatformIO installed

    2. Create New Project:

    3. Click on the PlatformIO icon in the sidebar
    4. Click "New Project"
    5. Name: my-first-pixelroot32-game
    6. Board: Select "ESP32 Dev Module" (or your specific board)
    7. Framework: Arduino
    8. Location: Choose your workspace folder
    9. Click "Finish"

    10. Project Structure: Your project should now have this structure:

      my-first-pixelroot32-game/
       ├── .pio/
       ├── include/
       ├── lib/
      @@ -106,12 +106,12 @@
       pr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);
       
       // Display configuration
      -// ST7789, rotation 0, 240x240 resolution
      -pr32::graphics::DisplayConfig displayConfig(
      +// 128x128 game logic scaled to 240x240 display
      +pr32::graphics::DisplayConfig displayConfig(
           pr32::graphics::DisplayType::ST7789, 
           0,      // rotation
      -    240,    // width
      -    240     // height
      +    240, 240, // physical resolution (hardware)
      +    128, 128  // logical resolution (rendering space)
       );
       
       // Input configuration (6 buttons: UP, DOWN, LEFT, RIGHT, A, B)
      @@ -165,49 +165,50 @@
       pr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);
       
       // Display configuration (NONE defaults to SDL2 on Native)
      -pr32::graphics::DisplayConfig displayConfig(
      -    pr32::graphics::DisplayType::NONE,
      -    0,      // rotation
      -    240,    // width
      -    240     // height
      -);
      -
      -// Input configuration (SDL scancodes)
      -pr32::input::InputConfig inputConfig(
      -    6,                      // button count
      -    SDL_SCANCODE_UP,        // UP
      -    SDL_SCANCODE_DOWN,      // DOWN
      -    SDL_SCANCODE_LEFT,      // LEFT
      -    SDL_SCANCODE_RIGHT,     // RIGHT
      -    SDL_SCANCODE_SPACE,     // A button
      -    SDL_SCANCODE_RETURN     // B button
      -);
      -
      -// Audio configuration
      -pr32::audio::AudioConfig audioConfig(&audioBackend, 22050);
      -
      -// Create the engine
      -pr32::core::Engine engine(displayConfig, inputConfig, audioConfig);
      -
      -// Create your scene
      -MyFirstScene myScene;
      -
      -int main(int argc, char* argv[]) {
      -    (void)argc;
      -    (void)argv;
      -
      -    // Initialize the engine
      -    engine.init();
      -
      -    // Initialize and set the scene
      -    myScene.init();
      -    engine.setScene(&myScene);
      -
      -    // Run the game loop
      -    engine.run();
      -
      -    return 0;
      -}
      +// 128x128 game logic scaled to 240x240 display
      +pr32::graphics::DisplayConfig displayConfig(
      +    pr32::graphics::DisplayType::NONE,
      +    0,      // rotation
      +    240, 240, // physical resolution
      +    128, 128  // logical resolution
      +);
      +
      +// Input configuration (SDL scancodes)
      +pr32::input::InputConfig inputConfig(
      +    6,                      // button count
      +    SDL_SCANCODE_UP,        // UP
      +    SDL_SCANCODE_DOWN,      // DOWN
      +    SDL_SCANCODE_LEFT,      // LEFT
      +    SDL_SCANCODE_RIGHT,     // RIGHT
      +    SDL_SCANCODE_SPACE,     // A button
      +    SDL_SCANCODE_RETURN     // B button
      +);
      +
      +// Audio configuration
      +pr32::audio::AudioConfig audioConfig(&audioBackend, 22050);
      +
      +// Create the engine
      +pr32::core::Engine engine(displayConfig, inputConfig, audioConfig);
      +
      +// Create your scene
      +MyFirstScene myScene;
      +
      +int main(int argc, char* argv[]) {
      +    (void)argc;
      +    (void)argv;
      +
      +    // Initialize the engine
      +    engine.init();
      +
      +    // Initialize and set the scene
      +    myScene.init();
      +    engine.setScene(&myScene);
      +
      +    // Run the game loop
      +    engine.run();
      +
      +    return 0;
      +}
       

      Configure Native Build

      Add to platformio.ini:

      [env:native]
       platform = native
       build_src_filter = 
      @@ -226,4 +227,4 @@
           -std=c++17
           -lSDL2
           -mconsole
      -

      Note: Adjust the SDL2 include and library paths for your system.

      Step 7: Build and Run

      For ESP32

      1. Connect your ESP32 via USB
      2. Select the environment: Click on the PlatformIO icon → Select env:esp32dev
      3. Build: Click the checkmark icon (✓) or press Ctrl+Alt+B
      4. Upload: Click the arrow icon (→) or press Ctrl+Alt+U
      5. Monitor: Click the plug icon to open serial monitor

      You should see "PixelRoot32 initialized!" in the serial monitor and your display should show a blue rectangle and text.

      For Native (PC)

      1. Select the environment: Click on the PlatformIO icon → Select env:native
      2. Build and Run: Click the play icon (▶) or press Ctrl+Alt+R

      A window should open showing your scene with a blue rectangle and "Hello PixelRoot32!" text.

      Step 8: Verify It Works

      If everything is set up correctly, you should see:

      • ESP32: Display shows a blue rectangle at (50, 50) and white text "Hello PixelRoot32!" at (20, 20)
      • Native: Window shows the same content

      If you see this, congratulations! Your first PixelRoot32 project is working.

      Troubleshooting

      ESP32 Issues

      Display is blank: - Check wiring connections - Verify pin numbers in platformio.ini match your hardware - Check SPI frequency (try lowering it) - Verify display type (ST7789 vs ST7735)

      Compilation errors: - Ensure library version is exactly 0.2.0-dev - Check that TFT_eSPI is installed - Verify all include paths are correct

      Upload fails: - Check USB cable connection - Try different USB port - Press BOOT button on ESP32 during upload - Check COM port in PlatformIO

      Native Issues

      SDL2 not found: - Verify SDL2 is installed - Check include/library paths in platformio.ini - On Windows, ensure MSYS2 paths are correct

      Window doesn't open: - Check console for error messages - Verify SDL2 is properly linked - Try running from terminal to see errors

      Next Steps

      Now that you have a working project, you can:

      1. Learn about Scenes and Entities: See how to create game objects
      2. Add Input: Make your scene respond to buttons
      3. Add Sprites: Draw custom graphics
      4. Add Audio: Play sounds and music

      Continue with the Development Guide to learn more.


      See also: - Fundamental Concepts - Installation - Manual - Scenes and Entities - API Reference

    \ No newline at end of file +

    Note: Adjust the SDL2 include and library paths for your system.

    Step 7: Build and Run

    For ESP32

    1. Connect your ESP32 via USB
    2. Select the environment: Click on the PlatformIO icon → Select env:esp32dev
    3. Build: Click the checkmark icon (✓) or press Ctrl+Alt+B
    4. Upload: Click the arrow icon (→) or press Ctrl+Alt+U
    5. Monitor: Click the plug icon to open serial monitor

    You should see "PixelRoot32 initialized!" in the serial monitor and your display should show a blue rectangle and text.

    For Native (PC)

    1. Select the environment: Click on the PlatformIO icon → Select env:native
    2. Build and Run: Click the play icon (▶) or press Ctrl+Alt+R

    A window should open showing your scene with a blue rectangle and "Hello PixelRoot32!" text.

    Step 8: Verify It Works

    If everything is set up correctly, you should see:

    • ESP32: Display shows a blue rectangle at (50, 50) and white text "Hello PixelRoot32!" at (20, 20)
    • Native: Window shows the same content

    If you see this, congratulations! Your first PixelRoot32 project is working.

    Troubleshooting

    ESP32 Issues

    Display is blank: - Check wiring connections - Verify pin numbers in platformio.ini match your hardware - Check SPI frequency (try lowering it) - Verify display type (ST7789 vs ST7735)

    Compilation errors: - Ensure library version is exactly 0.2.0-dev - Check that TFT_eSPI is installed - Verify all include paths are correct

    Upload fails: - Check USB cable connection - Try different USB port - Press BOOT button on ESP32 during upload - Check COM port in PlatformIO

    Native Issues

    SDL2 not found: - Verify SDL2 is installed - Check include/library paths in platformio.ini - On Windows, ensure MSYS2 paths are correct

    Window doesn't open: - Check console for error messages - Verify SDL2 is properly linked - Try running from terminal to see errors

    Next Steps

    Now that you have a working project, you can:

    1. Learn about Scenes and Entities: See how to create game objects
    2. Add Input: Make your scene respond to buttons
    3. Add Sprites: Draw custom graphics
    4. Add Audio: Play sounds and music

    Continue with the Development Guide to learn more.


    See also: - Fundamental Concepts - Installation - Manual - Scenes and Entities - API Reference

\ No newline at end of file diff --git a/site/index.html b/site/index.html index f4fb5d9..2ed7ede 100644 --- a/site/index.html +++ b/site/index.html @@ -1 +1 @@ - PixelRoot32 Documentation
Skip to content

PixelRoot32 Documentation

PixelRoot32 is a lightweight 2D game engine designed for ESP32 and native desktop targets. This site provides official, versioned documentation with clear guides, conceptual explanations, API references, and complete examples to help you build games efficiently.

Getting Started

New to PixelRoot32? Follow this learning path:

  1. What is PixelRoot32? - Understand what the engine is and what it can do
  2. Why PixelRoot32? - Learn the advantages and use cases
  3. Fundamental Concepts - Learn the core architecture concepts
  4. Your First Project - Create and run your first project

About This Documentation

  • Professional technical English across all pages
  • Search-enabled, mobile-friendly UI
  • Versioned with mike (stable/dev/experimental)
  • Cross-linked concepts, API, and examples
  • Progressive learning path from basics to advanced topics
\ No newline at end of file + PixelRoot32 Documentation
Skip to content

PixelRoot32 Documentation

PixelRoot32 is a lightweight 2D game engine designed for ESP32 and native desktop targets. This site provides official, versioned documentation with clear guides, conceptual explanations, API references, and complete examples to help you build games efficiently.

Getting Started

New to PixelRoot32? Follow this learning path:

  1. What is PixelRoot32? - Understand what the engine is and what it can do
  2. Why PixelRoot32? - Learn the advantages and use cases
  3. Fundamental Concepts - Learn the core architecture concepts
  4. Your First Project - Create and run your first project

About This Documentation

  • Professional technical English across all pages
  • Search-enabled, mobile-friendly UI
  • Versioned with mike (stable/dev/experimental)
  • Cross-linked concepts, API, and examples
  • Progressive learning path from basics to advanced topics
\ No newline at end of file diff --git a/site/manual/advanced_graphics/cameras_and_scrolling/index.html b/site/manual/advanced_graphics/cameras_and_scrolling/index.html index 3c2487b..8250e13 100644 --- a/site/manual/advanced_graphics/cameras_and_scrolling/index.html +++ b/site/manual/advanced_graphics/cameras_and_scrolling/index.html @@ -1,4 +1,4 @@ - Cameras and Scrolling - PixelRoot32 Documentation
Skip to content

Cameras and Scrolling

Camera2D allows you to create worlds larger than the screen by scrolling the view. This guide covers camera setup, following targets, boundaries, and parallax effects.

Camera2D Basics

A Camera2D defines what portion of your game world is visible on screen.

Creating a Camera

#include <graphics/Camera2D.h>
+ Cameras and Scrolling - PixelRoot32 Documentation      

Cameras and Scrolling

Camera2D allows you to create worlds larger than the screen by scrolling the view. This guide covers camera setup, following targets, boundaries, and parallax effects.

Camera2D Basics

A Camera2D defines what portion of your game world is visible on screen.

Creating a Camera

#include <graphics/Camera2D.h>
 
 // Create camera with viewport size
 pixelroot32::graphics::Camera2D camera(240, 240); // Screen width, height
@@ -316,4 +316,4 @@
              y + height < cameraY || 
              y > cameraY + screenHeight);
 }
-

Troubleshooting

Camera Not Moving

  • Verify camera.apply() is called in draw()
  • Check followTarget() or setPosition() is called in update()
  • Ensure camera is created with correct viewport size
  • Check boundaries aren't preventing movement

Objects Not Visible

  • Verify objects are within camera view
  • Check world coordinates vs screen coordinates
  • Ensure camera is applied before drawing
  • Verify render layers are correct

Parallax Not Working

  • Check setDisplayOffset() is used correctly
  • Verify parallax speed values (0.0 to 1.0)
  • Ensure offset is reset after parallax layers
  • Test with different speed values

Next Steps

Now that you understand cameras and scrolling, learn about: - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects - Performance Optimization - Optimize your game


See also: - API Reference - Camera2D - Manual - Basic Rendering - Manual - Tilemaps

\ No newline at end of file +

Troubleshooting

Camera Not Moving

  • Verify camera.apply() is called in draw()
  • Check followTarget() or setPosition() is called in update()
  • Ensure camera is created with correct viewport size
  • Check boundaries aren't preventing movement

Objects Not Visible

  • Verify objects are within camera view
  • Check world coordinates vs screen coordinates
  • Ensure camera is applied before drawing
  • Verify render layers are correct

Parallax Not Working

  • Check setDisplayOffset() is used correctly
  • Verify parallax speed values (0.0 to 1.0)
  • Ensure offset is reset after parallax layers
  • Test with different speed values

Next Steps

Now that you understand cameras and scrolling, learn about: - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects - Performance Optimization - Optimize your game


See also: - API Reference - Camera2D - Manual - Basic Rendering - Manual - Tilemaps

\ No newline at end of file diff --git a/site/manual/advanced_graphics/color_palettes/index.html b/site/manual/advanced_graphics/color_palettes/index.html index ff19ec6..29bad25 100644 --- a/site/manual/advanced_graphics/color_palettes/index.html +++ b/site/manual/advanced_graphics/color_palettes/index.html @@ -1,4 +1,4 @@ - Color Palettes - PixelRoot32 Documentation
Skip to content

Color Palettes

PixelRoot32 uses a palette-based color system that allows you to easily change the visual style of your game. This guide covers built-in palettes, dual palette mode, and custom palettes.

Built-in Palettes

PixelRoot32 includes several predefined palettes inspired by classic gaming systems:

Available Palettes

#include <graphics/PaletteDefs.h>
+ Color Palettes - PixelRoot32 Documentation      

Color Palettes

PixelRoot32 uses a palette-based color system that allows you to easily change the visual style of your game. This guide covers built-in palettes, dual palette mode, and custom palettes.

Built-in Palettes

PixelRoot32 includes several predefined palettes inspired by classic gaming systems:

Available Palettes

#include <graphics/PaletteDefs.h>
 
 namespace pixelroot32::graphics {
 
@@ -204,4 +204,4 @@
         Color::White
     };
 }
-

Troubleshooting

Colors Not Changing

  • Verify setPalette() is called before drawing
  • Check palette is set in init(), not update()
  • Ensure dual palette mode is enabled if using separate palettes
  • Verify Color constants are from correct namespace

Colors Look Wrong on Hardware

  • ESP32 displays may render colors differently
  • Test on actual hardware, not just PC
  • Adjust palette colors if needed
  • Consider display calibration

Dual Palette Not Working

  • Ensure enableDualPaletteMode() is called first
  • Verify both palettes are set
  • Check that you're drawing in correct context
  • Review renderer documentation

Next Steps

Now that you understand palettes, learn about: - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects


See also: - API Reference - PaletteDefs - API Reference - Color - Manual - Basic Rendering

\ No newline at end of file +

Troubleshooting

Colors Not Changing

  • Verify setPalette() is called before drawing
  • Check palette is set in init(), not update()
  • Ensure dual palette mode is enabled if using separate palettes
  • Verify Color constants are from correct namespace

Colors Look Wrong on Hardware

  • ESP32 displays may render colors differently
  • Test on actual hardware, not just PC
  • Adjust palette colors if needed
  • Consider display calibration

Dual Palette Not Working

  • Ensure enableDualPaletteMode() is called first
  • Verify both palettes are set
  • Check that you're drawing in correct context
  • Review renderer documentation

Next Steps

Now that you understand palettes, learn about: - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects


See also: - API Reference - PaletteDefs - API Reference - Color - Manual - Basic Rendering

\ No newline at end of file diff --git a/site/manual/advanced_graphics/particles_and_effects/index.html b/site/manual/advanced_graphics/particles_and_effects/index.html index 183ce08..d59882b 100644 --- a/site/manual/advanced_graphics/particles_and_effects/index.html +++ b/site/manual/advanced_graphics/particles_and_effects/index.html @@ -1,4 +1,4 @@ - Particles and Effects - PixelRoot32 Documentation
Skip to content

Particles and Effects

The particle system allows you to create visual effects like fire, explosions, smoke, and sparks. This guide covers ParticleEmitter, ParticleConfig, and the included presets.

ParticleEmitter Basics

A ParticleEmitter is an Entity that manages a pool of particles to create visual effects.

Creating a Particle Emitter

#include <graphics/particles/ParticleEmitter.h>
+ Particles and Effects - PixelRoot32 Documentation      

Particles and Effects

The particle system allows you to create visual effects like fire, explosions, smoke, and sparks. This guide covers ParticleEmitter, ParticleConfig, and the included presets.

ParticleEmitter Basics

A ParticleEmitter is an Entity that manages a pool of particles to create visual effects.

Creating a Particle Emitter

#include <graphics/particles/ParticleEmitter.h>
 #include <graphics/particles/ParticleConfig.h>
 
 // Create particle configuration
@@ -287,4 +287,4 @@
         emitter->update(deltaTime);
     }
 };
-

Troubleshooting

Particles Not Appearing

  • Verify emitter is added to scene
  • Check particle config is valid
  • Ensure burst() is being called
  • Verify emitter position is on-screen

Performance Issues

  • Reduce particle count per burst
  • Limit number of active emitters
  • Use simpler particle configs
  • Disable emitters when not visible

Particles Not Moving

  • Check gravity value (positive = down, negative = up)
  • Verify speed is not 0
  • Check friction isn't too high (1.0 = no movement)
  • Ensure direction is correct (degrees: 0=right, 90=up, 180=left, 270=down)

Next Steps

Now that you understand particles, you've completed the advanced graphics section. Continue with: - Performance Optimization - Optimize your game - Memory Management - Manage memory efficiently - API Reference - Complete API documentation


See also: - API Reference - ParticleEmitter - API Reference - ParticleConfig - API Reference - ParticlePresets - Manual - Basic Rendering

\ No newline at end of file +

Troubleshooting

Particles Not Appearing

  • Verify emitter is added to scene
  • Check particle config is valid
  • Ensure burst() is being called
  • Verify emitter position is on-screen

Performance Issues

  • Reduce particle count per burst
  • Limit number of active emitters
  • Use simpler particle configs
  • Disable emitters when not visible

Particles Not Moving

  • Check gravity value (positive = down, negative = up)
  • Verify speed is not 0
  • Check friction isn't too high (1.0 = no movement)
  • Ensure direction is correct (degrees: 0=right, 90=up, 180=left, 270=down)

Next Steps

Now that you understand particles, you've completed the advanced graphics section. Continue with: - Performance Optimization - Optimize your game - Memory Management - Manage memory efficiently - API Reference - Complete API documentation


See also: - API Reference - ParticleEmitter - API Reference - ParticleConfig - API Reference - ParticlePresets - Manual - Basic Rendering

\ No newline at end of file diff --git a/site/manual/advanced_graphics/resolution_scaling/index.html b/site/manual/advanced_graphics/resolution_scaling/index.html new file mode 100644 index 0000000..96c71c6 --- /dev/null +++ b/site/manual/advanced_graphics/resolution_scaling/index.html @@ -0,0 +1,28 @@ + Resolution Scaling - PixelRoot32 Documentation
Skip to content

Resolution Scaling

PixelRoot32 features a powerful Independent Resolution Scaling system. This allows the engine to render internally at a lower resolution (Logical Resolution) and then scale the final image to the display's actual hardware resolution (Physical Resolution).

Why use Resolution Scaling?

On microcontrollers like the ESP32, memory and processing power are limited. Rendering at a full 240x240 resolution consumes significant RAM and CPU cycles for every pixel drawn.

By using a lower logical resolution (e.g., 128x128): 1. Memory Savings: A 128x128 8bpp buffer uses ~16KB, while 240x240 uses ~57KB (72% reduction). 2. Performance Boost: Fewer pixels to process means more complex scenes and higher FPS. 3. Retro Aesthetic: Nearest-neighbor scaling preserves the pixel-art look perfectly.

Logical vs Physical Resolution

  • Logical Resolution: The virtual canvas where your game logic, sprites, and UI are drawn.
  • Physical Resolution: The actual pixel dimensions of your hardware display.
flowchart LR
+    subgraph Logical [Logical Resolution 128x128]
+        A[Game Logic] --> B[Renderer API]
+        B --> C[Internal Framebuffer]
+    end
+
+    subgraph Scaling [Hardware Scaling]
+        C --> D[Nearest Neighbor Scaler]
+    end
+
+    subgraph Physical [Physical Display 240x240]
+        D --> E[SPI/DMA Transfer]
+        E --> F[LCD Hardware]
+    end

Configuration

Using Presets

The easiest way to configure scaling is using the ResolutionPresets helper.

#include <graphics/ResolutionPresets.h>
+
+// Create a config for 128x128 logical resolution scaled to 240x240 physical
+auto config = pr32::graphics::ResolutionPresets::create(
+    pr32::graphics::RES_128x128,
+    pr32::graphics::ST7789
+);
+

Manual Configuration

You can also specify custom dimensions in the DisplayConfig constructor.

pr32::graphics::DisplayConfig config(
+    pr32::graphics::ST7789, // Driver
+    0,                      // Rotation
+    240, 240,               // Physical Width, Physical Height
+    160, 160                // Logical Width, Logical Height
+);
+

Performance Impact

The following table shows estimated savings on an ESP32 for a standard 240x240 display:

Logical Resolution Memory (8bpp) RAM Savings FPS Gain (est.)
240x240 (Full) 57.6 KB 0% Baseline
160x160 25.6 KB ~55% +30%
128x128 16.4 KB ~72% +60%
96x96 9.2 KB ~84% +100%

Implementation Details

Nearest Neighbor Scaling

The engine uses a Nearest Neighbor algorithm optimized for ESP32. It avoids floating-point math by using pre-calculated Lookup Tables (LUTs).

On-the-fly Scaling

To save even more RAM, the engine does not maintain a physical-sized buffer. Instead, it scales the image line-by-line during the SPI DMA transfer. This means the only large buffer in memory is the small logical one.

Profiling

You can measure the performance of the scaling system by enabling the Debug Statistics Overlay. This provides real-time data on FPS, CPU load, and RAM usage directly on the screen.

See Engine - Debug Overlay for instructions on how to enable it.

Alternatively, you can enable low-level profiling in EngineConfig.h:

#define PIXELROOT32_ENABLE_PROFILING
+

This will output the time taken for scaling and transfer to the Serial monitor: [PROFILING] Scaled Transfer: 12450 us (80 FPS max)

Best Practices

  1. Aspect Ratio: Keep the logical aspect ratio the same as the physical one to avoid stretching.
  2. Integer Multiples: For the sharpest results, try to use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen).
  3. UI Positioning: Use UIAnchorLayout to ensure your UI elements stay correctly positioned regardless of the logical resolution chosen.
\ No newline at end of file diff --git a/site/manual/advanced_graphics/sprites_and_animation/index.html b/site/manual/advanced_graphics/sprites_and_animation/index.html index 7b4162c..c67e88b 100644 --- a/site/manual/advanced_graphics/sprites_and_animation/index.html +++ b/site/manual/advanced_graphics/sprites_and_animation/index.html @@ -1,4 +1,4 @@ - Sprites and Animation - PixelRoot32 Documentation
Skip to content

Sprites and Animation

This guide covers advanced sprite techniques and animation in PixelRoot32, including different sprite formats, creating animations, and best practices.

Sprite Formats

PixelRoot32 supports multiple sprite formats, each optimized for different use cases.

1bpp (Standard, Monochrome)

The standard format uses 1 bit per pixel (monochrome). This is the most memory-efficient format:

#include <graphics/Renderer.h>
+ Sprites and Animation - PixelRoot32 Documentation      

Sprites and Animation

This guide covers advanced sprite techniques and animation in PixelRoot32, including different sprite formats, creating animations, and best practices.

Sprite Formats

PixelRoot32 supports multiple sprite formats, each optimized for different use cases.

1bpp (Standard, Monochrome)

The standard format uses 1 bit per pixel (monochrome). This is the most memory-efficient format:

#include <graphics/Renderer.h>
 
 // Define sprite data (8x8 example)
 static const uint16_t PLAYER_SPRITE_DATA[] = {
@@ -350,4 +350,4 @@
         return nullptr;
     }
 };
-

Troubleshooting

Sprites Not Displaying

  • Check sprite data is valid
  • Verify width/height match data
  • Ensure sprite is within screen bounds
  • Check render layer is correct

Animation Not Playing

  • Verify animation frames are set
  • Check step() is being called
  • Ensure timer logic is correct
  • Verify frame count matches array size

Memory Issues

  • Reduce sprite count
  • Use 1bpp instead of 2bpp/4bpp
  • Reuse sprites more
  • Check available flash memory

Next Steps

Now that you understand sprites and animation, learn about: - Color Palettes - Use different color schemes - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles


See also: - API Reference - Sprite - API Reference - SpriteAnimation - Manual - Basic Rendering

\ No newline at end of file +

Troubleshooting

Sprites Not Displaying

  • Check sprite data is valid
  • Verify width/height match data
  • Ensure sprite is within screen bounds
  • Check render layer is correct

Animation Not Playing

  • Verify animation frames are set
  • Check step() is being called
  • Ensure timer logic is correct
  • Verify frame count matches array size

Memory Issues

  • Reduce sprite count
  • Use 1bpp instead of 2bpp/4bpp
  • Reuse sprites more
  • Check available flash memory

Next Steps

Now that you understand sprites and animation, learn about: - Color Palettes - Use different color schemes - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles


See also: - API Reference - Sprite - API Reference - SpriteAnimation - Manual - Basic Rendering

\ No newline at end of file diff --git a/site/manual/advanced_graphics/tilemaps/index.html b/site/manual/advanced_graphics/tilemaps/index.html index 5c6a369..68c37bb 100644 --- a/site/manual/advanced_graphics/tilemaps/index.html +++ b/site/manual/advanced_graphics/tilemaps/index.html @@ -1,4 +1,4 @@ - Tilemaps - PixelRoot32 Documentation
Skip to content

Tilemaps

Tilemaps allow you to build levels efficiently by reusing small tile sprites. This guide covers creating tilemaps, rendering them, and using them with scrolling cameras.

What are Tilemaps?

A tilemap is a 2D grid where each cell references a tile sprite. Instead of placing individual sprites, you define which tile appears at each grid position.

Advantages: - Memory efficient: Reuse tile sprites many times - Easy level design: Edit level data, not code - Fast rendering: Optimized tilemap drawing - Large levels: Create levels bigger than screen - Multiple Bit-Depths: Support for 1bpp, 2bpp, and 4bpp tilemaps for higher graphical fidelity

Creating a Tilemap

1. Define Tiles

First, create the tile sprites you'll reuse. You can use standard 1bpp sprites or multi-bpp sprites (2bpp/4bpp) if enabled.

1bpp Tiles Example

#include <graphics/Renderer.h>
+ Tilemaps - PixelRoot32 Documentation      

Tilemaps

Tilemaps allow you to build levels efficiently by reusing small tile sprites. This guide covers creating tilemaps, rendering them, and using them with scrolling cameras.

What are Tilemaps?

A tilemap is a 2D grid where each cell references a tile sprite. Instead of placing individual sprites, you define which tile appears at each grid position.

Advantages: - Memory efficient: Reuse tile sprites many times - Easy level design: Edit level data, not code - Fast rendering: Optimized tilemap drawing - Large levels: Create levels bigger than screen - Multiple Bit-Depths: Support for 1bpp, 2bpp, and 4bpp tilemaps for higher graphical fidelity

Creating a Tilemap

1. Define Tiles

First, create the tile sprites you'll reuse. You can use standard 1bpp sprites or multi-bpp sprites (2bpp/4bpp) if enabled.

1bpp Tiles Example

#include <graphics/Renderer.h>
 
 // Ground tile (solid)
 static const uint16_t TILE_GROUND_BITS[] = {
@@ -297,4 +297,4 @@
 
     return false; // No collision
 }
-

Troubleshooting

Tiles Not Appearing

  • Verify tile indices are correct (0 = first tile, 1 = second, etc.)
  • Check tilemap dimensions match indices array size
  • Ensure tiles array has enough entries
  • Verify tile size matches sprite size

Performance Issues

  • Reduce tilemap size
  • Use smaller tiles
  • Limit number of unique tiles
  • Test viewport culling

Scrolling Problems

  • Ensure camera is applied before drawing tilemap
  • Check tilemap position matches camera offset
  • Verify tilemap boundaries are correct
  • Test with simple tilemap first

Next Steps

Now that you understand tilemaps, learn about: - Particles and Effects - Add visual effects - Cameras and Scrolling - Combine with scrolling - Performance Optimization - Optimize rendering


See also: - API Reference - TileMap - API Reference - Renderer - Manual - Cameras and Scrolling

\ No newline at end of file +

Troubleshooting

Tiles Not Appearing

  • Verify tile indices are correct (0 = first tile, 1 = second, etc.)
  • Check tilemap dimensions match indices array size
  • Ensure tiles array has enough entries
  • Verify tile size matches sprite size

Performance Issues

  • Reduce tilemap size
  • Use smaller tiles
  • Limit number of unique tiles
  • Test viewport culling

Scrolling Problems

  • Ensure camera is applied before drawing tilemap
  • Check tilemap position matches camera offset
  • Verify tilemap boundaries are correct
  • Test with simple tilemap first

Next Steps

Now that you understand tilemaps, learn about: - Particles and Effects - Add visual effects - Cameras and Scrolling - Combine with scrolling - Performance Optimization - Optimize rendering


See also: - API Reference - TileMap - API Reference - Renderer - Manual - Cameras and Scrolling

\ No newline at end of file diff --git a/site/manual/game_development/audio/index.html b/site/manual/game_development/audio/index.html index 9c89916..3e5fcd8 100644 --- a/site/manual/game_development/audio/index.html +++ b/site/manual/game_development/audio/index.html @@ -1,4 +1,4 @@ - Audio - PixelRoot32 Documentation
Skip to content

Audio

PixelRoot32 includes a complete NES-like audio system with 4 channels for sound effects and background music. This guide shows you how to add sound and music to your games.

Audio Configuration

Before using audio, you need to configure an AudioBackend. This is done when creating the Engine:

ESP32: Internal DAC

#include <drivers/esp32/ESP32_DAC_AudioBackend.h>
+ Audio - PixelRoot32 Documentation      

Audio

PixelRoot32 includes a complete NES-like audio system with 4 channels for sound effects and background music. This guide shows you how to add sound and music to your games.

Audio Configuration

Before using audio, you need to configure an AudioBackend. This is done when creating the Engine:

ESP32: Internal DAC

#include <drivers/esp32/ESP32_DAC_AudioBackend.h>
 
 const int DAC_PIN = 25; // GPIO 25 or 26
 pr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);
@@ -234,4 +234,4 @@
         Scene::update(deltaTime);
     }
 };
-

Troubleshooting

No Sound

  • Check audio backend is configured correctly
  • Verify sample rate matches backend
  • Check master volume is not 0
  • Ensure audio is initialized (engine.init())

Distorted Sound

  • Lower volume levels
  • Reduce sample rate (ESP32 DAC works better at 11025 Hz)
  • Check for too many simultaneous sounds
  • Verify hardware connections (ESP32)

Music Not Playing

  • Check music.isPlaying() status
  • Ensure track is properly defined
  • Verify MusicPlayer is updated (happens automatically)
  • Check that music channel is not being used by SFX

Next Steps

Now that you can add audio, learn about: - NES Audio Reference - Advanced audio techniques - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs


See also: - API Reference - AudioEngine - API Reference - MusicPlayer - API Reference - Audio Types - Manual - Audio Overview

\ No newline at end of file +

Troubleshooting

No Sound

  • Check audio backend is configured correctly
  • Verify sample rate matches backend
  • Check master volume is not 0
  • Ensure audio is initialized (engine.init())

Distorted Sound

  • Lower volume levels
  • Reduce sample rate (ESP32 DAC works better at 11025 Hz)
  • Check for too many simultaneous sounds
  • Verify hardware connections (ESP32)

Music Not Playing

  • Check music.isPlaying() status
  • Ensure track is properly defined
  • Verify MusicPlayer is updated (happens automatically)
  • Check that music channel is not being used by SFX

Next Steps

Now that you can add audio, learn about: - NES Audio Reference - Advanced audio techniques - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs


See also: - API Reference - AudioEngine - API Reference - MusicPlayer - API Reference - Audio Types - Manual - Audio Overview

\ No newline at end of file diff --git a/site/manual/game_development/basic_rendering/index.html b/site/manual/game_development/basic_rendering/index.html index e468a2f..bca2a18 100644 --- a/site/manual/game_development/basic_rendering/index.html +++ b/site/manual/game_development/basic_rendering/index.html @@ -1,8 +1,9 @@ - Basic Rendering - PixelRoot32 Documentation
Skip to content

Basic Rendering

Rendering is how you draw everything on screen. This guide covers the fundamental drawing operations in PixelRoot32: primitives, sprites, and text.

Accessing the Renderer

You can access the renderer in two ways:

From the Engine

auto& renderer = engine.getRenderer();
+ Basic Rendering - PixelRoot32 Documentation      

Basic Rendering

Rendering is how you draw everything on screen. This guide covers the fundamental drawing operations in PixelRoot32: primitives, sprites, and text.

Accessing the Renderer

You can access the renderer in two ways:

From the Engine

auto& renderer = engine.getRenderer();
 

From a Scene

void MyScene::draw(pixelroot32::graphics::Renderer& renderer) override {
     // renderer is passed as parameter
-    renderer.drawFilledRectangle(0, 0, 240, 240, Color::Black);
-}
+    // Drawing covers the entire logical screen (e.g., 128x128)
+    renderer.drawFilledRectangle(0, 0, renderer.getLogicalWidth(), renderer.getLogicalHeight(), Color::Black);
+}
 

Drawing Primitives

Pixels

Draw a single pixel:

renderer.drawPixel(100, 100, pixelroot32::graphics::Color::White);
 

Lines

Draw a line between two points:

renderer.drawLine(10, 10, 200, 200, pixelroot32::graphics::Color::Red);
 

Rectangles

Draw a rectangle outline:

renderer.drawRectangle(50, 50, 100, 80, pixelroot32::graphics::Color::Blue);
@@ -140,4 +141,4 @@
         renderer.drawSprite(sprite, x, startY, Color::White);
     }
 }
-

Next Steps

Now that you can draw basic graphics, learn about: - Sprites and Animation - Advanced sprite techniques - Input and Control - Make your game interactive - Palettes - Use different color schemes


See also: - API Reference - Renderer - API Reference - Sprite - Render Layers

\ No newline at end of file +

Next Steps

Now that you can draw basic graphics, learn about: - Sprites and Animation - Advanced sprite techniques - Input and Control - Make your game interactive - Palettes - Use different color schemes


See also: - API Reference - Renderer - API Reference - Sprite - Render Layers

\ No newline at end of file diff --git a/site/manual/game_development/input_and_control/index.html b/site/manual/game_development/input_and_control/index.html index 35ddf8e..b75d7d1 100644 --- a/site/manual/game_development/input_and_control/index.html +++ b/site/manual/game_development/input_and_control/index.html @@ -1,4 +1,4 @@ - Input and Control - PixelRoot32 Documentation
Skip to content

Input and Control

Handling user input is essential for any interactive game. This guide covers how to read and process input from buttons (ESP32) or keyboard (Native) in PixelRoot32.

Input Configuration

Before you can read input, you need to configure the InputManager. This is done when creating the Engine:

ESP32 Configuration

#include <input/InputConfig.h>
+ Input and Control - PixelRoot32 Documentation      

Input and Control

Handling user input is essential for any interactive game. This guide covers how to read and process input from buttons (ESP32) or keyboard (Native) in PixelRoot32.

Input Configuration

Before you can read input, you need to configure the InputManager. This is done when creating the Engine:

ESP32 Configuration

#include <input/InputConfig.h>
 
 // InputConfig(buttonCount, UP, DOWN, LEFT, RIGHT, A, B)
 pr32::input::InputConfig inputConfig(
@@ -258,4 +258,4 @@
     if (input.isButtonReleased(button)) return InputState::RELEASED;
     return InputState::IDLE;
 }
-

Troubleshooting

Button Not Responding

  • Check button indices match your InputConfig
  • Verify GPIO pins (ESP32) or scancodes (Native) are correct
  • Ensure InputManager is being updated (happens automatically in Engine)

Input Feels Laggy

  • Ensure you're using deltaTime for movement
  • Check that input is read in update(), not draw()
  • Verify framerate is stable

Multiple Triggers

  • Use isButtonPressed() instead of isButtonDown() for one-time actions
  • Implement input buffering or cooldown timers

Next Steps

Now that you can handle input, learn about: - Audio - Add sound effects and music - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs


See also: - API Reference - InputManager - API Reference - InputConfig - Manual - Input Overview

\ No newline at end of file +

Troubleshooting

Button Not Responding

  • Check button indices match your InputConfig
  • Verify GPIO pins (ESP32) or scancodes (Native) are correct
  • Ensure InputManager is being updated (happens automatically in Engine)

Input Feels Laggy

  • Ensure you're using deltaTime for movement
  • Check that input is read in update(), not draw()
  • Verify framerate is stable

Multiple Triggers

  • Use isButtonPressed() instead of isButtonDown() for one-time actions
  • Implement input buffering or cooldown timers

Next Steps

Now that you can handle input, learn about: - Audio - Add sound effects and music - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs


See also: - API Reference - InputManager - API Reference - InputConfig - Manual - Input Overview

\ No newline at end of file diff --git a/site/manual/game_development/physics_and_collisions/index.html b/site/manual/game_development/physics_and_collisions/index.html index 32d1a15..cd87c1d 100644 --- a/site/manual/game_development/physics_and_collisions/index.html +++ b/site/manual/game_development/physics_and_collisions/index.html @@ -1,4 +1,4 @@ - Physics and Collisions - PixelRoot32 Documentation
Skip to content

Physics and Collisions

PixelRoot32 provides a physics system for moving objects and collision detection. This guide covers PhysicsActor for automatic physics and the collision system for detecting interactions between objects.

PhysicsActor

A PhysicsActor is an Actor that automatically handles physics: velocity, gravity, friction, and world boundary collisions.

Creating a PhysicsActor

#include <core/PhysicsActor.h>
+ Physics and Collisions - PixelRoot32 Documentation      

Physics and Collisions

PixelRoot32 provides a physics system for moving objects and collision detection. This guide covers PhysicsActor for automatic physics and the collision system for detecting interactions between objects.

PhysicsActor

A PhysicsActor is an Actor that automatically handles physics: velocity, gravity, friction, and world boundary collisions.

Creating a PhysicsActor

#include <core/PhysicsActor.h>
 
 class Ball : public pixelroot32::core::PhysicsActor {
 public:
@@ -323,4 +323,4 @@
         }
     }
 }
-

Troubleshooting

Collisions Not Detected

  • Verify collision layers and masks overlap
  • Check that actors are added to the scene
  • Ensure Scene::update() is called
  • Verify hitboxes are correct

Physics Too Fast/Slow

  • Adjust values based on deltaTime
  • Check gravity and velocity values
  • Test on actual hardware (ESP32 may run slower)

Objects Passing Through

  • Use sweep tests for fast objects
  • Increase collision detection frequency
  • Check hitbox sizes match visual size

Next Steps

Now that you understand physics and collisions, learn about: - User Interface - Create menus and HUDs - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels


See also: - API Reference - PhysicsActor - API Reference - CollisionSystem - Manual - Physics Overview - Manual - Collision Detection

\ No newline at end of file +

Troubleshooting

Collisions Not Detected

  • Verify collision layers and masks overlap
  • Check that actors are added to the scene
  • Ensure Scene::update() is called
  • Verify hitboxes are correct

Physics Too Fast/Slow

  • Adjust values based on deltaTime
  • Check gravity and velocity values
  • Test on actual hardware (ESP32 may run slower)

Objects Passing Through

  • Use sweep tests for fast objects
  • Increase collision detection frequency
  • Check hitbox sizes match visual size

Next Steps

Now that you understand physics and collisions, learn about: - User Interface - Create menus and HUDs - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels


See also: - API Reference - PhysicsActor - API Reference - CollisionSystem - Manual - Physics Overview - Manual - Collision Detection

\ No newline at end of file diff --git a/site/manual/game_development/scenes_and_entities/index.html b/site/manual/game_development/scenes_and_entities/index.html index dc11d02..1c97f3c 100644 --- a/site/manual/game_development/scenes_and_entities/index.html +++ b/site/manual/game_development/scenes_and_entities/index.html @@ -1,4 +1,4 @@ - Scenes and Entities - PixelRoot32 Documentation
Skip to content

Scenes and Entities

Scenes and entities are the foundation of every PixelRoot32 game. This guide teaches you how to organize your game using scenes and create interactive game objects with entities.

Creating a Scene

A Scene represents a screen or level in your game. To create a scene, inherit from pixelroot32::core::Scene and implement the three main methods:

#include <core/Scene.h>
+ Scenes and Entities - PixelRoot32 Documentation      

Scenes and Entities

Scenes and entities are the foundation of every PixelRoot32 game. This guide teaches you how to organize your game using scenes and create interactive game objects with entities.

Creating a Scene

A Scene represents a screen or level in your game. To create a scene, inherit from pixelroot32::core::Scene and implement the three main methods:

#include <core/Scene.h>
 #include <graphics/Renderer.h>
 
 class MyGameScene : public pixelroot32::core::Scene {
@@ -254,4 +254,4 @@
         // ...
     }
 }
-

Next Steps

Now that you understand scenes and entities, learn about: - Basic Rendering - Draw sprites, text, and primitives - Input and Control - Handle user input - Physics and Collisions - Advanced collision handling


See also: - Fundamental Concepts - API Reference - Scene - API Reference - Entity - API Reference - Actor

\ No newline at end of file +

Next Steps

Now that you understand scenes and entities, learn about: - Basic Rendering - Draw sprites, text, and primitives - Input and Control - Handle user input - Physics and Collisions - Advanced collision handling


See also: - Fundamental Concepts - API Reference - Scene - API Reference - Entity - API Reference - Actor

\ No newline at end of file diff --git a/site/manual/game_development/user_interface/index.html b/site/manual/game_development/user_interface/index.html index 7417235..cfa5ca0 100644 --- a/site/manual/game_development/user_interface/index.html +++ b/site/manual/game_development/user_interface/index.html @@ -1,4 +1,4 @@ - User Interface - PixelRoot32 Documentation
Skip to content

User Interface

PixelRoot32 provides a complete UI system for creating menus, HUDs, and interface elements. This guide covers all UI components and layout systems.

UI Elements

All UI elements inherit from UIElement, which itself inherits from Entity. This means UI elements can be added to scenes just like any other entity.

UILabel

Display text on screen:

#include <graphics/ui/UILabel.h>
+ User Interface - PixelRoot32 Documentation      

User Interface

PixelRoot32 provides a complete UI system for creating menus, HUDs, and interface elements. This guide covers all UI components and layout systems.

UI Elements

All UI elements inherit from UIElement, which itself inherits from Entity. This means UI elements can be added to scenes just like any other entity.

UILabel

Display text on screen:

#include <graphics/ui/UILabel.h>
 
 // Create a label
 pixelroot32::graphics::ui::UILabel* scoreLabel = new pixelroot32::graphics::ui::UILabel(
@@ -389,4 +389,4 @@
     snprintf(buffer, sizeof(buffer), "Health: %d%%", health);
     healthLabel->setText(buffer);
 }
-

Next Steps

Now that you understand the UI system, you've completed the core game development topics. Continue with: - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels - Performance Tuning - Improve performance


See also: - API Reference - UIElement - API Reference - UIButton - API Reference - UI Layouts - Manual - UI Overview

\ No newline at end of file +

Next Steps

Now that you understand the UI system, you've completed the core game development topics. Continue with: - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels - Performance Tuning - Improve performance


See also: - API Reference - UIElement - API Reference - UIButton - API Reference - UI Layouts - Manual - UI Overview

\ No newline at end of file diff --git a/site/manual/optimization/extensibility/index.html b/site/manual/optimization/extensibility/index.html index 55dfa82..b9e9e51 100644 --- a/site/manual/optimization/extensibility/index.html +++ b/site/manual/optimization/extensibility/index.html @@ -1,4 +1,4 @@ - Extensibility - PixelRoot32 Documentation
Skip to content

Extensibility

PixelRoot32 is designed to be extensible. This guide covers how to create custom drivers, audio backends, and extend existing systems.

Creating Custom Display Drivers

To support a new display, implement the DrawSurface interface.

DrawSurface Interface

#include <graphics/DrawSurface.h>
+ Extensibility - PixelRoot32 Documentation      

Extensibility

PixelRoot32 is designed to be extensible. This guide covers how to create custom drivers, audio backends, and extend existing systems.

Creating Custom Display Drivers

To support a new display, implement the DrawSurface interface.

DrawSurface Interface

#include <graphics/DrawSurface.h>
 
 class MyCustomDrawer : public pixelroot32::graphics::DrawSurface {
 public:
@@ -348,4 +348,4 @@
         }
     }
 };
-

Troubleshooting

Driver Not Working

  • Verify all interface methods are implemented
  • Check initialization order
  • Test with simple drawing first
  • Verify hardware connections

Audio Backend Issues

  • Check sample rate matches hardware
  • Verify audio generation logic
  • Test with simple tones first
  • Check channel management

Extension Conflicts

  • Ensure namespace isolation
  • Avoid modifying engine code directly
  • Use composition over modification
  • Test with engine updates

Next Steps

Now that you understand extensibility, you've completed the optimization section. Continue with: - API Reference - Complete API documentation - Examples - Code examples - Resources - Tools and troubleshooting


See also: - API Reference - DrawSurface - API Reference - AudioBackend - Manual - Platforms and Drivers

\ No newline at end of file +

Troubleshooting

Driver Not Working

  • Verify all interface methods are implemented
  • Check initialization order
  • Test with simple drawing first
  • Verify hardware connections

Audio Backend Issues

  • Check sample rate matches hardware
  • Verify audio generation logic
  • Test with simple tones first
  • Check channel management

Extension Conflicts

  • Ensure namespace isolation
  • Avoid modifying engine code directly
  • Use composition over modification
  • Test with engine updates

Next Steps

Now that you understand extensibility, you've completed the optimization section. Continue with: - API Reference - Complete API documentation - Examples - Code examples - Resources - Tools and troubleshooting


See also: - API Reference - DrawSurface - API Reference - AudioBackend - Manual - Platforms and Drivers

\ No newline at end of file diff --git a/site/manual/optimization/memory_management/index.html b/site/manual/optimization/memory_management/index.html index 0623234..b711b79 100644 --- a/site/manual/optimization/memory_management/index.html +++ b/site/manual/optimization/memory_management/index.html @@ -1,4 +1,4 @@ - Memory Management - PixelRoot32 Documentation
Skip to content

Memory Management

ESP32 has limited memory, so efficient memory management is crucial for PixelRoot32 games. This guide covers memory constraints, object pooling, and best practices.

ESP32 Memory Constraints

Available Memory

ESP32 typically has: - RAM: ~320KB total (varies by model) - Flash: 4MB+ (for program storage) - Heap: Limited and fragmented over time

Real-World Limits

  • MAX_ENTITIES: 32 per scene (hard limit)
  • Sprite data: Stored in flash (const/constexpr)
  • Dynamic allocation: Should be avoided in game loop
  • Stack: Limited (~8KB), avoid large stack allocations

Object Pooling

Object pooling reuses objects instead of creating/destroying them, avoiding memory fragmentation.

Basic Pool Pattern

class ProjectilePool {
+ Memory Management - PixelRoot32 Documentation      

Memory Management

ESP32 has limited memory, so efficient memory management is crucial for PixelRoot32 games. This guide covers memory constraints, object pooling, and best practices.

ESP32 Memory Constraints

Available Memory

ESP32 typically has: - RAM: ~320KB total (varies by model) - Flash: 4MB+ (for program storage) - Heap: Limited and fragmented over time

Real-World Limits

  • MAX_ENTITIES: 32 per scene (hard limit)
  • Sprite data: Stored in flash (const/constexpr)
  • Dynamic allocation: Should be avoided in game loop
  • Stack: Limited (~8KB), avoid large stack allocations

Object Pooling

Object pooling reuses objects instead of creating/destroying them, avoiding memory fragmentation.

Basic Pool Pattern

class ProjectilePool {
 private:
     static const int POOL_SIZE = 10;
     ProjectileActor pool[POOL_SIZE];
@@ -294,4 +294,4 @@
     int size() const { return count; }
     pixelroot32::core::Entity* operator[](int index) { return entities[index]; }
 };
-

Troubleshooting

Out of Memory Errors

  • Reduce pool sizes
  • Use fewer entities
  • Store more data in flash
  • Avoid dynamic allocation
  • Check for memory leaks

Entity Limit Reached

  • MAX_ENTITIES = 32 is a hard limit
  • Use object pooling to reuse entities
  • Deactivate entities instead of removing
  • Combine multiple entities into one

Memory Fragmentation

  • Use object pooling
  • Pre-allocate all resources
  • Avoid frequent new/delete
  • Consider Scene Arena (experimental)

Next Steps

Now that you understand memory management, learn about: - Performance Optimization - Improve game performance - Platforms and Drivers - Understand platform specifics - Extensibility - Extend the engine


See also: - API Reference - Scene - Manual - Scenes and Entities

\ No newline at end of file +

Troubleshooting

Out of Memory Errors

  • Reduce pool sizes
  • Use fewer entities
  • Store more data in flash
  • Avoid dynamic allocation
  • Check for memory leaks

Entity Limit Reached

  • MAX_ENTITIES = 32 is a hard limit
  • Use object pooling to reuse entities
  • Deactivate entities instead of removing
  • Combine multiple entities into one

Memory Fragmentation

  • Use object pooling
  • Pre-allocate all resources
  • Avoid frequent new/delete
  • Consider Scene Arena (experimental)

Next Steps

Now that you understand memory management, learn about: - Performance Optimization - Improve game performance - Platforms and Drivers - Understand platform specifics - Extensibility - Extend the engine


See also: - API Reference - Scene - Manual - Scenes and Entities

\ No newline at end of file diff --git a/site/manual/optimization/performance_tuning/index.html b/site/manual/optimization/performance_tuning/index.html index 6a9349c..9402cd2 100644 --- a/site/manual/optimization/performance_tuning/index.html +++ b/site/manual/optimization/performance_tuning/index.html @@ -1,9 +1,9 @@ - Performance Tuning - PixelRoot32 Documentation
Skip to content

Performance Optimization

This guide covers techniques to improve game performance on ESP32, including rendering optimization, logic optimization, and profiling.

ESP32 Performance Characteristics

CPU Limitations

  • Dual-core: 240MHz (typically)
  • Single-threaded game loop: One core handles everything
  • Target FPS: 30-60 FPS (depends on game complexity)
  • Frame budget: ~16-33ms per frame at 60 FPS

Common Bottlenecks

  1. Rendering: Too many draw calls
  2. Collision detection: Too many collision checks
  3. Memory allocation: Dynamic allocation in game loop
  4. Complex calculations: Expensive math operations
  5. String operations: String concatenation/formatting

Técnicas de Optimización

El motor utiliza varias técnicas para maximizar los FPS, especialmente en hardware limitado como el ESP32.

1. Viewport Culling (Recorte de Cámara)

No proceses objetos que están fuera de la pantalla. El motor lo hace automáticamente en drawTileMap, pero debes implementarlo en tu lógica de actualización:

bool isOnScreen(float x, float y, int width, int height, 
+ Performance Tuning - PixelRoot32 Documentation      

Performance Optimization

This guide covers techniques to improve game performance on ESP32, including rendering optimization, logic optimization, and profiling.

ESP32 Performance Characteristics

CPU Limitations

  • Dual-core: 240MHz (typically)
  • Single-threaded game loop: One core handles everything
  • Target FPS: 30-60 FPS (depends on game complexity)
  • Frame budget: ~16-33ms per frame at 60 FPS

Common Bottlenecks

  1. Rendering: Too many draw calls
  2. Collision detection: Too many collision checks
  3. Memory allocation: Dynamic allocation in game loop
  4. Complex calculations: Expensive math operations
  5. String operations: String concatenation/formatting

Técnicas de Optimización

El motor utiliza varias técnicas para maximizar los FPS, especialmente en hardware limitado como el ESP32.

1. Independent Resolution Scaling (Escalado de Resolución)

Esta es probablemente la optimización más impactante para el ESP32. Permite renderizar el juego a una resolución lógica menor (ej: 128x128) y reescalarla automáticamente a la resolución física de la pantalla (ej: 240x240).

  • Reducción de Memoria: Un buffer de 128x128 (8bpp) consume solo 16KB, comparado con los 57KB de uno de 240x240.
  • Aumento de FPS: Al haber menos píxeles que procesar por cada primitiva o sprite, el rendimiento puede duplicarse.
  • Implementación: Se realiza mediante Hardware-accelerated Nearest Neighbor durante la transferencia DMA.

Consulta la guía completa de Resolution Scaling para aprender a configurarlo.

2. Viewport Culling (Recorte de Cámara)

No proceses objetos que están fuera de la pantalla. El motor lo hace automáticamente en drawTileMap, pero debes implementarlo en tu lógica de actualización:

bool isOnScreen(float x, float y, int width, int height, 
                 const Camera2D& camera) {
     float cameraX = camera.getX();
     float cameraY = camera.getY();
-    int screenWidth = engine.getRenderer().getWidth();
-    int screenHeight = engine.getRenderer().getHeight();
+    int screenWidth = engine.getRenderer().getLogicalWidth();
+    int screenHeight = engine.getRenderer().getLogicalHeight();
 
     return !(x + width < cameraX || 
              x > cameraX + screenWidth ||
@@ -16,7 +16,7 @@
 if (levelMap.data[tileY * levelMap.width + tileX] != 0) {
     // Colisión detectada
 }
-

Recomendaciones Generales

  • Sprites Indexados: Prefiere Sprite2bpp (4 colores) o Sprite4bpp (16 colores) sobre Sprite (1bpp) si necesitas color, ya que están altamente optimizados.
  • Evitar std::string en el Loop: Las concatenaciones de strings generan fragmentación de memoria. Usa buffers estáticos o char[] para textos dinámicos.
  • Perfilado: Activa el overlay de FPS compilando con PIXELROOT32_ENABLE_FPS_DISPLAY (ver Engine - FPS overlay) para monitorear el impacto de tus cambios en tiempo real.

Common Optimization Patterns

Update Frequency Reduction

class LowFrequencyUpdater {
+

Recomendaciones Generales

  • Sprites Indexados: Prefiere Sprite2bpp (4 colores) o Sprite4bpp (16 colores) sobre Sprite (1bpp) si necesitas color, ya que están altamente optimizados.
  • Evitar std::string en el Loop: Las concatenaciones de strings generan fragmentación de memoria. Usa buffers estáticos o char[] para textos dinámicos.
  • Perfilado: Activa el overlay de estadísticas de depuración compilando con PIXELROOT32_ENABLE_DEBUG_OVERLAY (ver Engine - Debug Overlay) para monitorear FPS, RAM y carga de CPU en tiempo real.

Common Optimization Patterns

Update Frequency Reduction

class LowFrequencyUpdater {
 private:
     unsigned long timer = 0;
     unsigned long interval = 100; // Update every 100ms
@@ -64,4 +64,4 @@
         }
     }
 };
-

Troubleshooting

Low FPS

  • Profile to find bottlenecks
  • Reduce entity count
  • Optimize rendering (culling, batching)
  • Simplify collision detection
  • Reduce update frequency

Frame Drops

  • Check for expensive operations in update()
  • Avoid dynamic allocation
  • Cache calculations
  • Reduce draw calls

Stuttering

  • Ensure frame-rate independence (use deltaTime)
  • Avoid blocking operations
  • Pre-load resources
  • Use object pooling

Next Steps

Now that you understand performance optimization, learn about: - Memory Management - Manage memory efficiently - Platforms and Drivers - Platform-specific optimizations - Extensibility - Extend the engine


See also: - Manual - Basic Rendering - Manual - Physics and Collisions

\ No newline at end of file +

Troubleshooting

Low FPS

  • Profile to find bottlenecks
  • Reduce entity count
  • Optimize rendering (culling, batching)
  • Simplify collision detection
  • Reduce update frequency

Frame Drops

  • Check for expensive operations in update()
  • Avoid dynamic allocation
  • Cache calculations
  • Reduce draw calls

Stuttering

  • Ensure frame-rate independence (use deltaTime)
  • Avoid blocking operations
  • Pre-load resources
  • Use object pooling

Next Steps

Now that you understand performance optimization, learn about: - Memory Management - Manage memory efficiently - Platforms and Drivers - Platform-specific optimizations - Extensibility - Extend the engine


See also: - Manual - Basic Rendering - Manual - Physics and Collisions

\ No newline at end of file diff --git a/site/manual/optimization/platforms_and_drivers/index.html b/site/manual/optimization/platforms_and_drivers/index.html index 1d1bf25..f57bac0 100644 --- a/site/manual/optimization/platforms_and_drivers/index.html +++ b/site/manual/optimization/platforms_and_drivers/index.html @@ -1,4 +1,4 @@ - Platforms and Drivers - PixelRoot32 Documentation
Skip to content

Platforms and Drivers

PixelRoot32 supports multiple platforms through driver abstraction. This guide covers supported platforms, display drivers, audio backends, and build configuration.

Supported Platforms

ESP32

Primary platform for PixelRoot32 games.

Characteristics: - TFT_eSPI display driver - Internal DAC or I2S audio - GPIO button input - Limited RAM/Flash - Real hardware constraints

Use for: - Final game deployment - Hardware testing - Production builds

Native/Desktop (SDL2)

Development platform for rapid iteration.

Characteristics: - SDL2 display driver - SDL2 audio backend - Keyboard input - Unlimited resources (for testing) - Fast development cycle

Use for: - Development and debugging - Testing without hardware - Rapid prototyping - CI/CD testing

Display Drivers

TFT_eSPI (ESP32)

TFT_eSPI is the display driver for ESP32, supporting many TFT displays.

Optimizaciones ESP32

Para maximizar el rendimiento en ESP32, PixelRoot32 utiliza:

  • DMA (Direct Memory Access): Las transferencias al display se realizan en segundo plano, permitiendo que la CPU prepare el siguiente frame mientras se envía el actual.
  • Doble Buffer con IRAM: El motor utiliza un buffer de pantalla (Sprite de TFT_eSPI) optimizado para transferencias rápidas.
  • Alineación de 16 bits: Los datos de sprites 2bpp/4bpp están alineados a palabras de 16 bits para aprovechar la arquitectura Xtensa.
  • IRAM_ATTR: Las funciones críticas de renderizado están marcadas para residir en la RAM de instrucciones, evitando cuellos de botella por acceso a la Flash.

Configuración DMA

El DMA se activa automáticamente si el hardware lo soporta. Asegúrate de configurar la frecuencia SPI adecuada para tu display (usualmente 40MHz u 80MHz).

[env:esp32dev]
+ Platforms and Drivers - PixelRoot32 Documentation      

Platforms and Drivers

PixelRoot32 supports multiple platforms through driver abstraction. This guide covers supported platforms, display drivers, audio backends, and build configuration.

Supported Platforms

ESP32

Primary platform for PixelRoot32 games.

Characteristics: - TFT_eSPI display driver - Internal DAC or I2S audio - GPIO button input - Limited RAM/Flash - Real hardware constraints

Use for: - Final game deployment - Hardware testing - Production builds

Native/Desktop (SDL2)

Development platform for rapid iteration.

Characteristics: - SDL2 display driver - SDL2 audio backend - Keyboard input - Unlimited resources (for testing) - Fast development cycle

Use for: - Development and debugging - Testing without hardware - Rapid prototyping - CI/CD testing

Display Drivers

TFT_eSPI (ESP32)

TFT_eSPI is the display driver for ESP32, supporting many TFT displays.

Optimizaciones ESP32

Para maximizar el rendimiento en ESP32, PixelRoot32 utiliza:

  • DMA (Direct Memory Access): Las transferencias al display se realizan en segundo plano, permitiendo que la CPU prepare el siguiente frame mientras se envía el actual.
  • Independent Resolution Scaling: El driver soporta resoluciones lógicas menores que las físicas, realizando el escalado Nearest-Neighbor on-the-fly durante la transferencia DMA para ahorrar RAM y ganar FPS.
  • Doble Buffer con IRAM: El motor utiliza un buffer de pantalla (Sprite de TFT_eSPI) optimizado para transferencias rápidas.
  • Alineación de 16 bits: Los datos de sprites 2bpp/4bpp están alineados a palabras de 16 bits para aprovechar la arquitectura Xtensa.
  • IRAM_ATTR: Las funciones críticas de renderizado están marcadas para residir en la RAM de instrucciones, evitando cuellos de botella por acceso a la Flash.

Configuración DMA

El DMA se activa automáticamente si el hardware lo soporta. Asegúrate de configurar la frecuencia SPI adecuada para tu display (usualmente 40MHz u 80MHz).

[env:esp32dev]
 build_flags = 
     -D ST7789_DRIVER          # Display type
     -D TFT_WIDTH=240          # Display width
@@ -12,15 +12,16 @@
 

Supported Displays

  • ST7735: 128x128, 128x160
  • ST7789: 240x240, 240x320
  • ILI9341: 240x320
  • And more: See TFT_eSPI documentation

Usage

#include <drivers/esp32/TFT_eSPI_Drawer.h>
 
 // Display configuration
-pixelroot32::graphics::DisplayConfig displayConfig(
-    pixelroot32::graphics::DisplayType::ST7789,
-    0,      // rotation
-    240,    // width
-    240     // height
-);
-
-// TFT_eSPI_Drawer is created automatically by Engine
-// No manual driver creation needed
+// 128x128 logic scaled to 240x240 hardware
+pixelroot32::graphics::DisplayConfig displayConfig(
+    pixelroot32::graphics::DisplayType::ST7789,
+    0,      // rotation
+    240, 240, // physical width, height
+    128, 128  // logical width, height
+);
+
+// TFT_eSPI_Drawer is created automatically by Engine
+// No manual driver creation needed
 

SDL2_Drawer (Native)

SDL2_Drawer provides display output for PC/desktop development.

Configuration

#include <drivers/native/SDL2_Drawer.h>
 
 // Display configuration (NONE defaults to SDL2)
@@ -72,10 +73,10 @@
 

Build Flags

Experimental Features

Enable experimental features with build flags:

[env:esp32dev]
 build_flags = 
     -D PIXELROOT32_ENABLE_2BPP_SPRITES    # Enable 2bpp sprite format
-    -D PIXELROOT32_ENABLE_4BPP_SPRITES   # Enable 4bpp sprite format
-    -D PIXELROOT32_ENABLE_SCENE_ARENA    # Enable Scene Arena (experimental)
-    -D PIXELROOT32_ENABLE_FPS_DISPLAY    # On-screen FPS counter (green, top-right; value updated every 8 frames)
-

FPS overlay (PIXELROOT32_ENABLE_FPS_DISPLAY)

When defined, the engine draws an on-screen FPS counter (green text, top-right) each frame. The value is recalculated every 8 frames to keep per-frame cost low. No code changes are required; the overlay is drawn automatically after the scene. See API Reference - Engine - Optional: FPS overlay for details.

Scene limits (MAX_LAYERS / MAX_ENTITIES)

You can override the default scene limits from your project without modifying the engine. The default of 3 for MAX_LAYERS is due to ESP32 platform constraints (memory and draw-loop cost); on native/PC you can use a higher value.

Option A: Compiler flags (recommended) — in platformio.ini, add to build_flags for your environment:

build_flags =
+    - D PIXELROOT32_ENABLE_4BPP_SPRITES   # Enable 4bpp sprite format
+    - D PIXELROOT32_ENABLE_SCENE_ARENA    # Enable Scene Arena (experimental)
+    - D PIXELROOT32_ENABLE_DEBUG_OVERLAY  # On-screen debug statistics (FPS, RAM, CPU load; throttled update)
+

Debug Statistics Overlay (PIXELROOT32_ENABLE_DEBUG_OVERLAY)

When defined, the engine draws a technical overlay (FPS, RAM, CPU load) in the top-right area of the screen each frame. Values are updated every 16 frames to maintain performance. No code changes are required. See API Reference - Engine - Optional: Debug Overlay for details.

Scene limits (MAX_LAYERS / MAX_ENTITIES)

You can override the default scene limits from your project without modifying the engine. The default of 3 for MAX_LAYERS is due to ESP32 platform constraints (memory and draw-loop cost); on native/PC you can use a higher value.

Option A: Compiler flags (recommended) — in platformio.ini, add to build_flags for your environment:

build_flags =
     -DMAX_LAYERS=5
     -DMAX_ENTITIES=64
 

The compiler defines these before any .cpp is processed. Because Scene.h uses #ifndef MAX_LAYERS / #ifndef MAX_ENTITIES, your values are used (more render layers drawn in Scene::draw, and on Arduino the entity queue capacity when built with MAX_ENTITIES).

See API Reference - Scene - Overriding scene limits for details.

Platform Detection

#ifdef PLATFORM_ESP32
@@ -170,4 +171,4 @@
     engine.run();
     return 0;
 }
-

Platform-Specific Considerations

ESP32

Memory: - Limited RAM (~320KB) - Use object pooling - Store data in flash - Avoid dynamic allocation

Performance: - Target 30-60 FPS - Optimize rendering - Reduce entity count - Profile on hardware

Hardware: - GPIO pin configuration - SPI display setup - Audio hardware connections - Power considerations

Native

Development: - Fast iteration - Easy debugging - Unlimited resources - Visual debugging tools

Testing: - Test logic without hardware - Rapid prototyping - CI/CD integration - Cross-platform testing

Troubleshooting

ESP32 Display Issues

  • Check wiring connections
  • Verify pin numbers
  • Lower SPI frequency
  • Check display type matches
  • Verify power supply

ESP32 Audio Issues

  • Check DAC/I2S pin configuration
  • Verify sample rate
  • Check hardware connections
  • Lower volume if distorted
  • Test with different sample rates

Native Build Issues

  • Verify SDL2 installation
  • Check include/library paths
  • Ensure SDL2 version compatibility
  • Check linker flags

Next Steps

Now that you understand platforms and drivers, learn about: - Extensibility - Create custom drivers - Memory Management - ESP32 memory constraints - Performance Optimization - Platform-specific optimization


See also: - API Reference - DrawSurface - API Reference - AudioBackend - Getting Started - Your First Project

\ No newline at end of file +

Platform-Specific Considerations

ESP32

Memory: - Limited RAM (~320KB) - Use object pooling - Store data in flash - Avoid dynamic allocation

Performance: - Target 30-60 FPS - Optimize rendering - Reduce entity count - Profile on hardware

Hardware: - GPIO pin configuration - SPI display setup - Audio hardware connections - Power considerations

Native

Development: - Fast iteration - Easy debugging - Unlimited resources - Visual debugging tools

Testing: - Test logic without hardware - Rapid prototyping - CI/CD integration - Cross-platform testing

Troubleshooting

ESP32 Display Issues

  • Check wiring connections
  • Verify pin numbers
  • Lower SPI frequency
  • Check display type matches
  • Verify power supply

ESP32 Audio Issues

  • Check DAC/I2S pin configuration
  • Verify sample rate
  • Check hardware connections
  • Lower volume if distorted
  • Test with different sample rates

Native Build Issues

  • Verify SDL2 installation
  • Check include/library paths
  • Ensure SDL2 version compatibility
  • Check linker flags

Next Steps

Now that you understand platforms and drivers, learn about: - Extensibility - Create custom drivers - Memory Management - ESP32 memory constraints - Performance Optimization - Platform-specific optimization


See also: - API Reference - DrawSurface - API Reference - AudioBackend - Getting Started - Your First Project

\ No newline at end of file diff --git a/site/reference/api_overview/index.html b/site/reference/api_overview/index.html index 36a65dd..c8ee7ff 100644 --- a/site/reference/api_overview/index.html +++ b/site/reference/api_overview/index.html @@ -1,7 +1,7 @@ - API Overview - PixelRoot32 Documentation
Skip to content

API Reference Overview

This document provides a complete technical reference for all PixelRoot32 APIs, organized by module. Each class includes descriptions, constructors, methods, properties, and usage examples.

Organization

The API is organized into the following modules:

  • Core: Engine, Scene, Entity, Actor, PhysicsActor, SceneManager
  • Graphics: Renderer, Camera2D, Color, Font, Sprite, TileMap, DrawSurface
  • Audio: AudioEngine, MusicPlayer, AudioTypes, AudioConfig, AudioBackend
  • Input: InputManager, InputConfig
  • Physics: CollisionSystem, CollisionTypes
  • UI: UIElement, UIButton, UILabel, UILayouts
  • Particles: ParticleEmitter, ParticleConfig, ParticlePresets

Quick Navigation

Core Module

Graphics Module

Audio Module

Physics Module

UI Module

API Documentation Format

Each API reference page follows this structure:

Class Name

Brief description of the class and its purpose.

Namespace

namespace pixelroot32::module {
+ API Overview - PixelRoot32 Documentation      

API Reference Overview

This document provides a complete technical reference for all PixelRoot32 APIs, organized by module. Each class includes descriptions, constructors, methods, properties, and usage examples.

Organization

The API is organized into the following modules:

  • Core: Engine, Scene, Entity, Actor, PhysicsActor, SceneManager
  • Graphics: Renderer, Camera2D, Color, Font, Sprite, TileMap, DrawSurface
  • Audio: AudioEngine, MusicPlayer, AudioTypes, AudioConfig, AudioBackend
  • Input: InputManager, InputConfig
  • Physics: CollisionSystem, CollisionTypes
  • UI: UIElement, UIButton, UILabel, UILayouts
  • Particles: ParticleEmitter, ParticleConfig, ParticlePresets

Quick Navigation

Core Module

Graphics Module

Audio Module

Physics Module

UI Module

API Documentation Format

Each API reference page follows this structure:

Class Name

Brief description of the class and its purpose.

Namespace

namespace pixelroot32::module {
     class ClassName {
         // ...
     };
 }
 

Constructors

List of all constructors with parameters.

Public Methods

Method Description Parameters Returns
methodName() Description param: type return type

Properties

Property Type Description
property type Description

Usage Example

// Example code showing typical usage
-

Performance Notes

Any performance considerations or limitations.

See Also

Links to related APIs and documentation.

Finding APIs

By Functionality

By Module

Navigate to the specific module folder: - api_reference/core/ - Core engine classes - api_reference/graphics/ - Rendering and graphics - api_reference/audio/ - Audio system - api_reference/physics/ - Physics and collisions - api_reference/ui/ - User interface

Complete API List

Core

Graphics

Audio

Physics

UI


Note: This is an overview. For detailed API documentation, see the individual reference pages linked above.

\ No newline at end of file +

Performance Notes

Any performance considerations or limitations.

See Also

Links to related APIs and documentation.

Finding APIs

By Functionality

By Module

Navigate to the specific module folder: - api_reference/core/ - Core engine classes - api_reference/graphics/ - Rendering and graphics - api_reference/audio/ - Audio system - api_reference/physics/ - Physics and collisions - api_reference/ui/ - User interface

Complete API List

Core

Graphics

Audio

Physics

UI


Note: This is an overview. For detailed API documentation, see the individual reference pages linked above.

\ No newline at end of file diff --git a/site/reference/code_examples/index.html b/site/reference/code_examples/index.html index 98017ba..1085910 100644 --- a/site/reference/code_examples/index.html +++ b/site/reference/code_examples/index.html @@ -1,4 +1,4 @@ - Code Examples - PixelRoot32 Documentation
Skip to content

Code Examples

A library of reusable code snippets for common PixelRoot32 tasks. All examples are complete and functional.

Initialization

Basic Engine Setup (ESP32)

#include <Arduino.h>
+ Code Examples - PixelRoot32 Documentation      

Code Examples

A library of reusable code snippets for common PixelRoot32 tasks. All examples are complete and functional.

Initialization

Basic Engine Setup (ESP32)

#include <Arduino.h>
 #include <core/Engine.h>
 #include <drivers/esp32/TFT_eSPI_Drawer.h>
 #include <drivers/esp32/ESP32_DAC_AudioBackend.h>
@@ -605,4 +605,4 @@
     bool isActive() const { return active; }
     float getProgress() const { return static_cast<float>(elapsed) / duration; }
 };
-

See Also

\ No newline at end of file +

See Also

\ No newline at end of file diff --git a/site/reference/game_examples_guide/index.html b/site/reference/game_examples_guide/index.html index e04a47c..fe60544 100644 --- a/site/reference/game_examples_guide/index.html +++ b/site/reference/game_examples_guide/index.html @@ -1,4 +1,4 @@ - Game Examples Guide - PixelRoot32 Documentation
Skip to content

Game Examples Guide

This guide analyzes the complete game examples included with PixelRoot32, explaining their architecture, patterns, and lessons learned.

Available Examples

PixelRoot32 (in the PixelRoot32 Game Samples project) includes these games and demos:

  • Metroidvania: 2D platformer with multi-layer 4bpp tilemap and tile-based collision (requires PIXELROOT32_ENABLE_4BPP_SPRITES; no scroll/camera)
  • Space Invaders: Full shooter with enemies, projectiles, bunkers and audio
  • Pong: Classic with physics and collisions
  • BrickBreaker: Breakout-style with particles and advanced audio
  • Snake: Grid-based game with entity pooling
  • TicTacToe: Turn-based with simple AI
  • CameraDemo: Platformer with camera and parallax
  • SpritesDemo: 2bpp and 4bpp sprites
  • TileMapDemo: 4bpp tilemaps (with viewport culling)

Space Invaders

Location: src/examples/SpaceInvaders/

Architecture

Space Invaders demonstrates a complete game with multiple systems:

  • Scene Management: SpaceInvadersScene manages game state
  • Actor Hierarchy: PlayerActor, AlienActor, ProjectileActor, BunkerActor
  • Collision System: Uses collision layers for player, enemies, projectiles
  • Audio Integration: Sound effects for shooting, explosions, music
  • Background: Starfield (code-generated star pattern) or tilemap

Key Systems

Collision Layers

namespace Layers {
+ Game Examples Guide - PixelRoot32 Documentation      

Game Examples Guide

This guide analyzes the complete game examples included with PixelRoot32, explaining their architecture, patterns, and lessons learned.

Available Examples

PixelRoot32 (in the PixelRoot32 Game Samples project) includes these games and demos:

  • Metroidvania: 2D platformer with multi-layer 4bpp tilemap and tile-based collision (requires PIXELROOT32_ENABLE_4BPP_SPRITES; no scroll/camera)
  • Space Invaders: Full shooter with enemies, projectiles, bunkers and audio
  • Pong: Classic with physics and collisions
  • BrickBreaker: Breakout-style with particles and advanced audio
  • Snake: Grid-based game with entity pooling
  • TicTacToe: Turn-based with simple AI
  • CameraDemo: Platformer with camera and parallax
  • SpritesDemo: 2bpp and 4bpp sprites
  • TileMapDemo: 4bpp tilemaps (with viewport culling)

Space Invaders

Location: src/examples/SpaceInvaders/

Architecture

Space Invaders demonstrates a complete game with multiple systems:

  • Scene Management: SpaceInvadersScene manages game state
  • Actor Hierarchy: PlayerActor, AlienActor, ProjectileActor, BunkerActor
  • Collision System: Uses collision layers for player, enemies, projectiles
  • Audio Integration: Sound effects for shooting, explosions, music
  • Background: Starfield (code-generated star pattern) or tilemap

Key Systems

Collision Layers

namespace Layers {
     constexpr uint16_t PLAYER = 0x0001;
     constexpr uint16_t ALIEN = 0x0002;
     constexpr uint16_t PROJECTILE = 0x0004;
@@ -171,4 +171,4 @@
     // 4. Draw UI/HUD
     drawHUD(renderer);
 }
-

Learning Path

Beginner Examples

  1. Pong: Basic physics and collisions
  2. TicTacToe: Turn-based logic
  3. Snake: Entity pooling and grid

Intermediate Examples

  1. CameraDemo: Camera and parallax
  2. SpritesDemo: 2bpp and 4bpp formats
  3. BrickBreaker: Physics, particles and audio

Advanced Examples

  1. Space Invaders: Full game (1bpp sprites, collisions, audio)
  2. Metroidvania: Platformer with multi-layer 4bpp tilemap, tile-based collision and ESP32 optimizations (no scroll/camera)

Code Study Recommendations

For Learning Physics

  • Study Pong/BallActor.cpp - PhysicsActor usage
  • Study CameraDemo/PlayerCube.cpp - Platformer physics

For Learning Collisions

  • Study SpaceInvaders - Complex collision layers
  • Study Pong - Simple collision response

For Learning Memory Management

  • Study Snake/SnakeScene.cpp - Entity pooling
  • Study SpaceInvaders - Projectile pooling

For Learning Audio

  • Study SpaceInvaders - Music and sound effects
  • Study Pong - Simple audio integration

For Learning UI

  • Study TicTacToe - Button-based UI
  • Study menu scenes - Layout usage

Extending Examples

Adding Features

  • Pong: Add power-ups, multiple balls
  • Snake: Add obstacles, multiple food types
  • Space Invaders: Add boss battles, power-ups

Creating Variations

  • Pong: Make it vertical, add walls
  • Snake: Change to hexagonal grid
  • TicTacToe: Make it 4x4 or 5x5

Best Practices from Examples

  1. Pre-allocate Resources: All examples pre-allocate entities
  2. Use Object Pooling: For frequently created/destroyed entities
  3. Organize by Layers: Clear collision layer organization
  4. Separate Concerns: Game logic separate from rendering
  5. State Management: Clear game state handling

See Also


Note: All example code is available in the src/examples/ directory of the PixelRoot32 Game Samples project.

\ No newline at end of file +

Learning Path

Beginner Examples

  1. Pong: Basic physics and collisions
  2. TicTacToe: Turn-based logic
  3. Snake: Entity pooling and grid

Intermediate Examples

  1. CameraDemo: Camera and parallax
  2. SpritesDemo: 2bpp and 4bpp formats
  3. BrickBreaker: Physics, particles and audio

Advanced Examples

  1. Space Invaders: Full game (1bpp sprites, collisions, audio)
  2. Metroidvania: Platformer with multi-layer 4bpp tilemap, tile-based collision and ESP32 optimizations (no scroll/camera)

Code Study Recommendations

For Learning Physics

  • Study Pong/BallActor.cpp - PhysicsActor usage
  • Study CameraDemo/PlayerCube.cpp - Platformer physics

For Learning Collisions

  • Study SpaceInvaders - Complex collision layers
  • Study Pong - Simple collision response

For Learning Memory Management

  • Study Snake/SnakeScene.cpp - Entity pooling
  • Study SpaceInvaders - Projectile pooling

For Learning Audio

  • Study SpaceInvaders - Music and sound effects
  • Study Pong - Simple audio integration

For Learning UI

  • Study TicTacToe - Button-based UI
  • Study menu scenes - Layout usage

Extending Examples

Adding Features

  • Pong: Add power-ups, multiple balls
  • Snake: Add obstacles, multiple food types
  • Space Invaders: Add boss battles, power-ups

Creating Variations

  • Pong: Make it vertical, add walls
  • Snake: Change to hexagonal grid
  • TicTacToe: Make it 4x4 or 5x5

Best Practices from Examples

  1. Pre-allocate Resources: All examples pre-allocate entities
  2. Use Object Pooling: For frequently created/destroyed entities
  3. Organize by Layers: Clear collision layer organization
  4. Separate Concerns: Game logic separate from rendering
  5. State Management: Clear game state handling

See Also


Note: All example code is available in the src/examples/ directory of the PixelRoot32 Game Samples project.

\ No newline at end of file diff --git a/site/resources/available_tools/index.html b/site/resources/available_tools/index.html index 480a146..5aabd6a 100644 --- a/site/resources/available_tools/index.html +++ b/site/resources/available_tools/index.html @@ -1,4 +1,4 @@ - Available Tools - PixelRoot32 Documentation
Skip to content

Available Tools

This guide documents tools available to facilitate PixelRoot32 game development.

Sprite Compiler (pr32-sprite-compiler)

The Sprite Compiler converts PNG images to PixelRoot32 sprite data formats, making it easy to create sprites from image files.

Read more in the Sprite Compiler Guide

pixelroot32-game-engine.github.io

Available Tools

This guide documents tools available to facilitate PixelRoot32 game development.

Sprite Compiler (pr32-sprite-compiler)

The Sprite Compiler converts PNG images to PixelRoot32 sprite data formats, making it easy to create sprites from image files.

Read more in the Sprite Compiler Guide

\ No newline at end of file +

Best Practices

  • Organize assets: Keep source images separate from generated code
  • Version control: Commit generated headers, not source images (or both)
  • Naming conventions: Use consistent naming for sprites
  • Batch processing: Process multiple sprites at once when possible

See Also


Note: Tool availability may vary. Check the PixelRoot32 repository for the latest tool information.

\ No newline at end of file diff --git a/site/resources/faq/index.html b/site/resources/faq/index.html index 23abd0f..85f86c6 100644 --- a/site/resources/faq/index.html +++ b/site/resources/faq/index.html @@ -1,4 +1,4 @@ - FAQ - PixelRoot32 Documentation
Skip to content

Frequently Asked Questions

Common questions about PixelRoot32, organized by category.

General

What is PixelRoot32?

PixelRoot32 is a lightweight, modular 2D game engine designed for ESP32 microcontrollers. It provides a complete game development framework with rendering, audio, physics, input, and UI systems, optimized for limited hardware resources.

What platforms does it support?

  • ESP32: Primary platform (TFT displays, GPIO buttons, DAC/I2S audio)
  • Native/Desktop: Development platform (SDL2, keyboard, SDL2 audio)

What kind of games can I make?

PixelRoot32 is ideal for: - Retro/arcade-style games - 2D platformers - Shooters - Puzzle games - Simple RPGs - Educational games

See Limitations and Considerations for what's not suitable.

Is it free to use?

Yes, PixelRoot32 is open source and licensed under the MIT License. You can use it freely for personal and commercial projects.

Where can I find the source code?

Installation and Configuration

How do I install PixelRoot32?

See Your First Project for detailed installation instructions.

Quick answer: 1. Install PlatformIO in VS Code 2. Create new ESP32 project 3. Add library dependency: gperez88/PixelRoot32-Game-Engine@0.2.0-dev 4. Configure hardware in platformio.ini

What version should I use?

Use the exact version 0.2.0-dev. Do NOT use ^ or fuzzy versioning, as the API may change.

How do I configure my display?

Configure TFT_eSPI via build flags in platformio.ini. See Your First Project for examples.

How do I set up audio?

Choose an audio backend: - ESP32_DAC: Simple, one pin (GPIO 25 or 26) - ESP32_I2S: Higher quality, requires external DAC - SDL2_AudioBackend: For Native/PC development

See Audio for details.

Development

How do I create a scene?

Inherit from pixelroot32::core::Scene and implement init(), update(), and draw(). See Scenes and Entities.

How do I add entities to a scene?

Create entities and call addEntity() in init(). The scene manages them automatically.

What's the difference between Entity, Actor, and PhysicsActor?

  • Entity: Base class, can be drawn and updated
  • Actor: Entity with collision detection
  • PhysicsActor: Actor with automatic physics (velocity, gravity, friction)

See Scenes and Entities for details.

How do I handle input?

Access InputManager through the engine:

auto& input = engine.getInputManager();
+ FAQ - PixelRoot32 Documentation      

Frequently Asked Questions

Common questions about PixelRoot32, organized by category.

General

What is PixelRoot32?

PixelRoot32 is a lightweight, modular 2D game engine designed for ESP32 microcontrollers. It provides a complete game development framework with rendering, audio, physics, input, and UI systems, optimized for limited hardware resources.

What platforms does it support?

  • ESP32: Primary platform (TFT displays, GPIO buttons, DAC/I2S audio)
  • Native/Desktop: Development platform (SDL2, keyboard, SDL2 audio)

What kind of games can I make?

PixelRoot32 is ideal for: - Retro/arcade-style games - 2D platformers - Shooters - Puzzle games - Simple RPGs - Educational games

See Limitations and Considerations for what's not suitable.

Is it free to use?

Yes, PixelRoot32 is open source and licensed under the MIT License. You can use it freely for personal and commercial projects.

Where can I find the source code?

Installation and Configuration

How do I install PixelRoot32?

See Your First Project for detailed installation instructions.

Quick answer: 1. Install PlatformIO in VS Code 2. Create new ESP32 project 3. Add library dependency: gperez88/PixelRoot32-Game-Engine@0.2.0-dev 4. Configure hardware in platformio.ini

What version should I use?

Use the exact version 0.2.0-dev. Do NOT use ^ or fuzzy versioning, as the API may change.

How do I configure my display?

Configure TFT_eSPI via build flags in platformio.ini. See Your First Project for examples.

How do I set up audio?

Choose an audio backend: - ESP32_DAC: Simple, one pin (GPIO 25 or 26) - ESP32_I2S: Higher quality, requires external DAC - SDL2_AudioBackend: For Native/PC development

See Audio for details.

Development

How do I create a scene?

Inherit from pixelroot32::core::Scene and implement init(), update(), and draw(). See Scenes and Entities.

How do I add entities to a scene?

Create entities and call addEntity() in init(). The scene manages them automatically.

What's the difference between Entity, Actor, and PhysicsActor?

  • Entity: Base class, can be drawn and updated
  • Actor: Entity with collision detection
  • PhysicsActor: Actor with automatic physics (velocity, gravity, friction)

See Scenes and Entities for details.

How do I handle input?

Access InputManager through the engine:

auto& input = engine.getInputManager();
 if (input.isButtonPressed(Buttons::A)) {
     // Handle input
 }
@@ -11,4 +11,4 @@
 Serial.print("Free heap: ");
 Serial.println(ESP.getFreeHeap());
 #endif
-

Hardware

Which ESP32 board should I use?

Any ESP32 board works. Common choices: - ESP32-WROOM-32 - ESP32-WROVER (more RAM) - ESP32-DevKit

Which display should I use?

Popular choices: - ST7789: 240x240, good quality - ST7735: 128x128, smaller/cheaper - ILI9341: 240x320, larger

See Platforms and Drivers.

How many buttons do I need?

Minimum: 4 (UP, DOWN, LEFT, RIGHT) Recommended: 6 (add A and B buttons) More buttons can be added if needed.

Can I use analog joysticks?

Not directly supported. You can read analog pins manually and convert to digital input, but the engine expects digital buttons.

Troubleshooting

My display is blank. What's wrong?

  1. Check wiring connections
  2. Verify pin numbers in platformio.ini
  3. Lower SPI frequency
  4. Check display type matches hardware
  5. Verify power supply

See Troubleshooting.

Buttons don't work. Why?

  1. Check button wiring
  2. Verify pin numbers in InputConfig
  3. Check pull-up/pull-down resistors
  4. Ensure InputManager is being updated
  5. Test with isButtonDown() vs isButtonPressed()

Audio is distorted. How do I fix it?

  1. Lower volume levels
  2. Reduce sample rate (try 11025 Hz)
  3. Check for too many simultaneous sounds
  4. Verify hardware connections
  5. Check power supply

Game crashes randomly. What's happening?

Common causes: - Out of memory - Too many entities - Infinite loops - Stack overflow - Watchdog timeout

See Troubleshooting for debugging techniques.

Advanced

Can I extend the engine?

Yes, PixelRoot32 is designed to be extensible. You can: - Create custom display drivers - Create custom audio backends - Extend existing systems

See Extensibility.

Can I use 3D graphics?

No, PixelRoot32 is 2D-only. It's designed for sprite-based 2D games.

Can I add networking?

Not currently supported. The engine focuses on single-player games.

Can I save game data?

Not currently supported. A save system is planned for future versions.

Can I use multiple scenes at once?

Yes, use SceneManager to push/pop scenes. This is useful for menus and pause screens.

Getting Help

Where can I get help?

  • Documentation: This documentation site
  • Examples: Study example games in the samples project
  • Discord: Community Discord server
  • GitHub: Open an issue for bugs

How do I report a bug?

Create a detailed bug report with: - Platform (ESP32 or Native) - Hardware details - Minimal reproduction code - Error messages - Expected vs actual behavior

Can I contribute?

Yes! PixelRoot32 is open source. Check the main repository for contribution guidelines.

See Also


Can't find your question? Check the Troubleshooting guide or ask on the Discord server.

\ No newline at end of file +

Hardware

Which ESP32 board should I use?

Any ESP32 board works. Common choices: - ESP32-WROOM-32 - ESP32-WROVER (more RAM) - ESP32-DevKit

Which display should I use?

Popular choices: - ST7789: 240x240, good quality - ST7735: 128x128, smaller/cheaper - ILI9341: 240x320, larger

See Platforms and Drivers.

How many buttons do I need?

Minimum: 4 (UP, DOWN, LEFT, RIGHT) Recommended: 6 (add A and B buttons) More buttons can be added if needed.

Can I use analog joysticks?

Not directly supported. You can read analog pins manually and convert to digital input, but the engine expects digital buttons.

Troubleshooting

My display is blank. What's wrong?

  1. Check wiring connections
  2. Verify pin numbers in platformio.ini
  3. Lower SPI frequency
  4. Check display type matches hardware
  5. Verify power supply

See Troubleshooting.

Buttons don't work. Why?

  1. Check button wiring
  2. Verify pin numbers in InputConfig
  3. Check pull-up/pull-down resistors
  4. Ensure InputManager is being updated
  5. Test with isButtonDown() vs isButtonPressed()

Audio is distorted. How do I fix it?

  1. Lower volume levels
  2. Reduce sample rate (try 11025 Hz)
  3. Check for too many simultaneous sounds
  4. Verify hardware connections
  5. Check power supply

Game crashes randomly. What's happening?

Common causes: - Out of memory - Too many entities - Infinite loops - Stack overflow - Watchdog timeout

See Troubleshooting for debugging techniques.

Advanced

Can I extend the engine?

Yes, PixelRoot32 is designed to be extensible. You can: - Create custom display drivers - Create custom audio backends - Extend existing systems

See Extensibility.

Can I use 3D graphics?

No, PixelRoot32 is 2D-only. It's designed for sprite-based 2D games.

Can I add networking?

Not currently supported. The engine focuses on single-player games.

Can I save game data?

Not currently supported. A save system is planned for future versions.

Can I use multiple scenes at once?

Yes, use SceneManager to push/pop scenes. This is useful for menus and pause screens.

Getting Help

Where can I get help?

  • Documentation: This documentation site
  • Examples: Study example games in the samples project
  • Discord: Community Discord server
  • GitHub: Open an issue for bugs

How do I report a bug?

Create a detailed bug report with: - Platform (ESP32 or Native) - Hardware details - Minimal reproduction code - Error messages - Expected vs actual behavior

Can I contribute?

Yes! PixelRoot32 is open source. Check the main repository for contribution guidelines.

See Also


Can't find your question? Check the Troubleshooting guide or ask on the Discord server.

\ No newline at end of file diff --git a/site/resources/limitations_and_considerations/index.html b/site/resources/limitations_and_considerations/index.html index b86840d..87e4ecb 100644 --- a/site/resources/limitations_and_considerations/index.html +++ b/site/resources/limitations_and_considerations/index.html @@ -1 +1 @@ - Limitations and Considerations - PixelRoot32 Documentation
Skip to content

Limitations and Considerations

This document honestly documents what PixelRoot32 can and cannot do, helping you make informed decisions about using the engine.

Hardware Limitations (ESP32)

Memory Constraints

RAM: - Available: ~320KB total (varies by ESP32 model) - Heap: Limited and fragmented over time - Stack: ~8KB, avoid large stack allocations - Impact: Limits entity count, sprite data, and dynamic allocation

Flash: - Available: 4MB+ (varies by model) - Usage: Program code, sprite data, assets - Impact: Large games may approach limits

Recommendations: - Use object pooling - Store data in flash (const/constexpr) - Avoid dynamic allocation in game loop - Keep entity count low

CPU Limitations

Performance: - Clock Speed: 240MHz (typically) - Single-threaded: One core handles everything - Target FPS: 30-60 FPS (depends on complexity) - Frame Budget: ~16-33ms per frame at 60 FPS

Impact: - Complex games may struggle - Many entities reduce performance - Expensive calculations hurt FPS

Recommendations: - Optimize rendering - Reduce entity count - Cache calculations - Profile on hardware

Display Limitations

Supported Displays: - TFT displays via SPI (ST7735, ST7789, ILI9341, etc.) - Limited to SPI displays - Resolution typically 128x128 to 320x240

Constraints: - SPI communication speed limits - Display initialization complexity - Power consumption

Audio Limitations

Hardware: - Internal DAC: Lower quality, simple setup - I2S: Higher quality, requires external DAC - Sample rates: 11025 Hz (DAC) or 22050 Hz (I2S)

Constraints: - 4 channels total (2 Pulse, 1 Triangle, 1 Noise) - Music uses one channel - Limited simultaneous sounds - Quality limited by hardware

Software Limitations

Entity System

MAX_ENTITIES = 32 per scene - Hard limit, cannot be changed easily - Applies to all entities (actors, UI, particles, etc.) - Must manage entity count carefully

Workarounds: - Use object pooling - Reuse entities - Disable entities instead of removing - Combine multiple entities into one

No RTTI (Runtime Type Information)

Impact: - Cannot use dynamic_cast in most code - Type checking must be done manually - Limits polymorphism patterns

Alternatives: - Use virtual functions - Manual type checking - Tag-based systems

No Exceptions in Critical Code

Impact: - Cannot use try/catch in game loop - Error handling must be explicit - Crashes instead of exceptions

Best Practices: - Validate inputs - Check return values - Use assertions for debugging - Handle errors explicitly

No Dynamic Allocation in Game Loop

Impact: - Cannot use new/delete during gameplay - Must pre-allocate resources - Limits flexibility

Solutions: - Object pooling - Pre-allocation in init() - Static buffers - Fixed-size arrays

No Advanced Features

Not Supported: - 3D graphics - Shaders - Advanced physics (joints, constraints) - Networking - File system (ESP32) - Advanced audio effects

Focus: - 2D sprite-based games - Simple physics - Retro-style games - Embedded-friendly features

Experimental Features

2bpp Sprites

Status: Experimental - Requires PIXELROOT32_ENABLE_2BPP_SPRITES flag - May have bugs or limitations - Not fully tested

Use with caution: - Test thoroughly - May change in future versions - Report issues if found

4bpp Sprites

Status: Experimental - Requires PIXELROOT32_ENABLE_4BPP_SPRITES flag - More experimental than 2bpp - Higher memory usage

Use with caution: - Test extensively - Monitor memory usage - May be unstable

Scene Arena

Status: Experimental - Requires PIXELROOT32_ENABLE_SCENE_ARENA flag - Alternative memory management - May have bugs

Recommendations: - Use object pooling instead (more stable) - Test thoroughly if using - May be removed or changed

Unsupported Features (Current)

Planned but Not Available

  • u8g2 Driver: Alternative display driver (planned)
  • Music Compiler: Tool to convert music files (planned)
  • Tilemap Compiler: Tool to create tilemaps (planned)
  • Save System: Persistent storage system (planned)
  • Spatial Partitioning: Advanced collision optimization (planned)

Not Planned

  • 3D Graphics: 2D-only engine
  • Networking: No network support
  • File System: No file I/O on ESP32
  • Advanced Audio: NES-like audio only
  • Scripting: No Lua/JavaScript support

Best Practices for ESP32

Memory Management

  • Pre-allocate: All resources in init()
  • Object pooling: Reuse entities
  • Flash storage: Use const/constexpr for data
  • Avoid strings: Use static buffers
  • Monitor usage: Check heap regularly

Performance

  • Limit entities: Stay well below MAX_ENTITIES
  • Optimize rendering: Use culling, batching
  • Cache calculations: Avoid repeated work
  • Profile on hardware: PC performance ≠ ESP32

Development

  • Test on hardware: Don't rely only on Native
  • Start simple: Add complexity gradually
  • Monitor memory: Watch for leaks
  • Optimize incrementally: Profile and optimize

What PixelRoot32 IS Good For

Retro-style 2D gamesArcade gamesPuzzle gamesPlatformersShootersEducational projectsPrototypingEmbedded game development

What PixelRoot32 is NOT Good For

3D gamesComplex physics simulationsLarge open worldsGames requiring many entitiesGames with complex graphicsNetwork multiplayerGames requiring file I/O

Making Informed Decisions

Before Starting a Project

  1. Assess requirements: Does PixelRoot32 fit?
  2. Check limitations: Can you work within constraints?
  3. Plan architecture: Design around limitations
  4. Test early: Verify on hardware early

If Limitations Are a Problem

Consider alternatives: - Full game engines (Unity, Godot) for complex games - Custom solutions for specific needs - Different hardware for more resources

Or work within limits: - Simplify game design - Optimize aggressively - Use creative solutions

Version Compatibility

Current Version

  • Engine Version: 0.2.0-dev
  • API Stability: May change
  • Breaking Changes: Possible in future versions

Recommendations: - Pin exact version in platformio.ini - Don't use ^ or fuzzy versioning - Test after engine updates - Review changelog

Honest Assessment

PixelRoot32 is designed for: - Simple to medium complexity games - Retro/arcade style - ESP32 hardware constraints - Rapid development

It is not designed for: - AAA game complexity - Modern graphics - Large-scale games - Unlimited resources

See Also


Remember: Understanding limitations helps you build better games within PixelRoot32's capabilities.

\ No newline at end of file + Limitations and Considerations - PixelRoot32 Documentation
Skip to content

Limitations and Considerations

This document honestly documents what PixelRoot32 can and cannot do, helping you make informed decisions about using the engine.

Hardware Limitations (ESP32)

Memory Constraints

RAM: - Available: ~320KB total (varies by ESP32 model) - Heap: Limited and fragmented over time - Stack: ~8KB, avoid large stack allocations - Impact: Limits entity count, sprite data, and dynamic allocation

Flash: - Available: 4MB+ (varies by model) - Usage: Program code, sprite data, assets - Impact: Large games may approach limits

Recommendations: - Use object pooling - Store data in flash (const/constexpr) - Avoid dynamic allocation in game loop - Keep entity count low

CPU Limitations

Performance: - Clock Speed: 240MHz (typically) - Single-threaded: One core handles everything - Target FPS: 30-60 FPS (depends on complexity) - Frame Budget: ~16-33ms per frame at 60 FPS

Impact: - Complex games may struggle - Many entities reduce performance - Expensive calculations hurt FPS

Recommendations: - Optimize rendering - Reduce entity count - Cache calculations - Profile on hardware

Display Limitations

Supported Displays: - TFT displays via SPI (ST7735, ST7789, ILI9341, etc.) - Limited to SPI displays - Resolution typically 128x128 to 320x240

Constraints: - SPI communication speed limits - Display initialization complexity - Power consumption

Audio Limitations

Hardware: - Internal DAC: Lower quality, simple setup - I2S: Higher quality, requires external DAC - Sample rates: 11025 Hz (DAC) or 22050 Hz (I2S)

Constraints: - 4 channels total (2 Pulse, 1 Triangle, 1 Noise) - Music uses one channel - Limited simultaneous sounds - Quality limited by hardware

Software Limitations

Entity System

MAX_ENTITIES = 32 per scene - Hard limit, cannot be changed easily - Applies to all entities (actors, UI, particles, etc.) - Must manage entity count carefully

Workarounds: - Use object pooling - Reuse entities - Disable entities instead of removing - Combine multiple entities into one

No RTTI (Runtime Type Information)

Impact: - Cannot use dynamic_cast in most code - Type checking must be done manually - Limits polymorphism patterns

Alternatives: - Use virtual functions - Manual type checking - Tag-based systems

No Exceptions in Critical Code

Impact: - Cannot use try/catch in game loop - Error handling must be explicit - Crashes instead of exceptions

Best Practices: - Validate inputs - Check return values - Use assertions for debugging - Handle errors explicitly

No Dynamic Allocation in Game Loop

Impact: - Cannot use new/delete during gameplay - Must pre-allocate resources - Limits flexibility

Solutions: - Object pooling - Pre-allocation in init() - Static buffers - Fixed-size arrays

No Advanced Features

Not Supported: - 3D graphics - Shaders - Advanced physics (joints, constraints) - Networking - File system (ESP32) - Advanced audio effects

Focus: - 2D sprite-based games - Simple physics - Retro-style games - Embedded-friendly features

Experimental Features

2bpp Sprites

Status: Experimental - Requires PIXELROOT32_ENABLE_2BPP_SPRITES flag - May have bugs or limitations - Not fully tested

Use with caution: - Test thoroughly - May change in future versions - Report issues if found

4bpp Sprites

Status: Experimental - Requires PIXELROOT32_ENABLE_4BPP_SPRITES flag - More experimental than 2bpp - Higher memory usage

Use with caution: - Test extensively - Monitor memory usage - May be unstable

Scene Arena

Status: Experimental - Requires PIXELROOT32_ENABLE_SCENE_ARENA flag - Alternative memory management - May have bugs

Recommendations: - Use object pooling instead (more stable) - Test thoroughly if using - May be removed or changed

Unsupported Features (Current)

Planned but Not Available

  • u8g2 Driver: Alternative display driver (planned)
  • Music Compiler: Tool to convert music files (planned)
  • Tilemap Compiler: Tool to create tilemaps (planned)
  • Save System: Persistent storage system (planned)
  • Spatial Partitioning: Advanced collision optimization (planned)

Not Planned

  • 3D Graphics: 2D-only engine
  • Networking: No network support
  • File System: No file I/O on ESP32
  • Advanced Audio: NES-like audio only
  • Scripting: No Lua/JavaScript support

Best Practices for ESP32

Memory Management

  • Pre-allocate: All resources in init()
  • Object pooling: Reuse entities
  • Flash storage: Use const/constexpr for data
  • Avoid strings: Use static buffers
  • Monitor usage: Check heap regularly

Performance

  • Limit entities: Stay well below MAX_ENTITIES
  • Optimize rendering: Use culling, batching
  • Cache calculations: Avoid repeated work
  • Profile on hardware: PC performance ≠ ESP32

Development

  • Test on hardware: Don't rely only on Native
  • Start simple: Add complexity gradually
  • Monitor memory: Watch for leaks
  • Optimize incrementally: Profile and optimize

What PixelRoot32 IS Good For

Retro-style 2D gamesArcade gamesPuzzle gamesPlatformersShootersEducational projectsPrototypingEmbedded game development

What PixelRoot32 is NOT Good For

3D gamesComplex physics simulationsLarge open worldsGames requiring many entitiesGames with complex graphicsNetwork multiplayerGames requiring file I/O

Making Informed Decisions

Before Starting a Project

  1. Assess requirements: Does PixelRoot32 fit?
  2. Check limitations: Can you work within constraints?
  3. Plan architecture: Design around limitations
  4. Test early: Verify on hardware early

If Limitations Are a Problem

Consider alternatives: - Full game engines (Unity, Godot) for complex games - Custom solutions for specific needs - Different hardware for more resources

Or work within limits: - Simplify game design - Optimize aggressively - Use creative solutions

Version Compatibility

Current Version

  • Engine Version: 0.2.0-dev
  • API Stability: May change
  • Breaking Changes: Possible in future versions

Recommendations: - Pin exact version in platformio.ini - Don't use ^ or fuzzy versioning - Test after engine updates - Review changelog

Honest Assessment

PixelRoot32 is designed for: - Simple to medium complexity games - Retro/arcade style - ESP32 hardware constraints - Rapid development

It is not designed for: - AAA game complexity - Modern graphics - Large-scale games - Unlimited resources

See Also


Remember: Understanding limitations helps you build better games within PixelRoot32's capabilities.

\ No newline at end of file diff --git a/site/resources/troubleshooting/index.html b/site/resources/troubleshooting/index.html index d58b1d5..a378ba5 100644 --- a/site/resources/troubleshooting/index.html +++ b/site/resources/troubleshooting/index.html @@ -1,4 +1,4 @@ - Troubleshooting - PixelRoot32 Documentation
Skip to content

Troubleshooting

This guide helps you diagnose and fix common issues when developing with PixelRoot32.

Compilation Problems

Common Compilation Errors

Error: Library not found

Solution: Ensure PixelRoot32-Game-Engine is properly installed
+ Troubleshooting - PixelRoot32 Documentation      

Troubleshooting

This guide helps you diagnose and fix common issues when developing with PixelRoot32.

Compilation Problems

Common Compilation Errors

Error: Library not found

Solution: Ensure PixelRoot32-Game-Engine is properly installed
 - Check platformio.ini has correct lib_deps
 - Verify library version matches (use exact version, not ^)
 - Try: pio lib install
@@ -14,7 +14,7 @@
 - Use -D FLAG_NAME (not --define)
 - Check flag names are correct
 - Ensure flags are in correct environment section
-

Configuration Issues

Wrong display type: - Verify DisplayType matches your hardware - Check TFT_eSPI build flags match display - Test with different display types

Incorrect pin configuration: - Verify GPIO pins match your wiring - Check pin numbers in platformio.ini - Ensure pins aren't used by other peripherals

Hardware Problems (ESP32)

Display Not Working

Symptoms: - Blank screen - Garbled display - No output

Solutions: 1. Check wiring: - Verify SPI connections (MOSI, SCLK, DC, RST) - Check power supply (3.3V or 5V as required) - Ensure ground connections

  1. Verify configuration:
  2. Check display type matches hardware
  3. Verify pin numbers in platformio.ini
  4. Test with known working configuration

  5. SPI frequency:

  6. Lower SPI frequency (try 20MHz instead of 40MHz)
  7. Some displays need slower speeds
  8. Check display datasheet for max frequency

  9. Display initialization:

  10. Try different rotation values
  11. Check display width/height settings
  12. Verify TFT_eSPI driver is correct

Buttons Not Responding

Symptoms: - No input detected - Buttons don't trigger actions - Input feels laggy

Solutions: 1. Check wiring: - Verify button connections to GPIO pins - Check pull-up/pull-down resistors - Test buttons with multimeter

  1. Verify pin configuration:
  2. Check InputConfig pin numbers
  3. Ensure pins match hardware
  4. Verify pins aren't used elsewhere

  5. Input debouncing:

  6. Add hardware debouncing (capacitor)
  7. Check InputManager is being updated
  8. Verify input is read in update(), not draw()

  9. Button logic:

  10. Test with isButtonDown() vs isButtonPressed()
  11. Check button indices match configuration
  12. Verify input is accessed correctly

Audio Not Working

Symptoms: - No sound output - Distorted audio - Audio glitches

Solutions: 1. DAC Configuration: - Verify DAC pin (25 or 26 for ESP32) - Check sample rate (11025 Hz recommended) - Ensure audio backend is initialized

  1. I2S Configuration:
  2. Verify I2S pin connections (BCLK, LRCK, DOUT)
  3. Check external DAC is powered
  4. Verify I2S DAC is compatible

  5. Audio quality:

  6. Lower sample rate if distorted
  7. Reduce volume levels
  8. Check for too many simultaneous sounds
  9. Verify audio buffer size

  10. Hardware:

  11. Check speaker connections
  12. Verify amplifier is powered
  13. Test with different audio hardware
  14. Check audio cable connections

Power Issues

Symptoms: - ESP32 resets randomly - Display flickers - Unstable operation

Solutions: 1. Power supply: - Use adequate power supply (500mA+ recommended) - Check voltage is stable (3.3V) - Add decoupling capacitors

  1. Current draw:
  2. Display draws significant current
  3. Audio amplifier adds load
  4. Reduce brightness if possible

  5. Wiring:

  6. Use thick wires for power
  7. Keep power wires short
  8. Add capacitors near ESP32

Performance Problems

Low FPS

Symptoms: - Game runs slowly - Laggy movement - Stuttering

Solutions: 1. Reduce entity count: - Limit active entities (MAX_ENTITIES = 32) - Disable off-screen entities - Use object pooling

  1. Optimize rendering:
  2. Use viewport culling
  3. Reduce draw calls
  4. Use tilemaps instead of individual sprites
  5. Limit sprite count

  6. Simplify logic:

  7. Cache expensive calculations
  8. Reduce collision checks
  9. Lower update frequency for non-critical entities

  10. Check hardware:

  11. Verify ESP32 is running at full speed (240MHz)
  12. Check for thermal throttling
  13. Ensure adequate power supply

Frame Drops

Symptoms: - Occasional stuttering - Inconsistent frame times - Periodic freezes

Solutions: 1. Identify bottlenecks: - Profile frame time - Check for expensive operations - Look for blocking code

  1. Optimize update loop:
  2. Avoid dynamic allocation
  3. Cache calculations
  4. Reduce string operations

  5. Memory issues:

  6. Check for memory leaks
  7. Reduce memory usage
  8. Use object pooling

Freezes/Crashes

Symptoms: - Game stops responding - ESP32 resets - Watchdog resets

Solutions: 1. Memory issues: - Check available heap memory - Reduce entity count - Avoid dynamic allocation - Use object pooling

  1. Infinite loops:
  2. Check for infinite loops in update()
  3. Verify collision detection doesn't loop
  4. Check animation logic

  5. Stack overflow:

  6. Avoid large stack allocations
  7. Reduce recursion depth
  8. Move large data to heap (carefully)

  9. Watchdog:

  10. Ensure update() completes quickly
  11. Add yield() calls if needed
  12. Check for blocking operations

Memory Problems

Out of Memory

Symptoms: - Compilation fails - Runtime crashes - "Allocation failed" errors

Solutions: 1. Reduce memory usage: - Use 1bpp sprites instead of 2bpp/4bpp - Store data in flash (const/constexpr) - Reduce entity count - Use object pooling

  1. Optimize data:
  2. Reuse sprites
  3. Compress tilemap data
  4. Remove unused code/data

  5. Memory management:

  6. Avoid dynamic allocation in game loop
  7. Pre-allocate all resources
  8. Use static buffers

Memory Fragmentation

Symptoms: - Gradual performance degradation - Allocation failures over time - Crashes after running for a while

Solutions: 1. Use object pooling: - Pre-allocate entities - Reuse objects instead of creating/destroying - Avoid frequent new/delete

  1. Pre-allocate resources:
  2. Allocate everything in init()
  3. Use fixed-size arrays
  4. Avoid dynamic containers

Native Build Problems

SDL2 Not Found

Symptoms: - Compilation fails - Linker errors - Missing SDL2 symbols

Solutions: 1. Install SDL2: - Windows (MSYS2): pacman -S mingw-w64-x86_64-SDL2 - Linux: sudo apt-get install libsdl2-dev - macOS: brew install sdl2

  1. Check paths:
  2. Verify include paths in platformio.ini
  3. Check library paths
  4. Ensure SDL2 version is compatible

  5. Linker flags:

  6. Verify -lSDL2 is in build flags
  7. Check library search paths
  8. Ensure SDL2 DLL is accessible (Windows)

Window Not Opening

Symptoms: - Program runs but no window - Console shows errors - Immediate exit

Solutions: 1. Check SDL2 initialization: - Verify SDL2 is properly initialized - Check for SDL2 error messages - Ensure display config is correct

  1. Graphics drivers:
  2. Update graphics drivers
  3. Check SDL2 video backend
  4. Test with simple SDL2 program

  5. Console output:

  6. Run from terminal to see errors
  7. Check for error messages
  8. Verify SDL2 is working

Debugging Techniques

Serial Debugging (ESP32)

void setup() {
+

Configuration Issues

Wrong display type: - Verify DisplayType matches your hardware - Check TFT_eSPI build flags match display - Test with different display types

Incorrect pin configuration: - Verify GPIO pins match your wiring - Check pin numbers in platformio.ini - Ensure pins aren't used by other peripherals

Hardware Problems (ESP32)

Display Not Working

Symptoms: - Blank screen - Garbled display - No output

Solutions: 1. Check wiring: - Verify SPI connections (MOSI, SCLK, DC, RST) - Check power supply (3.3V or 5V as required) - Ensure ground connections

  1. Verify configuration:
  2. Check display type matches hardware
  3. Verify pin numbers in platformio.ini
  4. Test with known working configuration

  5. SPI frequency:

  6. Lower SPI frequency (try 20MHz instead of 40MHz)
  7. Some displays need slower speeds
  8. Check display datasheet for max frequency

  9. Display initialization:

  10. Try different rotation values
  11. Check display width/height settings
  12. Verify TFT_eSPI driver is correct

Resolution Scaling Issues

Symptoms: - Image is not scaled to full screen - Visual artifacts (jittery pixels) - Frame rate drops when scaling is enabled

Solutions: 1. Verify DisplayConfig: - Ensure physicalWidth and physicalHeight match your hardware resolution (e.g., 240x240). - Check that logicalWidth and logicalHeight are set correctly (e.g., 128x128). - Use displayConfig.needsScaling() to check if the engine thinks scaling is required.

  1. Check Scaling Performance:
  2. Enabling scaling is generally faster than native high resolution, but still has some overhead.
  3. Use the Debug Statistics Overlay to check CPU load.
  4. Ensure you are using integer-only coordinates for drawing.

  5. Visual Quality:

  6. The engine uses nearest-neighbor scaling. Some aspect ratios might look "blocky" or have uneven pixel sizes.
  7. For best results, use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen).

Buttons Not Responding

Symptoms: - No input detected - Buttons don't trigger actions - Input feels laggy

Solutions: 1. Check wiring: - Verify button connections to GPIO pins - Check pull-up/pull-down resistors - Test buttons with multimeter

  1. Verify pin configuration:
  2. Check InputConfig pin numbers
  3. Ensure pins match hardware
  4. Verify pins aren't used elsewhere

  5. Input debouncing:

  6. Add hardware debouncing (capacitor)
  7. Check InputManager is being updated
  8. Verify input is read in update(), not draw()

  9. Button logic:

  10. Test with isButtonDown() vs isButtonPressed()
  11. Check button indices match configuration
  12. Verify input is accessed correctly

Audio Not Working

Symptoms: - No sound output - Distorted audio - Audio glitches

Solutions: 1. DAC Configuration: - Verify DAC pin (25 or 26 for ESP32) - Check sample rate (11025 Hz recommended) - Ensure audio backend is initialized

  1. I2S Configuration:
  2. Verify I2S pin connections (BCLK, LRCK, DOUT)
  3. Check external DAC is powered
  4. Verify I2S DAC is compatible

  5. Audio quality:

  6. Lower sample rate if distorted
  7. Reduce volume levels
  8. Check for too many simultaneous sounds
  9. Verify audio buffer size

  10. Hardware:

  11. Check speaker connections
  12. Verify amplifier is powered
  13. Test with different audio hardware
  14. Check audio cable connections

Power Issues

Symptoms: - ESP32 resets randomly - Display flickers - Unstable operation

Solutions: 1. Power supply: - Use adequate power supply (500mA+ recommended) - Check voltage is stable (3.3V) - Add decoupling capacitors

  1. Current draw:
  2. Display draws significant current
  3. Audio amplifier adds load
  4. Reduce brightness if possible

  5. Wiring:

  6. Use thick wires for power
  7. Keep power wires short
  8. Add capacitors near ESP32

Performance Problems

Low FPS

Symptoms: - Game runs slowly - Laggy movement - Stuttering

Solutions: 1. Reduce entity count: - Limit active entities (MAX_ENTITIES = 32) - Disable off-screen entities - Use object pooling

  1. Optimize rendering:
  2. Use viewport culling
  3. Reduce draw calls
  4. Use tilemaps instead of individual sprites
  5. Limit sprite count

  6. Simplify logic:

  7. Cache expensive calculations
  8. Reduce collision checks
  9. Lower update frequency for non-critical entities

  10. Check hardware:

  11. Verify ESP32 is running at full speed (240MHz)
  12. Check for thermal throttling
  13. Ensure adequate power supply

Frame Drops

Symptoms: - Occasional stuttering - Inconsistent frame times - Periodic freezes

Solutions: 1. Identify bottlenecks: - Profile frame time - Check for expensive operations - Look for blocking code

  1. Optimize update loop:
  2. Avoid dynamic allocation
  3. Cache calculations
  4. Reduce string operations

  5. Memory issues:

  6. Check for memory leaks
  7. Reduce memory usage
  8. Use object pooling

Freezes/Crashes

Symptoms: - Game stops responding - ESP32 resets - Watchdog resets

Solutions: 1. Memory issues: - Check available heap memory - Reduce entity count - Avoid dynamic allocation - Use object pooling

  1. Infinite loops:
  2. Check for infinite loops in update()
  3. Verify collision detection doesn't loop
  4. Check animation logic

  5. Stack overflow:

  6. Avoid large stack allocations
  7. Reduce recursion depth
  8. Move large data to heap (carefully)

  9. Watchdog:

  10. Ensure update() completes quickly
  11. Add yield() calls if needed
  12. Check for blocking operations

Memory Problems

Out of Memory

Symptoms: - Compilation fails - Runtime crashes - "Allocation failed" errors

Solutions: 1. Reduce memory usage: - Use 1bpp sprites instead of 2bpp/4bpp - Store data in flash (const/constexpr) - Reduce entity count - Use object pooling

  1. Optimize data:
  2. Reuse sprites
  3. Compress tilemap data
  4. Remove unused code/data

  5. Memory management:

  6. Avoid dynamic allocation in game loop
  7. Pre-allocate all resources
  8. Use static buffers

Memory Fragmentation

Symptoms: - Gradual performance degradation - Allocation failures over time - Crashes after running for a while

Solutions: 1. Use object pooling: - Pre-allocate entities - Reuse objects instead of creating/destroying - Avoid frequent new/delete

  1. Pre-allocate resources:
  2. Allocate everything in init()
  3. Use fixed-size arrays
  4. Avoid dynamic containers

Native Build Problems

SDL2 Not Found

Symptoms: - Compilation fails - Linker errors - Missing SDL2 symbols

Solutions: 1. Install SDL2: - Windows (MSYS2): pacman -S mingw-w64-x86_64-SDL2 - Linux: sudo apt-get install libsdl2-dev - macOS: brew install sdl2

  1. Check paths:
  2. Verify include paths in platformio.ini
  3. Check library paths
  4. Ensure SDL2 version is compatible

  5. Linker flags:

  6. Verify -lSDL2 is in build flags
  7. Check library search paths
  8. Ensure SDL2 DLL is accessible (Windows)

Window Not Opening

Symptoms: - Program runs but no window - Console shows errors - Immediate exit

Solutions: 1. Check SDL2 initialization: - Verify SDL2 is properly initialized - Check for SDL2 error messages - Ensure display config is correct

  1. Graphics drivers:
  2. Update graphics drivers
  3. Check SDL2 video backend
  4. Test with simple SDL2 program

  5. Console output:

  6. Run from terminal to see errors
  7. Check for error messages
  8. Verify SDL2 is working

Debugging Techniques

Serial Debugging (ESP32)

void setup() {
     Serial.begin(115200);
     // ... initialization
 
@@ -71,4 +71,4 @@
 // Usage
 DEBUG_LOG("Entity created");
 DEBUG_LOG("Collision detected");
-

Getting Help

If you can't resolve an issue:

  1. Check documentation: Review relevant guides
  2. Search examples: Look at example games
  3. Review code: Check engine source code
  4. Community: Ask on Discord or GitHub
  5. Report issue: Create detailed bug report

Bug Report Template

When reporting issues, include:

  • Platform: ESP32 or Native
  • Hardware: Display type, ESP32 model
  • Code: Minimal reproduction code
  • Error messages: Full error output
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Steps to reproduce: How to trigger the issue

See Also


Note: Many issues are configuration-related. Double-check your setup before assuming a bug.

\ No newline at end of file +

Getting Help

If you can't resolve an issue:

  1. Check documentation: Review relevant guides
  2. Search examples: Look at example games
  3. Review code: Check engine source code
  4. Community: Ask on Discord or GitHub
  5. Report issue: Create detailed bug report

Bug Report Template

When reporting issues, include:

  • Platform: ESP32 or Native
  • Hardware: Display type, ESP32 model
  • Code: Minimal reproduction code
  • Error messages: Full error output
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Steps to reproduce: How to trigger the issue

See Also


Note: Many issues are configuration-related. Double-check your setup before assuming a bug.

\ No newline at end of file diff --git a/site/search/search_index.json b/site/search/search_index.json index eb1a2d1..8add885 100644 --- a/site/search/search_index.json +++ b/site/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"PixelRoot32 Documentation","text":"

PixelRoot32 is a lightweight 2D game engine designed for ESP32 and native desktop targets. This site provides official, versioned documentation with clear guides, conceptual explanations, API references, and complete examples to help you build games efficiently.

"},{"location":"#quick-links","title":"Quick Links","text":"
  • What is PixelRoot32? - Start here to understand the engine
  • Your First Project - Get up and running quickly
  • Fundamental Concepts - Learn the core concepts
  • Manual - Complete user guide
  • API Reference - Complete API documentation
  • Examples - Complete game examples
  • Tools - Available tools
  • FAQ - FAQ and troubleshooting
"},{"location":"#getting-started","title":"Getting Started","text":"

New to PixelRoot32? Follow this learning path:

  1. What is PixelRoot32? - Understand what the engine is and what it can do
  2. Why PixelRoot32? - Learn the advantages and use cases
  3. Fundamental Concepts - Learn the core architecture concepts
  4. Your First Project - Create and run your first project
"},{"location":"#about-this-documentation","title":"About This Documentation","text":"
  • Professional technical English across all pages
  • Search-enabled, mobile-friendly UI
  • Versioned with mike (stable/dev/experimental)
  • Cross-linked concepts, API, and examples
  • Progressive learning path from basics to advanced topics
"},{"location":"api_reference/audio/audio_config/","title":"AudioConfig","text":"

Configuration for the Audio subsystem.

"},{"location":"api_reference/audio/audio_config/#description","title":"Description","text":"

AudioConfig is a simple struct that holds configuration settings for the audio system, including the audio backend and sample rate. It is passed to AudioEngine during construction.

"},{"location":"api_reference/audio/audio_config/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    struct AudioConfig {\n        // ...\n    };\n}\n
"},{"location":"api_reference/audio/audio_config/#structure","title":"Structure","text":""},{"location":"api_reference/audio/audio_config/#audiobackend-backend","title":"AudioBackend* backend","text":"

Pointer to the platform-specific audio backend implementation.

Type: AudioBackend*

Access: Read-write

Default: nullptr

Notes: - Must be set to a valid backend instance - Backend is platform-specific: - ESP32: ESP32_DAC_AudioBackend or ESP32_I2S_AudioBackend - Native: SDL2_AudioBackend - Backend manages the actual audio hardware/API

Example:

#ifdef PLATFORM_ESP32\n    pixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\n    audioConfig.backend = &dacBackend;\n#elif PLATFORM_NATIVE\n    pixelroot32::drivers::native::SDL2_AudioBackend sdlBackend;\n    audioConfig.backend = &sdlBackend;\n#endif\n

"},{"location":"api_reference/audio/audio_config/#int-samplerate","title":"int sampleRate","text":"

Desired sample rate in Hz.

Type: int

Access: Read-write

Default: 22050

Notes: - Common values: 11025, 22050, 44100 - Lower rates use less CPU and memory (better for ESP32) - Higher rates provide better quality - Must match backend capabilities

Example:

audioConfig.sampleRate = 11025;  // Lower quality, less CPU (ESP32)\naudioConfig.sampleRate = 22050;  // Balanced (default)\naudioConfig.sampleRate = 44100; // Higher quality (Native)\n

"},{"location":"api_reference/audio/audio_config/#constructors","title":"Constructors","text":""},{"location":"api_reference/audio/audio_config/#audioconfigaudiobackend-backend-nullptr-int-samplerate-22050","title":"AudioConfig(AudioBackend* backend = nullptr, int sampleRate = 22050)","text":"

Default constructor.

Parameters: - backend (AudioBackend*, optional): Pointer to the audio backend implementation. Default: nullptr - sampleRate (int, optional): Desired sample rate in Hz. Default: 22050

Example:

// Default construction\npixelroot32::audio::AudioConfig audioConfig;\n\n// With backend\npixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\npixelroot32::audio::AudioConfig audioConfig(&dacBackend, 11025);\n

"},{"location":"api_reference/audio/audio_config/#usage-example","title":"Usage Example","text":""},{"location":"api_reference/audio/audio_config/#esp32-with-dac-backend","title":"ESP32 with DAC Backend","text":"
#ifdef PLATFORM_ESP32\n#include \"drivers/esp32/ESP32_DAC_AudioBackend.h\"\n\npixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &dacBackend;\naudioConfig.sampleRate = 11025;  // Lower rate for ESP32\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n#endif\n
"},{"location":"api_reference/audio/audio_config/#esp32-with-i2s-backend","title":"ESP32 with I2S Backend","text":"
#ifdef PLATFORM_ESP32\n#include \"drivers/esp32/ESP32_I2S_AudioBackend.h\"\n\npixelroot32::drivers::esp32::ESP32_I2S_AudioBackend i2sBackend;\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &i2sBackend;\naudioConfig.sampleRate = 22050;  // Higher quality with I2S\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n#endif\n
"},{"location":"api_reference/audio/audio_config/#native-with-sdl2-backend","title":"Native with SDL2 Backend","text":"
#ifdef PLATFORM_NATIVE\n#include \"drivers/native/SDL2_AudioBackend.h\"\n\npixelroot32::drivers::native::SDL2_AudioBackend sdlBackend;\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &sdlBackend;\naudioConfig.sampleRate = 44100;  // High quality for PC\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n#endif\n
"},{"location":"api_reference/audio/audio_config/#complete-engine-setup","title":"Complete Engine Setup","text":"
#include \"core/Engine.h\"\n#include \"graphics/DisplayConfig.h\"\n#include \"input/InputConfig.h\"\n#include \"audio/AudioConfig.h\"\n\nvoid setup() {\n    // Display config\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    displayConfig.width = 128;\n    displayConfig.height = 128;\n\n    // Input config\n    pixelroot32::input::InputConfig inputConfig;\n    // ... configure input\n\n    // Audio config\n    #ifdef PLATFORM_ESP32\n        pixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\n        pixelroot32::audio::AudioConfig audioConfig(&dacBackend, 11025);\n    #elif PLATFORM_NATIVE\n        pixelroot32::drivers::native::SDL2_AudioBackend sdlBackend;\n        pixelroot32::audio::AudioConfig audioConfig(&sdlBackend, 44100);\n    #endif\n\n    // Create engine with all configs\n    pixelroot32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/audio/audio_config/#platform-specific-considerations","title":"Platform-Specific Considerations","text":""},{"location":"api_reference/audio/audio_config/#esp32-dac-backend","title":"ESP32 DAC Backend","text":"
  • Sample rate: 11025 Hz recommended (lower CPU usage)
  • Quality: Lower quality, but simple setup
  • Pin: Uses GPIO 25 or 26
  • Hardware: Requires simple amplifier circuit
"},{"location":"api_reference/audio/audio_config/#esp32-i2s-backend","title":"ESP32 I2S Backend","text":"
  • Sample rate: 22050 Hz recommended
  • Quality: Higher quality than DAC
  • Pins: Requires I2S pins (BCLK, LRCK, DOUT)
  • Hardware: Requires external I2S DAC
"},{"location":"api_reference/audio/audio_config/#native-sdl2-backend","title":"Native SDL2 Backend","text":"
  • Sample rate: 44100 Hz typical
  • Quality: High quality
  • Setup: Requires SDL2 library installed
  • Platforms: Windows, Linux, macOS
"},{"location":"api_reference/audio/audio_config/#performance-considerations","title":"Performance Considerations","text":"
  • Sample rate: Lower rates use less CPU and memory
  • Backend choice: DAC is simpler but lower quality than I2S
  • Buffer size: Configured in backend, affects latency vs stability
"},{"location":"api_reference/audio/audio_config/#see-also","title":"See Also","text":"
  • AudioEngine - Audio playback engine
  • Manual - Audio
  • Manual - Platforms and Drivers
  • API Overview
"},{"location":"api_reference/audio/audio_engine/","title":"AudioEngine","text":"

Core class for the NES-like audio subsystem.

"},{"location":"api_reference/audio/audio_engine/#description","title":"Description","text":"

AudioEngine manages the audio channels (Pulse, Triangle, Noise), mixes their output, and provides the audio stream to the backend. It implements a NES-like audio system with 4 fixed channels: 2 Pulse channels, 1 Triangle channel, and 1 Noise channel.

The engine is event-driven: you trigger sound effects via playEvent(), and the engine automatically manages channel allocation and playback.

"},{"location":"api_reference/audio/audio_engine/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    class AudioEngine {\n        // ...\n    };\n}\n
"},{"location":"api_reference/audio/audio_engine/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages audio engine instance)
"},{"location":"api_reference/audio/audio_engine/#constructors","title":"Constructors","text":""},{"location":"api_reference/audio/audio_engine/#audioengineconst-audioconfig-config","title":"AudioEngine(const AudioConfig& config)","text":"

Constructs the AudioEngine with the given configuration.

Parameters: - config (const AudioConfig&): Configuration struct containing the backend and parameters (sample rate, etc.)

Example:

#include \"audio/AudioEngine.h\"\n#include \"audio/AudioConfig.h\"\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &audioBackend;  // Platform-specific backend\naudioConfig.sampleRate = 22050;       // 22.05 kHz for retro feel\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n

"},{"location":"api_reference/audio/audio_engine/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/audio/audio_engine/#void-init","title":"void init()","text":"

Initializes the audio subsystem and the backend.

Returns: - void

Notes: - Must be called after construction and before use - Initializes the platform-specific audio backend - Safe to call multiple times (idempotent) - Typically called automatically by Engine::init()

Example:

AudioEngine audioEngine(audioConfig);\naudioEngine.init();  // Initialize before use\n

"},{"location":"api_reference/audio/audio_engine/#void-updateunsigned-long-deltatime","title":"void update(unsigned long deltaTime)","text":"

Updates the audio state based on game time.

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Returns: - void

Notes: - Should be called from the main game loop (typically via Engine::update()) - Updates channel lifetimes and durations - Automatically stops channels when their duration expires - Must be called every frame for proper audio timing

Example:

void update(unsigned long deltaTime) override {\n    // Update audio (called automatically by Engine)\n    engine.getAudioEngine().update(deltaTime);\n\n    // Your game logic...\n}\n

"},{"location":"api_reference/audio/audio_engine/#void-generatesamplesint16_t-stream-int-length","title":"void generateSamples(int16_t* stream, int length)","text":"

Fills the provided buffer with mixed audio samples.

Parameters: - stream (int16_t*): Pointer to the buffer to fill - length (int): Number of samples to generate

Returns: - void

Notes: - This method is typically called by the AudioBackend from an audio callback or task - Not usually called directly by game code - Generates 16-bit signed integer PCM samples - Mixes all active channels into a mono stream

Advanced Usage:

// Typically not called directly, but if implementing custom backend:\nint16_t buffer[512];\naudioEngine.generateSamples(buffer, 512);\n

"},{"location":"api_reference/audio/audio_engine/#void-playeventconst-audioevent-event","title":"void playEvent(const AudioEvent& event)","text":"

Triggers a one-shot sound effect.

Parameters: - event (const AudioEvent&): The audio event to play

Returns: - void

Notes: - Automatically finds an available channel of the correct type - If no channel is available, the event may be dropped (no error) - Events are fire-and-forget (no need to track playback) - Use for sound effects, not background music

Example:

// Play a jump sound\npixelroot32::audio::AudioEvent jumpSound{};\njumpSound.type = pixelroot32::audio::WaveType::PULSE;\njumpSound.frequency = 800.0f;\njumpSound.duration = 0.1f;\njumpSound.volume = 0.7f;\njumpSound.duty = 0.5f;\n\nauto& audio = engine.getAudioEngine();\naudio.playEvent(jumpSound);\n\n// Play an explosion sound\npixelroot32::audio::AudioEvent explosion{};\nexplosion.type = pixelroot32::audio::WaveType::NOISE;\nexplosion.frequency = 1000.0f;\nexplosion.duration = 0.3f;\nexplosion.volume = 0.9f;\n\naudio.playEvent(explosion);\n

"},{"location":"api_reference/audio/audio_engine/#void-setmastervolumefloat-volume","title":"void setMasterVolume(float volume)","text":"

Sets the master volume for all audio output.

Parameters: - volume (float): Volume level (0.0 = silent, 1.0 = full volume)

Returns: - void

Notes: - Affects all channels and events - Clamped to [0.0, 1.0] range - Use for volume control menus or mute functionality

Example:

auto& audio = engine.getAudioEngine();\naudio.setMasterVolume(0.5f);  // 50% volume\naudio.setMasterVolume(0.0f);  // Mute\naudio.setMasterVolume(1.0f);  // Full volume\n

"},{"location":"api_reference/audio/audio_engine/#float-getmastervolume-const","title":"float getMasterVolume() const","text":"

Gets the current master volume.

Returns: - float: Current master volume (0.0 to 1.0)

Example:

float currentVolume = audioEngine.getMasterVolume();\n

"},{"location":"api_reference/audio/audio_engine/#audio-channels","title":"Audio Channels","text":"

The engine manages 4 fixed channels:

  1. Channel 0: Pulse wave
  2. Channel 1: Pulse wave
  3. Channel 2: Triangle wave
  4. Channel 3: Noise wave

Notes: - Channels are automatically allocated when playing events - If all channels of a type are busy, new events may be dropped - Background music typically uses one channel (via MusicPlayer)

"},{"location":"api_reference/audio/audio_engine/#usage-example","title":"Usage Example","text":"
#include \"audio/AudioEngine.h\"\n#include \"audio/AudioConfig.h\"\n\nclass MyScene : public pixelroot32::core::Scene {\nprivate:\n    void playJumpSound() {\n        auto& audio = engine.getAudioEngine();\n\n        pixelroot32::audio::AudioEvent sound{};\n        sound.type = pixelroot32::audio::WaveType::PULSE;\n        sound.frequency = 800.0f;\n        sound.duration = 0.1f;\n        sound.volume = 0.7f;\n        sound.duty = 0.5f;\n\n        audio.playEvent(sound);\n    }\n\n    void playHitSound() {\n        auto& audio = engine.getAudioEngine();\n\n        pixelroot32::audio::AudioEvent sound{};\n        sound.type = pixelroot32::audio::WaveType::NOISE;\n        sound.frequency = 500.0f;\n        sound.duration = 0.05f;\n        sound.volume = 0.5f;\n\n        audio.playEvent(sound);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Audio is updated automatically by Engine\n        // Just play events when needed\n        if (playerJumped) {\n            playJumpSound();\n            playerJumped = false;\n        }\n    }\n};\n
"},{"location":"api_reference/audio/audio_engine/#performance-considerations","title":"Performance Considerations","text":"
  • Channel limit: Only 4 channels total; plan sound effects accordingly
  • Event dropping: If all channels are busy, new events are silently dropped
  • Update frequency: update() must be called every frame for proper timing
  • Sample generation: generateSamples() is called by backend at audio rate (not game rate)
"},{"location":"api_reference/audio/audio_engine/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Sample rate: Lower sample rates (11025 Hz) use less CPU and memory
  • Backend choice: DAC backend is simpler but lower quality than I2S
  • Buffer size: Larger buffers reduce underruns but increase latency
  • Channel management: Limit simultaneous sounds to avoid channel conflicts
"},{"location":"api_reference/audio/audio_engine/#see-also","title":"See Also","text":"
  • AudioConfig - Audio configuration
  • AudioTypes - Audio data structures
  • MusicPlayer - Background music playback
  • Manual - Audio
  • API Overview
"},{"location":"api_reference/audio/audio_types/","title":"Audio Types","text":"

Data structures and types for the audio system.

"},{"location":"api_reference/audio/audio_types/#description","title":"Description","text":"

This document describes the data structures used by the audio system, including wave types, audio events, and channel state.

"},{"location":"api_reference/audio/audio_types/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    // Types and structures\n}\n
"},{"location":"api_reference/audio/audio_types/#wavetype-enum","title":"WaveType Enum","text":"

Defines the types of waveforms available.

Values: - WaveType::PULSE: Pulse wave (square wave with variable duty cycle) - WaveType::TRIANGLE: Triangle wave (smooth, melodic) - WaveType::NOISE: Noise wave (random, percussive)

Example:

pixelroot32::audio::WaveType wave = pixelroot32::audio::WaveType::PULSE;\n

"},{"location":"api_reference/audio/audio_types/#audioevent-structure","title":"AudioEvent Structure","text":"

A fire-and-forget sound event triggered by the game.

Members: - WaveType type: Type of waveform to use - float frequency: Frequency in Hz - float duration: Duration in seconds - float volume: Volume level (0.0 to 1.0) - float duty: Duty cycle for pulse wave (0.0 to 1.0, pulse only)

Example:

pixelroot32::audio::AudioEvent jumpSound{};\njumpSound.type = pixelroot32::audio::WaveType::PULSE;\njumpSound.frequency = 800.0f;\njumpSound.duration = 0.1f;\njumpSound.volume = 0.7f;\njumpSound.duty = 0.5f;\n\nauto& audio = engine.getAudioEngine();\naudio.playEvent(jumpSound);\n

"},{"location":"api_reference/audio/audio_types/#common-sound-effects","title":"Common Sound Effects","text":"

Jump Sound:

pixelroot32::audio::AudioEvent jump{};\njump.type = pixelroot32::audio::WaveType::PULSE;\njump.frequency = 800.0f;\njump.duration = 0.1f;\njump.volume = 0.7f;\njump.duty = 0.5f;\n

Hit Sound:

pixelroot32::audio::AudioEvent hit{};\nhit.type = pixelroot32::audio::WaveType::NOISE;\nhit.frequency = 500.0f;\nhit.duration = 0.05f;\nhit.volume = 0.5f;\n

Collect Sound:

pixelroot32::audio::AudioEvent collect{};\ncollect.type = pixelroot32::audio::WaveType::TRIANGLE;\ncollect.frequency = 1000.0f;\ncollect.duration = 0.15f;\ncollect.volume = 0.6f;\n

Explosion:

pixelroot32::audio::AudioEvent explosion{};\nexplosion.type = pixelroot32::audio::WaveType::NOISE;\nexplosion.frequency = 200.0f;\nexplosion.duration = 0.3f;\nexplosion.volume = 0.9f;\n

"},{"location":"api_reference/audio/audio_types/#audiochannel-structure","title":"AudioChannel Structure","text":"

Represents the internal state of a single audio channel.

Members: - bool enabled: Whether the channel is active - WaveType type: Type of waveform - float frequency: Current frequency in Hz - float phase: Current phase (0.0 to 1.0) - float phaseIncrement: Pre-calculated phase increment - float volume: Current volume (0.0 to 1.0) - float targetVolume: Target volume for envelopes - float dutyCycle: Duty cycle for pulse wave (0.0 to 1.0) - uint16_t noiseRegister: LFSR state for noise generation - unsigned long durationMs: Total duration in milliseconds - unsigned long remainingMs: Remaining duration in milliseconds

Methods: - void reset(): Resets the channel to inactive state

Notes: - Internal structure, typically not accessed directly - Managed automatically by AudioEngine - 4 channels total: 2 Pulse, 1 Triangle, 1 Noise

"},{"location":"api_reference/audio/audio_types/#frequency-reference","title":"Frequency Reference","text":"

Common frequencies for musical notes (A4 = 440 Hz):

  • C4: 261.63 Hz
  • D4: 293.66 Hz
  • E4: 329.63 Hz
  • F4: 349.23 Hz
  • G4: 392.00 Hz
  • A4: 440.00 Hz
  • B4: 493.88 Hz
  • C5: 523.25 Hz

Example:

// Play a C note\npixelroot32::audio::AudioEvent note{};\nnote.type = pixelroot32::audio::WaveType::PULSE;\nnote.frequency = 261.63f;  // C4\nnote.duration = 0.5f;\nnote.volume = 0.8f;\nnote.duty = 0.5f;\n

"},{"location":"api_reference/audio/audio_types/#duty-cycle-pulse-wave","title":"Duty Cycle (Pulse Wave)","text":"

Duty cycle controls the shape of the pulse wave:

  • 0.125 (12.5%): Thin pulse (NES-like)
  • 0.25 (25%): Narrow pulse
  • 0.5 (50%): Square wave (most common)
  • 0.75 (75%): Wide pulse

Example:

// Thin pulse (NES style)\nevent.duty = 0.125f;\n\n// Square wave (standard)\nevent.duty = 0.5f;\n

"},{"location":"api_reference/audio/audio_types/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/audio/audio_types/#creating-sound-effect-library","title":"Creating Sound Effect Library","text":"
namespace SoundEffects {\n    // Jump sound\n    inline pixelroot32::audio::AudioEvent jump() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 800.0f;\n        evt.duration = 0.1f;\n        evt.volume = 0.7f;\n        evt.duty = 0.5f;\n        return evt;\n    }\n\n    // Hit sound\n    inline pixelroot32::audio::AudioEvent hit() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::NOISE;\n        evt.frequency = 500.0f;\n        evt.duration = 0.05f;\n        evt.volume = 0.5f;\n        return evt;\n    }\n\n    // Collect sound\n    inline pixelroot32::audio::AudioEvent collect() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::TRIANGLE;\n        evt.frequency = 1000.0f;\n        evt.duration = 0.15f;\n        evt.volume = 0.6f;\n        return evt;\n    }\n}\n\n// Usage\nauto& audio = engine.getAudioEngine();\naudio.playEvent(SoundEffects::jump());\naudio.playEvent(SoundEffects::hit());\n
"},{"location":"api_reference/audio/audio_types/#frequency-sweep-effect","title":"Frequency Sweep Effect","text":"
void playSweepSound() {\n    auto& audio = engine.getAudioEngine();\n\n    // Create multiple events for sweep effect\n    for (int i = 0; i < 5; i++) {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 400.0f + (i * 200.0f);  // Sweep from 400 to 1200 Hz\n        evt.duration = 0.05f;\n        evt.volume = 0.6f;\n        evt.duty = 0.5f;\n\n        audio.playEvent(evt);\n        delay(50);  // Small delay between events\n    }\n}\n
"},{"location":"api_reference/audio/audio_types/#performance-considerations","title":"Performance Considerations","text":"
  • Event creation: Creating events is fast (just struct initialization)
  • Channel allocation: Events are queued and played when channels are available
  • Frequency range: Keep frequencies in reasonable range (100-5000 Hz) for best results
  • Duration: Shorter durations free channels faster
"},{"location":"api_reference/audio/audio_types/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Events are small structs, safe to create frequently
  • CPU: Audio generation is efficient but limit simultaneous sounds
  • Quality: Lower sample rates reduce CPU usage
"},{"location":"api_reference/audio/audio_types/#see-also","title":"See Also","text":"
  • AudioEngine - Audio playback engine
  • AudioConfig - Audio configuration
  • Manual - Audio
  • API Overview
"},{"location":"api_reference/audio/music_player/","title":"MusicPlayer","text":"

Lightweight sequencer built on top of AudioEngine to play background melodies as tracks.

"},{"location":"api_reference/audio/music_player/#description","title":"Description","text":"

MusicPlayer is a simple sequencer that plays MusicTrack structures. It advances notes based on game time, converts MusicNote entries to AudioEvent calls, and manages playback state (play, stop, pause, resume).

The player uses one audio channel (typically a Pulse channel) for music, leaving other channels available for sound effects.

"},{"location":"api_reference/audio/music_player/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    class MusicPlayer {\n        // ...\n    };\n}\n
"},{"location":"api_reference/audio/music_player/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages music player instance)
"},{"location":"api_reference/audio/music_player/#constructors","title":"Constructors","text":""},{"location":"api_reference/audio/music_player/#musicplayeraudioengine-engine","title":"MusicPlayer(AudioEngine& engine)","text":"

Constructs the MusicPlayer.

Parameters: - engine (AudioEngine&): Reference to the AudioEngine used to play sounds

Notes: - Typically created and managed by Engine - Access via engine.getMusicPlayer()

Example:

auto& audio = engine.getAudioEngine();\npixelroot32::audio::MusicPlayer musicPlayer(audio);\n

"},{"location":"api_reference/audio/music_player/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/audio/music_player/#void-playconst-musictrack-track","title":"void play(const MusicTrack& track)","text":"

Starts playing a track.

Parameters: - track (const MusicTrack&): The track to play

Returns: - void

Notes: - Stops any currently playing track - Starts from the beginning of the track - If track has loop = true, will loop automatically - Uses one audio channel (typically Pulse)

Example:

static const MusicNote MELODY[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),\n};\n\nstatic const MusicTrack GAME_MUSIC = {\n    MELODY,\n    sizeof(MELODY) / sizeof(MusicNote),\n    true,  // loop\n    WaveType::PULSE,\n    0.5f   // volume\n};\n\nvoid init() override {\n    auto& music = engine.getMusicPlayer();\n    music.play(GAME_MUSIC);\n}\n

"},{"location":"api_reference/audio/music_player/#void-stop","title":"void stop()","text":"

Stops playback and silences the channel.

Returns: - void

Notes: - Immediately stops the current note - Resets playback to the beginning - Channel is freed for other use

Example:

void onGameOver() {\n    auto& music = engine.getMusicPlayer();\n    music.stop();\n}\n

"},{"location":"api_reference/audio/music_player/#void-pause","title":"void pause()","text":"

Pauses playback.

Returns: - void

Notes: - Current note continues until it ends, then playback pauses - Playback state is preserved (can resume from where it paused) - Use for pause menus

Example:

void onPause() {\n    auto& music = engine.getMusicPlayer();\n    music.pause();\n}\n

"},{"location":"api_reference/audio/music_player/#void-resume","title":"void resume()","text":"

Resumes playback.

Returns: - void

Notes: - Only works if playback was paused - Resumes from where it was paused - Use to unpause after pause menu

Example:

void onResume() {\n    auto& music = engine.getMusicPlayer();\n    music.resume();\n}\n

"},{"location":"api_reference/audio/music_player/#void-updateunsigned-long-deltatime","title":"void update(unsigned long deltaTime)","text":"

Updates the player state. Should be called every frame.

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Returns: - void

Notes: - Must be called every frame for proper timing - Advances note playback based on elapsed time - Automatically plays next notes in sequence - Typically called automatically by Engine

Example:

// Called automatically by Engine, but can be called manually:\nvoid update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);\n\n    // Music player is updated automatically by Engine\n    // No need to call manually\n}\n

"},{"location":"api_reference/audio/music_player/#bool-isplaying-const","title":"bool isPlaying() const","text":"

Checks if a track is currently playing.

Returns: - bool: true if playing, false otherwise

Notes: - Returns false if stopped or paused - Use to check playback state before operations

Example:

auto& music = engine.getMusicPlayer();\nif (music.isPlaying()) {\n    // Music is active\n} else {\n    // Music is stopped or paused\n}\n

"},{"location":"api_reference/audio/music_player/#void-settempofactorfloat-factor","title":"void setTempoFactor(float factor)","text":"

Sets the global tempo scaling factor.

Parameters: - factor (float): Tempo multiplier - 1.0f: Normal speed - 2.0f: Double speed - 0.5f: Half speed

Returns: - void

Notes: - Affects all note durations - Useful for speed-up effects or slow-motion - Applied to all tracks

Example:

auto& music = engine.getMusicPlayer();\nmusic.setTempoFactor(1.5f);  // 50% faster\nmusic.setTempoFactor(0.5f);   // 50% slower\nmusic.setTempoFactor(1.0f);   // Normal speed\n

"},{"location":"api_reference/audio/music_player/#float-gettempofactor-const","title":"float getTempoFactor() const","text":"

Gets the current tempo scaling factor.

Returns: - float: Current factor (default 1.0f)

Example:

float currentTempo = musicPlayer.getTempoFactor();\n

"},{"location":"api_reference/audio/music_player/#musictrack-structure","title":"MusicTrack Structure","text":"

A MusicTrack contains:

  • notes (const MusicNote*): Array of music notes
  • noteCount (size_t): Number of notes in the array
  • loop (bool): Whether to loop the track
  • waveType (WaveType): Wave type to use (typically PULSE)
  • volume (float): Volume level (0.0 to 1.0)
"},{"location":"api_reference/audio/music_player/#musicnote-structure","title":"MusicNote Structure","text":"

A MusicNote contains:

  • instrument (InstrumentPreset): Instrument preset to use
  • note (Note): Musical note (C, D, E, etc.)
  • duration (float): Duration in seconds

Use helper functions: - makeNote(instrument, note, duration): Create a note - makeRest(duration): Create a rest (silence)

"},{"location":"api_reference/audio/music_player/#usage-example","title":"Usage Example","text":"
#include \"audio/MusicPlayer.h\"\n#include \"audio/AudioMusicTypes.h\"\n\nusing namespace pixelroot32::audio;\n\n// Define a simple melody\nstatic const MusicNote MAIN_THEME[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.25f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.25f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.1f),\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.5f),\n    makeRest(0.2f),\n};\n\nstatic const MusicTrack MAIN_THEME_TRACK = {\n    MAIN_THEME,\n    sizeof(MAIN_THEME) / sizeof(MusicNote),\n    true,           // loop\n    WaveType::PULSE,\n    0.6f            // volume\n};\n\nclass GameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Start background music\n        auto& music = engine.getMusicPlayer();\n        music.play(MAIN_THEME_TRACK);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Music updates automatically\n    }\n\n    void onPauseMenu() {\n        auto& music = engine.getMusicPlayer();\n        music.pause();\n    }\n\n    void onResumeGame() {\n        auto& music = engine.getMusicPlayer();\n        music.resume();\n    }\n\n    void onGameOver() {\n        auto& music = engine.getMusicPlayer();\n        music.stop();\n    }\n};\n
"},{"location":"api_reference/audio/music_player/#performance-considerations","title":"Performance Considerations","text":"
  • One channel: Music uses one channel, leaving others for sound effects
  • Update frequency: update() must be called every frame
  • Track size: Larger tracks use more memory (store in flash)
  • Tempo factor: Changing tempo is fast (just a multiplier)
"},{"location":"api_reference/audio/music_player/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store tracks in flash (const/constexpr) to save RAM
  • CPU: Music playback is lightweight (simple sequencing)
  • Channel conflict: Music and sound effects share channels; plan accordingly
"},{"location":"api_reference/audio/music_player/#see-also","title":"See Also","text":"
  • AudioEngine - Audio playback engine
  • AudioTypes - Audio data structures
  • AudioMusicTypes - Music data structures
  • Manual - Audio
  • API Overview
"},{"location":"api_reference/core/actor/","title":"Actor","text":"

An Entity capable of physical interaction and collision.

"},{"location":"api_reference/core/actor/#description","title":"Description","text":"

Actor extends Entity with collision layers and masks. Actors are used for dynamic game objects like players, enemies, projectiles, and obstacles that need to interact with each other through collision detection.

Actors participate in the collision system and can detect collisions with other actors based on their collision layers and masks.

"},{"location":"api_reference/core/actor/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Actor : public Entity {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/actor/#inheritance","title":"Inheritance","text":"
  • Inherits from: Entity
  • Inherited by: PhysicsActor and your custom actor classes
"},{"location":"api_reference/core/actor/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/actor/#actorfloat-x-float-y-int-w-int-h","title":"Actor(float x, float y, int w, int h)","text":"

Creates a new actor with specified position and size.

Parameters: - x (float): Initial X position in world space - y (float): Initial Y position in world space - w (int): Actor width in pixels - h (int): Actor height in pixels

Notes: - Actor type is automatically set to EntityType::ACTOR - Collision layer and mask default to DefaultLayers::kNone - Must set collision layer and mask for collision detection to work

Example:

class PlayerActor : public pixelroot32::core::Actor {\npublic:\n    PlayerActor(float x, float y) \n        : Actor(x, y, 16, 16) {\n        // Set collision layer and mask\n        layer = pixelroot32::physics::DefaultLayers::kPlayer;\n        mask = pixelroot32::physics::DefaultLayers::kEnemy | \n               pixelroot32::physics::DefaultLayers::kObstacle;\n    }\n\n    void update(unsigned long deltaTime) override {\n        Actor::update(deltaTime);\n        // Player logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawSprite(playerSprite, \n                           static_cast<int>(x), \n                           static_cast<int>(y), \n                           Color::White);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        // Handle collision\n    }\n};\n

"},{"location":"api_reference/core/actor/#public-properties","title":"Public Properties","text":""},{"location":"api_reference/core/actor/#collisionlayer-layer","title":"CollisionLayer layer","text":"

The collision layer this actor belongs to.

Type: pixelroot32::physics::CollisionLayer (uint16_t)

Access: Read-write

Default: DefaultLayers::kNone

Notes: - Defines which layer this actor is on - Use bit flags to assign multiple layers (e.g., kPlayer | kProjectile) - Only actors with matching layers in their mask will collide

Example:

actor->layer = pixelroot32::physics::DefaultLayers::kPlayer;\n

"},{"location":"api_reference/core/actor/#collisionlayer-mask","title":"CollisionLayer mask","text":"

The collision layers this actor interacts with.

Type: pixelroot32::physics::CollisionLayer (uint16_t)

Access: Read-write

Default: DefaultLayers::kNone

Notes: - Defines which layers this actor can collide with - Use bit flags to check multiple layers (e.g., kEnemy | kObstacle) - Collision only occurs if the other actor's layer matches bits in this mask

Example:

// Actor collides with enemies and obstacles\nactor->mask = pixelroot32::physics::DefaultLayers::kEnemy | \n              pixelroot32::physics::DefaultLayers::kObstacle;\n

"},{"location":"api_reference/core/actor/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/actor/#void-setcollisionlayercollisionlayer-l","title":"void setCollisionLayer(CollisionLayer l)","text":"

Sets the collision layer for this actor.

Parameters: - l (pixelroot32::physics::CollisionLayer): The layer to set

Returns: - void

Notes: - Equivalent to setting layer directly - Use bit flags for multiple layers

Example:

actor->setCollisionLayer(pixelroot32::physics::DefaultLayers::kPlayer);\n

"},{"location":"api_reference/core/actor/#void-setcollisionmaskcollisionlayer-m","title":"void setCollisionMask(CollisionLayer m)","text":"

Sets the collision mask for this actor.

Parameters: - m (pixelroot32::physics::CollisionLayer): The mask to set

Returns: - void

Notes: - Equivalent to setting mask directly - Use bit flags for multiple layers

Example:

actor->setCollisionMask(pixelroot32::physics::DefaultLayers::kEnemy | \n                        pixelroot32::physics::DefaultLayers::kObstacle);\n

"},{"location":"api_reference/core/actor/#bool-isinlayeruint16_t-targetlayer-const","title":"bool isInLayer(uint16_t targetLayer) const","text":"

Checks if the Actor belongs to a specific collision layer.

Parameters: - targetLayer (uint16_t): The bit(s) to check (e.g., DefaultLayers::kPlayer)

Returns: - bool: true if the bit is set in the actor's layer

Notes: - Uses bitwise AND operation - Useful for checking if an actor is on a specific layer

Example:

if (actor->isInLayer(pixelroot32::physics::DefaultLayers::kPlayer)) {\n    // This is a player actor\n}\n

"},{"location":"api_reference/core/actor/#virtual-rect-gethitbox-0","title":"virtual Rect getHitBox() = 0","text":"

Gets the hitbox for collision detection. Must be implemented by derived classes.

Returns: - Rect: A rectangle representing the collision bounds

Notes: - Called by the collision system to check collisions - Should return the actual collision bounds (may differ from visual size) - Use AABB (Axis-Aligned Bounding Box) for efficiency

Example:

Rect getHitBox() override {\n    // Return collision bounds (may be smaller than visual)\n    return {x + 2, y + 2, width - 4, height - 4};\n}\n

"},{"location":"api_reference/core/actor/#virtual-void-oncollisionactor-other-0","title":"virtual void onCollision(Actor* other) = 0","text":"

Callback invoked when a collision occurs. Must be implemented by derived classes.

Parameters: - other (Actor*): The actor that this actor collided with

Notes: - Called automatically by the collision system when a collision is detected - Both actors' onCollision() methods are called - Use to handle collision responses (damage, bouncing, etc.)

Example:

void onCollision(Actor* other) override {\n    // Check what we collided with\n    if (other->isInLayer(pixelroot32::physics::DefaultLayers::kEnemy)) {\n        // Take damage\n        health--;\n        if (health <= 0) {\n            isEnabled = false;\n        }\n    } else if (other->isInLayer(pixelroot32::physics::DefaultLayers::kCollectible)) {\n        // Collect item\n        score += 10;\n        other->isEnabled = false;  // Remove collectible\n    }\n}\n

"},{"location":"api_reference/core/actor/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the actor logic. Default implementation does nothing.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Override to implement actor-specific update logic - Called automatically by Scene if isEnabled is true - Use deltaTime for frame-rate independent movement

Example:

void update(unsigned long deltaTime) override {\n    Actor::update(deltaTime);  // Call base implementation\n\n    // Move actor\n    float speed = 100.0f;  // pixels per second\n    x += (speed * deltaTime) / 1000.0f;\n}\n

"},{"location":"api_reference/core/actor/#collision-layers","title":"Collision Layers","text":"

Collision layers use bit flags to organize actors into groups. Common layers:

  • DefaultLayers::kNone (0): No layer
  • DefaultLayers::kPlayer (1 << 0): Player actors
  • DefaultLayers::kEnemy (1 << 1): Enemy actors
  • DefaultLayers::kObstacle (1 << 2): Obstacles/walls
  • DefaultLayers::kProjectile (1 << 3): Projectiles
  • DefaultLayers::kCollectible (1 << 4): Collectible items

Example:

// Player collides with enemies and obstacles\nplayer->layer = DefaultLayers::kPlayer;\nplayer->mask = DefaultLayers::kEnemy | DefaultLayers::kObstacle;\n\n// Enemy collides with player and obstacles\nenemy->layer = DefaultLayers::kEnemy;\nenemy->mask = DefaultLayers::kPlayer | DefaultLayers::kObstacle;\n\n// Projectile collides with enemies\nprojectile->layer = DefaultLayers::kProjectile;\nprojectile->mask = DefaultLayers::kEnemy;\n

"},{"location":"api_reference/core/actor/#usage-example","title":"Usage Example","text":"
#include \"core/Actor.h\"\n#include \"physics/CollisionTypes.h\"\n\nclass EnemyActor : public pixelroot32::core::Actor {\nprivate:\n    const pixelroot32::graphics::Sprite* sprite;\n    int health = 3;\n\npublic:\n    EnemyActor(float x, float y) \n        : Actor(x, y, 16, 16),\n          sprite(&enemySprite) {\n        // Set collision layer and mask\n        layer = pixelroot32::physics::DefaultLayers::kEnemy;\n        mask = pixelroot32::physics::DefaultLayers::kPlayer | \n               pixelroot32::physics::DefaultLayers::kProjectile;\n    }\n\n    void update(unsigned long deltaTime) override {\n        Actor::update(deltaTime);\n\n        // Move towards player\n        float speed = 50.0f;\n        // ... movement logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawSprite(*sprite, \n                           static_cast<int>(x), \n                           static_cast<int>(y), \n                           Color::Red);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        if (other->isInLayer(pixelroot32::physics::DefaultLayers::kProjectile)) {\n            // Hit by projectile\n            health--;\n            if (health <= 0) {\n                isEnabled = false;  // Remove enemy\n            }\n        }\n    }\n};\n
"},{"location":"api_reference/core/actor/#performance-considerations","title":"Performance Considerations","text":"
  • Collision layers: Use layers efficiently to reduce collision checks
  • Hitbox size: Keep hitboxes simple (AABB) for best performance
  • Collision callbacks: Keep onCollision() fast; avoid expensive operations
  • Layer organization: Group actors by layer to minimize checks
"},{"location":"api_reference/core/actor/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Collision checks: Collision system automatically optimizes using layers
  • Memory: Each actor consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse actors instead of creating/destroying frequently
"},{"location":"api_reference/core/actor/#see-also","title":"See Also","text":"
  • Entity - Base entity class
  • PhysicsActor - Entity with physics
  • CollisionSystem - Collision detection
  • CollisionTypes - Collision layer definitions
  • Manual - Scenes and Entities
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/core/engine/","title":"Engine","text":"

The main engine class that manages the game loop and core subsystems.

"},{"location":"api_reference/core/engine/#description","title":"Description","text":"

Engine acts as the central hub of the PixelRoot32 game engine. It initializes and manages the Renderer, InputManager, AudioEngine, and SceneManager. It runs the main game loop, handling timing (delta time), updating the current scene, and rendering frames.

The engine provides a unified interface for both ESP32 and Native (SDL2) platforms, abstracting platform-specific details while maintaining consistent behavior.

"},{"location":"api_reference/core/engine/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Engine {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/engine/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Application entry point (main.cpp)
"},{"location":"api_reference/core/engine/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/engine/#engineconst-displayconfig-displayconfig-const-inputconfig-inputconfig-const-audioconfig-audioconfig","title":"Engine(const DisplayConfig& displayConfig, const InputConfig& inputConfig, const AudioConfig& audioConfig)","text":"

Creates a new engine instance with custom display, input, and audio configurations.

Parameters: - displayConfig (const pixelroot32::graphics::DisplayConfig&): Configuration settings for the display (width, height, rotation, etc.) - inputConfig (const pixelroot32::input::InputConfig&): Configuration settings for the input system (pins, buttons) - audioConfig (const pixelroot32::audio::AudioConfig&): Configuration settings for the audio system (backend, sample rate, buffer size)

Example:

#include \"core/Engine.h\"\n#include \"graphics/DisplayConfig.h\"\n#include \"input/InputConfig.h\"\n#include \"audio/AudioConfig.h\"\n\npixelroot32::graphics::DisplayConfig displayConfig;\ndisplayConfig.width = 128;\ndisplayConfig.height = 128;\n\npixelroot32::input::InputConfig inputConfig;\n// Configure input pins...\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = pixelroot32::audio::AudioConfig::Backend::ESP32_DAC;\naudioConfig.sampleRate = 11025;\n\npixelroot32::core::Engine engine(displayConfig, inputConfig, audioConfig);\nengine.init();\nengine.run();\n

"},{"location":"api_reference/core/engine/#engineconst-displayconfig-displayconfig-const-inputconfig-inputconfig","title":"Engine(const DisplayConfig& displayConfig, const InputConfig& inputConfig)","text":"

Creates a new engine instance with custom display and input configurations, using default audio settings.

Parameters: - displayConfig (const pixelroot32::graphics::DisplayConfig&): Configuration settings for the display - inputConfig (const pixelroot32::input::InputConfig&): Configuration settings for the input system

Example:

pixelroot32::core::Engine engine(displayConfig, inputConfig);\nengine.init();\nengine.run();\n

"},{"location":"api_reference/core/engine/#engineconst-displayconfig-displayconfig","title":"Engine(const DisplayConfig& displayConfig)","text":"

Creates a new engine instance with custom display configuration and default input/audio settings.

Parameters: - displayConfig (const pixelroot32::graphics::DisplayConfig&): Configuration settings for the display

Example:

pixelroot32::core::Engine engine(displayConfig);\nengine.init();\nengine.run();\n

"},{"location":"api_reference/core/engine/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/engine/#void-init","title":"void init()","text":"

Initializes the engine subsystems. This method must be called before run().

Returns: - void

Notes: - Initializes the Renderer, InputManager, and sets up the initial state - Must be called after construction and before run() - Safe to call multiple times (idempotent)

Example:

Engine engine(displayConfig);\nengine.init();  // Initialize subsystems\nengine.setScene(myScene);\nengine.run();   // Start game loop\n

"},{"location":"api_reference/core/engine/#void-run","title":"void run()","text":"

Starts the main game loop. This method contains the infinite loop that calls update() and draw() repeatedly until the application exits.

Returns: - void

Notes: - This method blocks until the application exits - Handles frame timing and delta time calculation automatically - Calls update() and draw() once per frame - Do not call this method multiple times

Example:

Engine engine(displayConfig);\nengine.init();\nengine.setScene(myScene);\nengine.run();  // Blocks here, runs game loop\n

"},{"location":"api_reference/core/engine/#unsigned-long-getdeltatime-const","title":"unsigned long getDeltaTime() const","text":"

Gets the time elapsed since the last frame.

Returns: - unsigned long: The delta time in milliseconds

Performance Notes: - Very fast (inline accessor) - Safe to call every frame - Use this value to make movement frame-rate independent

Example:

void update(unsigned long deltaTime) override {\n    auto& engine = getEngine();\n    unsigned long dt = engine.getDeltaTime();\n\n    // Move at constant speed regardless of FPS\n    float speed = 100.0f;  // pixels per second\n    x += (speed * dt) / 1000.0f;\n}\n

"},{"location":"api_reference/core/engine/#void-setscenescene-newscene","title":"void setScene(Scene* newScene)","text":"

Sets the current active scene to be updated and rendered.

Parameters: - newScene (Scene*): Pointer to the new Scene to become active. Can be nullptr to clear the current scene.

Notes: - The previous scene is replaced (not pushed onto a stack) - Use SceneManager for push/pop operations if needed - The scene's init() method will be called automatically - Safe to call during the game loop

Example:

class MainMenuScene : public pixelroot32::core::Scene {\n    // ...\n};\n\nclass GameScene : public pixelroot32::core::Scene {\n    // ...\n};\n\nMainMenuScene menuScene;\nGameScene gameScene;\n\nEngine engine(displayConfig);\nengine.init();\nengine.setScene(&menuScene);  // Start with menu\nengine.run();\n

"},{"location":"api_reference/core/engine/#scene-getcurrentscene-const","title":"Scene* getCurrentScene() const","text":"

Retrieves the currently active scene.

Returns: - Scene*: Pointer to the current Scene, or nullptr if none is set

Example:

auto* currentScene = engine.getCurrentScene();\nif (currentScene) {\n    // Scene is active\n}\n

"},{"location":"api_reference/core/engine/#void-setrendererrenderer-newrenderer","title":"void setRenderer(Renderer& newRenderer)","text":"

Replaces the current renderer instance.

Parameters: - newRenderer (pixelroot32::graphics::Renderer&): Reference to the new Renderer to use

Notes: - Advanced usage: typically not needed unless implementing custom renderer - The renderer must be properly initialized before use - Use with caution: may break existing rendering code

"},{"location":"api_reference/core/engine/#renderer-getrenderer","title":"Renderer& getRenderer()","text":"

Provides access to the Renderer subsystem.

Returns: - pixelroot32::graphics::Renderer&: Reference to the current Renderer

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    auto& engineRenderer = engine.getRenderer();\n    engineRenderer.drawSprite(mySprite, 100, 100, Color::White);\n}\n

"},{"location":"api_reference/core/engine/#inputmanager-getinputmanager","title":"InputManager& getInputManager()","text":"

Provides access to the InputManager subsystem.

Returns: - pixelroot32::input::InputManager&: Reference to the InputManager

Example:

void update(unsigned long deltaTime) override {\n    auto& input = engine.getInputManager();\n    if (input.isButtonPressed(Buttons::A)) {\n        // Handle button press\n    }\n}\n

"},{"location":"api_reference/core/engine/#audioengine-getaudioengine","title":"AudioEngine& getAudioEngine()","text":"

Provides access to the AudioEngine subsystem.

Returns: - pixelroot32::audio::AudioEngine&: Reference to the AudioEngine

Example:

void playSound() {\n    auto& audio = engine.getAudioEngine();\n    pixelroot32::audio::AudioEvent sound{};\n    sound.type = pixelroot32::audio::WaveType::PULSE;\n    sound.frequency = 800.0f;\n    sound.duration = 0.1f;\n    audio.playEvent(sound);\n}\n

"},{"location":"api_reference/core/engine/#musicplayer-getmusicplayer","title":"MusicPlayer& getMusicPlayer()","text":"

Provides access to the MusicPlayer subsystem.

Returns: - pixelroot32::audio::MusicPlayer&: Reference to the MusicPlayer

Example:

void playMusic() {\n    auto& music = engine.getMusicPlayer();\n    music.playTrack(myMusicTrack);\n}\n

"},{"location":"api_reference/core/engine/#optional-fps-overlay","title":"Optional: FPS overlay","text":"

When the engine is built with the preprocessor define PIXELROOT32_ENABLE_FPS_DISPLAY, an on-screen FPS counter is drawn each frame.

Behavior:

  • A green text string \"FPS xxx\" is drawn in the top-right area (position from Renderer::getWidth() and a fixed Y offset).
  • The value is derived from frame delta time (FPS = 1000 / deltaTime ms), clamped to 0\u2013999.

Performance:

  • The numeric value is recalculated and formatted only every 8 frames; the cached string is drawn every frame to keep the overlay visible without extra per-frame cost (division and snprintf are done at most once every 8 frames).

How to enable:

In platformio.ini, add to your environment's build_flags:

build_flags =\n    -D PIXELROOT32_ENABLE_FPS_DISPLAY\n

No code changes are required; the overlay is drawn automatically after the scene in Engine::draw(). The implementation uses the private method drawFpsOverlay(Renderer& r), which is only compiled when the define is set.

See also: Performance Tuning - Profiling and Platforms and Drivers - Build flags.

"},{"location":"api_reference/core/engine/#usage-example","title":"Usage Example","text":"
#include \"core/Engine.h\"\n#include \"graphics/DisplayConfig.h\"\n#include \"MyScene.h\"\n\nvoid setup() {\n    // Configure display\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    displayConfig.width = 128;\n    displayConfig.height = 128;\n    displayConfig.rotation = 0;\n\n    // Create engine\n    pixelroot32::core::Engine engine(displayConfig);\n\n    // Initialize\n    engine.init();\n\n    // Create and set scene\n    MyScene myScene;\n    engine.setScene(&myScene);\n\n    // Run game loop\n    engine.run();\n}\n
"},{"location":"api_reference/core/engine/#performance-considerations","title":"Performance Considerations","text":"
  • Initialization: init() should be called once at startup, not in the game loop
  • Scene switching: Switching scenes is fast but avoid doing it every frame
  • Subsystem access: Getters are inline and very fast; safe to call every frame
  • Delta time: Use getDeltaTime() for frame-rate independent movement
"},{"location":"api_reference/core/engine/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Ensure init() completes before run() to avoid initialization issues
  • Monitor memory usage when switching scenes frequently
  • Use getDeltaTime() for consistent gameplay across different frame rates
"},{"location":"api_reference/core/engine/#see-also","title":"See Also","text":"
  • Scene - Scene management
  • Renderer - Rendering system
  • InputManager - Input handling
  • AudioEngine - Audio system
  • Getting Started - Fundamental Concepts
  • Manual - Scenes and Entities
  • API Overview
"},{"location":"api_reference/core/entity/","title":"Entity","text":"

Abstract base class for all game objects.

"},{"location":"api_reference/core/entity/#description","title":"Description","text":"

Entity is the fundamental building block of the scene. Entities have a position, size, and lifecycle methods (update, draw). All game objects inherit from Entity, including actors, UI elements, and custom game objects.

Entities are managed by Scene and are automatically updated and drawn each frame when enabled and visible.

"},{"location":"api_reference/core/entity/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Entity {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/entity/#inheritance","title":"Inheritance","text":"
  • Base class: None (abstract base class)
  • Inherited by: Actor, UI elements, and your custom entity classes
"},{"location":"api_reference/core/entity/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/entity/#entityfloat-x-float-y-int-w-int-h-entitytype-t","title":"Entity(float x, float y, int w, int h, EntityType t)","text":"

Creates a new entity with specified position, size, and type.

Parameters: - x (float): Initial X position in world space - y (float): Initial Y position in world space - w (int): Width in pixels - h (int): Height in pixels - t (EntityType): The type of entity (GENERIC, ACTOR, UI_ELEMENT)

Example:

class MyEntity : public pixelroot32::core::Entity {\npublic:\n    MyEntity(float x, float y) \n        : Entity(x, y, 16, 16, EntityType::GENERIC) {}\n\n    void update(unsigned long deltaTime) override {\n        // Update logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw logic\n    }\n};\n

"},{"location":"api_reference/core/entity/#public-properties","title":"Public Properties","text":""},{"location":"api_reference/core/entity/#float-x-y","title":"float x, y","text":"

Position of the entity in world space.

Type: float

Access: Read-write

Notes: - Position is in world coordinates, not screen coordinates - Can be modified directly or through helper methods - Use for entity positioning and movement

Example:

entity->x = 100.0f;\nentity->y = 50.0f;\n

"},{"location":"api_reference/core/entity/#int-width-height","title":"int width, height","text":"

Dimensions of the entity in pixels.

Type: int

Access: Read-write

Notes: - Used for collision detection, rendering bounds, and layout - Should match the visual size of the entity - Can be modified at runtime if needed

Example:

entity->width = 32;\nentity->height = 32;\n

"},{"location":"api_reference/core/entity/#entitytype-type","title":"EntityType type","text":"

The specific type of this entity.

Type: EntityType enum

Access: Read-only (set in constructor)

Values: - EntityType::GENERIC: Generic entity - EntityType::ACTOR: Actor entity (with collision) - EntityType::UI_ELEMENT: UI element

Notes: - Used for type-safe casting and logic differentiation - Set once in constructor, typically not changed

"},{"location":"api_reference/core/entity/#bool-isvisible","title":"bool isVisible","text":"

If false, the entity's draw() method will not be called.

Type: bool

Access: Read-write

Default: true

Notes: - Use to hide entities without removing them from the scene - More efficient than removing and re-adding entities - Useful for object pooling

Example:

entity->isVisible = false;  // Hide entity\nentity->setVisible(true);   // Show entity\n

"},{"location":"api_reference/core/entity/#bool-isenabled","title":"bool isEnabled","text":"

If false, the entity's update() method will not be called.

Type: bool

Access: Read-write

Default: true

Notes: - Use to disable entity logic without removing it - Entity still exists but doesn't update - Useful for paused entities or object pooling

Example:

entity->isEnabled = false;  // Disable updates\nentity->setEnabled(true);   // Enable updates\n

"},{"location":"api_reference/core/entity/#unsigned-char-renderlayer","title":"unsigned char renderLayer","text":"

The render layer this entity is drawn on.

Type: unsigned char

Access: Read-write

Default: 1

Notes: - Layers are drawn in ascending order (0 = background, 1 = gameplay, 2 = UI) - Entities on the same layer are drawn in add order - Use to control draw order without changing entity order

Example:

entity->renderLayer = 0;  // Background layer\nentity->setRenderLayer(2); // UI layer\n

"},{"location":"api_reference/core/entity/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/entity/#virtual-void-setvisiblebool-v","title":"virtual void setVisible(bool v)","text":"

Sets the visibility of the entity.

Parameters: - v (bool): true to show, false to hide

Returns: - void

Notes: - Equivalent to setting isVisible directly - Can be overridden for custom visibility logic

Example:

entity->setVisible(false);  // Hide\nentity->setVisible(true);   // Show\n

"},{"location":"api_reference/core/entity/#virtual-void-setenabledbool-e","title":"virtual void setEnabled(bool e)","text":"

Sets the enabled state of the entity.

Parameters: - e (bool): true to enable, false to disable

Returns: - void

Notes: - Equivalent to setting isEnabled directly - Can be overridden for custom enable logic

Example:

entity->setEnabled(false);  // Disable updates\nentity->setEnabled(true);   // Enable updates\n

"},{"location":"api_reference/core/entity/#unsigned-char-getrenderlayer-const","title":"unsigned char getRenderLayer() const","text":"

Gets the current render layer.

Returns: - unsigned char: The render layer (0-255)

Example:

unsigned char layer = entity->getRenderLayer();\n

"},{"location":"api_reference/core/entity/#virtual-void-setrenderlayerunsigned-char-layer","title":"virtual void setRenderLayer(unsigned char layer)","text":"

Sets the render layer for this entity.

Parameters: - layer (unsigned char): The render layer (0 = background, 1 = gameplay, 2 = UI)

Returns: - void

Example:

entity->setRenderLayer(0);  // Background\n

"},{"location":"api_reference/core/entity/#virtual-void-updateunsigned-long-deltatime-0","title":"virtual void update(unsigned long deltaTime) = 0","text":"

Updates the entity's logic. Must be implemented by derived classes.

Parameters: - deltaTime (unsigned long): Time elapsed since the last frame in milliseconds

Returns: - void

Notes: - Called automatically by Scene every frame if isEnabled is true - Use deltaTime for frame-rate independent movement - Override to implement entity-specific update logic

Example:

void update(unsigned long deltaTime) override {\n    // Move entity\n    float speed = 50.0f;  // pixels per second\n    x += (speed * deltaTime) / 1000.0f;\n\n    // Wrap around screen\n    if (x > 128) {\n        x = 0;\n    }\n}\n

"},{"location":"api_reference/core/entity/#virtual-void-drawrenderer-renderer-0","title":"virtual void draw(Renderer& renderer) = 0","text":"

Renders the entity. Must be implemented by derived classes.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer to use for drawing

Returns: - void

Notes: - Called automatically by Scene every frame if isVisible is true - Entities are drawn in render layer order, then in add order - Override to implement entity-specific drawing logic

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Draw sprite at entity position\n    renderer.drawSprite(mySprite, static_cast<int>(x), static_cast<int>(y), Color::White);\n}\n

"},{"location":"api_reference/core/entity/#entitytype-enum","title":"EntityType Enum","text":"

Categorizes entities for type-safe casting and logic differentiation.

Values: - EntityType::GENERIC: Generic entity (default) - EntityType::ACTOR: Actor entity (with collision support) - EntityType::UI_ELEMENT: UI element

Example:

if (entity->type == EntityType::ACTOR) {\n    Actor* actor = static_cast<Actor*>(entity);\n    // Use actor-specific methods\n}\n

"},{"location":"api_reference/core/entity/#rect-structure","title":"Rect Structure","text":"

Represents a 2D rectangle, typically used for hitboxes or bounds.

Members: - float x, y: Top-left corner coordinates - int width, height: Dimensions of the rectangle

Methods: - bool intersects(const Rect& other): Checks if this rectangle intersects with another

Example:

pixelroot32::core::Rect rect1{10.0f, 20.0f, 50, 50};\npixelroot32::core::Rect rect2{30.0f, 40.0f, 50, 50};\n\nif (rect1.intersects(rect2)) {\n    // Rectangles overlap\n}\n

"},{"location":"api_reference/core/entity/#usage-example","title":"Usage Example","text":"
#include \"core/Entity.h\"\n\nclass Collectible : public pixelroot32::core::Entity {\nprivate:\n    const pixelroot32::graphics::Sprite* sprite;\n\npublic:\n    Collectible(float x, float y) \n        : Entity(x, y, 8, 8, EntityType::GENERIC),\n          sprite(&collectibleSprite) {}\n\n    void update(unsigned long deltaTime) override {\n        // Rotate or animate\n        rotation += deltaTime * 0.001f;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        if (isVisible) {\n            renderer.drawSprite(*sprite, \n                               static_cast<int>(x), \n                               static_cast<int>(y), \n                               Color::Yellow);\n        }\n    }\n\nprivate:\n    float rotation = 0.0f;\n};\n
"},{"location":"api_reference/core/entity/#performance-considerations","title":"Performance Considerations","text":"
  • Visibility: Use isVisible = false instead of removing entities when hiding
  • Enable state: Use isEnabled = false to pause entity logic
  • Render layers: Organize entities by layer to minimize layer switches
  • Direct access: Direct property access is fast (no function call overhead)
"},{"location":"api_reference/core/entity/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Each entity consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse entities instead of creating/destroying frequently
  • Update frequency: Disable entities that don't need to update every frame
"},{"location":"api_reference/core/entity/#see-also","title":"See Also","text":"
  • Scene - Scene management
  • Actor - Entity with collision support
  • PhysicsActor - Entity with physics
  • Manual - Scenes and Entities
  • API Overview
"},{"location":"api_reference/core/input_config/","title":"InputConfig","text":"

Configuration structure for the InputManager.

"},{"location":"api_reference/core/input_config/#description","title":"Description","text":"

InputConfig defines the mapping between logical inputs and physical pins (ESP32) or keyboard keys (Native/SDL2). It uses variadic arguments to allow flexible configuration of any number of inputs.

The configuration is platform-specific: ESP32 uses GPIO pin numbers, while Native uses SDL keyboard scancodes.

"},{"location":"api_reference/core/input_config/#namespace","title":"Namespace","text":"
namespace pixelroot32::input {\n    struct InputConfig {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/input_config/#structure","title":"Structure","text":""},{"location":"api_reference/core/input_config/#int-count","title":"int count","text":"

Total number of configured inputs.

Type: int

Access: Read-write

Default: 0

Notes: - Must match the number of arguments provided to constructor - Determines the size of the internal button array

"},{"location":"api_reference/core/input_config/#int-inputpins-esp32-only","title":"int* inputPins (ESP32 only)","text":"

Array of GPIO pin numbers for ESP32.

Type: int*

Access: Read-write

Default: nullptr

Notes: - Only available on ESP32 platform - Array size equals count - Pin numbers correspond to ESP32 GPIO pins - Use nullptr if count is 0

Example:

// ESP32: 6 buttons on pins 0, 2, 4, 5, 18, 19\npixelroot32::input::InputConfig config(6, 0, 2, 4, 5, 18, 19);\n// config.inputPins[0] = 0  (Up)\n// config.inputPins[1] = 2  (Down)\n// config.inputPins[2] = 4  (Left)\n// config.inputPins[3] = 5  (Right)\n// config.inputPins[4] = 18 (Button A)\n// config.inputPins[5] = 19 (Button B)\n

"},{"location":"api_reference/core/input_config/#uint8_t-buttonnames-native-only","title":"uint8_t* buttonNames (Native only)","text":"

Array of button mappings (scancodes) for Native.

Type: uint8_t*

Access: Read-write

Default: nullptr

Notes: - Only available on Native platform - Array size equals count - Values are SDL keyboard scancodes - Use nullptr if count is 0

Example:

// Native: Map to keyboard keys\n#include <SDL2/SDL.h>\n\npixelroot32::input::InputConfig config(6,\n    SDL_SCANCODE_UP,    // Index 0\n    SDL_SCANCODE_DOWN,  // Index 1\n    SDL_SCANCODE_LEFT,  // Index 2\n    SDL_SCANCODE_RIGHT, // Index 3\n    SDL_SCANCODE_X,     // Index 4 (Button A)\n    SDL_SCANCODE_Z      // Index 5 (Button B)\n);\n

"},{"location":"api_reference/core/input_config/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/input_config/#inputconfigint-count","title":"InputConfig(int count, ...)","text":"

Constructs a new InputConfig with variadic arguments.

Parameters: - count (int): Number of inputs to configure - ... (variadic): Variable arguments list of pins (ESP32) or scancodes (Native)

Notes: - If count <= 0, configuration is empty (nullptr arrays) - Allocates arrays dynamically based on count - Arguments must match count in number - Platform-specific: ESP32 expects int (GPIO pins), Native expects int (SDL scancodes)

ESP32 Example:

// Configure 4 directional buttons\npixelroot32::input::InputConfig config(4, 0, 2, 4, 5);\n// Pin 0 = Up, Pin 2 = Down, Pin 4 = Left, Pin 5 = Right\n\n// Configure 6 buttons (4 directions + 2 action buttons)\npixelroot32::input::InputConfig config(6, 0, 2, 4, 5, 18, 19);\n

Native Example:

#include <SDL2/SDL.h>\n\n// Configure 4 directional buttons\npixelroot32::input::InputConfig config(4,\n    SDL_SCANCODE_UP,\n    SDL_SCANCODE_DOWN,\n    SDL_SCANCODE_LEFT,\n    SDL_SCANCODE_RIGHT\n);\n\n// Configure 6 buttons (4 directions + 2 action buttons)\npixelroot32::input::InputConfig config(6,\n    SDL_SCANCODE_UP,\n    SDL_SCANCODE_DOWN,\n    SDL_SCANCODE_LEFT,\n    SDL_SCANCODE_RIGHT,\n    SDL_SCANCODE_X,  // Button A\n    SDL_SCANCODE_Z   // Button B\n);\n

"},{"location":"api_reference/core/input_config/#usage-example","title":"Usage Example","text":""},{"location":"api_reference/core/input_config/#esp32-configuration","title":"ESP32 Configuration","text":"
#include \"input/InputConfig.h\"\n#include \"input/InputManager.h\"\n#include \"core/Engine.h\"\n\nvoid setup() {\n    // Configure input: 6 buttons\n    // Pins: Up=0, Down=2, Left=4, Right=5, A=18, B=19\n    pixelroot32::input::InputConfig inputConfig(6, 0, 2, 4, 5, 18, 19);\n\n    // Create input manager\n    pixelroot32::input::InputManager inputManager(inputConfig);\n    inputManager.init();\n\n    // Or use with Engine\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    pixelroot32::core::Engine engine(displayConfig, inputConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/core/input_config/#native-configuration","title":"Native Configuration","text":"
#include \"input/InputConfig.h\"\n#include <SDL2/SDL.h>\n\nvoid setup() {\n    // Configure input: 6 buttons mapped to keyboard\n    pixelroot32::input::InputConfig inputConfig(6,\n        SDL_SCANCODE_UP,    // Index 0: Up\n        SDL_SCANCODE_DOWN,  // Index 1: Down\n        SDL_SCANCODE_LEFT,  // Index 2: Left\n        SDL_SCANCODE_RIGHT, // Index 3: Right\n        SDL_SCANCODE_X,     // Index 4: Button A\n        SDL_SCANCODE_Z      // Index 5: Button B\n    );\n\n    // Use with Engine\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    pixelroot32::core::Engine engine(displayConfig, inputConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/core/input_config/#platform-agnostic-configuration","title":"Platform-Agnostic Configuration","text":"
#ifdef PLATFORM_ESP32\n    // ESP32: Use GPIO pins\n    pixelroot32::input::InputConfig inputConfig(6, 0, 2, 4, 5, 18, 19);\n#elif PLATFORM_NATIVE\n    // Native: Use SDL scancodes\n    #include <SDL2/SDL.h>\n    pixelroot32::input::InputConfig inputConfig(6,\n        SDL_SCANCODE_UP,\n        SDL_SCANCODE_DOWN,\n        SDL_SCANCODE_LEFT,\n        SDL_SCANCODE_RIGHT,\n        SDL_SCANCODE_X,\n        SDL_SCANCODE_Z\n    );\n#endif\n
"},{"location":"api_reference/core/input_config/#button-index-mapping","title":"Button Index Mapping","text":"

Button indices are determined by the order in the constructor:

Typical Convention: - Index 0: Up / Primary action - Index 1: Down / Secondary action - Index 2: Left - Index 3: Right - Index 4+: Additional buttons

Example:

// 4-button D-pad\nInputConfig config(4, UP_PIN, DOWN_PIN, LEFT_PIN, RIGHT_PIN);\n// Index 0 = Up, Index 1 = Down, Index 2 = Left, Index 3 = Right\n\n// 6-button setup (D-pad + 2 action buttons)\nInputConfig config(6, UP_PIN, DOWN_PIN, LEFT_PIN, RIGHT_PIN, A_PIN, B_PIN);\n// Index 0-3 = D-pad, Index 4 = A, Index 5 = B\n

"},{"location":"api_reference/core/input_config/#esp32-pin-considerations","title":"ESP32 Pin Considerations","text":"
  • GPIO pins: Use any available GPIO pin
  • Pull-up/pull-down: Configure resistors appropriately
  • Input mode: Pins are automatically configured as inputs
  • Restrictions: Some pins have special functions (check ESP32 datasheet)

Common Pin Choices: - GPIO 0, 2, 4, 5: Safe for buttons (watch for boot mode pins) - GPIO 18, 19: Good for additional buttons - Avoid: GPIO 6-11 (flash), GPIO 34-39 (input only, no pull-up)

"},{"location":"api_reference/core/input_config/#native-sdl-scancode-reference","title":"Native SDL Scancode Reference","text":"

Common SDL scancodes:

  • SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT: Arrow keys
  • SDL_SCANCODE_W, SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_D: WASD
  • SDL_SCANCODE_X, SDL_SCANCODE_Z: Common action buttons
  • SDL_SCANCODE_SPACE: Spacebar
  • SDL_SCANCODE_RETURN: Enter key

Example:

// WASD + Space + Enter\npixelroot32::input::InputConfig config(6,\n    SDL_SCANCODE_W,        // Up\n    SDL_SCANCODE_S,        // Down\n    SDL_SCANCODE_A,        // Left\n    SDL_SCANCODE_D,         // Right\n    SDL_SCANCODE_SPACE,    // Jump\n    SDL_SCANCODE_RETURN    // Action\n);\n

"},{"location":"api_reference/core/input_config/#performance-considerations","title":"Performance Considerations","text":"
  • Memory: Arrays are allocated dynamically (small overhead)
  • Configuration: Done once at startup, no runtime cost
  • Access: Button indices are fast (array access)
"},{"location":"api_reference/core/input_config/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Pin configuration: Ensure pins are not used by other peripherals
  • Debouncing: Hardware debouncing recommended for reliable input
  • Power: Buttons should use pull-up resistors to avoid floating pins
"},{"location":"api_reference/core/input_config/#see-also","title":"See Also","text":"
  • InputManager - Input handling
  • Engine - Engine that uses InputConfig
  • Manual - Input and Control
  • API Overview
"},{"location":"api_reference/core/input_manager/","title":"InputManager","text":"

Handles input from physical buttons or keyboard (on PC).

"},{"location":"api_reference/core/input_manager/#description","title":"Description","text":"

The InputManager polls configured pins (ESP32) or keyboard state (Native), handles debouncing, and tracks button states (Pressed, Released, Down, Clicked). It provides a unified input interface for both platforms.

The manager supports edge detection (just pressed/released) and continuous state (held down), making it suitable for both gameplay and UI navigation.

"},{"location":"api_reference/core/input_manager/#namespace","title":"Namespace","text":"
namespace pixelroot32::input {\n    class InputManager {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/input_manager/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages input manager instance)
"},{"location":"api_reference/core/input_manager/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/input_manager/#inputmanagerconst-inputconfig-config","title":"InputManager(const InputConfig& config)","text":"

Constructs the InputManager with a specific configuration.

Parameters: - config (const InputConfig&): The input configuration (pins, button count)

Example:

#include \"input/InputManager.h\"\n#include \"input/InputConfig.h\"\n\n// ESP32: Configure GPIO pins\npixelroot32::input::InputConfig inputConfig(6, 0, 2, 4, 5, 18, 19);\npixelroot32::input::InputManager inputManager(inputConfig);\ninputManager.init();\n\n// Native: Configure keyboard keys\n// (Configuration handled differently on Native)\n

"},{"location":"api_reference/core/input_manager/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/input_manager/#void-init","title":"void init()","text":"

Initializes the input pins.

Returns: - void

Notes: - Must be called after construction and before use - Configures GPIO pins (ESP32) or keyboard state (Native) - Safe to call multiple times (idempotent) - Typically called automatically by Engine::init()

Example:

InputManager inputManager(inputConfig);\ninputManager.init();  // Initialize before use\n

"},{"location":"api_reference/core/input_manager/#void-updateunsigned-long-dt","title":"void update(unsigned long dt)","text":"

Updates input state by polling hardware pins (ESP32) or keyboard state (Native).

Parameters: - dt (unsigned long): Delta time in milliseconds

Returns: - void

Notes: - Must be called every frame for proper input detection - Handles debouncing automatically - Updates button states and edge detection - Typically called automatically by Engine::update()

ESP32 Example:

void update(unsigned long deltaTime) override {\n    // Input is updated automatically by Engine\n    // Access input via engine.getInputManager()\n}\n

Native Example:

// On Native, update is called with keyboard state:\nvoid update(unsigned long dt, const uint8_t* keyboardState);\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttonpresseduint8_t-buttonindex-const","title":"bool isButtonPressed(uint8_t buttonIndex) const","text":"

Checks if a button was just pressed this frame.

Parameters: - buttonIndex (uint8_t): Index of the button to check (0-based)

Returns: - bool: true if the button transitioned from UP to DOWN this frame

Notes: - Returns true only on the frame the button was pressed - Useful for one-time actions (jump, shoot, menu select) - Resets automatically on next frame

Example:

auto& input = engine.getInputManager();\n\nif (input.isButtonPressed(0)) {  // Button A (index 0)\n    // Jump (only once per press)\n    player->jump();\n}\n\nif (input.isButtonPressed(1)) {  // Button B (index 1)\n    // Shoot (only once per press)\n    player->shoot();\n}\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttonreleaseduint8_t-buttonindex-const","title":"bool isButtonReleased(uint8_t buttonIndex) const","text":"

Checks if a button was just released this frame.

Parameters: - buttonIndex (uint8_t): Index of the button to check

Returns: - bool: true if the button transitioned from DOWN to UP this frame

Notes: - Returns true only on the frame the button was released - Useful for detecting button release events - Less commonly used than isButtonPressed()

Example:

auto& input = engine.getInputManager();\n\nif (input.isButtonReleased(0)) {\n    // Button A was just released\n    player->stopCharging();\n}\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttonclickeduint8_t-buttonindex-const","title":"bool isButtonClicked(uint8_t buttonIndex) const","text":"

Checks if a button was clicked (pressed and released).

Parameters: - buttonIndex (uint8_t): Index of the button to check

Returns: - bool: true if the button was clicked (pressed then released)

Notes: - Returns true when button is released after being pressed - Useful for UI buttons and menu selection - Detects complete press-release cycle

Example:

auto& input = engine.getInputManager();\n\nif (input.isButtonClicked(0)) {  // Button A clicked\n    // Select menu item\n    menu->select();\n}\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttondownuint8_t-buttonindex-const","title":"bool isButtonDown(uint8_t buttonIndex) const","text":"

Checks if a button is currently held down.

Parameters: - buttonIndex (uint8_t): Index of the button to check

Returns: - bool: true if the button is currently in the DOWN state

Notes: - Returns true for as long as the button is held - Useful for continuous actions (movement, charging) - Use with deltaTime for frame-rate independent movement

Example:

auto& input = engine.getInputManager();\n\nfloat speed = 100.0f;  // pixels per second\nfloat vx = 0.0f, vy = 0.0f;\n\nif (input.isButtonDown(2)) {  // Left button\n    vx = -speed;\n}\nif (input.isButtonDown(3)) {  // Right button\n    vx = speed;\n}\nif (input.isButtonDown(0)) {  // Up button\n    vy = -speed;\n}\nif (input.isButtonDown(1)) {  // Down button\n    vy = speed;\n}\n\n// Apply movement (frame-rate independent)\nx += (vx * deltaTime) / 1000.0f;\ny += (vy * deltaTime) / 1000.0f;\n

"},{"location":"api_reference/core/input_manager/#button-indices","title":"Button Indices","text":"

Button indices are defined by the order in InputConfig:

Typical Mapping: - 0: Up / Button A - 1: Down / Button B - 2: Left - 3: Right - 4: Additional button 1 - 5: Additional button 2

Example:

// Configure 6 buttons: Up, Down, Left, Right, A, B\npixelroot32::input::InputConfig inputConfig(6, \n    GPIO_UP,    // Index 0\n    GPIO_DOWN,  // Index 1\n    GPIO_LEFT,  // Index 2\n    GPIO_RIGHT, // Index 3\n    GPIO_A,     // Index 4\n    GPIO_B      // Index 5\n);\n\n// Use indices\nif (input.isButtonDown(2)) {  // Left\n    moveLeft();\n}\nif (input.isButtonPressed(4)) {  // A button\n    jump();\n}\n

"},{"location":"api_reference/core/input_manager/#usage-example","title":"Usage Example","text":"
#include \"input/InputManager.h\"\n#include \"core/Engine.h\"\n\nclass PlayerController {\nprivate:\n    pixelroot32::core::Engine& engine;\n\npublic:\n    PlayerController(pixelroot32::core::Engine& eng) : engine(eng) {}\n\n    void update(unsigned long deltaTime) {\n        auto& input = engine.getInputManager();\n\n        // Movement (continuous)\n        float speed = 150.0f;  // pixels per second\n        float vx = 0.0f, vy = 0.0f;\n\n        if (input.isButtonDown(3)) {  // Right\n            vx = speed;\n        }\n        if (input.isButtonDown(2)) {  // Left\n            vx = -speed;\n        }\n        if (input.isButtonDown(0)) {  // Up\n            vy = -speed;\n        }\n        if (input.isButtonDown(1)) {  // Down\n            vy = speed;\n        }\n\n        // Apply movement\n        playerX += (vx * deltaTime) / 1000.0f;\n        playerY += (vy * deltaTime) / 1000.0f;\n\n        // Actions (one-time)\n        if (input.isButtonPressed(4)) {  // A button\n            player->jump();\n        }\n\n        if (input.isButtonPressed(5)) {  // B button\n            player->shoot();\n        }\n    }\n};\n
"},{"location":"api_reference/core/input_manager/#input-state-comparison","title":"Input State Comparison","text":"Method Returns true when Use Case isButtonPressed() Button just pressed this frame One-time actions (jump, shoot) isButtonReleased() Button just released this frame Release events (stop charging) isButtonClicked() Button pressed then released UI buttons, menu selection isButtonDown() Button currently held Continuous actions (movement)"},{"location":"api_reference/core/input_manager/#performance-considerations","title":"Performance Considerations","text":"
  • Update frequency: update() must be called every frame
  • Debouncing: Handled automatically, no performance impact
  • State queries: All query methods are fast (inline accessors)
  • Memory: Button state arrays are small and efficient
"},{"location":"api_reference/core/input_manager/#esp32-considerations","title":"ESP32 Considerations","text":"
  • GPIO pins: Configure pins in InputConfig
  • Pull-up/pull-down: Ensure proper resistor configuration
  • Debouncing: Hardware debouncing recommended for noisy buttons
  • Pin limits: Some ESP32 pins have restrictions (check datasheet)
"},{"location":"api_reference/core/input_manager/#native-considerations","title":"Native Considerations","text":"
  • Keyboard mapping: Uses SDL scancodes
  • Key detection: Automatically handles keyboard state
  • Multiple keys: Can detect multiple keys simultaneously
"},{"location":"api_reference/core/input_manager/#see-also","title":"See Also","text":"
  • InputConfig - Input configuration
  • Engine - Engine that manages InputManager
  • Manual - Input and Control
  • API Overview
"},{"location":"api_reference/core/physics_actor/","title":"PhysicsActor","text":"

An actor with basic 2D physics properties.

"},{"location":"api_reference/core/physics_actor/#description","title":"Description","text":"

PhysicsActor extends the base Actor class by adding velocity, acceleration, friction, restitution (bounciness), and world boundary collision resolution. It is designed for objects that need to move and bounce within a defined area, such as balls, projectiles, or platformer characters.

PhysicsActor automatically handles: - Velocity-based movement - Friction application - World boundary collision and bouncing - Collision callbacks

"},{"location":"api_reference/core/physics_actor/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class PhysicsActor : public Actor {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/physics_actor/#inheritance","title":"Inheritance","text":"
  • Inherits from: Actor
  • Inherited by: Your custom physics-enabled actor classes
"},{"location":"api_reference/core/physics_actor/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/physics_actor/#physicsactorfloat-x-float-y-float-w-float-h","title":"PhysicsActor(float x, float y, float w, float h)","text":"

Creates a physics-enabled actor with specified position and size.

Parameters: - x (float): Initial X position in world space - y (float): Initial Y position in world space - w (float): Actor width in pixels - h (float): Actor height in pixels

Notes: - Velocity starts at (0, 0) - Restitution defaults to 1.0 (perfect bounce) - Friction defaults to 0.0 (no friction) - No world limits by default

Example:

class BallActor : public pixelroot32::core::PhysicsActor {\npublic:\n    BallActor(float x, float y) \n        : PhysicsActor(x, y, 8.0f, 8.0f) {\n        // Set physics properties\n        setRestitution(0.8f);  // 80% bounce\n        setFriction(0.1f);     // Small friction\n        setWorldSize(128, 128); // World bounds\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledCircle(static_cast<int>(x + width/2), \n                                 static_cast<int>(y + height/2), \n                                 width/2, \n                                 Color::White);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        // Bounce off other actors\n    }\n\n    void onWorldCollision() override {\n        // Play bounce sound\n    }\n};\n

"},{"location":"api_reference/core/physics_actor/#protected-properties","title":"Protected Properties","text":""},{"location":"api_reference/core/physics_actor/#float-vx-vy","title":"float vx, vy","text":"

Horizontal and vertical velocity components.

Type: float

Access: Protected (use setVelocity() to modify)

Default: 0.0f

Notes: - Velocity is in pixels per second - Automatically applied during update() - Modified by friction and world collisions

"},{"location":"api_reference/core/physics_actor/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/physics_actor/#void-setvelocityfloat-x-float-y","title":"void setVelocity(float x, float y)","text":"

Sets the linear velocity of the actor.

Parameters: - x (float): Horizontal velocity in pixels per second - y (float): Vertical velocity in pixels per second

Returns: - void

Notes: - Velocity is applied every frame during update() - Use for initial velocity or impulse-based movement - Can be called every frame for continuous control

Example:

// Set initial velocity\nphysicsActor->setVelocity(100.0f, -200.0f);  // Move right and up\n\n// Continuous control (e.g., player movement)\nvoid update(unsigned long deltaTime) override {\n    PhysicsActor::update(deltaTime);\n\n    float speed = 150.0f;\n    float vx = 0.0f, vy = 0.0f;\n\n    if (input.isButtonDown(Buttons::LEFT)) vx = -speed;\n    if (input.isButtonDown(Buttons::RIGHT)) vx = speed;\n    if (input.isButtonDown(Buttons::UP)) vy = -speed;\n    if (input.isButtonDown(Buttons::DOWN)) vy = speed;\n\n    setVelocity(vx, vy);\n}\n

"},{"location":"api_reference/core/physics_actor/#void-setrestitutionfloat-r","title":"void setRestitution(float r)","text":"

Sets the restitution (bounciness) of the actor.

Parameters: - r (float): Restitution value (0.0 to 1.0+) - 0.0: No bounce (stops on impact) - 1.0: Perfect bounce (no energy loss) - > 1.0: Energy gain (unrealistic but possible)

Returns: - void

Notes: - Applied when actor collides with world boundaries - Higher values = more bouncy - Typical values: 0.5-0.9 for realistic bouncing

Example:

ball->setRestitution(0.8f);  // 80% bounce\n

"},{"location":"api_reference/core/physics_actor/#void-setfrictionfloat-f","title":"void setFriction(float f)","text":"

Sets the friction coefficient.

Parameters: - f (float): Friction value - 0.0: No friction (object continues moving) - > 0.0: Friction applied to velocity each frame

Returns: - void

Notes: - Applied every frame to reduce velocity - Higher values = more friction (slower movement) - Typical values: 0.05-0.2 for smooth deceleration

Example:

player->setFriction(0.1f);  // Light friction\n

"},{"location":"api_reference/core/physics_actor/#void-setlimitslimitrect-limits","title":"void setLimits(LimitRect limits)","text":"

Sets custom movement limits for the actor.

Parameters: - limits (LimitRect): A rectangle defining the allowed area

Returns: - void

Notes: - Overrides world size limits - Use -1 for any boundary to disable that limit - Actor will bounce off these boundaries

Example:

pixelroot32::core::LimitRect limits;\nlimits.left = 0;\nlimits.top = 0;\nlimits.right = 128;\nlimits.bottom = 128;\nphysicsActor->setLimits(limits);\n

"},{"location":"api_reference/core/physics_actor/#void-setworldsizeint-width-int-height","title":"void setWorldSize(int width, int height)","text":"

Defines the world size for boundary checking.

Parameters: - width (int): Width of the world in pixels - height (int): Height of the world in pixels

Returns: - void

Notes: - Used as default limits if no custom LimitRect is provided - Actor will bounce off world boundaries - Set to display size for screen boundaries

Example:

physicsActor->setWorldSize(128, 128);  // Match display size\n

"},{"location":"api_reference/core/physics_actor/#worldcollisioninfo-getworldcollisioninfo-const","title":"WorldCollisionInfo getWorldCollisionInfo() const","text":"

Gets information about collisions with the world boundaries.

Returns: - WorldCollisionInfo: A struct containing collision flags (left, right, top, bottom)

Notes: - Updated every frame during update() - Use to detect which boundary was hit - Useful for sound effects or special behaviors

Example:

void update(unsigned long deltaTime) override {\n    PhysicsActor::update(deltaTime);\n\n    auto collision = getWorldCollisionInfo();\n    if (collision.left || collision.right) {\n        // Hit side wall\n        playSound(wallHitSound);\n    }\n    if (collision.top || collision.bottom) {\n        // Hit top or bottom\n        playSound(ceilingHitSound);\n    }\n}\n

"},{"location":"api_reference/core/physics_actor/#virtual-void-oncollisionactor-other-override","title":"virtual void onCollision(Actor* other) override","text":"

Callback triggered when this actor collides with another actor.

Parameters: - other (Actor*): Pointer to the actor involved in the collision

Returns: - void

Notes: - Called automatically by the collision system - Override to implement custom collision responses - Default implementation does nothing

Example:

void onCollision(Actor* other) override {\n    if (other->isInLayer(DefaultLayers::kEnemy)) {\n        // Bounce off enemy\n        vx = -vx * 0.5f;\n        vy = -vy * 0.5f;\n    }\n}\n

"},{"location":"api_reference/core/physics_actor/#virtual-void-onworldcollision","title":"virtual void onWorldCollision()","text":"

Callback triggered when this actor collides with world boundaries.

Returns: - void

Notes: - Called automatically when a world boundary collision occurs - Override to implement custom behavior (sound effects, particles, etc.) - Default implementation does nothing

Example:

void onWorldCollision() override {\n    // Play bounce sound\n    auto& audio = engine.getAudioEngine();\n    pixelroot32::audio::AudioEvent sound{};\n    sound.type = pixelroot32::audio::WaveType::NOISE;\n    sound.frequency = 500.0f;\n    sound.duration = 0.05f;\n    audio.playEvent(sound);\n\n    // Spawn particles\n    spawnBounceParticles();\n}\n

"},{"location":"api_reference/core/physics_actor/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the actor state. Applies physics integration and checks for world boundary collisions.

Parameters: - deltaTime (unsigned long): Time elapsed since the last frame in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Applies velocity to position - Applies friction to velocity - Resolves world boundary collisions - Override to add custom update logic, but call PhysicsActor::update(deltaTime) first

Example:

void update(unsigned long deltaTime) override {\n    // Apply physics\n    PhysicsActor::update(deltaTime);\n\n    // Custom logic\n    if (shouldApplyGravity) {\n        vy += gravity * (deltaTime / 1000.0f);\n    }\n}\n

"},{"location":"api_reference/core/physics_actor/#limitrect-structure","title":"LimitRect Structure","text":"

Bounding rectangle for world-collision resolution.

Members: - int left: Left boundary (-1 means no limit) - int top: Top boundary (-1 means no limit) - int right: Right boundary (-1 means no limit) - int bottom: Bottom boundary (-1 means no limit)

Methods: - int width() const: Calculates width (right - left) - int height() const: Calculates height (bottom - top)

Example:

pixelroot32::core::LimitRect limits(10, 10, 118, 118);  // 10px margin\nphysicsActor->setLimits(limits);\n

"},{"location":"api_reference/core/physics_actor/#worldcollisioninfo-structure","title":"WorldCollisionInfo Structure","text":"

Information about world collisions in the current frame.

Members: - bool left: True if collided with the left boundary - bool right: True if collided with the right boundary - bool top: True if collided with the top boundary - bool bottom: True if collided with the bottom boundary

Example:

auto collision = physicsActor->getWorldCollisionInfo();\nif (collision.bottom) {\n    // On ground\n    canJump = true;\n}\n

"},{"location":"api_reference/core/physics_actor/#usage-example","title":"Usage Example","text":"
#include \"core/PhysicsActor.h\"\n\nclass BouncingBall : public pixelroot32::core::PhysicsActor {\npublic:\n    BouncingBall(float x, float y) \n        : PhysicsActor(x, y, 8.0f, 8.0f) {\n        // Set physics properties\n        setRestitution(0.9f);  // Very bouncy\n        setFriction(0.05f);    // Light friction\n        setWorldSize(128, 128);\n\n        // Set initial velocity\n        setVelocity(100.0f, -150.0f);\n\n        // Set collision layer\n        layer = pixelroot32::physics::DefaultLayers::kProjectile;\n        mask = pixelroot32::physics::DefaultLayers::kObstacle;\n    }\n\n    void update(unsigned long deltaTime) override {\n        PhysicsActor::update(deltaTime);\n\n        // Apply gravity\n        vy += 200.0f * (deltaTime / 1000.0f);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledCircle(static_cast<int>(x + width/2), \n                                 static_cast<int>(y + height/2), \n                                 width/2, \n                                 Color::White);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        // Bounce off obstacles\n        vx = -vx * 0.8f;\n        vy = -vy * 0.8f;\n    }\n\n    void onWorldCollision() override {\n        // Play bounce sound\n        playBounceSound();\n    }\n};\n
"},{"location":"api_reference/core/physics_actor/#performance-considerations","title":"Performance Considerations","text":"
  • Physics integration: Very efficient (simple velocity integration)
  • World bounds: Boundary checks are fast (AABB)
  • Friction: Applied every frame; keep friction values reasonable
  • Collision callbacks: Keep onCollision() and onWorldCollision() fast
"},{"location":"api_reference/core/physics_actor/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Floating point: Uses float math; acceptable for ESP32 but integer math would be faster
  • Frame rate: Physics is frame-rate independent (uses deltaTime)
  • Memory: Each PhysicsActor consumes more memory than Actor (velocity, limits, etc.)
"},{"location":"api_reference/core/physics_actor/#see-also","title":"See Also","text":"
  • Actor - Base actor class
  • CollisionSystem - Collision detection
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/core/scene/","title":"Scene","text":"

Represents a game level or screen containing entities.

"},{"location":"api_reference/core/scene/#description","title":"Description","text":"

A Scene manages a collection of Entities and a CollisionSystem. It is responsible for updating and drawing all entities it contains. Scenes provide lifecycle hooks (init(), update(), draw()) to manage gameplay segments.

Scenes are the primary organizational unit in PixelRoot32, similar to levels or screens in other game engines. Each scene can contain up to MAX_ENTITIES (default 32; overridable via compiler flags) entities, and drawing uses up to MAX_LAYERS (default 3; overridable) render layers.

"},{"location":"api_reference/core/scene/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Scene {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/scene/#inheritance","title":"Inheritance","text":"
  • Base class: None (abstract base class)
  • Inherited by: Your custom scene classes (e.g., MainMenuScene, GameScene)
"},{"location":"api_reference/core/scene/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/scene/#scene_1","title":"Scene()","text":"

Creates an empty scene ready to be populated with entities.

Notes: - The scene starts with no entities - init() should be called when the scene becomes active - The collision system is automatically initialized

Example:

class MyScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Initialize scene resources\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);  // Update entities and collisions\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        Scene::draw(renderer);  // Draw all entities\n    }\n};\n

"},{"location":"api_reference/core/scene/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/scene/#virtual-void-init","title":"virtual void init()","text":"

Initializes the scene. Called when entering the scene.

Returns: - void

Notes: - Called automatically when the scene is set via Engine::setScene() - Override this method to initialize scene-specific resources - Safe to call multiple times (idempotent) - Add entities here or in the constructor

Example:

class GameScene : public pixelroot32::core::Scene {\nprivate:\n    PlayerActor* player;\n    std::array<EnemyActor*, 10> enemies;\n\npublic:\n    void init() override {\n        // Create player\n        player = new PlayerActor();\n        addEntity(player);\n\n        // Create enemies\n        for (int i = 0; i < 10; i++) {\n            enemies[i] = new EnemyActor();\n            addEntity(enemies[i]);\n        }\n    }\n};\n

"},{"location":"api_reference/core/scene/#virtual-void-updateunsigned-long-deltatime","title":"virtual void update(unsigned long deltaTime)","text":"

Updates all entities in the scene and handles collisions.

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Notes: - Called automatically by the engine every frame - Updates all entities in the scene - Processes collisions between actors - Override to add custom update logic, but call Scene::update(deltaTime) to maintain entity updates

Example:

void update(unsigned long deltaTime) override {\n    // Custom update logic\n    gameTimer += deltaTime;\n\n    // Update entities and collisions\n    Scene::update(deltaTime);\n\n    // Additional logic after entity updates\n    if (gameTimer > 60000) {\n        // Game over after 60 seconds\n    }\n}\n

"},{"location":"api_reference/core/scene/#virtual-void-drawrenderer-renderer","title":"virtual void draw(Renderer& renderer)","text":"

Draws all visible entities in the scene.

Parameters: - renderer (pixelroot32::graphics::Renderer&): The renderer to use for drawing

Notes: - Called automatically by the engine every frame after update() - Draws all visible entities in the scene - Override to add custom drawing logic, but call Scene::draw(renderer) to maintain entity rendering - Entities are drawn in the order they were added

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Draw background\n    renderer.drawTileMap(backgroundTileMap, 0, 0, Color::White);\n\n    // Draw all entities\n    Scene::draw(renderer);\n\n    // Draw UI overlay\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n}\n

"},{"location":"api_reference/core/scene/#void-addentityentity-entity","title":"void addEntity(Entity* entity)","text":"

Adds an entity to the scene.

Parameters: - entity (Entity*): Pointer to the Entity to add. Must not be nullptr.

Notes: - Entities are added to an internal queue - Maximum of MAX_ENTITIES (default 32; overridable) entities per scene - If the limit is reached, the entity may not be added (check return value if available) - Entities are updated and drawn in the order they were added - The entity's lifetime is managed by the scene (do not delete manually while in scene)

Example:

void init() override {\n    // Create and add player\n    PlayerActor* player = new PlayerActor();\n    player->setPosition(64, 64);\n    addEntity(player);\n\n    // Create and add enemy\n    EnemyActor* enemy = new EnemyActor();\n    enemy->setPosition(100, 100);\n    addEntity(enemy);\n}\n

"},{"location":"api_reference/core/scene/#void-removeentityentity-entity","title":"void removeEntity(Entity* entity)","text":"

Removes an entity from the scene.

Parameters: - entity (Entity*): Pointer to the Entity to remove

Notes: - The entity is removed from the update and draw queues - The entity is not deleted automatically (you must manage its lifetime) - Safe to call even if the entity is not in the scene - Consider using object pooling instead of frequent add/remove

Example:

void onEnemyDestroyed(EnemyActor* enemy) {\n    removeEntity(enemy);\n    // Return to pool or delete\n    enemyPool.returnToPool(enemy);\n}\n

"},{"location":"api_reference/core/scene/#void-clearentities","title":"void clearEntities()","text":"

Removes all entities from the scene.

Notes: - All entities are removed from the update and draw queues - Entities are not deleted automatically (you must manage their lifetimes) - Useful for scene cleanup or reset - Consider using object pooling to reuse entities

Example:

void reset() {\n    clearEntities();\n    // Return all entities to pool\n    for (auto* entity : entityPool) {\n        entityPool.returnToPool(entity);\n    }\n}\n

"},{"location":"api_reference/core/scene/#protected-members","title":"Protected Members","text":""},{"location":"api_reference/core/scene/#arduinoqueue-entities","title":"ArduinoQueue entities

Queue of entities in the scene. Accessible to derived classes for custom entity management.

Type: ArduinoQueue<Entity*>

Notes: - Maximum capacity: MAX_ENTITIES (default 32; overridable) - Direct access allows custom iteration or filtering - Use with caution: modifying while iterating may cause issues

","text":""},{"location":"api_reference/core/scene/#collisionsystem-collisionsystem","title":"CollisionSystem collisionSystem

System to handle collisions between actors. Accessible to derived classes for custom collision handling.

Type: pixelroot32::physics::CollisionSystem

Notes: - Automatically processes collisions between actors - Uses collision layers and masks for filtering - Can be accessed for custom collision queries

","text":""},{"location":"api_reference/core/scene/#overriding-scene-limits-max_layers-max_entities","title":"Overriding scene limits (MAX_LAYERS / MAX_ENTITIES)","text":"

The engine defines default limits in core/Scene.h: MAX_LAYERS (default 3) and MAX_ENTITIES (default 32). These are guarded with #ifndef, so you can override them from your project without modifying the engine.

ESP32 platform limitation

The default of 3 for MAX_LAYERS is due to ESP32 platform constraints (memory and draw-loop cost). On native/PC you can safely use a higher value; on ESP32, increasing it may affect performance or memory.

"},{"location":"api_reference/core/scene/#option-a-compiler-flags-recommended","title":"Option A: Compiler flags (recommended)

In your project (e.g. in platformio.ini), add the defines to build_flags for the environment you use:

build_flags =\n    -DMAX_LAYERS=5\n    -DMAX_ENTITIES=64\n

The compiler defines MAX_LAYERS and MAX_ENTITIES before processing any .cpp file. Because Scene.h uses #ifndef MAX_LAYERS / #ifndef MAX_ENTITIES, it will not redefine them and your values will be used.

Effect: - MAX_LAYERS: Number of render layers drawn in Scene::draw() (layer 0 = background, 1+ = sprite context). Increasing this allows more distinct draw layers (e.g. background, platforms, gameplay, foreground, UI). - MAX_ENTITIES: On Arduino, the capacity of the scene entity queue when constructed with this value. On native (mock queue), the value is ignored (unbounded).

See also: Platforms and Drivers - Scene limits.

","text":""},{"location":"api_reference/core/scene/#usage-example","title":"Usage Example","text":"
#include \"core/Scene.h\"\n#include \"core/Actor.h\"\n\nclass MyGameScene : public pixelroot32::core::Scene {\nprivate:\n    PlayerActor* player;\n\npublic:\n    void init() override {\n        // Create player\n        player = new PlayerActor();\n        player->setPosition(64, 64);\n        addEntity(player);\n\n        // Create some enemies\n        for (int i = 0; i < 5; i++) {\n            EnemyActor* enemy = new EnemyActor();\n            enemy->setPosition(10 + i * 20, 10);\n            addEntity(enemy);\n        }\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Custom game logic\n        if (player->isDead()) {\n            // Handle game over\n        }\n\n        // Update entities and collisions\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background\n        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n\n        // Draw all entities\n        Scene::draw(renderer);\n\n        // Draw HUD\n        char scoreText[32];\n        snprintf(scoreText, sizeof(scoreText), \"Score: %d\", score);\n        renderer.drawText(scoreText, 10, 10, Color::White, 1);\n    }\n};\n
"},{"location":"api_reference/core/scene/#performance-considerations","title":"Performance Considerations","text":"
  • Entity limit: MAX_ENTITIES (default 32) can be overridden via compiler flags; plan accordingly
  • Add/Remove: Frequent add/remove operations can be expensive; use object pooling
  • Update order: Entities are updated in add order; consider order for dependencies
  • Collision checks: CollisionSystem automatically handles actor collisions efficiently
"},{"location":"api_reference/core/scene/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Each entity consumes memory; stay well below the limit
  • Object pooling: Essential for ESP32 to avoid memory fragmentation
  • Scene switching: Clearing and recreating scenes can fragment memory; reuse scenes when possible
"},{"location":"api_reference/core/scene/#see-also","title":"See Also","text":"
  • Entity - Base entity class
  • Actor - Entity with collision support
  • PhysicsActor - Entity with physics
  • CollisionSystem - Collision detection
  • Manual - Scenes and Entities
  • API Overview
"},{"location":"api_reference/graphics/camera2d/","title":"Camera2D","text":"

2D camera for scrolling and viewport control.

"},{"location":"api_reference/graphics/camera2d/#description","title":"Description","text":"

Camera2D controls viewport position and enables scrolling by shifting the renderer's display offset. It supports following targets, boundary constraints, and can be used for parallax effects.

The camera uses a dead-zone system: it only moves when the target is outside a central zone, creating smooth following behavior.

"},{"location":"api_reference/graphics/camera2d/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    class Camera2D {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/camera2d/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Scenes (for scrolling and camera control)
"},{"location":"api_reference/graphics/camera2d/#constructors","title":"Constructors","text":""},{"location":"api_reference/graphics/camera2d/#camera2dint-viewportwidth-int-viewportheight","title":"Camera2D(int viewportWidth, int viewportHeight)","text":"

Creates a new camera with specified viewport dimensions.

Parameters: - viewportWidth (int): Width of the viewport in pixels - viewportHeight (int): Height of the viewport in pixels

Notes: - Viewport size should match display size - Camera position starts at (0, 0) - No boundaries set by default (camera can move anywhere)

Example:

#include \"graphics/Camera2D.h\"\n\n// Create camera matching display size\npixelroot32::graphics::Camera2D camera(128, 128);\n\n// Or get from renderer\nint width = renderer.getWidth();\nint height = renderer.getHeight();\npixelroot32::graphics::Camera2D camera(width, height);\n

"},{"location":"api_reference/graphics/camera2d/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/graphics/camera2d/#void-setpositionfloat-x-float-y","title":"void setPosition(float x, float y)","text":"

Sets the camera position directly.

Parameters: - x (float): X position in world space - y (float): Y position in world space

Returns: - void

Notes: - Position is clamped to boundaries if set - Use for direct camera control or cutscenes - Overrides any following behavior

Example:

camera.setPosition(100.0f, 200.0f);\n

"},{"location":"api_reference/graphics/camera2d/#void-setboundsfloat-minx-float-maxx","title":"void setBounds(float minX, float maxX)","text":"

Sets horizontal boundaries for the camera.

Parameters: - minX (float): Minimum X position - maxX (float): Maximum X position

Returns: - void

Notes: - Camera position is clamped to these bounds - Use to prevent camera from going outside level bounds - Set both horizontal and vertical bounds for full constraint

Example:

// Level is 512 pixels wide, camera viewport is 128\n// Prevent camera from showing outside level\ncamera.setBounds(0.0f, 512.0f - 128.0f);\n

"},{"location":"api_reference/graphics/camera2d/#void-setverticalboundsfloat-miny-float-maxy","title":"void setVerticalBounds(float minY, float maxY)","text":"

Sets vertical boundaries for the camera.

Parameters: - minY (float): Minimum Y position - maxY (float): Maximum Y position

Returns: - void

Notes: - Camera position is clamped to these bounds - Use to prevent camera from going outside level bounds vertically

Example:

// Level is 512 pixels tall, camera viewport is 128\ncamera.setVerticalBounds(0.0f, 512.0f - 128.0f);\n

"},{"location":"api_reference/graphics/camera2d/#void-followtargetfloat-targetx","title":"void followTarget(float targetX)","text":"

Makes the camera follow a target horizontally only.

Parameters: - targetX (float): X position of the target to follow

Returns: - void

Notes: - Camera follows target with dead-zone behavior - Only horizontal movement; vertical position unchanged - Useful for side-scrolling games

Example:

void update(unsigned long deltaTime) override {\n    // Update player position\n    player->update(deltaTime);\n\n    // Camera follows player horizontally\n    camera.followTarget(player->x);\n    camera.apply(renderer);\n}\n

"},{"location":"api_reference/graphics/camera2d/#void-followtargetfloat-targetx-float-targety","title":"void followTarget(float targetX, float targetY)","text":"

Makes the camera follow a target in both axes.

Parameters: - targetX (float): X position of the target to follow - targetY (float): Y position of the target to follow

Returns: - void

Notes: - Camera follows target with dead-zone behavior - Both horizontal and vertical following - Useful for top-down or platformer games

Example:

void update(unsigned long deltaTime) override {\n    player->update(deltaTime);\n\n    // Camera follows player in both axes\n    camera.followTarget(player->x, player->y);\n    camera.apply(renderer);\n}\n

"},{"location":"api_reference/graphics/camera2d/#float-getx-const","title":"float getX() const","text":"

Gets the current X position of the camera.

Returns: - float: Current X position in world space

Example:

float cameraX = camera.getX();\n

"},{"location":"api_reference/graphics/camera2d/#float-gety-const","title":"float getY() const","text":"

Gets the current Y position of the camera.

Returns: - float: Current Y position in world space

Example:

float cameraY = camera.getY();\n

"},{"location":"api_reference/graphics/camera2d/#void-applyrenderer-renderer-const","title":"void apply(Renderer& renderer) const","text":"

Applies the camera's offset to the renderer.

Parameters: - renderer (Renderer&): The renderer to apply the camera offset to

Returns: - void

Notes: - Sets the renderer's display offset based on camera position - Should be called before drawing world elements - Negative offset is applied (camera moves right = world moves left)

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera offset\n    camera.apply(renderer);\n\n    // Draw world (offset applied automatically)\n    renderer.drawTileMap(levelMap, 0, 0, Color::White);\n    renderer.drawSprite(playerSprite, playerX, playerY, Color::White);\n\n    // UI elements (not affected by camera)\n    renderer.setDisplayOffset(0, 0);  // Reset for UI\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n}\n

"},{"location":"api_reference/graphics/camera2d/#dead-zone-following","title":"Dead-Zone Following","text":"

The camera uses a dead-zone system for smooth following:

  • Dead zone: Central area where camera doesn't move
  • Following: Camera moves only when target leaves dead zone
  • Smooth: Creates natural, non-jarring camera movement

Example:

// Camera follows player with dead zone\nvoid update(unsigned long deltaTime) override {\n    player->update(deltaTime);\n\n    // Camera follows (dead zone handled internally)\n    camera.followTarget(player->x, player->y);\n}\n

"},{"location":"api_reference/graphics/camera2d/#usage-example","title":"Usage Example","text":"
#include \"graphics/Camera2D.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n    TileMap levelMap;\n\npublic:\n    void init() override {\n        // Create camera matching display size\n        auto& renderer = engine.getRenderer();\n        camera = pixelroot32::graphics::Camera2D(\n            renderer.getWidth(), \n            renderer.getHeight()\n        );\n\n        // Set level boundaries\n        // Level is 512x512, viewport is 128x128\n        camera.setBounds(0.0f, 512.0f - 128.0f);\n        camera.setVerticalBounds(0.0f, 512.0f - 128.0f);\n\n        // Create player\n        player = new PlayerActor(64, 64);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Camera follows player\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw world (camera offset applied)\n        renderer.drawTileMap(levelMap, 0, 0, Color::White);\n\n        // Draw entities (Scene::draw handles this)\n        Scene::draw(renderer);\n\n        // Reset offset for UI\n        renderer.setDisplayOffset(0, 0);\n        renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n    }\n};\n
"},{"location":"api_reference/graphics/camera2d/#parallax-scrolling","title":"Parallax Scrolling","text":"

Use multiple cameras or manual offset for parallax:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Background layer (slow parallax)\n    float bgOffsetX = camera.getX() * 0.5f;  // 50% speed\n    renderer.setDisplayOffset(-bgOffsetX, 0);\n    renderer.drawTileMap(backgroundMap, 0, 0, Color::White);\n\n    // Midground layer (normal speed)\n    camera.apply(renderer);\n    renderer.drawTileMap(midgroundMap, 0, 0, Color::White);\n\n    // Foreground (entities, normal speed)\n    Scene::draw(renderer);\n\n    // UI (no offset)\n    renderer.setDisplayOffset(0, 0);\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n}\n
"},{"location":"api_reference/graphics/camera2d/#performance-considerations","title":"Performance Considerations","text":"
  • Apply frequency: apply() is fast; safe to call every frame
  • Boundary checks: Boundary clamping is efficient
  • Following: Dead-zone calculations are lightweight
"},{"location":"api_reference/graphics/camera2d/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Float math: Uses floating point; acceptable but integer math would be faster
  • Memory: Camera is small (few floats); minimal memory usage
"},{"location":"api_reference/graphics/camera2d/#see-also","title":"See Also","text":"
  • Renderer - Rendering system
  • Manual - Cameras and Scrolling
  • API Overview
"},{"location":"api_reference/graphics/color/","title":"Color","text":"

Color constants and palette management system.

"},{"location":"api_reference/graphics/color/#description","title":"Description","text":"

The Color enum provides color constants that map to palette indices. The engine supports both legacy mode (single global palette) and dual palette mode (separate palettes for backgrounds and sprites).

Colors are resolved to 16-bit RGB565 values based on the active palette(s).

"},{"location":"api_reference/graphics/color/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    enum class Color : uint8_t {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/color/#color-enum-values","title":"Color Enum Values","text":""},{"location":"api_reference/graphics/color/#standard-colors-pr32-palette-indices","title":"Standard Colors (PR32 Palette Indices)","text":"
  • Color::Black (0)
  • Color::White (1)
  • Color::Navy (2)
  • Color::Blue (3)
  • Color::Cyan (4)
  • Color::DarkGreen (5)
  • Color::Green (6)
  • Color::LightGreen (7)
  • Color::Yellow (8)
  • Color::Orange (9)
  • Color::LightRed (10)
  • Color::Red (11)
  • Color::DarkRed (12)
  • Color::Purple (13)
  • Color::Magenta (14)
  • Color::Gray (15)
"},{"location":"api_reference/graphics/color/#color-aliases","title":"Color Aliases","text":"

For compatibility, several aliases map to the closest available color:

  • Color::DarkBlue \u2192 Navy
  • Color::LightBlue \u2192 Blue
  • Color::Teal \u2192 Cyan
  • Color::Olive \u2192 DarkGreen
  • Color::Gold \u2192 Yellow
  • Color::Brown \u2192 DarkRed
  • Color::Pink \u2192 Magenta
  • Color::LightPurple \u2192 Magenta
  • Color::Maroon \u2192 DarkRed
  • Color::MidGray \u2192 Gray
  • Color::LightGray \u2192 Gray
  • Color::DarkGray \u2192 Gray
  • Color::Silver \u2192 Gray
"},{"location":"api_reference/graphics/color/#special-colors","title":"Special Colors","text":"
  • Color::Transparent (255): Not a real color; must be handled by renderer (results in no-op)
  • Color::DebugRed \u2192 Red
  • Color::DebugGreen \u2192 Green
  • Color::DebugBlue \u2192 Blue
"},{"location":"api_reference/graphics/color/#palettetype-enum","title":"PaletteType Enum","text":"

Built-in palette types:

  • PaletteType::NES: NES color palette
  • PaletteType::GB: Game Boy (4 shades of green)
  • PaletteType::GBC: Game Boy Color palette
  • PaletteType::PICO8: PICO-8 palette
  • PaletteType::PR32: PixelRoot32 default palette
"},{"location":"api_reference/graphics/color/#palettecontext-enum","title":"PaletteContext Enum","text":"

Context for palette selection in dual palette mode:

  • PaletteContext::Background: For backgrounds, tilemaps, and background primitives
  • PaletteContext::Sprite: For sprites, characters, and gameplay elements
"},{"location":"api_reference/graphics/color/#palette-functions","title":"Palette Functions","text":""},{"location":"api_reference/graphics/color/#void-setpalettepalettetype-palette","title":"void setPalette(PaletteType palette)","text":"

Selects the active color palette (legacy mode). Sets both background and sprite palettes to the same value.

Parameters: - palette (PaletteType): The palette to use

Notes: - Does not enable dual palette mode - All rendering uses the same palette - Use for simple games with single palette

Example:

pixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n

"},{"location":"api_reference/graphics/color/#void-setcustompaletteconst-uint16_t-palette","title":"void setCustomPalette(const uint16_t* palette)","text":"

Sets a custom color palette (legacy mode). Sets both background and sprite palettes to the same value.

Parameters: - palette (const uint16_t*): Pointer to an array of 16 uint16_t RGB565 color values

Notes: - Array must remain valid (use static/global storage) - Engine does not copy the palette - Does not enable dual palette mode

Example:

static const uint16_t MY_PALETTE[16] = {\n    0x0000,  // Black\n    0xFFFF,  // White\n    0x001F,  // Blue\n    // ... 13 more colors\n};\n\npixelroot32::graphics::setCustomPalette(MY_PALETTE);\n

"},{"location":"api_reference/graphics/color/#void-enabledualpalettemodebool-enable","title":"void enableDualPaletteMode(bool enable)","text":"

Enables or disables dual palette mode.

Parameters: - enable (bool): true to enable dual palette mode, false for legacy mode

Notes: - When enabled: backgrounds and sprites use separate palettes - When disabled: single palette for all rendering (legacy mode)

Example:

pixelroot32::graphics::enableDualPaletteMode(true);\n

"},{"location":"api_reference/graphics/color/#void-setbackgroundpalettepalettetype-palette","title":"void setBackgroundPalette(PaletteType palette)","text":"

Sets the background palette (for backgrounds, tilemaps, etc.).

Parameters: - palette (PaletteType): The palette type to use for backgrounds

Notes: - Only used in dual palette mode - Affects tilemaps, background primitives, etc.

Example:

pixelroot32::graphics::enableDualPaletteMode(true);\npixelroot32::graphics::setBackgroundPalette(pixelroot32::graphics::PaletteType::NES);\n

"},{"location":"api_reference/graphics/color/#void-setspritepalettepalettetype-palette","title":"void setSpritePalette(PaletteType palette)","text":"

Sets the sprite palette (for sprites, characters, etc.).

Parameters: - palette (PaletteType): The palette type to use for sprites

Notes: - Only used in dual palette mode - Affects sprites, characters, gameplay elements

Example:

pixelroot32::graphics::setSpritePalette(pixelroot32::graphics::PaletteType::GB);\n

"},{"location":"api_reference/graphics/color/#void-setdualpalettepalettetype-bgpalette-palettetype-spritepalette","title":"void setDualPalette(PaletteType bgPalette, PaletteType spritePalette)","text":"

Sets both background and sprite palettes at once. Automatically enables dual palette mode.

Parameters: - bgPalette (PaletteType): The palette type to use for backgrounds - spritePalette (PaletteType): The palette type to use for sprites

Example:

pixelroot32::graphics::setDualPalette(\n    pixelroot32::graphics::PaletteType::NES,  // Background\n    pixelroot32::graphics::PaletteType::GB     // Sprites\n);\n

"},{"location":"api_reference/graphics/color/#void-setbackgroundcustompaletteconst-uint16_t-palette","title":"void setBackgroundCustomPalette(const uint16_t* palette)","text":"

Sets a custom background palette.

Parameters: - palette (const uint16_t*): Pointer to an array of 16 uint16_t RGB565 color values

Notes: - Array must remain valid (use static/global storage) - Only used in dual palette mode

Example:

static const uint16_t BG_PALETTE[16] = { /* ... */ };\npixelroot32::graphics::enableDualPaletteMode(true);\npixelroot32::graphics::setBackgroundCustomPalette(BG_PALETTE);\n

"},{"location":"api_reference/graphics/color/#void-setspritecustompaletteconst-uint16_t-palette","title":"void setSpriteCustomPalette(const uint16_t* palette)","text":"

Sets a custom sprite palette.

Parameters: - palette (const uint16_t*): Pointer to an array of 16 uint16_t RGB565 color values

Notes: - Array must remain valid (use static/global storage) - Only used in dual palette mode

Example:

static const uint16_t SPRITE_PALETTE[16] = { /* ... */ };\npixelroot32::graphics::setSpriteCustomPalette(SPRITE_PALETTE);\n

"},{"location":"api_reference/graphics/color/#void-setdualcustompaletteconst-uint16_t-bgpalette-const-uint16_t-spritepal","title":"void setDualCustomPalette(const uint16_t bgPalette, const uint16_t spritePal)","text":"

Sets both background and sprite custom palettes at once. Automatically enables dual palette mode.

Parameters: - bgPalette (const uint16_t): Pointer to background palette array (16 RGB565 values) - spritePal (const uint16_t): Pointer to sprite palette array (16 RGB565 values)

Example:

static const uint16_t BG_PAL[16] = { /* ... */ };\nstatic const uint16_t SPRITE_PAL[16] = { /* ... */ };\npixelroot32::graphics::setDualCustomPalette(BG_PAL, SPRITE_PAL);\n

"},{"location":"api_reference/graphics/color/#uint16_t-resolvecolorcolor-color","title":"uint16_t resolveColor(Color color)","text":"

Resolves a Color enum to its corresponding 16-bit color value (legacy mode).

Parameters: - color (Color): The Color enum value

Returns: - uint16_t: The 16-bit RGB565 color value

Notes: - Uses the current active palette (single palette mode) - Color::Transparent must not be resolved (handled by renderer) - Typically called internally by renderer

Example:

uint16_t rgb565 = pixelroot32::graphics::resolveColor(pixelroot32::graphics::Color::Red);\n

"},{"location":"api_reference/graphics/color/#uint16_t-resolvecolorcolor-color-palettecontext-context","title":"uint16_t resolveColor(Color color, PaletteContext context)","text":"

Resolves a Color enum with context (dual palette mode).

Parameters: - color (Color): The Color enum value - context (PaletteContext): The palette context (Background or Sprite)

Returns: - uint16_t: The 16-bit RGB565 color value

Notes: - Uses the appropriate palette based on context - In legacy mode, context is ignored - Color::Transparent must not be resolved

Example:

uint16_t bgColor = pixelroot32::graphics::resolveColor(\n    pixelroot32::graphics::Color::Blue,\n    pixelroot32::graphics::PaletteContext::Background\n);\n

"},{"location":"api_reference/graphics/color/#rgb565-format","title":"RGB565 Format","text":"

Colors are stored as 16-bit RGB565 values:

  • Bits 15-11: Red (5 bits, 0-31)
  • Bits 10-5: Green (6 bits, 0-63)
  • Bits 4-0: Blue (5 bits, 0-31)

Conversion Example:

// Convert RGB to RGB565\nuint16_t rgb565 = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\n

"},{"location":"api_reference/graphics/color/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/graphics/color/#legacy-mode-single-palette","title":"Legacy Mode (Single Palette)","text":"
// Set single palette for all rendering\npixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n\n// Use colors\nrenderer.drawSprite(sprite, 100, 100, pixelroot32::graphics::Color::Red);\nrenderer.drawFilledRectangle(10, 10, 50, 50, pixelroot32::graphics::Color::Blue);\n
"},{"location":"api_reference/graphics/color/#dual-palette-mode","title":"Dual Palette Mode","text":"
// Enable dual palette mode\npixelroot32::graphics::enableDualPaletteMode(true);\n\n// Set different palettes for backgrounds and sprites\npixelroot32::graphics::setBackgroundPalette(pixelroot32::graphics::PaletteType::NES);\npixelroot32::graphics::setSpritePalette(pixelroot32::graphics::PaletteType::GB);\n\n// Or use convenience function\npixelroot32::graphics::setDualPalette(\n    pixelroot32::graphics::PaletteType::NES,\n    pixelroot32::graphics::PaletteType::GB\n);\n
"},{"location":"api_reference/graphics/color/#custom-palettes","title":"Custom Palettes","text":"
// Define custom palette (RGB565 values)\nstatic const uint16_t CUSTOM_PALETTE[16] = {\n    0x0000,  // 0: Black\n    0xFFFF,  // 1: White\n    0x001F,  // 2: Blue\n    0x07E0,  // 3: Green\n    0xF800,  // 4: Red\n    // ... 11 more colors\n};\n\n// Use in legacy mode\npixelroot32::graphics::setCustomPalette(CUSTOM_PALETTE);\n\n// Or use in dual palette mode\npixelroot32::graphics::enableDualPaletteMode(true);\npixelroot32::graphics::setBackgroundCustomPalette(CUSTOM_PALETTE);\npixelroot32::graphics::setSpriteCustomPalette(CUSTOM_PALETTE);\n
"},{"location":"api_reference/graphics/color/#performance-considerations","title":"Performance Considerations","text":"
  • Color resolution: Fast lookup operation
  • Palette switching: Changing palettes is fast (just pointer assignment)
  • Memory: Palettes are stored in flash (const arrays) for best performance
  • Dual mode: Slightly more overhead than legacy mode, but minimal
"},{"location":"api_reference/graphics/color/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Flash storage: Store custom palettes in flash (const/constexpr)
  • Memory: Palettes are small (16 uint16_t = 32 bytes)
  • Palette switching: Avoid switching palettes every frame
"},{"location":"api_reference/graphics/color/#see-also","title":"See Also","text":"
  • Renderer - Rendering system
  • Manual - Color Palettes
  • API Overview
"},{"location":"api_reference/graphics/display_config/","title":"DisplayConfig","text":"

Configuration settings for initializing the display.

"},{"location":"api_reference/graphics/display_config/#description","title":"Description","text":"

DisplayConfig holds display parameters used by the renderer and camera to draw correctly on the target device. It defines the display type, dimensions, rotation, and creates the appropriate DrawSurface implementation for the platform.

"},{"location":"api_reference/graphics/display_config/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    struct DisplayConfig {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/display_config/#displaytype-enum","title":"DisplayType Enum","text":"

Supported display types:

  • DisplayType::ST7789: 240x240 TFT display
  • DisplayType::ST7735: 128x128 TFT display
  • DisplayType::NONE: For SDL2 native (no driver needed)
"},{"location":"api_reference/graphics/display_config/#structure","title":"Structure","text":""},{"location":"api_reference/graphics/display_config/#displaytype-type","title":"DisplayType type","text":"

The type of display.

Type: DisplayType enum

Access: Read-write

Notes: - Determines which driver to use (ESP32) - NONE for Native/SDL2 platform

"},{"location":"api_reference/graphics/display_config/#int-rotation","title":"int rotation","text":"

Display rotation in degrees.

Type: int

Access: Read-write

Default: 0

Notes: - Common values: 0, 90, 180, 270 - Rotation is applied during initialization - Some displays may not support all rotations

"},{"location":"api_reference/graphics/display_config/#uint16_t-width","title":"uint16_t width","text":"

Display width in pixels.

Type: uint16_t

Access: Read-write

Default: 240

Notes: - Should match actual display width - Used for viewport and camera calculations

"},{"location":"api_reference/graphics/display_config/#uint16_t-height","title":"uint16_t height","text":"

Display height in pixels.

Type: uint16_t

Access: Read-write

Default: 240

Notes: - Should match actual display height - Used for viewport and camera calculations

"},{"location":"api_reference/graphics/display_config/#int-xoffset","title":"int xOffset","text":"

X offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

"},{"location":"api_reference/graphics/display_config/#int-yoffset","title":"int yOffset","text":"

Y offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

"},{"location":"api_reference/graphics/display_config/#drawsurface-getdrawsurface-const","title":"DrawSurface& getDrawSurface() const","text":"

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed - Provides access to low-level display driver - Platform-specific implementation

"},{"location":"api_reference/graphics/display_config/#constructors","title":"Constructors","text":""},{"location":"api_reference/graphics/display_config/#displayconfigdisplaytype-type-const-int-rot-0-uint16_t-w-240-uint16_t-h-240-const-int-xoffset-0-const-int-yoffset-0","title":"DisplayConfig(DisplayType type, const int rot = 0, uint16_t w = 240, uint16_t h = 240, const int xOffset = 0, const int yOffset = 0)","text":"

Constructs a DisplayConfig with specified parameters.

Parameters: - type (DisplayType): The display type - rot (int, optional): Rotation in degrees. Default: 0 - w (uint16_t, optional): Width in pixels. Default: 240 - h (uint16_t, optional): Height in pixels. Default: 240 - xOffset (int, optional): X offset. Default: 0 - yOffset (int, optional): Y offset. Default: 0

Notes: - Automatically creates the appropriate DrawSurface for the platform - ESP32: Creates TFT_eSPI_Drawer based on display type - Native: Creates SDL2_Drawer

Example:

// ST7789 display, 240x240, no rotation\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7789\n);\n\n// ST7735 display, 128x128, rotated 90 degrees\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7735,\n    90,   // rotation\n    128,  // width\n    128   // height\n);\n\n// Native/SDL2 (no specific display type)\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::NONE,\n    0,    // rotation\n    128,  // width\n    128   // height\n);\n

"},{"location":"api_reference/graphics/display_config/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/graphics/display_config/#esp32-with-st7789","title":"ESP32 with ST7789","text":"
#ifdef PLATFORM_ESP32\n#include \"graphics/DisplayConfig.h\"\n\nvoid setup() {\n    // Configure ST7789 display (240x240)\n    pixelroot32::graphics::DisplayConfig displayConfig(\n        pixelroot32::graphics::DisplayType::ST7789,\n        0,    // rotation\n        240,  // width\n        240   // height\n    );\n\n    // Use with Engine\n    pixelroot32::core::Engine engine(displayConfig);\n    engine.init();\n    engine.run();\n}\n#endif\n
"},{"location":"api_reference/graphics/display_config/#esp32-with-st7735","title":"ESP32 with ST7735","text":"
#ifdef PLATFORM_ESP32\n    // Configure ST7735 display (128x128)\n    pixelroot32::graphics::DisplayConfig displayConfig(\n        pixelroot32::graphics::DisplayType::ST7735,\n        0,    // rotation\n        128,  // width\n        128   // height\n    );\n#endif\n
"},{"location":"api_reference/graphics/display_config/#nativesdl2","title":"Native/SDL2","text":"
#ifdef PLATFORM_NATIVE\n    // Native display (SDL2 window)\n    pixelroot32::graphics::DisplayConfig displayConfig(\n        pixelroot32::graphics::DisplayType::NONE,\n        0,    // rotation\n        128,  // width\n        128   // height\n    );\n#endif\n
"},{"location":"api_reference/graphics/display_config/#platform-agnostic-setup","title":"Platform-Agnostic Setup","text":"
#include \"graphics/DisplayConfig.h\"\n#include \"core/Engine.h\"\n\nvoid setup() {\n    pixelroot32::graphics::DisplayConfig displayConfig;\n\n    #ifdef PLATFORM_ESP32\n        displayConfig.type = pixelroot32::graphics::DisplayType::ST7789;\n        displayConfig.width = 240;\n        displayConfig.height = 240;\n    #elif PLATFORM_NATIVE\n        displayConfig.type = pixelroot32::graphics::DisplayType::NONE;\n        displayConfig.width = 128;\n        displayConfig.height = 128;\n    #endif\n\n    displayConfig.rotation = 0;\n\n    pixelroot32::core::Engine engine(displayConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/graphics/display_config/#display-type-details","title":"Display Type Details","text":""},{"location":"api_reference/graphics/display_config/#st7789","title":"ST7789","text":"
  • Resolution: Typically 240x240 or 240x320
  • Interface: SPI
  • Driver: TFT_eSPI
  • Common sizes: 240x240, 240x320
"},{"location":"api_reference/graphics/display_config/#st7735","title":"ST7735","text":"
  • Resolution: Typically 128x128 or 128x160
  • Interface: SPI
  • Driver: TFT_eSPI
  • Common sizes: 128x128, 128x160
"},{"location":"api_reference/graphics/display_config/#none-native","title":"NONE (Native)","text":"
  • Platform: Native/SDL2
  • Driver: SDL2_Drawer
  • Resolution: Configurable (any size)
  • Window: Creates SDL2 window
"},{"location":"api_reference/graphics/display_config/#rotation","title":"Rotation","text":"

Display rotation values:

  • 0: Normal orientation
  • 90: Rotated 90 degrees clockwise
  • 180: Rotated 180 degrees
  • 270: Rotated 90 degrees counter-clockwise

Notes: - Rotation affects coordinate system - Some displays may not support all rotations - Test rotation on your specific hardware

"},{"location":"api_reference/graphics/display_config/#performance-considerations","title":"Performance Considerations","text":"
  • Initialization: Display initialization happens once at startup
  • Driver selection: Automatic based on platform and type
  • Memory: DisplayConfig is small (few fields)
"},{"location":"api_reference/graphics/display_config/#esp32-considerations","title":"ESP32 Considerations","text":""},{"location":"api_reference/graphics/display_config/#tft_espi-configuration","title":"TFT_eSPI Configuration","text":"

DisplayConfig uses TFT_eSPI driver. Additional configuration may be needed in platformio.ini:

build_flags =\n    -DUSER_SETUP_LOADED=1\n    -DST7789_DRIVER=1\n    -DTFT_WIDTH=240\n    -DTFT_HEIGHT=240\n    # ... pin configuration\n
"},{"location":"api_reference/graphics/display_config/#pin-configuration","title":"Pin Configuration","text":"

GPIO pins must be configured separately (not in DisplayConfig):

  • MOSI: Data pin
  • SCLK: Clock pin
  • DC: Data/Command pin
  • RST: Reset pin
  • CS: Chip select pin (optional)
"},{"location":"api_reference/graphics/display_config/#see-also","title":"See Also","text":"
  • Renderer - Rendering system
  • Camera2D - Camera that uses display dimensions
  • Manual - Platforms and Drivers
  • API Overview
"},{"location":"api_reference/graphics/font/","title":"Font","text":"

Descriptor for a bitmap font using 1bpp sprites.

"},{"location":"api_reference/graphics/font/#description","title":"Description","text":"

A Font contains an array of Sprite structures, one for each character in the font's character set. Each glyph is rendered as a 1bpp sprite, allowing consistent rendering across platforms.

The font uses fixed-width glyphs for simplicity and performance. All glyphs share the same width and height, with spacing between characters controlled by the spacing field.

"},{"location":"api_reference/graphics/font/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    struct Font {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/font/#structure","title":"Structure","text":""},{"location":"api_reference/graphics/font/#const-sprite-glyphs","title":"const Sprite* glyphs","text":"

Array of sprites, one per character (indexed by character code - firstChar).

Type: const Sprite*

Access: Read-only

Notes: - Array must contain sprites for all characters from firstChar to lastChar - Each sprite represents one character glyph - Should be stored in flash (const/constexpr) for best performance

Example:

static const Sprite FONT_GLYPHS[] = {\n    spaceGlyph,    // Index 0 = ' ' (firstChar = 32)\n    exclamationGlyph, // Index 1 = '!'\n    // ... more glyphs\n};\n\nstatic const Font myFont = {\n    FONT_GLYPHS,\n    32,  // firstChar\n    126, // lastChar\n    5,   // glyphWidth\n    7,   // glyphHeight\n    1,   // spacing\n    8    // lineHeight\n};\n

"},{"location":"api_reference/graphics/font/#uint8_t-firstchar","title":"uint8_t firstChar","text":"

First character code in the font.

Type: uint8_t

Access: Read-only

Default: Typically 32 (space character)

Notes: - ASCII code of the first character - Common: 32 (space ' ') for ASCII fonts - Glyphs array starts at index 0 for this character

Example:

firstChar = 32;  // Starts at space character\n

"},{"location":"api_reference/graphics/font/#uint8_t-lastchar","title":"uint8_t lastChar","text":"

Last character code in the font.

Type: uint8_t

Access: Read-only

Default: Typically 126 (tilde '~')

Notes: - ASCII code of the last character - Common: 126 (tilde '~') for full ASCII fonts - Glyphs array must contain (lastChar - firstChar + 1) sprites

Example:

lastChar = 126;  // Ends at tilde character\n// Font contains characters 32-126 (95 characters)\n

"},{"location":"api_reference/graphics/font/#uint8_t-glyphwidth","title":"uint8_t glyphWidth","text":"

Fixed width of each glyph in pixels.

Type: uint8_t

Access: Read-only

Notes: - All glyphs must have the same width - Typical values: 5, 6, 8 pixels - Smaller = more characters per line, less readable

Example:

glyphWidth = 5;  // 5 pixels wide (like FONT_5X7)\n

"},{"location":"api_reference/graphics/font/#uint8_t-glyphheight","title":"uint8_t glyphHeight","text":"

Fixed height of each glyph in pixels.

Type: uint8_t

Access: Read-only

Notes: - All glyphs must have the same height - Typical values: 7, 8, 10 pixels - Smaller = more lines, less readable

Example:

glyphHeight = 7;  // 7 pixels tall (like FONT_5X7)\n

"},{"location":"api_reference/graphics/font/#uint8_t-spacing","title":"uint8_t spacing","text":"

Horizontal spacing between characters in pixels.

Type: uint8_t

Access: Read-only

Default: Typically 1

Notes: - Space added between characters - 0 = no spacing (characters touch) - 1 = 1 pixel gap (common) - Higher values = more readable but wider text

Example:

spacing = 1;  // 1 pixel between characters\n

"},{"location":"api_reference/graphics/font/#uint8_t-lineheight","title":"uint8_t lineHeight","text":"

Total line height including vertical spacing.

Type: uint8_t

Access: Read-only

Notes: - Should be glyphHeight + verticalSpacing - Used for line breaks and multi-line text - Typical: glyphHeight + 1 or glyphHeight + 2

Example:

lineHeight = 8;  // 7 pixel glyph + 1 pixel spacing\n

"},{"location":"api_reference/graphics/font/#built-in-fonts","title":"Built-in Fonts","text":""},{"location":"api_reference/graphics/font/#font_5x7","title":"FONT_5X7","text":"

Standard 5x7 pixel font (built-in).

Properties: - Width: 5 pixels - Height: 7 pixels - Characters: Typically ASCII 32-126 - Spacing: 1 pixel - Line height: 8 pixels

Usage:

#include \"graphics/Font.h\"\n\nrenderer.drawText(\"Hello\", 10, 10, Color::White, 1, &FONT_5X7);\n

"},{"location":"api_reference/graphics/font/#creating-custom-fonts","title":"Creating Custom Fonts","text":""},{"location":"api_reference/graphics/font/#step-1-create-glyph-sprites","title":"Step 1: Create Glyph Sprites","text":"
// Space character (ASCII 32)\nstatic const uint16_t SPACE_GLYPH[] = {\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000\n};\n\n// 'A' character (ASCII 65)\nstatic const uint16_t A_GLYPH[] = {\n    0b00100,\n    0b01010,\n    0b10001,\n    0b11111,\n    0b10001,\n    0b10001,\n    0b00000\n};\n\n// ... more glyphs\n
"},{"location":"api_reference/graphics/font/#step-2-create-glyph-array","title":"Step 2: Create Glyph Array","text":"
static const Sprite FONT_GLYPHS[] = {\n    {SPACE_GLYPH, 5, 7},  // Index 0 = ' ' (32)\n    // ... more glyphs\n    {A_GLYPH, 5, 7},      // Index 33 = 'A' (65)\n    // ... more glyphs\n};\n
"},{"location":"api_reference/graphics/font/#step-3-create-font-structure","title":"Step 3: Create Font Structure","text":"
static const Font MY_FONT = {\n    FONT_GLYPHS,  // glyphs array\n    32,           // firstChar (space)\n    126,          // lastChar (tilde)\n    5,            // glyphWidth\n    7,            // glyphHeight\n    1,            // spacing\n    8             // lineHeight\n};\n
"},{"location":"api_reference/graphics/font/#step-4-use-font","title":"Step 4: Use Font","text":"
renderer.drawText(\"Hello\", 10, 10, Color::White, 1, &MY_FONT);\n
"},{"location":"api_reference/graphics/font/#usage-example","title":"Usage Example","text":"
#include \"graphics/Font.h\"\n#include \"graphics/Renderer.h\"\n\n// Using built-in font\nvoid draw(Renderer& renderer) override {\n    // Default font\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n\n    // Explicit font\n    renderer.drawText(\"Score: 100\", 10, 30, Color::White, 1, &FONT_5X7);\n\n    // Centered text with font\n    renderer.drawTextCentered(\"Game Over\", 64, Color::Yellow, 2, &FONT_5X7);\n}\n\n// Custom font example\nstatic const uint16_t CUSTOM_GLYPHS[][7] = {\n    // Space, A, B, C, etc.\n};\n\nstatic const Sprite CUSTOM_SPRITES[] = {\n    {CUSTOM_GLYPHS[0], 6, 8},  // Space\n    {CUSTOM_GLYPHS[1], 6, 8},  // A\n    // ... more\n};\n\nstatic const Font CUSTOM_FONT = {\n    CUSTOM_SPRITES,\n    32,   // firstChar\n    90,   // lastChar (A-Z only)\n    6,    // width\n    8,    // height\n    1,    // spacing\n    9     // lineHeight\n};\n\nvoid draw(Renderer& renderer) override {\n    renderer.drawText(\"CUSTOM\", 10, 10, Color::White, 1, &CUSTOM_FONT);\n}\n
"},{"location":"api_reference/graphics/font/#text-sizing","title":"Text Sizing","text":"

Calculate text dimensions:

int getTextWidth(const Font* font, const char* text) {\n    if (!font || !text) return 0;\n\n    int width = 0;\n    for (int i = 0; text[i] != '\\0'; i++) {\n        if (text[i] >= font->firstChar && text[i] <= font->lastChar) {\n            width += font->glyphWidth + font->spacing;\n        }\n    }\n    return width - font->spacing;  // Remove last spacing\n}\n\nint getTextHeight(const Font* font) {\n    return font ? font->lineHeight : 8;\n}\n
"},{"location":"api_reference/graphics/font/#performance-considerations","title":"Performance Considerations","text":"
  • Font storage: Store fonts in flash (const/constexpr) for best performance
  • Glyph lookup: Fast array access (character code - firstChar)
  • Fixed width: Fixed-width fonts are faster than variable-width
  • Font switching: Changing fonts is fast (just pointer assignment)
"},{"location":"api_reference/graphics/font/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store font data in flash, not RAM
  • Font size: Larger fonts use more flash memory
  • Character range: Limit character range to save memory if not needed
"},{"location":"api_reference/graphics/font/#see-also","title":"See Also","text":"
  • Renderer - Rendering system that uses fonts
  • Sprite - Sprite structure used for glyphs
  • Manual - Basic Rendering
  • API Overview
"},{"location":"api_reference/graphics/renderer/","title":"Renderer","text":"

High-level graphics rendering system for drawing shapes, text, sprites, and tilemaps.

"},{"location":"api_reference/graphics/renderer/#description","title":"Description","text":"

The Renderer class provides a unified API for drawing shapes, text, and images. It abstracts the underlying hardware implementation (DrawSurface) and manages display configuration, including rotation and offsets.

The renderer uses integer-only math for optimal performance on ESP32 and supports multiple sprite formats (1bpp, 2bpp, 4bpp) and multi-layer sprites.

"},{"location":"api_reference/graphics/renderer/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    class Renderer {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/renderer/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages renderer instance)
"},{"location":"api_reference/graphics/renderer/#constructors","title":"Constructors","text":""},{"location":"api_reference/graphics/renderer/#rendererconst-displayconfig-config","title":"Renderer(const DisplayConfig& config)","text":"

Constructs the Renderer with a specific display configuration.

Parameters: - config (const DisplayConfig&): The display configuration settings (width, height, rotation, etc.)

Example:

#include \"graphics/Renderer.h\"\n#include \"graphics/DisplayConfig.h\"\n\npixelroot32::graphics::DisplayConfig config;\nconfig.width = 128;\nconfig.height = 128;\nconfig.rotation = 0;\n\npixelroot32::graphics::Renderer renderer(config);\nrenderer.init();\n

"},{"location":"api_reference/graphics/renderer/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/graphics/renderer/#void-init","title":"void init()","text":"

Initializes the renderer and the underlying draw surface.

Returns: - void

Notes: - Must be called after construction and before any drawing operations - Initializes the platform-specific DrawSurface implementation - Safe to call multiple times (idempotent)

Example:

Renderer renderer(displayConfig);\nrenderer.init();  // Initialize before use\n

"},{"location":"api_reference/graphics/renderer/#void-beginframe","title":"void beginFrame()","text":"

Prepares the buffer for a new frame (clears screen).

Returns: - void

Notes: - Should be called once at the start of each frame - Clears the display buffer - Typically called automatically by Engine, but can be called manually

Example:

void draw(Renderer& renderer) override {\n    renderer.beginFrame();\n    // Draw everything...\n    renderer.endFrame();\n}\n

"},{"location":"api_reference/graphics/renderer/#void-endframe","title":"void endFrame()","text":"

Finalizes the frame and sends the buffer to the display.

Returns: - void

Notes: - Should be called once at the end of each frame - Sends the completed frame buffer to the display - Typically called automatically by Engine, but can be called manually

"},{"location":"api_reference/graphics/renderer/#drawsurface-getdrawsurface","title":"DrawSurface& getDrawSurface()","text":"

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed unless implementing custom drawing - Provides low-level access to the display driver

"},{"location":"api_reference/graphics/renderer/#void-drawtextconst-char-text-int16_t-x-int16_t-y-color-color-uint8_t-size","title":"void drawText(const char* text, int16_t x, int16_t y, Color color, uint8_t size)","text":"

Draws a string of text using the default font.

Parameters: - text (const char*): The text to draw (null-terminated string) - x (int16_t): X coordinate (top-left corner of text) - y (int16_t): Y coordinate (top-left corner of text) - color (Color): Text color - size (uint8_t): Text size multiplier (1 = normal, 2 = double, etc.)

Performance Notes: - Efficient for small amounts of text - Avoid calling in tight loops with long strings - Use static buffers for text formatting

Example:

renderer.drawText(\"Hello World\", 10, 10, Color::White, 1);\nrenderer.drawText(\"Score: 100\", 10, 30, Color::Yellow, 2);\n

"},{"location":"api_reference/graphics/renderer/#void-drawtextconst-char-text-int16_t-x-int16_t-y-color-color-uint8_t-size-const-font-font","title":"void drawText(const char text, int16_t x, int16_t y, Color color, uint8_t size, const Font font)","text":"

Draws a string of text using a specific font.

Parameters: - text (const char): The text to draw - x (int16_t): X coordinate - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size multiplier - font (const Font): Pointer to the font to use. If nullptr, uses the default font

Example:

const Font* customFont = &FONT_5X7;\nrenderer.drawText(\"Custom Font\", 10, 10, Color::White, 1, customFont);\n

"},{"location":"api_reference/graphics/renderer/#void-drawtextcenteredconst-char-text-int16_t-y-color-color-uint8_t-size","title":"void drawTextCentered(const char* text, int16_t y, Color color, uint8_t size)","text":"

Draws text centered horizontally at a given Y coordinate using the default font.

Parameters: - text (const char*): The text to draw - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size

Example:

renderer.drawTextCentered(\"Game Over\", 64, Color::White, 2);\n

"},{"location":"api_reference/graphics/renderer/#void-drawtextcenteredconst-char-text-int16_t-y-color-color-uint8_t-size-const-font-font","title":"void drawTextCentered(const char text, int16_t y, Color color, uint8_t size, const Font font)","text":"

Draws text centered horizontally at a given Y coordinate using a specific font.

Parameters: - text (const char): The text to draw - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size - font (const Font): Pointer to the font to use. If nullptr, uses the default font

"},{"location":"api_reference/graphics/renderer/#void-drawfilledcircleint-x-int-y-int-radius-color-color","title":"void drawFilledCircle(int x, int y, int radius, Color color)","text":"

Draws a filled circle.

Parameters: - x (int): Center X coordinate - y (int): Center Y coordinate - radius (int): Radius of the circle in pixels - color (Color): Fill color

Example:

renderer.drawFilledCircle(64, 64, 20, Color::Red);\n

"},{"location":"api_reference/graphics/renderer/#void-drawcircleint-x-int-y-int-radius-color-color","title":"void drawCircle(int x, int y, int radius, Color color)","text":"

Draws a circle outline.

Parameters: - x (int): Center X coordinate - y (int): Center Y coordinate - radius (int): Radius of the circle in pixels - color (Color): Outline color

Example:

renderer.drawCircle(64, 64, 20, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-drawrectangleint-x-int-y-int-width-int-height-color-color","title":"void drawRectangle(int x, int y, int width, int height, Color color)","text":"

Draws a rectangle outline.

Parameters: - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - width (int): Width of the rectangle in pixels - height (int): Height of the rectangle in pixels - color (Color): Outline color

Example:

renderer.drawRectangle(10, 10, 100, 50, Color::Blue);\n

"},{"location":"api_reference/graphics/renderer/#void-drawfilledrectangleint-x-int-y-int-width-int-height-color-color","title":"void drawFilledRectangle(int x, int y, int width, int height, Color color)","text":"

Draws a filled rectangle.

Parameters: - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - width (int): Width of the rectangle in pixels - height (int): Height of the rectangle in pixels - color (Color): Fill color

Example:

renderer.drawFilledRectangle(10, 10, 100, 50, Color::Green);\n

"},{"location":"api_reference/graphics/renderer/#void-drawlineint-x1-int-y1-int-x2-int-y2-color-color","title":"void drawLine(int x1, int y1, int x2, int y2, Color color)","text":"

Draws a line between two points.

Parameters: - x1 (int): Start X coordinate - y1 (int): Start Y coordinate - x2 (int): End X coordinate - y2 (int): End Y coordinate - color (Color): Line color

Example:

renderer.drawLine(0, 0, 128, 128, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-drawpixelint-x-int-y-color-color","title":"void drawPixel(int x, int y, Color color)","text":"

Draws a single pixel.

Parameters: - x (int): X coordinate - y (int): Y coordinate - color (Color): Pixel color

Performance Notes: - Very fast, but avoid calling thousands of times per frame - Use for special effects or debugging

Example:

renderer.drawPixel(64, 64, Color::Red);\n

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite-sprite-int-x-int-y-color-color-bool-flipx-false","title":"void drawSprite(const Sprite& sprite, int x, int y, Color color, bool flipX = false)","text":"

Draws a 1bpp monochrome sprite using the Sprite descriptor.

Parameters: - sprite (const Sprite&): Sprite descriptor (data, width, height) - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space - color (Color): Color used for \"on\" pixels. Default: uses sprite palette context - flipX (bool, optional): If true, sprite is mirrored horizontally. Default: false

Performance Notes: - Very efficient for 1bpp sprites (integer-only operations) - Sprite data should be stored in flash (const/constexpr) for best performance - Avoid calling in tight loops; batch similar operations when possible

Example:

static const uint16_t playerData[] = {\n    0b00111100,\n    0b01111110,\n    // ... more rows\n};\n\nstatic const Sprite playerSprite = {\n    playerData,\n    8,  // width\n    8   // height\n};\n\nrenderer.drawSprite(playerSprite, 100, 100, Color::White);\nrenderer.drawSprite(playerSprite, 120, 100, Color::White, true);  // Flipped\n

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite-sprite-int-x-int-y-float-scalex-float-scaley-color-color-bool-flipx-false","title":"void drawSprite(const Sprite& sprite, int x, int y, float scaleX, float scaleY, Color color, bool flipX = false)","text":"

Draws a scaled 1bpp monochrome sprite.

Parameters: - sprite (const Sprite&): Sprite descriptor - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - scaleX (float): Horizontal scaling factor (e.g., 1.25 for 25% larger) - scaleY (float): Vertical scaling factor - color (Color): Color used for \"on\" pixels - flipX (bool, optional): If true, sprite is mirrored horizontally before scaling. Default: false

Performance Notes: - Slower than non-scaled version due to scaling calculations - Use integer scaling factors when possible (1.0, 2.0, etc.) for better performance

Example:

renderer.drawSprite(playerSprite, 100, 100, 2.0f, 2.0f, Color::White);  // 2x size\n

"},{"location":"api_reference/graphics/renderer/#void-drawmultispriteconst-multisprite-sprite-int-x-int-y","title":"void drawMultiSprite(const MultiSprite& sprite, int x, int y)","text":"

Draws a multi-layer sprite composed of several 1bpp layers.

Parameters: - sprite (const MultiSprite&): Multi-layer sprite descriptor - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space

Performance Notes: - Each layer is rendered separately, so more layers = more draw calls - Still efficient as each layer uses 1bpp format - Use for multi-color sprites without higher bit-depths

Example:

static const SpriteLayer layers[] = {\n    { outlineData, Color::Black },\n    { fillData, Color::Red },\n    { highlightData, Color::Yellow }\n};\n\nstatic const MultiSprite playerMultiSprite = {\n    8,      // width\n    8,      // height\n    layers, // layers array\n    3       // layer count\n};\n\nrenderer.drawMultiSprite(playerMultiSprite, 100, 100);\n

"},{"location":"api_reference/graphics/renderer/#void-drawmultispriteconst-multisprite-sprite-int-x-int-y-float-scalex-float-scaley","title":"void drawMultiSprite(const MultiSprite& sprite, int x, int y, float scaleX, float scaleY)","text":"

Draws a scaled multi-layer sprite.

Parameters: - sprite (const MultiSprite&): Multi-layer sprite descriptor - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - scaleX (float): Horizontal scaling factor - scaleY (float): Vertical scaling factor

"},{"location":"api_reference/graphics/renderer/#void-drawtilemapconst-tilemap-map-int-originx-int-originy-color-color","title":"void drawTileMap(const TileMap& map, int originX, int originY, Color color)","text":"

Draws a 1bpp tilemap.

Parameters: - map (const TileMap&): Tilemap descriptor (indices, 1bpp tiles, dimensions) - originX (int): X coordinate of the top-left corner - originY (int): Y coordinate of the top-left corner - color (Color): Color used for all tiles in the map

"},{"location":"api_reference/graphics/renderer/#void-drawtilemapconst-tilemap2bpp-map-int-originx-int-originy","title":"void drawTileMap(const TileMap2bpp& map, int originX, int originY)","text":"

Draws a 2bpp tilemap. Available when PIXELROOT32_ENABLE_2BPP_SPRITES is defined.

Parameters: - map (const TileMap2bpp&): Tilemap descriptor (indices, 2bpp tiles, dimensions) - originX (int): X coordinate - originY (int): Y coordinate

"},{"location":"api_reference/graphics/renderer/#void-drawtilemapconst-tilemap4bpp-map-int-originx-int-originy","title":"void drawTileMap(const TileMap4bpp& map, int originX, int originY)","text":"

Draws a 4bpp tilemap. Available when PIXELROOT32_ENABLE_4BPP_SPRITES is defined.

Parameters: - map (const TileMap4bpp&): Tilemap descriptor (indices, 4bpp tiles, dimensions) - originX (int): X coordinate - originY (int): Y coordinate

Performance Notes: - Very efficient for rendering large backgrounds - Only visible tiles are drawn (viewport culling) - Use tilemaps instead of individual sprites for backgrounds

Example:

static const uint8_t levelIndices[] = {\n    0, 1, 2, 3,\n    4, 5, 6, 7,\n    // ... more rows\n};\n\nstatic const TileMap levelMap = {\n    levelIndices,\n    16,        // width in tiles\n    16,        // height in tiles\n    tileSprites, // tile sprite array\n    8,         // tile width\n    8,         // tile height\n    16         // tile count\n};\n\nrenderer.drawTileMap(levelMap, 0, 0, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-setdisplayoffsetint-x-int-y","title":"void setDisplayOffset(int x, int y)","text":"

Sets a global offset for all drawing operations. Useful for camera/parallax effects.

Parameters: - x (int): X offset in pixels - y (int): Y offset in pixels

Notes: - All subsequent drawing operations are offset by this amount - Useful for camera scrolling and parallax effects - Reset to (0, 0) to disable offset

Example:

// Camera scrolling\ncamera.setPosition(playerX - 64, playerY - 64);\nrenderer.setDisplayOffset(-camera.getX(), -camera.getY());\nrenderer.drawTileMap(background, 0, 0, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-setdisplaysizeint-w-int-h","title":"void setDisplaySize(int w, int h)","text":"

Sets the logical display size.

Parameters: - w (int): Width in pixels - h (int): Height in pixels

Notes: - Typically set via DisplayConfig during construction - Use this to change display size at runtime if needed

"},{"location":"api_reference/graphics/renderer/#int-getwidth-const","title":"int getWidth() const","text":"

Gets the display width.

Returns: - int: Display width in pixels

"},{"location":"api_reference/graphics/renderer/#int-getheight-const","title":"int getHeight() const","text":"

Gets the display height.

Returns: - int: Display height in pixels

"},{"location":"api_reference/graphics/renderer/#int-getxoffset-const","title":"int getXOffset() const","text":"

Gets the current X display offset.

Returns: - int: X offset in pixels

"},{"location":"api_reference/graphics/renderer/#int-getyoffset-const","title":"int getYOffset() const","text":"

Gets the current Y display offset.

Returns: - int: Y offset in pixels

"},{"location":"api_reference/graphics/renderer/#void-setcontrastuint8_t-level","title":"void setContrast(uint8_t level)","text":"

Sets the display contrast (brightness).

Parameters: - level (uint8_t): Contrast level (0-255)

Notes: - Platform-specific: may not be supported on all displays - Higher values = brighter display

"},{"location":"api_reference/graphics/renderer/#void-setfontconst-uint8_t-font","title":"void setFont(const uint8_t* font)","text":"

Sets the font for text rendering.

Parameters: - font (const uint8_t*): Pointer to the font data

Notes: - Sets the default font for drawText() calls without font parameter - Use font constants like FONT_5X7 from Font.h

"},{"location":"api_reference/graphics/renderer/#usage-example","title":"Usage Example","text":"
#include \"graphics/Renderer.h\"\n#include \"graphics/DisplayConfig.h\"\n\nvoid draw(Renderer& renderer) override {\n    renderer.beginFrame();\n\n    // Draw background\n    renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n\n    // Draw sprites\n    renderer.drawSprite(playerSprite, playerX, playerY, Color::White);\n    renderer.drawSprite(enemySprite, enemyX, enemyY, Color::Red);\n\n    // Draw UI\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n    renderer.drawTextCentered(\"Game Over\", 64, Color::Yellow, 2);\n\n    renderer.endFrame();\n}\n
"},{"location":"api_reference/graphics/renderer/#performance-considerations","title":"Performance Considerations","text":"
  • Integer-only math: All operations use integer arithmetic for ESP32 efficiency
  • Sprite storage: Store sprite data in flash (const/constexpr) for best performance
  • Batch operations: Group similar draw calls together
  • Tilemaps: Dibuja un mapa de tiles completo. Implementa viewport culling autom\u00e1tico y cach\u00e9 de paleta para m\u00e1ximo rendimiento.
  • Sprites 2bpp/4bpp: Optimizado para ESP32 (IRAM + acceso de 16 bits).
"},{"location":"api_reference/graphics/renderer/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Sprite data should be in flash, not RAM
  • Frame rate: Limit draw calls per frame for consistent FPS
  • Display offset: Use for scrolling instead of redrawing everything
"},{"location":"api_reference/graphics/renderer/#see-also","title":"See Also","text":"
  • Sprite - Sprite structure
  • MultiSprite - Multi-layer sprites
  • TileMap - Tilemap structure
  • Color - Color constants
  • DisplayConfig - Display configuration
  • Camera2D - Camera for scrolling
  • Manual - Basic Rendering
  • Manual - Sprites and Animation
  • API Overview
"},{"location":"api_reference/graphics/sprite/","title":"Sprite","text":"

Low-level bitmap descriptor and multi-layer composition for retro rendering.

"},{"location":"api_reference/graphics/sprite/#description","title":"Description","text":"

Sprites are the fundamental graphics primitive in PixelRoot32. The engine supports multiple sprite formats:

  • 1bpp (Standard): Monochrome sprites, most memory-efficient
  • 2bpp (Experimental): 4 colors per sprite
  • 4bpp (Experimental): 16 colors per sprite
  • MultiSprite: Multi-layer 1bpp sprites for multi-color effects
"},{"location":"api_reference/graphics/sprite/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    struct Sprite {\n        // ...\n    };\n\n    struct MultiSprite {\n        // ...\n    };\n\n    struct SpriteLayer {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/sprite/#sprite-structure-1bpp","title":"Sprite Structure (1bpp)","text":"

Compact sprite descriptor for monochrome bitmapped sprites.

"},{"location":"api_reference/graphics/sprite/#members","title":"Members","text":"
  • const uint16_t* data: Pointer to packed row data (size = height)
  • uint8_t width: Sprite width in pixels (\u2264 16)
  • uint8_t height: Sprite height in pixels
"},{"location":"api_reference/graphics/sprite/#data-format","title":"Data Format","text":"

Sprites are stored as an array of 16-bit rows. Each row packs horizontal pixels into bits:

  • Bit 0: Leftmost pixel of the row
  • Bit (width - 1): Rightmost pixel of the row
  • Bit value 1: Pixel on (colored)
  • Bit value 0: Pixel off (transparent/background)

Only the lowest width bits of each row are used.

"},{"location":"api_reference/graphics/sprite/#example","title":"Example","text":"
// 8x8 sprite (smiley face)\nstatic const uint16_t SMILEY_DATA[] = {\n    0b00111100,  // Row 0:  \u2588\u2588\u2588\u2588\n    0b01111110,  // Row 1:  \u2588\u2588\u2588\u2588\u2588\u2588\n    0b11011011,  // Row 2:  \u2588\u2588 \u2588\u2588 \u2588\u2588\n    0b11111111,  // Row 3:  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\n    0b11011011,  // Row 4:  \u2588\u2588 \u2588\u2588 \u2588\u2588\n    0b01100110,  // Row 5:  \u2588\u2588  \u2588\u2588\n    0b01111110,  // Row 6:  \u2588\u2588\u2588\u2588\u2588\u2588\n    0b00111100   // Row 7:  \u2588\u2588\u2588\u2588\n};\n\nstatic const Sprite SMILEY_SPRITE = {\n    SMILEY_DATA,\n    8,  // width\n    8   // height\n};\n
"},{"location":"api_reference/graphics/sprite/#spritelayer-structure","title":"SpriteLayer Structure","text":"

Single monochrome layer used by layered sprites.

"},{"location":"api_reference/graphics/sprite/#members_1","title":"Members","text":"
  • const uint16_t* data: Pointer to packed row data for this layer
  • Color color: Color used for \"on\" pixels in this layer
"},{"location":"api_reference/graphics/sprite/#notes","title":"Notes","text":"
  • Each layer uses the same width/height as its owning MultiSprite
  • Layers can have different colors
  • Layers are drawn in array order
"},{"location":"api_reference/graphics/sprite/#multisprite-structure","title":"MultiSprite Structure","text":"

Multi-layer, multi-color sprite built from 1bpp layers.

"},{"location":"api_reference/graphics/sprite/#members_2","title":"Members","text":"
  • uint8_t width: Sprite width in pixels (\u2264 16)
  • uint8_t height: Sprite height in pixels
  • const SpriteLayer* layers: Pointer to array of layers
  • uint8_t layerCount: Number of layers in the array
"},{"location":"api_reference/graphics/sprite/#notes_1","title":"Notes","text":"
  • Combines several 1bpp layers with different colors
  • Layers are drawn in array order
  • Enables multi-color sprites without higher bit-depths
  • More layers = more draw calls (but still efficient)
"},{"location":"api_reference/graphics/sprite/#example_1","title":"Example","text":"
// Outline layer\nstatic const uint16_t OUTLINE_DATA[] = {\n    0b11111111,\n    0b10000001,\n    0b10000001,\n    0b11111111\n};\n\n// Fill layer\nstatic const uint16_t FILL_DATA[] = {\n    0b00000000,\n    0b01111110,\n    0b01111110,\n    0b00000000\n};\n\nstatic const SpriteLayer LAYERS[] = {\n    {OUTLINE_DATA, Color::Black},  // Layer 0: Black outline\n    {FILL_DATA, Color::Red}       // Layer 1: Red fill\n};\n\nstatic const MultiSprite PLAYER_MULTISPRITE = {\n    8,      // width\n    8,      // height\n    LAYERS, // layers array\n    2       // layer count\n};\n
"},{"location":"api_reference/graphics/sprite/#sprite2bpp-structure-experimental","title":"Sprite2bpp Structure (Experimental)","text":"

2-bit per pixel sprite (4 colors).

Requires: PIXELROOT32_ENABLE_2BPP_SPRITES build flag

"},{"location":"api_reference/graphics/sprite/#members_3","title":"Members","text":"
  • const uint16_t* data: Datos empaquetados (4 p\u00edxeles por cada 8 bits, alineados a 16 bits)
  • const Color* palette: Local palette (4 colors)
  • uint8_t width: Sprite width
  • uint8_t height: Sprite height
  • uint8_t paletteSize: Number of colors (typically 4)
"},{"location":"api_reference/graphics/sprite/#notes_2","title":"Notes","text":"
  • Experimental feature
  • Uses more memory than 1bpp
  • Each pixel can be one of 4 colors from local palette
"},{"location":"api_reference/graphics/sprite/#sprite4bpp-structure-experimental","title":"Sprite4bpp Structure (Experimental)","text":"

4-bit per pixel sprite (16 colors).

Requires: PIXELROOT32_ENABLE_4BPP_SPRITES build flag

"},{"location":"api_reference/graphics/sprite/#members_4","title":"Members","text":"
  • const uint16_t* data: Datos empaquetados (2 p\u00edxeles por cada 8 bits, alineados a 16 bits)
  • const Color* palette: Local palette (16 colors)
  • uint8_t width: Sprite width
  • uint8_t height: Sprite height
  • uint8_t paletteSize: Number of colors (typically 16)
"},{"location":"api_reference/graphics/sprite/#notes_3","title":"Notes","text":"
  • Experimental feature
  • Uses more memory than 1bpp/2bpp
  • Each pixel can be one of 16 colors from local palette
"},{"location":"api_reference/graphics/sprite/#sprite-animation","title":"Sprite Animation","text":""},{"location":"api_reference/graphics/sprite/#spriteanimationframe-structure","title":"SpriteAnimationFrame Structure","text":"

Frame that can reference either a Sprite or a MultiSprite.

Members: - const Sprite* sprite: Optional pointer to a simple 1bpp sprite frame - const MultiSprite* multiSprite: Optional pointer to a layered sprite frame

Notes: - Exactly one pointer should be non-null for a valid frame - Allows same animation system for both sprite types

"},{"location":"api_reference/graphics/sprite/#spriteanimation-structure","title":"SpriteAnimation Structure","text":"

Lightweight, step-based sprite animation controller.

Members: - const SpriteAnimationFrame* frames: Pointer to immutable frame table - uint8_t frameCount: Number of frames in the table - uint8_t current: Current frame index [0, frameCount)

Methods: - void reset(): Reset to first frame - void step(): Advance to next frame (wrapping) - const SpriteAnimationFrame& getCurrentFrame() const: Get current frame - const Sprite* getCurrentSprite() const: Get current simple sprite - const MultiSprite* getCurrentMultiSprite() const: Get current multi-sprite

Example:

static const SpriteAnimationFrame WALK_FRAMES[] = {\n    {&walkFrame1, nullptr},\n    {&walkFrame2, nullptr},\n    {&walkFrame3, nullptr},\n    {&walkFrame2, nullptr}  // Loop back\n};\n\nstatic SpriteAnimation walkAnimation = {\n    WALK_FRAMES,\n    4,    // frameCount\n    0     // current\n};\n\n// In update\nwalkAnimation.step();\nconst Sprite* currentSprite = walkAnimation.getCurrentSprite();\n

"},{"location":"api_reference/graphics/sprite/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/graphics/sprite/#creating-1bpp-sprites","title":"Creating 1bpp Sprites","text":"
// 8x8 player sprite\nstatic const uint16_t PLAYER_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11011011,\n    0b11111111,\n    0b01111110,\n    0b00111100,\n    0b00011000\n};\n\nstatic const Sprite PLAYER_SPRITE = {\n    PLAYER_DATA,\n    8,  // width\n    8   // height\n};\n\n// Use in rendering\nrenderer.drawSprite(PLAYER_SPRITE, 100, 100, Color::White);\n
"},{"location":"api_reference/graphics/sprite/#creating-multisprite","title":"Creating MultiSprite","text":"
// Outline layer\nstatic const uint16_t OUTLINE[] = {\n    0b11111111,\n    0b10000001,\n    0b10000001,\n    0b11111111\n};\n\n// Fill layer\nstatic const uint16_t FILL[] = {\n    0b00000000,\n    0b01111110,\n    0b01111110,\n    0b00000000\n};\n\nstatic const SpriteLayer LAYERS[] = {\n    {OUTLINE, Color::Black},\n    {FILL, Color::Red}\n};\n\nstatic const MultiSprite ENEMY_SPRITE = {\n    8,      // width\n    8,      // height\n    LAYERS, // layers\n    2       // layer count\n};\n\n// Use in rendering\nrenderer.drawMultiSprite(ENEMY_SPRITE, 100, 100);\n
"},{"location":"api_reference/graphics/sprite/#sprite-animation_1","title":"Sprite Animation","text":"
class AnimatedActor : public pixelroot32::core::Actor {\nprivate:\n    SpriteAnimation animation;\n    unsigned long animTimer = 0;\n    unsigned long animInterval = 200;  // 200ms per frame\n\npublic:\n    void update(unsigned long deltaTime) override {\n        Actor::update(deltaTime);\n\n        animTimer += deltaTime;\n        if (animTimer >= animInterval) {\n            animTimer -= animInterval;\n            animation.step();\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        const Sprite* frame = animation.getCurrentSprite();\n        if (frame) {\n            renderer.drawSprite(*frame, \n                               static_cast<int>(x), \n                               static_cast<int>(y), \n                               Color::White);\n        }\n    }\n};\n
"},{"location":"api_reference/graphics/sprite/#sprite-flipping","title":"Sprite Flipping","text":"

Sprites can be flipped horizontally:

// Draw normal\nrenderer.drawSprite(sprite, 100, 100, Color::White, false);\n\n// Draw flipped\nrenderer.drawSprite(sprite, 100, 100, Color::White, true);\n
"},{"location":"api_reference/graphics/sprite/#performance-considerations","title":"Performance Considerations","text":"
  • 1bpp sprites: Most efficient (integer-only operations)
  • MultiSprite: Each layer is a separate draw call (still efficient)
  • 2bpp/4bpp: Experimental, uses more memory and CPU
  • Storage: Store sprite data in flash (const/constexpr) for best performance
  • Size limit: Sprites are limited to 16 pixels wide for 1bpp format
"},{"location":"api_reference/graphics/sprite/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store sprite data in flash, not RAM
  • Sprite size: Smaller sprites = faster drawing
  • Format choice: Use 1bpp when possible for best performance
  • MultiSprite: More layers = more draw calls (but acceptable)
"},{"location":"api_reference/graphics/sprite/#see-also","title":"See Also","text":"
  • Renderer - Rendering system that draws sprites
  • Color - Color constants for sprites
  • Manual - Sprites and Animation
  • API Overview
"},{"location":"api_reference/graphics/tilemap/","title":"TileMap","text":"

Generic structure for tile-based background rendering.

"},{"location":"api_reference/graphics/tilemap/#description","title":"Description","text":"

TileMapGeneric<T> is a template structure for rendering tile-based backgrounds efficiently. It supports multiple bit-depths (1bpp, 2bpp, 4bpp) by using the appropriate sprite type for tiles.

Tilemaps are ideal for large backgrounds, levels, and static environments. They support viewport culling (only visible tiles are drawn) for optimal performance.

"},{"location":"api_reference/graphics/tilemap/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    template<typename T>\n    struct TileMapGeneric {\n        // ...\n    };\n\n    using TileMap = TileMapGeneric<Sprite>;\n    using TileMap2bpp = TileMapGeneric<Sprite2bpp>;\n    using TileMap4bpp = TileMapGeneric<Sprite4bpp>;\n}\n
"},{"location":"api_reference/graphics/tilemap/#template-parameters","title":"Template Parameters","text":""},{"location":"api_reference/graphics/tilemap/#t","title":"T","text":"

The sprite type used for tiles.

Supported types: - Sprite (1bpp) - Sprite2bpp (2bpp) - Sprite4bpp (4bpp)

"},{"location":"api_reference/graphics/tilemap/#structure","title":"Structure","text":""},{"location":"api_reference/graphics/tilemap/#uint8_t-indices","title":"uint8_t* indices","text":"

Array of tile indices mapping to tile sprites.

Type: uint8_t*

Access: Read-write

Notes: - Array size = width * height - Each value is an index into the tiles array - 0 = first tile, 1 = second tile, etc. - Should be stored in flash (const) for best performance

Example:

// 16x16 tilemap (256 tiles)\nstatic const uint8_t LEVEL_INDICES[] = {\n    0, 0, 0, 0, 1, 1, 1, 1, // Row 0\n    0, 2, 2, 2, 2, 2, 2, 0, // Row 1\n    // ... more rows\n};\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-width","title":"uint8_t width","text":"

Width of the tilemap in tiles.

Type: uint8_t

Access: Read-write

Example:

width = 16;  // 16 tiles wide\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-height","title":"uint8_t height","text":"

Height of the tilemap in tiles.

Type: uint8_t

Access: Read-write

Example:

height = 16;  // 16 tiles tall\n

"},{"location":"api_reference/graphics/tilemap/#const-t-tiles","title":"const T* tiles","text":"

Array of tile sprites of type T.

Type: const T*

Access: Read-only

Notes: - Array of sprite pointers, one per unique tile - Indices reference this array - All tiles should be the same size - Should be stored in flash (const) for best performance

Example (1bpp):

static const Sprite TILE_SPRITES[] = {\n    EMPTY_TILE,   // Index 0\n    WALL_TILE,    // Index 1\n    FLOOR_TILE,   // Index 2\n    // ... more tiles\n};\n

Example (2bpp):

static const Sprite2bpp TILE_SPRITES_2BPP[] = {\n    TILE_GRASS,   // Index 0\n    TILE_DIRT,    // Index 1\n    // ... more tiles\n};\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-tilewidth","title":"uint8_t tileWidth","text":"

Width of each tile in pixels.

Type: uint8_t

Access: Read-write

Notes: - All tiles must have the same width - Common values: 8, 16 pixels - Should match sprite width

Example:

tileWidth = 8;  // 8x8 tiles\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-tileheight","title":"uint8_t tileHeight","text":"

Height of each tile in pixels.

Type: uint8_t

Access: Read-write

Notes: - All tiles must have the same height - Common values: 8, 16 pixels - Should match sprite height

Example:

tileHeight = 8;  // 8x8 tiles\n

"},{"location":"api_reference/graphics/tilemap/#uint16_t-tilecount","title":"uint16_t tileCount","text":"

Number of unique tiles in the tiles array.

Type: uint16_t

Access: Read-write

Notes: - Must match the size of the tiles array - Indices must be < tileCount

Example:

tileCount = 16;  // 16 unique tiles\n

"},{"location":"api_reference/graphics/tilemap/#creating-tilemaps","title":"Creating Tilemaps","text":""},{"location":"api_reference/graphics/tilemap/#step-1-create-tile-sprites","title":"Step 1: Create Tile Sprites","text":"
// Empty tile (index 0)\nstatic const uint16_t EMPTY_DATA[] = {\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000\n};\n\n// Wall tile (index 1)\nstatic const uint16_t WALL_DATA[] = {\n    0b11111111,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b11111111\n};\n\n// Floor tile (index 2)\nstatic const uint16_t FLOOR_DATA[] = {\n    0b00000000,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b00000000\n};\n\nstatic const Sprite TILE_SPRITES[] = {\n    {EMPTY_DATA, 8, 8},  // Index 0\n    {WALL_DATA, 8, 8},   // Index 1\n    {FLOOR_DATA, 8, 8}   // Index 2\n};\n
"},{"location":"api_reference/graphics/tilemap/#step-2-create-index-array","title":"Step 2: Create Index Array","text":"
// 16x16 level (256 tiles)\n// 0 = empty, 1 = wall, 2 = floor\nstatic const uint8_t LEVEL_INDICES[] = {\n    // Row 0: Top wall\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n    // Row 1: Walls on sides\n    1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,\n    // Row 2\n    1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,\n    // ... more rows\n    // Row 15: Bottom wall\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n};\n
"},{"location":"api_reference/graphics/tilemap/#step-3-create-tilemap-structure","title":"Step 3: Create TileMap Structure","text":"
static const TileMap LEVEL_MAP = {\n    const_cast<uint8_t*>(LEVEL_INDICES),  // indices (non-const for struct)\n    16,        // width in tiles\n    16,        // height in tiles\n    TILE_SPRITES, // tile sprites array\n    8,         // tile width\n    8,         // tile height\n    3          // tile count\n};\n
"},{"location":"api_reference/graphics/tilemap/#rendering-tilemaps","title":"Rendering Tilemaps","text":"

Use Renderer::drawTileMap():

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Draw tilemap at origin (0, 0)\n    renderer.drawTileMap(LEVEL_MAP, 0, 0, Color::White);\n\n    // With camera offset\n    camera.apply(renderer);\n    renderer.drawTileMap(LEVEL_MAP, 0, 0, Color::White);\n}\n
"},{"location":"api_reference/graphics/tilemap/#viewport-culling","title":"Viewport Culling","text":"

Tilemaps automatically cull tiles outside the viewport:

  • Only visible tiles are drawn
  • Very efficient for large levels
  • Works with camera scrolling

Example:

// Large level (256x256 tiles)\n// Only tiles visible on screen are drawn\ncamera.apply(renderer);\nrenderer.drawTileMap(LARGE_LEVEL_MAP, 0, 0, Color::White);\n

"},{"location":"api_reference/graphics/tilemap/#collision-detection-with-tilemaps","title":"Collision Detection with Tilemaps","text":"

Check tile at world position:

bool isSolidTile(int worldX, int worldY, const TileMap& map) {\n    int tileX = worldX / map.tileWidth;\n    int tileY = worldY / map.tileHeight;\n\n    if (tileX < 0 || tileX >= map.width || \n        tileY < 0 || tileY >= map.height) {\n        return true;  // Outside map = solid\n    }\n\n    int index = tileY * map.width + tileX;\n    uint8_t tileIndex = map.indices[index];\n\n    // Check if tile is solid (e.g., wall = index 1)\n    return (tileIndex == 1);\n}\n
"},{"location":"api_reference/graphics/tilemap/#usage-example","title":"Usage Example","text":"
#include \"graphics/TileMap.h\"\n#include \"graphics/Renderer.h\"\n\nclass LevelScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::TileMap levelMap;\n    pixelroot32::graphics::Camera2D camera;\n\npublic:\n    void init() override {\n        // Level map is already defined (see above)\n        // Create camera\n        auto& renderer = engine.getRenderer();\n        camera = pixelroot32::graphics::Camera2D(\n            renderer.getWidth(),\n            renderer.getHeight()\n        );\n\n        // Set level boundaries\n        int levelWidth = levelMap.width * levelMap.tileWidth;\n        int levelHeight = levelMap.height * levelMap.tileHeight;\n        camera.setBounds(0.0f, levelWidth - renderer.getWidth());\n        camera.setVerticalBounds(0.0f, levelHeight - renderer.getHeight());\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Camera follows player\n        if (player) {\n            camera.followTarget(player->x, player->y);\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw tilemap (viewport culling automatic)\n        renderer.drawTileMap(levelMap, 0, 0, Color::White);\n\n        // Draw entities\n        Scene::draw(renderer);\n\n        // Reset for UI\n        renderer.setDisplayOffset(0, 0);\n    }\n\n    bool checkTileCollision(float x, float y) {\n        int tileX = static_cast<int>(x) / levelMap.tileWidth;\n        int tileY = static_cast<int>(y) / levelMap.tileHeight;\n\n        if (tileX < 0 || tileX >= levelMap.width || \n            tileY < 0 || tileY >= levelMap.height) {\n            return true;  // Outside = solid\n        }\n\n        int index = tileY * levelMap.width + tileX;\n        uint8_t tile = levelMap.indices[index];\n        return (tile == 1);  // Wall tile\n    }\n};\n
"},{"location":"api_reference/graphics/tilemap/#performance-considerations","title":"Performance Considerations","text":"
  • Viewport culling: Only visible tiles are drawn (automatic)
  • Tile reuse: Reuse tile sprites across the map
  • Index storage: Compact uint8_t indices (1 byte per tile)
  • Memory: Store indices and tiles in flash (const) for best performance
  • Tile size: Smaller tiles = more tiles to draw, but more detail
"},{"location":"api_reference/graphics/tilemap/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store tilemap data in flash, not RAM
  • Map size: Large maps use more flash memory
  • Tile count: Limit unique tiles to save memory
  • Culling: Viewport culling is essential for large levels
"},{"location":"api_reference/graphics/tilemap/#see-also","title":"See Also","text":"
  • Renderer - Rendering system that draws tilemaps
  • Sprite - Sprite structure used for tiles
  • Camera2D - Camera for scrolling tilemaps
  • Manual - Tilemaps
  • API Overview
"},{"location":"api_reference/physics/collision_system/","title":"CollisionSystem","text":"

Manages collision detection between entities.

"},{"location":"api_reference/physics/collision_system/#description","title":"Description","text":"

CollisionSystem iterates through registered entities, checks if they are Actors, and performs AABB (Axis-Aligned Bounding Box) collision checks based on their collision layers and masks.

The system automatically filters collisions using layers and masks, avoiding unnecessary checks. When a collision is detected, it triggers the onCollision() callback on both actors.

"},{"location":"api_reference/physics/collision_system/#namespace","title":"Namespace","text":"
namespace pixelroot32::physics {\n    class CollisionSystem {\n        // ...\n    };\n}\n
"},{"location":"api_reference/physics/collision_system/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Scene (manages collision system instance)
"},{"location":"api_reference/physics/collision_system/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/physics/collision_system/#void-addentityentity-e","title":"void addEntity(Entity* e)","text":"

Adds an entity to the collision system.

Parameters: - e (pixelroot32::core::Entity*): Pointer to the entity to add

Returns: - void

Notes: - Only Actor entities participate in collisions - Entities are automatically added when added to Scene - Typically not called directly (handled by Scene)

Example:

// Typically handled automatically by Scene\nscene->addEntity(actor);  // Automatically added to collision system\n

"},{"location":"api_reference/physics/collision_system/#void-removeentityentity-e","title":"void removeEntity(Entity* e)","text":"

Removes an entity from the collision system.

Parameters: - e (pixelroot32::core::Entity*): Pointer to the entity to remove

Returns: - void

Notes: - Entities are automatically removed when removed from Scene - Typically not called directly

Example:

// Typically handled automatically by Scene\nscene->removeEntity(actor);  // Automatically removed from collision system\n

"},{"location":"api_reference/physics/collision_system/#void-update","title":"void update()","text":"

Performs collision detection for all registered entities.

Returns: - void

Notes: - Called automatically by Scene::update() - Iterates through all pairs of entities - Only checks collisions between Actors with matching layers/masks - Triggers onCollision() callbacks when collisions are detected - Uses AABB (Axis-Aligned Bounding Box) collision detection

Example:

// Called automatically by Scene, but can be called manually:\nvoid update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);  // Calls collisionSystem.update()\n\n    // Or manually:\n    collisionSystem.update();\n}\n

"},{"location":"api_reference/physics/collision_system/#how-it-works","title":"How It Works","text":"
  1. Entity Registration: Entities added to Scene are automatically registered
  2. Layer Filtering: Only actors with matching layers/masks are checked
  3. AABB Check: Uses Rect::intersects() for collision detection
  4. Callback: Calls onCollision() on both actors when collision detected
"},{"location":"api_reference/physics/collision_system/#collision-detection-algorithm","title":"Collision Detection Algorithm","text":"
for each actor1 in entities:\n    if actor1 is not an Actor: continue\n    for each actor2 in entities:\n        if actor2 is not an Actor: continue\n        if actor1 == actor2: continue\n\n        // Check layers/masks\n        if (actor1->layer & actor2->mask) == 0: continue\n        if (actor2->layer & actor1->mask) == 0: continue\n\n        // Check AABB intersection\n        Rect box1 = actor1->getHitBox();\n        Rect box2 = actor2->getHitBox();\n\n        if (box1.intersects(box2)) {\n            actor1->onCollision(actor2);\n            actor2->onCollision(actor1);\n        }\n
"},{"location":"api_reference/physics/collision_system/#usage-example","title":"Usage Example","text":"
#include \"physics/CollisionSystem.h\"\n#include \"core/Actor.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Create actors with collision layers\n        PlayerActor* player = new PlayerActor(64, 64);\n        player->layer = pixelroot32::physics::DefaultLayers::kPlayer;\n        player->mask = pixelroot32::physics::DefaultLayers::kEnemy | \n                       pixelroot32::physics::DefaultLayers::kObstacle;\n        addEntity(player);\n\n        EnemyActor* enemy = new EnemyActor(100, 100);\n        enemy->layer = pixelroot32::physics::DefaultLayers::kEnemy;\n        enemy->mask = pixelroot32::physics::DefaultLayers::kPlayer;\n        addEntity(enemy);\n\n        // Collision system is managed by Scene\n        // Collisions are checked automatically in Scene::update()\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Collision detection happens here automatically\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"api_reference/physics/collision_system/#performance-considerations","title":"Performance Considerations","text":"
  • Layer filtering: Very efficient; avoids most collision checks
  • AABB checks: Fast (simple rectangle intersection)
  • Pair checking: O(n\u00b2) complexity, but n is limited (MAX_ENTITIES = 32)
  • Update frequency: Called every frame; keep hitboxes simple
"},{"location":"api_reference/physics/collision_system/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Entity limit: MAX_ENTITIES = 32 limits collision pairs
  • Layer efficiency: Use layers effectively to minimize checks
  • Hitbox simplicity: Keep hitboxes as simple AABB for best performance
"},{"location":"api_reference/physics/collision_system/#see-also","title":"See Also","text":"
  • Actor - Actors that participate in collisions
  • CollisionTypes - Collision primitives and layers
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/physics/collision_types/","title":"Collision Types","text":"

Basic geometric types and collision layer definitions.

"},{"location":"api_reference/physics/collision_types/#description","title":"Description","text":"

This document describes the collision primitives (Rect, Circle, Segment) and collision layer system used by the collision detection system.

"},{"location":"api_reference/physics/collision_types/#namespace","title":"Namespace","text":"
namespace pixelroot32::physics {\n    // Types and functions\n}\n
"},{"location":"api_reference/physics/collision_types/#collisionlayer-type","title":"CollisionLayer Type","text":"

Collision layer type (bit flags).

Type: uint16_t (typedef)

Notes: - Uses bit flags for layer assignment - Actors can be on multiple layers (bitwise OR) - Masks define which layers an actor can collide with

"},{"location":"api_reference/physics/collision_types/#defaultlayers-namespace","title":"DefaultLayers Namespace","text":"

Predefined collision layers.

"},{"location":"api_reference/physics/collision_types/#knone","title":"kNone","text":"

No layer (0).

Value: 0

Usage:

actor->layer = pixelroot32::physics::DefaultLayers::kNone;\n

"},{"location":"api_reference/physics/collision_types/#kall","title":"kAll","text":"

All layers (0xFFFF).

Value: 0xFFFF

Usage:

actor->mask = pixelroot32::physics::DefaultLayers::kAll;  // Collide with everything\n

"},{"location":"api_reference/physics/collision_types/#custom-layers","title":"Custom Layers","text":"

Define custom layers using bit flags:

namespace MyLayers {\n    const pixelroot32::physics::CollisionLayer kPlayer = 1 << 0;      // Bit 0\n    const pixelroot32::physics::CollisionLayer kEnemy = 1 << 1;       // Bit 1\n    const pixelroot32::physics::CollisionLayer kObstacle = 1 << 2;    // Bit 2\n    const pixelroot32::physics::CollisionLayer kProjectile = 1 << 3;  // Bit 3\n    const pixelroot32::physics::CollisionLayer kCollectible = 1 << 4;  // Bit 4\n}\n\n// Usage\nactor->layer = MyLayers::kPlayer;\nactor->mask = MyLayers::kEnemy | MyLayers::kObstacle;\n
"},{"location":"api_reference/physics/collision_types/#circle-structure","title":"Circle Structure","text":"

Represents a circle for collision detection.

Members: - float x: Center X coordinate - float y: Center Y coordinate - float radius: Radius of the circle

Example:

pixelroot32::physics::Circle circle;\ncircle.x = 100.0f;\ncircle.y = 100.0f;\ncircle.radius = 10.0f;\n

"},{"location":"api_reference/physics/collision_types/#segment-structure","title":"Segment Structure","text":"

Represents a line segment for collision detection.

Members: - float x1, y1: Start point coordinates - float x2, y2: End point coordinates

Example:

pixelroot32::physics::Segment segment;\nsegment.x1 = 0.0f;\nsegment.y1 = 0.0f;\nsegment.x2 = 100.0f;\nsegment.y2 = 100.0f;\n

"},{"location":"api_reference/physics/collision_types/#intersection-functions","title":"Intersection Functions","text":""},{"location":"api_reference/physics/collision_types/#bool-intersectsconst-circle-a-const-circle-b","title":"bool intersects(const Circle& a, const Circle& b)","text":"

Checks if two circles intersect.

Parameters: - a (const Circle&): First circle - b (const Circle&): Second circle

Returns: - bool: true if circles intersect

Example:

pixelroot32::physics::Circle circle1{100.0f, 100.0f, 10.0f};\npixelroot32::physics::Circle circle2{110.0f, 100.0f, 10.0f};\n\nif (pixelroot32::physics::intersects(circle1, circle2)) {\n    // Circles overlap\n}\n

"},{"location":"api_reference/physics/collision_types/#bool-intersectsconst-circle-c-const-rect-r","title":"bool intersects(const Circle& c, const Rect& r)","text":"

Checks if a circle and rectangle intersect.

Parameters: - c (const Circle&): Circle - r (const Rect&): Rectangle

Returns: - bool: true if circle and rectangle intersect

Example:

pixelroot32::physics::Circle circle{100.0f, 100.0f, 10.0f};\npixelroot32::core::Rect rect{95.0f, 95.0f, 20, 20};\n\nif (pixelroot32::physics::intersects(circle, rect)) {\n    // Circle overlaps rectangle\n}\n

"},{"location":"api_reference/physics/collision_types/#bool-intersectsconst-segment-s-const-rect-r","title":"bool intersects(const Segment& s, const Rect& r)","text":"

Checks if a line segment and rectangle intersect.

Parameters: - s (const Segment&): Line segment - r (const Rect&): Rectangle

Returns: - bool: true if segment and rectangle intersect

Example:

pixelroot32::physics::Segment segment{0.0f, 0.0f, 100.0f, 100.0f};\npixelroot32::core::Rect rect{50.0f, 50.0f, 20, 20};\n\nif (pixelroot32::physics::intersects(segment, rect)) {\n    // Segment intersects rectangle\n}\n

"},{"location":"api_reference/physics/collision_types/#bool-sweepcirclevsrectconst-circle-start-const-circle-end-const-rect-target-float-thit","title":"bool sweepCircleVsRect(const Circle& start, const Circle& end, const Rect& target, float& tHit)","text":"

Performs a sweep test: checks if a moving circle collides with a rectangle.

Parameters: - start (const Circle&): Circle at start position - end (const Circle&): Circle at end position - target (const Rect&): Target rectangle - tHit (float&): Output parameter for collision time (0.0 to 1.0)

Returns: - bool: true if collision occurs during sweep

Notes: - Useful for fast-moving projectiles - tHit indicates when collision occurs (0.0 = start, 1.0 = end) - More expensive than simple AABB check

Example:

// Projectile moving from (0, 0) to (100, 100)\npixelroot32::physics::Circle start{0.0f, 0.0f, 5.0f};\npixelroot32::physics::Circle end{100.0f, 100.0f, 5.0f};\npixelroot32::core::Rect wall{50.0f, 50.0f, 20, 20};\n\nfloat tHit = 0.0f;\nif (pixelroot32::physics::sweepCircleVsRect(start, end, wall, tHit)) {\n    // Collision at time tHit\n    float hitX = 0.0f + (100.0f - 0.0f) * tHit;\n    float hitY = 0.0f + (100.0f - 0.0f) * tHit;\n}\n

"},{"location":"api_reference/physics/collision_types/#rect-structure-from-coreentityh","title":"Rect Structure (from core/Entity.h)","text":"

Represents a 2D rectangle for collision detection.

Members: - float x, y: Top-left corner coordinates - int width, height: Dimensions

Methods: - bool intersects(const Rect& other) const: Checks if rectangles overlap

Example:

pixelroot32::core::Rect rect1{10.0f, 20.0f, 50, 50};\npixelroot32::core::Rect rect2{30.0f, 40.0f, 50, 50};\n\nif (rect1.intersects(rect2)) {\n    // Rectangles overlap\n}\n

"},{"location":"api_reference/physics/collision_types/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/physics/collision_types/#layer-based-collision","title":"Layer-Based Collision","text":"
// Define layers\nnamespace GameLayers {\n    const pixelroot32::physics::CollisionLayer kPlayer = 1 << 0;\n    const pixelroot32::physics::CollisionLayer kEnemy = 1 << 1;\n    const pixelroot32::physics::CollisionLayer kObstacle = 1 << 2;\n    const pixelroot32::physics::CollisionLayer kProjectile = 1 << 3;\n}\n\n// Player collides with enemies and obstacles\nplayer->layer = GameLayers::kPlayer;\nplayer->mask = GameLayers::kEnemy | GameLayers::kObstacle;\n\n// Enemy collides with player and obstacles\nenemy->layer = GameLayers::kEnemy;\nenemy->mask = GameLayers::kPlayer | GameLayers::kObstacle;\n\n// Projectile collides with enemies only\nprojectile->layer = GameLayers::kProjectile;\nprojectile->mask = GameLayers::kEnemy;\n
"},{"location":"api_reference/physics/collision_types/#circle-vs-circle-collision","title":"Circle vs Circle Collision","text":"
bool checkCollision(const Circle& a, const Circle& b) {\n    return pixelroot32::physics::intersects(a, b);\n}\n
"},{"location":"api_reference/physics/collision_types/#sweep-test-for-fast-projectiles","title":"Sweep Test for Fast Projectiles","text":"
class ProjectileActor : public pixelroot32::core::Actor {\nprivate:\n    float startX, startY;\n    float endX, endY;\n    float radius = 2.0f;\n\npublic:\n    bool checkWallCollision(const Rect& wall) {\n        pixelroot32::physics::Circle start{startX, startY, radius};\n        pixelroot32::physics::Circle end{endX, endY, radius};\n\n        float tHit = 0.0f;\n        if (pixelroot32::physics::sweepCircleVsRect(start, end, wall, tHit)) {\n            // Collision detected at time tHit\n            return true;\n        }\n        return false;\n    }\n};\n
"},{"location":"api_reference/physics/collision_types/#performance-considerations","title":"Performance Considerations","text":"
  • AABB checks: Very fast (simple rectangle intersection)
  • Circle checks: Slightly slower (distance calculation)
  • Sweep tests: More expensive (use only for fast-moving objects)
  • Layer filtering: Essential for performance with many actors
"},{"location":"api_reference/physics/collision_types/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Float math: Uses floating point; acceptable but integer math would be faster
  • Sweep tests: Use sparingly (more CPU intensive)
  • Layer efficiency: Use layers effectively to minimize checks
"},{"location":"api_reference/physics/collision_types/#see-also","title":"See Also","text":"
  • CollisionSystem - Collision detection system
  • Actor - Actors that use collision layers
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/ui/ui_button/","title":"UIButton","text":"

A clickable button UI element.

"},{"location":"api_reference/ui/ui_button/#description","title":"Description","text":"

UIButton is a clickable button that supports both physical (keyboard/gamepad) and touch input. It can trigger a callback function when pressed and integrates with UI layouts for automatic navigation.

Buttons support selection state (for D-pad navigation), custom styling, and text alignment.

"},{"location":"api_reference/ui/ui_button/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIButton : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_button/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom button classes (if needed)
"},{"location":"api_reference/ui/ui_button/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_button/#uibuttonstring-t-uint8_t-index-float-x-float-y-float-w-float-h-function-callback-textalignment-textalign-center-int-fontsize-2","title":"UIButton(string t, uint8_t index, float x, float y, float w, float h, function callback, TextAlignment textAlign = CENTER, int fontSize = 2)

Constructs a new UIButton.

Parameters: - t (std::string): Button label text - index (uint8_t): Navigation index (for D-pad navigation in layouts) - x (float): X position - y (float): Y position - w (float): Width - h (float): Height - callback (std::function): Function to call when clicked/pressed - textAlign (TextAlignment, optional): Text alignment. Default: CENTER - fontSize (int, optional): Text size multiplier. Default: 2

Example:

#include \"graphics/ui/UIButton.h\"\n\nvoid onStartButtonClicked() {\n    // Start game\n    engine.setScene(&gameScene);\n}\n\nvoid onQuitButtonClicked() {\n    // Quit game\n    engine.stop();\n}\n\n// Create buttons\npixelroot32::graphics::ui::UIButton* startButton = new pixelroot32::graphics::ui::UIButton(\n    \"Start\",\n    0,  // index\n    64.0f, 64.0f,  // position\n    100.0f, 30.0f, // size\n    onStartButtonClicked,\n    pixelroot32::graphics::ui::TextAlignment::CENTER,\n    2\n);\n\npixelroot32::graphics::ui::UIButton* quitButton = new pixelroot32::graphics::ui::UIButton(\n    \"Quit\",\n    1,  // index\n    64.0f, 100.0f,\n    100.0f, 30.0f,\n    onQuitButtonClicked\n);\n

","text":""},{"location":"api_reference/ui/ui_button/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_button/#void-setstylecolor-textcol-color-bgcol-bool-drawbg","title":"void setStyle(Color textCol, Color bgCol, bool drawBg)

Configures the button's visual style.

Parameters: - textCol (Color): Color of the text - bgCol (Color): Color of the background - drawBg (bool): Whether to draw the background rectangle

Returns: - void

Example:

button->setStyle(\n    pixelroot32::graphics::Color::White,  // Text color\n    pixelroot32::graphics::Color::Blue,   // Background color\n    true                                   // Draw background\n);\n

","text":""},{"location":"api_reference/ui/ui_button/#void-setselectedbool-selected","title":"void setSelected(bool selected)

Sets the selection state (e.g., focused via D-pad).

Parameters: - selected (bool): true if selected

Returns: - void

Notes: - Used by layouts for D-pad navigation - Selected buttons typically have different visual style - Can be set manually or automatically by layouts

Example:

button->setSelected(true);  // Highlight button\n

","text":""},{"location":"api_reference/ui/ui_button/#bool-getselected-const","title":"bool getSelected() const

Checks if the button is currently selected.

Returns: - bool: true if selected

Example:

if (button->getSelected()) {\n    // Button is focused\n}\n

","text":""},{"location":"api_reference/ui/ui_button/#bool-isfocusable-const-override","title":"bool isFocusable() const override

Returns true (Buttons are always focusable).

Returns: - bool: Always true

","text":""},{"location":"api_reference/ui/ui_button/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)

Handles input events. Checks for touch events within bounds or confirmation buttons if selected.

Parameters: - input (const pixelroot32::input::InputManager&): The input manager instance

Returns: - void

Notes: - Should be called every frame in update() - Checks if button is selected and action button is pressed - Triggers callback if conditions are met

Example:

void update(unsigned long deltaTime) override {\n    UIElement::update(deltaTime);\n\n    auto& input = engine.getInputManager();\n    button->handleInput(input);\n}\n

","text":""},{"location":"api_reference/ui/ui_button/#void-press","title":"void press()

Manually triggers the button's action.

Returns: - void

Notes: - Calls the button's callback function - Useful for programmatic button presses

Example:

button->press();  // Trigger button action\n

","text":""},{"location":"api_reference/ui/ui_button/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override

Updates the button state.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Handles input and updates button state - Override to add custom update logic

Example:

void update(unsigned long deltaTime) override {\n    UIButton::update(deltaTime);\n\n    // Custom update logic\n    if (shouldPulse) {\n        // Animate button\n    }\n}\n

","text":""},{"location":"api_reference/ui/ui_button/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override

Renders the button.

Parameters: - renderer (pixelroot32::graphics::Renderer&): The renderer to use

Returns: - void

Notes: - Called automatically by Scene if isVisible is true - Draws background (if enabled) and text - Selected state may change appearance

Example:

// Drawing is handled automatically\n// Override only for custom rendering\n

","text":""},{"location":"api_reference/ui/ui_button/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIButton.h\"\n#include \"core/Scene.h\"\n\nclass MainMenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIButton* startButton;\n    pixelroot32::graphics::ui::UIButton* quitButton;\n\npublic:\n    void init() override {\n        // Start button\n        startButton = new pixelroot32::graphics::ui::UIButton(\n            \"Start Game\",\n            0,  // index\n            64.0f, 50.0f,  // position (centered)\n            120.0f, 30.0f, // size\n            [this]() {\n                // Lambda callback\n                engine.setScene(&gameScene);\n            },\n            pixelroot32::graphics::ui::TextAlignment::CENTER,\n            2\n        );\n        startButton->setStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Blue,\n            true\n        );\n        addEntity(startButton);\n\n        // Quit button\n        quitButton = new pixelroot32::graphics::ui::UIButton(\n            \"Quit\",\n            1,  // index\n            64.0f, 90.0f,\n            120.0f, 30.0f,\n            [this]() {\n                // Quit game\n                engine.stop();\n            }\n        );\n        quitButton->setStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Red,\n            true\n        );\n        addEntity(quitButton);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Buttons handle input automatically\n        // Layouts handle navigation automatically\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background\n        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n\n        // Draw UI elements (buttons)\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"api_reference/ui/ui_button/#button-navigation","title":"Button Navigation","text":"

Buttons can be navigated with D-pad when in layouts:

// Buttons in a vertical layout\npixelroot32::graphics::ui::UIVerticalLayout* layout = new UIVerticalLayout(64.0f, 50.0f);\nlayout->addChild(startButton);  // Index 0\nlayout->addChild(quitButton);   // Index 1\n\n// D-pad navigation is automatic\n// UP/DOWN moves selection\n// Action button (A) triggers selected button\n
"},{"location":"api_reference/ui/ui_button/#performance-considerations","title":"Performance Considerations","text":"
  • Input handling: handleInput() is fast; safe to call every frame
  • Rendering: Simple rectangle and text; very efficient
  • Memory: Each button consumes memory (stay within MAX_ENTITIES)
"},{"location":"api_reference/ui/ui_button/#esp32-considerations","title":"ESP32 Considerations","text":"
  • String storage: Button labels use std::string; consider memory usage
  • Callback functions: Use function pointers or lambdas (both efficient)
"},{"location":"api_reference/ui/ui_button/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UILabel - Text label
  • UILayouts - Layout containers
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_checkbox/","title":"UICheckBox","text":"

A clickable checkbox UI element.

"},{"location":"api_reference/ui/ui_checkbox/#description","title":"Description","text":"

UICheckBox is a clickable checkbox that can be toggled between checked and unchecked states. It supports both physical (keyboard/gamepad) and touch input. It can trigger a callback function when its state changes and integrates with UI layouts for automatic navigation.

"},{"location":"api_reference/ui/ui_checkbox/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UICheckBox : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_checkbox/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
"},{"location":"api_reference/ui/ui_checkbox/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_checkbox/#uicheckboxstring-label-uint8_t-index-float-x-float-y-float-w-float-h-bool-checked-false-function-callback-nullptr-int-fontsize-2","title":"UICheckBox(string label, uint8_t index, float x, float y, float w, float h, bool checked = false, function callback = nullptr, int fontSize = 2)

Constructs a new UICheckBox.

Parameters: - label (std::string): Checkbox label text - index (uint8_t): Navigation index (for D-pad navigation in layouts) - x (float): X position - y (float): Y position - w (float): Width - h (float): Height - checked (bool, optional): Initial checked state. Default: false - callback (std::function, optional): Function to call when the state changes. Default: nullptr - fontSize (int, optional): Text size multiplier. Default: 2

Example:

#include \"graphics/ui/UICheckBox.h\"\n\nvoid onCheckChanged(bool checked) {\n    if (checked) {\n        // Sound enabled\n    } else {\n        // Sound disabled\n    }\n}\n\n// Create checkbox\npixelroot32::graphics::ui::UICheckBox* soundCheckbox = new pixelroot32::graphics::ui::UICheckBox(\n    \"Enable Sound\",\n    0,  // index\n    64.0f, 64.0f,  // position\n    120.0f, 20.0f, // size\n    true,          // initial state\n    onCheckChanged,\n    1              // font size\n);\n

","text":""},{"location":"api_reference/ui/ui_checkbox/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_checkbox/#void-setstylecolor-textcol-color-bgcol-bool-drawbg-false","title":"void setStyle(Color textCol, Color bgCol, bool drawBg = false)

Configures the checkbox's visual style.

Parameters: - textCol (Color): Color of the text - bgCol (Color): Color of the background - drawBg (bool, optional): Whether to draw the background rectangle. Default: false

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#void-setcheckedbool-checked","title":"void setChecked(bool checked)

Sets the checked state.

Parameters: - checked (bool): True if checked

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#bool-ischecked-const","title":"bool isChecked() const

Checks if the checkbox is currently checked.

Returns: - bool: true if checked

","text":""},{"location":"api_reference/ui/ui_checkbox/#void-toggle","title":"void toggle()

Toggles the checkbox state and triggers the callback.

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#void-setselectedbool-selected","title":"void setSelected(bool selected)

Sets the selection state (e.g., focused via D-pad).

Parameters: - selected (bool): True if selected

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#bool-getselected-const","title":"bool getSelected() const

Checks if the checkbox is currently selected.

Returns: - bool: true if selected

","text":""},{"location":"api_reference/ui/ui_checkbox/#callbacks","title":"Callbacks","text":""},{"location":"api_reference/ui/ui_checkbox/#oncheckchanged","title":"onCheckChanged

The onCheckChanged callback is a std::function<void(bool)> that is triggered whenever the checkbox state changes via setChecked() or toggle().

checkbox->onCheckChanged = [](bool isChecked) {\n    Serial.println(isChecked ? \"Checked!\" : \"Unchecked!\");\n};\n
","text":""},{"location":"api_reference/ui/ui_checkbox/#navigation-layouts","title":"Navigation & Layouts","text":"

UICheckBox is designed to work seamlessly with UILayout containers (like UIVerticalLayout).

  • Focusable: Returns true for isFocusable(), allowing it to receive focus in a layout.
  • Input Handling: When selected (focused), it listens for the button index provided in the constructor (typically the 'A' button) to toggle its state.
  • Visual Feedback: When selected, it displays a selection indicator (usually a > character) if no background is drawn, or highlights its text/border.
"},{"location":"api_reference/ui/ui_element/","title":"UIElement","text":"

Base class for all user interface elements.

"},{"location":"api_reference/ui/ui_element/#description","title":"Description","text":"

UIElement is the base class for all UI components (buttons, labels, panels, etc.). It inherits from Entity to integrate with the scene graph and automatically sets the entity type to UI_ELEMENT and render layer to 2 (UI layer).

"},{"location":"api_reference/ui/ui_element/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    enum class UIElementType {\n        GENERIC,\n        BUTTON,\n        LABEL,\n        CHECKBOX,\n        LAYOUT\n    };\n\n    class UIElement : public pixelroot32::core::Entity {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_element/#inheritance","title":"Inheritance","text":"
  • Inherits from: pixelroot32::core::Entity
  • Inherited by: UIButton, UICheckBox, UILabel, UIPanel, and all UI layouts
"},{"location":"api_reference/ui/ui_element/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_element/#uielementfloat-x-float-y-float-w-float-h-uielementtype-type-uielementtypegeneric","title":"UIElement(float x, float y, float w, float h, UIElementType type = UIElementType::GENERIC)","text":"

Constructs a new UIElement.

Parameters: - x (float): X position - y (float): Y position - w (float): Width - h (float): Height - type (UIElementType): The type of the element (default: GENERIC)

Notes: - Entity type is automatically set to UI_ELEMENT - Render layer is automatically set to 2 (UI layer) - Position and size can be modified after construction

Example:

class MyUIElement : public pixelroot32::graphics::ui::UIElement {\npublic:\n    MyUIElement(float x, float y) \n        : UIElement(x, y, 100.0f, 50.0f) {}\n\n    void update(unsigned long deltaTime) override {\n        // UI logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // UI rendering\n    }\n};\n

"},{"location":"api_reference/ui/ui_element/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_element/#uielementtype-gettype-const","title":"UIElementType getType() const","text":"

Returns the type of the UI element.

Returns: - UIElementType: The type enum value (GENERIC, BUTTON, LABEL, CHECKBOX, or LAYOUT)

"},{"location":"api_reference/ui/ui_element/#virtual-bool-isfocusable-const","title":"virtual bool isFocusable() const","text":"

Checks if the element is focusable/selectable. Useful for navigation logic.

Returns: - bool: true if focusable, false otherwise (default: false)

"},{"location":"api_reference/ui/ui_element/#void-setpositionfloat-newx-float-newy","title":"void setPosition(float newX, float newY)","text":"

Sets the position of the element.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Updates element position immediately - Use for manual positioning or animations

Example:

uiElement->setPosition(100.0f, 50.0f);\n

"},{"location":"api_reference/ui/ui_element/#virtual-void-getpreferredsizefloat-preferredwidth-float-preferredheight-const","title":"virtual void getPreferredSize(float& preferredWidth, float& preferredHeight) const","text":"

Gets the preferred size of the element. Used by layouts to determine how much space the element needs.

Parameters: - preferredWidth (float&): Output parameter for preferred width (or -1 if flexible) - preferredHeight (float&): Output parameter for preferred height (or -1 if flexible)

Returns: - void

Notes: - Default implementation returns current width/height - Override in derived classes for custom sizing logic - Layouts use this to arrange elements

Example:

void getPreferredSize(float& w, float& h) const override {\n    // Custom sizing logic\n    w = static_cast<float>(width);\n    h = static_cast<float>(height);\n}\n

"},{"location":"api_reference/ui/ui_element/#inherited-from-entity","title":"Inherited from Entity","text":"

UIElement inherits all properties and methods from Entity:

  • float x, y: Position
  • int width, height: Dimensions
  • bool isVisible: Visibility state
  • bool isEnabled: Enabled state
  • unsigned char renderLayer: Render layer (automatically set to 2)
  • void setVisible(bool v): Set visibility
  • void setEnabled(bool e): Set enabled state
  • virtual void update(unsigned long deltaTime): Update logic
  • virtual void draw(Renderer& renderer): Drawing logic
"},{"location":"api_reference/ui/ui_element/#textalignment-enum","title":"TextAlignment Enum","text":"

Text alignment options for UI elements.

Values: - TextAlignment::LEFT: Left-aligned text - TextAlignment::CENTER: Center-aligned text - TextAlignment::RIGHT: Right-aligned text

"},{"location":"api_reference/ui/ui_element/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIElement.h\"\n\nclass CustomUIElement : public pixelroot32::graphics::ui::UIElement {\nprivate:\n    pixelroot32::graphics::Color bgColor;\n\npublic:\n    CustomUIElement(float x, float y, float w, float h) \n        : UIElement(x, y, w, h),\n          bgColor(pixelroot32::graphics::Color::Blue) {}\n\n    void update(unsigned long deltaTime) override {\n        // Update logic (if needed)\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        if (isVisible) {\n            // Draw background\n            renderer.drawFilledRectangle(\n                static_cast<int>(x),\n                static_cast<int>(y),\n                width,\n                height,\n                bgColor\n            );\n\n            // Draw border\n            renderer.drawRectangle(\n                static_cast<int>(x),\n                static_cast<int>(y),\n                width,\n                height,\n                pixelroot32::graphics::Color::White\n            );\n        }\n    }\n\n    void getPreferredSize(float& w, float& h) const override {\n        w = static_cast<float>(width);\n        h = static_cast<float>(height);\n    }\n};\n
"},{"location":"api_reference/ui/ui_element/#performance-considerations","title":"Performance Considerations","text":"
  • Render layer: UI elements are on layer 2, drawn after gameplay
  • Visibility: Use isVisible = false to hide elements efficiently
  • Layout integration: Layouts automatically manage element positioning
"},{"location":"api_reference/ui/ui_element/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Each UI element consumes memory (stay within MAX_ENTITIES)
  • Object pooling: Reuse UI elements when possible
  • Update frequency: Disable UI elements that don't need to update
"},{"location":"api_reference/ui/ui_element/#see-also","title":"See Also","text":"
  • Entity - Base entity class
  • UIButton - Clickable button
  • UILabel - Text label
  • UILayout - Layout containers
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_label/","title":"UILabel","text":"

A simple text label UI element.

"},{"location":"api_reference/ui/ui_label/#description","title":"Description","text":"

UILabel displays a string of text on the screen. It auto-calculates its bounds based on text length and font size, making it easy to create dynamic text displays.

Labels are useful for displaying scores, status messages, menu text, and other UI information.

"},{"location":"api_reference/ui/ui_label/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UILabel : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_label/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom label classes (if needed)
"},{"location":"api_reference/ui/ui_label/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_label/#uilabelstring-t-float-x-float-y-color-col-uint8_t-sz","title":"UILabel(string t, float x, float y, Color col, uint8_t sz)","text":"

Constructs a new UILabel.

Parameters: - t (std::string): Initial text - x (float): X position - y (float): Y position - col (Color): Text color - sz (uint8_t): Text size multiplier

Example:

#include \"graphics/ui/UILabel.h\"\n\n// Create label\npixelroot32::graphics::ui::UILabel* scoreLabel = new pixelroot32::graphics::ui::UILabel(\n    \"Score: 0\",\n    10.0f, 10.0f,  // position\n    pixelroot32::graphics::Color::White,\n    1  // size\n);\n\n// Add to scene\nscene->addEntity(scoreLabel);\n

"},{"location":"api_reference/ui/ui_label/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_label/#void-settextconst-string-t","title":"void setText(const string& t)","text":"

Updates the label's text. Recalculates dimensions immediately using the active font metrics to ensure precise layout.

Parameters: - t (const std::string&): New text

Returns: - void

Notes: - Automatically recalculates width and height using FontManager::textWidth - Use for dynamic text (scores, timers, etc.) - Text is stored as std::string (consider memory on ESP32)

Example:

// Update score label\nchar scoreText[32];\nsnprintf(scoreText, sizeof(scoreText), \"Score: %d\", score);\nscoreLabel->setText(scoreText);\n

"},{"location":"api_reference/ui/ui_label/#void-setvisiblebool-v","title":"void setVisible(bool v)","text":"

Sets visibility.

Parameters: - v (bool): true to show, false to hide

Returns: - void

Notes: - Inherited from Entity - Hides label without removing from scene

Example:

label->setVisible(false);  // Hide\nlabel->setVisible(true);   // Show\n

"},{"location":"api_reference/ui/ui_label/#void-centerxint-screenwidth","title":"void centerX(int screenWidth)","text":"

Centers the label horizontally within a given width (typically the screen width). Recalculates dimensions before positioning to ensure perfect centering.

Parameters: - screenWidth (int): The width to center within (e.g., engine.getRenderer().getWidth())

Returns: - void

Example:

label->centerX(128); // Center on a 128px screen\n

"},{"location":"api_reference/ui/ui_label/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the label state.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Default implementation does nothing - Override to add custom update logic (animations, etc.)

Example:

void update(unsigned long deltaTime) override {\n    UILabel::update(deltaTime);\n\n    // Custom logic (e.g., update text based on game state)\n    if (scoreChanged) {\n        updateScoreText();\n    }\n}\n

"},{"location":"api_reference/ui/ui_label/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Renders the label.

Parameters: - renderer (pixelroot32::graphics::Renderer&): The renderer to use

Returns: - void

Notes: - Called automatically by Scene if isVisible is true - Draws text at label position - Uses default font

Example:

// Drawing is handled automatically\n// Override only for custom rendering\n

"},{"location":"api_reference/ui/ui_label/#auto-sizing","title":"Auto-Sizing","text":"

Labels automatically calculate their size based on text:

  • Width: text.length() * (6 * size) pixels
  • Height: 8 * size pixels

Example:

// Label with text \"Hello\" (5 characters), size 1\n// Width: 5 * 6 * 1 = 30 pixels\n// Height: 8 * 1 = 8 pixels\n\nUILabel label(\"Hello\", 10, 10, Color::White, 1);\n// label.width = 30, label.height = 8\n

"},{"location":"api_reference/ui/ui_label/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UILabel.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n    int score = 0;\n    int lives = 3;\n\npublic:\n    void init() override {\n        // Score label\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\",\n            10.0f, 10.0f,\n            pixelroot32::graphics::Color::White,\n            1\n        );\n        addEntity(scoreLabel);\n\n        // Lives label\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\",\n            10.0f, 25.0f,\n            pixelroot32::graphics::Color::Yellow,\n            1\n        );\n        addEntity(livesLabel);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Update labels\n        char text[32];\n        snprintf(text, sizeof(text), \"Score: %d\", score);\n        scoreLabel->setText(text);\n\n        snprintf(text, sizeof(text), \"Lives: %d\", lives);\n        livesLabel->setText(text);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw game\n        Scene::draw(renderer);\n\n        // Labels are drawn automatically by Scene::draw()\n    }\n};\n
"},{"location":"api_reference/ui/ui_label/#centered-labels","title":"Centered Labels","text":"
// Create centered title\npixelroot32::graphics::ui::UILabel* title = new pixelroot32::graphics::ui::UILabel(\n    \"Game Title\",\n    0, 20.0f,  // X will be adjusted\n    pixelroot32::graphics::Color::Yellow,\n    2  // Large text\n);\ntitle->centerX(128);  // Center on screen\naddEntity(title);\n
"},{"location":"api_reference/ui/ui_label/#performance-considerations","title":"Performance Considerations","text":"
  • Text updates: setText() recalculates size; avoid calling every frame if text doesn't change
  • String storage: Uses std::string; consider memory on ESP32
  • Rendering: Simple text drawing; very efficient
  • Static text: For static text, create once and don't update
"},{"location":"api_reference/ui/ui_label/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: std::string uses heap memory; use static buffers when possible
  • Text updates: Limit frequency of text updates
  • String length: Keep text short to save memory
"},{"location":"api_reference/ui/ui_label/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UIButton - Clickable button
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layout/","title":"UILayout","text":"

Base class for UI layout containers.

"},{"location":"api_reference/ui/ui_layout/#description","title":"Description","text":"

UILayout is the base class for all layout containers. Layouts organize UI elements automatically, handling positioning, spacing, and optional scrolling. Layouts are themselves UI elements that can be added to scenes.

"},{"location":"api_reference/ui/ui_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UILayout : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: UIVerticalLayout, UIHorizontalLayout, UIGridLayout, UIAnchorLayout
"},{"location":"api_reference/ui/ui_layout/#scrollbehavior-enum","title":"ScrollBehavior Enum","text":"

Defines how scrolling behaves in layouts.

Values: - ScrollBehavior::NONE: No scrolling allowed - ScrollBehavior::SCROLL: Scroll freely within bounds - ScrollBehavior::CLAMP: Scroll but clamp to content bounds

"},{"location":"api_reference/ui/ui_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layout/#virtual-void-addelementuielement-element-0","title":"virtual void addElement(UIElement* element) = 0","text":"

Adds a UI element to the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to add

"},{"location":"api_reference/ui/ui_layout/#virtual-void-removeelementuielement-element-0","title":"virtual void removeElement(UIElement* element) = 0","text":"

Removes a UI element from the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to remove

"},{"location":"api_reference/ui/ui_layout/#virtual-void-updatelayout-0","title":"virtual void updateLayout() = 0","text":"

Recalculates positions of all elements in the layout. Must be implemented by derived classes.

Returns: - void

Notes: - Should be called automatically when elements are added/removed

"},{"location":"api_reference/ui/ui_layout/#virtual-void-handleinputconst-inputmanager-input-0","title":"virtual void handleInput(const InputManager& input) = 0","text":"

Handles input for layout navigation (scroll, selection, etc.). Must be implemented by derived classes.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

"},{"location":"api_reference/ui/ui_layout/#void-setpaddingfloat-p","title":"void setPadding(float p)","text":"

Sets the padding (internal spacing) of the layout.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Layout is automatically recalculated

"},{"location":"api_reference/ui/ui_layout/#float-getpadding-const","title":"float getPadding() const","text":"

Gets the current padding.

Returns: - float: Padding value in pixels

"},{"location":"api_reference/ui/ui_layout/#void-setspacingfloat-s","title":"void setSpacing(float s)","text":"

Sets the spacing between elements.

Parameters: - s (float): Spacing value in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Default: 4.0 pixels

"},{"location":"api_reference/ui/ui_layout/#float-getspacing-const","title":"float getSpacing() const","text":"

Gets the current spacing.

Returns: - float: Spacing value in pixels

"},{"location":"api_reference/ui/ui_layout/#size_t-getelementcount-const","title":"size_t getElementCount() const","text":"

Gets the number of elements in the layout.

Returns: - size_t: Element count

"},{"location":"api_reference/ui/ui_layout/#uielement-getelementsize_t-index-const","title":"UIElement* getElement(size_t index) const","text":"

Gets the element at a specific index.

Parameters: - index (size_t): Element index

Returns: - UIElement*: Pointer to the element, or nullptr if index is invalid

"},{"location":"api_reference/ui/ui_layout/#void-clearelements","title":"void clearElements()","text":"

Clears all elements from the layout.

Returns: - void

Notes: - Elements are not deleted (you must manage their lifetimes) - Layout is automatically recalculated

"},{"location":"api_reference/ui/ui_layout/#protected-members","title":"Protected Members","text":"
  • std::vector<UIElement*> elements: List of child elements
  • float padding: Internal padding
  • float spacing: Spacing between elements (default: 4.0)
  • float scrollOffset: Current scroll offset
  • bool enableScroll: Whether scrolling is enabled
  • ScrollBehavior scrollBehavior: Scroll behavior mode
"},{"location":"api_reference/ui/ui_layout/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UIVerticalLayout - Vertical layout
  • UIHorizontalLayout - Horizontal layout
  • UIGridLayout - Grid layout
  • UIAnchorLayout - Anchor layout
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/","title":"UIAnchorLayout","text":"

Layout that positions elements at fixed anchor points on the screen.

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#description","title":"Description","text":"

UIAnchorLayout positions UI elements at fixed anchor points (corners, center, edges) without reflow. Very efficient for HUDs, debug UI, and fixed-position elements. Positions are calculated once or when screen size changes.

This layout is ideal for HUD elements like score, lives, health bars, and other fixed-position UI.

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIAnchorLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom anchor layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#anchor-enum","title":"Anchor Enum","text":"

Defines anchor points for positioning UI elements.

Values: - Anchor::TOP_LEFT: Top-left corner - Anchor::TOP_RIGHT: Top-right corner - Anchor::BOTTOM_LEFT: Bottom-left corner - Anchor::BOTTOM_RIGHT: Bottom-right corner - Anchor::CENTER: Center of screen - Anchor::TOP_CENTER: Top center - Anchor::BOTTOM_CENTER: Bottom center - Anchor::LEFT_CENTER: Left center - Anchor::RIGHT_CENTER: Right center

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/anchor_layout/#uianchorlayoutfloat-x-float-y-float-w-float-h","title":"UIAnchorLayout(float x, float y, float w, float h)","text":"

Constructs a new UIAnchorLayout.

Parameters: - x (float): X position of the layout container (usually 0) - y (float): Y position of the layout container (usually 0) - w (float): Width of the layout container (usually screen width) - h (float): Height of the layout container (usually screen height)

Example:

#include \"graphics/ui/UIAnchorLayout.h\"\n\n// Create full-screen anchor layout for HUD\nauto& renderer = engine.getRenderer();\npixelroot32::graphics::ui::UIAnchorLayout* hud = \n    new pixelroot32::graphics::ui::UIAnchorLayout(\n        0.0f, 0.0f,\n        static_cast<float>(renderer.getWidth()),\n        static_cast<float>(renderer.getHeight())\n    );\nhud->setScreenSize(\n    static_cast<float>(renderer.getWidth()),\n    static_cast<float>(renderer.getHeight())\n);\n

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-addelementuielement-element-anchor-anchor","title":"void addElement(UIElement* element, Anchor anchor)","text":"

Adds a UI element with a specific anchor point.

Parameters: - element (UIElement*): Pointer to the element to add - anchor (Anchor): Anchor point for positioning

Returns: - void

Example:

// Score label at top-right\nhud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\n// Lives label at top-left\nhud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout (defaults to TOP_LEFT anchor).

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements based on anchors.

Returns: - void

Notes: - Called automatically when screen size changes - Can be called manually if needed

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input (no-op for anchor layout, elements handle their own input).

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Anchor layout doesn't handle navigation - Elements handle their own input

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout and child elements.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws all elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-setscreensizefloat-screenwidth-float-screenheight","title":"void setScreenSize(float screenWidth, float screenHeight)","text":"

Sets the screen size for anchor calculations.

Parameters: - screenWidth (float): Screen width in pixels - screenHeight (float): Screen height in pixels

Returns: - void

Notes: - Used to calculate anchor positions - Should match actual display size - Layout is automatically recalculated

Example:

auto& renderer = engine.getRenderer();\nhud->setScreenSize(\n    static_cast<float>(renderer.getWidth()),\n    static_cast<float>(renderer.getHeight())\n);\n

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#float-getscreenwidth-const","title":"float getScreenWidth() const","text":"

Gets the screen width.

Returns: - float: Screen width in pixels

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#float-getscreenheight-const","title":"float getScreenHeight() const","text":"

Gets the screen height.

Returns: - float: Screen height in pixels

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIAnchorLayout.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIAnchorLayout* hud;\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n\npublic:\n    void init() override {\n        auto& renderer = engine.getRenderer();\n\n        // Create HUD layout\n        hud = new pixelroot32::graphics::ui::UIAnchorLayout(\n            0.0f, 0.0f,\n            static_cast<float>(renderer.getWidth()),\n            static_cast<float>(renderer.getHeight())\n        );\n        hud->setScreenSize(\n            static_cast<float>(renderer.getWidth()),\n            static_cast<float>(renderer.getHeight())\n        );\n\n        // Score label (top-right)\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\",\n            0, 0,\n            Color::White,\n            1\n        );\n        hud->addElement(scoreLabel, \n                        pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\n        // Lives label (top-left)\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\",\n            0, 0,\n            Color::Yellow,\n            1\n        );\n        hud->addElement(livesLabel, \n                        pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n\n        addEntity(hud);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Update labels\n        char text[32];\n        snprintf(text, sizeof(text), \"Score: %d\", score);\n        scoreLabel->setText(text);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw game\n        Scene::draw(renderer);\n\n        // HUD is drawn automatically (on layer 2)\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#anchor-positioning","title":"Anchor Positioning","text":"

Elements are positioned based on their anchor:

  • TOP_LEFT: Element's top-left at screen top-left
  • TOP_RIGHT: Element's top-right at screen top-right
  • BOTTOM_LEFT: Element's bottom-left at screen bottom-left
  • BOTTOM_RIGHT: Element's bottom-right at screen bottom-right
  • CENTER: Element centered on screen
  • TOP_CENTER: Element centered horizontally, top-aligned
  • BOTTOM_CENTER: Element centered horizontally, bottom-aligned
  • LEFT_CENTER: Element centered vertically, left-aligned
  • RIGHT_CENTER: Element centered vertically, right-aligned
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#performance-considerations","title":"Performance Considerations","text":"
  • No reflow: Very efficient (positions calculated once)
  • Fixed positions: Ideal for HUD elements
  • Viewport independent: Elements stay in fixed screen positions
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Very efficient (no complex calculations)
  • Update frequency: Positions only recalculate when screen size changes
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class
  • UILabel - Labels for HUD
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/grid_layout/","title":"UIGridLayout","text":"

Grid layout container for organizing elements in a matrix.

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#description","title":"Description","text":"

UIGridLayout organizes UI elements in a fixed grid of rows and columns. It supports navigation in 4 directions (UP/DOWN/LEFT/RIGHT) and automatic positioning based on grid coordinates.

This layout is ideal for inventories, level selection screens, galleries, and any grid-based UI arrangement.

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIGridLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/grid_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom grid layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/grid_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/grid_layout/#uigridlayoutfloat-x-float-y-float-w-float-h","title":"UIGridLayout(float x, float y, float w, float h)","text":"

Constructs a new UIGridLayout.

Parameters: - x (float): X position of the layout container - y (float): Y position of the layout container - w (float): Width of the layout container - h (float): Height of the layout container

Example:

#include \"graphics/ui/UIGridLayout.h\"\n\n// Create 4x4 grid for inventory\npixelroot32::graphics::ui::UIGridLayout* inventory = \n    new pixelroot32::graphics::ui::UIGridLayout(\n        10.0f, 10.0f,  // position\n        108.0f, 108.0f // size\n    );\ninventory->setColumns(4);\n

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout.

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

Notes: - Elements are arranged in grid order (left to right, top to bottom) - Layout is automatically recalculated - Cell size is calculated based on columns and layout size

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements.

Returns: - void

Notes: - Recalculates cell dimensions - Recalculates row count - Repositions all elements

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input for navigation and selection.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Handles UP/DOWN/LEFT/RIGHT navigation - Manages selection state - Wraps around grid edges (if configured)

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout and child elements.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the layout and its visible elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setcolumnsuint8_t-cols","title":"void setColumns(uint8_t cols)","text":"

Sets the number of columns in the grid.

Parameters: - cols (uint8_t): Number of columns (must be > 0)

Returns: - void

Notes: - Layout is automatically recalculated - Row count is calculated based on element count and columns

Example:

inventory->setColumns(4);  // 4 columns\n

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#uint8_t-getcolumns-const","title":"uint8_t getColumns() const","text":"

Gets the number of columns.

Returns: - uint8_t: Number of columns

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#uint8_t-getrows-const","title":"uint8_t getRows() const","text":"

Gets the number of rows (calculated).

Returns: - uint8_t: Number of rows

Notes: - Calculated as ceil(elementCount / columns)

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#int-getselectedindex-const","title":"int getSelectedIndex() const","text":"

Gets the currently selected element index.

Returns: - int: Selected index, or -1 if none selected

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setselectedindexint-index","title":"void setSelectedIndex(int index)","text":"

Sets the selected element index.

Parameters: - index (int): Index to select (-1 to deselect)

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#uielement-getselectedelement-const","title":"UIElement* getSelectedElement() const","text":"

Gets the selected element.

Returns: - UIElement*: Pointer to selected element, or nullptr if none selected

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setnavigationbuttonsuint8_t-upbutton-uint8_t-downbutton-uint8_t-leftbutton-uint8_t-rightbutton","title":"void setNavigationButtons(uint8_t upButton, uint8_t downButton, uint8_t leftButton, uint8_t rightButton)","text":"

Sets the navigation button indices.

Parameters: - upButton (uint8_t): Button index for UP navigation - downButton (uint8_t): Button index for DOWN navigation - leftButton (uint8_t): Button index for LEFT navigation - rightButton (uint8_t): Button index for RIGHT navigation

Returns: - void

Notes: - Default: UP=0, DOWN=1, LEFT=2, RIGHT=3 - Change if your input mapping differs

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setbuttonstylecolor-selectedtextcol-color-selectedbgcol-color-unselectedtextcol-color-unselectedbgcol","title":"void setButtonStyle(Color selectedTextCol, Color selectedBgCol, Color unselectedTextCol, Color unselectedBgCol)","text":"

Sets the style colors for selected and unselected buttons.

Parameters: - selectedTextCol (Color): Text color when selected - selectedBgCol (Color): Background color when selected - unselectedTextCol (Color): Text color when not selected - unselectedBgCol (Color): Background color when not selected

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIGridLayout.h\"\n\nclass InventoryScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIGridLayout* inventory;\n\npublic:\n    void init() override {\n        // Create 4x4 inventory grid\n        inventory = new pixelroot32::graphics::ui::UIGridLayout(\n            10.0f, 10.0f,\n            108.0f, 108.0f\n        );\n        inventory->setColumns(4);\n        inventory->setSpacing(2.0f);\n        inventory->setPadding(4.0f);\n\n        // Add inventory slots\n        for (int i = 0; i < 16; i++) {\n            auto* slot = createInventorySlot(i);\n            inventory->addElement(slot);\n        }\n\n        addEntity(inventory);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/grid_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class (abstract)
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/","title":"UIHorizontalLayout","text":"

Horizontal layout container with scroll support.

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#description","title":"Description","text":"

UIHorizontalLayout organizes UI elements horizontally, one next to another. It supports scrolling when content exceeds the visible viewport and handles keyboard/D-pad navigation automatically.

This layout is ideal for toolbars, tab bars, horizontal menus, and any horizontal arrangement of UI elements.

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIHorizontalLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom horizontal layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#uihorizontallayoutfloat-x-float-y-float-w-float-h","title":"UIHorizontalLayout(float x, float y, float w, float h)","text":"

Constructs a new UIHorizontalLayout.

Parameters: - x (float): X position of the layout container - y (float): Y position of the layout container - w (float): Width of the layout container (viewport width) - h (float): Height of the layout container

Example:

#include \"graphics/ui/UIHorizontalLayout.h\"\n\n// Create horizontal layout for toolbar\npixelroot32::graphics::ui::UIHorizontalLayout* toolbar = \n    new pixelroot32::graphics::ui::UIHorizontalLayout(\n        0.0f, 0.0f,   // position (top of screen)\n        128.0f, 20.0f // size\n    );\n

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout.

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

Notes: - Elements are arranged horizontally, left to right - Layout is automatically recalculated - Elements are positioned based on spacing and padding

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements.

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input for navigation and scrolling.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Handles LEFT/RIGHT navigation - Manages selection state - Handles scrolling if enabled

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout (handles smooth scrolling).

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the layout and its visible elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setscrollenabledbool-enable","title":"void setScrollEnabled(bool enable)","text":"

Enables or disables scrolling.

Parameters: - enable (bool): true to enable scrolling

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setviewportwidthfloat-w","title":"void setViewportWidth(float w)","text":"

Sets the viewport width (visible area).

Parameters: - w (float): Viewport width in pixels

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#float-getscrolloffset-const","title":"float getScrollOffset() const","text":"

Gets the current scroll offset.

Returns: - float: Scroll offset in pixels

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setscrolloffsetfloat-offset","title":"void setScrollOffset(float offset)","text":"

Sets the scroll offset directly.

Parameters: - offset (float): Scroll offset in pixels

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#float-getcontentwidth-const","title":"float getContentWidth() const","text":"

Gets the total content width.

Returns: - float: Content width in pixels

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#int-getselectedindex-const","title":"int getSelectedIndex() const","text":"

Gets the currently selected element index.

Returns: - int: Selected index, or -1 if none selected

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setselectedindexint-index","title":"void setSelectedIndex(int index)","text":"

Sets the selected element index.

Parameters: - index (int): Index to select (-1 to deselect)

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#uielement-getselectedelement-const","title":"UIElement* getSelectedElement() const","text":"

Gets the selected element.

Returns: - UIElement*: Pointer to selected element, or nullptr if none selected

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setscrollspeedfloat-speed","title":"void setScrollSpeed(float speed)","text":"

Sets the scroll speed for smooth scrolling.

Parameters: - speed (float): Pixels per millisecond

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setnavigationbuttonsuint8_t-leftbutton-uint8_t-rightbutton","title":"void setNavigationButtons(uint8_t leftButton, uint8_t rightButton)","text":"

Sets the navigation button indices.

Parameters: - leftButton (uint8_t): Button index for LEFT navigation - rightButton (uint8_t): Button index for RIGHT navigation

Returns: - void

Notes: - Default: LEFT = 2, RIGHT = 3 - Change if your input mapping differs

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setbuttonstylecolor-selectedtextcol-color-selectedbgcol-color-unselectedtextcol-color-unselectedbgcol","title":"void setButtonStyle(Color selectedTextCol, Color selectedBgCol, Color unselectedTextCol, Color unselectedBgCol)","text":"

Sets the style colors for selected and unselected buttons.

Parameters: - selectedTextCol (Color): Text color when selected - selectedBgCol (Color): Background color when selected - unselectedTextCol (Color): Text color when not selected - unselectedBgCol (Color): Background color when not selected

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIHorizontalLayout.h\"\n\nclass ToolbarScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIHorizontalLayout* toolbar;\n\npublic:\n    void init() override {\n        // Create horizontal toolbar\n        toolbar = new pixelroot32::graphics::ui::UIHorizontalLayout(\n            0.0f, 0.0f,    // Top of screen\n            128.0f, 20.0f  // Full width, 20px tall\n        );\n        toolbar->setSpacing(4.0f);\n        toolbar->setPadding(2.0f);\n\n        // Add toolbar buttons\n        toolbar->addElement(newButton(\"File\", ...));\n        toolbar->addElement(newButton(\"Edit\", ...));\n        toolbar->addElement(newButton(\"View\", ...));\n\n        addEntity(toolbar);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class (abstract)
  • UIVerticalLayout - Vertical layout
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/padding_container/","title":"UIPaddingContainer","text":"

Container that wraps a single UI element and applies padding.

"},{"location":"api_reference/ui/ui_layouts/padding_container/#description","title":"Description","text":"

UIPaddingContainer adds padding/margin around a single child element without organizing multiple elements. Useful for adding spacing to individual elements or nesting layouts with custom padding.

This container is simpler than UIPanel (no background/border) and focuses only on spacing.

"},{"location":"api_reference/ui/ui_layouts/padding_container/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIPaddingContainer : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/padding_container/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom padding containers (if needed)
"},{"location":"api_reference/ui/ui_layouts/padding_container/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/padding_container/#uipaddingcontainerfloat-x-float-y-float-w-float-h","title":"UIPaddingContainer(float x, float y, float w, float h)","text":"

Constructs a new UIPaddingContainer.

Parameters: - x (float): X position of the container - y (float): Y position of the container - w (float): Width of the container - h (float): Height of the container

Example:

#include \"graphics/ui/UIPaddingContainer.h\"\n\n// Create padding container\npixelroot32::graphics::ui::UIPaddingContainer* padded = \n    new pixelroot32::graphics::ui::UIPaddingContainer(\n        10.0f, 10.0f,\n        108.0f, 108.0f\n    );\npadded->setPadding(8.0f);  // 8px padding on all sides\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setchilduielement-element","title":"void setChild(UIElement* element)","text":"

Sets the child element.

Parameters: - element (UIElement*): Pointer to the UI element to wrap

Returns: - void

Notes: - Child element is positioned with padding applied - Can wrap any UI element (button, label, layout, etc.)

Example:

padded->setChild(button);\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#uielement-getchild-const","title":"UIElement* getChild() const","text":"

Gets the child element.

Returns: - UIElement*: Pointer to the child element, or nullptr if none set

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setpaddingfloat-p","title":"void setPadding(float p)","text":"

Sets uniform padding on all sides.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Applies same padding to all sides - Child position is automatically updated

Example:

padded->setPadding(10.0f);  // 10px padding all around\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setpaddingfloat-left-float-right-float-top-float-bottom","title":"void setPadding(float left, float right, float top, float bottom)","text":"

Sets asymmetric padding.

Parameters: - left (float): Left padding in pixels - right (float): Right padding in pixels - top (float): Top padding in pixels - bottom (float): Bottom padding in pixels

Returns: - void

Example:

padded->setPadding(10.0f, 5.0f, 8.0f, 12.0f);  // Different padding per side\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingleft-const","title":"float getPaddingLeft() const","text":"

Gets the left padding.

Returns: - float: Left padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingright-const","title":"float getPaddingRight() const","text":"

Gets the right padding.

Returns: - float: Right padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingtop-const","title":"float getPaddingTop() const","text":"

Gets the top padding.

Returns: - float: Top padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingbottom-const","title":"float getPaddingBottom() const","text":"

Gets the bottom padding.

Returns: - float: Bottom padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setpositionfloat-newx-float-newy","title":"void setPosition(float newX, float newY)","text":"

Sets the position of the container. Also updates the child element's position.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Child element position is updated automatically with padding applied

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the container and child element.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Updates child element if set - Called automatically by Scene

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the child element.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

Notes: - Only draws child element (no background/border) - Child is drawn at padded position

"},{"location":"api_reference/ui/ui_layouts/padding_container/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIPaddingContainer.h\"\n\nclass MenuScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Create button\n        auto* button = new UIButton(\"Start\", 0, 0, 0, 100.0f, 30.0f, \n                                    [this]() { startGame(); });\n\n        // Wrap button with padding\n        auto* paddedButton = new pixelroot32::graphics::ui::UIPaddingContainer(\n            64.0f, 50.0f,  // position\n            120.0f, 50.0f  // size (button + padding)\n        );\n        paddedButton->setPadding(10.0f);  // 10px padding\n        paddedButton->setChild(button);\n\n        addEntity(paddedButton);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/padding_container/#nesting-with-layouts","title":"Nesting with Layouts","text":"
// Create layout\nauto* layout = new UIVerticalLayout(10, 10, 108, 108);\n\n// Wrap layout with padding\nauto* paddedLayout = new UIPaddingContainer(0, 0, 128, 128);\npaddedLayout->setPadding(10.0f, 10.0f, 20.0f, 20.0f);  // Asymmetric\npaddedLayout->setChild(layout);\n
"},{"location":"api_reference/ui/ui_layouts/padding_container/#performance-considerations","title":"Performance Considerations","text":"
  • Rendering: Very efficient (just draws child)
  • Position calculation: Fast (simple addition)
  • Memory: Minimal overhead
"},{"location":"api_reference/ui/ui_layouts/padding_container/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Very lightweight
  • Update frequency: Position only recalculates when padding/position changes
"},{"location":"api_reference/ui/ui_layouts/padding_container/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UIPanel - Panel with background and border
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/panel/","title":"UIPanel","text":"

Visual container that draws a background and border around a child element.

"},{"location":"api_reference/ui/ui_layouts/panel/#description","title":"Description","text":"

UIPanel provides a retro-style window/panel appearance with a background color and border. Typically contains a UILayout or other UI elements. Useful for dialogs, menus, and information panels.

The panel wraps a single child element and draws a background rectangle and border around it.

"},{"location":"api_reference/ui/ui_layouts/panel/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIPanel : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/panel/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom panel classes (if needed)
"},{"location":"api_reference/ui/ui_layouts/panel/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/panel/#uipanelfloat-x-float-y-float-w-float-h","title":"UIPanel(float x, float y, float w, float h)","text":"

Constructs a new UIPanel.

Parameters: - x (float): X position of the panel - y (float): Y position of the panel - w (float): Width of the panel - h (float): Height of the panel

Example:

#include \"graphics/ui/UIPanel.h\"\n\n// Create dialog panel\npixelroot32::graphics::ui::UIPanel* dialog = \n    new pixelroot32::graphics::ui::UIPanel(\n        20.0f, 30.0f,  // position\n        88.0f, 68.0f   // size\n    );\n

"},{"location":"api_reference/ui/ui_layouts/panel/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/panel/#void-setchilduielement-element","title":"void setChild(UIElement* element)","text":"

Sets the child element.

Parameters: - element (UIElement*): Pointer to the UI element to wrap (typically a UILayout)

Returns: - void

Notes: - Child element is positioned inside the panel (with padding) - Typically a layout (VerticalLayout, etc.)

Example:

// Create panel\nauto* panel = new UIPanel(20, 30, 88, 68);\n\n// Create layout for panel content\nauto* layout = new UIVerticalLayout(0, 0, 80, 60);\nlayout->addElement(button1);\nlayout->addElement(button2);\n\n// Set layout as panel child\npanel->setChild(layout);\n

"},{"location":"api_reference/ui/ui_layouts/panel/#uielement-getchild-const","title":"UIElement* getChild() const","text":"

Gets the child element.

Returns: - UIElement*: Pointer to the child element, or nullptr if none set

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setbackgroundcolorcolor-color","title":"void setBackgroundColor(Color color)","text":"

Sets the background color.

Parameters: - color (Color): Background color

Returns: - void

Example:

panel->setBackgroundColor(Color::Blue);\n

"},{"location":"api_reference/ui/ui_layouts/panel/#color-getbackgroundcolor-const","title":"Color getBackgroundColor() const","text":"

Gets the background color.

Returns: - Color: Background color

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setbordercolorcolor-color","title":"void setBorderColor(Color color)","text":"

Sets the border color.

Parameters: - color (Color): Border color

Returns: - void

Example:

panel->setBorderColor(Color::White);\n

"},{"location":"api_reference/ui/ui_layouts/panel/#color-getbordercolor-const","title":"Color getBorderColor() const","text":"

Gets the border color.

Returns: - Color: Border color

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setborderwidthuint8_t-width","title":"void setBorderWidth(uint8_t width)","text":"

Sets the border width.

Parameters: - width (uint8_t): Border width in pixels

Returns: - void

Notes: - Default: 1 pixel - Higher values = thicker border

Example:

panel->setBorderWidth(2);  // 2 pixel border\n

"},{"location":"api_reference/ui/ui_layouts/panel/#uint8_t-getborderwidth-const","title":"uint8_t getBorderWidth() const","text":"

Gets the border width.

Returns: - uint8_t: Border width in pixels

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setpositionfloat-newx-float-newy","title":"void setPosition(float newX, float newY)","text":"

Sets the position of the panel. Also updates the child element's position.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Child element position is updated automatically

"},{"location":"api_reference/ui/ui_layouts/panel/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the panel and child element.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Updates child element if set - Called automatically by Scene

"},{"location":"api_reference/ui/ui_layouts/panel/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the panel (background, border) and child element.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

Notes: - Draws background rectangle - Draws border rectangle - Draws child element if set

"},{"location":"api_reference/ui/ui_layouts/panel/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIPanel.h\"\n#include \"graphics/ui/UIVerticalLayout.h\"\n\nclass DialogScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIPanel* dialog;\n\npublic:\n    void init() override {\n        // Create dialog panel\n        dialog = new pixelroot32::graphics::ui::UIPanel(\n            20.0f, 30.0f,  // position\n            88.0f, 68.0f   // size\n        );\n        dialog->setBackgroundColor(Color::Navy);\n        dialog->setBorderColor(Color::White);\n        dialog->setBorderWidth(2);\n\n        // Create layout for dialog content\n        auto* layout = new pixelroot32::graphics::ui::UIVerticalLayout(\n            4.0f, 4.0f,  // Position inside panel\n            80.0f, 60.0f // Size inside panel\n        );\n        layout->setSpacing(8.0f);\n\n        // Add buttons\n        auto* okButton = new UIButton(\"OK\", 0, 0, 0, 70.0f, 20.0f, \n                                     [this]() { closeDialog(); });\n        auto* cancelButton = new UIButton(\"Cancel\", 1, 0, 0, 70.0f, 20.0f,\n                                         [this]() { closeDialog(); });\n\n        layout->addElement(okButton);\n        layout->addElement(cancelButton);\n\n        // Set layout as panel child\n        dialog->setChild(layout);\n\n        addEntity(dialog);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/panel/#performance-considerations","title":"Performance Considerations","text":"
  • Rendering: Simple rectangles; very efficient
  • Child updates: Child element updates are fast
  • Memory: Small overhead (just colors and border width)
"},{"location":"api_reference/ui/ui_layouts/panel/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Panel is lightweight
  • Rendering: Two rectangles (background + border); minimal overhead
"},{"location":"api_reference/ui/ui_layouts/panel/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UILayouts - Layout containers to use inside panels
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/","title":"UIVerticalLayout","text":"

Vertical layout container with scroll support.

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#description","title":"Description","text":"

UIVerticalLayout organizes UI elements vertically, one below another. It supports scrolling when content exceeds the visible viewport and handles keyboard/D-pad navigation automatically.

This layout is ideal for menus, lists, and any vertical arrangement of UI elements.

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIVerticalLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom vertical layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/vertical_layout/#uiverticallayoutfloat-x-float-y-float-w-float-h","title":"UIVerticalLayout(float x, float y, float w, float h)","text":"

Constructs a new UIVerticalLayout.

Parameters: - x (float): X position of the layout container - y (float): Y position of the layout container - w (float): Width of the layout container - h (float): Height of the layout container (viewport height)

Example:

#include \"graphics/ui/UIVerticalLayout.h\"\n\n// Create vertical layout for menu\npixelroot32::graphics::ui::UIVerticalLayout* menuLayout = \n    new pixelroot32::graphics::ui::UIVerticalLayout(\n        20.0f, 20.0f,  // position\n        88.0f, 88.0f   // size (viewport)\n    );\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout.

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

Notes: - Elements are arranged vertically, one below another - Layout is automatically recalculated - Elements are positioned based on spacing and padding

Example:

menuLayout->addElement(startButton);\nmenuLayout->addElement(quitButton);\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

Notes: - Layout is automatically recalculated - Element is not deleted (you must manage its lifetime)

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements.

Returns: - void

Notes: - Called automatically when elements are added/removed - Can be called manually if needed - Recalculates all element positions and content height

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input for navigation and scrolling.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Handles UP/DOWN navigation - Manages selection state - Handles scrolling if enabled - Should be called every frame in update()

Example:

void update(unsigned long deltaTime) override {\n    UIVerticalLayout::update(deltaTime);\n\n    auto& input = engine.getInputManager();\n    menuLayout->handleInput(input);\n}\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout (handles smooth scrolling).

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Updates smooth scrolling animation - Updates child elements

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the layout and its visible elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

Notes: - Called automatically by Scene if isVisible is true - Only draws visible elements (viewport culling) - Draws elements in order

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setscrollenabledbool-enable","title":"void setScrollEnabled(bool enable)","text":"

Enables or disables scrolling.

Parameters: - enable (bool): true to enable scrolling

Returns: - void

Notes: - When disabled, scroll offset is reset to 0 - Scrolling is useful when content exceeds viewport height

Example:

menuLayout->setScrollEnabled(true);  // Enable scrolling\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-enablescrollbool-enable","title":"void enableScroll(bool enable)","text":"

Alias for setScrollEnabled().

Parameters: - enable (bool): true to enable scrolling

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setviewportheightfloat-h","title":"void setViewportHeight(float h)","text":"

Sets the viewport height (visible area).

Parameters: - h (float): Viewport height in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Use to adjust visible area

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#float-getscrolloffset-const","title":"float getScrollOffset() const","text":"

Gets the current scroll offset.

Returns: - float: Scroll offset in pixels

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setscrolloffsetfloat-offset","title":"void setScrollOffset(float offset)","text":"

Sets the scroll offset directly.

Parameters: - offset (float): Scroll offset in pixels

Returns: - void

Notes: - Offset is clamped to valid range automatically - Use for programmatic scrolling

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#float-getcontentheight-const","title":"float getContentHeight() const","text":"

Gets the total content height.

Returns: - float: Content height in pixels

Notes: - Includes all elements plus spacing and padding - Useful for scroll calculations

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#int-getselectedindex-const","title":"int getSelectedIndex() const","text":"

Gets the currently selected element index.

Returns: - int: Selected index, or -1 if none selected

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setselectedindexint-index","title":"void setSelectedIndex(int index)","text":"

Sets the selected element index.

Parameters: - index (int): Index to select (-1 to deselect)

Returns: - void

Notes: - Selected element is highlighted - Selection is scrolled into view if needed

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#uielement-getselectedelement-const","title":"UIElement* getSelectedElement() const","text":"

Gets the selected element.

Returns: - UIElement*: Pointer to selected element, or nullptr if none selected

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setscrollspeedfloat-speed","title":"void setScrollSpeed(float speed)","text":"

Sets the scroll speed for smooth scrolling.

Parameters: - speed (float): Pixels per millisecond

Returns: - void

Notes: - Default: 0.5 pixels per millisecond - Higher values = faster scrolling

Example:

menuLayout->setScrollSpeed(1.0f);  // Faster scrolling\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setnavigationbuttonsuint8_t-upbutton-uint8_t-downbutton","title":"void setNavigationButtons(uint8_t upButton, uint8_t downButton)","text":"

Sets the navigation button indices.

Parameters: - upButton (uint8_t): Button index for UP navigation - downButton (uint8_t): Button index for DOWN navigation

Returns: - void

Notes: - Default: UP = 0, DOWN = 1 - Change if your input mapping differs

Example:

menuLayout->setNavigationButtons(0, 1);  // UP=0, DOWN=1\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setbuttonstylecolor-selectedtextcol-color-selectedbgcol-color-unselectedtextcol-color-unselectedbgcol","title":"void setButtonStyle(Color selectedTextCol, Color selectedBgCol, Color unselectedTextCol, Color unselectedBgCol)","text":"

Sets the style colors for selected and unselected buttons.

Parameters: - selectedTextCol (Color): Text color when selected - selectedBgCol (Color): Background color when selected - unselectedTextCol (Color): Text color when not selected - unselectedBgCol (Color): Background color when not selected

Returns: - void

Example:

menuLayout->setButtonStyle(\n    Color::Yellow,  // Selected text\n    Color::Blue,    // Selected background\n    Color::White,   // Unselected text\n    Color::Black    // Unselected background\n);\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIVerticalLayout.h\"\n#include \"graphics/ui/UIButton.h\"\n\nclass MainMenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIVerticalLayout* menuLayout;\n\npublic:\n    void init() override {\n        // Create menu layout\n        menuLayout = new pixelroot32::graphics::ui::UIVerticalLayout(\n            20.0f, 20.0f,  // position\n            88.0f, 88.0f   // size\n        );\n        menuLayout->setScrollEnabled(true);\n        menuLayout->setSpacing(8.0f);\n        menuLayout->setPadding(4.0f);\n\n        // Create buttons\n        auto* startButton = new pixelroot32::graphics::ui::UIButton(\n            \"Start\",\n            0, 64.0f, 50.0f, 100.0f, 30.0f,\n            [this]() { engine.setScene(&gameScene); }\n        );\n\n        auto* quitButton = new pixelroot32::graphics::ui::UIButton(\n            \"Quit\",\n            1, 64.0f, 50.0f, 100.0f, 30.0f,\n            [this]() { engine.stop(); }\n        );\n\n        // Add buttons to layout\n        menuLayout->addElement(startButton);\n        menuLayout->addElement(quitButton);\n\n        // Add layout to scene\n        addEntity(menuLayout);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Layout handles input automatically\n        auto& input = engine.getInputManager();\n        menuLayout->handleInput(input);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n        Scene::draw(renderer);  // Draws layout and buttons\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#navigation","title":"Navigation","text":"

The layout handles D-pad navigation automatically:

  • UP button: Moves selection up
  • DOWN button: Moves selection down
  • Action button: Triggers selected button's callback
  • Scrolling: Automatically scrolls to keep selected element visible
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#performance-considerations","title":"Performance Considerations","text":"
  • Viewport culling: Only visible elements are drawn
  • Layout recalculation: Fast (simple positioning)
  • Scrolling: Smooth scrolling is efficient
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Element count: Stay within MAX_ENTITIES limit
  • Scrolling: Smooth scrolling uses minimal CPU
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class (abstract)
  • UIButton - Buttons for menus
  • Manual - User Interface
  • API Overview
"},{"location":"getting_started/fundamental_concepts/","title":"Fundamental Concepts","text":"

Before you start programming, it's important to understand the basic concepts that form PixelRoot32's architecture. This section explains how the engine works at a conceptual level, without going into code details.

"},{"location":"getting_started/fundamental_concepts/#engine-architecture","title":"Engine Architecture","text":""},{"location":"getting_started/fundamental_concepts/#engine-the-heart-of-the-engine","title":"Engine: The Heart of the Engine","text":"

The Engine is the main class that orchestrates the entire system. Think of it as the conductor that coordinates all subsystems:

  • Renderer: Handles drawing everything on screen
  • InputManager: Reads and processes user input (buttons, keyboard)
  • AudioEngine: Generates and plays sounds and music
  • SceneManager: Manages game scenes (menus, levels, etc.)

The Engine runs the main game loop: an infinite cycle that updates game logic and draws each frame on screen. It also calculates delta time (time elapsed between frames) so the game runs at the same speed regardless of framerate.

"},{"location":"getting_started/fundamental_concepts/#scene-organizing-your-game","title":"Scene: Organizing Your Game","text":"

A Scene represents a screen or level in your game. For example: - A scene for the main menu - A scene for each game level - A scene for the game over screen - A scene for the pause menu

Each scene contains and manages a set of entities (characters, enemies, objects, etc.). The scene is responsible for: - Initializing its entities when loaded - Updating the logic of all its entities each frame - Drawing all its visible entities each frame - Managing collisions between entities that can collide

The Engine can only have one active scene at a time, but you can easily switch between scenes (for example, go from menu to game, or from game to pause menu).

"},{"location":"getting_started/fundamental_concepts/#entity-the-fundamental-building-blocks","title":"Entity: The Fundamental Building Blocks","text":"

An Entity is any object in your game that has: - Position (x, y) in the world - Size (width and height) - Visibility (can be visible or not) - Active state (can be enabled or disabled) - Render layer (in what order it's drawn)

Entities are the foundation of everything in your game: the player, enemies, projectiles, objects, UI elements\u2014everything is an entity or inherits from Entity.

Each entity has two main methods: - update(): Called each frame to update the entity's logic (movement, animation, etc.) - draw(): Called each frame to draw the entity on screen

"},{"location":"getting_started/fundamental_concepts/#actor-entities-that-can-collide","title":"Actor: Entities That Can Collide","text":"

An Actor is a special entity that can participate in the collision system. In addition to everything an Entity has, an Actor has: - Collision layer: Which group it belongs to (e.g., \"player\", \"enemy\", \"projectile\") - Collision mask: Which other groups it can collide with - Hitbox: The shape used to detect collisions (usually a rectangle)

For example, a player might be on the \"player\" layer and have a mask that allows it to collide with \"enemies\" and \"obstacles\", but not with \"other players\".

When two actors collide, the system calls their onCollision() method so they can react (e.g., player loses health, enemy is destroyed, etc.).

"},{"location":"getting_started/fundamental_concepts/#physicsactor-entities-with-physics","title":"PhysicsActor: Entities with Physics","text":"

A PhysicsActor is an Actor that also has physical properties: - Velocity (vx, vy): Moves automatically according to its velocity - Gravity: Can fall automatically - Friction: Gradually loses velocity - Restitution: Bounces when it collides (like a ball)

The PhysicsActor updates automatically each frame, applying physics and moving the entity. It can also detect collisions with world boundaries (the walls of the play area).

"},{"location":"getting_started/fundamental_concepts/#entity-hierarchy","title":"Entity Hierarchy","text":"

The relationship between these classes is hierarchical:

Entity (base)\n  \u2514\u2500\u2500 Actor (can collide)\n       \u2514\u2500\u2500 PhysicsActor (has physics)\n

This means: - Every Actor is also an Entity - Every PhysicsActor is also an Actor and an Entity - You can use Entity for simple objects that don't need collisions - You can use Actor for objects that need to detect collisions - You can use PhysicsActor for objects that need automatic physics

"},{"location":"getting_started/fundamental_concepts/#rendering-system","title":"Rendering System","text":""},{"location":"getting_started/fundamental_concepts/#render-layers","title":"Render Layers","text":"

To control the order in which things are drawn, PixelRoot32 uses render layers:

  • Layer 0 (Background): Backgrounds, tilemaps, background elements
  • Layer 1 (Gameplay): Characters, enemies, projectiles, game objects
  • Layer 2 (UI): Menus, HUD, text, interface elements

Layers are drawn in order: first 0, then 1, and finally 2. This ensures the background is always behind, gameplay in the middle, and UI always visible in front.

Each entity has a renderLayer property that indicates which layer it should be drawn on. You can change this property to move entities between layers.

"},{"location":"getting_started/fundamental_concepts/#rendering-pipeline","title":"Rendering Pipeline","text":"

The rendering process works like this:

  1. beginFrame(): The screen is cleared (painted black or background color)
  2. Draw entities: All visible entities are traversed, organized by layer
  3. endFrame(): The complete frame is sent to the display

The Renderer abstracts hardware details, so the same code works on both ESP32 (TFT_eSPI) and PC (SDL2).

"},{"location":"getting_started/fundamental_concepts/#coordinates-and-space","title":"Coordinates and Space","text":"

PixelRoot32 uses a standard coordinate system: - Origin (0, 0): Top-left corner - X-axis: Increases to the right - Y-axis: Increases downward

Coordinates are in pixels. If your display is 240x240, coordinates range from (0, 0) to (239, 239).

"},{"location":"getting_started/fundamental_concepts/#lifecycle","title":"Lifecycle","text":""},{"location":"getting_started/fundamental_concepts/#initialization","title":"Initialization","text":"

When your game starts:

  1. Configuration: Configuration objects are created (DisplayConfig, InputConfig, AudioConfig)
  2. Engine: The Engine is created with these configurations
  3. init(): engine.init() is called to initialize all subsystems
  4. Scene: The initial scene is created and configured
  5. setScene(): The scene is assigned to the Engine
"},{"location":"getting_started/fundamental_concepts/#game-loop","title":"Game Loop","text":"

Once initialized, the Engine enters the game loop:

While the game is running:\n  1. Calculate deltaTime (time since last frame)\n  2. Update InputManager (read buttons/keyboard)\n  3. Update AudioEngine (advance sounds and music)\n  4. Update current scene (update all entities)\n  5. Detect collisions in the scene\n  6. Draw the scene (draw all visible entities)\n  7. Repeat\n

This cycle runs continuously, typically at 30-60 FPS on ESP32, or faster on PC.

"},{"location":"getting_started/fundamental_concepts/#update","title":"Update","text":"

Each frame, all enabled entities receive a call to their update(deltaTime) method. This is where: - Entities move - Animations update - Game logic is processed - User input is read - Sound effects are played

The deltaTime is passed in milliseconds and represents how much time has passed since the last frame. This allows movement to be framerate-independent.

"},{"location":"getting_started/fundamental_concepts/#rendering-draw","title":"Rendering (Draw)","text":"

After updating, all visible entities receive a call to their draw(renderer) method. This is where: - Sprites are drawn - Text is drawn - Primitives are drawn (rectangles, circles, etc.)

The renderer is passed as a parameter so entities can draw themselves.

"},{"location":"getting_started/fundamental_concepts/#cleanup","title":"Cleanup","text":"

When you change scenes or end the game: - Entities from the previous scene can be cleaned up - Resources are freed - The new scene is initialized

"},{"location":"getting_started/fundamental_concepts/#conceptual-summary","title":"Conceptual Summary","text":"

To summarize, PixelRoot32 works like this:

  1. Engine coordinates everything and runs the game loop
  2. Scene organizes your game into screens/levels
  3. Entity is any object in your game
  4. Actor is an entity that can collide
  5. PhysicsActor is an actor with automatic physics
  6. Renderer draws everything on screen using layers
  7. Each frame updates logic and then draws

All of this works automatically once you configure the Engine and create your scenes and entities. You don't need to worry about game loop details; you just need to implement update() and draw() in your entities.

"},{"location":"getting_started/fundamental_concepts/#next-step","title":"Next Step","text":"

Now that you understand the fundamental concepts, you're ready to create your first project and see these concepts in action with real code.

See also: - What is PixelRoot32? - Why PixelRoot32? - Your First Project - Manual - Scenes and Entities

"},{"location":"getting_started/installation/","title":"Installation","text":"

This guide covers installing the PixelRoot32 documentation environment and preparing your development setup for ESP32 and Native (PC) targets.

"},{"location":"getting_started/installation/#requirements","title":"Requirements","text":"
  • Python 3.11 or newer
  • Git (recommended for source management)
  • VS Code (or your preferred IDE)
  • For ESP32 targets: PlatformIO (VS Code extension) with ESP32 toolchain
  • For Native targets: a C++ build toolchain (CMake or your OS-native toolchain)
"},{"location":"getting_started/installation/#install-documentation-tooling","title":"Install Documentation Tooling","text":"

To build and preview this documentation locally:

pip install mkdocs mkdocs-material mkdocs-minify-plugin mkdocs-git-revision-date-localized-plugin mike\nmkdocs serve\n

Open http://127.0.0.1:8000 in your browser to preview.

"},{"location":"getting_started/installation/#esp32-setup-recommended","title":"ESP32 Setup (Recommended)","text":"
  1. Install VS Code
  2. Install PlatformIO IDE extension
  3. Install ESP32 platform/toolchain via PlatformIO
  4. Clone the engine repository:
  5. https://github.com/Gperez88/PixelRoot32-Game-Engine
  6. Open the engine or example project in VS Code (PlatformIO)
  7. Build and upload to your ESP32 board

Tip: Use boards based on ESP32-WROOM/WROVER for best compatibility. Ensure a reliable USB cable and correct serial port selection.

"},{"location":"getting_started/installation/#native-pc-setup","title":"Native (PC) Setup","text":"
  1. Install a C++ toolchain (e.g., MSVC or MinGW on Windows)
  2. Install CMake (if the engine provides CMake build files)
  3. Clone the engine repository:
  4. https://github.com/Gperez88/PixelRoot32-Game-Engine
  5. Configure and build the native runtime:
  6. Follow the engine\u2019s native build instructions (Development \u2192 Compiling)
"},{"location":"getting_started/installation/#verify-your-environment","title":"Verify Your Environment","text":"
  • ESP32: Build and flash a minimal sample; confirm serial output and display if applicable
  • Native: Run the executable; confirm window output and input handling
"},{"location":"getting_started/installation/#troubleshooting","title":"Troubleshooting","text":"
  • If PlatformIO cannot find the ESP32 platform, update PlatformIO and retry
  • If native builds fail, verify compiler versions and CMake generator settings
  • Use Community \u2192 Troubleshooting for common issues and fixes
"},{"location":"getting_started/installation/#next-steps","title":"Next Steps","text":"
  • First Project
  • Concepts
"},{"location":"getting_started/what_is_pixelroot32/","title":"What is PixelRoot32?","text":"

PixelRoot32 is a lightweight, modular 2D game engine written in C++ designed specifically for ESP32 microcontrollers, with a native simulation layer for PC (SDL2) that allows you to develop and debug quickly on your desktop before deploying to hardware.

"},{"location":"getting_started/what_is_pixelroot32/#simple-definition","title":"Simple Definition","text":"

PixelRoot32 is a game engine that lets you create retro-style 8-bit/16-bit video games directly on an ESP32 board, with the ability to develop and test on your PC before transferring code to hardware.

"},{"location":"getting_started/what_is_pixelroot32/#key-features","title":"Key Features","text":""},{"location":"getting_started/what_is_pixelroot32/#scene-based-architecture","title":"\ud83c\udfae Scene-Based Architecture","text":"
  • Scene system inspired by Godot Engine
  • Intuitive management of levels, menus, and screens
  • Simple transitions between scenes
"},{"location":"getting_started/what_is_pixelroot32/#optimized-rendering","title":"\ud83c\udfa8 Optimized Rendering","text":"
  • 1bpp (monochrome) sprites as the standard format
  • Support for multi-layer sprites (MultiSprite)
  • Experimental 2bpp and 4bpp formats for higher fidelity
  • Retro color palette system (NES, GameBoy, PICO-8, etc.)
  • Compact tilemaps for backgrounds and levels
  • 2D camera with dead-zone for smooth scrolling
  • Render layer system (background, gameplay, UI)
"},{"location":"getting_started/what_is_pixelroot32/#nes-like-audio","title":"\ud83d\udd0a NES-like Audio","text":"
  • 4 audio channels (2 Pulse, 1 Triangle, 1 Noise)
  • Integrated sound effects system
  • Music player for background melodies
  • Backends for ESP32 (internal DAC or external I2S) and SDL2
"},{"location":"getting_started/what_is_pixelroot32/#physics-and-collisions","title":"\ud83c\udfaf Physics and Collisions","text":"
  • AABB (Axis-Aligned Bounding Box) collision system
  • PhysicsActor with gravity, friction, and restitution
  • Collision layers and masks for fine control
  • World boundary collision detection
"},{"location":"getting_started/what_is_pixelroot32/#user-interface","title":"\ud83d\udda5\ufe0f User Interface","text":"
  • Basic elements: Labels, Buttons, Panels
  • Automatic layouts: Vertical, Horizontal, Grid, Anchor
  • Integrated D-pad navigation
  • Scroll and viewport culling for long lists
"},{"location":"getting_started/what_is_pixelroot32/#optimized-for-esp32","title":"\u26a1 Optimized for ESP32","text":"
  • Efficient memory management
  • Integrated object pooling
  • No dynamic allocations in the game loop
  • Performance optimized for limited hardware
"},{"location":"getting_started/what_is_pixelroot32/#typical-use-cases","title":"Typical Use Cases","text":"

PixelRoot32 is ideal for creating:

  • Arcade Games: Space Invaders, Pong, Breakout
  • Platformers: Horizontal scrolling games with simple physics
  • Puzzles: Tetris, Snake, logic games
  • Simple RPGs: Basic role-playing games with tilemaps
  • Shooters: Vertical or horizontal shooting games
  • Rapid Prototypes: Quick development of game ideas
"},{"location":"getting_started/what_is_pixelroot32/#supported-platforms","title":"Supported Platforms","text":""},{"location":"getting_started/what_is_pixelroot32/#esp32","title":"ESP32","text":"
  • Display: TFT_eSPI (ST7735, ILI9341, ST7789, etc.)
  • Audio: Internal DAC (GPIO 25/26) or external I2S (MAX98357A, PCM5102)
  • Input: Digital buttons, D-pad
  • Hardware: Any ESP32 board (ESP32-WROOM, ESP32-WROVER, etc.)
"},{"location":"getting_started/what_is_pixelroot32/#desktopnative-pc","title":"Desktop/Native (PC)","text":"
  • Display: SDL2 (Windows, Linux, macOS)
  • Audio: SDL2 Audio
  • Input: Keyboard, mouse
  • Usage: Development, debugging, testing

Note: Support for u8g2 (OLEDs) is planned for the future.

"},{"location":"getting_started/what_is_pixelroot32/#project-status","title":"Project Status","text":"

Current Version: v0.2.0-dev

PixelRoot32 is under active development. APIs may change and some subsystems are still experimental. Occasional changes or breaking changes are expected, especially on less-tested configurations.

"},{"location":"getting_started/what_is_pixelroot32/#stable-features","title":"Stable Features","text":"
  • Scene and entity system
  • Basic rendering (1bpp sprites)
  • NES-like audio system
  • Basic physics and collisions
  • Basic UI system
  • ESP32 and Native support
"},{"location":"getting_started/what_is_pixelroot32/#experimental-features","title":"Experimental Features","text":"
  • 2bpp and 4bpp sprites (require compilation flags)
  • Scene Arena (advanced memory management)
"},{"location":"getting_started/what_is_pixelroot32/#planned-features","title":"Planned Features","text":"
  • Support for u8g2 (OLEDs)
  • Music compiler
  • Tilemap compiler
  • Save/load system
  • Spatial partitioning for collisions
"},{"location":"getting_started/what_is_pixelroot32/#quick-comparison","title":"Quick Comparison","text":""},{"location":"getting_started/what_is_pixelroot32/#when-to-use-pixelroot32","title":"When to use PixelRoot32?","text":"

\u2705 Use PixelRoot32 if: - You want to create retro games on ESP32 - You need a lightweight and efficient engine - You prefer a simple and clear architecture - You want to develop on PC and deploy to ESP32 - You like 8-bit/16-bit style games

\u274c Don't use PixelRoot32 if: - You need 3D graphics - You require advanced shaders - You need complex physics (advanced physics engines) - You want to create modern AAA games - You need support for multiple mobile platforms

"},{"location":"getting_started/what_is_pixelroot32/#next-step","title":"Next Step","text":"

Now that you understand what PixelRoot32 is, discover why you should use it or go directly to your first project.

See also: - Fundamental Concepts - Installation - API Reference

"},{"location":"getting_started/why_pixelroot32/","title":"Why PixelRoot32?","text":"

PixelRoot32 is specifically designed to solve the unique challenges of creating video games on embedded hardware like the ESP32, while maintaining the simplicity and productivity of modern development.

"},{"location":"getting_started/why_pixelroot32/#main-advantages","title":"Main Advantages","text":""},{"location":"getting_started/why_pixelroot32/#optimized-for-esp32","title":"\ud83c\udfaf Optimized for ESP32","text":"

Memory Efficient - 1bpp sprite system that minimizes RAM and Flash usage - Integrated object pooling to avoid memory fragmentation - Compact tilemaps that reuse sprites - No dynamic allocations in the game loop

Performance Optimized - Rendering optimized for ESP32 limitations - Efficient render layer system - Viewport culling to reduce draw calls - Rendering pipeline designed for limited hardware

Real Hardware - Direct support for common TFT displays (ST7735, ILI9341, ST7789) - Integrated audio (internal DAC or external I2S) - Simple pin and hardware configuration

"},{"location":"getting_started/why_pixelroot32/#cross-platform-development","title":"\ud83d\udda5\ufe0f Cross-Platform Development","text":"

Develop on PC, Deploy to ESP32 - Same code works on PC (SDL2) and ESP32 - Fast debugging on desktop - Testing without hardware needed - Rapid development iteration

Visual Consistency - Native bitmap font system (pixel-perfect) - Same rendering on PC and ESP32 - Consistent color palettes - No surprises when transferring to hardware

"},{"location":"getting_started/why_pixelroot32/#retro-palette-system","title":"\ud83c\udfa8 Retro Palette System","text":"

Authentic Style - Predefined palettes: NES, GameBoy, GameBoy Color, PICO-8 - Dual palette mode for visual contrasts - Custom palettes for unique styles - Automatic color resolution (RGB565)

Easy to Use - Change palette with one line of code - Consistent visualization across all sprites - No need to manually convert assets

"},{"location":"getting_started/why_pixelroot32/#integrated-audio","title":"\ud83d\udd0a Integrated Audio","text":"

Complete NES-like System - 4 audio channels (2 Pulse, 1 Triangle, 1 Noise) - Simple sound effects to create - Integrated music system - Backends for different hardware configurations

No External Dependencies - Software-generated audio - No heavy audio libraries required - Full control over sound - Deterministic and predictable

"},{"location":"getting_started/why_pixelroot32/#simple-and-clear-architecture","title":"\ud83c\udfd7\ufe0f Simple and Clear Architecture","text":"

Easy to Understand - Intuitive scene system (inspired by Godot) - Clear hierarchy: Entity \u2192 Actor \u2192 PhysicsActor - Consistent and predictable APIs - Clean and well-organized code

Quick to Learn - Familiar concepts for game developers - Clear documentation and complete examples - Smooth learning curve - Active community and support

"},{"location":"getting_started/why_pixelroot32/#complete-features","title":"\ud83c\udfae Complete Features","text":"

Everything Needed for Games - Rendering (sprites, tilemaps, primitives) - Audio (effects and music) - Physics (gravity, collisions, basic physics) - UI (layouts, buttons, navigation) - Input (buttons, keyboard) - Camera (scroll, parallax)

No Bloat - Only the essentials, nothing more - No heavy dependencies - Small and maintainable codebase - Easy to understand and modify

"},{"location":"getting_started/why_pixelroot32/#tools-and-ecosystem","title":"\ud83d\udee0\ufe0f Tools and Ecosystem","text":"

Available Tools - Sprite Compiler to convert PNG to sprites - Complete game examples - Templates and starter code - Extensive documentation

Community and Support - Active and developing project - Open source (MIT License) - Feedback and contributions welcome - Examples available

"},{"location":"getting_started/why_pixelroot32/#comparison-with-alternatives","title":"Comparison with Alternatives","text":""},{"location":"getting_started/why_pixelroot32/#vs-full-engines-unity-godot-etc","title":"vs. Full Engines (Unity, Godot, etc.)","text":"

PixelRoot32 Advantages: - \u2705 Much lighter (fits in ESP32) - \u2705 No unnecessary overhead - \u2705 Full control over code - \u2705 Specifically optimized for limited hardware

Disadvantages: - \u274c Fewer advanced features - \u274c No visual editor - \u274c Fewer resources and community

"},{"location":"getting_started/why_pixelroot32/#vs-writing-everything-from-scratch","title":"vs. Writing Everything from Scratch","text":"

PixelRoot32 Advantages: - \u2705 Rendering system already implemented - \u2705 Integrated and working audio - \u2705 Physics and collisions ready - \u2705 Complete UI system - \u2705 Saves months of development

Disadvantages: - \u274c Less control over internal implementation - \u274c You must learn the engine API

"},{"location":"getting_started/why_pixelroot32/#vs-other-esp32-engines","title":"vs. Other ESP32 Engines","text":"

PixelRoot32 Advantages: - \u2705 More modern and clear architecture - \u2705 Better documentation - \u2705 Unique palette system - \u2705 Integrated NES-like audio - \u2705 Real cross-platform development

"},{"location":"getting_started/why_pixelroot32/#ideal-use-cases","title":"Ideal Use Cases","text":"

PixelRoot32 is perfect for:

  1. Educational Projects
  2. Learn game development
  3. Understand engine architecture
  4. Student projects

  5. Rapid Prototypes

  6. Quickly validate game ideas
  7. Create demos and proof-of-concepts
  8. Test mechanics

  9. Retro Games

  10. 8-bit/16-bit style games
  11. Arcade games
  12. Games with retro aesthetics

  13. Hardware Projects

  14. Games on small displays
  15. DIY portable consoles
  16. Maker/retro projects

  17. C++ Learning

  18. Clean and well-structured code
  19. Good programming practices
  20. Real and functional examples
"},{"location":"getting_started/why_pixelroot32/#limitations-to-consider","title":"Limitations to Consider","text":"

To be honest, PixelRoot32 has limitations:

  • Limited Hardware: Designed for ESP32, not powerful PCs
  • Simple Graphics: No 3D, no advanced shaders
  • Basic Physics: Not a complete physics engine
  • Restricted Memory: MAX_ENTITIES = 32 per scene
  • In Development: Some features are experimental

If you need advanced features or powerful hardware, consider other engines. But for retro games on ESP32, PixelRoot32 is an excellent choice.

"},{"location":"getting_started/why_pixelroot32/#conclusion","title":"Conclusion","text":"

PixelRoot32 combines:

  • \u2705 Simplicity of use
  • \u2705 Efficiency for limited hardware
  • \u2705 Completeness of essential features
  • \u2705 Clarity of architecture
  • \u2705 Productivity in development

If you want to create retro games on ESP32 without the complexity of large engines, PixelRoot32 is the right choice.

"},{"location":"getting_started/why_pixelroot32/#next-step","title":"Next Step","text":"

Now that you understand why PixelRoot32 is a good option, learn the fundamental concepts or start directly with your first project.

See also: - What is PixelRoot32? - Fundamental Concepts - Your First Project

"},{"location":"getting_started/your_first_project/","title":"Your First Project","text":"

This guide will walk you through creating and running your first PixelRoot32 project step by step. By the end, you'll have a working project that displays a simple scene on both ESP32 and PC.

"},{"location":"getting_started/your_first_project/#prerequisites","title":"Prerequisites","text":""},{"location":"getting_started/your_first_project/#required-software","title":"Required Software","text":"
  • PlatformIO: Install the PlatformIO IDE extension in VS Code
  • Open VS Code
  • Go to Extensions (Ctrl+Shift+X)
  • Search for \"PlatformIO IDE\"
  • Install and restart VS Code

  • Python 3.8+: Required for PlatformIO (usually installed automatically)

"},{"location":"getting_started/your_first_project/#for-esp32-development","title":"For ESP32 Development","text":"
  • ESP32 Board: Any ESP32 development board (ESP32-WROOM, ESP32-WROVER, etc.)
  • USB Cable: To connect and program your ESP32
  • TFT Display: Compatible display (ST7735, ST7789, ILI9341, etc.)
  • Buttons: 5-6 digital buttons for input (optional for first project)
  • Audio Hardware (optional): Speaker + amplifier (PAM8302A) or I2S DAC (MAX98357A)
"},{"location":"getting_started/your_first_project/#for-native-pc-development","title":"For Native (PC) Development","text":"
  • SDL2: Development libraries
  • Windows (MSYS2): pacman -S mingw-w64-x86_64-SDL2
  • Linux: sudo apt-get install libsdl2-dev
  • macOS: brew install sdl2
"},{"location":"getting_started/your_first_project/#step-1-create-a-new-platformio-project","title":"Step 1: Create a New PlatformIO Project","text":"
  1. Open VS Code with PlatformIO installed

  2. Create New Project:

  3. Click on the PlatformIO icon in the sidebar
  4. Click \"New Project\"
  5. Name: my-first-pixelroot32-game
  6. Board: Select \"ESP32 Dev Module\" (or your specific board)
  7. Framework: Arduino
  8. Location: Choose your workspace folder
  9. Click \"Finish\"

  10. Project Structure: Your project should now have this structure:

    my-first-pixelroot32-game/\n\u251c\u2500\u2500 .pio/\n\u251c\u2500\u2500 include/\n\u251c\u2500\u2500 lib/\n\u251c\u2500\u2500 src/\n\u2502   \u2514\u2500\u2500 main.cpp\n\u251c\u2500\u2500 test/\n\u2514\u2500\u2500 platformio.ini\n

"},{"location":"getting_started/your_first_project/#step-2-install-pixelroot32-engine","title":"Step 2: Install PixelRoot32 Engine","text":""},{"location":"getting_started/your_first_project/#option-a-via-platformio-library-manager-recommended","title":"Option A: Via PlatformIO Library Manager (Recommended)","text":"
  1. Open platformio.ini

  2. Add the library dependency:

[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = arduino\nlib_deps = \n    gperez88/PixelRoot32-Game-Engine@0.2.0-dev\n

\u26a0\ufe0f IMPORTANT: Use the exact version 0.2.0-dev. Do NOT use ^ or fuzzy versioning.

  1. Save the file. PlatformIO will automatically download the library.
"},{"location":"getting_started/your_first_project/#option-b-git-submodule","title":"Option B: Git Submodule","text":"
  1. Open terminal in your project root

  2. Add as submodule:

    git submodule add https://github.com/Gperez88/PixelRoot32-Game-Engine.git lib/PixelRoot32-Game-Engine\n

  3. Update platformio.ini:

    lib_extra_dirs = lib\n

"},{"location":"getting_started/your_first_project/#step-3-configure-hardware-esp32","title":"Step 3: Configure Hardware (ESP32)","text":""},{"location":"getting_started/your_first_project/#configure-tft_espi-display","title":"Configure TFT_eSPI Display","text":"

Edit platformio.ini and add build flags for your display. Here are two common configurations:

For ST7789 (240x240):

[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = arduino\nlib_deps = \n    gperez88/PixelRoot32-Game-Engine@0.2.0-dev\n    bodmer/TFT_eSPI@^2.5.43\n\nbuild_flags = \n    -D ST7789_DRIVER\n    -D TFT_WIDTH=240\n    -D TFT_HEIGHT=240\n    -D TFT_MOSI=23\n    -D TFT_SCLK=18\n    -D TFT_DC=2\n    -D TFT_RST=4\n    -D TFT_CS=-1\n    -D LOAD_GLCD\n    -D LOAD_FONT2\n    -D LOAD_FONT4\n    -D LOAD_FONT6\n    -D LOAD_FONT7\n    -D LOAD_FONT8\n    -D LOAD_GFXFF\n    -D SMOOTH_FONT\n    -D SPI_FREQUENCY=40000000\n    -D SPI_READ_FREQUENCY=20000000\n

For ST7735 (128x128):

build_flags = \n    -D ST7735_DRIVER\n    -D ST7735_GREENTAB3\n    -D TFT_WIDTH=128\n    -D TFT_HEIGHT=128\n    -D TFT_MOSI=23\n    -D TFT_SCLK=18\n    -D TFT_DC=2\n    -D TFT_RST=4\n    -D TFT_CS=-1\n    -D LOAD_GLCD\n    -D LOAD_FONT2\n    -D LOAD_FONT4\n    -D LOAD_FONT6\n    -D LOAD_FONT7\n    -D LOAD_FONT8\n    -D LOAD_GFXFF\n    -D SMOOTH_FONT\n    -D SPI_FREQUENCY=27000000\n    -D SPI_READ_FREQUENCY=20000000\n

Note: Adjust the pin numbers (TFT_MOSI, TFT_SCLK, TFT_DC, TFT_RST) to match your hardware wiring.

"},{"location":"getting_started/your_first_project/#configure-input-optional-for-first-project","title":"Configure Input (Optional for First Project)","text":"

If you have buttons connected, note the GPIO pins. For now, we'll create a project that works without input.

"},{"location":"getting_started/your_first_project/#configure-audio-optional-for-first-project","title":"Configure Audio (Optional for First Project)","text":"

Audio is optional for the first project. We'll add it later.

"},{"location":"getting_started/your_first_project/#step-4-create-your-first-scene","title":"Step 4: Create Your First Scene","text":"

Create a new file src/MyFirstScene.h:

#pragma once\n#include <core/Scene.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass MyFirstScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Called when the scene is initialized\n        // Set up your scene here\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Called every frame\n        // Update game logic here\n        Scene::update(deltaTime); // Don't forget to call parent update!\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Called every frame to draw\n        // Draw your scene here\n\n        // Example: Draw a simple rectangle\n        renderer.drawFilledRectangle(50, 50, 100, 100, pixelroot32::graphics::Color::Blue);\n\n        // Example: Draw text\n        renderer.drawText(\"Hello PixelRoot32!\", 20, 20, pixelroot32::graphics::Color::White, 2);\n\n        // Don't forget to call parent draw to draw all entities!\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"getting_started/your_first_project/#step-5-create-main-file-esp32","title":"Step 5: Create Main File (ESP32)","text":"

Replace the contents of src/main.cpp with:

#include <Arduino.h>\n#include <core/Engine.h>\n#include <drivers/esp32/TFT_eSPI_Drawer.h>\n#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n#include \"MyFirstScene.h\"\n\nnamespace pr32 = pixelroot32;\n\n// Audio configuration (optional - can be omitted for first project)\nconst int DAC_PIN = 25; // GPIO 25 or 26\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\n// Display configuration\n// ST7789, rotation 0, 240x240 resolution\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::ST7789, \n    0,      // rotation\n    240,    // width\n    240     // height\n);\n\n// Input configuration (6 buttons: UP, DOWN, LEFT, RIGHT, A, B)\n// For now, we'll use dummy pins - you can change these later\npr32::input::InputConfig inputConfig(\n    6,      // button count\n    32,     // UP pin\n    27,     // DOWN pin\n    33,     // LEFT pin\n    14,     // RIGHT pin\n    13,     // A button pin\n    12      // B button pin\n);\n\n// Audio configuration\npr32::audio::AudioConfig audioConfig(&audioBackend, audioBackend.getSampleRate());\n\n// Create the engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\n// Create your scene\nMyFirstScene myScene;\n\nvoid setup() {\n    Serial.begin(115200);\n\n    // Initialize the engine\n    engine.init();\n\n    // Initialize and set the scene\n    myScene.init();\n    engine.setScene(&myScene);\n\n    Serial.println(\"PixelRoot32 initialized!\");\n}\n\nvoid loop() {\n    // Run the game loop\n    engine.run();\n}\n
"},{"location":"getting_started/your_first_project/#step-6-create-native-version-optional","title":"Step 6: Create Native Version (Optional)","text":"

If you want to test on PC first, create src/main_native.cpp:

#define SDL_MAIN_HANDLED\n#include <SDL2/SDL.h>\n#include <core/Engine.h>\n#include <drivers/native/SDL2_Drawer.h>\n#include <drivers/native/SDL2_AudioBackend.h>\n#include \"MyFirstScene.h\"\n\nnamespace pr32 = pixelroot32;\n\n// Audio configuration\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\n\n// Display configuration (NONE defaults to SDL2 on Native)\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::NONE,\n    0,      // rotation\n    240,    // width\n    240     // height\n);\n\n// Input configuration (SDL scancodes)\npr32::input::InputConfig inputConfig(\n    6,                      // button count\n    SDL_SCANCODE_UP,        // UP\n    SDL_SCANCODE_DOWN,      // DOWN\n    SDL_SCANCODE_LEFT,      // LEFT\n    SDL_SCANCODE_RIGHT,     // RIGHT\n    SDL_SCANCODE_SPACE,     // A button\n    SDL_SCANCODE_RETURN     // B button\n);\n\n// Audio configuration\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n\n// Create the engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\n// Create your scene\nMyFirstScene myScene;\n\nint main(int argc, char* argv[]) {\n    (void)argc;\n    (void)argv;\n\n    // Initialize the engine\n    engine.init();\n\n    // Initialize and set the scene\n    myScene.init();\n    engine.setScene(&myScene);\n\n    // Run the game loop\n    engine.run();\n\n    return 0;\n}\n
"},{"location":"getting_started/your_first_project/#configure-native-build","title":"Configure Native Build","text":"

Add to platformio.ini:

[env:native]\nplatform = native\nbuild_src_filter = \n    +<*>\n    -<main.cpp>\nlib_extra_dirs = lib\nbuild_flags = \n    -D PLATFORM_NATIVE\n    -Isrc\n    -Ilib/PixelRoot32-Game-Engine/include\n    -IC:/msys64/mingw64/include/SDL2    # Windows MSYS2 path - adjust for your system\n    -LC:/msys64/mingw64/lib             # Windows MSYS2 path - adjust for your system\n    -O2\n    -Wall\n    -Wextra\n    -std=c++17\n    -lSDL2\n    -mconsole\n

Note: Adjust the SDL2 include and library paths for your system.

"},{"location":"getting_started/your_first_project/#step-7-build-and-run","title":"Step 7: Build and Run","text":""},{"location":"getting_started/your_first_project/#for-esp32","title":"For ESP32","text":"
  1. Connect your ESP32 via USB
  2. Select the environment: Click on the PlatformIO icon \u2192 Select env:esp32dev
  3. Build: Click the checkmark icon (\u2713) or press Ctrl+Alt+B
  4. Upload: Click the arrow icon (\u2192) or press Ctrl+Alt+U
  5. Monitor: Click the plug icon to open serial monitor

You should see \"PixelRoot32 initialized!\" in the serial monitor and your display should show a blue rectangle and text.

"},{"location":"getting_started/your_first_project/#for-native-pc","title":"For Native (PC)","text":"
  1. Select the environment: Click on the PlatformIO icon \u2192 Select env:native
  2. Build and Run: Click the play icon (\u25b6) or press Ctrl+Alt+R

A window should open showing your scene with a blue rectangle and \"Hello PixelRoot32!\" text.

"},{"location":"getting_started/your_first_project/#step-8-verify-it-works","title":"Step 8: Verify It Works","text":"

If everything is set up correctly, you should see:

  • ESP32: Display shows a blue rectangle at (50, 50) and white text \"Hello PixelRoot32!\" at (20, 20)
  • Native: Window shows the same content

If you see this, congratulations! Your first PixelRoot32 project is working.

"},{"location":"getting_started/your_first_project/#troubleshooting","title":"Troubleshooting","text":""},{"location":"getting_started/your_first_project/#esp32-issues","title":"ESP32 Issues","text":"

Display is blank: - Check wiring connections - Verify pin numbers in platformio.ini match your hardware - Check SPI frequency (try lowering it) - Verify display type (ST7789 vs ST7735)

Compilation errors: - Ensure library version is exactly 0.2.0-dev - Check that TFT_eSPI is installed - Verify all include paths are correct

Upload fails: - Check USB cable connection - Try different USB port - Press BOOT button on ESP32 during upload - Check COM port in PlatformIO

"},{"location":"getting_started/your_first_project/#native-issues","title":"Native Issues","text":"

SDL2 not found: - Verify SDL2 is installed - Check include/library paths in platformio.ini - On Windows, ensure MSYS2 paths are correct

Window doesn't open: - Check console for error messages - Verify SDL2 is properly linked - Try running from terminal to see errors

"},{"location":"getting_started/your_first_project/#next-steps","title":"Next Steps","text":"

Now that you have a working project, you can:

  1. Learn about Scenes and Entities: See how to create game objects
  2. Add Input: Make your scene respond to buttons
  3. Add Sprites: Draw custom graphics
  4. Add Audio: Play sounds and music

Continue with the Development Guide to learn more.

See also: - Fundamental Concepts - Installation - Manual - Scenes and Entities - API Reference

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/","title":"Cameras and Scrolling","text":"

Camera2D allows you to create worlds larger than the screen by scrolling the view. This guide covers camera setup, following targets, boundaries, and parallax effects.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera2d-basics","title":"Camera2D Basics","text":"

A Camera2D defines what portion of your game world is visible on screen.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#creating-a-camera","title":"Creating a Camera","text":"
#include <graphics/Camera2D.h>\n\n// Create camera with viewport size\npixelroot32::graphics::Camera2D camera(240, 240); // Screen width, height\n\n// Set camera position\ncamera.setPosition(0, 0);\n\n// Apply camera to renderer (in draw method)\ncamera.apply(renderer);\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#how-it-works","title":"How It Works","text":"

The camera translates world coordinates to screen coordinates: - Objects at world position (100, 50) with camera at (0, 0) appear at screen (100, 50) - Objects at world position (100, 50) with camera at (50, 0) appear at screen (50, 50) - The camera effectively \"moves\" the world relative to the screen

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#following-a-target","title":"Following a Target","text":"

The most common use is following a player or other target.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#basic-follow","title":"Basic Follow","text":"
class GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        // Create camera\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n\n        // Create player\n        player = new PlayerActor(500, 300); // World position\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Make camera follow player\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera before drawing\n        camera.apply(renderer);\n\n        // Now all drawing uses camera coordinates\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#dead-zone-smooth-following","title":"Dead Zone (Smooth Following)","text":"

For smoother following, you can implement a dead zone where the camera doesn't move until the target leaves the zone:

void update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);\n\n    // Get screen center\n    int screenCenterX = engine.getRenderer().getWidth() / 2;\n    int screenCenterY = engine.getRenderer().getHeight() / 2;\n\n    // Calculate player position relative to screen center\n    float playerScreenX = player->x - camera.getX();\n    float playerScreenY = player->y - camera.getY();\n\n    // Dead zone size\n    const int DEAD_ZONE_X = 40;\n    const int DEAD_ZONE_Y = 40;\n\n    // Move camera if player leaves dead zone\n    if (playerScreenX < screenCenterX - DEAD_ZONE_X) {\n        camera.setPosition(player->x - (screenCenterX - DEAD_ZONE_X), camera.getY());\n    } else if (playerScreenX > screenCenterX + DEAD_ZONE_X) {\n        camera.setPosition(player->x - (screenCenterX + DEAD_ZONE_X), camera.getY());\n    }\n\n    if (playerScreenY < screenCenterY - DEAD_ZONE_Y) {\n        camera.setPosition(camera.getX(), player->y - (screenCenterY - DEAD_ZONE_Y));\n    } else if (playerScreenY > screenCenterY + DEAD_ZONE_Y) {\n        camera.setPosition(camera.getX(), player->y - (screenCenterY + DEAD_ZONE_Y));\n    }\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-boundaries","title":"Camera Boundaries","text":"

Limit camera movement to keep it within your level bounds.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#setting-boundaries","title":"Setting Boundaries","text":"
void init() override {\n    // Create camera\n    camera = pixelroot32::graphics::Camera2D(240, 240);\n\n    // Set horizontal boundaries (level is 2000 pixels wide)\n    camera.setBounds(0, 2000 - 240); // minX, maxX\n\n    // Set vertical boundaries (level is 1000 pixels tall)\n    camera.setVerticalBounds(0, 1000 - 240); // minY, maxY\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#example-side-scroller-with-boundaries","title":"Example: Side-Scroller with Boundaries","text":"
class SideScrollerScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n    static const int LEVEL_WIDTH = 2000;\n    static const int LEVEL_HEIGHT = 240;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n\n        // Set boundaries (camera can't go outside level)\n        camera.setBounds(0, LEVEL_WIDTH - screenWidth);\n        camera.setVerticalBounds(0, LEVEL_HEIGHT - screenHeight);\n\n        // Create player at start\n        player = new PlayerActor(100, 100);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Follow player horizontally\n        camera.followTarget(player->x, camera.getY());\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#parallax-scrolling","title":"Parallax Scrolling","text":"

Parallax creates depth by moving background layers at different speeds.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#basic-parallax","title":"Basic Parallax","text":"
class ParallaxBackground : public pixelroot32::core::Entity {\nprivate:\n    float parallaxSpeed; // 0.0 to 1.0 (1.0 = normal, 0.5 = half speed)\n    float baseX;\n\npublic:\n    ParallaxBackground(float speed)\n        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::GENERIC),\n          parallaxSpeed(speed), baseX(0) {\n        setRenderLayer(0);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Get camera position\n        auto& camera = getCamera(); // You'll need to pass camera reference\n\n        // Calculate parallax offset\n        baseX = camera.getX() * parallaxSpeed;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background with parallax offset\n        renderer.drawTileMap(backgroundTileMap, \n            static_cast<int>(baseX), 0, \n            pixelroot32::graphics::Color::White);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#multiple-parallax-layers","title":"Multiple Parallax Layers","text":"
class ParallaxScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n\n    // Parallax layers (farther = slower)\n    ParallaxLayer* farBackground;    // Speed: 0.2\n    ParallaxLayer* midBackground;      // Speed: 0.5\n    ParallaxLayer* nearBackground;     // Speed: 0.8\n    PlayerActor* player;               // Speed: 1.0 (normal)\n\npublic:\n    void init() override {\n        camera = pixelroot32::graphics::Camera2D(240, 240);\n\n        // Create parallax layers\n        farBackground = new ParallaxLayer(0.2f);  // Moves slowest\n        midBackground = new ParallaxLayer(0.5f);\n        nearBackground = new ParallaxLayer(0.8f);\n\n        addEntity(farBackground);\n        addEntity(midBackground);\n        addEntity(nearBackground);\n\n        player = new PlayerActor(100, 100);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Update parallax layers with camera position\n        farBackground->updateParallax(camera.getX());\n        midBackground->updateParallax(camera.getX());\n        nearBackground->updateParallax(camera.getX());\n\n        // Follow player\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#using-setdisplayoffset-for-parallax","title":"Using setDisplayOffset for Parallax","text":"

For simpler parallax, you can use setDisplayOffset():

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera\n    camera.apply(renderer);\n\n    // Draw far background with offset (moves slower)\n    renderer.setDisplayOffset(\n        static_cast<int>(camera.getX() * 0.3f), \n        0\n    );\n    renderer.drawTileMap(farBackground, 0, 0, Color::White);\n\n    // Draw mid background\n    renderer.setDisplayOffset(\n        static_cast<int>(camera.getX() * 0.6f), \n        0\n    );\n    renderer.drawTileMap(midBackground, 0, 0, Color::White);\n\n    // Reset offset for normal drawing\n    renderer.setDisplayOffset(0, 0);\n\n    // Draw game objects (normal speed)\n    Scene::draw(renderer);\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#complete-example-platformer-with-camera","title":"Complete Example: Platformer with Camera","text":"
class PlatformerScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n    static const int LEVEL_WIDTH = 3000;\n    static const int LEVEL_HEIGHT = 800;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        // Create camera\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n\n        // Set boundaries\n        camera.setBounds(0, LEVEL_WIDTH - screenWidth);\n        camera.setVerticalBounds(0, LEVEL_HEIGHT - screenHeight);\n\n        // Create player\n        player = new PlayerActor(100, 400);\n        addEntity(player);\n\n        // Create platforms, enemies, etc.\n        // ...\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Follow player with dead zone\n        int screenCenterX = engine.getRenderer().getWidth() / 2;\n        int screenCenterY = engine.getRenderer().getHeight() / 2;\n\n        float playerScreenX = player->x - camera.getX();\n        float playerScreenY = player->y - camera.getY();\n\n        const int DEAD_ZONE = 60;\n\n        // Horizontal follow\n        if (playerScreenX < screenCenterX - DEAD_ZONE) {\n            camera.setPosition(player->x - (screenCenterX - DEAD_ZONE), camera.getY());\n        } else if (playerScreenX > screenCenterX + DEAD_ZONE) {\n            camera.setPosition(player->x - (screenCenterX + DEAD_ZONE), camera.getY());\n        }\n\n        // Vertical follow (only when falling or jumping high)\n        if (playerScreenY < screenCenterY - DEAD_ZONE || \n            playerScreenY > screenCenterY + DEAD_ZONE) {\n            camera.setPosition(camera.getX(), player->y - screenCenterY);\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw background (parallax)\n        renderer.setDisplayOffset(\n            static_cast<int>(camera.getX() * 0.3f), \n            0\n        );\n        renderer.drawTileMap(backgroundTileMap, 0, 0, Color::DarkGray);\n        renderer.setDisplayOffset(0, 0);\n\n        // Draw game objects\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-movement","title":"Camera Movement","text":"
  • Use dead zones: Prevents jittery camera movement
  • Smooth transitions: Consider lerping camera position for smoother movement
  • Set boundaries: Always limit camera to level bounds
  • Test on hardware: Camera performance may differ on ESP32
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#parallax","title":"Parallax","text":"
  • Layer speeds: Farther layers move slower (0.2-0.5), closer move faster (0.7-0.9)
  • Limit layers: Too many parallax layers can impact performance
  • Use tilemaps: Parallax works best with tilemaps
  • Test visually: Ensure parallax effect is noticeable but not distracting
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#performance","title":"Performance","text":"
  • Apply once: Call camera.apply() once per frame, at start of draw()
  • Cull off-screen: Don't draw entities outside camera view
  • Limit parallax layers: 2-3 layers is usually enough
  • Optimize tilemaps: Use efficient tilemap rendering
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-helper-class","title":"Camera Helper Class","text":"
class CameraController {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    float targetX, targetY;\n    float smoothSpeed = 0.1f;\n\npublic:\n    void followTarget(float x, float y) {\n        targetX = x;\n        targetY = y;\n    }\n\n    void update(unsigned long deltaTime) {\n        // Smooth camera movement\n        float currentX = camera.getX();\n        float currentY = camera.getY();\n\n        float newX = currentX + (targetX - currentX) * smoothSpeed;\n        float newY = currentY + (targetY - currentY) * smoothSpeed;\n\n        camera.setPosition(newX, newY);\n    }\n\n    void apply(pixelroot32::graphics::Renderer& renderer) {\n        camera.apply(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#viewport-culling","title":"Viewport Culling","text":"

Only draw entities within camera view:

bool isVisible(float x, float y, int width, int height) {\n    float cameraX = camera.getX();\n    float cameraY = camera.getY();\n    int screenWidth = engine.getRenderer().getWidth();\n    int screenHeight = engine.getRenderer().getHeight();\n\n    return !(x + width < cameraX || \n             x > cameraX + screenWidth ||\n             y + height < cameraY || \n             y > cameraY + screenHeight);\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-not-moving","title":"Camera Not Moving","text":"
  • Verify camera.apply() is called in draw()
  • Check followTarget() or setPosition() is called in update()
  • Ensure camera is created with correct viewport size
  • Check boundaries aren't preventing movement
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#objects-not-visible","title":"Objects Not Visible","text":"
  • Verify objects are within camera view
  • Check world coordinates vs screen coordinates
  • Ensure camera is applied before drawing
  • Verify render layers are correct
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#parallax-not-working","title":"Parallax Not Working","text":"
  • Check setDisplayOffset() is used correctly
  • Verify parallax speed values (0.0 to 1.0)
  • Ensure offset is reset after parallax layers
  • Test with different speed values
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#next-steps","title":"Next Steps","text":"

Now that you understand cameras and scrolling, learn about: - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects - Performance Optimization - Optimize your game

See also: - API Reference - Camera2D - Manual - Basic Rendering - Manual - Tilemaps

"},{"location":"manual/advanced_graphics/color_palettes/","title":"Color Palettes","text":"

PixelRoot32 uses a palette-based color system that allows you to easily change the visual style of your game. This guide covers built-in palettes, dual palette mode, and custom palettes.

"},{"location":"manual/advanced_graphics/color_palettes/#built-in-palettes","title":"Built-in Palettes","text":"

PixelRoot32 includes several predefined palettes inspired by classic gaming systems:

"},{"location":"manual/advanced_graphics/color_palettes/#available-palettes","title":"Available Palettes","text":"
#include <graphics/PaletteDefs.h>\n\nnamespace pixelroot32::graphics {\n\nenum class PaletteType {\n    PR32,    // PixelRoot32 default palette\n    NES,     // Nintendo Entertainment System\n    GB,      // GameBoy (4 shades of green)\n    GBC,     // GameBoy Color\n    PICO8    // PICO-8 palette\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#using-built-in-palettes","title":"Using Built-in Palettes","text":"
#include <graphics/PaletteDefs.h>\n\n// Set palette globally (legacy mode)\npixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n\n// All sprites will now use NES colors\nrenderer.drawSprite(MY_SPRITE, 100, 100, pixelroot32::graphics::Color::White);\n
"},{"location":"manual/advanced_graphics/color_palettes/#palette-characteristics","title":"Palette Characteristics","text":"

PR32 (Default) - Modern, balanced colors - Good contrast - Suitable for most games

NES - Classic 8-bit console colors - Limited color range - Nostalgic feel

GB (GameBoy) - 4 shades of green - Monochrome aesthetic - Classic handheld look

GBC (GameBoy Color) - Expanded color range - More vibrant than GB - Classic portable console

PICO8 - PICO-8 fantasy console palette - 16 carefully chosen colors - Popular for retro games

"},{"location":"manual/advanced_graphics/color_palettes/#legacy-mode-single-global-palette","title":"Legacy Mode (Single Global Palette)","text":"

In legacy mode, one palette is used for all sprites:

void MyScene::init() override {\n    // Set global palette\n    pixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n\n    // All sprites use NES colors\n    // This is the simplest mode\n}\n

When to use: - Simple games - Consistent visual style - Maximum compatibility

"},{"location":"manual/advanced_graphics/color_palettes/#dual-palette-mode","title":"Dual Palette Mode","text":"

Dual palette mode allows different palettes for background elements and sprites, creating visual contrast.

"},{"location":"manual/advanced_graphics/color_palettes/#enabling-dual-palette-mode","title":"Enabling Dual Palette Mode","text":"
#include <graphics/PaletteDefs.h>\n\nvoid MyScene::init() override {\n    // Enable dual palette mode\n    pixelroot32::graphics::enableDualPaletteMode();\n\n    // Set background palette\n    pixelroot32::graphics::setBackgroundPalette(\n        pixelroot32::graphics::PaletteType::GB\n    );\n\n    // Set sprite palette\n    pixelroot32::graphics::setSpritePalette(\n        pixelroot32::graphics::PaletteType::NES\n    );\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#how-it-works","title":"How It Works","text":"
  • Background palette: Used for tilemaps, primitives, and background sprites
  • Sprite palette: Used for game objects, characters, and foreground sprites
  • Automatic context: The renderer automatically selects the correct palette based on what you're drawing
"},{"location":"manual/advanced_graphics/color_palettes/#example-contrasting-styles","title":"Example: Contrasting Styles","text":"
void MyScene::init() override {\n    pixelroot32::graphics::enableDualPaletteMode();\n\n    // Dark, muted background (GameBoy green)\n    pixelroot32::graphics::setBackgroundPalette(\n        pixelroot32::graphics::PaletteType::GB\n    );\n\n    // Bright, colorful sprites (NES)\n    pixelroot32::graphics::setSpritePalette(\n        pixelroot32::graphics::PaletteType::NES\n    );\n\n    // Background uses GB palette\n    renderer.drawTileMap(backgroundTileMap, 0, 0, \n        pixelroot32::graphics::Color::White);\n\n    // Sprites use NES palette\n    renderer.drawSprite(playerSprite, 100, 100, \n        pixelroot32::graphics::Color::White);\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#when-to-use-dual-palette-mode","title":"When to Use Dual Palette Mode","text":"
  • Visual contrast: Make sprites stand out from background
  • Artistic style: Different palettes for different layers
  • Retro aesthetics: Classic console color separation
  • Performance: No performance impact, just visual variety
"},{"location":"manual/advanced_graphics/color_palettes/#custom-palettes","title":"Custom Palettes","text":"

Create your own color palettes for unique visual styles.

"},{"location":"manual/advanced_graphics/color_palettes/#creating-a-custom-palette","title":"Creating a Custom Palette","text":"
#include <graphics/PaletteDefs.h>\n#include <graphics/Color.h>\n\n// Define custom colors (RGB565 format)\nstatic const pixelroot32::graphics::Color CUSTOM_PALETTE[] = {\n    pixelroot32::graphics::Color::Black,      // 0: Transparent/background\n    pixelroot32::graphics::Color::DarkBlue,   // 1\n    pixelroot32::graphics::Color::Blue,       // 2\n    pixelroot32::graphics::Color::LightBlue, // 3\n    pixelroot32::graphics::Color::Cyan,      // 4\n    pixelroot32::graphics::Color::White,      // 5\n    // ... more colors\n};\n\n// Set custom palette\npixelroot32::graphics::setCustomPalette(\n    CUSTOM_PALETTE,\n    sizeof(CUSTOM_PALETTE) / sizeof(pixelroot32::graphics::Color)\n);\n
"},{"location":"manual/advanced_graphics/color_palettes/#rgb565-color-format","title":"RGB565 Color Format","text":"

Colors in PixelRoot32 use RGB565 format (16-bit):

// RGB565: 5 bits red, 6 bits green, 5 bits blue\n// Format: RRRRR GGGGGG BBBBB\n\n// Create custom RGB565 color\nuint16_t myColor = (31 << 11) | (63 << 5) | 31; // White\nuint16_t myColor = (0 << 11) | (0 << 5) | 0;    // Black\nuint16_t myColor = (31 << 11) | (0 << 5) | 0;   // Red\n\n// Or use Color constants\npixelroot32::graphics::Color::Red\npixelroot32::graphics::Color::Green\npixelroot32::graphics::Color::Blue\n
"},{"location":"manual/advanced_graphics/color_palettes/#helper-function-for-custom-colors","title":"Helper Function for Custom Colors","text":"
// Create RGB565 color from RGB values (0-255)\nuint16_t rgb565(uint8_t r, uint8_t g, uint8_t b) {\n    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\n}\n\n// Usage\nstatic const pixelroot32::graphics::Color MY_PALETTE[] = {\n    rgb565(0, 0, 0),        // Black\n    rgb565(255, 0, 0),      // Red\n    rgb565(0, 255, 0),      // Green\n    rgb565(0, 0, 255),      // Blue\n    rgb565(255, 255, 255),  // White\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#complete-custom-palette-example","title":"Complete Custom Palette Example","text":"
class CustomPaletteScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Define custom palette (ocean theme)\n        static const pixelroot32::graphics::Color OCEAN_PALETTE[] = {\n            pixelroot32::graphics::Color::Black,      // 0: Deep ocean\n            pixelroot32::graphics::Color::Navy,        // 1: Dark blue\n            pixelroot32::graphics::Color::Blue,       // 2: Medium blue\n            pixelroot32::graphics::Color::Cyan,       // 3: Light blue\n            pixelroot32::graphics::Color::LightBlue, // 4: Surface\n            pixelroot32::graphics::Color::White,      // 5: Foam\n        };\n\n        // Set custom palette\n        pixelroot32::graphics::setCustomPalette(\n            OCEAN_PALETTE,\n            sizeof(OCEAN_PALETTE) / sizeof(pixelroot32::graphics::Color)\n        );\n\n        // Now all sprites use the ocean palette\n    }\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#color-constants","title":"Color Constants","text":"

PixelRoot32 provides predefined color constants:

namespace pixelroot32::graphics {\n    Color::Black\n    Color::White\n    Color::Red\n    Color::Green\n    Color::Blue\n    Color::Yellow\n    Color::Cyan\n    Color::Magenta\n    Color::DarkGray\n    Color::LightGray\n    Color::Navy\n    Color::DarkGreen\n    Color::DarkRed\n    Color::Brown\n    Color::Purple\n    Color::Orange\n    Color::Pink\n    Color::Gold\n    Color::LightBlue\n    Color::LightGreen\n    Color::LightRed\n    Color::Transparent\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/color_palettes/#palette-selection","title":"Palette Selection","text":"
  • Match game style: Choose palette that fits your game's theme
  • Test on hardware: Colors may look different on ESP32 display
  • Consider contrast: Ensure sprites are visible against background
  • Consistency: Stick with one palette per scene (or use dual mode)
"},{"location":"manual/advanced_graphics/color_palettes/#dual-palette-mode_1","title":"Dual Palette Mode","text":"
  • Use sparingly: Not all games need dual palettes
  • Test combinations: Some palette combinations work better than others
  • Clear separation: Use for clear visual distinction between layers
  • Performance: No performance cost, use freely
"},{"location":"manual/advanced_graphics/color_palettes/#custom-palettes_1","title":"Custom Palettes","text":"
  • Limit colors: Keep palette size reasonable (8-16 colors)
  • Plan ahead: Design palette before creating sprites
  • Test thoroughly: Verify colors work well together
  • Document: Comment your palette choices
"},{"location":"manual/advanced_graphics/color_palettes/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/color_palettes/#palette-switching","title":"Palette Switching","text":"
class GameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Set initial palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::NES\n        );\n    }\n\n    void changeToNightMode() {\n        // Switch to darker palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::GB\n        );\n    }\n\n    void changeToDayMode() {\n        // Switch to brighter palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::PICO8\n        );\n    }\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#theme-based-palettes","title":"Theme-Based Palettes","text":"
namespace GamePalettes {\n    // Forest theme\n    static const pixelroot32::graphics::Color FOREST[] = {\n        Color::Black,\n        Color::DarkGreen,\n        Color::Green,\n        Color::LightGreen,\n        Color::Brown,\n        Color::Yellow\n    };\n\n    // Desert theme\n    static const pixelroot32::graphics::Color DESERT[] = {\n        Color::Black,\n        Color::Brown,\n        Color::Yellow,\n        Color::Gold,\n        Color::Orange,\n        Color::White\n    };\n\n    // Ocean theme\n    static const pixelroot32::graphics::Color OCEAN[] = {\n        Color::Black,\n        Color::Navy,\n        Color::Blue,\n        Color::Cyan,\n        Color::LightBlue,\n        Color::White\n    };\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/color_palettes/#colors-not-changing","title":"Colors Not Changing","text":"
  • Verify setPalette() is called before drawing
  • Check palette is set in init(), not update()
  • Ensure dual palette mode is enabled if using separate palettes
  • Verify Color constants are from correct namespace
"},{"location":"manual/advanced_graphics/color_palettes/#colors-look-wrong-on-hardware","title":"Colors Look Wrong on Hardware","text":"
  • ESP32 displays may render colors differently
  • Test on actual hardware, not just PC
  • Adjust palette colors if needed
  • Consider display calibration
"},{"location":"manual/advanced_graphics/color_palettes/#dual-palette-not-working","title":"Dual Palette Not Working","text":"
  • Ensure enableDualPaletteMode() is called first
  • Verify both palettes are set
  • Check that you're drawing in correct context
  • Review renderer documentation
"},{"location":"manual/advanced_graphics/color_palettes/#next-steps","title":"Next Steps","text":"

Now that you understand palettes, learn about: - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects

See also: - API Reference - PaletteDefs - API Reference - Color - Manual - Basic Rendering

"},{"location":"manual/advanced_graphics/particles_and_effects/","title":"Particles and Effects","text":"

The particle system allows you to create visual effects like fire, explosions, smoke, and sparks. This guide covers ParticleEmitter, ParticleConfig, and the included presets.

"},{"location":"manual/advanced_graphics/particles_and_effects/#particleemitter-basics","title":"ParticleEmitter Basics","text":"

A ParticleEmitter is an Entity that manages a pool of particles to create visual effects.

"},{"location":"manual/advanced_graphics/particles_and_effects/#creating-a-particle-emitter","title":"Creating a Particle Emitter","text":"
#include <graphics/particles/ParticleEmitter.h>\n#include <graphics/particles/ParticleConfig.h>\n\n// Create particle configuration\npixelroot32::graphics::particles::ParticleConfig config;\nconfig.startColor = pixelroot32::graphics::Color::Red;\nconfig.endColor = pixelroot32::graphics::Color::Yellow;\nconfig.lifetime = 1.0f; // 1 second\nconfig.speed = 50.0f;\nconfig.gravity = -100.0f; // Upward (negative = up)\n\n// Create emitter\npixelroot32::graphics::particles::ParticleEmitter* emitter = \n    new pixelroot32::graphics::particles::ParticleEmitter(100, 100, config);\n\n// Add to scene\naddEntity(emitter);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#emitting-particles","title":"Emitting Particles","text":"
// Emit a burst of particles\nemitter->burst(100, 100, 10); // x, y, particle count\n\n// Particles will automatically update and draw\n// No additional code needed!\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#particleconfig","title":"ParticleConfig","text":"

ParticleConfig defines how particles behave:

#include <graphics/particles/ParticleConfig.h>\n\npixelroot32::graphics::particles::ParticleConfig config;\n\n// Colors\nconfig.startColor = pixelroot32::graphics::Color::Red;   // Color at spawn\nconfig.endColor = pixelroot32::graphics::Color::Yellow;  // Color at death\n\n// Lifetime\nconfig.lifetime = 0.5f; // Duration in seconds\n\n// Velocity\nconfig.speed = 100.0f;           // Base speed\nconfig.speedVariation = 20.0f;   // Random variation\nconfig.direction = 90.0f;        // Direction in degrees (0 = right, 90 = up)\nconfig.directionVariation = 45.0f; // Random direction spread\n\n// Physics\nconfig.gravity = 200.0f;  // Gravity force (positive = down)\nconfig.friction = 0.95f;   // Friction (0.0 to 1.0, 1.0 = no friction)\n\n// Size\nconfig.startSize = 2;     // Size at spawn (pixels)\nconfig.endSize = 1;       // Size at death\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#complete-config-example","title":"Complete Config Example","text":"
pixelroot32::graphics::particles::ParticleConfig fireConfig;\n\n// Fire colors (red to yellow)\nfireConfig.startColor = pixelroot32::graphics::Color::Red;\nfireConfig.endColor = pixelroot32::graphics::Color::Yellow;\n\n// Short lifetime\nfireConfig.lifetime = 0.3f;\n\n// Upward movement with variation\nfireConfig.speed = 80.0f;\nfireConfig.speedVariation = 30.0f;\nfireConfig.direction = 90.0f; // Up\nfireConfig.directionVariation = 30.0f; // Spread\n\n// Upward gravity (negative)\nfireConfig.gravity = -50.0f;\n\n// Slight friction\nfireConfig.friction = 0.98f;\n\n// Size\nfireConfig.startSize = 3;\nfireConfig.endSize = 1;\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#built-in-presets","title":"Built-in Presets","text":"

PixelRoot32 includes several particle presets for common effects:

"},{"location":"manual/advanced_graphics/particles_and_effects/#fire","title":"Fire","text":"
#include <graphics/particles/ParticlePresets.h>\n\n// Create fire emitter\npixelroot32::graphics::particles::ParticleEmitter* fire = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Fire()\n    );\n\n// Emit continuous fire\nvoid update(unsigned long deltaTime) override {\n    fire->burst(100, 100, 2); // Emit 2 particles per frame\n    Scene::update(deltaTime);\n}\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#explosion","title":"Explosion","text":"
// Create explosion emitter\npixelroot32::graphics::particles::ParticleEmitter* explosion = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Explosion()\n    );\n\n// Emit explosion burst\nexplosion->burst(100, 100, 20); // 20 particles at once\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#sparks","title":"Sparks","text":"
// Create sparks emitter\npixelroot32::graphics::particles::ParticleEmitter* sparks = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Sparks()\n    );\n\n// Emit sparks\nsparks->burst(100, 100, 10);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#smoke","title":"Smoke","text":"
// Create smoke emitter\npixelroot32::graphics::particles::ParticleEmitter* smoke = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Smoke()\n    );\n\n// Emit smoke\nsmoke->burst(100, 100, 3);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#dust","title":"Dust","text":"
// Create dust emitter\npixelroot32::graphics::particles::ParticleEmitter* dust = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Dust()\n    );\n\n// Emit dust\ndust->burst(100, 100, 5);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#complete-example-explosion-effect","title":"Complete Example: Explosion Effect","text":"
#include <core/Scene.h>\n#include <graphics/particles/ParticleEmitter.h>\n#include <graphics/particles/ParticlePresets.h>\n\nclass ExplosionEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* explosion;\n    bool active = false;\n\npublic:\n    ExplosionEffect()\n        : Entity(0, 0, 1, 1, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n\n        // Create explosion emitter\n        explosion = new pixelroot32::graphics::particles::ParticleEmitter(\n            0, 0,\n            pixelroot32::graphics::particles::ParticlePresets::Explosion()\n        );\n    }\n\n    void trigger(float x, float y) {\n        active = true;\n        this->x = x;\n        this->y = y;\n\n        // Emit explosion burst\n        explosion->burst(x, y, 25);\n    }\n\n    void update(unsigned long deltaTime) override {\n        explosion->update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        explosion->draw(renderer);\n    }\n};\n\n// Usage in scene\nvoid MyScene::init() override {\n    explosionEffect = new ExplosionEffect();\n    addEntity(explosionEffect);\n}\n\nvoid MyScene::update(unsigned long deltaTime) override {\n    auto& input = engine.getInputManager();\n\n    // Trigger explosion on button press\n    if (input.isButtonPressed(4)) { // Button A\n        explosionEffect->trigger(player->x, player->y);\n    }\n\n    Scene::update(deltaTime);\n}\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#continuous-effects","title":"Continuous Effects","text":"

For continuous effects like fire or smoke:

class FireEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* fire;\n    unsigned long emitTimer = 0;\n    const unsigned long EMIT_INTERVAL_MS = 50; // Emit every 50ms\n\npublic:\n    FireEffect(float x, float y)\n        : Entity(x, y, 1, 1, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n\n        fire = new pixelroot32::graphics::particles::ParticleEmitter(\n            x, y,\n            pixelroot32::graphics::particles::ParticlePresets::Fire()\n        );\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Emit particles continuously\n        emitTimer += deltaTime;\n        if (emitTimer >= EMIT_INTERVAL_MS) {\n            emitTimer -= EMIT_INTERVAL_MS;\n            fire->burst(x, y, 2); // 2 particles per interval\n        }\n\n        fire->update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        fire->draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#custom-particle-effects","title":"Custom Particle Effects","text":"

Create your own particle effects by customizing ParticleConfig:

"},{"location":"manual/advanced_graphics/particles_and_effects/#magic-spell-effect","title":"Magic Spell Effect","text":"
pixelroot32::graphics::particles::ParticleConfig magicConfig;\n\n// Magical colors (purple to cyan)\nmagicConfig.startColor = pixelroot32::graphics::Color::Purple;\nmagicConfig.endColor = pixelroot32::graphics::Color::Cyan;\n\n// Medium lifetime\nmagicConfig.lifetime = 0.8f;\n\n// Outward spread\nmagicConfig.speed = 60.0f;\nmagicConfig.speedVariation = 20.0f;\nmagicConfig.direction = 0.0f; // Right\nmagicConfig.directionVariation = 360.0f; // Full circle\n\n// Slight upward float\nmagicConfig.gravity = -30.0f;\n\n// Low friction (floaty)\nmagicConfig.friction = 0.92f;\n\n// Size\nmagicConfig.startSize = 2;\nmagicConfig.endSize = 1;\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#rain-effect","title":"Rain Effect","text":"
pixelroot32::graphics::particles::ParticleConfig rainConfig;\n\n// Rain color (light blue)\nrainConfig.startColor = pixelroot32::graphics::Color::LightBlue;\nrainConfig.endColor = pixelroot32::graphics::Color::LightBlue;\n\n// Long lifetime\nrainConfig.lifetime = 2.0f;\n\n// Downward movement\nrainConfig.speed = 150.0f;\nrainConfig.speedVariation = 20.0f;\nrainConfig.direction = 270.0f; // Down\nrainConfig.directionVariation = 5.0f; // Slight angle variation\n\n// Downward gravity\nrainConfig.gravity = 200.0f;\n\n// No friction\nrainConfig.friction = 1.0f;\n\n// Small size\nrainConfig.startSize = 1;\nrainConfig.endSize = 1;\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/particles_and_effects/#performance","title":"Performance","text":"
  • Limit particle count: Each emitter has MAX_PARTICLES_PER_EMITTER (50)
  • Reuse emitters: Don't create new emitters every frame
  • Disable when not visible: Set isVisible = false when off-screen
  • Limit active emitters: Too many emitters can impact performance
"},{"location":"manual/advanced_graphics/particles_and_effects/#visual-design","title":"Visual Design","text":"
  • Match game style: Particle effects should fit your game's aesthetic
  • Use appropriate colors: Match particle colors to game palette
  • Test on hardware: ESP32 may render particles differently
  • Keep it simple: Simple effects often look better than complex ones
"},{"location":"manual/advanced_graphics/particles_and_effects/#timing","title":"Timing","text":"
  • Burst timing: Space out bursts for better visual effect
  • Continuous effects: Use timers to control emission rate
  • Lifetime: Adjust lifetime to match effect duration
  • Cleanup: Particles automatically clean up when lifetime expires
"},{"location":"manual/advanced_graphics/particles_and_effects/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/particles_and_effects/#one-shot-effect","title":"One-Shot Effect","text":"
class OneShotEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* emitter;\n    bool hasEmitted = false;\n\npublic:\n    void trigger(float x, float y) {\n        if (!hasEmitted) {\n            emitter->burst(x, y, 20);\n            hasEmitted = true;\n        }\n    }\n\n    void reset() {\n        hasEmitted = false;\n    }\n};\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#attached-effect","title":"Attached Effect","text":"
class AttachedParticleEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* emitter;\n    pixelroot32::core::Actor* target;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        // Update emitter position to follow target\n        emitter->x = target->x;\n        emitter->y = target->y;\n\n        // Emit particles\n        emitter->burst(target->x, target->y, 1);\n\n        emitter->update(deltaTime);\n    }\n};\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/particles_and_effects/#particles-not-appearing","title":"Particles Not Appearing","text":"
  • Verify emitter is added to scene
  • Check particle config is valid
  • Ensure burst() is being called
  • Verify emitter position is on-screen
"},{"location":"manual/advanced_graphics/particles_and_effects/#performance-issues","title":"Performance Issues","text":"
  • Reduce particle count per burst
  • Limit number of active emitters
  • Use simpler particle configs
  • Disable emitters when not visible
"},{"location":"manual/advanced_graphics/particles_and_effects/#particles-not-moving","title":"Particles Not Moving","text":"
  • Check gravity value (positive = down, negative = up)
  • Verify speed is not 0
  • Check friction isn't too high (1.0 = no movement)
  • Ensure direction is correct (degrees: 0=right, 90=up, 180=left, 270=down)
"},{"location":"manual/advanced_graphics/particles_and_effects/#next-steps","title":"Next Steps","text":"

Now that you understand particles, you've completed the advanced graphics section. Continue with: - Performance Optimization - Optimize your game - Memory Management - Manage memory efficiently - API Reference - Complete API documentation

See also: - API Reference - ParticleEmitter - API Reference - ParticleConfig - API Reference - ParticlePresets - Manual - Basic Rendering

"},{"location":"manual/advanced_graphics/sprites_and_animation/","title":"Sprites and Animation","text":"

This guide covers advanced sprite techniques and animation in PixelRoot32, including different sprite formats, creating animations, and best practices.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-formats","title":"Sprite Formats","text":"

PixelRoot32 supports multiple sprite formats, each optimized for different use cases.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#1bpp-standard-monochrome","title":"1bpp (Standard, Monochrome)","text":"

The standard format uses 1 bit per pixel (monochrome). This is the most memory-efficient format:

#include <graphics/Renderer.h>\n\n// Define sprite data (8x8 example)\nstatic const uint16_t PLAYER_SPRITE_DATA[] = {\n    0b00111100,  // Row 0\n    0b01111110,  // Row 1\n    0b11111111,  // Row 2\n    0b11111111,  // Row 3\n    0b11111111,  // Row 4\n    0b01111110,  // Row 5\n    0b00111100,  // Row 6\n    0b00000000   // Row 7\n};\n\n// Create sprite descriptor\nstatic const pixelroot32::graphics::Sprite PLAYER_SPRITE = {\n    PLAYER_SPRITE_DATA,\n    8,  // width\n    8   // height\n};\n\n// Draw sprite\nrenderer.drawSprite(PLAYER_SPRITE, 100, 100, pixelroot32::graphics::Color::White);\n

Characteristics: - Most memory-efficient - 1 bit per pixel - Maximum width: 16 pixels - Color applied at draw time - Best for: Simple graphics, retro style

"},{"location":"manual/advanced_graphics/sprites_and_animation/#2bpp-experimental-4-colors","title":"2bpp (Experimental, 4 Colors)","text":"

2 bits per pixel allows 4 colors per sprite:

#ifdef PIXELROOT32_ENABLE_2BPP_SPRITES\n#include <graphics/Renderer.h>\n\n// Define 2bpp sprite data\nstatic const uint8_t COLORFUL_SPRITE_DATA[] = {\n    // Each byte represents 4 pixels (2 bits each)\n    // Format: [pixel3][pixel2][pixel1][pixel0]\n    0x00, 0x11, 0x22, 0x33,  // Row 0\n    0x11, 0x22, 0x33, 0x00,  // Row 1\n    // ... more rows\n};\n\n// Define palette (4 colors)\nstatic const pixelroot32::graphics::Color SPRITE_PALETTE[] = {\n    pixelroot32::graphics::Color::Transparent,\n    pixelroot32::graphics::Color::Red,\n    pixelroot32::graphics::Color::Green,\n    pixelroot32::graphics::Color::Blue\n};\n\n// Create 2bpp sprite\nstatic const pixelroot32::graphics::Sprite2bpp COLORFUL_SPRITE = {\n    COLORFUL_SPRITE_DATA,\n    SPRITE_PALETTE,\n    16,  // width\n    8,   // height\n    4    // palette size\n};\n\n// Draw 2bpp sprite\nrenderer.drawSprite(COLORFUL_SPRITE, 100, 100, false);\n#endif\n

Characteristics: - 2 bits per pixel (4 colors) - Requires custom palette - More memory than 1bpp - Best for: More colorful sprites without full color

"},{"location":"manual/advanced_graphics/sprites_and_animation/#4bpp-experimental-16-colors","title":"4bpp (Experimental, 16 Colors)","text":"

4 bits per pixel allows 16 colors per sprite:

#ifdef PIXELROOT32_ENABLE_4BPP_SPRITES\n#include <graphics/Renderer.h>\n\n// Define 4bpp sprite data\nstatic const uint8_t RICH_SPRITE_DATA[] = {\n    // Each byte represents 2 pixels (4 bits each)\n    // Format: [pixel1][pixel0]\n    0x01, 0x23, 0x45, 0x67,  // Row 0\n    // ... more rows\n};\n\n// Define palette (16 colors)\nstatic const pixelroot32::graphics::Color RICH_PALETTE[] = {\n    pixelroot32::graphics::Color::Transparent,\n    pixelroot32::graphics::Color::Black,\n    pixelroot32::graphics::Color::DarkGray,\n    // ... 13 more colors\n};\n\n// Create 4bpp sprite\nstatic const pixelroot32::graphics::Sprite4bpp RICH_SPRITE = {\n    RICH_SPRITE_DATA,\n    RICH_PALETTE,\n    16,  // width\n    16,  // height\n    16   // palette size\n};\n\n// Draw 4bpp sprite\nrenderer.drawSprite(RICH_SPRITE, 100, 100, false);\n#endif\n

Characteristics: - 4 bits per pixel (16 colors) - Requires custom palette - Most memory-intensive - Best for: Detailed sprites with many colors

"},{"location":"manual/advanced_graphics/sprites_and_animation/#multisprite-multi-layer","title":"MultiSprite (Multi-Layer)","text":"

MultiSprite combines multiple 1bpp layers to create multi-color sprites:

#include <graphics/Renderer.h>\n\n// Define layers (each is 1bpp)\nstatic const uint16_t BASE_LAYER_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b01111110,\n    0b00111100,\n    0b00000000\n};\n\nstatic const uint16_t HIGHLIGHT_LAYER_DATA[] = {\n    0b00000000,\n    0b00011000,\n    0b00111100,\n    0b00111100,\n    0b00111100,\n    0b00011000,\n    0b00000000,\n    0b00000000\n};\n\n// Create layers\nstatic const pixelroot32::graphics::SpriteLayer LAYERS[] = {\n    { BASE_LAYER_DATA, pixelroot32::graphics::Color::Blue },      // Base layer\n    { HIGHLIGHT_LAYER_DATA, pixelroot32::graphics::Color::Cyan }  // Highlight layer\n};\n\n// Create MultiSprite\nstatic const pixelroot32::graphics::MultiSprite PLAYER_MULTI = {\n    8,      // width\n    8,      // height\n    LAYERS, // layers array\n    2       // layer count\n};\n\n// Draw MultiSprite\nrenderer.drawSprite(PLAYER_MULTI, 100, 100, false);\n

Characteristics: - Combines multiple 1bpp layers - Each layer can have different color - Layers drawn in order (first = bottom) - Best for: Complex sprites with highlights, outlines, etc.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#creating-sprites","title":"Creating Sprites","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#manual-creation-1bpp","title":"Manual Creation (1bpp)","text":"

For simple sprites, you can create them manually:

// 8x8 sprite: Simple circle\nstatic const uint16_t CIRCLE_SPRITE_DATA[] = {\n    0b00111100,  //   ####\n    0b01111110,  //  ######\n    0b11111111,  // ########\n    0b11111111,  // ########\n    0b11111111,  // ########\n    0b11111111,  // ########\n    0b01111110,  //  ######\n    0b00111100   //   ####\n};\n\nstatic const pixelroot32::graphics::Sprite CIRCLE_SPRITE = {\n    CIRCLE_SPRITE_DATA,\n    8,\n    8\n};\n

Tips: - Use binary notation for clarity - Comment each row to visualize - Keep sprites small (8x8, 16x16) - Reuse sprites when possible

"},{"location":"manual/advanced_graphics/sprites_and_animation/#using-sprite-compiler","title":"Using Sprite Compiler","text":"

For complex sprites, use the Sprite Compiler tool (if available) to convert PNG images to sprite data.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-animation","title":"Sprite Animation","text":"

PixelRoot32 uses a step-based animation system that's lightweight and efficient.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#spriteanimation-structure","title":"SpriteAnimation Structure","text":"
#include <graphics/Renderer.h>\n\n// Define animation frames\nstatic const uint16_t FRAME1_DATA[] = { /* ... */ };\nstatic const uint16_t FRAME2_DATA[] = { /* ... */ };\nstatic const uint16_t FRAME3_DATA[] = { /* ... */ };\n\nstatic const pixelroot32::graphics::Sprite FRAME1 = { FRAME1_DATA, 8, 8 };\nstatic const pixelroot32::graphics::Sprite FRAME2 = { FRAME2_DATA, 8, 8 };\nstatic const pixelroot32::graphics::Sprite FRAME3 = { FRAME3_DATA, 8, 8 };\n\n// Create animation frames\nstatic const pixelroot32::graphics::SpriteAnimationFrame ANIMATION_FRAMES[] = {\n    { &FRAME1, nullptr },  // Frame 1 (no mask)\n    { &FRAME2, nullptr },  // Frame 2\n    { &FRAME3, nullptr }   // Frame 3\n};\n\n// Create animation\npixelroot32::graphics::SpriteAnimation walkAnimation;\nwalkAnimation.frames = ANIMATION_FRAMES;\nwalkAnimation.frameCount = 3;\nwalkAnimation.current = 0;\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#using-animations-in-actors","title":"Using Animations in Actors","text":"
#include <core/Actor.h>\n#include <graphics/Renderer.h>\n\nclass AnimatedPlayer : public pixelroot32::core::Actor {\nprivate:\n    pixelroot32::graphics::SpriteAnimation walkAnimation;\n    unsigned long animationTimer = 0;\n    const unsigned long FRAME_DURATION_MS = 100; // 100ms per frame\n\npublic:\n    AnimatedPlayer(float x, float y)\n        : Actor(x, y, 8, 8) {\n        setRenderLayer(1);\n\n        // Initialize animation\n        walkAnimation.frames = WALK_ANIMATION_FRAMES;\n        walkAnimation.frameCount = 3;\n        walkAnimation.current = 0;\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update animation\n        animationTimer += deltaTime;\n        if (animationTimer >= FRAME_DURATION_MS) {\n            animationTimer -= FRAME_DURATION_MS;\n            walkAnimation.step(); // Advance to next frame\n        }\n\n        // Movement logic...\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Get current frame\n        const pixelroot32::graphics::Sprite* currentFrame = \n            walkAnimation.frames[walkAnimation.current].sprite;\n\n        // Draw current frame\n        renderer.drawSprite(\n            *currentFrame,\n            static_cast<int>(x),\n            static_cast<int>(y),\n            pixelroot32::graphics::Color::White,\n            false // flipX\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collision\n    }\n};\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#animation-control","title":"Animation Control","text":"
// Reset animation to first frame\nwalkAnimation.reset();\n\n// Step to next frame (loops automatically)\nwalkAnimation.step();\n\n// Get current frame\nconst pixelroot32::graphics::Sprite* frame = \n    walkAnimation.frames[walkAnimation.current].sprite;\n\n// Check if animation is at specific frame\nif (walkAnimation.current == 0) {\n    // At first frame\n}\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#multiple-animations","title":"Multiple Animations","text":"

For actors with multiple animations (idle, walk, jump):

class PlayerActor : public pixelroot32::core::Actor {\nprivate:\n    enum class AnimationState {\n        IDLE,\n        WALK,\n        JUMP\n    };\n\n    AnimationState currentState = AnimationState::IDLE;\n    pixelroot32::graphics::SpriteAnimation idleAnim;\n    pixelroot32::graphics::SpriteAnimation walkAnim;\n    pixelroot32::graphics::SpriteAnimation jumpAnim;\n\n    pixelroot32::graphics::SpriteAnimation* getCurrentAnimation() {\n        switch (currentState) {\n            case AnimationState::IDLE: return &idleAnim;\n            case AnimationState::WALK: return &walkAnim;\n            case AnimationState::JUMP: return &jumpAnim;\n        }\n        return &idleAnim;\n    }\n\npublic:\n    void update(unsigned long deltaTime) override {\n        // Update current animation\n        auto* anim = getCurrentAnimation();\n        animationTimer += deltaTime;\n        if (animationTimer >= FRAME_DURATION_MS) {\n            animationTimer -= FRAME_DURATION_MS;\n            anim->step();\n        }\n\n        // Change animation state based on game logic\n        if (isMoving) {\n            if (currentState != AnimationState::WALK) {\n                currentState = AnimationState::WALK;\n                walkAnim.reset();\n            }\n        } else if (isJumping) {\n            if (currentState != AnimationState::JUMP) {\n                currentState = AnimationState::JUMP;\n                jumpAnim.reset();\n            }\n        } else {\n            if (currentState != AnimationState::IDLE) {\n                currentState = AnimationState::IDLE;\n                idleAnim.reset();\n            }\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        auto* anim = getCurrentAnimation();\n        const auto* frame = anim->frames[anim->current].sprite;\n        renderer.drawSprite(*frame, static_cast<int>(x), static_cast<int>(y), \n            pixelroot32::graphics::Color::White);\n    }\n};\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-flipping","title":"Sprite Flipping","text":"

Flip sprites horizontally for facing direction:

bool facingRight = true;\n\nvoid draw(pixelroot32::graphics::Renderer& renderer) override {\n    renderer.drawSprite(\n        PLAYER_SPRITE,\n        static_cast<int>(x),\n        static_cast<int>(y),\n        pixelroot32::graphics::Color::White,\n        !facingRight // Flip if facing left\n    );\n}\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#memory-optimization","title":"Memory Optimization","text":"
  • Reuse sprites: Define sprites once, use many times
  • Use 1bpp when possible: Most memory-efficient
  • Store in flash: Use static const to keep in flash memory
  • Limit sprite count: Too many unique sprites can exhaust memory
"},{"location":"manual/advanced_graphics/sprites_and_animation/#performance","title":"Performance","text":"
  • Pre-calculate animations: Set up animations in init(), not update()
  • Limit active animations: Only animate visible entities
  • Use appropriate formats: Don't use 4bpp if 1bpp works
  • Batch similar sprites: Draw similar sprites together
"},{"location":"manual/advanced_graphics/sprites_and_animation/#organization","title":"Organization","text":"
  • Group related sprites: Keep sprite data together
  • Use meaningful names: Name sprites clearly
  • Document complex sprites: Comment sprite bit patterns
  • Create sprite libraries: Reusable sprite collections
"},{"location":"manual/advanced_graphics/sprites_and_animation/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-sheet-pattern","title":"Sprite Sheet Pattern","text":"

Organize multiple sprites in arrays:

namespace PlayerSprites {\n    static const uint16_t IDLE_FRAME1[] = { /* ... */ };\n    static const uint16_t IDLE_FRAME2[] = { /* ... */ };\n    static const uint16_t WALK_FRAME1[] = { /* ... */ };\n    static const uint16_t WALK_FRAME2[] = { /* ... */ };\n\n    static const pixelroot32::graphics::Sprite IDLE[] = {\n        { IDLE_FRAME1, 8, 8 },\n        { IDLE_FRAME2, 8, 8 }\n    };\n\n    static const pixelroot32::graphics::Sprite WALK[] = {\n        { WALK_FRAME1, 8, 8 },\n        { WALK_FRAME2, 8, 8 }\n    };\n}\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#animation-helper","title":"Animation Helper","text":"

Create a helper class for animation management:

class AnimationController {\nprivate:\n    pixelroot32::graphics::SpriteAnimation* currentAnim;\n    unsigned long timer = 0;\n    unsigned long frameDuration;\n\npublic:\n    void setAnimation(pixelroot32::graphics::SpriteAnimation* anim) {\n        if (currentAnim != anim) {\n            currentAnim = anim;\n            currentAnim->reset();\n            timer = 0;\n        }\n    }\n\n    void update(unsigned long deltaTime) {\n        if (currentAnim) {\n            timer += deltaTime;\n            if (timer >= frameDuration) {\n                timer -= frameDuration;\n                currentAnim->step();\n            }\n        }\n    }\n\n    const pixelroot32::graphics::Sprite* getCurrentFrame() {\n        if (currentAnim && currentAnim->frameCount > 0) {\n            return currentAnim->frames[currentAnim->current].sprite;\n        }\n        return nullptr;\n    }\n};\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#sprites-not-displaying","title":"Sprites Not Displaying","text":"
  • Check sprite data is valid
  • Verify width/height match data
  • Ensure sprite is within screen bounds
  • Check render layer is correct
"},{"location":"manual/advanced_graphics/sprites_and_animation/#animation-not-playing","title":"Animation Not Playing","text":"
  • Verify animation frames are set
  • Check step() is being called
  • Ensure timer logic is correct
  • Verify frame count matches array size
"},{"location":"manual/advanced_graphics/sprites_and_animation/#memory-issues","title":"Memory Issues","text":"
  • Reduce sprite count
  • Use 1bpp instead of 2bpp/4bpp
  • Reuse sprites more
  • Check available flash memory
"},{"location":"manual/advanced_graphics/sprites_and_animation/#next-steps","title":"Next Steps","text":"

Now that you understand sprites and animation, learn about: - Color Palettes - Use different color schemes - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles

See also: - API Reference - Sprite - API Reference - SpriteAnimation - Manual - Basic Rendering

"},{"location":"manual/advanced_graphics/tilemaps/","title":"Tilemaps","text":"

Tilemaps allow you to build levels efficiently by reusing small tile sprites. This guide covers creating tilemaps, rendering them, and using them with scrolling cameras.

"},{"location":"manual/advanced_graphics/tilemaps/#what-are-tilemaps","title":"What are Tilemaps?","text":"

A tilemap is a 2D grid where each cell references a tile sprite. Instead of placing individual sprites, you define which tile appears at each grid position.

Advantages: - Memory efficient: Reuse tile sprites many times - Easy level design: Edit level data, not code - Fast rendering: Optimized tilemap drawing - Large levels: Create levels bigger than screen - Multiple Bit-Depths: Support for 1bpp, 2bpp, and 4bpp tilemaps for higher graphical fidelity

"},{"location":"manual/advanced_graphics/tilemaps/#creating-a-tilemap","title":"Creating a Tilemap","text":""},{"location":"manual/advanced_graphics/tilemaps/#1-define-tiles","title":"1. Define Tiles","text":"

First, create the tile sprites you'll reuse. You can use standard 1bpp sprites or multi-bpp sprites (2bpp/4bpp) if enabled.

"},{"location":"manual/advanced_graphics/tilemaps/#1bpp-tiles-example","title":"1bpp Tiles Example","text":"
#include <graphics/Renderer.h>\n\n// Ground tile (solid)\nstatic const uint16_t TILE_GROUND_BITS[] = {\n    0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,\n    0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF\n};\n\n// Create tile sprites (8x8 tiles)\nstatic const pixelroot32::graphics::Sprite TILES[] = {\n    { TILE_EMPTY_BITS, 8, 8 },  // Index 0: Empty\n    { TILE_GROUND_BITS, 8, 8 }  // Index 1: Ground\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#2bpp-tiles-example-multi-color","title":"2bpp Tiles Example (Multi-color)","text":"
#include <graphics/Renderer.h>\n\n// 2bpp grass tile\nstatic const uint8_t TILE_GRASS_DATA[] = {\n    0b01010101, 0b01010101, // Packed 2bpp data\n    // ...\n};\n\nstatic const Color GRASS_PALETTE[] = {\n    Color::Transparent, Color::DarkGreen, Color::Green, Color::LightGreen\n};\n\nstatic const pixelroot32::graphics::Sprite2bpp TILES_2BPP[] = {\n    { TILE_GRASS_DATA, GRASS_PALETTE, 8, 8, 4 }\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#2-create-tile-index-array","title":"2. Create Tile Index Array","text":"

Define which tile appears at each position:

// Tilemap dimensions (30 tiles wide, 20 tiles tall)\nstatic const int TILEMAP_WIDTH = 30;\nstatic const int TILEMAP_HEIGHT = 20;\n\n// Array of tile indices (each byte is a tile index)\nstatic uint8_t TILEMAP_INDICES[TILEMAP_WIDTH * TILEMAP_HEIGHT];\n\n// Initialize to empty\nvoid initTilemap() {\n    for (int i = 0; i < TILEMAP_WIDTH * TILEMAP_HEIGHT; i++) {\n        TILEMAP_INDICES[i] = 0; // Empty\n    }\n\n    // Draw ground at bottom\n    int groundRow = TILEMAP_HEIGHT - 1;\n    for (int x = 0; x < TILEMAP_WIDTH; x++) {\n        TILEMAP_INDICES[groundRow * TILEMAP_WIDTH + x] = 1; // Ground tile\n    }\n\n    // Add some walls\n    TILEMAP_INDICES[5 * TILEMAP_WIDTH + 10] = 2; // Wall at (10, 5)\n    TILEMAP_INDICES[5 * TILEMAP_WIDTH + 11] = 2;\n    TILEMAP_INDICES[5 * TILEMAP_WIDTH + 12] = 2;\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#3-create-tilemap-structure","title":"3. Create TileMap Structure","text":"
#include <graphics/Renderer.h>\n\nstatic pixelroot32::graphics::TileMap myTileMap = {\n    TILEMAP_INDICES,                    // indices array\n    TILEMAP_WIDTH,                      // width (in tiles)\n    TILEMAP_HEIGHT,                     // height (in tiles)\n    TILES,                              // tiles array\n    8,                                  // tile width (pixels)\n    8,                                  // tile height (pixels)\n    sizeof(TILES) / sizeof(pixelroot32::graphics::Sprite) // tile count\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#rendering-tilemaps","title":"Rendering Tilemaps","text":""},{"location":"manual/advanced_graphics/tilemaps/#basic-rendering","title":"Basic Rendering","text":"
void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // 1bpp Tilemap (requires a color)\n    renderer.drawTileMap(\n        myTileMap,\n        0, 0,\n        pixelroot32::graphics::Color::White\n    );\n\n    // 2bpp/4bpp Tilemap (colors are in the sprite palettes)\n    renderer.drawTileMap(myTileMap2bpp, 0, 100);\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#with-camerascrolling","title":"With Camera/Scrolling","text":"
void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera first\n    camera.apply(renderer);\n\n    // Draw tilemap (camera offset is automatically applied)\n    renderer.drawTileMap(\n        myTileMap,\n        0,                              // World position (0, 0)\n        0,\n        pixelroot32::graphics::Color::White\n    );\n\n    // Draw game objects\n    Scene::draw(renderer);\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#complete-example-platformer-level","title":"Complete Example: Platformer Level","text":"
#include <core/Scene.h>\n#include <graphics/Renderer.h>\n#include <graphics/Camera2D.h>\n\nclass PlatformerLevel : public pixelroot32::core::Scene {\nprivate:\n    static const int TILE_SIZE = 8;\n    static const int TILEMAP_WIDTH = 100;  // 800 pixels wide\n    static const int TILEMAP_HEIGHT = 30;   // 240 pixels tall\n\n    // Tile definitions\n    static const uint16_t TILE_EMPTY_BITS[] = {\n        0x0000, 0x0000, 0x0000, 0x0000,\n        0x0000, 0x0000, 0x0000, 0x0000\n    };\n\n    static const uint16_t TILE_GROUND_BITS[] = {\n        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,\n        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF\n    };\n\n    static const uint16_t TILE_GRASS_BITS[] = {\n        0x0000, 0x0000, 0x0000, 0x0000,\n        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF\n    };\n\n    static const pixelroot32::graphics::Sprite TILES[] = {\n        { TILE_EMPTY_BITS, TILE_SIZE, TILE_SIZE },  // 0: Empty\n        { TILE_GROUND_BITS, TILE_SIZE, TILE_SIZE }, // 1: Ground\n        { TILE_GRASS_BITS, TILE_SIZE, TILE_SIZE }   // 2: Grass top\n    };\n\n    static uint8_t LEVEL_INDICES[TILEMAP_WIDTH * TILEMAP_HEIGHT];\n\n    pixelroot32::graphics::TileMap levelTileMap;\n    pixelroot32::graphics::Camera2D camera;\n\npublic:\n    PlatformerLevel() \n        : camera(240, 240) {\n        // Initialize tilemap structure\n        levelTileMap = {\n            LEVEL_INDICES,\n            TILEMAP_WIDTH,\n            TILEMAP_HEIGHT,\n            TILES,\n            TILE_SIZE,\n            TILE_SIZE,\n            sizeof(TILES) / sizeof(pixelroot32::graphics::Sprite)\n        };\n    }\n\n    void init() override {\n        // Initialize all tiles to empty\n        for (int i = 0; i < TILEMAP_WIDTH * TILEMAP_HEIGHT; i++) {\n            LEVEL_INDICES[i] = 0;\n        }\n\n        // Create ground level\n        int groundY = TILEMAP_HEIGHT - 1;\n        for (int x = 0; x < TILEMAP_WIDTH; x++) {\n            LEVEL_INDICES[groundY * TILEMAP_WIDTH + x] = 1; // Ground\n        }\n\n        // Add grass on top of ground\n        int grassY = groundY - 1;\n        for (int x = 0; x < TILEMAP_WIDTH; x++) {\n            LEVEL_INDICES[grassY * TILEMAP_WIDTH + x] = 2; // Grass\n        }\n\n        // Add platforms\n        // Platform 1: x=10 to x=15, y=20\n        for (int x = 10; x < 16; x++) {\n            LEVEL_INDICES[20 * TILEMAP_WIDTH + x] = 1; // Ground tile\n        }\n\n        // Platform 2: x=30 to x=35, y=15\n        for (int x = 30; x < 36; x++) {\n            LEVEL_INDICES[15 * TILEMAP_WIDTH + x] = 1;\n        }\n\n        // Set camera boundaries\n        camera.setBounds(0, TILEMAP_WIDTH * TILE_SIZE - 240);\n        camera.setVerticalBounds(0, TILEMAP_HEIGHT * TILE_SIZE - 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Follow player (example)\n        // camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw tilemap\n        renderer.drawTileMap(\n            levelTileMap,\n            0, 0,\n            pixelroot32::graphics::Color::White\n        );\n\n        // Draw game objects\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#tilemap-with-scroll","title":"Tilemap with Scroll","text":"

For scrolling levels, combine tilemaps with cameras:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera (handles scrolling)\n    camera.apply(renderer);\n\n    // Draw tilemap (automatically scrolled by camera)\n    renderer.drawTileMap(\n        levelTileMap,\n        0, 0,\n        pixelroot32::graphics::Color::White\n    );\n\n    // Draw entities (also scrolled)\n    Scene::draw(renderer);\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#optimizing-tilemap-rendering","title":"Optimizing Tilemap Rendering","text":""},{"location":"manual/advanced_graphics/tilemaps/#viewport-culling","title":"Viewport Culling","text":"

Only draw visible tiles:

void drawTileMapOptimized(\n    pixelroot32::graphics::Renderer& renderer,\n    const pixelroot32::graphics::TileMap& tileMap,\n    int offsetX, int offsetY,\n    pixelroot32::graphics::Color color\n) {\n    int screenWidth = renderer.getWidth();\n    int screenHeight = renderer.getHeight();\n\n    // Calculate which tiles are visible\n    int startTileX = (offsetX < 0) ? (-offsetX / tileMap.tileWidth) : 0;\n    int startTileY = (offsetY < 0) ? (-offsetY / tileMap.tileHeight) : 0;\n    int endTileX = startTileX + (screenWidth / tileMap.tileWidth) + 1;\n    int endTileY = startTileY + (screenHeight / tileMap.tileHeight) + 1;\n\n    // Clamp to tilemap bounds\n    if (startTileX < 0) startTileX = 0;\n    if (startTileY < 0) startTileY = 0;\n    if (endTileX > tileMap.width) endTileX = tileMap.width;\n    if (endTileY > tileMap.height) endTileY = tileMap.height;\n\n    // Draw only visible tiles\n    for (int ty = startTileY; ty < endTileY; ty++) {\n        for (int tx = startTileX; tx < endTileX; tx++) {\n            uint8_t tileIndex = tileMap.indices[ty * tileMap.width + tx];\n            if (tileIndex < tileMap.tileCount) {\n                int x = tx * tileMap.tileWidth + offsetX;\n                int y = ty * tileMap.tileHeight + offsetY;\n                renderer.drawSprite(\n                    tileMap.tiles[tileIndex],\n                    x, y,\n                    color,\n                    false\n                );\n            }\n        }\n    }\n}\n

Note: The built-in drawTileMap() already performs viewport culling, so you typically don't need to implement this yourself.

"},{"location":"manual/advanced_graphics/tilemaps/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/tilemaps/#tile-design","title":"Tile Design","text":"
  • Keep tiles small: 8x8 or 16x16 pixels work best
  • Reuse tiles: Design tiles that can be used in multiple ways
  • Consistent style: All tiles should match visually
  • Limit tile count: Too many unique tiles uses more memory
"},{"location":"manual/advanced_graphics/tilemaps/#level-design","title":"Level Design","text":"
  • Use indices efficiently: 0 = empty, 1+ = different tiles
  • Plan layout: Design level on paper/grid first
  • Test on hardware: Large tilemaps may impact performance
  • Optimize data: Use compact level data format
"},{"location":"manual/advanced_graphics/tilemaps/#performance","title":"Performance","text":"
  • Limit tilemap size: Very large tilemaps can be slow
  • Use appropriate tile size: Smaller tiles = more tiles to draw
  • Combine with culling: Only draw visible area
  • Test scrolling: Ensure smooth scrolling performance
"},{"location":"manual/advanced_graphics/tilemaps/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/tilemaps/#level-data-in-code","title":"Level Data in Code","text":"
// Define level as 2D array (easier to read)\nstatic const uint8_t LEVEL_DATA[][TILEMAP_WIDTH] = {\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, // Ground\n};\n\n// Copy to tilemap indices\nvoid loadLevel() {\n    for (int y = 0; y < TILEMAP_HEIGHT; y++) {\n        for (int x = 0; x < TILEMAP_WIDTH; x++) {\n            TILEMAP_INDICES[y * TILEMAP_WIDTH + x] = LEVEL_DATA[y][x];\n        }\n    }\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#collision-detection-with-tilemaps","title":"Collision Detection with Tilemaps","text":"
bool isTileSolid(int tileX, int tileY) {\n    if (tileX < 0 || tileX >= TILEMAP_WIDTH ||\n        tileY < 0 || tileY >= TILEMAP_HEIGHT) {\n        return true; // Out of bounds = solid\n    }\n\n    uint8_t tileIndex = TILEMAP_INDICES[tileY * TILEMAP_WIDTH + tileX];\n    return tileIndex != 0; // 0 = empty, others = solid\n}\n\nbool checkCollision(float x, float y, int width, int height) {\n    // Convert world position to tile coordinates\n    int tileX1 = static_cast<int>(x) / TILE_SIZE;\n    int tileY1 = static_cast<int>(y) / TILE_SIZE;\n    int tileX2 = static_cast<int>(x + width) / TILE_SIZE;\n    int tileY2 = static_cast<int>(y + height) / TILE_SIZE;\n\n    // Check all tiles actor overlaps\n    for (int ty = tileY1; ty <= tileY2; ty++) {\n        for (int tx = tileX1; tx <= tileX2; tx++) {\n            if (isTileSolid(tx, ty)) {\n                return true; // Collision!\n            }\n        }\n    }\n\n    return false; // No collision\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/tilemaps/#tiles-not-appearing","title":"Tiles Not Appearing","text":"
  • Verify tile indices are correct (0 = first tile, 1 = second, etc.)
  • Check tilemap dimensions match indices array size
  • Ensure tiles array has enough entries
  • Verify tile size matches sprite size
"},{"location":"manual/advanced_graphics/tilemaps/#performance-issues","title":"Performance Issues","text":"
  • Reduce tilemap size
  • Use smaller tiles
  • Limit number of unique tiles
  • Test viewport culling
"},{"location":"manual/advanced_graphics/tilemaps/#scrolling-problems","title":"Scrolling Problems","text":"
  • Ensure camera is applied before drawing tilemap
  • Check tilemap position matches camera offset
  • Verify tilemap boundaries are correct
  • Test with simple tilemap first
"},{"location":"manual/advanced_graphics/tilemaps/#next-steps","title":"Next Steps","text":"

Now that you understand tilemaps, learn about: - Particles and Effects - Add visual effects - Cameras and Scrolling - Combine with scrolling - Performance Optimization - Optimize rendering

See also: - API Reference - TileMap - API Reference - Renderer - Manual - Cameras and Scrolling

"},{"location":"manual/game_development/audio/","title":"Audio","text":"

PixelRoot32 includes a complete NES-like audio system with 4 channels for sound effects and background music. This guide shows you how to add sound and music to your games.

"},{"location":"manual/game_development/audio/#audio-configuration","title":"Audio Configuration","text":"

Before using audio, you need to configure an AudioBackend. This is done when creating the Engine:

"},{"location":"manual/game_development/audio/#esp32-internal-dac","title":"ESP32: Internal DAC","text":"
#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nconst int DAC_PIN = 25; // GPIO 25 or 26\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\npr32::audio::AudioConfig audioConfig(&audioBackend, audioBackend.getSampleRate());\n
"},{"location":"manual/game_development/audio/#esp32-external-i2s-dac","title":"ESP32: External I2S DAC","text":"
#include <drivers/esp32/ESP32_I2S_AudioBackend.h>\n\nconst int I2S_BCLK = 26;  // Bit clock\nconst int I2S_LRCK = 25;  // Left/Right clock\nconst int I2S_DOUT = 22;  // Data out\n\npr32::drivers::esp32::ESP32_I2S_AudioBackend audioBackend(\n    I2S_BCLK, I2S_LRCK, I2S_DOUT, 22050\n);\n\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n
"},{"location":"manual/game_development/audio/#native-pc-sdl2","title":"Native (PC): SDL2","text":"
#include <drivers/native/SDL2_AudioBackend.h>\n\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\n\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n
"},{"location":"manual/game_development/audio/#sound-effects","title":"Sound Effects","text":"

Sound effects are created using AudioEvent structures and played through the AudioEngine.

"},{"location":"manual/game_development/audio/#audioevent-structure","title":"AudioEvent Structure","text":"
#include <audio/AudioTypes.h>\n\npr32::audio::AudioEvent soundEffect{};\nsoundEffect.type = pr32::audio::WaveType::PULSE;  // Waveform type\nsoundEffect.frequency = 1500.0f;                  // Frequency in Hz\nsoundEffect.duration = 0.12f;                      // Duration in seconds\nsoundEffect.volume = 0.8f;                         // Volume (0.0 to 1.0)\nsoundEffect.duty = 0.5f;                           // Duty cycle (for PULSE only)\n
"},{"location":"manual/game_development/audio/#wave-types","title":"Wave Types","text":"

PixelRoot32 supports three wave types:

  • PULSE: Square wave with variable duty cycle
  • Duty cycles: 0.125 (thin), 0.25 (classic NES), 0.5 (symmetric), 0.75 (fat)
  • Good for: Beeps, jumps, UI sounds, leads

  • TRIANGLE: Triangle wave (fixed volume/duty)

  • Softer, smoother sound
  • Good for: Bass lines, pads, background tones

  • NOISE: Pseudo-random noise

  • Harsh, chaotic sound
  • Good for: Explosions, hits, impacts, drums
"},{"location":"manual/game_development/audio/#playing-sound-effects","title":"Playing Sound Effects","text":"
// Get the audio engine\nauto& audio = engine.getAudioEngine();\n\n// Create and play a sound\npr32::audio::AudioEvent jumpSound{};\njumpSound.type = pr32::audio::WaveType::PULSE;\njumpSound.frequency = 800.0f;\njumpSound.duration = 0.1f;\njumpSound.volume = 0.7f;\njumpSound.duty = 0.25f;\n\naudio.playEvent(jumpSound);\n
"},{"location":"manual/game_development/audio/#common-sound-effects","title":"Common Sound Effects","text":"

Here are some example sound effects you can use:

namespace SoundEffects {\n    // Jump sound\n    inline pr32::audio::AudioEvent jump() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::PULSE;\n        evt.frequency = 600.0f;\n        evt.duration = 0.1f;\n        evt.volume = 0.7f;\n        evt.duty = 0.25f;\n        return evt;\n    }\n\n    // Coin/collect sound\n    inline pr32::audio::AudioEvent coin() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::PULSE;\n        evt.frequency = 1500.0f;\n        evt.duration = 0.12f;\n        evt.volume = 0.8f;\n        evt.duty = 0.5f;\n        return evt;\n    }\n\n    // Explosion\n    inline pr32::audio::AudioEvent explosion() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::NOISE;\n        evt.frequency = 200.0f;\n        evt.duration = 0.3f;\n        evt.volume = 0.9f;\n        return evt;\n    }\n\n    // Hit/damage\n    inline pr32::audio::AudioEvent hit() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::NOISE;\n        evt.frequency = 300.0f;\n        evt.duration = 0.15f;\n        evt.volume = 0.6f;\n        return evt;\n    }\n}\n\n// Usage\naudio.playEvent(SoundEffects::jump());\n
"},{"location":"manual/game_development/audio/#background-music","title":"Background Music","text":"

Background music uses the MusicPlayer system, which sequences notes over time.

"},{"location":"manual/game_development/audio/#music-notes","title":"Music Notes","text":"

Music is built from MusicNote structures:

#include <audio/AudioMusicTypes.h>\n\nusing namespace pr32::audio;\n\nMusicNote note{};\nnote.note = Note::C;        // Musical note (C, D, E, F, G, A, B, or Rest)\nnote.octave = 4;            // Octave (0-8)\nnote.duration = 0.2f;       // Duration in seconds\nnote.volume = 0.7f;         // Volume (0.0 to 1.0)\n
"},{"location":"manual/game_development/audio/#instrument-presets","title":"Instrument Presets","text":"

For convenience, use predefined instrument presets:

using namespace pr32::audio;\n\n// Available presets:\n// - INSTR_PULSE_LEAD: Main lead pulse (octave 4)\n// - INSTR_PULSE_BASS: Bass pulse (octave 3)\n// - INSTR_PULSE_CHIP_HIGH: High-pitched chiptune (octave 5)\n// - INSTR_TRIANGLE_PAD: Soft triangle pad (octave 4)\n
"},{"location":"manual/game_development/audio/#creating-a-melody","title":"Creating a Melody","text":"
#include <audio/AudioMusicTypes.h>\n\nusing namespace pr32::audio;\n\n// Define melody notes\nstatic const MusicNote MELODY_NOTES[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),  // Rest (silence)\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),\n};\n\n// Create music track\nstatic const MusicTrack GAME_MUSIC = {\n    MELODY_NOTES,                              // notes array\n    sizeof(MELODY_NOTES) / sizeof(MusicNote),  // note count\n    true,                                       // loop\n    WaveType::PULSE,                           // channel type\n    0.5f                                       // duty cycle\n};\n
"},{"location":"manual/game_development/audio/#playing-music","title":"Playing Music","text":"
// Get the music player\nauto& music = engine.getMusicPlayer();\n\n// Play a track\nmusic.play(GAME_MUSIC);\n\n// Control playback\nmusic.stop();   // Stop playback\nmusic.pause();  // Pause (time doesn't advance)\nmusic.resume(); // Resume after pause\n\n// Check status\nif (music.isPlaying()) {\n    // Music is currently playing\n}\n
"},{"location":"manual/game_development/audio/#music-in-scene","title":"Music in Scene","text":"

Typically, you start music in your scene's init():

void MyGameScene::init() override {\n    // Start background music\n    engine.getMusicPlayer().play(GAME_MUSIC);\n\n    // ... rest of initialization\n}\n
"},{"location":"manual/game_development/audio/#master-volume","title":"Master Volume","text":"

Control overall volume without changing individual sounds:

auto& audio = engine.getAudioEngine();\n\n// Set master volume (0.0 to 1.0)\naudio.setMasterVolume(0.5f); // 50% volume\n\n// Get current volume\nfloat currentVolume = audio.getMasterVolume();\n
"},{"location":"manual/game_development/audio/#complete-example","title":"Complete Example","text":"

Here's a complete example combining sound effects and music:

#include <core/Scene.h>\n#include <audio/AudioTypes.h>\n#include <audio/AudioMusicTypes.h>\n\nusing namespace pr32::audio;\n\n// Background music\nstatic const MusicNote GAME_MELODY[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),\n};\n\nstatic const MusicTrack BACKGROUND_MUSIC = {\n    GAME_MELODY,\n    sizeof(GAME_MELODY) / sizeof(MusicNote),\n    true,  // loop\n    WaveType::PULSE,\n    0.5f\n};\n\nclass AudioExampleScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Start background music\n        engine.getMusicPlayer().play(BACKGROUND_MUSIC);\n\n        // Set master volume\n        engine.getAudioEngine().setMasterVolume(0.8f);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        auto& audio = engine.getAudioEngine();\n\n        // Play sound effect on button press\n        if (input.isButtonPressed(4)) { // Button A\n            AudioEvent jumpSound{};\n            jumpSound.type = WaveType::PULSE;\n            jumpSound.frequency = 800.0f;\n            jumpSound.duration = 0.1f;\n            jumpSound.volume = 0.7f;\n            jumpSound.duty = 0.25f;\n\n            audio.playEvent(jumpSound);\n        }\n\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/audio/#designing-nes-like-sounds","title":"Designing NES-like Sounds","text":""},{"location":"manual/game_development/audio/#frequency-guidelines","title":"Frequency Guidelines","text":"
  • Low frequencies (200-400 Hz): Bass, impacts, explosions
  • Mid frequencies (400-1000 Hz): Main sounds, jumps, UI
  • High frequencies (1000-2000 Hz): Beeps, coins, pickups
  • Very high (2000+ Hz): Sharp sounds, alerts
"},{"location":"manual/game_development/audio/#duration-guidelines","title":"Duration Guidelines","text":"
  • Short (0.05-0.1s): UI clicks, small effects
  • Medium (0.1-0.2s): Jumps, hits, pickups
  • Long (0.2-0.5s): Explosions, power-ups, transitions
"},{"location":"manual/game_development/audio/#duty-cycle-pulse-only","title":"Duty Cycle (PULSE only)","text":"
  • 0.125: Thin, sharp, piercing
  • 0.25: Classic NES lead sound
  • 0.5: Symmetric, full, fat
  • 0.75: Very fat, bass-like
"},{"location":"manual/game_development/audio/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/audio/#sound-design","title":"Sound Design","text":"
  • Keep sounds short: Long sounds can overlap and cause issues
  • Use appropriate volumes: 0.6-0.8 is usually good for effects
  • Vary frequencies: Don't use the same frequency for everything
  • Test on hardware: ESP32 audio may sound different than PC
"},{"location":"manual/game_development/audio/#music","title":"Music","text":"
  • Use one channel for music: Leave other channels for SFX
  • Keep melodies simple: Complex melodies can be hard to follow
  • Loop seamlessly: End your melody where it can loop naturally
  • Consider tempo: Faster games need faster music
"},{"location":"manual/game_development/audio/#performance","title":"Performance","text":"
  • Limit simultaneous sounds: Only 4 channels total
  • Music uses one channel: Plan your SFX accordingly
  • Don't spam sounds: Too many sounds can cause audio glitches
  • Use master volume: Easier than adjusting individual sounds
"},{"location":"manual/game_development/audio/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/audio/#sound-effect-helper-function","title":"Sound Effect Helper Function","text":"
void playJumpSound() {\n    auto& audio = engine.getAudioEngine();\n    AudioEvent evt{};\n    evt.type = WaveType::PULSE;\n    evt.frequency = 600.0f;\n    evt.duration = 0.1f;\n    evt.volume = 0.7f;\n    evt.duty = 0.25f;\n    audio.playEvent(evt);\n}\n
"},{"location":"manual/game_development/audio/#music-state-management","title":"Music State Management","text":"
class GameScene : public Scene {\n    bool musicStarted = false;\n\n    void init() override {\n        // Don't start music here if scene can be re-initialized\n    }\n\n    void update(unsigned long deltaTime) override {\n        if (!musicStarted) {\n            engine.getMusicPlayer().play(GAME_MUSIC);\n            musicStarted = true;\n        }\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"manual/game_development/audio/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/game_development/audio/#no-sound","title":"No Sound","text":"
  • Check audio backend is configured correctly
  • Verify sample rate matches backend
  • Check master volume is not 0
  • Ensure audio is initialized (engine.init())
"},{"location":"manual/game_development/audio/#distorted-sound","title":"Distorted Sound","text":"
  • Lower volume levels
  • Reduce sample rate (ESP32 DAC works better at 11025 Hz)
  • Check for too many simultaneous sounds
  • Verify hardware connections (ESP32)
"},{"location":"manual/game_development/audio/#music-not-playing","title":"Music Not Playing","text":"
  • Check music.isPlaying() status
  • Ensure track is properly defined
  • Verify MusicPlayer is updated (happens automatically)
  • Check that music channel is not being used by SFX
"},{"location":"manual/game_development/audio/#next-steps","title":"Next Steps","text":"

Now that you can add audio, learn about: - NES Audio Reference - Advanced audio techniques - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs

See also: - API Reference - AudioEngine - API Reference - MusicPlayer - API Reference - Audio Types - Manual - Audio Overview

"},{"location":"manual/game_development/basic_rendering/","title":"Basic Rendering","text":"

Rendering is how you draw everything on screen. This guide covers the fundamental drawing operations in PixelRoot32: primitives, sprites, and text.

"},{"location":"manual/game_development/basic_rendering/#accessing-the-renderer","title":"Accessing the Renderer","text":"

You can access the renderer in two ways:

"},{"location":"manual/game_development/basic_rendering/#from-the-engine","title":"From the Engine","text":"
auto& renderer = engine.getRenderer();\n
"},{"location":"manual/game_development/basic_rendering/#from-a-scene","title":"From a Scene","text":"
void MyScene::draw(pixelroot32::graphics::Renderer& renderer) override {\n    // renderer is passed as parameter\n    renderer.drawFilledRectangle(0, 0, 240, 240, Color::Black);\n}\n
"},{"location":"manual/game_development/basic_rendering/#drawing-primitives","title":"Drawing Primitives","text":""},{"location":"manual/game_development/basic_rendering/#pixels","title":"Pixels","text":"

Draw a single pixel:

renderer.drawPixel(100, 100, pixelroot32::graphics::Color::White);\n
"},{"location":"manual/game_development/basic_rendering/#lines","title":"Lines","text":"

Draw a line between two points:

renderer.drawLine(10, 10, 200, 200, pixelroot32::graphics::Color::Red);\n
"},{"location":"manual/game_development/basic_rendering/#rectangles","title":"Rectangles","text":"

Draw a rectangle outline:

renderer.drawRectangle(50, 50, 100, 80, pixelroot32::graphics::Color::Blue);\n

Draw a filled rectangle:

renderer.drawFilledRectangle(50, 50, 100, 80, pixelroot32::graphics::Color::Blue);\n
"},{"location":"manual/game_development/basic_rendering/#circles","title":"Circles","text":"

Draw a circle outline:

renderer.drawCircle(120, 120, 30, pixelroot32::graphics::Color::Green);\n

Draw a filled circle:

renderer.drawFilledCircle(120, 120, 30, pixelroot32::graphics::Color::Green);\n
"},{"location":"manual/game_development/basic_rendering/#simple-sprites-1bpp","title":"Simple Sprites (1bpp)","text":"

Sprites are the primary way to draw game graphics. The standard format is 1bpp (1 bit per pixel), which is memory-efficient and perfect for retro-style graphics.

"},{"location":"manual/game_development/basic_rendering/#creating-a-sprite-manually","title":"Creating a Sprite Manually","text":"

A 1bpp sprite is defined as an array of uint16_t, where each value represents one row:

#include <graphics/Renderer.h>\n\n// Example: 8x8 sprite (8 rows, each row is a uint16_t)\n// Bit 0 = leftmost pixel, bit 7 = rightmost pixel\nstatic const uint16_t MY_SPRITE_DATA[] = {\n    0b00111100,  // Row 0:   ..####..\n    0b01111110,  // Row 1:  .######.\n    0b11111111,  // Row 2:  ########\n    0b11111111,  // Row 3:  ########\n    0b11111111,  // Row 4:  ########\n    0b01111110,  // Row 5:  .######.\n    0b00111100,  // Row 6:   ..####..\n    0b00000000   // Row 7:  ........\n};\n\n// Create sprite descriptor\nstatic const pixelroot32::graphics::Sprite MY_SPRITE = {\n    MY_SPRITE_DATA,  // data pointer\n    8,                // width\n    8                 // height\n};\n
"},{"location":"manual/game_development/basic_rendering/#drawing-a-sprite","title":"Drawing a Sprite","text":"
renderer.drawSprite(\n    MY_SPRITE,                                    // sprite\n    100,                                          // x position\n    100,                                          // y position\n    pixelroot32::graphics::Color::White,         // color\n    false                                         // flipX (optional, default false)\n);\n
"},{"location":"manual/game_development/basic_rendering/#sprite-bit-convention","title":"Sprite Bit Convention","text":"
  • Each uint16_t represents one row
  • Bit 0 (rightmost bit) = leftmost pixel
  • Bit (width - 1) = rightmost pixel
  • 0 = transparent/off, 1 = on (colored)

Example: For an 8-pixel wide sprite:

Row value: 0b00111100\nPixels:    ..####..\n           ^      ^\n         bit 7  bit 0 (leftmost)\n

"},{"location":"manual/game_development/basic_rendering/#flipping-sprites","title":"Flipping Sprites","text":"

You can flip a sprite horizontally:

renderer.drawSprite(MY_SPRITE, 100, 100, Color::White, true); // flipped\n
"},{"location":"manual/game_development/basic_rendering/#text-rendering","title":"Text Rendering","text":"

PixelRoot32 uses a native bitmap font system for pixel-perfect text rendering.

"},{"location":"manual/game_development/basic_rendering/#drawing-text","title":"Drawing Text","text":"
renderer.drawText(\n    \"Hello World!\",                           // text string\n    10,                                       // x position\n    20,                                       // y position\n    pixelroot32::graphics::Color::White,     // color\n    1                                         // size multiplier (1=normal, 2=double, etc.)\n);\n
"},{"location":"manual/game_development/basic_rendering/#centered-text","title":"Centered Text","text":"
renderer.drawTextCentered(\n    \"Game Over\",                              // text\n    120,                                      // y position (centered horizontally)\n    pixelroot32::graphics::Color::Red,       // color\n    2                                         // size\n);\n
"},{"location":"manual/game_development/basic_rendering/#text-size","title":"Text Size","text":"

The size parameter multiplies the font size: - 1 = normal size (5x7 pixels per character with default font) - 2 = double size (10x14 pixels) - 3 = triple size (15x21 pixels) - etc.

"},{"location":"manual/game_development/basic_rendering/#supported-characters","title":"Supported Characters","text":"

The default font (FONT_5X7) supports ASCII characters 32-126: - Letters: A-Z, a-z - Numbers: 0-9 - Symbols: !@#$%^&*()_+-=[]{}|;:'\",.<>?/ etc.

"},{"location":"manual/game_development/basic_rendering/#render-layers","title":"Render Layers","text":"

Entities are drawn in order based on their renderLayer property:

  • Layer 0 (Background): Drawn first (behind everything)
  • Layer 1 (Gameplay): Drawn second (main game objects)
  • Layer 2 (UI): Drawn last (on top of everything)

Set the render layer when creating an entity:

myEntity->setRenderLayer(0); // Background\nmyEntity->setRenderLayer(1); // Gameplay (default)\nmyEntity->setRenderLayer(2); // UI\n
"},{"location":"manual/game_development/basic_rendering/#complete-example","title":"Complete Example","text":"

Here's a complete example that draws various primitives and a sprite:

#include <core/Scene.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\n// Simple sprite data (8x8 circle)\nstatic const uint16_t CIRCLE_SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b01111110,\n    0b00111100\n};\n\nstatic const pixelroot32::graphics::Sprite CIRCLE_SPRITE = {\n    CIRCLE_SPRITE_DATA,\n    8,\n    8\n};\n\nclass RenderingExampleScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Set palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::NES\n        );\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background (layer 0)\n        renderer.drawFilledRectangle(0, 0, 240, 240, \n            pixelroot32::graphics::Color::Navy);\n\n        // Draw primitives (layer 1)\n        renderer.drawRectangle(10, 10, 100, 80, \n            pixelroot32::graphics::Color::White);\n        renderer.drawFilledCircle(120, 120, 30, \n            pixelroot32::graphics::Color::Red);\n        renderer.drawLine(0, 0, 240, 240, \n            pixelroot32::graphics::Color::Yellow);\n\n        // Draw sprite\n        renderer.drawSprite(CIRCLE_SPRITE, 50, 50, \n            pixelroot32::graphics::Color::Cyan);\n\n        // Draw text (layer 2 - UI)\n        renderer.drawText(\"Score: 100\", 10, 10, \n            pixelroot32::graphics::Color::White, 1);\n        renderer.drawTextCentered(\"Rendering Demo\", 200, \n            pixelroot32::graphics::Color::Yellow, 2);\n\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/basic_rendering/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/basic_rendering/#performance","title":"Performance","text":"
  • Minimize draw calls: Batch similar operations when possible
  • Use render layers efficiently: Don't mix layers unnecessarily
  • Avoid drawing off-screen: Check bounds before drawing
  • Reuse sprites: Define sprites once, use many times
"},{"location":"manual/game_development/basic_rendering/#organization","title":"Organization","text":"
  • Define sprites as static const: Keep them in flash memory
  • Use meaningful names: Name your sprites clearly
  • Group related sprites: Organize sprite data logically
  • Document complex sprites: Comment sprite bit patterns if needed
"},{"location":"manual/game_development/basic_rendering/#text","title":"Text","text":"
  • Avoid frequent text updates: Text rendering has overhead
  • Use appropriate sizes: Larger text uses more memory
  • Cache text dimensions: Use FontManager::textWidth() if needed
  • Keep text simple: Complex formatting is not supported
"},{"location":"manual/game_development/basic_rendering/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/basic_rendering/#drawing-a-background","title":"Drawing a Background","text":"
void drawBackground(Renderer& renderer) {\n    // Solid color background\n    renderer.drawFilledRectangle(0, 0, 240, 240, Color::Black);\n\n    // Or use a tilemap (see Advanced Graphics section)\n}\n
"},{"location":"manual/game_development/basic_rendering/#drawing-a-hud","title":"Drawing a HUD","text":"
void drawHUD(Renderer& renderer, int score, int lives) {\n    char buffer[32];\n    snprintf(buffer, sizeof(buffer), \"Score: %d\", score);\n    renderer.drawText(buffer, 10, 10, Color::White, 1);\n\n    snprintf(buffer, sizeof(buffer), \"Lives: %d\", lives);\n    renderer.drawText(buffer, 10, 20, Color::White, 1);\n}\n
"},{"location":"manual/game_development/basic_rendering/#drawing-multiple-sprites","title":"Drawing Multiple Sprites","text":"
void drawSpriteArray(Renderer& renderer, const Sprite& sprite, \n                     int count, int startX, int startY, int spacing) {\n    for (int i = 0; i < count; i++) {\n        int x = startX + (i * (sprite.width + spacing));\n        renderer.drawSprite(sprite, x, startY, Color::White);\n    }\n}\n
"},{"location":"manual/game_development/basic_rendering/#next-steps","title":"Next Steps","text":"

Now that you can draw basic graphics, learn about: - Sprites and Animation - Advanced sprite techniques - Input and Control - Make your game interactive - Palettes - Use different color schemes

See also: - API Reference - Renderer - API Reference - Sprite - Render Layers

"},{"location":"manual/game_development/input_and_control/","title":"Input and Control","text":"

Handling user input is essential for any interactive game. This guide covers how to read and process input from buttons (ESP32) or keyboard (Native) in PixelRoot32.

"},{"location":"manual/game_development/input_and_control/#input-configuration","title":"Input Configuration","text":"

Before you can read input, you need to configure the InputManager. This is done when creating the Engine:

"},{"location":"manual/game_development/input_and_control/#esp32-configuration","title":"ESP32 Configuration","text":"
#include <input/InputConfig.h>\n\n// InputConfig(buttonCount, UP, DOWN, LEFT, RIGHT, A, B)\npr32::input::InputConfig inputConfig(\n    6,      // Total number of buttons\n    32,     // UP button GPIO pin\n    27,     // DOWN button GPIO pin\n    33,     // LEFT button GPIO pin\n    14,     // RIGHT button GPIO pin\n    13,     // A button GPIO pin\n    12      // B button GPIO pin\n);\n
"},{"location":"manual/game_development/input_and_control/#native-pc-configuration","title":"Native (PC) Configuration","text":"
#include <SDL2/SDL.h>\n#include <input/InputConfig.h>\n\n// InputConfig(buttonCount, UP, DOWN, LEFT, RIGHT, A, B)\npr32::input::InputConfig inputConfig(\n    6,                      // Total number of buttons\n    SDL_SCANCODE_UP,        // UP key\n    SDL_SCANCODE_DOWN,      // DOWN key\n    SDL_SCANCODE_LEFT,      // LEFT key\n    SDL_SCANCODE_RIGHT,     // RIGHT key\n    SDL_SCANCODE_SPACE,     // A button (Space)\n    SDL_SCANCODE_RETURN     // B button (Enter)\n);\n
"},{"location":"manual/game_development/input_and_control/#reading-input","title":"Reading Input","text":"

Access the InputManager through the Engine:

auto& input = engine.getInputManager();\n
"},{"location":"manual/game_development/input_and_control/#input-states","title":"Input States","text":"

The InputManager provides four different ways to check button state:

"},{"location":"manual/game_development/input_and_control/#1-isbuttonpressed","title":"1. isButtonPressed()","text":"

Returns true only on the frame when the button was just pressed:

if (input.isButtonPressed(4)) { // Button A (index 4)\n    // This code runs only once when button is first pressed\n    jump();\n}\n

Use for: Actions that should trigger once per press (jump, shoot, select menu item).

"},{"location":"manual/game_development/input_and_control/#2-isbuttonreleased","title":"2. isButtonReleased()","text":"

Returns true only on the frame when the button was just released:

if (input.isButtonReleased(4)) {\n    // This code runs only once when button is released\n    stopCharging();\n}\n

Use for: Actions that trigger on release (charge attacks, menu confirmation).

"},{"location":"manual/game_development/input_and_control/#3-isbuttondown","title":"3. isButtonDown()","text":"

Returns true while the button is currently held down:

if (input.isButtonDown(2)) { // LEFT button (index 2)\n    // This code runs every frame while button is held\n    playerX -= speed * (deltaTime * 0.001f);\n}\n

Use for: Continuous actions (movement, holding, charging).

"},{"location":"manual/game_development/input_and_control/#4-isbuttonclicked","title":"4. isButtonClicked()","text":"

Returns true when the button was pressed and then released:

if (input.isButtonClicked(4)) {\n    // This code runs once per click (press + release cycle)\n    toggleMenu();\n}\n

Use for: Toggle actions, menu selections, click interactions.

"},{"location":"manual/game_development/input_and_control/#button-indices","title":"Button Indices","text":"

The button indices correspond to the order in InputConfig:

  • Index 0: UP
  • Index 1: DOWN
  • Index 2: LEFT
  • Index 3: RIGHT
  • Index 4: A button
  • Index 5: B button

For convenience, you can define constants:

namespace Buttons {\n    constexpr uint8_t UP = 0;\n    constexpr uint8_t DOWN = 1;\n    constexpr uint8_t LEFT = 2;\n    constexpr uint8_t RIGHT = 3;\n    constexpr uint8_t A = 4;\n    constexpr uint8_t B = 5;\n}\n\n// Usage\nif (input.isButtonPressed(Buttons::A)) {\n    // ...\n}\n
"},{"location":"manual/game_development/input_and_control/#character-control-example","title":"Character Control Example","text":"

Here's a complete example of character movement:

#include <core/Actor.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass PlayerActor : public pixelroot32::core::Actor {\npublic:\n    float speed = 100.0f; // pixels per second\n\n    PlayerActor(float x, float y)\n        : Actor(x, y, 16, 16) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f; // Convert to seconds\n\n        // Horizontal movement\n        if (input.isButtonDown(Buttons::LEFT)) {\n            x -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::RIGHT)) {\n            x += speed * dt;\n        }\n\n        // Vertical movement\n        if (input.isButtonDown(Buttons::UP)) {\n            y -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::DOWN)) {\n            y += speed * dt;\n        }\n\n        // Keep player on screen\n        if (x < 0) x = 0;\n        if (x > 224) x = 224;\n        if (y < 0) y = 0;\n        if (y > 224) y = 224;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width,\n            height,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collisions\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#jumping-example","title":"Jumping Example","text":"

For platformer-style jumping:

class PlatformerPlayer : public pixelroot32::core::PhysicsActor {\npublic:\n    bool canJump = true;\n    float jumpForce = 200.0f;\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        // Horizontal movement\n        float moveSpeed = 80.0f;\n        if (input.isButtonDown(Buttons::LEFT)) {\n            setVelocity(-moveSpeed, vy);\n        } else if (input.isButtonDown(Buttons::RIGHT)) {\n            setVelocity(moveSpeed, vy);\n        } else {\n            setVelocity(0, vy);\n        }\n\n        // Jump (only on press, and only if on ground)\n        if (input.isButtonPressed(Buttons::A) && canJump) {\n            setVelocity(vx, -jumpForce);\n            canJump = false;\n        }\n\n        // Check if on ground (for jump reset)\n        auto collisionInfo = getWorldCollisionInfo();\n        if (collisionInfo.bottom) {\n            canJump = true;\n        }\n\n        PhysicsActor::update(deltaTime);\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#shooting-example","title":"Shooting Example","text":"

For shooting projectiles:

class ShooterActor : public pixelroot32::core::Actor {\nprivate:\n    bool fireInputReady = true;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n\n        // Shooting (with cooldown)\n        if (input.isButtonPressed(Buttons::A) && fireInputReady) {\n            shoot();\n            fireInputReady = false;\n        }\n\n        // Reset fire input when button is released\n        if (input.isButtonReleased(Buttons::A)) {\n            fireInputReady = true;\n        }\n    }\n\n    void shoot() {\n        // Create projectile\n        // ...\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#menu-navigation-example","title":"Menu Navigation Example","text":"

For menu navigation:

class MenuScene : public pixelroot32::core::Scene {\nprivate:\n    int selectedIndex = 0;\n    static const int MENU_ITEMS = 3;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n\n        // Navigate menu\n        if (input.isButtonPressed(Buttons::UP)) {\n            selectedIndex--;\n            if (selectedIndex < 0) selectedIndex = MENU_ITEMS - 1;\n        }\n\n        if (input.isButtonPressed(Buttons::DOWN)) {\n            selectedIndex++;\n            if (selectedIndex >= MENU_ITEMS) selectedIndex = 0;\n        }\n\n        // Select menu item\n        if (input.isButtonPressed(Buttons::A)) {\n            selectMenuItem(selectedIndex);\n        }\n\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/input_and_control/#frame-rate-independence","title":"Frame-Rate Independence","text":"

Always multiply movement by delta time:

// \u2705 GOOD: Framerate-independent\nx += speed * (deltaTime * 0.001f);\n\n// \u274c BAD: Framerate-dependent\nx += speed;\n
"},{"location":"manual/game_development/input_and_control/#input-debouncing","title":"Input Debouncing","text":"

For actions that should only trigger once:

// Use isButtonPressed() instead of isButtonDown()\nif (input.isButtonPressed(Buttons::A)) {\n    // Triggers once per press\n}\n
"},{"location":"manual/game_development/input_and_control/#input-buffering","title":"Input Buffering","text":"

For responsive controls, you can buffer input:

class InputBuffer {\n    uint8_t bufferedInput = 0;\n\npublic:\n    void update(const InputManager& input) {\n        if (input.isButtonPressed(Buttons::A)) {\n            bufferedInput = Buttons::A;\n        }\n    }\n\n    bool hasBufferedInput() const { return bufferedInput != 0; }\n    uint8_t consumeInput() {\n        uint8_t result = bufferedInput;\n        bufferedInput = 0;\n        return result;\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#multiple-input-methods","title":"Multiple Input Methods","text":"

Support both button presses and held buttons:

// Allow both tap and hold for rapid fire\nif (input.isButtonPressed(Buttons::A) || \n    (input.isButtonDown(Buttons::A) && rapidFireTimer <= 0)) {\n    shoot();\n    rapidFireTimer = RAPID_FIRE_DELAY;\n}\n
"},{"location":"manual/game_development/input_and_control/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/input_and_control/#directional-input","title":"Directional Input","text":"
float getHorizontalInput() {\n    auto& input = engine.getInputManager();\n    float dir = 0.0f;\n    if (input.isButtonDown(Buttons::LEFT)) dir -= 1.0f;\n    if (input.isButtonDown(Buttons::RIGHT)) dir += 1.0f;\n    return dir;\n}\n\nfloat getVerticalInput() {\n    auto& input = engine.getInputManager();\n    float dir = 0.0f;\n    if (input.isButtonDown(Buttons::UP)) dir -= 1.0f;\n    if (input.isButtonDown(Buttons::DOWN)) dir += 1.0f;\n    return dir;\n}\n
"},{"location":"manual/game_development/input_and_control/#input-state-machine","title":"Input State Machine","text":"

For complex input handling:

enum class InputState {\n    IDLE,\n    PRESSED,\n    HELD,\n    RELEASED\n};\n\nInputState getButtonState(const InputManager& input, uint8_t button) {\n    if (input.isButtonPressed(button)) return InputState::PRESSED;\n    if (input.isButtonDown(button)) return InputState::HELD;\n    if (input.isButtonReleased(button)) return InputState::RELEASED;\n    return InputState::IDLE;\n}\n
"},{"location":"manual/game_development/input_and_control/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/game_development/input_and_control/#button-not-responding","title":"Button Not Responding","text":"
  • Check button indices match your InputConfig
  • Verify GPIO pins (ESP32) or scancodes (Native) are correct
  • Ensure InputManager is being updated (happens automatically in Engine)
"},{"location":"manual/game_development/input_and_control/#input-feels-laggy","title":"Input Feels Laggy","text":"
  • Ensure you're using deltaTime for movement
  • Check that input is read in update(), not draw()
  • Verify framerate is stable
"},{"location":"manual/game_development/input_and_control/#multiple-triggers","title":"Multiple Triggers","text":"
  • Use isButtonPressed() instead of isButtonDown() for one-time actions
  • Implement input buffering or cooldown timers
"},{"location":"manual/game_development/input_and_control/#next-steps","title":"Next Steps","text":"

Now that you can handle input, learn about: - Audio - Add sound effects and music - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs

See also: - API Reference - InputManager - API Reference - InputConfig - Manual - Input Overview

"},{"location":"manual/game_development/physics_and_collisions/","title":"Physics and Collisions","text":"

PixelRoot32 provides a physics system for moving objects and collision detection. This guide covers PhysicsActor for automatic physics and the collision system for detecting interactions between objects.

"},{"location":"manual/game_development/physics_and_collisions/#physicsactor","title":"PhysicsActor","text":"

A PhysicsActor is an Actor that automatically handles physics: velocity, gravity, friction, and world boundary collisions.

"},{"location":"manual/game_development/physics_and_collisions/#creating-a-physicsactor","title":"Creating a PhysicsActor","text":"
#include <core/PhysicsActor.h>\n\nclass Ball : public pixelroot32::core::PhysicsActor {\npublic:\n    Ball(float x, float y, float radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRenderLayer(1);\n\n        // Set physics properties\n        setRestitution(0.8f);  // Bounciness (0.8 = 80% bounce)\n        setFriction(0.1f);     // Friction (0.1 = slight friction)\n\n        // Set world boundaries\n        setWorldSize(240, 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Apply gravity\n        // (PhysicsActor handles this automatically, but you can add custom forces)\n\n        // Call parent update to apply physics\n        PhysicsActor::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        int radius = width / 2;\n        renderer.drawFilledCircle(\n            static_cast<int>(x + radius),\n            static_cast<int>(y + radius),\n            radius,\n            pixelroot32::graphics::Color::White\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collision with other actors\n    }\n\n    void onWorldCollision() override {\n        // Called when hitting world boundaries\n        // You can play a sound effect here, for example\n    }\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#physics-properties","title":"Physics Properties","text":""},{"location":"manual/game_development/physics_and_collisions/#velocity","title":"Velocity","text":"

Set the velocity directly:

ball->setVelocity(100.0f, -50.0f); // Move right at 100 px/s, up at 50 px/s\n

Or modify existing velocity:

float vx = ball->vx; // Access velocity components (protected, use getter if needed)\nball->setVelocity(vx + 10.0f, ball->vy); // Accelerate horizontally\n
"},{"location":"manual/game_development/physics_and_collisions/#restitution-bounciness","title":"Restitution (Bounciness)","text":"

Controls how much energy is conserved in collisions:

ball->setRestitution(1.0f);  // Perfect bounce (no energy loss)\nball->setRestitution(0.5f);  // 50% energy loss\nball->setRestitution(0.0f);  // No bounce (stops on impact)\n
"},{"location":"manual/game_development/physics_and_collisions/#friction","title":"Friction","text":"

Applies gradual velocity reduction:

ball->setFriction(0.0f);  // No friction (slides forever)\nball->setFriction(0.5f);  // Moderate friction\nball->setFriction(1.0f);  // High friction (stops quickly)\n
"},{"location":"manual/game_development/physics_and_collisions/#world-boundaries","title":"World Boundaries","text":"

Set the playable area:

// Set world size (used as default boundaries)\nball->setWorldSize(240, 240);\n\n// Or set custom boundaries\npixelroot32::core::LimitRect limits(10, 10, 230, 230); // Left, Top, Right, Bottom\nball->setLimits(limits);\n
"},{"location":"manual/game_development/physics_and_collisions/#world-collision-detection","title":"World Collision Detection","text":"

Check if the actor hit world boundaries:

void update(unsigned long deltaTime) override {\n    PhysicsActor::update(deltaTime);\n\n    auto collisionInfo = getWorldCollisionInfo();\n\n    if (collisionInfo.left || collisionInfo.right) {\n        // Hit side walls\n    }\n\n    if (collisionInfo.top || collisionInfo.bottom) {\n        // Hit top/bottom walls\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#collision-system","title":"Collision System","text":"

The collision system detects when Actors overlap and triggers callbacks.

"},{"location":"manual/game_development/physics_and_collisions/#collision-layers","title":"Collision Layers","text":"

Use bit flags to organize actors into groups:

// Define layers (typically in GameLayers.h)\nnamespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;    // Bit 0\n    constexpr uint16_t ENEMY = 0x0002;     // Bit 1\n    constexpr uint16_t PROJECTILE = 0x0004; // Bit 2\n    constexpr uint16_t WALL = 0x0008;      // Bit 3\n    constexpr uint16_t PICKUP = 0x0010;    // Bit 4\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#setting-up-collisions","title":"Setting Up Collisions","text":"

Configure each actor's collision layer and mask:

class PlayerActor : public pixelroot32::core::Actor {\npublic:\n    PlayerActor(float x, float y)\n        : Actor(x, y, 16, 16) {\n        // This actor belongs to the PLAYER layer\n        setCollisionLayer(Layers::PLAYER);\n\n        // This actor can collide with ENEMY, WALL, and PICKUP\n        setCollisionMask(Layers::ENEMY | Layers::WALL | Layers::PICKUP);\n    }\n\n    // ... rest of implementation\n};\n\nclass EnemyActor : public pixelroot32::core::Actor {\npublic:\n    EnemyActor(float x, float y)\n        : Actor(x, y, 16, 16) {\n        // This actor belongs to the ENEMY layer\n        setCollisionLayer(Layers::ENEMY);\n\n        // This actor can collide with PLAYER and PROJECTILE\n        setCollisionMask(Layers::PLAYER | Layers::PROJECTILE);\n    }\n\n    // ... rest of implementation\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#collision-detection","title":"Collision Detection","text":"

Collisions are automatically detected by the Scene's CollisionSystem. You handle collisions in onCollision():

void PlayerActor::onCollision(pixelroot32::core::Actor* other) override {\n    // Check what we collided with\n    if (other->isInLayer(Layers::ENEMY)) {\n        // Hit an enemy - take damage\n        takeDamage();\n    } else if (other->isInLayer(Layers::PICKUP)) {\n        // Hit a pickup - collect it\n        collectPickup(other);\n    } else if (other->isInLayer(Layers::WALL)) {\n        // Hit a wall - stop movement\n        stopMovement();\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#hitbox","title":"Hitbox","text":"

Define the collision shape:

pixelroot32::core::Rect getHitBox() override {\n    // Simple AABB (Axis-Aligned Bounding Box)\n    return {x, y, width, height};\n\n    // Or use a smaller hitbox for more forgiving collisions\n    // return {x + 2, y + 2, width - 4, height - 4};\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#complete-example-bouncing-ball","title":"Complete Example: Bouncing Ball","text":"
#include <core/PhysicsActor.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass BouncingBall : public pixelroot32::core::PhysicsActor {\npublic:\n    BouncingBall(float x, float y, float radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRenderLayer(1);\n\n        // Physics setup\n        setRestitution(0.9f);  // Very bouncy\n        setFriction(0.05f);    // Low friction\n        setWorldSize(240, 240); // World boundaries\n\n        // Initial velocity\n        setVelocity(50.0f, -30.0f);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Apply gravity\n        float gravity = 200.0f; // pixels per second squared\n        float dt = deltaTime * 0.001f;\n        setVelocity(vx, vy + gravity * dt);\n\n        // Update physics\n        PhysicsActor::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        int radius = width / 2;\n        renderer.drawFilledCircle(\n            static_cast<int>(x + radius),\n            static_cast<int>(y + radius),\n            radius,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Bounce off other objects\n        // (PhysicsActor handles world boundaries automatically)\n    }\n\n    void onWorldCollision() override {\n        // Play bounce sound when hitting walls\n        // (Implementation depends on your audio setup)\n    }\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#complete-example-platformer-player","title":"Complete Example: Platformer Player","text":"
class PlatformerPlayer : public pixelroot32::core::PhysicsActor {\nprivate:\n    bool onGround = false;\n    float jumpForce = 250.0f;\n    float moveSpeed = 100.0f;\n\npublic:\n    PlatformerPlayer(float x, float y)\n        : PhysicsActor(x, y, 16, 16) {\n        setRenderLayer(1);\n        setFriction(0.3f);  // Ground friction\n        setWorldSize(240, 240);\n\n        // Collision setup\n        setCollisionLayer(Layers::PLAYER);\n        setCollisionMask(Layers::ENEMY | Layers::PLATFORM);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        // Horizontal movement\n        float moveDir = 0.0f;\n        if (input.isButtonDown(Buttons::LEFT)) moveDir -= 1.0f;\n        if (input.isButtonDown(Buttons::RIGHT)) moveDir += 1.0f;\n\n        setVelocity(moveDir * moveSpeed, vy);\n\n        // Apply gravity\n        float gravity = 300.0f;\n        setVelocity(vx, vy + gravity * dt);\n\n        // Jump\n        if (input.isButtonPressed(Buttons::A) && onGround) {\n            setVelocity(vx, -jumpForce);\n            onGround = false;\n        }\n\n        // Update physics\n        PhysicsActor::update(deltaTime);\n\n        // Check if on ground\n        auto collisionInfo = getWorldCollisionInfo();\n        onGround = collisionInfo.bottom;\n\n        // Also check collision with platforms\n        // (This would be handled in onCollision)\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        if (other->isInLayer(Layers::PLATFORM)) {\n            // Land on platform\n            auto platformRect = other->getHitBox();\n            if (y + height <= platformRect.y + 5) { // Within 5 pixels of top\n                y = platformRect.y - height;\n                vy = 0;\n                onGround = true;\n            }\n        } else if (other->isInLayer(Layers::ENEMY)) {\n            // Hit enemy\n            takeDamage();\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width,\n            height,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#sweep-tests","title":"Sweep Tests","text":"

For fast-moving projectiles, use sweep tests to detect collisions between positions:

#include <physics/CollisionPrimitives.h>\n\nbool checkProjectileHit(PhysicsActor* projectile, Actor* target) {\n    // Get previous and current positions\n    float prevX = projectile->x - (projectile->vx * deltaTime * 0.001f);\n    float prevY = projectile->y - (projectile->vy * deltaTime * 0.001f);\n\n    // Create circles for sweep test\n    pixelroot32::physics::Circle startCircle;\n    startCircle.x = prevX + projectile->width / 2;\n    startCircle.y = prevY + projectile->height / 2;\n    startCircle.radius = projectile->width / 2;\n\n    pixelroot32::physics::Circle endCircle;\n    endCircle.x = projectile->x + projectile->width / 2;\n    endCircle.y = projectile->y + projectile->height / 2;\n    endCircle.radius = projectile->width / 2;\n\n    // Get target rectangle\n    auto targetRect = target->getHitBox();\n\n    // Perform sweep test\n    float tHit;\n    if (pixelroot32::physics::sweepCircleVsRect(\n        startCircle, endCircle, targetRect, tHit)) {\n        // Collision detected at time tHit (0.0 = at start, 1.0 = at end)\n        return true;\n    }\n\n    return false;\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/physics_and_collisions/#collision-layers_1","title":"Collision Layers","text":"
  • Plan your layers: Design the layer system before coding
  • Use bit flags: Makes combining layers easy with | operator
  • Keep it simple: Don't create too many layers
  • Document layers: Create a GameLayers.h file with all definitions
"},{"location":"manual/game_development/physics_and_collisions/#physics","title":"Physics","text":"
  • Use appropriate values: Test gravity, speed, and forces
  • Frame-rate independence: Always use deltaTime
  • Limit world size: Keep boundaries reasonable
  • Test on hardware: Physics may behave differently on ESP32 vs PC
"},{"location":"manual/game_development/physics_and_collisions/#performance","title":"Performance","text":"
  • Limit active actors: Fewer actors = faster collision checks
  • Use layers efficiently: Reduce unnecessary collision pairs
  • Simple hitboxes: AABB is fast, complex shapes are slow
  • Sweep tests sparingly: Only for fast-moving objects
"},{"location":"manual/game_development/physics_and_collisions/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/physics_and_collisions/#collision-layer-helper","title":"Collision Layer Helper","text":"
namespace CollisionLayers {\n    constexpr uint16_t PLAYER = 0x0001;\n    constexpr uint16_t ENEMY = 0x0002;\n    constexpr uint16_t PROJECTILE = 0x0004;\n    constexpr uint16_t WALL = 0x0008;\n    constexpr uint16_t PICKUP = 0x0010;\n\n    // Helper to check if actor is in specific layer\n    bool isPlayer(Actor* actor) {\n        return actor->isInLayer(PLAYER);\n    }\n\n    bool isEnemy(Actor* actor) {\n        return actor->isInLayer(ENEMY);\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#platform-collision","title":"Platform Collision","text":"
void PlatformerPlayer::onCollision(Actor* other) override {\n    if (other->isInLayer(Layers::PLATFORM)) {\n        auto platform = other->getHitBox();\n\n        // Check if landing on top of platform\n        float playerBottom = y + height;\n        float platformTop = platform.y;\n\n        if (playerBottom <= platformTop + 5 && vy > 0) {\n            // Land on platform\n            y = platformTop - height;\n            vy = 0;\n            onGround = true;\n        }\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/game_development/physics_and_collisions/#collisions-not-detected","title":"Collisions Not Detected","text":"
  • Verify collision layers and masks overlap
  • Check that actors are added to the scene
  • Ensure Scene::update() is called
  • Verify hitboxes are correct
"},{"location":"manual/game_development/physics_and_collisions/#physics-too-fastslow","title":"Physics Too Fast/Slow","text":"
  • Adjust values based on deltaTime
  • Check gravity and velocity values
  • Test on actual hardware (ESP32 may run slower)
"},{"location":"manual/game_development/physics_and_collisions/#objects-passing-through","title":"Objects Passing Through","text":"
  • Use sweep tests for fast objects
  • Increase collision detection frequency
  • Check hitbox sizes match visual size
"},{"location":"manual/game_development/physics_and_collisions/#next-steps","title":"Next Steps","text":"

Now that you understand physics and collisions, learn about: - User Interface - Create menus and HUDs - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels

See also: - API Reference - PhysicsActor - API Reference - CollisionSystem - Manual - Physics Overview - Manual - Collision Detection

"},{"location":"manual/game_development/scenes_and_entities/","title":"Scenes and Entities","text":"

Scenes and entities are the foundation of every PixelRoot32 game. This guide teaches you how to organize your game using scenes and create interactive game objects with entities.

"},{"location":"manual/game_development/scenes_and_entities/#creating-a-scene","title":"Creating a Scene","text":"

A Scene represents a screen or level in your game. To create a scene, inherit from pixelroot32::core::Scene and implement the three main methods:

#include <core/Scene.h>\n#include <graphics/Renderer.h>\n\nclass MyGameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Called once when the scene is initialized\n        // Set up your scene here: create entities, load resources, etc.\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Called every frame\n        // Update game logic here\n\n        // IMPORTANT: Always call parent update to update all entities\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Called every frame to draw\n        // Draw your scene here\n\n        // IMPORTANT: Always call parent draw to draw all entities\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#scene-lifecycle","title":"Scene Lifecycle","text":"
  1. init(): Called once when the scene is set as active
  2. Create and initialize entities
  3. Set up game state
  4. Load resources
  5. Configure palettes, audio, etc.

  6. update(deltaTime): Called every frame

  7. Process input
  8. Update game logic
  9. Handle collisions
  10. Must call Scene::update(deltaTime) to update all entities

  11. draw(renderer): Called every frame

  12. Draw background elements
  13. Draw UI elements
  14. Must call Scene::draw(renderer) to draw all entities
"},{"location":"manual/game_development/scenes_and_entities/#basic-entities","title":"Basic Entities","text":"

An Entity is any object in your game. To create an entity, inherit from pixelroot32::core::Entity:

#include <core/Entity.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass SimpleEntity : public pixelroot32::core::Entity {\npublic:\n    SimpleEntity(float x, float y)\n        : Entity(x, y, 16, 16, pixelroot32::core::EntityType::GENERIC) {\n        // Set render layer (0=background, 1=gameplay, 2=UI)\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update entity logic\n        // For example, move the entity\n        this->x += 1.0f * (deltaTime * 0.001f); // Move right at 1 pixel per second\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw the entity\n        renderer.drawFilledRectangle(\n            static_cast<int>(x), \n            static_cast<int>(y), \n            width, \n            height, \n            pixelroot32::graphics::Color::Red\n        );\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#entity-properties","title":"Entity Properties","text":"

Every entity has these properties:

  • x, y: Position in world space (float)
  • width, height: Dimensions (int)
  • isVisible: If false, draw() is not called
  • isEnabled: If false, update() is not called
  • renderLayer: Which layer to draw on (0, 1, or 2)
"},{"location":"manual/game_development/scenes_and_entities/#adding-entities-to-a-scene","title":"Adding Entities to a Scene","text":"

Add entities to your scene in init():

void MyGameScene::init() override {\n    // Create entities\n    SimpleEntity* entity1 = new SimpleEntity(50, 50);\n    SimpleEntity* entity2 = new SimpleEntity(100, 100);\n\n    // Add them to the scene\n    addEntity(entity1);\n    addEntity(entity2);\n}\n

The scene automatically manages these entities: - Calls update() on all enabled entities each frame - Calls draw() on all visible entities each frame - Handles cleanup when the scene is destroyed

"},{"location":"manual/game_development/scenes_and_entities/#actors-entities-with-collisions","title":"Actors: Entities with Collisions","text":"

An Actor is an entity that can participate in collision detection. Inherit from pixelroot32::core::Actor:

#include <core/Actor.h>\n#include <physics/CollisionTypes.h>\n\nclass MyActor : public pixelroot32::core::Actor {\npublic:\n    MyActor(float x, float y, int w, int h)\n        : Actor(x, y, w, h) {\n        // Set collision layer (what group this actor belongs to)\n        setCollisionLayer(0x0001); // Example: layer 1\n\n        // Set collision mask (what groups this actor can collide with)\n        setCollisionMask(0x0002); // Example: can collide with layer 2\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update actor logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw the actor\n    }\n\n    // REQUIRED: Define the hitbox for collision detection\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    // REQUIRED: Handle collisions\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // React to collision\n        // For example: take damage, destroy self, etc.\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#collision-layers-and-masks","title":"Collision Layers and Masks","text":"

Collision layers use bit flags to organize actors into groups:

// Define your layers (typically in a GameLayers.h file)\nnamespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;  // Bit 0\n    constexpr uint16_t ENEMY = 0x0002;  // Bit 1\n    constexpr uint16_t PROJECTILE = 0x0004; // Bit 2\n    constexpr uint16_t WALL = 0x0008;   // Bit 3\n}\n\n// Set up a player actor\nplayer->setCollisionLayer(Layers::PLAYER);\nplayer->setCollisionMask(Layers::ENEMY | Layers::WALL); // Can collide with enemies and walls\n\n// Set up an enemy actor\nenemy->setCollisionLayer(Layers::ENEMY);\nenemy->setCollisionMask(Layers::PLAYER | Layers::PROJECTILE); // Can collide with player and projectiles\n

The collision system only checks collisions between actors whose layers and masks overlap. This is much more efficient than checking every pair.

"},{"location":"manual/game_development/scenes_and_entities/#scene-management","title":"Scene Management","text":""},{"location":"manual/game_development/scenes_and_entities/#setting-the-active-scene","title":"Setting the Active Scene","text":"

From your main code, set the active scene:

MyGameScene gameScene;\n\nvoid setup() {\n    engine.init();\n    gameScene.init();\n    engine.setScene(&gameScene); // Set as active scene\n}\n
"},{"location":"manual/game_development/scenes_and_entities/#switching-scenes","title":"Switching Scenes","text":"

To switch to a different scene:

MenuScene menuScene;\nGameScene gameScene;\n\nvoid switchToGame() {\n    gameScene.init();\n    engine.setScene(&gameScene); // Replaces current scene\n}\n
"},{"location":"manual/game_development/scenes_and_entities/#scene-stack-pushpop","title":"Scene Stack (Push/Pop)","text":"

For menus and pause screens, use the scene stack:

// Push a pause menu (game scene stays in background)\nvoid pauseGame() {\n    pauseMenu.init();\n    engine.getCurrentScene()->getSceneManager().pushScene(&pauseMenu);\n}\n\n// Pop the pause menu (resume game)\nvoid resumeGame() {\n    engine.getCurrentScene()->getSceneManager().popScene();\n}\n

Note: Scene stack management is handled internally by the Engine's SceneManager. You typically access it through engine.getCurrentScene().

"},{"location":"manual/game_development/scenes_and_entities/#complete-example","title":"Complete Example","text":"

Here's a complete example of a scene with multiple entities:

#include <core/Scene.h>\n#include <core/Entity.h>\n#include <core/Actor.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\n// A simple moving entity\nclass MovingBox : public pixelroot32::core::Entity {\npublic:\n    MovingBox(float x, float y) \n        : Entity(x, y, 20, 20, pixelroot32::core::EntityType::GENERIC),\n          speedX(50.0f), speedY(30.0f) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        float dt = deltaTime * 0.001f; // Convert to seconds\n\n        x += speedX * dt;\n        y += speedY * dt;\n\n        // Bounce off screen edges\n        if (x < 0 || x > 220) speedX = -speedX;\n        if (y < 0 || y > 220) speedY = -speedY;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x), \n            static_cast<int>(y), \n            width, \n            height, \n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\nprivate:\n    float speedX, speedY;\n};\n\n// A simple actor that can collide\nclass CollidableBox : public pixelroot32::core::Actor {\npublic:\n    CollidableBox(float x, float y)\n        : Actor(x, y, 30, 30) {\n        setRenderLayer(1);\n        setCollisionLayer(0x0001);\n        setCollisionMask(0x0001);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Static actor, no movement\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x), \n            static_cast<int>(y), \n            width, \n            height, \n            pixelroot32::graphics::Color::Yellow\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Change color when collided\n        // (In a real game, you'd handle collision logic here)\n    }\n};\n\n// The scene\nclass ExampleScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Create and add entities\n        addEntity(new MovingBox(50, 50));\n        addEntity(new MovingBox(150, 100));\n        addEntity(new CollidableBox(100, 100));\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime); // Update all entities\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background\n        renderer.drawFilledRectangle(0, 0, 240, 240, \n            pixelroot32::graphics::Color::Black);\n\n        Scene::draw(renderer); // Draw all entities\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/scenes_and_entities/#entity-management","title":"Entity Management","text":"
  • Pre-allocate entities: Create entities in init(), not in update()
  • Reuse entities: Instead of creating/destroying, enable/disable entities
  • Limit entity count: MAX_ENTITIES = 32 per scene
  • Use object pooling: For frequently created/destroyed entities (projectiles, particles)
"},{"location":"manual/game_development/scenes_and_entities/#scene-organization","title":"Scene Organization","text":"
  • One scene per screen: Menu, game, game over, etc.
  • Keep scenes focused: Each scene should have a single responsibility
  • Initialize in init(): Don't do heavy work in the constructor
  • Clean up properly: Remove entities when switching scenes
"},{"location":"manual/game_development/scenes_and_entities/#collision-layers","title":"Collision Layers","text":"
  • Plan your layers: Design your layer system before coding
  • Use bit flags: Makes layer combinations easy
  • Keep it simple: Don't over-complicate with too many layers
  • Document your layers: Create a GameLayers.h file
"},{"location":"manual/game_development/scenes_and_entities/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/scenes_and_entities/#entity-pool-pattern","title":"Entity Pool Pattern","text":"

For entities that are frequently created and destroyed (like projectiles):

class ProjectilePool {\n    static const int POOL_SIZE = 10;\n    ProjectileActor pool[POOL_SIZE];\n\npublic:\n    ProjectileActor* getAvailable() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!pool[i].isActive) {\n                pool[i].isActive = true;\n                return &pool[i];\n            }\n        }\n        return nullptr; // Pool exhausted\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#entity-factory-pattern","title":"Entity Factory Pattern","text":"

Create entities through factory functions:

Entity* createEnemy(EnemyType type, float x, float y) {\n    switch (type) {\n        case EnemyType::BASIC:\n            return new BasicEnemy(x, y);\n        case EnemyType::FAST:\n            return new FastEnemy(x, y);\n        // ...\n    }\n}\n
"},{"location":"manual/game_development/scenes_and_entities/#next-steps","title":"Next Steps","text":"

Now that you understand scenes and entities, learn about: - Basic Rendering - Draw sprites, text, and primitives - Input and Control - Handle user input - Physics and Collisions - Advanced collision handling

See also: - Fundamental Concepts - API Reference - Scene - API Reference - Entity - API Reference - Actor

"},{"location":"manual/game_development/user_interface/","title":"User Interface","text":"

PixelRoot32 provides a complete UI system for creating menus, HUDs, and interface elements. This guide covers all UI components and layout systems.

"},{"location":"manual/game_development/user_interface/#ui-elements","title":"UI Elements","text":"

All UI elements inherit from UIElement, which itself inherits from Entity. This means UI elements can be added to scenes just like any other entity.

"},{"location":"manual/game_development/user_interface/#uilabel","title":"UILabel","text":"

Display text on screen:

#include <graphics/ui/UILabel.h>\n\n// Create a label\npixelroot32::graphics::ui::UILabel* scoreLabel = new pixelroot32::graphics::ui::UILabel(\n    \"Score: 0\",                    // text\n    10,                            // x position\n    10,                            // y position\n    pixelroot32::graphics::Color::White,  // color\n    1                              // size multiplier\n);\n\n// Add to scene\naddEntity(scoreLabel);\n\n// Update text dynamically\nscoreLabel->setText(\"Score: 100\");\n\n// Center horizontally\nscoreLabel->centerX(240); // Screen width\n
"},{"location":"manual/game_development/user_interface/#uibutton","title":"UIButton","text":"

Create clickable buttons:

#include <graphics/ui/UIButton.h>\n\n// Create a button\npixelroot32::graphics::ui::UIButton* startButton = new pixelroot32::graphics::ui::UIButton(\n    \"Start Game\",                  // text\n    4,                             // navigation index\n    50,                            // x position\n    100,                           // y position\n    140,                           // width\n    30,                            // height\n    []() {                         // callback function\n        // Button clicked - start game\n        startGame();\n    }\n);\n\n// Configure style\nstartButton->setStyle(\n    pixelroot32::graphics::Color::White,   // text color\n    pixelroot32::graphics::Color::Blue,    // background color\n    true                                    // draw background\n);\n\n// Add to scene\naddEntity(startButton);\n
"},{"location":"manual/game_development/user_interface/#uicheckbox","title":"UICheckBox","text":"

Create interactive checkboxes:

#include <graphics/ui/UICheckBox.h>\n\n// Create a checkbox\npixelroot32::graphics::ui::UICheckBox* soundCheckbox = new pixelroot32::graphics::ui::UICheckBox(\n    \"Enable Sound\",                // text\n    4,                             // navigation index\n    50,                            // x position\n    140,                           // y position\n    140,                           // width\n    20,                            // height\n    true,                          // initial checked state\n    [](bool checked) {             // callback function\n        // Checkbox state changed\n        setSoundEnabled(checked);\n    },\n    1                              // font size\n);\n\n// Configure style\nsoundCheckbox->setStyle(\n    pixelroot32::graphics::Color::White,   // text color\n    pixelroot32::graphics::Color::Blue,    // background color\n    false                                  // draw background\n);\n\n// Add to scene\naddEntity(soundCheckbox);\n
"},{"location":"manual/game_development/user_interface/#uipanel","title":"UIPanel","text":"

Create visual containers with background and border:

#include <graphics/ui/UIPanel.h>\n\n// Create a panel\npixelroot32::graphics::ui::UIPanel* dialog = new pixelroot32::graphics::ui::UIPanel(\n    50,   // x\n    50,   // y\n    140,  // width\n    140   // height\n);\n\n// Configure appearance\ndialog->setBackgroundColor(pixelroot32::graphics::Color::Black);\ndialog->setBorderColor(pixelroot32::graphics::Color::White);\ndialog->setBorderWidth(2);\n\n// Add content (typically a layout)\ndialog->setChild(menuLayout);\n\n// Add to scene\naddEntity(dialog);\n
"},{"location":"manual/game_development/user_interface/#layouts","title":"Layouts","text":"

Layouts automatically organize UI elements, eliminating the need for manual position calculations.

"},{"location":"manual/game_development/user_interface/#uiverticallayout","title":"UIVerticalLayout","text":"

Organize elements vertically with automatic scrolling:

#include <graphics/ui/UIVerticalLayout.h>\n\n// Create vertical layout\npixelroot32::graphics::ui::UIVerticalLayout* menu = new pixelroot32::graphics::ui::UIVerticalLayout(\n    10,   // x\n    60,   // y\n    220,  // width\n    160   // height (viewport)\n);\n\n// Configure layout\nmenu->setPadding(5);        // Internal padding\nmenu->setSpacing(6);        // Space between elements\nmenu->setScrollEnabled(true); // Enable scrolling\n\n// Set navigation buttons\nmenu->setNavigationButtons(0, 1); // UP=0, DOWN=1\n\n// Set button styles\nmenu->setButtonStyle(\n    pixelroot32::graphics::Color::White,  // selected text\n    pixelroot32::graphics::Color::Cyan,    // selected background\n    pixelroot32::graphics::Color::White,  // unselected text\n    pixelroot32::graphics::Color::Black   // unselected background\n);\n\n// Add buttons (no manual positioning needed!)\nfor (int i = 0; i < 10; i++) {\n    UIButton* btn = new UIButton(\n        \"Option \" + std::to_string(i),\n        i,\n        0, 0,  // Position ignored - layout handles it\n        200, 20,\n        [i]() { handleOption(i); }\n    );\n    menu->addElement(btn);\n}\n\n// Add layout to scene\nmenu->setRenderLayer(2); // UI layer\naddEntity(menu);\n
"},{"location":"manual/game_development/user_interface/#uihorizontallayout","title":"UIHorizontalLayout","text":"

Organize elements horizontally:

#include <graphics/ui/UIHorizontalLayout.h>\n\n// Create horizontal layout (menu bar)\npixelroot32::graphics::ui::UIHorizontalLayout* menuBar = new pixelroot32::graphics::ui::UIHorizontalLayout(\n    0,    // x\n    0,    // y\n    240,  // width\n    30    // height\n);\n\nmenuBar->setPadding(5);\nmenuBar->setSpacing(4);\nmenuBar->setScrollEnabled(true);\nmenuBar->setNavigationButtons(2, 3); // LEFT=2, RIGHT=3\n\n// Add menu items\nmenuBar->addElement(new UIButton(\"File\", 0, 0, 0, 60, 20, []() {}));\nmenuBar->addElement(new UIButton(\"Edit\", 1, 0, 0, 60, 20, []() {}));\nmenuBar->addElement(new UIButton(\"View\", 2, 0, 0, 60, 20, []() {}));\n\naddEntity(menuBar);\n
"},{"location":"manual/game_development/user_interface/#uigridlayout","title":"UIGridLayout","text":"

Organize elements in a grid (matrix):

#include <graphics/ui/UIGridLayout.h>\n\n// Create grid layout (inventory)\npixelroot32::graphics::ui::UIGridLayout* inventory = new pixelroot32::graphics::ui::UIGridLayout(\n    10,   // x\n    60,   // y\n    220,  // width\n    160   // height\n);\n\ninventory->setColumns(4);  // 4 columns\ninventory->setPadding(5);\ninventory->setSpacing(4);\ninventory->setNavigationButtons(0, 1, 2, 3); // UP, DOWN, LEFT, RIGHT\n\n// Add items (automatically arranged in grid)\nfor (int i = 0; i < 16; i++) {\n    UIButton* item = new UIButton(\n        \"Item \" + std::to_string(i),\n        i,\n        0, 0,  // Position ignored\n        50, 50,\n        [i]() { useItem(i); }\n    );\n    inventory->addElement(item);\n}\n\naddEntity(inventory);\n
"},{"location":"manual/game_development/user_interface/#uianchorlayout","title":"UIAnchorLayout","text":"

Position elements at fixed screen positions (perfect for HUDs):

#include <graphics/ui/UIAnchorLayout.h>\n\n// Create anchor layout for HUD\npixelroot32::graphics::ui::UIAnchorLayout* hud = new pixelroot32::graphics::ui::UIAnchorLayout(\n    0,    // x\n    0,    // y\n    240,  // screen width\n    240   // screen height\n);\n\nhud->setScreenSize(240, 240);\n\n// Add HUD elements at different anchor points\nUILabel* scoreLabel = new UILabel(\"Score: 0\", 0, 0, Color::White, 1);\nUILabel* livesLabel = new UILabel(\"Lives: 3\", 0, 0, Color::White, 1);\n\nhud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\nhud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\naddEntity(hud);\n

Available Anchors: - TOP_LEFT, TOP_RIGHT, TOP_CENTER - BOTTOM_LEFT, BOTTOM_RIGHT, BOTTOM_CENTER - LEFT_CENTER, RIGHT_CENTER - CENTER

"},{"location":"manual/game_development/user_interface/#uipaddingcontainer","title":"UIPaddingContainer","text":"

Add padding around a single element:

#include <graphics/ui/UIPaddingContainer.h>\n\n// Create padding container\npixelroot32::graphics::ui::UIPaddingContainer* container = new pixelroot32::graphics::ui::UIPaddingContainer(\n    10,   // x\n    10,   // y\n    200,  // width\n    100   // height\n);\n\n// Set uniform padding\ncontainer->setPadding(10);\n\n// Or set asymmetric padding\ncontainer->setPadding(5, 15, 10, 10); // left, right, top, bottom\n\n// Add child element\ncontainer->setChild(button);\n\naddEntity(container);\n
"},{"location":"manual/game_development/user_interface/#navigation","title":"Navigation","text":"

Layouts handle D-pad navigation automatically:

"},{"location":"manual/game_development/user_interface/#vertical-navigation","title":"Vertical Navigation","text":"
verticalLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN);\n\n// Layout automatically:\n// - Highlights selected button\n// - Scrolls to keep selected button visible\n// - Handles wrapping (optional)\n
"},{"location":"manual/game_development/user_interface/#horizontal-navigation","title":"Horizontal Navigation","text":"
horizontalLayout->setNavigationButtons(Buttons::LEFT, Buttons::RIGHT);\n
"},{"location":"manual/game_development/user_interface/#grid-navigation","title":"Grid Navigation","text":"
gridLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN, Buttons::LEFT, Buttons::RIGHT);\n\n// Layout automatically:\n// - Handles 4-direction navigation\n// - Wraps around edges\n// - Updates selection\n
"},{"location":"manual/game_development/user_interface/#manual-selection","title":"Manual Selection","text":"
// Set selected element programmatically\nlayout->setSelectedIndex(2);\n\n// Get selected element\nint selected = layout->getSelectedIndex();\nUIElement* element = layout->getSelectedElement();\n
"},{"location":"manual/game_development/user_interface/#complete-example-main-menu","title":"Complete Example: Main Menu","text":"
#include <core/Scene.h>\n#include <graphics/ui/UIVerticalLayout.h>\n#include <graphics/ui/UIButton.h>\n#include <graphics/ui/UILabel.h>\n#include <graphics/ui/UIPanel.h>\n\nclass MainMenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIVerticalLayout* menuLayout;\n    pixelroot32::graphics::ui::UIPanel* menuPanel;\n\npublic:\n    void init() override {\n        // Create panel\n        menuPanel = new pixelroot32::graphics::ui::UIPanel(40, 40, 160, 160);\n        menuPanel->setBackgroundColor(pixelroot32::graphics::Color::Black);\n        menuPanel->setBorderColor(pixelroot32::graphics::Color::White);\n        menuPanel->setBorderWidth(2);\n        menuPanel->setRenderLayer(2);\n        addEntity(menuPanel);\n\n        // Create layout inside panel\n        menuLayout = new pixelroot32::graphics::ui::UIVerticalLayout(0, 0, 160, 160);\n        menuLayout->setPadding(10);\n        menuLayout->setSpacing(8);\n        menuLayout->setNavigationButtons(0, 1);\n        menuLayout->setButtonStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Cyan,\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Black\n        );\n\n        // Add title\n        pixelroot32::graphics::ui::UILabel* title = new pixelroot32::graphics::ui::UILabel(\n            \"GAME MENU\", 0, 0, pixelroot32::graphics::Color::Yellow, 2\n        );\n        menuLayout->addElement(title);\n\n        // Add menu buttons\n        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Start Game\", 0, 0, 0, 140, 25, []() { startGame(); }\n        ));\n\n        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Options\", 1, 0, 0, 140, 25, []() { showOptions(); }\n        ));\n\n        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Quit\", 2, 0, 0, 140, 25, []() { quitGame(); }\n        ));\n\n        menuPanel->setChild(menuLayout);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Handle input for layout navigation\n        auto& input = engine.getInputManager();\n        menuLayout->handleInput(input);\n\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/user_interface/#complete-example-hud","title":"Complete Example: HUD","text":"
class GameHUD : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::ui::UIAnchorLayout* hud;\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n    pixelroot32::graphics::ui::UILabel* healthLabel;\n\npublic:\n    GameHUD()\n        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::UI_ELEMENT) {\n        setRenderLayer(2); // UI layer\n\n        // Create HUD layout\n        hud = new pixelroot32::graphics::ui::UIAnchorLayout(0, 0, 240, 240);\n        hud->setScreenSize(240, 240);\n\n        // Create labels\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\", 0, 0, pixelroot32::graphics::Color::White, 1\n        );\n\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\", 0, 0, pixelroot32::graphics::Color::White, 1\n        );\n\n        healthLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Health: 100%\", 0, 0, pixelroot32::graphics::Color::Green, 1\n        );\n\n        // Position labels\n        hud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n        hud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n        hud->addElement(healthLabel, pixelroot32::graphics::ui::Anchor::BOTTOM_CENTER);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update HUD text (example)\n        char buffer[32];\n        snprintf(buffer, sizeof(buffer), \"Score: %d\", currentScore);\n        scoreLabel->setText(buffer);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // HUD draws itself through its layout\n    }\n\n    // Add HUD to scene\n    void addToScene(Scene* scene) {\n        scene->addEntity(hud);\n    }\n};\n
"},{"location":"manual/game_development/user_interface/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/user_interface/#organization","title":"Organization","text":"
  • Use render layer 2: Keep all UI on the top layer
  • Group related elements: Use panels to group menu items
  • Separate HUD from menus: Use different layouts for different UI types
  • Reuse layouts: Create layout factories for common patterns
"},{"location":"manual/game_development/user_interface/#performance","title":"Performance","text":"
  • Layouts use viewport culling: Only visible elements are rendered
  • Minimize text updates: Updating text has overhead
  • Use appropriate layouts: Choose the right layout for your needs
  • Limit element count: Too many elements can impact performance
"},{"location":"manual/game_development/user_interface/#navigation_1","title":"Navigation","text":"
  • Set navigation buttons: Configure D-pad navigation for layouts
  • Handle input in update(): Check for button presses to trigger actions
  • Provide visual feedback: Selected buttons should be clearly visible
  • Test navigation flow: Ensure navigation feels responsive
"},{"location":"manual/game_development/user_interface/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/user_interface/#menu-system","title":"Menu System","text":"
class MenuSystem {\n    UIVerticalLayout* currentMenu;\n\npublic:\n    void showMainMenu() {\n        currentMenu = createMainMenu();\n        scene->addEntity(currentMenu);\n    }\n\n    void showPauseMenu() {\n        currentMenu = createPauseMenu();\n        scene->addEntity(currentMenu);\n    }\n\n    void hideMenu() {\n        if (currentMenu) {\n            scene->removeEntity(currentMenu);\n            currentMenu = nullptr;\n        }\n    }\n};\n
"},{"location":"manual/game_development/user_interface/#dynamic-ui-updates","title":"Dynamic UI Updates","text":"
void updateHUD(int score, int lives, int health) {\n    char buffer[32];\n\n    snprintf(buffer, sizeof(buffer), \"Score: %d\", score);\n    scoreLabel->setText(buffer);\n\n    snprintf(buffer, sizeof(buffer), \"Lives: %d\", lives);\n    livesLabel->setText(buffer);\n\n    snprintf(buffer, sizeof(buffer), \"Health: %d%%\", health);\n    healthLabel->setText(buffer);\n}\n
"},{"location":"manual/game_development/user_interface/#next-steps","title":"Next Steps","text":"

Now that you understand the UI system, you've completed the core game development topics. Continue with: - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels - Performance Tuning - Improve performance

See also: - API Reference - UIElement - API Reference - UIButton - API Reference - UI Layouts - Manual - UI Overview

"},{"location":"manual/optimization/extensibility/","title":"Extensibility","text":"

PixelRoot32 is designed to be extensible. This guide covers how to create custom drivers, audio backends, and extend existing systems.

"},{"location":"manual/optimization/extensibility/#creating-custom-display-drivers","title":"Creating Custom Display Drivers","text":"

To support a new display, implement the DrawSurface interface.

"},{"location":"manual/optimization/extensibility/#drawsurface-interface","title":"DrawSurface Interface","text":"
#include <graphics/DrawSurface.h>\n\nclass MyCustomDrawer : public pixelroot32::graphics::DrawSurface {\npublic:\n    // Required methods\n    void init() override;\n    void setRotation(uint8_t rotation) override;\n    void clearBuffer() override;\n    void sendBuffer() override;\n\n    // Drawing primitives\n    void drawPixel(int x, int y, uint16_t color) override;\n    void drawLine(int x1, int y1, int x2, int y2, uint16_t color) override;\n    void drawRectangle(int x, int y, int width, int height, uint16_t color) override;\n    void drawFilledRectangle(int x, int y, int width, int height, uint16_t color) override;\n    void drawCircle(int x, int y, int radius, uint16_t color) override;\n    void drawFilledCircle(int x, int y, int radius, uint16_t color) override;\n    void drawBitmap(int x, int y, int width, int height, const uint8_t* bitmap, uint16_t color) override;\n\n    // Text (deprecated, but must implement)\n    void drawText(const char* text, int16_t x, int16_t y, uint16_t color, uint8_t size) override;\n    void drawTextCentered(const char* text, int16_t y, uint16_t color, uint8_t size) override;\n\n    // State management\n    void setTextColor(uint16_t color) override;\n    void setTextSize(uint8_t size) override;\n    void setCursor(int16_t x, int16_t y) override;\n    void setContrast(uint8_t level) override;\n    void setDisplaySize(int w, int h) override;\n\n    // Utilities\n    uint16_t color565(uint8_t r, uint8_t g, uint8_t b) override;\n    bool processEvents() override;\n    void present() override;\n};\n
"},{"location":"manual/optimization/extensibility/#example-simple-custom-drawer","title":"Example: Simple Custom Drawer","text":"
#include <graphics/DrawSurface.h>\n\nclass SimpleDrawer : public pixelroot32::graphics::DrawSurface {\nprivate:\n    uint16_t* framebuffer;\n    int width, height;\n\npublic:\n    SimpleDrawer(int w, int h) : width(w), height(h) {\n        framebuffer = new uint16_t[w * h];\n    }\n\n    ~SimpleDrawer() {\n        delete[] framebuffer;\n    }\n\n    void init() override {\n        // Initialize your display hardware\n        // Clear framebuffer\n        clearBuffer();\n    }\n\n    void clearBuffer() override {\n        for (int i = 0; i < width * height; i++) {\n            framebuffer[i] = 0x0000; // Black\n        }\n    }\n\n    void sendBuffer() override {\n        // Send framebuffer to display\n        // Implementation depends on your hardware\n    }\n\n    void drawPixel(int x, int y, uint16_t color) override {\n        if (x >= 0 && x < width && y >= 0 && y < height) {\n            framebuffer[y * width + x] = color;\n        }\n    }\n\n    void drawFilledRectangle(int x, int y, int w, int h, uint16_t color) override {\n        for (int py = y; py < y + h; py++) {\n            for (int px = x; px < x + w; px++) {\n                drawPixel(px, py, color);\n            }\n        }\n    }\n\n    // Implement other required methods...\n    // (See TFT_eSPI_Drawer or SDL2_Drawer for reference implementations)\n};\n
"},{"location":"manual/optimization/extensibility/#integrating-custom-driver","title":"Integrating Custom Driver","text":"
// Create custom drawer\nSimpleDrawer* customDrawer = new SimpleDrawer(240, 240);\n\n// Create renderer with custom drawer\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::NONE, // Use NONE for custom\n    0, 240, 240\n);\n\n// You'll need to modify Engine to accept custom DrawSurface\n// Or create a custom Engine wrapper\n
"},{"location":"manual/optimization/extensibility/#creating-custom-audio-backends","title":"Creating Custom Audio Backends","text":"

Implement the AudioBackend interface for custom audio hardware.

"},{"location":"manual/optimization/extensibility/#audiobackend-interface","title":"AudioBackend Interface","text":"
#include <audio/AudioBackend.h>\n\nclass MyCustomAudioBackend : public pixelroot32::audio::AudioBackend {\npublic:\n    // Required methods\n    void init() override;\n    void start() override;\n    void stop() override;\n    uint32_t getSampleRate() const override;\n\n    // Audio generation\n    int16_t generateSample() override;\n\n    // Channel management\n    void setChannelWave(int channel, pixelroot32::audio::WaveType type, float frequency, float duty) override;\n    void setChannelVolume(int channel, float volume) override;\n    void stopChannel(int channel) override;\n};\n
"},{"location":"manual/optimization/extensibility/#example-custom-audio-backend","title":"Example: Custom Audio Backend","text":"
#include <audio/AudioBackend.h>\n\nclass CustomAudioBackend : public pixelroot32::audio::AudioBackend {\nprivate:\n    uint32_t sampleRate;\n    float phase[4] = {0, 0, 0, 0}; // 4 channels\n    float frequency[4] = {0, 0, 0, 0};\n    float volume[4] = {0, 0, 0, 0};\n    pixelroot32::audio::WaveType waveType[4];\n\npublic:\n    CustomAudioBackend(uint32_t rate) : sampleRate(rate) {\n        for (int i = 0; i < 4; i++) {\n            waveType[i] = pixelroot32::audio::WaveType::PULSE;\n            volume[i] = 0.0f;\n        }\n    }\n\n    void init() override {\n        // Initialize your audio hardware\n    }\n\n    void start() override {\n        // Start audio output\n    }\n\n    void stop() override {\n        // Stop audio output\n    }\n\n    uint32_t getSampleRate() const override {\n        return sampleRate;\n    }\n\n    int16_t generateSample() override {\n        float sample = 0.0f;\n\n        for (int ch = 0; ch < 4; ch++) {\n            if (frequency[ch] > 0 && volume[ch] > 0) {\n                float phaseIncrement = frequency[ch] / sampleRate;\n                phase[ch] += phaseIncrement;\n                if (phase[ch] >= 1.0f) phase[ch] -= 1.0f;\n\n                float channelSample = 0.0f;\n                switch (waveType[ch]) {\n                    case pixelroot32::audio::WaveType::PULSE:\n                        channelSample = (phase[ch] < 0.5f) ? 1.0f : -1.0f;\n                        break;\n                    case pixelroot32::audio::WaveType::TRIANGLE:\n                        channelSample = (phase[ch] < 0.5f) ? \n                            (phase[ch] * 4.0f - 1.0f) : \n                            (3.0f - phase[ch] * 4.0f);\n                        break;\n                    // ... other wave types\n                }\n\n                sample += channelSample * volume[ch];\n            }\n        }\n\n        // Clamp and convert to int16_t\n        if (sample > 1.0f) sample = 1.0f;\n        if (sample < -1.0f) sample = -1.0f;\n        return static_cast<int16_t>(sample * 32767.0f);\n    }\n\n    void setChannelWave(int ch, pixelroot32::audio::WaveType type, \n                       float freq, float duty) override {\n        if (ch >= 0 && ch < 4) {\n            waveType[ch] = type;\n            frequency[ch] = freq;\n        }\n    }\n\n    void setChannelVolume(int ch, float vol) override {\n        if (ch >= 0 && ch < 4) {\n            volume[ch] = vol;\n        }\n    }\n\n    void stopChannel(int ch) override {\n        if (ch >= 0 && ch < 4) {\n            frequency[ch] = 0.0f;\n            volume[ch] = 0.0f;\n        }\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#extending-existing-systems","title":"Extending Existing Systems","text":""},{"location":"manual/optimization/extensibility/#custom-entity-types","title":"Custom Entity Types","text":"

Create specialized entity types:

class PowerUpActor : public pixelroot32::core::Actor {\nprivate:\n    PowerUpType type;\n    float lifetime = 5.0f; // 5 seconds\n\npublic:\n    PowerUpActor(float x, float y, PowerUpType t)\n        : Actor(x, y, 8, 8), type(t) {\n        setRenderLayer(1);\n        setCollisionLayer(Layers::POWERUP);\n        setCollisionMask(Layers::PLAYER);\n    }\n\n    void update(unsigned long deltaTime) override {\n        lifetime -= deltaTime * 0.001f;\n        if (lifetime <= 0) {\n            isEnabled = false;\n            isVisible = false;\n        }\n\n        // Animate (bob up and down)\n        y += sin(millis() * 0.005f) * 0.5f;\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        if (other->isInLayer(Layers::PLAYER)) {\n            applyPowerUp(other);\n            isEnabled = false;\n            isVisible = false;\n        }\n    }\n\nprivate:\n    void applyPowerUp(pixelroot32::core::Actor* player) {\n        switch (type) {\n            case PowerUpType::SPEED:\n                // Increase player speed\n                break;\n            case PowerUpType::HEALTH:\n                // Restore health\n                break;\n            // ...\n        }\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#custom-ui-layouts","title":"Custom UI Layouts","text":"

Create new layout types:

#include <graphics/ui/UILayout.h>\n\nclass UICircularLayout : public pixelroot32::graphics::ui::UILayout {\nprivate:\n    float radius;\n    float startAngle;\n\npublic:\n    UICircularLayout(float x, float y, float w, float h, float r)\n        : UILayout(x, y, w, h), radius(r), startAngle(0.0f) {\n    }\n\n    void updateLayout() override {\n        int count = elements.size();\n        float angleStep = 360.0f / count;\n\n        for (size_t i = 0; i < elements.size(); i++) {\n            float angle = startAngle + (i * angleStep);\n            float rad = angle * M_PI / 180.0f;\n\n            float elementX = x + (radius * cos(rad)) - (elements[i]->width / 2);\n            float elementY = y + (radius * sin(rad)) - (elements[i]->height / 2);\n\n            elements[i]->x = elementX;\n            elements[i]->y = elementY;\n        }\n    }\n\n    void handleInput(const pixelroot32::input::InputManager& input) override {\n        // Implement circular navigation\n        // ...\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#custom-collision-primitives","title":"Custom Collision Primitives","text":"

Extend collision system with new shapes:

// Add to your game code (not engine modification)\nstruct Triangle {\n    float x1, y1, x2, y2, x3, y3;\n};\n\nbool intersects(const Triangle& tri, const pixelroot32::core::Rect& rect) {\n    // Implement triangle-rectangle intersection\n    // ...\n    return false;\n}\n\nbool intersects(const Triangle& tri1, const Triangle& tri2) {\n    // Implement triangle-triangle intersection\n    // ...\n    return false;\n}\n
"},{"location":"manual/optimization/extensibility/#best-practices","title":"Best Practices","text":""},{"location":"manual/optimization/extensibility/#maintain-compatibility","title":"Maintain Compatibility","text":"
  • Don't break existing APIs: Extend, don't modify
  • Use inheritance: Inherit from base classes
  • Follow patterns: Match existing code patterns
  • Document extensions: Comment your custom code
"},{"location":"manual/optimization/extensibility/#testing","title":"Testing","text":"
  • Test on both platforms: ESP32 and Native
  • Test edge cases: Boundary conditions, null pointers
  • Performance testing: Ensure extensions don't hurt performance
  • Memory testing: Check for leaks with custom code
"},{"location":"manual/optimization/extensibility/#documentation","title":"Documentation","text":"
  • Comment your code: Explain why, not just what
  • Provide examples: Show how to use your extensions
  • Document limitations: State what doesn't work
  • Version compatibility: Note which engine version
"},{"location":"manual/optimization/extensibility/#common-extension-patterns","title":"Common Extension Patterns","text":""},{"location":"manual/optimization/extensibility/#factory-pattern","title":"Factory Pattern","text":"
class EntityFactory {\npublic:\n    static pixelroot32::core::Entity* createEnemy(EnemyType type, float x, float y) {\n        switch (type) {\n            case EnemyType::BASIC:\n                return new BasicEnemy(x, y);\n            case EnemyType::FAST:\n                return new FastEnemy(x, y);\n            case EnemyType::TANK:\n                return new TankEnemy(x, y);\n            default:\n                return nullptr;\n        }\n    }\n\n    static pixelroot32::core::Entity* createPowerUp(PowerUpType type, float x, float y) {\n        return new PowerUpActor(x, y, type);\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#strategy-pattern","title":"Strategy Pattern","text":"
class MovementStrategy {\npublic:\n    virtual void update(pixelroot32::core::Actor* actor, unsigned long deltaTime) = 0;\n};\n\nclass LinearMovement : public MovementStrategy {\npublic:\n    void update(pixelroot32::core::Actor* actor, unsigned long deltaTime) override {\n        actor->x += speed * (deltaTime * 0.001f);\n    }\n};\n\nclass CircularMovement : public MovementStrategy {\npublic:\n    void update(pixelroot32::core::Actor* actor, unsigned long deltaTime) override {\n        float angle = millis() * 0.001f;\n        actor->x = centerX + radius * cos(angle);\n        actor->y = centerY + radius * sin(angle);\n    }\n};\n\nclass SmartEnemy : public pixelroot32::core::Actor {\nprivate:\n    MovementStrategy* movement;\n\npublic:\n    void setMovement(MovementStrategy* strat) {\n        movement = strat;\n    }\n\n    void update(unsigned long deltaTime) override {\n        if (movement) {\n            movement->update(this, deltaTime);\n        }\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/extensibility/#driver-not-working","title":"Driver Not Working","text":"
  • Verify all interface methods are implemented
  • Check initialization order
  • Test with simple drawing first
  • Verify hardware connections
"},{"location":"manual/optimization/extensibility/#audio-backend-issues","title":"Audio Backend Issues","text":"
  • Check sample rate matches hardware
  • Verify audio generation logic
  • Test with simple tones first
  • Check channel management
"},{"location":"manual/optimization/extensibility/#extension-conflicts","title":"Extension Conflicts","text":"
  • Ensure namespace isolation
  • Avoid modifying engine code directly
  • Use composition over modification
  • Test with engine updates
"},{"location":"manual/optimization/extensibility/#next-steps","title":"Next Steps","text":"

Now that you understand extensibility, you've completed the optimization section. Continue with: - API Reference - Complete API documentation - Examples - Code examples - Resources - Tools and troubleshooting

See also: - API Reference - DrawSurface - API Reference - AudioBackend - Manual - Platforms and Drivers

"},{"location":"manual/optimization/memory_management/","title":"Memory Management","text":"

ESP32 has limited memory, so efficient memory management is crucial for PixelRoot32 games. This guide covers memory constraints, object pooling, and best practices.

"},{"location":"manual/optimization/memory_management/#esp32-memory-constraints","title":"ESP32 Memory Constraints","text":""},{"location":"manual/optimization/memory_management/#available-memory","title":"Available Memory","text":"

ESP32 typically has: - RAM: ~320KB total (varies by model) - Flash: 4MB+ (for program storage) - Heap: Limited and fragmented over time

"},{"location":"manual/optimization/memory_management/#real-world-limits","title":"Real-World Limits","text":"
  • MAX_ENTITIES: 32 per scene (hard limit)
  • Sprite data: Stored in flash (const/constexpr)
  • Dynamic allocation: Should be avoided in game loop
  • Stack: Limited (~8KB), avoid large stack allocations
"},{"location":"manual/optimization/memory_management/#object-pooling","title":"Object Pooling","text":"

Object pooling reuses objects instead of creating/destroying them, avoiding memory fragmentation.

"},{"location":"manual/optimization/memory_management/#basic-pool-pattern","title":"Basic Pool Pattern","text":"
class ProjectilePool {\nprivate:\n    static const int POOL_SIZE = 10;\n    ProjectileActor pool[POOL_SIZE];\n    bool inUse[POOL_SIZE];\n\npublic:\n    ProjectilePool() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            inUse[i] = false;\n        }\n    }\n\n    ProjectileActor* getAvailable() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!inUse[i]) {\n                inUse[i] = true;\n                return &pool[i];\n            }\n        }\n        return nullptr; // Pool exhausted\n    }\n\n    void release(ProjectileActor* projectile) {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (&pool[i] == projectile) {\n                inUse[i] = false;\n                projectile->isEnabled = false;\n                projectile->isVisible = false;\n                break;\n            }\n        }\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#using-object-pools","title":"Using Object Pools","text":"
class GameScene : public pixelroot32::core::Scene {\nprivate:\n    ProjectilePool projectilePool;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Fire projectile\n        if (input.isButtonPressed(Buttons::A)) {\n            ProjectileActor* proj = projectilePool.getAvailable();\n            if (proj) {\n                proj->x = player->x;\n                proj->y = player->y;\n                proj->isEnabled = true;\n                proj->isVisible = true;\n                // ... initialize projectile\n            }\n        }\n\n        // Clean up projectiles that hit target\n        for (auto* entity : entities) {\n            if (auto* proj = dynamic_cast<ProjectileActor*>(entity)) {\n                if (proj->hitTarget) {\n                    projectilePool.release(proj);\n                }\n            }\n        }\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#complete-example-entity-pool","title":"Complete Example: Entity Pool","text":"
template<typename T, int POOL_SIZE>\nclass EntityPool {\nprivate:\n    T pool[POOL_SIZE];\n    bool inUse[POOL_SIZE];\n    int activeCount = 0;\n\npublic:\n    EntityPool() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            inUse[i] = false;\n        }\n    }\n\n    T* acquire() {\n        if (activeCount >= POOL_SIZE) {\n            return nullptr; // Pool full\n        }\n\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!inUse[i]) {\n                inUse[i] = true;\n                activeCount++;\n                return &pool[i];\n            }\n        }\n        return nullptr;\n    }\n\n    void release(T* obj) {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (&pool[i] == obj) {\n                inUse[i] = false;\n                activeCount--;\n                obj->isEnabled = false;\n                obj->isVisible = false;\n                break;\n            }\n        }\n    }\n\n    int getActiveCount() const { return activeCount; }\n    int getAvailableCount() const { return POOL_SIZE - activeCount; }\n};\n\n// Usage\nEntityPool<EnemyActor, 8> enemyPool;\nEntityPool<ParticleEmitter, 5> particlePool;\n
"},{"location":"manual/optimization/memory_management/#scene-arena-experimental","title":"Scene Arena (Experimental)","text":"

Scene Arena provides a memory arena for scene-specific allocations, reducing fragmentation.

"},{"location":"manual/optimization/memory_management/#what-is-scene-arena","title":"What is Scene Arena?","text":"

Scene Arena is a contiguous memory block pre-allocated for a scene. All scene entities are allocated from this arena instead of the heap.

"},{"location":"manual/optimization/memory_management/#when-to-use","title":"When to Use","text":"
  • Large scenes: Scenes with many entities
  • Frequent allocation: Scenes that create/destroy entities often
  • Memory fragmentation: When heap fragmentation is a problem
  • Performance: When you need predictable allocation performance
"},{"location":"manual/optimization/memory_management/#configuration","title":"Configuration","text":"
#ifdef PIXELROOT32_ENABLE_SCENE_ARENA\n#include <core/Scene.h>\n\n// Define arena buffer (typically in scene header)\nstatic unsigned char MY_SCENE_ARENA_BUFFER[8192]; // 8KB arena\n\nclass MyScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Initialize arena\n        arena.init(MY_SCENE_ARENA_BUFFER, sizeof(MY_SCENE_ARENA_BUFFER));\n\n        // Now entities allocated with arena will use this memory\n        // (Requires custom allocation functions)\n    }\n};\n#endif\n
"},{"location":"manual/optimization/memory_management/#limitations","title":"Limitations","text":"
  • Experimental: May have bugs or limitations
  • Fixed size: Arena size must be determined at compile time
  • No reallocation: Can't resize arena at runtime
  • Manual management: Requires careful memory management

Note: Scene Arena is an experimental feature. Use object pooling for most cases.

"},{"location":"manual/optimization/memory_management/#best-practices","title":"Best Practices","text":""},{"location":"manual/optimization/memory_management/#avoid-dynamic-allocation-in-game-loop","title":"Avoid Dynamic Allocation in Game Loop","text":"
// \u274c BAD: Allocates every frame\nvoid update(unsigned long deltaTime) override {\n    if (shouldSpawnEnemy) {\n        EnemyActor* enemy = new EnemyActor(x, y);\n        addEntity(enemy);\n    }\n}\n\n// \u2705 GOOD: Use pool\nvoid update(unsigned long deltaTime) override {\n    if (shouldSpawnEnemy) {\n        EnemyActor* enemy = enemyPool.getAvailable();\n        if (enemy) {\n            enemy->reset(x, y);\n            enemy->isEnabled = true;\n        }\n    }\n}\n
"},{"location":"manual/optimization/memory_management/#pre-allocate-resources","title":"Pre-allocate Resources","text":"
class GameScene : public pixelroot32::core::Scene {\nprivate:\n    // Pre-allocated pools\n    ProjectilePool projectiles;\n    EnemyPool enemies;\n    ParticlePool particles;\n\npublic:\n    void init() override {\n        // All pools created in constructor\n        // No allocation in init() or update()\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#reuse-objects","title":"Reuse Objects","text":"
class EnemyActor : public pixelroot32::core::Actor {\npublic:\n    void reset(float x, float y) {\n        this->x = x;\n        this->y = y;\n        this->isEnabled = true;\n        this->isVisible = true;\n        this->health = maxHealth;\n        // Reset all state\n    }\n\n    void deactivate() {\n        isEnabled = false;\n        isVisible = false;\n    }\n};\n\n// Usage\nEnemyActor* enemy = enemyPool.getAvailable();\nif (enemy) {\n    enemy->reset(spawnX, spawnY);\n    addEntity(enemy);\n}\n
"},{"location":"manual/optimization/memory_management/#avoid-strings-and-dynamic-memory","title":"Avoid Strings and Dynamic Memory","text":"
// \u274c BAD: String allocation\nvoid draw(Renderer& renderer) override {\n    std::string scoreText = \"Score: \" + std::to_string(score);\n    renderer.drawText(scoreText.c_str(), 10, 10, Color::White, 1);\n}\n\n// \u2705 GOOD: Static buffer\nvoid draw(Renderer& renderer) override {\n    char scoreBuffer[32];\n    snprintf(scoreBuffer, sizeof(scoreBuffer), \"Score: %d\", score);\n    renderer.drawText(scoreBuffer, 10, 10, Color::White, 1);\n}\n
"},{"location":"manual/optimization/memory_management/#store-data-in-flash","title":"Store Data in Flash","text":"
// \u2705 GOOD: Stored in flash (const/constexpr)\nstatic const uint16_t SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    // ...\n};\n\n// \u274c BAD: Stored in RAM\nuint16_t spriteData[] = {\n    0b00111100,\n    0b01111110,\n    // ...\n};\n
"},{"location":"manual/optimization/memory_management/#memory-monitoring","title":"Memory Monitoring","text":""},{"location":"manual/optimization/memory_management/#check-available-memory","title":"Check Available Memory","text":"
#ifdef PLATFORM_ESP32\n#include <Arduino.h>\n\nvoid checkMemory() {\n    Serial.print(\"Free heap: \");\n    Serial.println(ESP.getFreeHeap());\n    Serial.print(\"Largest free block: \");\n    Serial.println(ESP.getMaxAllocHeap());\n}\n#endif\n
"},{"location":"manual/optimization/memory_management/#monitor-entity-count","title":"Monitor Entity Count","text":"
void update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);\n\n    // Check entity count\n    int entityCount = getEntityCount();\n    if (entityCount >= MAX_ENTITIES) {\n        Serial.println(\"WARNING: Entity limit reached!\");\n    }\n}\n
"},{"location":"manual/optimization/memory_management/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/optimization/memory_management/#entity-lifecycle-management","title":"Entity Lifecycle Management","text":"
class ManagedEntity {\nprivate:\n    bool isActive = false;\n\npublic:\n    void activate(float x, float y) {\n        this->x = x;\n        this->y = y;\n        isActive = true;\n        isEnabled = true;\n        isVisible = true;\n    }\n\n    void deactivate() {\n        isActive = false;\n        isEnabled = false;\n        isVisible = false;\n    }\n\n    bool getIsActive() const { return isActive; }\n};\n\n// Pool manages lifecycle\nclass EntityManager {\nprivate:\n    EntityPool<ManagedEntity, 20> pool;\n\npublic:\n    ManagedEntity* spawn(float x, float y) {\n        auto* entity = pool.acquire();\n        if (entity) {\n            entity->activate(x, y);\n        }\n        return entity;\n    }\n\n    void despawn(ManagedEntity* entity) {\n        if (entity) {\n            entity->deactivate();\n            pool.release(entity);\n        }\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#memory-efficient-collections","title":"Memory-Efficient Collections","text":"
// Fixed-size array instead of vector\nclass EntityArray {\nprivate:\n    static const int MAX_SIZE = 32;\n    pixelroot32::core::Entity* entities[MAX_SIZE];\n    int count = 0;\n\npublic:\n    bool add(pixelroot32::core::Entity* entity) {\n        if (count >= MAX_SIZE) return false;\n        entities[count++] = entity;\n        return true;\n    }\n\n    void remove(pixelroot32::core::Entity* entity) {\n        for (int i = 0; i < count; i++) {\n            if (entities[i] == entity) {\n                entities[i] = entities[--count];\n                break;\n            }\n        }\n    }\n\n    int size() const { return count; }\n    pixelroot32::core::Entity* operator[](int index) { return entities[index]; }\n};\n
"},{"location":"manual/optimization/memory_management/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/memory_management/#out-of-memory-errors","title":"Out of Memory Errors","text":"
  • Reduce pool sizes
  • Use fewer entities
  • Store more data in flash
  • Avoid dynamic allocation
  • Check for memory leaks
"},{"location":"manual/optimization/memory_management/#entity-limit-reached","title":"Entity Limit Reached","text":"
  • MAX_ENTITIES = 32 is a hard limit
  • Use object pooling to reuse entities
  • Deactivate entities instead of removing
  • Combine multiple entities into one
"},{"location":"manual/optimization/memory_management/#memory-fragmentation","title":"Memory Fragmentation","text":"
  • Use object pooling
  • Pre-allocate all resources
  • Avoid frequent new/delete
  • Consider Scene Arena (experimental)
"},{"location":"manual/optimization/memory_management/#next-steps","title":"Next Steps","text":"

Now that you understand memory management, learn about: - Performance Optimization - Improve game performance - Platforms and Drivers - Understand platform specifics - Extensibility - Extend the engine

See also: - API Reference - Scene - Manual - Scenes and Entities

"},{"location":"manual/optimization/performance_tuning/","title":"Performance Optimization","text":"

This guide covers techniques to improve game performance on ESP32, including rendering optimization, logic optimization, and profiling.

"},{"location":"manual/optimization/performance_tuning/#esp32-performance-characteristics","title":"ESP32 Performance Characteristics","text":""},{"location":"manual/optimization/performance_tuning/#cpu-limitations","title":"CPU Limitations","text":"
  • Dual-core: 240MHz (typically)
  • Single-threaded game loop: One core handles everything
  • Target FPS: 30-60 FPS (depends on game complexity)
  • Frame budget: ~16-33ms per frame at 60 FPS
"},{"location":"manual/optimization/performance_tuning/#common-bottlenecks","title":"Common Bottlenecks","text":"
  1. Rendering: Too many draw calls
  2. Collision detection: Too many collision checks
  3. Memory allocation: Dynamic allocation in game loop
  4. Complex calculations: Expensive math operations
  5. String operations: String concatenation/formatting
"},{"location":"manual/optimization/performance_tuning/#tecnicas-de-optimizacion","title":"T\u00e9cnicas de Optimizaci\u00f3n","text":"

El motor utiliza varias t\u00e9cnicas para maximizar los FPS, especialmente en hardware limitado como el ESP32.

"},{"location":"manual/optimization/performance_tuning/#1-viewport-culling-recorte-de-camara","title":"1. Viewport Culling (Recorte de C\u00e1mara)","text":"

No proceses objetos que est\u00e1n fuera de la pantalla. El motor lo hace autom\u00e1ticamente en drawTileMap, pero debes implementarlo en tu l\u00f3gica de actualizaci\u00f3n:

bool isOnScreen(float x, float y, int width, int height, \n                const Camera2D& camera) {\n    float cameraX = camera.getX();\n    float cameraY = camera.getY();\n    int screenWidth = engine.getRenderer().getWidth();\n    int screenHeight = engine.getRenderer().getHeight();\n\n    return !(x + width < cameraX || \n             x > cameraX + screenWidth ||\n             y + height < cameraY || \n             y > cameraY + screenHeight);\n}\n
"},{"location":"manual/optimization/performance_tuning/#2-optimizacion-de-memoria-y-cpu-esp32","title":"2. Optimizaci\u00f3n de Memoria y CPU (ESP32)","text":"

Para la plataforma ESP32, se han implementado optimizaciones de bajo nivel cr\u00edticas:

  • IRAM_ATTR: Las funciones cr\u00edticas de renderizado (drawSprite, drawTileMap, etc.) est\u00e1n marcadas para ejecutarse desde la RAM interna (IRAM), eliminando la latencia de lectura de la Flash SPI.
  • DMA (Direct Memory Access): El volcado del buffer a la pantalla TFT se realiza mediante DMA, lo que permite que la CPU comience a procesar el siguiente frame mientras el hardware transfiere los datos.
  • Acceso a Datos de 16 bits: Los sprites de 2bpp y 4bpp utilizan punteros uint16_t* para garantizar accesos alineados a memoria, lo cual es significativamente m\u00e1s r\u00e1pido en la arquitectura Xtensa del ESP32.
"},{"location":"manual/optimization/performance_tuning/#3-optimizacion-de-tilemaps","title":"3. Optimizaci\u00f3n de TileMaps","text":"

El renderizado de mapas de tiles es una de las operaciones m\u00e1s costosas. PixelRoot32 utiliza:

  • Cach\u00e9 de Paleta: Durante el dibujado de un tilemap, se genera una tabla de b\u00fasqueda (LUT) temporal para evitar c\u00e1lculos de color redundantes por cada p\u00edxel.
  • Dibujado por Columnas: Optimizado para minimizar los saltos de memoria en el framebuffer.
"},{"location":"manual/optimization/performance_tuning/#4-colisiones-eficientes","title":"4. Colisiones Eficientes","text":"

Usa colisiones basadas en tiles siempre que sea posible. Acceder a un array de tiles es O(1), mientras que iterar sobre una lista de entidades es O(n).

// Ejemplo de colisi\u00f3n r\u00e1pida con el mapa\nint tileX = x / 8;\nint tileY = y / 8;\nif (levelMap.data[tileY * levelMap.width + tileX] != 0) {\n    // Colisi\u00f3n detectada\n}\n
"},{"location":"manual/optimization/performance_tuning/#recomendaciones-generales","title":"Recomendaciones Generales","text":"
  • Sprites Indexados: Prefiere Sprite2bpp (4 colores) o Sprite4bpp (16 colores) sobre Sprite (1bpp) si necesitas color, ya que est\u00e1n altamente optimizados.
  • Evitar std::string en el Loop: Las concatenaciones de strings generan fragmentaci\u00f3n de memoria. Usa buffers est\u00e1ticos o char[] para textos din\u00e1micos.
  • Perfilado: Activa el overlay de FPS compilando con PIXELROOT32_ENABLE_FPS_DISPLAY (ver Engine - FPS overlay) para monitorear el impacto de tus cambios en tiempo real.
"},{"location":"manual/optimization/performance_tuning/#common-optimization-patterns","title":"Common Optimization Patterns","text":""},{"location":"manual/optimization/performance_tuning/#update-frequency-reduction","title":"Update Frequency Reduction","text":"
class LowFrequencyUpdater {\nprivate:\n    unsigned long timer = 0;\n    unsigned long interval = 100; // Update every 100ms\n\npublic:\n    void update(unsigned long deltaTime) {\n        timer += deltaTime;\n        if (timer >= interval) {\n            timer -= interval;\n            // Do expensive update\n            expensiveUpdate();\n        }\n    }\n};\n
"},{"location":"manual/optimization/performance_tuning/#spatial-partitioning-simple","title":"Spatial Partitioning (Simple)","text":"
// Divide screen into zones\nclass SpatialGrid {\nprivate:\n    static const int GRID_SIZE = 4;\n    static const int CELL_WIDTH = 60;\n    static const int CELL_HEIGHT = 60;\n\n    std::vector<Actor*> grid[GRID_SIZE][GRID_SIZE];\n\npublic:\n    void add(Actor* actor) {\n        int cellX = static_cast<int>(actor->x) / CELL_WIDTH;\n        int cellY = static_cast<int>(actor->y) / CELL_HEIGHT;\n        if (cellX >= 0 && cellX < GRID_SIZE && \n            cellY >= 0 && cellY < GRID_SIZE) {\n            grid[cellY][cellX].push_back(actor);\n        }\n    }\n\n    void checkCollisions() {\n        // Only check collisions within same cell\n        for (int y = 0; y < GRID_SIZE; y++) {\n            for (int x = 0; x < GRID_SIZE; x++) {\n                auto& cell = grid[y][x];\n                for (size_t i = 0; i < cell.size(); i++) {\n                    for (size_t j = i + 1; j < cell.size(); j++) {\n                        checkCollision(cell[i], cell[j]);\n                    }\n                }\n            }\n        }\n    }\n};\n
"},{"location":"manual/optimization/performance_tuning/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/performance_tuning/#low-fps","title":"Low FPS","text":"
  • Profile to find bottlenecks
  • Reduce entity count
  • Optimize rendering (culling, batching)
  • Simplify collision detection
  • Reduce update frequency
"},{"location":"manual/optimization/performance_tuning/#frame-drops","title":"Frame Drops","text":"
  • Check for expensive operations in update()
  • Avoid dynamic allocation
  • Cache calculations
  • Reduce draw calls
"},{"location":"manual/optimization/performance_tuning/#stuttering","title":"Stuttering","text":"
  • Ensure frame-rate independence (use deltaTime)
  • Avoid blocking operations
  • Pre-load resources
  • Use object pooling
"},{"location":"manual/optimization/performance_tuning/#next-steps","title":"Next Steps","text":"

Now that you understand performance optimization, learn about: - Memory Management - Manage memory efficiently - Platforms and Drivers - Platform-specific optimizations - Extensibility - Extend the engine

See also: - Manual - Basic Rendering - Manual - Physics and Collisions

"},{"location":"manual/optimization/platforms_and_drivers/","title":"Platforms and Drivers","text":"

PixelRoot32 supports multiple platforms through driver abstraction. This guide covers supported platforms, display drivers, audio backends, and build configuration.

"},{"location":"manual/optimization/platforms_and_drivers/#supported-platforms","title":"Supported Platforms","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32","title":"ESP32","text":"

Primary platform for PixelRoot32 games.

Characteristics: - TFT_eSPI display driver - Internal DAC or I2S audio - GPIO button input - Limited RAM/Flash - Real hardware constraints

Use for: - Final game deployment - Hardware testing - Production builds

"},{"location":"manual/optimization/platforms_and_drivers/#nativedesktop-sdl2","title":"Native/Desktop (SDL2)","text":"

Development platform for rapid iteration.

Characteristics: - SDL2 display driver - SDL2 audio backend - Keyboard input - Unlimited resources (for testing) - Fast development cycle

Use for: - Development and debugging - Testing without hardware - Rapid prototyping - CI/CD testing

"},{"location":"manual/optimization/platforms_and_drivers/#display-drivers","title":"Display Drivers","text":""},{"location":"manual/optimization/platforms_and_drivers/#tft_espi-esp32","title":"TFT_eSPI (ESP32)","text":"

TFT_eSPI is the display driver for ESP32, supporting many TFT displays.

"},{"location":"manual/optimization/platforms_and_drivers/#optimizaciones-esp32","title":"Optimizaciones ESP32","text":"

Para maximizar el rendimiento en ESP32, PixelRoot32 utiliza:

  • DMA (Direct Memory Access): Las transferencias al display se realizan en segundo plano, permitiendo que la CPU prepare el siguiente frame mientras se env\u00eda el actual.
  • Doble Buffer con IRAM: El motor utiliza un buffer de pantalla (Sprite de TFT_eSPI) optimizado para transferencias r\u00e1pidas.
  • Alineaci\u00f3n de 16 bits: Los datos de sprites 2bpp/4bpp est\u00e1n alineados a palabras de 16 bits para aprovechar la arquitectura Xtensa.
  • IRAM_ATTR: Las funciones cr\u00edticas de renderizado est\u00e1n marcadas para residir en la RAM de instrucciones, evitando cuellos de botella por acceso a la Flash.
"},{"location":"manual/optimization/platforms_and_drivers/#configuracion-dma","title":"Configuraci\u00f3n DMA","text":"

El DMA se activa autom\u00e1ticamente si el hardware lo soporta. Aseg\u00farate de configurar la frecuencia SPI adecuada para tu display (usualmente 40MHz u 80MHz).

[env:esp32dev]\nbuild_flags = \n    -D ST7789_DRIVER          # Display type\n    -D TFT_WIDTH=240          # Display width\n    -D TFT_HEIGHT=240         # Display height\n    -D TFT_MOSI=23            # SPI MOSI pin\n    -D TFT_SCLK=18            # SPI clock pin\n    -D TFT_DC=2               # Data/Command pin\n    -D TFT_RST=4              # Reset pin\n    -D TFT_CS=-1              # Chip select (-1 if not used)\n    -D SPI_FREQUENCY=40000000 # SPI frequency\n
"},{"location":"manual/optimization/platforms_and_drivers/#supported-displays","title":"Supported Displays","text":"
  • ST7735: 128x128, 128x160
  • ST7789: 240x240, 240x320
  • ILI9341: 240x320
  • And more: See TFT_eSPI documentation
"},{"location":"manual/optimization/platforms_and_drivers/#usage","title":"Usage","text":"
#include <drivers/esp32/TFT_eSPI_Drawer.h>\n\n// Display configuration\npixelroot32::graphics::DisplayConfig displayConfig(\n    pixelroot32::graphics::DisplayType::ST7789,\n    0,      // rotation\n    240,    // width\n    240     // height\n);\n\n// TFT_eSPI_Drawer is created automatically by Engine\n// No manual driver creation needed\n
"},{"location":"manual/optimization/platforms_and_drivers/#sdl2_drawer-native","title":"SDL2_Drawer (Native)","text":"

SDL2_Drawer provides display output for PC/desktop development.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration","title":"Configuration","text":"
#include <drivers/native/SDL2_Drawer.h>\n\n// Display configuration (NONE defaults to SDL2)\npixelroot32::graphics::DisplayConfig displayConfig(\n    pixelroot32::graphics::DisplayType::NONE,\n    0,      // rotation\n    240,    // width\n    240     // height\n);\n\n// SDL2_Drawer is created automatically\n
"},{"location":"manual/optimization/platforms_and_drivers/#sdl2-installation","title":"SDL2 Installation","text":"

Windows (MSYS2):

pacman -S mingw-w64-x86_64-SDL2\n

Linux:

sudo apt-get install libsdl2-dev\n

macOS:

brew install sdl2\n

"},{"location":"manual/optimization/platforms_and_drivers/#audio-backends","title":"Audio Backends","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32_dac_audiobackend","title":"ESP32_DAC_AudioBackend","text":"

Uses ESP32's internal DAC for audio output.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration_1","title":"Configuration","text":"
#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nconst int DAC_PIN = 25; // GPIO 25 or 26\npixelroot32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(\n    DAC_PIN,    // DAC pin (25 or 26)\n    11025       // Sample rate (Hz)\n);\n\npixelroot32::audio::AudioConfig audioConfig(\n    &audioBackend, \n    audioBackend.getSampleRate()\n);\n

Characteristics: - Simple setup (just one pin) - Lower quality than I2S - Good for basic audio - Sample rate: 11025 Hz recommended

"},{"location":"manual/optimization/platforms_and_drivers/#esp32_i2s_audiobackend","title":"ESP32_I2S_AudioBackend","text":"

Uses ESP32's I2S peripheral for higher quality audio.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration_2","title":"Configuration","text":"
#include <drivers/esp32/ESP32_I2S_AudioBackend.h>\n\nconst int I2S_BCLK = 26;  // Bit clock pin\nconst int I2S_LRCK = 25;  // Left/Right clock pin\nconst int I2S_DOUT = 22;  // Data out pin\n\npixelroot32::drivers::esp32::ESP32_I2S_AudioBackend audioBackend(\n    I2S_BCLK,\n    I2S_LRCK,\n    I2S_DOUT,\n    22050  // Sample rate (Hz)\n);\n\npixelroot32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n

Characteristics: - Higher quality than DAC - Requires external I2S DAC (e.g., MAX98357A) - Better for music - Sample rate: 22050 Hz recommended

"},{"location":"manual/optimization/platforms_and_drivers/#sdl2_audiobackend-native","title":"SDL2_AudioBackend (Native)","text":"

SDL2 audio for PC development.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration_3","title":"Configuration","text":"
#include <drivers/native/SDL2_AudioBackend.h>\n\npixelroot32::drivers::native::SDL2_AudioBackend audioBackend(\n    22050,  // Sample rate\n    1024    // Buffer size\n);\n\npixelroot32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n
"},{"location":"manual/optimization/platforms_and_drivers/#build-flags","title":"Build Flags","text":""},{"location":"manual/optimization/platforms_and_drivers/#experimental-features","title":"Experimental Features","text":"

Enable experimental features with build flags:

[env:esp32dev]\nbuild_flags = \n    -D PIXELROOT32_ENABLE_2BPP_SPRITES    # Enable 2bpp sprite format\n    -D PIXELROOT32_ENABLE_4BPP_SPRITES   # Enable 4bpp sprite format\n    -D PIXELROOT32_ENABLE_SCENE_ARENA    # Enable Scene Arena (experimental)\n    -D PIXELROOT32_ENABLE_FPS_DISPLAY    # On-screen FPS counter (green, top-right; value updated every 8 frames)\n
"},{"location":"manual/optimization/platforms_and_drivers/#fps-overlay-pixelroot32_enable_fps_display","title":"FPS overlay (PIXELROOT32_ENABLE_FPS_DISPLAY)","text":"

When defined, the engine draws an on-screen FPS counter (green text, top-right) each frame. The value is recalculated every 8 frames to keep per-frame cost low. No code changes are required; the overlay is drawn automatically after the scene. See API Reference - Engine - Optional: FPS overlay for details.

"},{"location":"manual/optimization/platforms_and_drivers/#scene-limits-max_layers-max_entities","title":"Scene limits (MAX_LAYERS / MAX_ENTITIES)","text":"

You can override the default scene limits from your project without modifying the engine. The default of 3 for MAX_LAYERS is due to ESP32 platform constraints (memory and draw-loop cost); on native/PC you can use a higher value.

Option A: Compiler flags (recommended) \u2014 in platformio.ini, add to build_flags for your environment:

build_flags =\n    -DMAX_LAYERS=5\n    -DMAX_ENTITIES=64\n

The compiler defines these before any .cpp is processed. Because Scene.h uses #ifndef MAX_LAYERS / #ifndef MAX_ENTITIES, your values are used (more render layers drawn in Scene::draw, and on Arduino the entity queue capacity when built with MAX_ENTITIES).

See API Reference - Scene - Overriding scene limits for details.

"},{"location":"manual/optimization/platforms_and_drivers/#platform-detection","title":"Platform Detection","text":"
#ifdef PLATFORM_ESP32\n    // ESP32-specific code\n    Serial.println(\"Running on ESP32\");\n#endif\n\n#ifdef PLATFORM_NATIVE\n    // Native/PC-specific code\n    printf(\"Running on PC\\n\");\n#endif\n
"},{"location":"manual/optimization/platforms_and_drivers/#optimization-flags","title":"Optimization Flags","text":"
[env:esp32dev]\nbuild_flags = \n    -O2              # Optimization level\n    -ffunction-sections\n    -fdata-sections\n    -Wl,--gc-sections\n
"},{"location":"manual/optimization/platforms_and_drivers/#complete-platform-setup-examples","title":"Complete Platform Setup Examples","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32-complete-setup","title":"ESP32 Complete Setup","text":"
#include <Arduino.h>\n#include <core/Engine.h>\n#include <drivers/esp32/TFT_eSPI_Drawer.h>\n#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\n// Audio\nconst int DAC_PIN = 25;\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\n// Display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::ST7789,\n    0, 240, 240\n);\n\n// Input\npr32::input::InputConfig inputConfig(\n    6, 32, 27, 33, 14, 13, 12  // 6 buttons, pins\n);\n\n// Audio config\npr32::audio::AudioConfig audioConfig(&audioBackend, 11025);\n\n// Engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nvoid setup() {\n    Serial.begin(115200);\n    engine.init();\n    // ... scene setup\n}\n\nvoid loop() {\n    engine.run();\n}\n
"},{"location":"manual/optimization/platforms_and_drivers/#native-complete-setup","title":"Native Complete Setup","text":"
#define SDL_MAIN_HANDLED\n#include <SDL2/SDL.h>\n#include <core/Engine.h>\n#include <drivers/native/SDL2_Drawer.h>\n#include <drivers/native/SDL2_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\n// Audio\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\n\n// Display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::NONE,\n    0, 240, 240\n);\n\n// Input (SDL scancodes)\npr32::input::InputConfig inputConfig(\n    6,\n    SDL_SCANCODE_UP,\n    SDL_SCANCODE_DOWN,\n    SDL_SCANCODE_LEFT,\n    SDL_SCANCODE_RIGHT,\n    SDL_SCANCODE_SPACE,\n    SDL_SCANCODE_RETURN\n);\n\n// Audio config\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n\n// Engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nint main(int argc, char* argv[]) {\n    engine.init();\n    // ... scene setup\n    engine.run();\n    return 0;\n}\n
"},{"location":"manual/optimization/platforms_and_drivers/#platform-specific-considerations","title":"Platform-Specific Considerations","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32_1","title":"ESP32","text":"

Memory: - Limited RAM (~320KB) - Use object pooling - Store data in flash - Avoid dynamic allocation

Performance: - Target 30-60 FPS - Optimize rendering - Reduce entity count - Profile on hardware

Hardware: - GPIO pin configuration - SPI display setup - Audio hardware connections - Power considerations

"},{"location":"manual/optimization/platforms_and_drivers/#native","title":"Native","text":"

Development: - Fast iteration - Easy debugging - Unlimited resources - Visual debugging tools

Testing: - Test logic without hardware - Rapid prototyping - CI/CD integration - Cross-platform testing

"},{"location":"manual/optimization/platforms_and_drivers/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32-display-issues","title":"ESP32 Display Issues","text":"
  • Check wiring connections
  • Verify pin numbers
  • Lower SPI frequency
  • Check display type matches
  • Verify power supply
"},{"location":"manual/optimization/platforms_and_drivers/#esp32-audio-issues","title":"ESP32 Audio Issues","text":"
  • Check DAC/I2S pin configuration
  • Verify sample rate
  • Check hardware connections
  • Lower volume if distorted
  • Test with different sample rates
"},{"location":"manual/optimization/platforms_and_drivers/#native-build-issues","title":"Native Build Issues","text":"
  • Verify SDL2 installation
  • Check include/library paths
  • Ensure SDL2 version compatibility
  • Check linker flags
"},{"location":"manual/optimization/platforms_and_drivers/#next-steps","title":"Next Steps","text":"

Now that you understand platforms and drivers, learn about: - Extensibility - Create custom drivers - Memory Management - ESP32 memory constraints - Performance Optimization - Platform-specific optimization

See also: - API Reference - DrawSurface - API Reference - AudioBackend - Getting Started - Your First Project

"},{"location":"reference/api_overview/","title":"API Reference Overview","text":"

This document provides a complete technical reference for all PixelRoot32 APIs, organized by module. Each class includes descriptions, constructors, methods, properties, and usage examples.

"},{"location":"reference/api_overview/#organization","title":"Organization","text":"

The API is organized into the following modules:

  • Core: Engine, Scene, Entity, Actor, PhysicsActor, SceneManager
  • Graphics: Renderer, Camera2D, Color, Font, Sprite, TileMap, DrawSurface
  • Audio: AudioEngine, MusicPlayer, AudioTypes, AudioConfig, AudioBackend
  • Input: InputManager, InputConfig
  • Physics: CollisionSystem, CollisionTypes
  • UI: UIElement, UIButton, UILabel, UILayouts
  • Particles: ParticleEmitter, ParticleConfig, ParticlePresets
"},{"location":"reference/api_overview/#quick-navigation","title":"Quick Navigation","text":""},{"location":"reference/api_overview/#core-module","title":"Core Module","text":"
  • Engine - Main engine class, game loop management
  • Scene - Scene/level management
  • Entity - Base game object class
  • Actor - Entity with collision support
  • PhysicsActor - Actor with automatic physics
  • InputManager - Input handling
  • InputConfig - Input configuration
"},{"location":"reference/api_overview/#graphics-module","title":"Graphics Module","text":"
  • Renderer - High-level rendering API
  • Camera2D - 2D camera for scrolling
  • Color - Color constants and utilities
  • Font - Bitmap font system
  • Sprite - Sprite structures and formats
  • TileMap - Tilemap structure
  • DisplayConfig - Display configuration
"},{"location":"reference/api_overview/#audio-module","title":"Audio Module","text":"
  • AudioEngine - Sound effects playback
  • MusicPlayer - Background music playback
  • AudioTypes - Audio data structures
  • AudioConfig - Audio configuration
"},{"location":"reference/api_overview/#physics-module","title":"Physics Module","text":"
  • CollisionSystem - Collision detection
  • CollisionTypes - Collision primitives
"},{"location":"reference/api_overview/#ui-module","title":"UI Module","text":"
  • UIElement - Base UI element class
  • UIButton - Clickable button
  • UILabel - Text label
  • UILayouts - Layout containers
"},{"location":"reference/api_overview/#api-documentation-format","title":"API Documentation Format","text":"

Each API reference page follows this structure:

"},{"location":"reference/api_overview/#class-name","title":"Class Name","text":"

Brief description of the class and its purpose.

"},{"location":"reference/api_overview/#namespace","title":"Namespace","text":"
namespace pixelroot32::module {\n    class ClassName {\n        // ...\n    };\n}\n
"},{"location":"reference/api_overview/#constructors","title":"Constructors","text":"

List of all constructors with parameters.

"},{"location":"reference/api_overview/#public-methods","title":"Public Methods","text":"Method Description Parameters Returns methodName() Description param: type return type"},{"location":"reference/api_overview/#properties","title":"Properties","text":"Property Type Description property type Description"},{"location":"reference/api_overview/#usage-example","title":"Usage Example","text":"
// Example code showing typical usage\n
"},{"location":"reference/api_overview/#performance-notes","title":"Performance Notes","text":"

Any performance considerations or limitations.

"},{"location":"reference/api_overview/#see-also","title":"See Also","text":"

Links to related APIs and documentation.

"},{"location":"reference/api_overview/#finding-apis","title":"Finding APIs","text":""},{"location":"reference/api_overview/#by-functionality","title":"By Functionality","text":"
  • Game Loop: See Engine
  • Rendering: See Renderer
  • Input: See InputManager
  • Audio: See AudioEngine and MusicPlayer
  • Physics: See PhysicsActor and CollisionSystem
  • UI: See UIElement and layouts
"},{"location":"reference/api_overview/#by-module","title":"By Module","text":"

Navigate to the specific module folder: - api_reference/core/ - Core engine classes - api_reference/graphics/ - Rendering and graphics - api_reference/audio/ - Audio system - api_reference/physics/ - Physics and collisions - api_reference/ui/ - User interface

"},{"location":"reference/api_overview/#complete-api-list","title":"Complete API List","text":""},{"location":"reference/api_overview/#core","title":"Core","text":"
  • Engine
  • Scene
  • Entity
  • Actor
  • PhysicsActor
  • InputManager
  • InputConfig
"},{"location":"reference/api_overview/#graphics","title":"Graphics","text":"
  • Renderer
  • Camera2D
  • Color
  • Font
  • Sprite
  • TileMap
  • DisplayConfig
"},{"location":"reference/api_overview/#audio","title":"Audio","text":"
  • AudioEngine
  • MusicPlayer
  • AudioTypes
  • AudioConfig
"},{"location":"reference/api_overview/#physics","title":"Physics","text":"
  • CollisionSystem
  • CollisionTypes
"},{"location":"reference/api_overview/#ui","title":"UI","text":"
  • UIElement
  • UIButton
  • UILabel
  • UIVerticalLayout
  • UIHorizontalLayout
  • UIGridLayout
  • UIAnchorLayout
  • UIPanel
  • UIPaddingContainer
"},{"location":"reference/api_overview/#related-documentation","title":"Related Documentation","text":"
  • Manual - Game Development - How to use the APIs
  • Manual - Advanced Graphics - Advanced techniques
  • Code Examples - Reusable code snippets
  • Game Examples Guide - Learn from complete games

Note: This is an overview. For detailed API documentation, see the individual reference pages linked above.

"},{"location":"reference/code_examples/","title":"Code Examples","text":"

A library of reusable code snippets for common PixelRoot32 tasks. All examples are complete and functional.

"},{"location":"reference/code_examples/#initialization","title":"Initialization","text":""},{"location":"reference/code_examples/#basic-engine-setup-esp32","title":"Basic Engine Setup (ESP32)","text":"
#include <Arduino.h>\n#include <core/Engine.h>\n#include <drivers/esp32/TFT_eSPI_Drawer.h>\n#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\n// Audio\nconst int DAC_PIN = 25;\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\n// Display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::ST7789,\n    0, 240, 240\n);\n\n// Input\npr32::input::InputConfig inputConfig(6, 32, 27, 33, 14, 13, 12);\n\n// Audio config\npr32::audio::AudioConfig audioConfig(&audioBackend, 11025);\n\n// Engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nvoid setup() {\n    Serial.begin(115200);\n    engine.init();\n    // ... scene setup\n}\n\nvoid loop() {\n    engine.run();\n}\n
"},{"location":"reference/code_examples/#basic-engine-setup-native","title":"Basic Engine Setup (Native)","text":"
#define SDL_MAIN_HANDLED\n#include <SDL2/SDL.h>\n#include <core/Engine.h>\n#include <drivers/native/SDL2_Drawer.h>\n#include <drivers/native/SDL2_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::NONE, 0, 240, 240\n);\npr32::input::InputConfig inputConfig(\n    6, SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, \n    SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT,\n    SDL_SCANCODE_SPACE, SDL_SCANCODE_RETURN\n);\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nint main(int argc, char* argv[]) {\n    engine.init();\n    // ... scene setup\n    engine.run();\n    return 0;\n}\n
"},{"location":"reference/code_examples/#entity-movement","title":"Entity Movement","text":""},{"location":"reference/code_examples/#simple-movement","title":"Simple Movement","text":"
class MovingEntity : public pixelroot32::core::Entity {\nprivate:\n    float speedX = 50.0f;\n    float speedY = 30.0f;\n\npublic:\n    MovingEntity(float x, float y)\n        : Entity(x, y, 16, 16, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        float dt = deltaTime * 0.001f;\n        x += speedX * dt;\n        y += speedY * dt;\n\n        // Bounce off edges\n        if (x < 0 || x > 224) speedX = -speedX;\n        if (y < 0 || y > 224) speedY = -speedY;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width, height,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n};\n
"},{"location":"reference/code_examples/#input-based-movement","title":"Input-Based Movement","text":"
class PlayerEntity : public pixelroot32::core::Actor {\nprivate:\n    float speed = 100.0f;\n\npublic:\n    PlayerEntity(float x, float y)\n        : Actor(x, y, 16, 16) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        if (input.isButtonDown(Buttons::LEFT)) {\n            x -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::RIGHT)) {\n            x += speed * dt;\n        }\n        if (input.isButtonDown(Buttons::UP)) {\n            y -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::DOWN)) {\n            y += speed * dt;\n        }\n\n        // Keep on screen\n        if (x < 0) x = 0;\n        if (x > 224) x = 224;\n        if (y < 0) y = 0;\n        if (y > 224) y = 224;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width, height,\n            pixelroot32::graphics::Color::White\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collision\n    }\n};\n
"},{"location":"reference/code_examples/#collisions","title":"Collisions","text":""},{"location":"reference/code_examples/#basic-collision-detection","title":"Basic Collision Detection","text":"
class CollidableEntity : public pixelroot32::core::Actor {\npublic:\n    CollidableEntity(float x, float y)\n        : Actor(x, y, 16, 16) {\n        setRenderLayer(1);\n        setCollisionLayer(Layers::PLAYER);\n        setCollisionMask(Layers::ENEMY | Layers::WALL);\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        if (other->isInLayer(Layers::ENEMY)) {\n            // Hit enemy\n            takeDamage();\n        } else if (other->isInLayer(Layers::WALL)) {\n            // Hit wall\n            stopMovement();\n        }\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"reference/code_examples/#collision-layers-setup","title":"Collision Layers Setup","text":"
// Define in GameLayers.h\nnamespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;\n    constexpr uint16_t ENEMY = 0x0002;\n    constexpr uint16_t PROJECTILE = 0x0004;\n    constexpr uint16_t WALL = 0x0008;\n    constexpr uint16_t PICKUP = 0x0010;\n}\n\n// Usage\nplayer->setCollisionLayer(Layers::PLAYER);\nplayer->setCollisionMask(Layers::ENEMY | Layers::WALL);\n\nenemy->setCollisionLayer(Layers::ENEMY);\nenemy->setCollisionMask(Layers::PLAYER | Layers::PROJECTILE);\n
"},{"location":"reference/code_examples/#sound-effects","title":"Sound Effects","text":""},{"location":"reference/code_examples/#common-sound-effects","title":"Common Sound Effects","text":"
namespace SoundEffects {\n    inline pixelroot32::audio::AudioEvent jump() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 600.0f;\n        evt.duration = 0.1f;\n        evt.volume = 0.7f;\n        evt.duty = 0.25f;\n        return evt;\n    }\n\n    inline pixelroot32::audio::AudioEvent coin() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 1500.0f;\n        evt.duration = 0.12f;\n        evt.volume = 0.8f;\n        evt.duty = 0.5f;\n        return evt;\n    }\n\n    inline pixelroot32::audio::AudioEvent explosion() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::NOISE;\n        evt.frequency = 200.0f;\n        evt.duration = 0.3f;\n        evt.volume = 0.9f;\n        return evt;\n    }\n}\n\n// Usage\nengine.getAudioEngine().playEvent(SoundEffects::jump());\n
"},{"location":"reference/code_examples/#playing-sound-on-event","title":"Playing Sound on Event","text":"
class PlayerActor : public pixelroot32::core::Actor {\npublic:\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n\n        if (input.isButtonPressed(Buttons::A)) {\n            // Play jump sound\n            pixelroot32::audio::AudioEvent jumpSound{};\n            jumpSound.type = pixelroot32::audio::WaveType::PULSE;\n            jumpSound.frequency = 800.0f;\n            jumpSound.duration = 0.1f;\n            jumpSound.volume = 0.7f;\n            jumpSound.duty = 0.25f;\n\n            engine.getAudioEngine().playEvent(jumpSound);\n\n            // Jump logic\n            jump();\n        }\n    }\n};\n
"},{"location":"reference/code_examples/#ui-components","title":"UI Components","text":""},{"location":"reference/code_examples/#simple-menu","title":"Simple Menu","text":"
class MenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIVerticalLayout* menu;\n\npublic:\n    void init() override {\n        menu = new pixelroot32::graphics::ui::UIVerticalLayout(40, 60, 160, 160);\n        menu->setPadding(10);\n        menu->setSpacing(8);\n        menu->setNavigationButtons(0, 1);\n        menu->setButtonStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Cyan,\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Black\n        );\n\n        menu->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Start\", 0, 0, 0, 140, 25, []() { startGame(); }\n        ));\n\n        menu->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Options\", 1, 0, 0, 140, 25, []() { showOptions(); }\n        ));\n\n        addEntity(menu);\n    }\n\n    void update(unsigned long deltaTime) override {\n        menu->handleInput(engine.getInputManager());\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"reference/code_examples/#hud-with-labels","title":"HUD with Labels","text":"
class GameHUD : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n\npublic:\n    GameHUD()\n        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::UI_ELEMENT) {\n        setRenderLayer(2);\n\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\", 10, 10,\n            pixelroot32::graphics::Color::White, 1\n        );\n\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\", 10, 20,\n            pixelroot32::graphics::Color::White, 1\n        );\n    }\n\n    void updateHUD(int score, int lives) {\n        char buffer[32];\n        snprintf(buffer, sizeof(buffer), \"Score: %d\", score);\n        scoreLabel->setText(buffer);\n\n        snprintf(buffer, sizeof(buffer), \"Lives: %d\", lives);\n        livesLabel->setText(buffer);\n    }\n};\n
"},{"location":"reference/code_examples/#physics","title":"Physics","text":""},{"location":"reference/code_examples/#bouncing-ball","title":"Bouncing Ball","text":"
class BouncingBall : public pixelroot32::core::PhysicsActor {\npublic:\n    BouncingBall(float x, float y, float radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRenderLayer(1);\n        setRestitution(0.9f);\n        setFriction(0.05f);\n        setWorldSize(240, 240);\n        setVelocity(50.0f, -30.0f);\n    }\n\n    void update(unsigned long deltaTime) override {\n        float gravity = 200.0f;\n        float dt = deltaTime * 0.001f;\n        setVelocity(vx, vy + gravity * dt);\n        PhysicsActor::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        int radius = width / 2;\n        renderer.drawFilledCircle(\n            static_cast<int>(x + radius),\n            static_cast<int>(y + radius),\n            radius,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"reference/code_examples/#platformer-player","title":"Platformer Player","text":"
class PlatformerPlayer : public pixelroot32::core::PhysicsActor {\nprivate:\n    bool canJump = true;\n    float jumpForce = 250.0f;\n    float moveSpeed = 100.0f;\n\npublic:\n    PlatformerPlayer(float x, float y)\n        : PhysicsActor(x, y, 16, 16) {\n        setRenderLayer(1);\n        setFriction(0.3f);\n        setWorldSize(240, 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        // Horizontal movement\n        float moveDir = 0.0f;\n        if (input.isButtonDown(Buttons::LEFT)) moveDir -= 1.0f;\n        if (input.isButtonDown(Buttons::RIGHT)) moveDir += 1.0f;\n        setVelocity(moveDir * moveSpeed, vy);\n\n        // Gravity\n        float gravity = 300.0f;\n        setVelocity(vx, vy + gravity * dt);\n\n        // Jump\n        if (input.isButtonPressed(Buttons::A) && canJump) {\n            setVelocity(vx, -jumpForce);\n            canJump = false;\n        }\n\n        PhysicsActor::update(deltaTime);\n\n        // Check if on ground\n        auto collisionInfo = getWorldCollisionInfo();\n        if (collisionInfo.bottom) {\n            canJump = true;\n        }\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"reference/code_examples/#sprites-and-animation","title":"Sprites and Animation","text":""},{"location":"reference/code_examples/#simple-sprite","title":"Simple Sprite","text":"
// Define sprite data\nstatic const uint16_t PLAYER_SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b01111110,\n    0b00111100,\n    0b00000000\n};\n\nstatic const pixelroot32::graphics::Sprite PLAYER_SPRITE = {\n    PLAYER_SPRITE_DATA, 8, 8\n};\n\n// Draw sprite\nrenderer.drawSprite(PLAYER_SPRITE, 100, 100, \n    pixelroot32::graphics::Color::White);\n
"},{"location":"reference/code_examples/#sprite-animation","title":"Sprite Animation","text":"
class AnimatedActor : public pixelroot32::core::Actor {\nprivate:\n    pixelroot32::graphics::SpriteAnimation animation;\n    unsigned long timer = 0;\n    const unsigned long FRAME_DURATION_MS = 100;\n\npublic:\n    AnimatedActor(float x, float y)\n        : Actor(x, y, 8, 8) {\n        setRenderLayer(1);\n        animation.frames = WALK_ANIMATION_FRAMES;\n        animation.frameCount = 3;\n        animation.current = 0;\n    }\n\n    void update(unsigned long deltaTime) override {\n        timer += deltaTime;\n        if (timer >= FRAME_DURATION_MS) {\n            timer -= FRAME_DURATION_MS;\n            animation.step();\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        const auto* frame = animation.frames[animation.current].sprite;\n        renderer.drawSprite(*frame, static_cast<int>(x), static_cast<int>(y),\n            pixelroot32::graphics::Color::White);\n    }\n};\n
"},{"location":"reference/code_examples/#camera-and-scrolling","title":"Camera and Scrolling","text":""},{"location":"reference/code_examples/#basic-camera-follow","title":"Basic Camera Follow","text":"
class ScrollingScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n        camera.setBounds(0, 2000 - screenWidth);\n\n        player = new PlayerActor(100, 100);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"reference/code_examples/#tilemaps","title":"Tilemaps","text":""},{"location":"reference/code_examples/#simple-tilemap","title":"Simple Tilemap","text":"
// Define tiles\nstatic const uint16_t TILE_EMPTY_BITS[] = { /* ... */ };\nstatic const uint16_t TILE_GROUND_BITS[] = { /* ... */ };\n\nstatic const pixelroot32::graphics::Sprite TILES[] = {\n    { TILE_EMPTY_BITS, 8, 8 },\n    { TILE_GROUND_BITS, 8, 8 }\n};\n\n// Create tilemap\nstatic uint8_t TILEMAP_INDICES[30 * 20];\nstatic pixelroot32::graphics::TileMap levelTileMap = {\n    TILEMAP_INDICES, 30, 20, TILES, 8, 8, 2\n};\n\n// Initialize\nvoid initTilemap() {\n    for (int i = 0; i < 30 * 20; i++) {\n        TILEMAP_INDICES[i] = 0;\n    }\n    // Set ground row\n    for (int x = 0; x < 30; x++) {\n        TILEMAP_INDICES[19 * 30 + x] = 1; // Ground tile\n    }\n}\n\n// Draw\nrenderer.drawTileMap(levelTileMap, 0, 0, \n    pixelroot32::graphics::Color::White);\n
"},{"location":"reference/code_examples/#particles","title":"Particles","text":""},{"location":"reference/code_examples/#explosion-effect","title":"Explosion Effect","text":"
#include <graphics/particles/ParticleEmitter.h>\n#include <graphics/particles/ParticlePresets.h>\n\nclass ExplosionEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* emitter;\n\npublic:\n    ExplosionEffect()\n        : Entity(0, 0, 1, 1, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n        emitter = new pixelroot32::graphics::particles::ParticleEmitter(\n            0, 0,\n            pixelroot32::graphics::particles::ParticlePresets::Explosion()\n        );\n    }\n\n    void trigger(float x, float y) {\n        this->x = x;\n        this->y = y;\n        emitter->burst(x, y, 25);\n    }\n\n    void update(unsigned long deltaTime) override {\n        emitter->update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        emitter->draw(renderer);\n    }\n};\n
"},{"location":"reference/code_examples/#object-pooling","title":"Object Pooling","text":""},{"location":"reference/code_examples/#entity-pool","title":"Entity Pool","text":"
template<typename T, int POOL_SIZE>\nclass EntityPool {\nprivate:\n    T pool[POOL_SIZE];\n    bool inUse[POOL_SIZE];\n    int activeCount = 0;\n\npublic:\n    EntityPool() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            inUse[i] = false;\n        }\n    }\n\n    T* acquire() {\n        if (activeCount >= POOL_SIZE) return nullptr;\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!inUse[i]) {\n                inUse[i] = true;\n                activeCount++;\n                return &pool[i];\n            }\n        }\n        return nullptr;\n    }\n\n    void release(T* obj) {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (&pool[i] == obj) {\n                inUse[i] = false;\n                activeCount--;\n                obj->isEnabled = false;\n                obj->isVisible = false;\n                break;\n            }\n        }\n    }\n};\n
"},{"location":"reference/code_examples/#common-patterns","title":"Common Patterns","text":""},{"location":"reference/code_examples/#state-machine","title":"State Machine","text":"
enum class GameState {\n    MENU,\n    PLAYING,\n    PAUSED,\n    GAME_OVER\n};\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    GameState currentState = GameState::MENU;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        switch (currentState) {\n            case GameState::MENU:\n                updateMenu();\n                break;\n            case GameState::PLAYING:\n                updateGame();\n                break;\n            case GameState::PAUSED:\n                updatePause();\n                break;\n            case GameState::GAME_OVER:\n                updateGameOver();\n                break;\n        }\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"reference/code_examples/#timer-pattern","title":"Timer Pattern","text":"
class Timer {\nprivate:\n    unsigned long duration;\n    unsigned long elapsed = 0;\n    bool active = false;\n\npublic:\n    Timer(unsigned long ms) : duration(ms) {}\n\n    void start() {\n        active = true;\n        elapsed = 0;\n    }\n\n    void update(unsigned long deltaTime) {\n        if (active) {\n            elapsed += deltaTime;\n            if (elapsed >= duration) {\n                active = false;\n            }\n        }\n    }\n\n    bool isFinished() const { return !active && elapsed >= duration; }\n    bool isActive() const { return active; }\n    float getProgress() const { return static_cast<float>(elapsed) / duration; }\n};\n
"},{"location":"reference/code_examples/#see-also","title":"See Also","text":"
  • API Reference Overview - Complete API documentation
  • Game Examples Guide - Learn from complete games
  • Manual - Game Development - Detailed guides
"},{"location":"reference/game_examples_guide/","title":"Game Examples Guide","text":"

This guide analyzes the complete game examples included with PixelRoot32, explaining their architecture, patterns, and lessons learned.

"},{"location":"reference/game_examples_guide/#available-examples","title":"Available Examples","text":"

PixelRoot32 (in the PixelRoot32 Game Samples project) includes these games and demos:

  • Metroidvania: 2D platformer with multi-layer 4bpp tilemap and tile-based collision (requires PIXELROOT32_ENABLE_4BPP_SPRITES; no scroll/camera)
  • Space Invaders: Full shooter with enemies, projectiles, bunkers and audio
  • Pong: Classic with physics and collisions
  • BrickBreaker: Breakout-style with particles and advanced audio
  • Snake: Grid-based game with entity pooling
  • TicTacToe: Turn-based with simple AI
  • CameraDemo: Platformer with camera and parallax
  • SpritesDemo: 2bpp and 4bpp sprites
  • TileMapDemo: 4bpp tilemaps (with viewport culling)
"},{"location":"reference/game_examples_guide/#space-invaders","title":"Space Invaders","text":"

Location: src/examples/SpaceInvaders/

"},{"location":"reference/game_examples_guide/#architecture","title":"Architecture","text":"

Space Invaders demonstrates a complete game with multiple systems:

  • Scene Management: SpaceInvadersScene manages game state
  • Actor Hierarchy: PlayerActor, AlienActor, ProjectileActor, BunkerActor
  • Collision System: Uses collision layers for player, enemies, projectiles
  • Audio Integration: Sound effects for shooting, explosions, music
  • Background: Starfield (code-generated star pattern) or tilemap
"},{"location":"reference/game_examples_guide/#key-systems","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#collision-layers","title":"Collision Layers","text":"
namespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;\n    constexpr uint16_t ALIEN = 0x0002;\n    constexpr uint16_t PROJECTILE = 0x0004;\n    constexpr uint16_t BUNKER = 0x0008;\n}\n\n// Player can collide with aliens and bunkers\nplayer->setCollisionLayer(Layers::PLAYER);\nplayer->setCollisionMask(Layers::ALIEN | Layers::BUNKER);\n\n// Projectiles can hit aliens and bunkers\nprojectile->setCollisionLayer(Layers::PROJECTILE);\nprojectile->setCollisionMask(Layers::ALIEN | Layers::BUNKER);\n
"},{"location":"reference/game_examples_guide/#entity-management","title":"Entity Management","text":"
  • Uses object pooling for projectiles
  • Manages alien formation with grid layout
  • Handles game state (playing, game over)
"},{"location":"reference/game_examples_guide/#audio-integration","title":"Audio Integration","text":"
  • Background music using MusicPlayer
  • Sound effects for various events
  • Audio events triggered on collisions
"},{"location":"reference/game_examples_guide/#patterns-used","title":"Patterns Used","text":"
  • Object Pooling: Projectiles are pooled and reused
  • State Machine: Game states (playing, game over, victory)
  • Grid Layout: Alien formation uses grid-based positioning
  • Event-Driven Audio: Sounds triggered by game events
"},{"location":"reference/game_examples_guide/#lessons-learned","title":"Lessons Learned","text":"
  • Collision layers are essential for complex games
  • Object pooling improves performance
  • Starfield or tilemap backgrounds are efficient
  • Audio enhances game feel significantly
"},{"location":"reference/game_examples_guide/#metroidvania","title":"Metroidvania","text":"

Location: src/examples/Games/Metroidvania/

Assets: Sprites and tilesets for this example come from the Tiny Metroidvania 8x8 pack by Kenmi (kenmi-art.itch.io).

"},{"location":"reference/game_examples_guide/#architecture_1","title":"Architecture","text":"

Metroidvania is a 2D platformer example with multi-layer tilemap and optimizations aimed at ESP32. It does not use scroll or camera; the level is drawn with a fixed origin (0,0).

  • Scene: MetroidvaniaScene with a single PlayerActor and several tilemap layers (background, platforms, details, stairs).
  • PlayerActor: Horizontal and vertical movement, stairs, tile-based collision (no rectangle lists).
  • Tilemap: 4bpp (TileMap4bpp), with viewport culling and palette cache in the engine. Level 40\u00d730 tiles (320\u00d7240 px).
  • No camera: The view does not follow the player; for scroll you would use Camera2D and apply offset in the renderer (as in CameraDemo).
"},{"location":"reference/game_examples_guide/#engine-features-used","title":"Engine features used","text":"
  • Tile-based collision: Direct tile checks around the player (getTileAt), instead of iterating over platformRects.
  • 4bpp sprites: Player with animations (idle, run, jump) from generated headers (e.g. Sprite Compiler).
  • Rendering optimizations: Viewport culling in drawTileMap, optimized 4bpp drawSprite, layers culled by viewport.
  • Optional: Scene arena, DMA, IRAM_ATTR on critical paths (per example optimization plan).
"},{"location":"reference/game_examples_guide/#patterns-used_1","title":"Patterns used","text":"
  • Tile-based collision: Single O(1) access per tile instead of O(N) rectangles.
  • Stair detection: Single result reused for collision and state change.
  • Simplified hitbox: Fewer vertical check points (head and feet).
"},{"location":"reference/game_examples_guide/#lessons-learned_1","title":"Lessons learned","text":"
  • Tile-based collision scales better than rectangle lists on large levels.
  • Viewport and 4bpp optimizations improve FPS on ESP32.
  • Metroidvania serves as a reference for platformers with tilemap and camera.
"},{"location":"reference/game_examples_guide/#pong","title":"Pong","text":"

Location: src/examples/Pong/

"},{"location":"reference/game_examples_guide/#architecture_2","title":"Architecture","text":"

Pong demonstrates physics and collision handling:

  • PhysicsActor: Ball uses PhysicsActor for automatic physics
  • Collision Callbacks: Paddles and ball handle collisions
  • Score System: Simple score tracking and display
  • Game State: Reset and game over handling
"},{"location":"reference/game_examples_guide/#key-systems_1","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#physics-setup","title":"Physics Setup","text":"
class BallActor : public pixelroot32::core::PhysicsActor {\npublic:\n    BallActor(float x, float y, float speed, int radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRestitution(0.8f);  // Bouncy\n        setFriction(0.1f);     // Low friction\n        setWorldSize(240, 240);\n    }\n};\n
"},{"location":"reference/game_examples_guide/#collision-response","title":"Collision Response","text":"
void BallActor::onCollision(pixelroot32::core::Actor* other) {\n    // Adjust ball position\n    // Modify velocity based on impact point\n    // Play bounce sound\n}\n
"},{"location":"reference/game_examples_guide/#patterns-used_2","title":"Patterns Used","text":"
  • Physics Integration: Uses PhysicsActor for automatic movement
  • Collision Response: Custom collision handling
  • Score Management: Simple state tracking
  • Audio Feedback: Sound on collision
"},{"location":"reference/game_examples_guide/#lessons-learned_2","title":"Lessons Learned","text":"
  • PhysicsActor simplifies physics-based games
  • Collision callbacks allow custom response logic
  • Simple games can be very effective
"},{"location":"reference/game_examples_guide/#snake","title":"Snake","text":"

Location: src/examples/Snake/

"},{"location":"reference/game_examples_guide/#architecture_3","title":"Architecture","text":"

Snake demonstrates entity pooling and grid-based movement:

  • Entity Pooling: Snake segments are pooled
  • Grid Movement: Movement constrained to grid
  • Game Logic: Food spawning, collision detection
  • State Management: Game over, reset functionality
"},{"location":"reference/game_examples_guide/#key-systems_2","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#entity-pooling","title":"Entity Pooling","text":"
class SnakeScene {\nprivate:\n    std::vector<SnakeSegmentActor*> segmentPool;\n    std::vector<SnakeSegmentActor*> snakeSegments;\n\n    void resetGame() {\n        // Reuse pooled segments\n        for (int i = 0; i < initialLength; ++i) {\n            SnakeSegmentActor* segment = segmentPool[i];\n            segment->resetAlive();\n            snakeSegments.push_back(segment);\n            addEntity(segment);\n        }\n    }\n};\n
"},{"location":"reference/game_examples_guide/#grid-based-movement","title":"Grid-Based Movement","text":"
class SnakeSegmentActor : public pixelroot32::core::Actor {\nprivate:\n    int cellX, cellY;  // Grid position\n\npublic:\n    void setCellPosition(int x, int y) {\n        cellX = x;\n        cellY = y;\n        // Convert to world position\n        this->x = cellX * CELL_SIZE;\n        this->y = cellY * CELL_SIZE;\n    }\n};\n
"},{"location":"reference/game_examples_guide/#patterns-used_3","title":"Patterns Used","text":"
  • Object Pooling: Segments are pre-allocated and reused
  • Grid System: Discrete grid-based movement
  • Linked List: Snake segments form a linked structure
  • Food Spawning: Random food placement with collision checking
"},{"location":"reference/game_examples_guide/#lessons-learned_3","title":"Lessons Learned","text":"
  • Entity pooling is essential for dynamic entities
  • Grid-based movement simplifies collision detection
  • Pre-allocation avoids memory fragmentation
"},{"location":"reference/game_examples_guide/#tictactoe","title":"TicTacToe","text":"

Location: src/examples/TicTacToe/

"},{"location":"reference/game_examples_guide/#architecture_4","title":"Architecture","text":"

TicTacToe demonstrates turn-based logic and simple AI:

  • Turn Management: Player vs AI turns
  • Game Board: 3x3 grid representation
  • Win Detection: Check for winning conditions
  • Simple AI: Random move selection
"},{"location":"reference/game_examples_guide/#key-systems_3","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#board-representation","title":"Board Representation","text":"
class TicTacToeScene {\nprivate:\n    int board[3][3];  // 0=empty, 1=X, 2=O\n    bool playerTurn = true;\n\n    bool makeMove(int row, int col, int player) {\n        if (board[row][col] == 0) {\n            board[row][col] = player;\n            return true;\n        }\n        return false;\n    }\n};\n
"},{"location":"reference/game_examples_guide/#win-detection","title":"Win Detection","text":"
int checkWinner() {\n    // Check rows\n    for (int i = 0; i < 3; i++) {\n        if (board[i][0] == board[i][1] && board[i][1] == board[i][2]) {\n            return board[i][0];\n        }\n    }\n    // Check columns, diagonals...\n    return 0; // No winner\n}\n
"},{"location":"reference/game_examples_guide/#patterns-used_4","title":"Patterns Used","text":"
  • State Machine: Turn-based state management
  • Grid Logic: 2D array for board representation
  • Simple AI: Random valid move selection
  • UI Integration: Buttons for player input
"},{"location":"reference/game_examples_guide/#lessons-learned_4","title":"Lessons Learned","text":"
  • Turn-based games are straightforward to implement
  • Simple AI can be effective for basic games
  • Grid-based logic is easy to reason about
"},{"location":"reference/game_examples_guide/#camerademo","title":"CameraDemo","text":"

Location: src/examples/CameraDemo/

"},{"location":"reference/game_examples_guide/#architecture_5","title":"Architecture","text":"

CameraDemo demonstrates scrolling and parallax:

  • Camera2D: Camera following player
  • Tilemap: Level built with tilemap
  • Parallax: Multiple background layers
  • Platformer Physics: Player with jumping and gravity
"},{"location":"reference/game_examples_guide/#key-systems_4","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#camera-setup","title":"Camera Setup","text":"
class CameraDemoScene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    float levelWidth;\n\npublic:\n    void init() override {\n        camera = pixelroot32::graphics::Camera2D(240, 240);\n        camera.setBounds(0, levelWidth - 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        renderer.drawTileMap(levelTileMap, 0, 0, Color::White);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"reference/game_examples_guide/#platformer-physics","title":"Platformer Physics","text":"
class PlayerCube : public pixelroot32::core::PhysicsActor {\npublic:\n    void update(unsigned long deltaTime) override {\n        // Input handling\n        // Gravity application\n        // Jump logic\n        // Platform collision\n        PhysicsActor::update(deltaTime);\n    }\n};\n
"},{"location":"reference/game_examples_guide/#patterns-used_5","title":"Patterns Used","text":"
  • Camera Following: Dead-zone camera following
  • Tilemap Rendering: Efficient level rendering
  • Parallax Scrolling: Multiple background layers
  • Platform Collision: Custom collision with platforms
"},{"location":"reference/game_examples_guide/#lessons-learned_5","title":"Lessons Learned","text":"
  • Camera system enables large levels
  • Tilemaps are efficient for level data
  • Parallax adds depth to 2D games
  • Platform collision requires custom logic
"},{"location":"reference/game_examples_guide/#spritesdemo","title":"SpritesDemo","text":"

Location: src/examples/SpritesDemo/

"},{"location":"reference/game_examples_guide/#architecture_6","title":"Architecture","text":"

SpritesDemo showcases advanced sprite formats:

  • 2bpp Sprites: 4-color sprite format
  • 4bpp Sprites: 16-color sprite format (if enabled)
  • Animation: Sprite animation examples
  • Format Comparison: Side-by-side format display
"},{"location":"reference/game_examples_guide/#key-systems_5","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#2bpp-sprite-usage","title":"2bpp Sprite Usage","text":"
#ifdef PIXELROOT32_ENABLE_2BPP_SPRITES\nstatic const pixelroot32::graphics::Sprite2bpp SPRITE_2BPP = {\n    SPRITE_DATA,\n    SPRITE_PALETTE,\n    16, 32, 4\n};\n\nrenderer.drawSprite(SPRITE_2BPP, x, y, false);\n#endif\n
"},{"location":"reference/game_examples_guide/#animation-display","title":"Animation Display","text":"
class SpritesDemoActor : public pixelroot32::core::Entity {\nprivate:\n    unsigned long timer = 0;\n    uint8_t currentFrame = 0;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        timer += deltaTime;\n        if (timer >= 150) {\n            timer -= 150;\n            currentFrame = (currentFrame + 1) % 9;\n        }\n    }\n};\n
"},{"location":"reference/game_examples_guide/#patterns-used_6","title":"Patterns Used","text":"
  • Format Comparison: Shows different sprite formats
  • Animation Loop: Frame-based animation
  • Conditional Compilation: Uses build flags
"},{"location":"reference/game_examples_guide/#lessons-learned_6","title":"Lessons Learned","text":"
  • Advanced formats provide more color options
  • Animation is straightforward with frame arrays
  • Build flags enable/disable experimental features
"},{"location":"reference/game_examples_guide/#common-patterns-across-examples","title":"Common Patterns Across Examples","text":""},{"location":"reference/game_examples_guide/#screen-resolution","title":"Screen Resolution","text":"

All examples are configured for a 240x240 screen resolution.

"},{"location":"reference/game_examples_guide/#scene-initialization","title":"Scene Initialization","text":"

All examples follow this pattern:

void init() override {\n    // 1. Set palette\n    pixelroot32::graphics::setPalette(PaletteType::NES);\n\n    // 2. Create background entity\n    addEntity(new BackgroundEntity());\n\n    // 3. Create game entities\n    player = new PlayerActor(...);\n    addEntity(player);\n\n    // 4. Initialize game state\n    resetGame();\n}\n
"},{"location":"reference/game_examples_guide/#update-pattern","title":"Update Pattern","text":"
void update(unsigned long deltaTime) override {\n    // 1. Process input\n    handleInput();\n\n    // 2. Update game logic\n    updateGameLogic();\n\n    // 3. Call parent update (updates all entities)\n    Scene::update(deltaTime);\n\n    // 4. Post-update logic\n    checkGameState();\n}\n
"},{"location":"reference/game_examples_guide/#draw-pattern","title":"Draw Pattern","text":"
void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // 1. Apply camera (if used)\n    camera.apply(renderer);\n\n    // 2. Draw background/tilemap\n    renderer.drawTileMap(background, 0, 0, Color::White);\n\n    // 3. Call parent draw (draws all entities)\n    Scene::draw(renderer);\n\n    // 4. Draw UI/HUD\n    drawHUD(renderer);\n}\n
"},{"location":"reference/game_examples_guide/#learning-path","title":"Learning Path","text":""},{"location":"reference/game_examples_guide/#beginner-examples","title":"Beginner Examples","text":"
  1. Pong: Basic physics and collisions
  2. TicTacToe: Turn-based logic
  3. Snake: Entity pooling and grid
"},{"location":"reference/game_examples_guide/#intermediate-examples","title":"Intermediate Examples","text":"
  1. CameraDemo: Camera and parallax
  2. SpritesDemo: 2bpp and 4bpp formats
  3. BrickBreaker: Physics, particles and audio
"},{"location":"reference/game_examples_guide/#advanced-examples","title":"Advanced Examples","text":"
  1. Space Invaders: Full game (1bpp sprites, collisions, audio)
  2. Metroidvania: Platformer with multi-layer 4bpp tilemap, tile-based collision and ESP32 optimizations (no scroll/camera)
"},{"location":"reference/game_examples_guide/#code-study-recommendations","title":"Code Study Recommendations","text":""},{"location":"reference/game_examples_guide/#for-learning-physics","title":"For Learning Physics","text":"
  • Study Pong/BallActor.cpp - PhysicsActor usage
  • Study CameraDemo/PlayerCube.cpp - Platformer physics
"},{"location":"reference/game_examples_guide/#for-learning-collisions","title":"For Learning Collisions","text":"
  • Study SpaceInvaders - Complex collision layers
  • Study Pong - Simple collision response
"},{"location":"reference/game_examples_guide/#for-learning-memory-management","title":"For Learning Memory Management","text":"
  • Study Snake/SnakeScene.cpp - Entity pooling
  • Study SpaceInvaders - Projectile pooling
"},{"location":"reference/game_examples_guide/#for-learning-audio","title":"For Learning Audio","text":"
  • Study SpaceInvaders - Music and sound effects
  • Study Pong - Simple audio integration
"},{"location":"reference/game_examples_guide/#for-learning-ui","title":"For Learning UI","text":"
  • Study TicTacToe - Button-based UI
  • Study menu scenes - Layout usage
"},{"location":"reference/game_examples_guide/#extending-examples","title":"Extending Examples","text":""},{"location":"reference/game_examples_guide/#adding-features","title":"Adding Features","text":"
  • Pong: Add power-ups, multiple balls
  • Snake: Add obstacles, multiple food types
  • Space Invaders: Add boss battles, power-ups
"},{"location":"reference/game_examples_guide/#creating-variations","title":"Creating Variations","text":"
  • Pong: Make it vertical, add walls
  • Snake: Change to hexagonal grid
  • TicTacToe: Make it 4x4 or 5x5
"},{"location":"reference/game_examples_guide/#best-practices-from-examples","title":"Best Practices from Examples","text":"
  1. Pre-allocate Resources: All examples pre-allocate entities
  2. Use Object Pooling: For frequently created/destroyed entities
  3. Organize by Layers: Clear collision layer organization
  4. Separate Concerns: Game logic separate from rendering
  5. State Management: Clear game state handling
"},{"location":"reference/game_examples_guide/#see-also","title":"See Also","text":"
  • Code Examples - Reusable code snippets
  • API Reference Overview - Complete API documentation
  • Manual - Game Development - Detailed guides

Note: All example code is available in the src/examples/ directory of the PixelRoot32 Game Samples project.

"},{"location":"resources/available_tools/","title":"Available Tools","text":"

This guide documents tools available to facilitate PixelRoot32 game development.

"},{"location":"resources/available_tools/#sprite-compiler-pr32-sprite-compiler","title":"Sprite Compiler (pr32-sprite-compiler)","text":"

The Sprite Compiler converts PNG images to PixelRoot32 sprite data formats, making it easy to create sprites from image files.

Read more in the Sprite Compiler Guide

From Source:

git clone https://github.com/Gperez88/pr32-sprite-compiler.git\ncd pr32-sprite-compiler\nnpm install\nnpm link  # Optional: install globally\n

As NPM Package:

npm install -g pr32-sprite-compiler\n
"},{"location":"resources/available_tools/#basic-usage","title":"Basic Usage","text":"

Command Line:

pr32-sprite-compiler input.png output.h\n

With Options:

pr32-sprite-compiler input.png output.h --format 1bpp --name MY_SPRITE\n
"},{"location":"resources/available_tools/#supported-formats","title":"Supported Formats","text":"
  • 1bpp (default): Monochrome, most memory-efficient
  • 2bpp: 4 colors per sprite (requires PIXELROOT32_ENABLE_2BPP_SPRITES)
  • 4bpp: 16 colors per sprite (requires PIXELROOT32_ENABLE_4BPP_SPRITES)
"},{"location":"resources/available_tools/#output-format","title":"Output Format","text":"

The compiler generates C++ header files with sprite data:

// output.h\n#ifndef SPRITE_DATA_H\n#define SPRITE_DATA_H\n\n#include <stdint.h>\n\nstatic const uint16_t MY_SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    // ... more rows\n};\n\nstatic const pixelroot32::graphics::Sprite MY_SPRITE = {\n    MY_SPRITE_DATA,\n    8,  // width\n    8   // height\n};\n\n#endif\n
"},{"location":"resources/available_tools/#advanced-options","title":"Advanced Options","text":"

Batch Processing:

pr32-sprite-compiler --batch sprites/*.png --output-dir sprites/out/\n

Custom Palette:

pr32-sprite-compiler input.png output.h --palette custom_palette.json\n

Sprite Sheet:

pr32-sprite-compiler sheet.png output.h --sheet 8x8 --count 16\n
"},{"location":"resources/available_tools/#gui-version","title":"GUI Version","text":"

If available, a GUI version provides visual feedback:

  • Drag and drop images
  • Preview sprite data
  • Adjust settings visually
  • Export to header files
"},{"location":"resources/available_tools/#step-by-step-example","title":"Step-by-Step Example","text":"
  1. Create or find a PNG image (8x8, 16x16, etc.)

  2. Run the compiler:

pr32-sprite-compiler player.png player_sprite.h --name PLAYER_SPRITE\n
  1. Include in your project:
#include \"player_sprite.h\"\n\nvoid draw() {\n    renderer.drawSprite(PLAYER_SPRITE, 100, 100, Color::White);\n}\n
"},{"location":"resources/available_tools/#troubleshooting","title":"Troubleshooting","text":"

Image too large:

  • Sprites must be \u2264 16 pixels wide for 1bpp
  • Reduce image size or split into multiple sprites

Colors not converting correctly:

  • Ensure image uses indexed colors
  • Use black/white for 1bpp
  • Use 4 colors for 2bpp, 16 for 4bpp

Output file not found:

  • Check write permissions
  • Verify output path exists
"},{"location":"resources/available_tools/#future-tools","title":"Future Tools","text":""},{"location":"resources/available_tools/#music-compiler-planned","title":"Music Compiler (Planned)","text":"

A tool to convert music files or MIDI to PixelRoot32 MusicTrack format.

Planned Features:

  • MIDI to MusicTrack conversion
  • Visual music editor
  • Instrument preset management
  • Export to C++ header files
"},{"location":"resources/available_tools/#tilemap-compiler-planned","title":"Tilemap Compiler (Planned)","text":"

A tool to create tilemaps from image files or tile editors.

Planned Features:

  • Image to tilemap conversion
  • Tile editor integration
  • Export to C++ arrays
  • Collision data generation
"},{"location":"resources/available_tools/#other-planned-tools","title":"Other Planned Tools","text":"
  • Save System Generator: Generate save/load code
  • Asset Packer: Bundle assets for distribution
  • Performance Profiler: Analyze game performance
"},{"location":"resources/available_tools/#using-tools-in-development","title":"Using Tools in Development","text":""},{"location":"resources/available_tools/#workflow-integration","title":"Workflow Integration","text":"

Typical Workflow:

  1. Create/edit sprites in image editor
  2. Compile sprites to C++ headers
  3. Include headers in project
  4. Use sprites in code

Automation:

# Build script example\n#!/bin/bash\npr32-sprite-compiler assets/sprites/*.png --output-dir src/sprites/\n# Continue with build...\n
"},{"location":"resources/available_tools/#best-practices","title":"Best Practices","text":"
  • Organize assets: Keep source images separate from generated code
  • Version control: Commit generated headers, not source images (or both)
  • Naming conventions: Use consistent naming for sprites
  • Batch processing: Process multiple sprites at once when possible
"},{"location":"resources/available_tools/#see-also","title":"See Also","text":"
  • Sprite Compiler Documentation - Detailed sprite compiler guide
  • Manual - Sprites and Animation - Using sprites in games
  • Troubleshooting - Common tool issues

Note: Tool availability may vary. Check the PixelRoot32 repository for the latest tool information.

"},{"location":"resources/faq/","title":"Frequently Asked Questions","text":"

Common questions about PixelRoot32, organized by category.

"},{"location":"resources/faq/#general","title":"General","text":""},{"location":"resources/faq/#what-is-pixelroot32","title":"What is PixelRoot32?","text":"

PixelRoot32 is a lightweight, modular 2D game engine designed for ESP32 microcontrollers. It provides a complete game development framework with rendering, audio, physics, input, and UI systems, optimized for limited hardware resources.

"},{"location":"resources/faq/#what-platforms-does-it-support","title":"What platforms does it support?","text":"
  • ESP32: Primary platform (TFT displays, GPIO buttons, DAC/I2S audio)
  • Native/Desktop: Development platform (SDL2, keyboard, SDL2 audio)
"},{"location":"resources/faq/#what-kind-of-games-can-i-make","title":"What kind of games can I make?","text":"

PixelRoot32 is ideal for: - Retro/arcade-style games - 2D platformers - Shooters - Puzzle games - Simple RPGs - Educational games

See Limitations and Considerations for what's not suitable.

"},{"location":"resources/faq/#is-it-free-to-use","title":"Is it free to use?","text":"

Yes, PixelRoot32 is open source and licensed under the MIT License. You can use it freely for personal and commercial projects.

"},{"location":"resources/faq/#where-can-i-find-the-source-code","title":"Where can I find the source code?","text":"
  • Engine: https://github.com/Gperez88/PixelRoot32-Game-Engine
  • Samples: https://github.com/Gperez88/PixelRoot32-Game-Samples
  • Documentation: https://github.com/PixelRoot32-Game-Engine/PixelRoot32-Docs
"},{"location":"resources/faq/#installation-and-configuration","title":"Installation and Configuration","text":""},{"location":"resources/faq/#how-do-i-install-pixelroot32","title":"How do I install PixelRoot32?","text":"

See Your First Project for detailed installation instructions.

Quick answer: 1. Install PlatformIO in VS Code 2. Create new ESP32 project 3. Add library dependency: gperez88/PixelRoot32-Game-Engine@0.2.0-dev 4. Configure hardware in platformio.ini

"},{"location":"resources/faq/#what-version-should-i-use","title":"What version should I use?","text":"

Use the exact version 0.2.0-dev. Do NOT use ^ or fuzzy versioning, as the API may change.

"},{"location":"resources/faq/#how-do-i-configure-my-display","title":"How do I configure my display?","text":"

Configure TFT_eSPI via build flags in platformio.ini. See Your First Project for examples.

"},{"location":"resources/faq/#how-do-i-set-up-audio","title":"How do I set up audio?","text":"

Choose an audio backend: - ESP32_DAC: Simple, one pin (GPIO 25 or 26) - ESP32_I2S: Higher quality, requires external DAC - SDL2_AudioBackend: For Native/PC development

See Audio for details.

"},{"location":"resources/faq/#development","title":"Development","text":""},{"location":"resources/faq/#how-do-i-create-a-scene","title":"How do I create a scene?","text":"

Inherit from pixelroot32::core::Scene and implement init(), update(), and draw(). See Scenes and Entities.

"},{"location":"resources/faq/#how-do-i-add-entities-to-a-scene","title":"How do I add entities to a scene?","text":"

Create entities and call addEntity() in init(). The scene manages them automatically.

"},{"location":"resources/faq/#whats-the-difference-between-entity-actor-and-physicsactor","title":"What's the difference between Entity, Actor, and PhysicsActor?","text":"
  • Entity: Base class, can be drawn and updated
  • Actor: Entity with collision detection
  • PhysicsActor: Actor with automatic physics (velocity, gravity, friction)

See Scenes and Entities for details.

"},{"location":"resources/faq/#how-do-i-handle-input","title":"How do I handle input?","text":"

Access InputManager through the engine:

auto& input = engine.getInputManager();\nif (input.isButtonPressed(Buttons::A)) {\n    // Handle input\n}\n

See Input and Control.

"},{"location":"resources/faq/#how-do-i-play-sounds","title":"How do I play sounds?","text":"

Create an AudioEvent and play it:

pixelroot32::audio::AudioEvent sound{};\nsound.type = pixelroot32::audio::WaveType::PULSE;\nsound.frequency = 800.0f;\nsound.duration = 0.1f;\nengine.getAudioEngine().playEvent(sound);\n

See Audio.

"},{"location":"resources/faq/#how-do-i-create-sprites","title":"How do I create sprites?","text":"

Define sprite data manually or use the Sprite Compiler tool. See Sprites and Animation.

"},{"location":"resources/faq/#can-i-use-images-instead-of-manual-sprite-data","title":"Can I use images instead of manual sprite data?","text":"

Yes, use the Sprite Compiler tool to convert PNG images to sprite data. See Available Tools.

"},{"location":"resources/faq/#performance","title":"Performance","text":""},{"location":"resources/faq/#why-is-my-game-running-slowly","title":"Why is my game running slowly?","text":"

Common causes: - Too many entities (MAX_ENTITIES = 32) - Too many draw calls - Expensive calculations in update() - Memory issues

See Performance Tuning for solutions.

"},{"location":"resources/faq/#what-fps-should-i-target","title":"What FPS should I target?","text":"

30-60 FPS is typical. Lower complexity games can achieve 60 FPS, more complex games may need to target 30 FPS.

"},{"location":"resources/faq/#how-do-i-optimize-my-game","title":"How do I optimize my game?","text":"
  • Use object pooling
  • Implement viewport culling
  • Reduce entity count
  • Cache calculations
  • Use tilemaps for backgrounds

See Performance Tuning.

"},{"location":"resources/faq/#memory","title":"Memory","text":""},{"location":"resources/faq/#why-do-i-get-out-of-memory-errors","title":"Why do I get \"out of memory\" errors?","text":"

ESP32 has limited RAM (~320KB). Solutions: - Use object pooling - Store data in flash (const/constexpr) - Reduce entity count - Avoid dynamic allocation

See Memory Management.

"},{"location":"resources/faq/#what-is-max_entities","title":"What is MAX_ENTITIES?","text":"

MAX_ENTITIES = 32 is a hard limit per scene. This includes all entities: actors, UI elements, particles, etc.

Solutions: - Use object pooling to reuse entities - Disable entities instead of removing - Combine multiple entities into one

"},{"location":"resources/faq/#how-do-i-check-available-memory","title":"How do I check available memory?","text":"
#ifdef PLATFORM_ESP32\nSerial.print(\"Free heap: \");\nSerial.println(ESP.getFreeHeap());\n#endif\n
"},{"location":"resources/faq/#hardware","title":"Hardware","text":""},{"location":"resources/faq/#which-esp32-board-should-i-use","title":"Which ESP32 board should I use?","text":"

Any ESP32 board works. Common choices: - ESP32-WROOM-32 - ESP32-WROVER (more RAM) - ESP32-DevKit

"},{"location":"resources/faq/#which-display-should-i-use","title":"Which display should I use?","text":"

Popular choices: - ST7789: 240x240, good quality - ST7735: 128x128, smaller/cheaper - ILI9341: 240x320, larger

See Platforms and Drivers.

"},{"location":"resources/faq/#how-many-buttons-do-i-need","title":"How many buttons do I need?","text":"

Minimum: 4 (UP, DOWN, LEFT, RIGHT) Recommended: 6 (add A and B buttons) More buttons can be added if needed.

"},{"location":"resources/faq/#can-i-use-analog-joysticks","title":"Can I use analog joysticks?","text":"

Not directly supported. You can read analog pins manually and convert to digital input, but the engine expects digital buttons.

"},{"location":"resources/faq/#troubleshooting","title":"Troubleshooting","text":""},{"location":"resources/faq/#my-display-is-blank-whats-wrong","title":"My display is blank. What's wrong?","text":"
  1. Check wiring connections
  2. Verify pin numbers in platformio.ini
  3. Lower SPI frequency
  4. Check display type matches hardware
  5. Verify power supply

See Troubleshooting.

"},{"location":"resources/faq/#buttons-dont-work-why","title":"Buttons don't work. Why?","text":"
  1. Check button wiring
  2. Verify pin numbers in InputConfig
  3. Check pull-up/pull-down resistors
  4. Ensure InputManager is being updated
  5. Test with isButtonDown() vs isButtonPressed()
"},{"location":"resources/faq/#audio-is-distorted-how-do-i-fix-it","title":"Audio is distorted. How do I fix it?","text":"
  1. Lower volume levels
  2. Reduce sample rate (try 11025 Hz)
  3. Check for too many simultaneous sounds
  4. Verify hardware connections
  5. Check power supply
"},{"location":"resources/faq/#game-crashes-randomly-whats-happening","title":"Game crashes randomly. What's happening?","text":"

Common causes: - Out of memory - Too many entities - Infinite loops - Stack overflow - Watchdog timeout

See Troubleshooting for debugging techniques.

"},{"location":"resources/faq/#advanced","title":"Advanced","text":""},{"location":"resources/faq/#can-i-extend-the-engine","title":"Can I extend the engine?","text":"

Yes, PixelRoot32 is designed to be extensible. You can: - Create custom display drivers - Create custom audio backends - Extend existing systems

See Extensibility.

"},{"location":"resources/faq/#can-i-use-3d-graphics","title":"Can I use 3D graphics?","text":"

No, PixelRoot32 is 2D-only. It's designed for sprite-based 2D games.

"},{"location":"resources/faq/#can-i-add-networking","title":"Can I add networking?","text":"

Not currently supported. The engine focuses on single-player games.

"},{"location":"resources/faq/#can-i-save-game-data","title":"Can I save game data?","text":"

Not currently supported. A save system is planned for future versions.

"},{"location":"resources/faq/#can-i-use-multiple-scenes-at-once","title":"Can I use multiple scenes at once?","text":"

Yes, use SceneManager to push/pop scenes. This is useful for menus and pause screens.

"},{"location":"resources/faq/#getting-help","title":"Getting Help","text":""},{"location":"resources/faq/#where-can-i-get-help","title":"Where can I get help?","text":"
  • Documentation: This documentation site
  • Examples: Study example games in the samples project
  • Discord: Community Discord server
  • GitHub: Open an issue for bugs
"},{"location":"resources/faq/#how-do-i-report-a-bug","title":"How do I report a bug?","text":"

Create a detailed bug report with: - Platform (ESP32 or Native) - Hardware details - Minimal reproduction code - Error messages - Expected vs actual behavior

"},{"location":"resources/faq/#can-i-contribute","title":"Can I contribute?","text":"

Yes! PixelRoot32 is open source. Check the main repository for contribution guidelines.

"},{"location":"resources/faq/#see-also","title":"See Also","text":"
  • Troubleshooting - Detailed problem solving
  • Limitations and Considerations - What the engine can/can't do
  • Getting Started - Start here if you're new
  • Manual - Complete development guides

Can't find your question? Check the Troubleshooting guide or ask on the Discord server.

"},{"location":"resources/limitations_and_considerations/","title":"Limitations and Considerations","text":"

This document honestly documents what PixelRoot32 can and cannot do, helping you make informed decisions about using the engine.

"},{"location":"resources/limitations_and_considerations/#hardware-limitations-esp32","title":"Hardware Limitations (ESP32)","text":""},{"location":"resources/limitations_and_considerations/#memory-constraints","title":"Memory Constraints","text":"

RAM: - Available: ~320KB total (varies by ESP32 model) - Heap: Limited and fragmented over time - Stack: ~8KB, avoid large stack allocations - Impact: Limits entity count, sprite data, and dynamic allocation

Flash: - Available: 4MB+ (varies by model) - Usage: Program code, sprite data, assets - Impact: Large games may approach limits

Recommendations: - Use object pooling - Store data in flash (const/constexpr) - Avoid dynamic allocation in game loop - Keep entity count low

"},{"location":"resources/limitations_and_considerations/#cpu-limitations","title":"CPU Limitations","text":"

Performance: - Clock Speed: 240MHz (typically) - Single-threaded: One core handles everything - Target FPS: 30-60 FPS (depends on complexity) - Frame Budget: ~16-33ms per frame at 60 FPS

Impact: - Complex games may struggle - Many entities reduce performance - Expensive calculations hurt FPS

Recommendations: - Optimize rendering - Reduce entity count - Cache calculations - Profile on hardware

"},{"location":"resources/limitations_and_considerations/#display-limitations","title":"Display Limitations","text":"

Supported Displays: - TFT displays via SPI (ST7735, ST7789, ILI9341, etc.) - Limited to SPI displays - Resolution typically 128x128 to 320x240

Constraints: - SPI communication speed limits - Display initialization complexity - Power consumption

"},{"location":"resources/limitations_and_considerations/#audio-limitations","title":"Audio Limitations","text":"

Hardware: - Internal DAC: Lower quality, simple setup - I2S: Higher quality, requires external DAC - Sample rates: 11025 Hz (DAC) or 22050 Hz (I2S)

Constraints: - 4 channels total (2 Pulse, 1 Triangle, 1 Noise) - Music uses one channel - Limited simultaneous sounds - Quality limited by hardware

"},{"location":"resources/limitations_and_considerations/#software-limitations","title":"Software Limitations","text":""},{"location":"resources/limitations_and_considerations/#entity-system","title":"Entity System","text":"

MAX_ENTITIES = 32 per scene - Hard limit, cannot be changed easily - Applies to all entities (actors, UI, particles, etc.) - Must manage entity count carefully

Workarounds: - Use object pooling - Reuse entities - Disable entities instead of removing - Combine multiple entities into one

"},{"location":"resources/limitations_and_considerations/#no-rtti-runtime-type-information","title":"No RTTI (Runtime Type Information)","text":"

Impact: - Cannot use dynamic_cast in most code - Type checking must be done manually - Limits polymorphism patterns

Alternatives: - Use virtual functions - Manual type checking - Tag-based systems

"},{"location":"resources/limitations_and_considerations/#no-exceptions-in-critical-code","title":"No Exceptions in Critical Code","text":"

Impact: - Cannot use try/catch in game loop - Error handling must be explicit - Crashes instead of exceptions

Best Practices: - Validate inputs - Check return values - Use assertions for debugging - Handle errors explicitly

"},{"location":"resources/limitations_and_considerations/#no-dynamic-allocation-in-game-loop","title":"No Dynamic Allocation in Game Loop","text":"

Impact: - Cannot use new/delete during gameplay - Must pre-allocate resources - Limits flexibility

Solutions: - Object pooling - Pre-allocation in init() - Static buffers - Fixed-size arrays

"},{"location":"resources/limitations_and_considerations/#no-advanced-features","title":"No Advanced Features","text":"

Not Supported: - 3D graphics - Shaders - Advanced physics (joints, constraints) - Networking - File system (ESP32) - Advanced audio effects

Focus: - 2D sprite-based games - Simple physics - Retro-style games - Embedded-friendly features

"},{"location":"resources/limitations_and_considerations/#experimental-features","title":"Experimental Features","text":""},{"location":"resources/limitations_and_considerations/#2bpp-sprites","title":"2bpp Sprites","text":"

Status: Experimental - Requires PIXELROOT32_ENABLE_2BPP_SPRITES flag - May have bugs or limitations - Not fully tested

Use with caution: - Test thoroughly - May change in future versions - Report issues if found

"},{"location":"resources/limitations_and_considerations/#4bpp-sprites","title":"4bpp Sprites","text":"

Status: Experimental - Requires PIXELROOT32_ENABLE_4BPP_SPRITES flag - More experimental than 2bpp - Higher memory usage

Use with caution: - Test extensively - Monitor memory usage - May be unstable

"},{"location":"resources/limitations_and_considerations/#scene-arena","title":"Scene Arena","text":"

Status: Experimental - Requires PIXELROOT32_ENABLE_SCENE_ARENA flag - Alternative memory management - May have bugs

Recommendations: - Use object pooling instead (more stable) - Test thoroughly if using - May be removed or changed

"},{"location":"resources/limitations_and_considerations/#unsupported-features-current","title":"Unsupported Features (Current)","text":""},{"location":"resources/limitations_and_considerations/#planned-but-not-available","title":"Planned but Not Available","text":"
  • u8g2 Driver: Alternative display driver (planned)
  • Music Compiler: Tool to convert music files (planned)
  • Tilemap Compiler: Tool to create tilemaps (planned)
  • Save System: Persistent storage system (planned)
  • Spatial Partitioning: Advanced collision optimization (planned)
"},{"location":"resources/limitations_and_considerations/#not-planned","title":"Not Planned","text":"
  • 3D Graphics: 2D-only engine
  • Networking: No network support
  • File System: No file I/O on ESP32
  • Advanced Audio: NES-like audio only
  • Scripting: No Lua/JavaScript support
"},{"location":"resources/limitations_and_considerations/#best-practices-for-esp32","title":"Best Practices for ESP32","text":""},{"location":"resources/limitations_and_considerations/#memory-management","title":"Memory Management","text":"
  • Pre-allocate: All resources in init()
  • Object pooling: Reuse entities
  • Flash storage: Use const/constexpr for data
  • Avoid strings: Use static buffers
  • Monitor usage: Check heap regularly
"},{"location":"resources/limitations_and_considerations/#performance","title":"Performance","text":"
  • Limit entities: Stay well below MAX_ENTITIES
  • Optimize rendering: Use culling, batching
  • Cache calculations: Avoid repeated work
  • Profile on hardware: PC performance \u2260 ESP32
"},{"location":"resources/limitations_and_considerations/#development","title":"Development","text":"
  • Test on hardware: Don't rely only on Native
  • Start simple: Add complexity gradually
  • Monitor memory: Watch for leaks
  • Optimize incrementally: Profile and optimize
"},{"location":"resources/limitations_and_considerations/#what-pixelroot32-is-good-for","title":"What PixelRoot32 IS Good For","text":"

\u2705 Retro-style 2D games \u2705 Arcade games \u2705 Puzzle games \u2705 Platformers \u2705 Shooters \u2705 Educational projects \u2705 Prototyping \u2705 Embedded game development

"},{"location":"resources/limitations_and_considerations/#what-pixelroot32-is-not-good-for","title":"What PixelRoot32 is NOT Good For","text":"

\u274c 3D games \u274c Complex physics simulations \u274c Large open worlds \u274c Games requiring many entities \u274c Games with complex graphics \u274c Network multiplayer \u274c Games requiring file I/O

"},{"location":"resources/limitations_and_considerations/#making-informed-decisions","title":"Making Informed Decisions","text":""},{"location":"resources/limitations_and_considerations/#before-starting-a-project","title":"Before Starting a Project","text":"
  1. Assess requirements: Does PixelRoot32 fit?
  2. Check limitations: Can you work within constraints?
  3. Plan architecture: Design around limitations
  4. Test early: Verify on hardware early
"},{"location":"resources/limitations_and_considerations/#if-limitations-are-a-problem","title":"If Limitations Are a Problem","text":"

Consider alternatives: - Full game engines (Unity, Godot) for complex games - Custom solutions for specific needs - Different hardware for more resources

Or work within limits: - Simplify game design - Optimize aggressively - Use creative solutions

"},{"location":"resources/limitations_and_considerations/#version-compatibility","title":"Version Compatibility","text":""},{"location":"resources/limitations_and_considerations/#current-version","title":"Current Version","text":"
  • Engine Version: 0.2.0-dev
  • API Stability: May change
  • Breaking Changes: Possible in future versions

Recommendations: - Pin exact version in platformio.ini - Don't use ^ or fuzzy versioning - Test after engine updates - Review changelog

"},{"location":"resources/limitations_and_considerations/#honest-assessment","title":"Honest Assessment","text":"

PixelRoot32 is designed for: - Simple to medium complexity games - Retro/arcade style - ESP32 hardware constraints - Rapid development

It is not designed for: - AAA game complexity - Modern graphics - Large-scale games - Unlimited resources

"},{"location":"resources/limitations_and_considerations/#see-also","title":"See Also","text":"
  • Memory Management - Working with memory limits
  • Performance Tuning - Optimizing performance
  • Troubleshooting - Solving problems
  • FAQ - Common questions

Remember: Understanding limitations helps you build better games within PixelRoot32's capabilities.

"},{"location":"resources/troubleshooting/","title":"Troubleshooting","text":"

This guide helps you diagnose and fix common issues when developing with PixelRoot32.

"},{"location":"resources/troubleshooting/#compilation-problems","title":"Compilation Problems","text":""},{"location":"resources/troubleshooting/#common-compilation-errors","title":"Common Compilation Errors","text":"

Error: Library not found

Solution: Ensure PixelRoot32-Game-Engine is properly installed\n- Check platformio.ini has correct lib_deps\n- Verify library version matches (use exact version, not ^)\n- Try: pio lib install\n

Error: Include file not found

Solution: Check include paths\n- Verify lib_extra_dirs in platformio.ini\n- Check that library is in lib/ directory\n- Ensure correct namespace (pixelroot32::)\n

Error: Undefined reference

Solution: Link missing libraries\n- Check all required libraries are listed\n- Verify TFT_eSPI is installed for ESP32\n- Check SDL2 is installed for Native builds\n

Error: Build flags not recognized

Solution: Verify build flag syntax\n- Use -D FLAG_NAME (not --define)\n- Check flag names are correct\n- Ensure flags are in correct environment section\n

"},{"location":"resources/troubleshooting/#configuration-issues","title":"Configuration Issues","text":"

Wrong display type: - Verify DisplayType matches your hardware - Check TFT_eSPI build flags match display - Test with different display types

Incorrect pin configuration: - Verify GPIO pins match your wiring - Check pin numbers in platformio.ini - Ensure pins aren't used by other peripherals

"},{"location":"resources/troubleshooting/#hardware-problems-esp32","title":"Hardware Problems (ESP32)","text":""},{"location":"resources/troubleshooting/#display-not-working","title":"Display Not Working","text":"

Symptoms: - Blank screen - Garbled display - No output

Solutions: 1. Check wiring: - Verify SPI connections (MOSI, SCLK, DC, RST) - Check power supply (3.3V or 5V as required) - Ensure ground connections

  1. Verify configuration:
  2. Check display type matches hardware
  3. Verify pin numbers in platformio.ini
  4. Test with known working configuration

  5. SPI frequency:

  6. Lower SPI frequency (try 20MHz instead of 40MHz)
  7. Some displays need slower speeds
  8. Check display datasheet for max frequency

  9. Display initialization:

  10. Try different rotation values
  11. Check display width/height settings
  12. Verify TFT_eSPI driver is correct
"},{"location":"resources/troubleshooting/#buttons-not-responding","title":"Buttons Not Responding","text":"

Symptoms: - No input detected - Buttons don't trigger actions - Input feels laggy

Solutions: 1. Check wiring: - Verify button connections to GPIO pins - Check pull-up/pull-down resistors - Test buttons with multimeter

  1. Verify pin configuration:
  2. Check InputConfig pin numbers
  3. Ensure pins match hardware
  4. Verify pins aren't used elsewhere

  5. Input debouncing:

  6. Add hardware debouncing (capacitor)
  7. Check InputManager is being updated
  8. Verify input is read in update(), not draw()

  9. Button logic:

  10. Test with isButtonDown() vs isButtonPressed()
  11. Check button indices match configuration
  12. Verify input is accessed correctly
"},{"location":"resources/troubleshooting/#audio-not-working","title":"Audio Not Working","text":"

Symptoms: - No sound output - Distorted audio - Audio glitches

Solutions: 1. DAC Configuration: - Verify DAC pin (25 or 26 for ESP32) - Check sample rate (11025 Hz recommended) - Ensure audio backend is initialized

  1. I2S Configuration:
  2. Verify I2S pin connections (BCLK, LRCK, DOUT)
  3. Check external DAC is powered
  4. Verify I2S DAC is compatible

  5. Audio quality:

  6. Lower sample rate if distorted
  7. Reduce volume levels
  8. Check for too many simultaneous sounds
  9. Verify audio buffer size

  10. Hardware:

  11. Check speaker connections
  12. Verify amplifier is powered
  13. Test with different audio hardware
  14. Check audio cable connections
"},{"location":"resources/troubleshooting/#power-issues","title":"Power Issues","text":"

Symptoms: - ESP32 resets randomly - Display flickers - Unstable operation

Solutions: 1. Power supply: - Use adequate power supply (500mA+ recommended) - Check voltage is stable (3.3V) - Add decoupling capacitors

  1. Current draw:
  2. Display draws significant current
  3. Audio amplifier adds load
  4. Reduce brightness if possible

  5. Wiring:

  6. Use thick wires for power
  7. Keep power wires short
  8. Add capacitors near ESP32
"},{"location":"resources/troubleshooting/#performance-problems","title":"Performance Problems","text":""},{"location":"resources/troubleshooting/#low-fps","title":"Low FPS","text":"

Symptoms: - Game runs slowly - Laggy movement - Stuttering

Solutions: 1. Reduce entity count: - Limit active entities (MAX_ENTITIES = 32) - Disable off-screen entities - Use object pooling

  1. Optimize rendering:
  2. Use viewport culling
  3. Reduce draw calls
  4. Use tilemaps instead of individual sprites
  5. Limit sprite count

  6. Simplify logic:

  7. Cache expensive calculations
  8. Reduce collision checks
  9. Lower update frequency for non-critical entities

  10. Check hardware:

  11. Verify ESP32 is running at full speed (240MHz)
  12. Check for thermal throttling
  13. Ensure adequate power supply
"},{"location":"resources/troubleshooting/#frame-drops","title":"Frame Drops","text":"

Symptoms: - Occasional stuttering - Inconsistent frame times - Periodic freezes

Solutions: 1. Identify bottlenecks: - Profile frame time - Check for expensive operations - Look for blocking code

  1. Optimize update loop:
  2. Avoid dynamic allocation
  3. Cache calculations
  4. Reduce string operations

  5. Memory issues:

  6. Check for memory leaks
  7. Reduce memory usage
  8. Use object pooling
"},{"location":"resources/troubleshooting/#freezescrashes","title":"Freezes/Crashes","text":"

Symptoms: - Game stops responding - ESP32 resets - Watchdog resets

Solutions: 1. Memory issues: - Check available heap memory - Reduce entity count - Avoid dynamic allocation - Use object pooling

  1. Infinite loops:
  2. Check for infinite loops in update()
  3. Verify collision detection doesn't loop
  4. Check animation logic

  5. Stack overflow:

  6. Avoid large stack allocations
  7. Reduce recursion depth
  8. Move large data to heap (carefully)

  9. Watchdog:

  10. Ensure update() completes quickly
  11. Add yield() calls if needed
  12. Check for blocking operations
"},{"location":"resources/troubleshooting/#memory-problems","title":"Memory Problems","text":""},{"location":"resources/troubleshooting/#out-of-memory","title":"Out of Memory","text":"

Symptoms: - Compilation fails - Runtime crashes - \"Allocation failed\" errors

Solutions: 1. Reduce memory usage: - Use 1bpp sprites instead of 2bpp/4bpp - Store data in flash (const/constexpr) - Reduce entity count - Use object pooling

  1. Optimize data:
  2. Reuse sprites
  3. Compress tilemap data
  4. Remove unused code/data

  5. Memory management:

  6. Avoid dynamic allocation in game loop
  7. Pre-allocate all resources
  8. Use static buffers
"},{"location":"resources/troubleshooting/#memory-fragmentation","title":"Memory Fragmentation","text":"

Symptoms: - Gradual performance degradation - Allocation failures over time - Crashes after running for a while

Solutions: 1. Use object pooling: - Pre-allocate entities - Reuse objects instead of creating/destroying - Avoid frequent new/delete

  1. Pre-allocate resources:
  2. Allocate everything in init()
  3. Use fixed-size arrays
  4. Avoid dynamic containers
"},{"location":"resources/troubleshooting/#native-build-problems","title":"Native Build Problems","text":""},{"location":"resources/troubleshooting/#sdl2-not-found","title":"SDL2 Not Found","text":"

Symptoms: - Compilation fails - Linker errors - Missing SDL2 symbols

Solutions: 1. Install SDL2: - Windows (MSYS2): pacman -S mingw-w64-x86_64-SDL2 - Linux: sudo apt-get install libsdl2-dev - macOS: brew install sdl2

  1. Check paths:
  2. Verify include paths in platformio.ini
  3. Check library paths
  4. Ensure SDL2 version is compatible

  5. Linker flags:

  6. Verify -lSDL2 is in build flags
  7. Check library search paths
  8. Ensure SDL2 DLL is accessible (Windows)
"},{"location":"resources/troubleshooting/#window-not-opening","title":"Window Not Opening","text":"

Symptoms: - Program runs but no window - Console shows errors - Immediate exit

Solutions: 1. Check SDL2 initialization: - Verify SDL2 is properly initialized - Check for SDL2 error messages - Ensure display config is correct

  1. Graphics drivers:
  2. Update graphics drivers
  3. Check SDL2 video backend
  4. Test with simple SDL2 program

  5. Console output:

  6. Run from terminal to see errors
  7. Check for error messages
  8. Verify SDL2 is working
"},{"location":"resources/troubleshooting/#debugging-techniques","title":"Debugging Techniques","text":""},{"location":"resources/troubleshooting/#serial-debugging-esp32","title":"Serial Debugging (ESP32)","text":"
void setup() {\n    Serial.begin(115200);\n    // ... initialization\n\n    Serial.println(\"Engine initialized\");\n}\n\nvoid update(unsigned long deltaTime) override {\n    // Debug output\n    if (frameCount % 60 == 0) {\n        Serial.print(\"FPS: \");\n        Serial.println(1000.0f / deltaTime);\n    }\n    frameCount++;\n}\n
"},{"location":"resources/troubleshooting/#memory-monitoring","title":"Memory Monitoring","text":"
#ifdef PLATFORM_ESP32\n#include <Arduino.h>\n\nvoid checkMemory() {\n    Serial.print(\"Free heap: \");\n    Serial.println(ESP.getFreeHeap());\n    Serial.print(\"Largest block: \");\n    Serial.println(ESP.getMaxAllocHeap());\n}\n#endif\n
"},{"location":"resources/troubleshooting/#performance-profiling","title":"Performance Profiling","text":"
class Profiler {\nprivate:\n    unsigned long updateTime = 0;\n    unsigned long drawTime = 0;\n\npublic:\n    void startUpdate() {\n        updateTime = micros();\n    }\n\n    void endUpdate() {\n        updateTime = micros() - updateTime;\n    }\n\n    void log() {\n        Serial.print(\"Update: \");\n        Serial.print(updateTime);\n        Serial.print(\"us, Draw: \");\n        Serial.println(drawTime);\n    }\n};\n
"},{"location":"resources/troubleshooting/#visual-debugging","title":"Visual Debugging","text":"
  • Draw hitboxes: Visualize collision boxes
  • Show FPS: Display frame rate on screen
  • Entity count: Show active entity count
  • Memory usage: Display memory statistics
"},{"location":"resources/troubleshooting/#common-patterns-for-debugging","title":"Common Patterns for Debugging","text":""},{"location":"resources/troubleshooting/#isolate-the-problem","title":"Isolate the Problem","text":"
  1. Minimal reproduction: Create smallest code that shows issue
  2. Disable features: Turn off systems one by one
  3. Test incrementally: Add features back one at a time
"},{"location":"resources/troubleshooting/#check-the-basics","title":"Check the Basics","text":"
  1. Verify initialization: Ensure engine.init() is called
  2. Check scene setup: Verify scene is set and initialized
  3. Test on both platforms: Compare ESP32 vs Native behavior
  4. Review recent changes: What changed before the issue?
"},{"location":"resources/troubleshooting/#use-logging","title":"Use Logging","text":"
#define DEBUG_MODE\n\n#ifdef DEBUG_MODE\n    #define DEBUG_LOG(x) Serial.println(x)\n#else\n    #define DEBUG_LOG(x)\n#endif\n\n// Usage\nDEBUG_LOG(\"Entity created\");\nDEBUG_LOG(\"Collision detected\");\n
"},{"location":"resources/troubleshooting/#getting-help","title":"Getting Help","text":"

If you can't resolve an issue:

  1. Check documentation: Review relevant guides
  2. Search examples: Look at example games
  3. Review code: Check engine source code
  4. Community: Ask on Discord or GitHub
  5. Report issue: Create detailed bug report
"},{"location":"resources/troubleshooting/#bug-report-template","title":"Bug Report Template","text":"

When reporting issues, include:

  • Platform: ESP32 or Native
  • Hardware: Display type, ESP32 model
  • Code: Minimal reproduction code
  • Error messages: Full error output
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Steps to reproduce: How to trigger the issue
"},{"location":"resources/troubleshooting/#see-also","title":"See Also","text":"
  • Limitations and Considerations - Known limitations
  • Performance Tuning - Performance optimization
  • Memory Management - Memory optimization
  • FAQ - Frequently asked questions

Note: Many issues are configuration-related. Double-check your setup before assuming a bug.

"},{"location":"tools/sprite_compiler/advanced_features/","title":"Sprite Compiler Advanced Features","text":"

Advanced features and options for the PixelRoot32 Sprite Compiler to optimize sprite conversion and handle complex scenarios.

"},{"location":"tools/sprite_compiler/advanced_features/#automatic-palette-detection","title":"Automatic Palette Detection","text":"

The Sprite Compiler automatically detects if your sprite uses one of the engine's built-in palettes. This simplifies your workflow and ensures color consistency.

"},{"location":"tools/sprite_compiler/advanced_features/#predefined-engine-palettes","title":"Predefined Engine Palettes","text":"

The engine includes 5 optimized palettes: - PR32 (Default PixelRoot32 palette) - NES (Nintendo style) - GB (GameBoy style) - GBC (GameBoy Color style) - PICO8 (Fantasy console style)

"},{"location":"tools/sprite_compiler/advanced_features/#how-it-works","title":"How it works","text":"
  1. Detection: When you compile an image, the tool compares all unique colors found in the sprite with the colors in the 5 engine palettes.
  2. Match: If all colors in your sprite belong to one of these palettes, the compiler:
  3. Omits generating a color array in the header.
  4. Assumes you will use the engine's built-in palette definitions at runtime.
  5. Custom Palette: If your sprite uses colors not found in the engine palettes, it automatically generates a {PREFIX}_PALETTE_MAPPING[16] array in the header file.
"},{"location":"tools/sprite_compiler/advanced_features/#naming-with-prefixes","title":"Naming with Prefixes","text":"

You can organize your generated code by using the --prefix parameter (or the Prefix field in the GUI).

"},{"location":"tools/sprite_compiler/advanced_features/#using-prefixes","title":"Using Prefixes","text":"

By default, sprites are named SPRITE_N_.... Using a prefix allows you to create more descriptive names and avoid naming collisions.

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --prefix PLAYER_JUM\n

Generated names will follow this pattern: - PLAYER_JUM_SPRITE_0_LAYER_0 - PLAYER_JUM_SPRITE_0_2BPP - PLAYER_JUM_SPRITE_0_4BPP - PLAYER_JUM_PALETTE_MAPPING (if a custom palette is used)

"},{"location":"tools/sprite_compiler/advanced_features/#export-modes","title":"Export Modes","text":""},{"location":"tools/sprite_compiler/advanced_features/#layered-1bpp","title":"Layered (1bpp)","text":"

Best for standard PixelRoot32 rendering. It extracts each color into its own bitmask (1bpp). The engine then renders these layers sequentially.

"},{"location":"tools/sprite_compiler/advanced_features/#packed-2bpp-4bpp","title":"Packed (2bpp / 4bpp)","text":"

Generates a single packed array where each pixel uses multiple bits. - 2bpp: 4 colors max (Index 0 is always transparent). - 4bpp: 16 colors max (Index 0 is always transparent).

These modes are more efficient for sprites with many colors as they require only a single draw call.

"},{"location":"tools/sprite_compiler/installation/","title":"Sprite Compiler Installation","text":"

This guide walks you through installing the PixelRoot32 Sprite Compiler on your system.

"},{"location":"tools/sprite_compiler/installation/#prerequisites","title":"Prerequisites","text":""},{"location":"tools/sprite_compiler/installation/#required-software","title":"Required Software","text":"
  • Python: Version 3.8 or higher
  • pip: Usually included with Python
"},{"location":"tools/sprite_compiler/installation/#verify-prerequisites","title":"Verify Prerequisites","text":"

Check if Python is installed:

python --version\n# Should show 3.8.0 or higher\n

Check if pip is installed:

pip --version\n# Should show version number\n

If not installed, download from python.org

"},{"location":"tools/sprite_compiler/installation/#installation-methods","title":"Installation Methods","text":""},{"location":"tools/sprite_compiler/installation/#method-1-from-source-recommended","title":"Method 1: From Source (Recommended)","text":""},{"location":"tools/sprite_compiler/installation/#step-1-clone-repository","title":"Step 1: Clone Repository","text":"
git clone https://github.com/Gperez88/PixelRoot32-Sprite-Compiler.git\ncd PixelRoot32-Sprite-Compiler\n
"},{"location":"tools/sprite_compiler/installation/#step-2-install-dependencies","title":"Step 2: Install Dependencies","text":"
pip install -r requirements.txt\n
"},{"location":"tools/sprite_compiler/installation/#step-3-verify-installation","title":"Step 3: Verify Installation","text":"
python main.py --help\n
"},{"location":"tools/sprite_compiler/installation/#method-2-standalone-executable-windows","title":"Method 2: Standalone Executable (Windows)","text":"

If you are on Windows, you can download the latest standalone .exe from the Releases section of the repository. This does not require Python or any dependencies to be installed.

"},{"location":"tools/sprite_compiler/installation/#platform-specific-instructions","title":"Platform-Specific Instructions","text":""},{"location":"tools/sprite_compiler/installation/#windows","title":"Windows","text":""},{"location":"tools/sprite_compiler/installation/#using-npm-recommended","title":"Using npm (Recommended)","text":"
  1. Install Node.js from nodejs.org
  2. Download the Windows installer
  3. Run the installer
  4. Restart your terminal/command prompt

  5. Open Command Prompt or PowerShell

  6. Install globally:

    npm install -g pr32-sprite-compiler\n

  7. Verify:

    pr32-sprite-compiler --version\n

"},{"location":"tools/sprite_compiler/installation/#troubleshooting-windows-issues","title":"Troubleshooting Windows Issues","text":"

\"pr32-sprite-compiler is not recognized\": - Ensure Node.js is in your PATH - Restart terminal after installation - Try using full path: C:\\Users\\YourName\\AppData\\Roaming\\npm\\pr32-sprite-compiler.cmd

Permission errors: - Run terminal as Administrator - Or install locally: npm install pr32-sprite-compiler (without -g)

"},{"location":"tools/sprite_compiler/installation/#linux","title":"Linux","text":""},{"location":"tools/sprite_compiler/installation/#using-npm","title":"Using npm","text":"
  1. Install Node.js (if not already installed):

Ubuntu/Debian:

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -\nsudo apt-get install -y nodejs\n

Fedora/RHEL:

sudo dnf install nodejs npm\n

  1. Install Sprite Compiler:

    sudo npm install -g pr32-sprite-compiler\n

  2. Verify:

    pr32-sprite-compiler --version\n

"},{"location":"tools/sprite_compiler/installation/#troubleshooting-linux-issues","title":"Troubleshooting Linux Issues","text":"

Permission denied: - Use sudo for global installation - Or install locally without -g flag

Command not found: - Check npm global bin path: npm config get prefix - Add to PATH if needed: export PATH=$PATH:$(npm config get prefix)/bin

"},{"location":"tools/sprite_compiler/installation/#macos","title":"macOS","text":""},{"location":"tools/sprite_compiler/installation/#using-npm_1","title":"Using npm","text":"
  1. Install Node.js:
  2. Download from nodejs.org
  3. Or use Homebrew: brew install node

  4. Install Sprite Compiler:

    npm install -g pr32-sprite-compiler\n

  5. Verify:

    pr32-sprite-compiler --version\n

"},{"location":"tools/sprite_compiler/installation/#using-homebrew-alternative","title":"Using Homebrew (Alternative)","text":"

If available as a Homebrew formula:

brew install pr32-sprite-compiler\n

"},{"location":"tools/sprite_compiler/installation/#gui-version-installation","title":"GUI Version Installation","text":"

If a GUI version is available:

"},{"location":"tools/sprite_compiler/installation/#windows_1","title":"Windows","text":"

Download the installer from the releases page and run it.

"},{"location":"tools/sprite_compiler/installation/#linux_1","title":"Linux","text":"
# Download AppImage or .deb package\n# Make executable and run\nchmod +x pr32-sprite-compiler-gui.AppImage\n./pr32-sprite-compiler-gui.AppImage\n
"},{"location":"tools/sprite_compiler/installation/#macos_1","title":"macOS","text":"

Download the .dmg file from releases and install.

"},{"location":"tools/sprite_compiler/installation/#verification","title":"Verification","text":"

After installation, verify everything works:

"},{"location":"tools/sprite_compiler/installation/#test-basic-functionality","title":"Test Basic Functionality","text":"
  1. Create a test image:
  2. Create an 8x8 pixel PNG image (black and white)
  3. Save as test.png

  4. Run compiler:

    pr32-sprite-compiler test.png test_output.h\n

  5. Check output:

  6. File test_output.h should be created
  7. Should contain sprite data arrays
"},{"location":"tools/sprite_compiler/installation/#check-version","title":"Check Version","text":"
pr32-sprite-compiler --version\n
"},{"location":"tools/sprite_compiler/installation/#check-help","title":"Check Help","text":"
pr32-sprite-compiler --help\n
"},{"location":"tools/sprite_compiler/installation/#updating","title":"Updating","text":""},{"location":"tools/sprite_compiler/installation/#update-via-npm","title":"Update via npm","text":"
npm update -g pr32-sprite-compiler\n
"},{"location":"tools/sprite_compiler/installation/#update-from-source","title":"Update from Source","text":"
cd pr32-sprite-compiler\ngit pull\nnpm install\n
"},{"location":"tools/sprite_compiler/installation/#uninstallation","title":"Uninstallation","text":""},{"location":"tools/sprite_compiler/installation/#remove-global-installation","title":"Remove Global Installation","text":"
npm uninstall -g pr32-sprite-compiler\n
"},{"location":"tools/sprite_compiler/installation/#remove-local-installation","title":"Remove Local Installation","text":"
npm uninstall pr32-sprite-compiler\n
"},{"location":"tools/sprite_compiler/installation/#troubleshooting","title":"Troubleshooting","text":""},{"location":"tools/sprite_compiler/installation/#common-issues","title":"Common Issues","text":"

\"Command not found\" after installation: - Restart your terminal - Check npm global bin path: npm config get prefix - Verify PATH includes npm bin directory

Permission errors: - On Linux/macOS: Use sudo for global install - Or install locally without -g flag - On Windows: Run terminal as Administrator

Module not found errors: - Reinstall: npm install -g pr32-sprite-compiler - Clear npm cache: npm cache clean --force

Version conflicts: - Check Node.js version: node --version - Update Node.js if version is too old - Use nvm (Node Version Manager) to manage versions

"},{"location":"tools/sprite_compiler/installation/#getting-help","title":"Getting Help","text":"
  • Check the Usage Guide for usage examples
  • Review Troubleshooting for common issues
  • Open an issue on GitHub if problems persist
"},{"location":"tools/sprite_compiler/installation/#next-steps","title":"Next Steps","text":"

Once installed, proceed to: - Usage Guide - Learn how to use the compiler - Advanced Features - Explore advanced options

"},{"location":"tools/sprite_compiler/installation/#see-also","title":"See Also","text":"
  • Overview - What the Sprite Compiler does
  • Available Tools - All PixelRoot32 tools
"},{"location":"tools/sprite_compiler/overview/","title":"Sprite Compiler Overview","text":"

The Sprite Compiler is a tool that converts PNG images into PixelRoot32 sprite data formats. It provides both a graphical interface (GUI) and a command-line interface (CLI) to automate the process of creating sprite arrays from image files.

"},{"location":"tools/sprite_compiler/overview/#what-it-does","title":"What It Does","text":"

The Sprite Compiler takes bitmap images (PNG) and converts them into C header files containing:

  • Sprite data arrays: Optimized uint16_t arrays for various formats.
  • Layered support: Generates multiple 1bpp layers for complex sprites.
  • Packed formats: Supports 2bpp and 4bpp packed formats.
  • Sprite sheets: Handles grid-based sprite sheets with auto-detection.
"},{"location":"tools/sprite_compiler/overview/#key-features","title":"Key Features","text":""},{"location":"tools/sprite_compiler/overview/#format-support","title":"\u2705 Format Support","text":"
  • Layered (1bpp): Standard format, generates one array per color.
  • 2bpp (4 colors): Packed format, 2 bits per pixel.
  • 4bpp (16 colors): Packed format, 4 bits per pixel.
"},{"location":"tools/sprite_compiler/overview/#gui-cli","title":"\u2705 GUI & CLI","text":"
  • Modern GUI: Step-by-step card-based interface for easy configuration.
  • Powerful CLI: Perfect for build scripts and automation.
"},{"location":"tools/sprite_compiler/overview/#sprite-sheets","title":"\u2705 Sprite Sheets","text":"

Automatically split sprite sheets into individual sprites:

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --sprite 1,0,1,1 --out output.h\n

"},{"location":"tools/sprite_compiler/overview/#gui-interface","title":"GUI Interface","text":"

The GUI is designed to be intuitive and follows a 5-step process:

  1. Input Image: Select your PNG source.
  2. Grid Settings: Define the cell size and offsets.
  3. Sprite Selection: Pick which cells to export.
  4. Export Settings: Choose the mode (Layered, 2bpp, 4bpp), set a Prefix, and choose the output path.
  5. About: Quick access to version info and credits (via the ? button).
  6. Log: Technical feedback and performance alerts.
"},{"location":"tools/sprite_compiler/overview/#input-requirements","title":"Input Requirements","text":""},{"location":"tools/sprite_compiler/overview/#supported-formats","title":"Supported Formats","text":"
  • PNG: Primary format (recommended)
  • Indexed color PNG: Best for 1bpp conversion
  • Grayscale PNG: Automatically converted to 1bpp
  • RGB PNG: Converted using threshold or palette
"},{"location":"tools/sprite_compiler/overview/#image-constraints","title":"Image Constraints","text":"

For 1bpp sprites: - Maximum width: 16 pixels - Height: Any (typically 8, 16, 32 pixels) - Colors: Black and white (or converted automatically)

For 2bpp sprites: - Maximum width: 16 pixels - Colors: Up to 4 colors

For 4bpp sprites: - Maximum width: 16 pixels - Colors: Up to 16 colors

"},{"location":"tools/sprite_compiler/overview/#output-format","title":"Output Format","text":"

The compiler generates C header files with optimized arrays:

// Generated by PixelRoot32 Sprite Compiler\n\n// Optional palette mapping if using custom colors\nstatic const Color PLAYER_PALETTE_MAPPING[16] = {\n    (Color)0, (Color)1, (Color)2, (Color)3,\n    // ...\n};\n\n// Sprite data array (4bpp example)\nstatic const uint16_t PLAYER_SPRITE_0_4BPP[] = {\n    0x0000, 0x1234, 0x5678, // Row 0\n    // ... more rows\n};\n
"},{"location":"tools/sprite_compiler/overview/#use-cases","title":"Use Cases","text":""},{"location":"tools/sprite_compiler/overview/#1-single-sprite-conversion","title":"1. Single Sprite Conversion","text":"

Convert a single image to a sprite:

pr32-sprite-compiler player.png player_sprite.h --name PLAYER_SPRITE\n

"},{"location":"tools/sprite_compiler/overview/#2-animation-frames","title":"2. Animation Frames","text":"

Convert multiple frames for animation:

pr32-sprite-compiler --batch walk_*.png --output-dir animations/ --prefix WALK_\n

"},{"location":"tools/sprite_compiler/overview/#3-sprite-sheet-processing","title":"3. Sprite Sheet Processing","text":"

Split a sprite sheet into individual sprites:

pr32-sprite-compiler characters.png output.h --sheet 16x16 --count 8\n

"},{"location":"tools/sprite_compiler/overview/#4-batch-asset-processing","title":"4. Batch Asset Processing","text":"

Process entire asset directories:

pr32-sprite-compiler --batch assets/sprites/*.png --output-dir src/sprites/\n

"},{"location":"tools/sprite_compiler/overview/#workflow-integration","title":"Workflow Integration","text":""},{"location":"tools/sprite_compiler/overview/#typical-development-workflow","title":"Typical Development Workflow","text":"
  1. Create sprites in your image editor (Aseprite, Piskel, GIMP, etc.)
  2. Save as PNG with appropriate dimensions
  3. Run compiler to generate header files
  4. Include headers in your PixelRoot32 project
  5. Use sprites in your game code
"},{"location":"tools/sprite_compiler/overview/#automation-example","title":"Automation Example","text":"
#!/bin/bash\n# build-sprites.sh\n\n# Compile all sprites\npr32-sprite-compiler assets/sprites/*.png --output-dir src/sprites/\n\n# Continue with your build process\nplatformio run\n
"},{"location":"tools/sprite_compiler/overview/#advantages-over-manual-creation","title":"Advantages Over Manual Creation","text":""},{"location":"tools/sprite_compiler/overview/#time-saving","title":"\u2705 Time Saving","text":"
  • No manual bit pattern conversion
  • Automatic format optimization
  • Batch processing multiple sprites
"},{"location":"tools/sprite_compiler/overview/#accuracy","title":"\u2705 Accuracy","text":"
  • Correct bit ordering
  • Proper array formatting
  • Valid C++ syntax
"},{"location":"tools/sprite_compiler/overview/#consistency","title":"\u2705 Consistency","text":"
  • Uniform naming conventions
  • Standardized output format
  • Consistent code structure
"},{"location":"tools/sprite_compiler/overview/#maintainability","title":"\u2705 Maintainability","text":"
  • Easy to regenerate from source images
  • Version control friendly
  • Clear separation of assets and code
"},{"location":"tools/sprite_compiler/overview/#limitations","title":"Limitations","text":"
  • Width limit: 16 pixels for 1bpp (hardware constraint)
  • Color depth: Limited by format (1bpp = 2 colors, 2bpp = 4 colors, etc.)
  • File format: Primarily PNG (other formats may require conversion)
"},{"location":"tools/sprite_compiler/overview/#next-steps","title":"Next Steps","text":"
  • Installation Guide - Set up the compiler
  • Usage Guide - Learn how to use it
  • Advanced Features - Explore advanced options
"},{"location":"tools/sprite_compiler/overview/#see-also","title":"See Also","text":"
  • Manual - Sprites and Animation - Using sprites in games
  • Code Examples - Sprites - Sprite usage examples
  • Available Tools - All PixelRoot32 tools
"},{"location":"tools/sprite_compiler/usage_guide/","title":"Sprite Compiler Usage Guide","text":"

Complete guide to using the PixelRoot32 Sprite Compiler for converting images to sprite data.

"},{"location":"tools/sprite_compiler/usage_guide/#basic-usage","title":"Basic Usage","text":""},{"location":"tools/sprite_compiler/usage_guide/#launching-the-gui","title":"Launching the GUI","text":"

The easiest way to use the compiler is via the Graphical User Interface (GUI).

python main.py\n

This will open the application where you can interactively load images, configure the grid, and export sprites.

"},{"location":"tools/sprite_compiler/usage_guide/#command-line-interface-cli","title":"Command Line Interface (CLI)","text":"

For automation, you can use the CLI mode by passing arguments to the script.

python main.py [input] [options]\n

Required:

  • input: Input PNG image file
  • --grid WxH: Grid cell size (e.g., 16x16)
  • --sprite gx,gy,gw,gh: Sprite definition (can be repeated)

Optional:

  • --prefix NAME: Prefix for generated arrays (e.g., PLAYER_JUM)
  • --out FILE: Output header file (default: sprites.h)
  • --offset X,Y: Initial offset in pixels (default: 0,0)
  • --mode MODE: Export mode (layered, 2bpp, 4bpp)
"},{"location":"tools/sprite_compiler/usage_guide/#cli-examples","title":"CLI Examples","text":""},{"location":"tools/sprite_compiler/usage_guide/#simple-conversion","title":"Simple Conversion","text":"

Convert a single 16x16 sprite located at the top-left corner:

python main.py player.png --grid 16x16 --sprite 0,0,1,1 --out player.h\n
"},{"location":"tools/sprite_compiler/usage_guide/#multiple-sprites","title":"Multiple Sprites","text":"

Convert multiple sprites from a single sheet:

python main.py sheet.png --grid 16x16 \\\n  --sprite 0,0,1,1 \\\n  --sprite 1,0,1,1 \\\n  --sprite 2,0,1,1 \\\n  --out animations.h\n
"},{"location":"tools/sprite_compiler/usage_guide/#export-modes","title":"Export Modes","text":"

Layered (Default): Generates multiple uint16_t arrays, one for each color layer. Best for standard PixelRoot32 rendering.

python main.py icon.png --grid 16x16 --sprite 0,0,1,1 --mode layered\n

Packed 2bpp: Generates a single array with 2 bits per pixel (4 colors max).

python main.py icon.png --grid 16x16 --sprite 0,0,1,1 --mode 2bpp\n
"},{"location":"tools/sprite_compiler/usage_guide/#step-by-step-examples","title":"Step-by-Step Examples","text":""},{"location":"tools/sprite_compiler/usage_guide/#example-1-simple-player-sprite","title":"Example 1: Simple Player Sprite","text":"

Step 1: Create Image

  • Create an 8x8 pixel PNG image
  • Use black and white colors
  • Save as player.png

Step 2: Compile

python main.py player.png --grid 8x8 --sprite 0,0,1,1 --prefix PLAYER --out player_sprite.h\n

Step 3: Use in Code

#include \"player_sprite.h\"\n\nvoid draw() {\n    // PLAYER_SPRITE_0_LAYER_0 is generated automatically\n    renderer.drawSprite(PLAYER_SPRITE_0_LAYER_0, 100, 100, Color::White);\n}\n
"},{"location":"tools/sprite_compiler/usage_guide/#example-2-multiple-animation-frames","title":"Example 2: Multiple Animation Frames","text":"

Step 1: Prepare Images

  • Create frames: walk_0.png, walk_1.png, walk_2.png
  • All same size (e.g., 16x16)

Step 2: Batch Compile

pr32-sprite-compiler --batch walk_*.png --output-dir animations/ --prefix WALK_\n

Step 3: Use in Animation

#include \"animations/walk_0.h\"\n#include \"animations/walk_1.h\"\n#include \"animations/walk_2.h\"\n\nconst Sprite* WALK_FRAMES[] = {\n    &WALK_0_SPRITE,\n    &WALK_1_SPRITE,\n    &WALK_2_SPRITE\n};\n
"},{"location":"tools/sprite_compiler/usage_guide/#example-3-sprite-sheet","title":"Example 3: Sprite Sheet","text":"

Step 1: Create Sprite Sheet

  • Create a 64x64 image with 4x4 grid of 16x16 sprites
  • Save as characters.png

Step 2: Split Sheet

pr32-sprite-compiler characters.png characters.h --sheet 16x16 --count 16\n

Step 3: Use Individual Sprites

#include \"characters.h\"\n\n// Sprites named CHARACTER_0, CHARACTER_1, etc.\nrenderer.drawSprite(CHARACTER_0, 50, 50, Color::White);\nrenderer.drawSprite(CHARACTER_1, 70, 50, Color::White);\n
"},{"location":"tools/sprite_compiler/usage_guide/#batch-processing","title":"Batch Processing","text":""},{"location":"tools/sprite_compiler/usage_guide/#process-multiple-files","title":"Process Multiple Files","text":"

Process all PNG files in a directory:

pr32-sprite-compiler --batch sprites/*.png --output-dir generated/\n
"},{"location":"tools/sprite_compiler/usage_guide/#with-options","title":"With Options","text":"

Apply options to all files:

pr32-sprite-compiler --batch assets/*.png \\\n    --output-dir src/sprites/ \\\n    --format 1bpp \\\n    --prefix SPRITE_\n
"},{"location":"tools/sprite_compiler/usage_guide/#recursive-processing","title":"Recursive Processing","text":"

Process subdirectories:

pr32-sprite-compiler --batch assets/**/*.png --output-dir generated/\n
"},{"location":"tools/sprite_compiler/usage_guide/#sprite-sheets","title":"Sprite Sheets","text":""},{"location":"tools/sprite_compiler/usage_guide/#automatic-splitting","title":"Automatic Splitting","text":"

Split a sprite sheet into individual sprites:

pr32-sprite-compiler sheet.png output.h --sheet 8x8 --count 16\n

Parameters:

  • --sheet WxH: Tile size (width x height)
  • --count N: Number of sprites in sheet
"},{"location":"tools/sprite_compiler/usage_guide/#grid-layout","title":"Grid Layout","text":"

Specify grid dimensions:

pr32-sprite-compiler sheet.png output.h \\\n    --sheet 16x16 \\\n    --grid 4x4 \\\n    --count 16\n

Parameters:

  • --grid WxH: Grid dimensions (columns x rows)
"},{"location":"tools/sprite_compiler/usage_guide/#custom-naming","title":"Custom Naming","text":"

Name sprites with index:

pr32-sprite-compiler sheet.png output.h \\\n    --sheet 8x8 \\\n    --count 8 \\\n    --prefix CHARACTER_ \\\n    --indexed\n

Generates: CHARACTER_0, CHARACTER_1, etc.

"},{"location":"tools/sprite_compiler/usage_guide/#custom-palettes","title":"Custom Palettes","text":""},{"location":"tools/sprite_compiler/usage_guide/#using-palette-file","title":"Using Palette File","text":"

Convert with custom color palette:

pr32-sprite-compiler sprite.png output.h --palette palette.json\n

Palette JSON format:

{\n  \"colors\": [\n    {\"r\": 0, \"g\": 0, \"b\": 0, \"name\": \"black\"},\n    {\"r\": 255, \"g\": 255, \"b\": 255, \"name\": \"white\"}\n  ]\n}\n
"},{"location":"tools/sprite_compiler/usage_guide/#built-in-palettes","title":"Built-in Palettes","text":"

Use predefined palettes:

pr32-sprite-compiler sprite.png output.h --palette nes\npr32-sprite-compiler sprite.png output.h --palette gb\npr32-sprite-compiler sprite.png output.h --palette pico8\n
"},{"location":"tools/sprite_compiler/usage_guide/#advanced-options","title":"Advanced Options","text":""},{"location":"tools/sprite_compiler/usage_guide/#threshold-for-grayscale","title":"Threshold for Grayscale","text":"

Set threshold for black/white conversion:

pr32-sprite-compiler sprite.png output.h --threshold 128\n

Values: 0-255 (default: 127)

"},{"location":"tools/sprite_compiler/usage_guide/#dithering","title":"Dithering","text":"

Enable dithering for better gradients:

pr32-sprite-compiler sprite.png output.h --dither\n
"},{"location":"tools/sprite_compiler/usage_guide/#alignment","title":"Alignment","text":"

Control output alignment:

pr32-sprite-compiler sprite.png output.h --align 4\n
"},{"location":"tools/sprite_compiler/usage_guide/#endianness","title":"Endianness","text":"

Specify byte order:

pr32-sprite-compiler sprite.png output.h --endian little\npr32-sprite-compiler sprite.png output.h --endian big\n
"},{"location":"tools/sprite_compiler/usage_guide/#output-customization","title":"Output Customization","text":""},{"location":"tools/sprite_compiler/usage_guide/#namespace","title":"Namespace","text":"

Wrap output in namespace:

pr32-sprite-compiler sprite.png output.h --namespace MyGame\n
"},{"location":"tools/sprite_compiler/usage_guide/#header-guard","title":"Header Guard","text":"

Custom header guard:

pr32-sprite-compiler sprite.png output.h --guard MY_SPRITE_H\n
"},{"location":"tools/sprite_compiler/usage_guide/#include-paths","title":"Include Paths","text":"

Custom include paths:

pr32-sprite-compiler sprite.png output.h \\\n    --include \"<graphics/Sprite.h>\" \\\n    --include \"<stdint.h>\"\n
"},{"location":"tools/sprite_compiler/usage_guide/#integration-with-build-systems","title":"Integration with Build Systems","text":""},{"location":"tools/sprite_compiler/usage_guide/#platformio","title":"PlatformIO","text":"

Add to platformio.ini:

[env:esp32dev]\nextra_scripts = \n    pre:scripts/compile_sprites.py\n

compile_sprites.py:

Import(\"env\")\nimport subprocess\n\nsubprocess.run([\n    \"pr32-sprite-compiler\",\n    \"--batch\", \"assets/sprites/*.png\",\n    \"--output-dir\", \"src/sprites/\"\n])\n
"},{"location":"tools/sprite_compiler/usage_guide/#makefile","title":"Makefile","text":"
SPRITES = $(wildcard assets/sprites/*.png)\nSPRITE_HEADERS = $(SPRITES:assets/sprites/%.png=src/sprites/%.h)\n\nsrc/sprites/%.h: assets/sprites/%.png\n pr32-sprite-compiler $< $@ --name $(shell basename $< .png | tr '[:lower:]' '[:upper:]')_SPRITE\n\nsprites: $(SPRITE_HEADERS)\n
"},{"location":"tools/sprite_compiler/usage_guide/#cmake","title":"CMake","text":"
file(GLOB SPRITE_FILES \"assets/sprites/*.png\")\n\nforeach(SPRITE ${SPRITE_FILES})\n    get_filename_component(SPRITE_NAME ${SPRITE} NAME_WE)\n    add_custom_command(\n        OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/sprites/${SPRITE_NAME}.h\n        COMMAND pr32-sprite-compiler\n        ARGS ${SPRITE} ${CMAKE_CURRENT_SOURCE_DIR}/src/sprites/${SPRITE_NAME}.h\n        DEPENDS ${SPRITE}\n    )\nendforeach()\n
"},{"location":"tools/sprite_compiler/usage_guide/#gui-usage-if-available","title":"GUI Usage (If Available)","text":""},{"location":"tools/sprite_compiler/usage_guide/#opening-gui","title":"Opening GUI","text":"
pr32-sprite-compiler --gui\n

Or launch the GUI application directly.

"},{"location":"tools/sprite_compiler/usage_guide/#gui-workflow","title":"GUI Workflow","text":"
  1. Drag and drop images into the window
  2. Preview sprite data in real-time
  3. Adjust settings visually (format, threshold, etc.)
  4. Export to header files
  5. Batch process multiple files
"},{"location":"tools/sprite_compiler/usage_guide/#gui-features","title":"GUI Features","text":"
  • Visual preview of sprite conversion
  • Real-time threshold adjustment
  • Palette selection
  • Batch processing interface
  • Export options
"},{"location":"tools/sprite_compiler/usage_guide/#best-practices","title":"Best Practices","text":""},{"location":"tools/sprite_compiler/usage_guide/#image-preparation","title":"Image Preparation","text":"
  • Use indexed color PNG for best results
  • Keep sprites small (8x8, 16x16, 32x32)
  • Use black and white for 1bpp
  • Limit colors for 2bpp/4bpp formats
"},{"location":"tools/sprite_compiler/usage_guide/#file-organization","title":"File Organization","text":"
project/\n\u251c\u2500\u2500 assets/\n\u2502   \u2514\u2500\u2500 sprites/\n\u2502       \u251c\u2500\u2500 player.png\n\u2502       \u251c\u2500\u2500 enemy.png\n\u2502       \u2514\u2500\u2500 items.png\n\u251c\u2500\u2500 src/\n\u2502   \u2514\u2500\u2500 sprites/          # Generated headers\n\u2502       \u251c\u2500\u2500 player.h\n\u2502       \u251c\u2500\u2500 enemy.h\n\u2502       \u2514\u2500\u2500 items.h\n\u2514\u2500\u2500 platformio.ini\n
"},{"location":"tools/sprite_compiler/usage_guide/#naming-conventions","title":"Naming Conventions","text":"
  • Use descriptive names: player_walk_0.png \u2192 PLAYER_WALK_0_SPRITE
  • Be consistent: All caps for sprite names
  • Use prefixes: ENEMY_, PLAYER_, ITEM_
"},{"location":"tools/sprite_compiler/usage_guide/#version-control","title":"Version Control","text":"
  • Commit generated headers (they're part of the build)
  • Or add to .gitignore and regenerate on build
  • Keep source images in version control
"},{"location":"tools/sprite_compiler/usage_guide/#troubleshooting","title":"Troubleshooting","text":""},{"location":"tools/sprite_compiler/usage_guide/#common-issues","title":"Common Issues","text":"

\"Image too large\":

  • Sprites must be \u2264 16 pixels wide for 1bpp
  • Resize image or split into multiple sprites

\"Colors not converting correctly\":

  • Use indexed color PNG
  • For 1bpp: Use only black and white
  • For 2bpp: Use exactly 4 colors
  • For 4bpp: Use up to 16 colors

\"Output file not found\":

  • Check write permissions
  • Verify output directory exists
  • Use absolute paths if needed

\"Invalid format\":

  • Ensure input is PNG format
  • Check file is not corrupted
  • Try re-saving image in image editor
"},{"location":"tools/sprite_compiler/usage_guide/#getting-help","title":"Getting Help","text":"
pr32-sprite-compiler --help\n

Shows all available options and usage.

"},{"location":"tools/sprite_compiler/usage_guide/#next-steps","title":"Next Steps","text":"
  • Advanced Features - Explore advanced options
  • Overview - Learn more about the compiler
  • Manual - Sprites - Using sprites in games
"},{"location":"tools/sprite_compiler/usage_guide/#see-also","title":"See Also","text":"
  • Code Examples - Sprites - Sprite usage examples
  • Troubleshooting - Common issues and solutions
"},{"location":"tools/tilemap_editor/installation/","title":"Installation Guide","text":"

The PixelRoot32 Tilemap Editor can be run directly from source or as a standalone executable on Windows.

"},{"location":"tools/tilemap_editor/installation/#1-requirements","title":"1. Requirements","text":"
  • Python 3.13+ (if running from source).
  • Windows 10/11 (recommended).
"},{"location":"tools/tilemap_editor/installation/#2-install-from-source","title":"2. Install from Source","text":""},{"location":"tools/tilemap_editor/installation/#21-clone-the-repository","title":"2.1 Clone the Repository","text":"
git clone https://github.com/Gperez88/PixelRoot32-Tilemap-Editor.git\ncd PixelRoot32-Tilemap-Editor\n
"},{"location":"tools/tilemap_editor/installation/#22-install-dependencies","title":"2.2 Install Dependencies","text":"

The editor uses several Python libraries for the GUI and image processing:

pip install ttkbootstrap pillow jinja2\n
"},{"location":"tools/tilemap_editor/installation/#23-run-the-editor","title":"2.3 Run the Editor","text":"
python main.py\n
"},{"location":"tools/tilemap_editor/installation/#3-standalone-executable-windows","title":"3. Standalone Executable (Windows)","text":"

For a more convenient experience, you can use the pre-compiled version:

  1. Go to the Releases section of the repository.
  2. Download the latest PixelRoot32-Editor-win64.zip.
  3. Extract the contents to a folder.
  4. Run PixelRoot32-Editor.exe.

Note: No Python installation is required to run the standalone executable.

"},{"location":"tools/tilemap_editor/installation/#4-building-your-own-executable","title":"4. Building your own Executable","text":"

If you want to package the editor yourself:

  1. Install PyInstaller:
pip install pyinstaller\n
  1. Run the build command using the provided .spec file:
pyinstaller pixelroot32_editor.spec\n
  1. The executable will be available in the dist/ folder.
"},{"location":"tools/tilemap_editor/overview/","title":"Tilemap Editor Overview","text":"

The PixelRoot32 Tilemap Editor is a powerful visual tool designed to create complex multi-layered tile-based maps for the PixelRoot32 engine. It simplifies the process of designing game environments, managing tilesets, and exporting optimized C++ code.

"},{"location":"tools/tilemap_editor/overview/#what-it-does","title":"What It Does","text":"

The Tilemap Editor allows you to:

  • Visual Design: Paint tiles directly onto a canvas with layers and transparency.
  • Tileset Management: Import PNG images as tilesets and select single or multiple tiles.
  • Multi-Layer Support: Organize your map into up to 8 layers for parallax effects or depth.
  • Optimized Export: Generate C++ header and source files compatible with the PixelRoot32 renderer.
  • BPP Support: Export maps in 1bpp, 2bpp, or 4bpp formats to balance memory usage and color depth.
"},{"location":"tools/tilemap_editor/overview/#key-features","title":"Key Features","text":""},{"location":"tools/tilemap_editor/overview/#visual-editing-tools","title":"\u2705 Visual Editing Tools","text":"
  • Brush: Paint individual tiles or patterns.
  • Eraser: Remove tiles from the active layer.
  • Rectangle Fill: Quickly fill areas with a specific tile.
  • Pipette: Pick an existing tile from the canvas.
"},{"location":"tools/tilemap_editor/overview/#multi-layer-system","title":"\u2705 Multi-Layer System","text":"
  • Visibility Toggle: Hide/show layers to focus on specific parts of the map.
  • Opacity Control: Adjust layer transparency for complex blending effects.
  • Layer Reordering: Change the render order of your tilemaps.
"},{"location":"tools/tilemap_editor/overview/#tileset-selector","title":"\u2705 Tileset Selector","text":"
  • Smart Selection: Drag and select a rectangular area of tiles.
  • Multiple Tilesets: Support for multiple tilesets per project (planned).
  • Auto-import: Automatically detects tile size from the imported image.
"},{"location":"tools/tilemap_editor/overview/#engine-integration","title":"\u2705 Engine Integration","text":"
  • Workspace Selection: Link the editor to your PixelRoot32 projects directory.
  • Direct Export: Files are generated with the correct namespaces and structures for immediate use.
  • BPP Compatibility: Ensures exported data matches the engine's expected format for 1bpp, 2bpp, and 4bpp.
"},{"location":"tools/tilemap_editor/overview/#data-formats","title":"Data Formats","text":""},{"location":"tools/tilemap_editor/overview/#project-file-pr32scene","title":"Project File (.pr32scene)","text":"

The editor uses a custom JSON-based format to save your project state, including:

  • Tileset metadata (path, tile size, spacing).
  • Layer data (tile indices, width, height, position).
  • Project settings (BPP, namespace).
"},{"location":"tools/tilemap_editor/overview/#exported-c","title":"Exported C++","text":"

The editor generates <namespace>.h and <namespace>.cpp files containing:

  • Tilemap Data: One packed array of tile indices per layer (*_INDICES[]). Each layer is exposed as a TileMap4bpp (or TileMap2bpp/TileMap) with an indices pointer; use the same data for rendering and for tile-based collision in your game code.
  • Tilemap Structures: pixelroot32::graphics::TileMap (or TileMap2bpp/TileMap4bpp) definitions, plus tileset pool and palette.
  • Export options: Store data in Flash (ESP32) (default) emits static data with PROGMEM to reduce RAM use; Legacy format disables Flash attributes for backward compatibility or non-ESP32 builds.
  • Scene init: Call init() once before drawing; the generated code registers the palette and configures each layer for the engine.
"},{"location":"tools/tilemap_editor/usage_guide/","title":"Usage Guide","text":"

This guide covers the basic workflow for creating and exporting a tilemap using the PixelRoot32 Tilemap Editor.

"},{"location":"tools/tilemap_editor/usage_guide/#1-creating-a-new-project","title":"1. Creating a New Project","text":"
  1. Launch the editor.
  2. Go to File > New Project.
  3. Enter the project name and select the base Color Depth (BPP):
  4. 1bpp: Monochrome (2 colors).
  5. 2bpp: 4 colors.
  6. 4bpp: 16 colors.
  7. Set the Tile Size (e.g., 8x8, 16x16).
"},{"location":"tools/tilemap_editor/usage_guide/#2-importing-a-tileset","title":"2. Importing a Tileset","text":"
  1. In the Tileset panel, click on Load Tileset.
  2. Select a PNG image containing your tiles.
  3. The image will be sliced into tiles based on the tile size set in the project.
"},{"location":"tools/tilemap_editor/usage_guide/#3-painting-tiles","title":"3. Painting Tiles","text":"
  1. Select a tile (or a range of tiles) from the Tileset panel.
  2. Select the Brush tool (Shortcut: B).
  3. Click and drag on the canvas to paint.
  4. Use the Layers panel to switch between different layers.
"},{"location":"tools/tilemap_editor/usage_guide/#4-selection-and-transformations","title":"4. Selection and Transformations","text":"
  • Single Selection: Click on a tile in the tileset.
  • Area Selection: Click and drag in the tileset to select a rectangular block of tiles.
  • Pipette: Press P and click on the canvas to pick the tile under the cursor.
"},{"location":"tools/tilemap_editor/usage_guide/#5-exporting-to-c","title":"5. Exporting to C++","text":"
  1. Ensure you have at least one tileset imported.
  2. Click the Export button in the top right (or File > Export / Ctrl+E).
  3. In the export dialog:
  4. Set the C++ Namespace (e.g. forest_level); it defaults to the project name.
  5. Review the Color Depth (BPP); it is auto-detected from your tileset colors (1bpp, 2bpp, or 4bpp).
  6. Store data in Flash (ESP32): Checked by default; emits PROGMEM for palette, tileset, and layer data to reduce RAM on ESP32.
  7. Legacy format (no Flash attribute): Use for older projects or non-ESP32 builds.
  8. Click Export Now and choose the output directory.
  9. The editor generates:
  10. <namespace>.h: Declarations (e.g. TILE_SIZE, MAP_WIDTH, MAP_HEIGHT, layer TileMap4bpp externs, init()).
  11. <namespace>.cpp: Definitions (palette, tileset pool, layer indices, init() implementation). Use each layer's .indices in your game for drawing and tile-based collision.
"},{"location":"tools/tilemap_editor/usage_guide/#6-keyboard-shortcuts","title":"6. Keyboard Shortcuts","text":"Shortcut Action B Brush Tool E Eraser Tool R Rectangle Fill Tool P Pipette Tool Space + Drag Pan Canvas Mouse Wheel Zoom In/Out Ctrl + N New Project Ctrl + S Save Project Ctrl + E Export Project Esc Close floating panels"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"PixelRoot32 Documentation","text":"

PixelRoot32 is a lightweight 2D game engine designed for ESP32 and native desktop targets. This site provides official, versioned documentation with clear guides, conceptual explanations, API references, and complete examples to help you build games efficiently.

"},{"location":"#quick-links","title":"Quick Links","text":"
  • What is PixelRoot32? - Start here to understand the engine
  • Your First Project - Get up and running quickly
  • Fundamental Concepts - Learn the core concepts
  • Manual - Complete user guide
  • API Reference - Complete API documentation
  • Examples - Complete game examples
  • Tools - Available tools
  • FAQ - FAQ and troubleshooting
"},{"location":"#getting-started","title":"Getting Started","text":"

New to PixelRoot32? Follow this learning path:

  1. What is PixelRoot32? - Understand what the engine is and what it can do
  2. Why PixelRoot32? - Learn the advantages and use cases
  3. Fundamental Concepts - Learn the core architecture concepts
  4. Your First Project - Create and run your first project
"},{"location":"#about-this-documentation","title":"About This Documentation","text":"
  • Professional technical English across all pages
  • Search-enabled, mobile-friendly UI
  • Versioned with mike (stable/dev/experimental)
  • Cross-linked concepts, API, and examples
  • Progressive learning path from basics to advanced topics
"},{"location":"api_reference/audio/audio_config/","title":"AudioConfig","text":"

Configuration for the Audio subsystem.

"},{"location":"api_reference/audio/audio_config/#description","title":"Description","text":"

AudioConfig is a simple struct that holds configuration settings for the audio system, including the audio backend and sample rate. It is passed to AudioEngine during construction.

"},{"location":"api_reference/audio/audio_config/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    struct AudioConfig {\n        // ...\n    };\n}\n
"},{"location":"api_reference/audio/audio_config/#structure","title":"Structure","text":""},{"location":"api_reference/audio/audio_config/#audiobackend-backend","title":"AudioBackend* backend","text":"

Pointer to the platform-specific audio backend implementation.

Type: AudioBackend*

Access: Read-write

Default: nullptr

Notes: - Must be set to a valid backend instance - Backend is platform-specific: - ESP32: ESP32_DAC_AudioBackend or ESP32_I2S_AudioBackend - Native: SDL2_AudioBackend - Backend manages the actual audio hardware/API

Example:

#ifdef PLATFORM_ESP32\n    pixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\n    audioConfig.backend = &dacBackend;\n#elif PLATFORM_NATIVE\n    pixelroot32::drivers::native::SDL2_AudioBackend sdlBackend;\n    audioConfig.backend = &sdlBackend;\n#endif\n

"},{"location":"api_reference/audio/audio_config/#int-samplerate","title":"int sampleRate","text":"

Desired sample rate in Hz.

Type: int

Access: Read-write

Default: 22050

Notes: - Common values: 11025, 22050, 44100 - Lower rates use less CPU and memory (better for ESP32) - Higher rates provide better quality - Must match backend capabilities

Example:

audioConfig.sampleRate = 11025;  // Lower quality, less CPU (ESP32)\naudioConfig.sampleRate = 22050;  // Balanced (default)\naudioConfig.sampleRate = 44100; // Higher quality (Native)\n

"},{"location":"api_reference/audio/audio_config/#constructors","title":"Constructors","text":""},{"location":"api_reference/audio/audio_config/#audioconfigaudiobackend-backend-nullptr-int-samplerate-22050","title":"AudioConfig(AudioBackend* backend = nullptr, int sampleRate = 22050)","text":"

Default constructor.

Parameters: - backend (AudioBackend*, optional): Pointer to the audio backend implementation. Default: nullptr - sampleRate (int, optional): Desired sample rate in Hz. Default: 22050

Example:

// Default construction\npixelroot32::audio::AudioConfig audioConfig;\n\n// With backend\npixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\npixelroot32::audio::AudioConfig audioConfig(&dacBackend, 11025);\n

"},{"location":"api_reference/audio/audio_config/#usage-example","title":"Usage Example","text":""},{"location":"api_reference/audio/audio_config/#esp32-with-dac-backend","title":"ESP32 with DAC Backend","text":"
#ifdef PLATFORM_ESP32\n#include \"drivers/esp32/ESP32_DAC_AudioBackend.h\"\n\npixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &dacBackend;\naudioConfig.sampleRate = 11025;  // Lower rate for ESP32\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n#endif\n
"},{"location":"api_reference/audio/audio_config/#esp32-with-i2s-backend","title":"ESP32 with I2S Backend","text":"
#ifdef PLATFORM_ESP32\n#include \"drivers/esp32/ESP32_I2S_AudioBackend.h\"\n\npixelroot32::drivers::esp32::ESP32_I2S_AudioBackend i2sBackend;\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &i2sBackend;\naudioConfig.sampleRate = 22050;  // Higher quality with I2S\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n#endif\n
"},{"location":"api_reference/audio/audio_config/#native-with-sdl2-backend","title":"Native with SDL2 Backend","text":"
#ifdef PLATFORM_NATIVE\n#include \"drivers/native/SDL2_AudioBackend.h\"\n\npixelroot32::drivers::native::SDL2_AudioBackend sdlBackend;\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &sdlBackend;\naudioConfig.sampleRate = 44100;  // High quality for PC\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n#endif\n
"},{"location":"api_reference/audio/audio_config/#complete-engine-setup","title":"Complete Engine Setup","text":"
#include \"core/Engine.h\"\n#include \"graphics/DisplayConfig.h\"\n#include \"input/InputConfig.h\"\n#include \"audio/AudioConfig.h\"\n\nvoid setup() {\n    // Display config\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    displayConfig.width = 128;\n    displayConfig.height = 128;\n\n    // Input config\n    pixelroot32::input::InputConfig inputConfig;\n    // ... configure input\n\n    // Audio config\n    #ifdef PLATFORM_ESP32\n        pixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\n        pixelroot32::audio::AudioConfig audioConfig(&dacBackend, 11025);\n    #elif PLATFORM_NATIVE\n        pixelroot32::drivers::native::SDL2_AudioBackend sdlBackend;\n        pixelroot32::audio::AudioConfig audioConfig(&sdlBackend, 44100);\n    #endif\n\n    // Create engine with all configs\n    pixelroot32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/audio/audio_config/#platform-specific-considerations","title":"Platform-Specific Considerations","text":""},{"location":"api_reference/audio/audio_config/#esp32-dac-backend","title":"ESP32 DAC Backend","text":"
  • Sample rate: 11025 Hz recommended (lower CPU usage)
  • Quality: Lower quality, but simple setup
  • Pin: Uses GPIO 25 or 26
  • Hardware: Requires simple amplifier circuit
"},{"location":"api_reference/audio/audio_config/#esp32-i2s-backend","title":"ESP32 I2S Backend","text":"
  • Sample rate: 22050 Hz recommended
  • Quality: Higher quality than DAC
  • Pins: Requires I2S pins (BCLK, LRCK, DOUT)
  • Hardware: Requires external I2S DAC
"},{"location":"api_reference/audio/audio_config/#native-sdl2-backend","title":"Native SDL2 Backend","text":"
  • Sample rate: 44100 Hz typical
  • Quality: High quality
  • Setup: Requires SDL2 library installed
  • Platforms: Windows, Linux, macOS
"},{"location":"api_reference/audio/audio_config/#performance-considerations","title":"Performance Considerations","text":"
  • Sample rate: Lower rates use less CPU and memory
  • Backend choice: DAC is simpler but lower quality than I2S
  • Buffer size: Configured in backend, affects latency vs stability
"},{"location":"api_reference/audio/audio_config/#see-also","title":"See Also","text":"
  • AudioEngine - Audio playback engine
  • Manual - Audio
  • Manual - Platforms and Drivers
  • API Overview
"},{"location":"api_reference/audio/audio_engine/","title":"AudioEngine","text":"

Core class for the NES-like audio subsystem.

"},{"location":"api_reference/audio/audio_engine/#description","title":"Description","text":"

AudioEngine manages the audio channels (Pulse, Triangle, Noise), mixes their output, and provides the audio stream to the backend. It implements a NES-like audio system with 4 fixed channels: 2 Pulse channels, 1 Triangle channel, and 1 Noise channel.

The engine is event-driven: you trigger sound effects via playEvent(), and the engine automatically manages channel allocation and playback.

"},{"location":"api_reference/audio/audio_engine/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    class AudioEngine {\n        // ...\n    };\n}\n
"},{"location":"api_reference/audio/audio_engine/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages audio engine instance)
"},{"location":"api_reference/audio/audio_engine/#constructors","title":"Constructors","text":""},{"location":"api_reference/audio/audio_engine/#audioengineconst-audioconfig-config","title":"AudioEngine(const AudioConfig& config)","text":"

Constructs the AudioEngine with the given configuration.

Parameters: - config (const AudioConfig&): Configuration struct containing the backend and parameters (sample rate, etc.)

Example:

#include \"audio/AudioEngine.h\"\n#include \"audio/AudioConfig.h\"\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &audioBackend;  // Platform-specific backend\naudioConfig.sampleRate = 22050;       // 22.05 kHz for retro feel\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n

"},{"location":"api_reference/audio/audio_engine/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/audio/audio_engine/#void-init","title":"void init()","text":"

Initializes the audio subsystem and the backend.

Returns: - void

Notes: - Must be called after construction and before use - Initializes the platform-specific audio backend - Safe to call multiple times (idempotent) - Typically called automatically by Engine::init()

Example:

AudioEngine audioEngine(audioConfig);\naudioEngine.init();  // Initialize before use\n

"},{"location":"api_reference/audio/audio_engine/#void-updateunsigned-long-deltatime","title":"void update(unsigned long deltaTime)","text":"

Updates the audio state based on game time.

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Returns: - void

Notes: - Should be called from the main game loop (typically via Engine::update()) - Updates channel lifetimes and durations - Automatically stops channels when their duration expires - Must be called every frame for proper audio timing

Example:

void update(unsigned long deltaTime) override {\n    // Update audio (called automatically by Engine)\n    engine.getAudioEngine().update(deltaTime);\n\n    // Your game logic...\n}\n

"},{"location":"api_reference/audio/audio_engine/#void-generatesamplesint16_t-stream-int-length","title":"void generateSamples(int16_t* stream, int length)","text":"

Fills the provided buffer with mixed audio samples.

Parameters: - stream (int16_t*): Pointer to the buffer to fill - length (int): Number of samples to generate

Returns: - void

Notes: - This method is typically called by the AudioBackend from an audio callback or task - Not usually called directly by game code - Generates 16-bit signed integer PCM samples - Mixes all active channels into a mono stream

Advanced Usage:

// Typically not called directly, but if implementing custom backend:\nint16_t buffer[512];\naudioEngine.generateSamples(buffer, 512);\n

"},{"location":"api_reference/audio/audio_engine/#void-playeventconst-audioevent-event","title":"void playEvent(const AudioEvent& event)","text":"

Triggers a one-shot sound effect.

Parameters: - event (const AudioEvent&): The audio event to play

Returns: - void

Notes: - Automatically finds an available channel of the correct type - If no channel is available, the event may be dropped (no error) - Events are fire-and-forget (no need to track playback) - Use for sound effects, not background music

Example:

// Play a jump sound\npixelroot32::audio::AudioEvent jumpSound{};\njumpSound.type = pixelroot32::audio::WaveType::PULSE;\njumpSound.frequency = 800.0f;\njumpSound.duration = 0.1f;\njumpSound.volume = 0.7f;\njumpSound.duty = 0.5f;\n\nauto& audio = engine.getAudioEngine();\naudio.playEvent(jumpSound);\n\n// Play an explosion sound\npixelroot32::audio::AudioEvent explosion{};\nexplosion.type = pixelroot32::audio::WaveType::NOISE;\nexplosion.frequency = 1000.0f;\nexplosion.duration = 0.3f;\nexplosion.volume = 0.9f;\n\naudio.playEvent(explosion);\n

"},{"location":"api_reference/audio/audio_engine/#void-setmastervolumefloat-volume","title":"void setMasterVolume(float volume)","text":"

Sets the master volume for all audio output.

Parameters: - volume (float): Volume level (0.0 = silent, 1.0 = full volume)

Returns: - void

Notes: - Affects all channels and events - Clamped to [0.0, 1.0] range - Use for volume control menus or mute functionality

Example:

auto& audio = engine.getAudioEngine();\naudio.setMasterVolume(0.5f);  // 50% volume\naudio.setMasterVolume(0.0f);  // Mute\naudio.setMasterVolume(1.0f);  // Full volume\n

"},{"location":"api_reference/audio/audio_engine/#float-getmastervolume-const","title":"float getMasterVolume() const","text":"

Gets the current master volume.

Returns: - float: Current master volume (0.0 to 1.0)

Example:

float currentVolume = audioEngine.getMasterVolume();\n

"},{"location":"api_reference/audio/audio_engine/#audio-channels","title":"Audio Channels","text":"

The engine manages 4 fixed channels:

  1. Channel 0: Pulse wave
  2. Channel 1: Pulse wave
  3. Channel 2: Triangle wave
  4. Channel 3: Noise wave

Notes: - Channels are automatically allocated when playing events - If all channels of a type are busy, new events may be dropped - Background music typically uses one channel (via MusicPlayer)

"},{"location":"api_reference/audio/audio_engine/#usage-example","title":"Usage Example","text":"
#include \"audio/AudioEngine.h\"\n#include \"audio/AudioConfig.h\"\n\nclass MyScene : public pixelroot32::core::Scene {\nprivate:\n    void playJumpSound() {\n        auto& audio = engine.getAudioEngine();\n\n        pixelroot32::audio::AudioEvent sound{};\n        sound.type = pixelroot32::audio::WaveType::PULSE;\n        sound.frequency = 800.0f;\n        sound.duration = 0.1f;\n        sound.volume = 0.7f;\n        sound.duty = 0.5f;\n\n        audio.playEvent(sound);\n    }\n\n    void playHitSound() {\n        auto& audio = engine.getAudioEngine();\n\n        pixelroot32::audio::AudioEvent sound{};\n        sound.type = pixelroot32::audio::WaveType::NOISE;\n        sound.frequency = 500.0f;\n        sound.duration = 0.05f;\n        sound.volume = 0.5f;\n\n        audio.playEvent(sound);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Audio is updated automatically by Engine\n        // Just play events when needed\n        if (playerJumped) {\n            playJumpSound();\n            playerJumped = false;\n        }\n    }\n};\n
"},{"location":"api_reference/audio/audio_engine/#performance-considerations","title":"Performance Considerations","text":"
  • Channel limit: Only 4 channels total; plan sound effects accordingly
  • Event dropping: If all channels are busy, new events are silently dropped
  • Update frequency: update() must be called every frame for proper timing
  • Sample generation: generateSamples() is called by backend at audio rate (not game rate)
"},{"location":"api_reference/audio/audio_engine/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Sample rate: Lower sample rates (11025 Hz) use less CPU and memory
  • Backend choice: DAC backend is simpler but lower quality than I2S
  • Buffer size: Larger buffers reduce underruns but increase latency
  • Channel management: Limit simultaneous sounds to avoid channel conflicts
"},{"location":"api_reference/audio/audio_engine/#see-also","title":"See Also","text":"
  • AudioConfig - Audio configuration
  • AudioTypes - Audio data structures
  • MusicPlayer - Background music playback
  • Manual - Audio
  • API Overview
"},{"location":"api_reference/audio/audio_types/","title":"Audio Types","text":"

Data structures and types for the audio system.

"},{"location":"api_reference/audio/audio_types/#description","title":"Description","text":"

This document describes the data structures used by the audio system, including wave types, audio events, and channel state.

"},{"location":"api_reference/audio/audio_types/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    // Types and structures\n}\n
"},{"location":"api_reference/audio/audio_types/#wavetype-enum","title":"WaveType Enum","text":"

Defines the types of waveforms available.

Values: - WaveType::PULSE: Pulse wave (square wave with variable duty cycle) - WaveType::TRIANGLE: Triangle wave (smooth, melodic) - WaveType::NOISE: Noise wave (random, percussive)

Example:

pixelroot32::audio::WaveType wave = pixelroot32::audio::WaveType::PULSE;\n

"},{"location":"api_reference/audio/audio_types/#audioevent-structure","title":"AudioEvent Structure","text":"

A fire-and-forget sound event triggered by the game.

Members: - WaveType type: Type of waveform to use - float frequency: Frequency in Hz - float duration: Duration in seconds - float volume: Volume level (0.0 to 1.0) - float duty: Duty cycle for pulse wave (0.0 to 1.0, pulse only)

Example:

pixelroot32::audio::AudioEvent jumpSound{};\njumpSound.type = pixelroot32::audio::WaveType::PULSE;\njumpSound.frequency = 800.0f;\njumpSound.duration = 0.1f;\njumpSound.volume = 0.7f;\njumpSound.duty = 0.5f;\n\nauto& audio = engine.getAudioEngine();\naudio.playEvent(jumpSound);\n

"},{"location":"api_reference/audio/audio_types/#common-sound-effects","title":"Common Sound Effects","text":"

Jump Sound:

pixelroot32::audio::AudioEvent jump{};\njump.type = pixelroot32::audio::WaveType::PULSE;\njump.frequency = 800.0f;\njump.duration = 0.1f;\njump.volume = 0.7f;\njump.duty = 0.5f;\n

Hit Sound:

pixelroot32::audio::AudioEvent hit{};\nhit.type = pixelroot32::audio::WaveType::NOISE;\nhit.frequency = 500.0f;\nhit.duration = 0.05f;\nhit.volume = 0.5f;\n

Collect Sound:

pixelroot32::audio::AudioEvent collect{};\ncollect.type = pixelroot32::audio::WaveType::TRIANGLE;\ncollect.frequency = 1000.0f;\ncollect.duration = 0.15f;\ncollect.volume = 0.6f;\n

Explosion:

pixelroot32::audio::AudioEvent explosion{};\nexplosion.type = pixelroot32::audio::WaveType::NOISE;\nexplosion.frequency = 200.0f;\nexplosion.duration = 0.3f;\nexplosion.volume = 0.9f;\n

"},{"location":"api_reference/audio/audio_types/#audiochannel-structure","title":"AudioChannel Structure","text":"

Represents the internal state of a single audio channel.

Members: - bool enabled: Whether the channel is active - WaveType type: Type of waveform - float frequency: Current frequency in Hz - float phase: Current phase (0.0 to 1.0) - float phaseIncrement: Pre-calculated phase increment - float volume: Current volume (0.0 to 1.0) - float targetVolume: Target volume for envelopes - float dutyCycle: Duty cycle for pulse wave (0.0 to 1.0) - uint16_t noiseRegister: LFSR state for noise generation - unsigned long durationMs: Total duration in milliseconds - unsigned long remainingMs: Remaining duration in milliseconds

Methods: - void reset(): Resets the channel to inactive state

Notes: - Internal structure, typically not accessed directly - Managed automatically by AudioEngine - 4 channels total: 2 Pulse, 1 Triangle, 1 Noise

"},{"location":"api_reference/audio/audio_types/#frequency-reference","title":"Frequency Reference","text":"

Common frequencies for musical notes (A4 = 440 Hz):

  • C4: 261.63 Hz
  • D4: 293.66 Hz
  • E4: 329.63 Hz
  • F4: 349.23 Hz
  • G4: 392.00 Hz
  • A4: 440.00 Hz
  • B4: 493.88 Hz
  • C5: 523.25 Hz

Example:

// Play a C note\npixelroot32::audio::AudioEvent note{};\nnote.type = pixelroot32::audio::WaveType::PULSE;\nnote.frequency = 261.63f;  // C4\nnote.duration = 0.5f;\nnote.volume = 0.8f;\nnote.duty = 0.5f;\n

"},{"location":"api_reference/audio/audio_types/#duty-cycle-pulse-wave","title":"Duty Cycle (Pulse Wave)","text":"

Duty cycle controls the shape of the pulse wave:

  • 0.125 (12.5%): Thin pulse (NES-like)
  • 0.25 (25%): Narrow pulse
  • 0.5 (50%): Square wave (most common)
  • 0.75 (75%): Wide pulse

Example:

// Thin pulse (NES style)\nevent.duty = 0.125f;\n\n// Square wave (standard)\nevent.duty = 0.5f;\n

"},{"location":"api_reference/audio/audio_types/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/audio/audio_types/#creating-sound-effect-library","title":"Creating Sound Effect Library","text":"
namespace SoundEffects {\n    // Jump sound\n    inline pixelroot32::audio::AudioEvent jump() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 800.0f;\n        evt.duration = 0.1f;\n        evt.volume = 0.7f;\n        evt.duty = 0.5f;\n        return evt;\n    }\n\n    // Hit sound\n    inline pixelroot32::audio::AudioEvent hit() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::NOISE;\n        evt.frequency = 500.0f;\n        evt.duration = 0.05f;\n        evt.volume = 0.5f;\n        return evt;\n    }\n\n    // Collect sound\n    inline pixelroot32::audio::AudioEvent collect() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::TRIANGLE;\n        evt.frequency = 1000.0f;\n        evt.duration = 0.15f;\n        evt.volume = 0.6f;\n        return evt;\n    }\n}\n\n// Usage\nauto& audio = engine.getAudioEngine();\naudio.playEvent(SoundEffects::jump());\naudio.playEvent(SoundEffects::hit());\n
"},{"location":"api_reference/audio/audio_types/#frequency-sweep-effect","title":"Frequency Sweep Effect","text":"
void playSweepSound() {\n    auto& audio = engine.getAudioEngine();\n\n    // Create multiple events for sweep effect\n    for (int i = 0; i < 5; i++) {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 400.0f + (i * 200.0f);  // Sweep from 400 to 1200 Hz\n        evt.duration = 0.05f;\n        evt.volume = 0.6f;\n        evt.duty = 0.5f;\n\n        audio.playEvent(evt);\n        delay(50);  // Small delay between events\n    }\n}\n
"},{"location":"api_reference/audio/audio_types/#performance-considerations","title":"Performance Considerations","text":"
  • Event creation: Creating events is fast (just struct initialization)
  • Channel allocation: Events are queued and played when channels are available
  • Frequency range: Keep frequencies in reasonable range (100-5000 Hz) for best results
  • Duration: Shorter durations free channels faster
"},{"location":"api_reference/audio/audio_types/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Events are small structs, safe to create frequently
  • CPU: Audio generation is efficient but limit simultaneous sounds
  • Quality: Lower sample rates reduce CPU usage
"},{"location":"api_reference/audio/audio_types/#see-also","title":"See Also","text":"
  • AudioEngine - Audio playback engine
  • AudioConfig - Audio configuration
  • Manual - Audio
  • API Overview
"},{"location":"api_reference/audio/music_player/","title":"MusicPlayer","text":"

Lightweight sequencer built on top of AudioEngine to play background melodies as tracks.

"},{"location":"api_reference/audio/music_player/#description","title":"Description","text":"

MusicPlayer is a simple sequencer that plays MusicTrack structures. It advances notes based on game time, converts MusicNote entries to AudioEvent calls, and manages playback state (play, stop, pause, resume).

The player uses one audio channel (typically a Pulse channel) for music, leaving other channels available for sound effects.

"},{"location":"api_reference/audio/music_player/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    class MusicPlayer {\n        // ...\n    };\n}\n
"},{"location":"api_reference/audio/music_player/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages music player instance)
"},{"location":"api_reference/audio/music_player/#constructors","title":"Constructors","text":""},{"location":"api_reference/audio/music_player/#musicplayeraudioengine-engine","title":"MusicPlayer(AudioEngine& engine)","text":"

Constructs the MusicPlayer.

Parameters: - engine (AudioEngine&): Reference to the AudioEngine used to play sounds

Notes: - Typically created and managed by Engine - Access via engine.getMusicPlayer()

Example:

auto& audio = engine.getAudioEngine();\npixelroot32::audio::MusicPlayer musicPlayer(audio);\n

"},{"location":"api_reference/audio/music_player/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/audio/music_player/#void-playconst-musictrack-track","title":"void play(const MusicTrack& track)","text":"

Starts playing a track.

Parameters: - track (const MusicTrack&): The track to play

Returns: - void

Notes: - Stops any currently playing track - Starts from the beginning of the track - If track has loop = true, will loop automatically - Uses one audio channel (typically Pulse)

Example:

static const MusicNote MELODY[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),\n};\n\nstatic const MusicTrack GAME_MUSIC = {\n    MELODY,\n    sizeof(MELODY) / sizeof(MusicNote),\n    true,  // loop\n    WaveType::PULSE,\n    0.5f   // volume\n};\n\nvoid init() override {\n    auto& music = engine.getMusicPlayer();\n    music.play(GAME_MUSIC);\n}\n

"},{"location":"api_reference/audio/music_player/#void-stop","title":"void stop()","text":"

Stops playback and silences the channel.

Returns: - void

Notes: - Immediately stops the current note - Resets playback to the beginning - Channel is freed for other use

Example:

void onGameOver() {\n    auto& music = engine.getMusicPlayer();\n    music.stop();\n}\n

"},{"location":"api_reference/audio/music_player/#void-pause","title":"void pause()","text":"

Pauses playback.

Returns: - void

Notes: - Current note continues until it ends, then playback pauses - Playback state is preserved (can resume from where it paused) - Use for pause menus

Example:

void onPause() {\n    auto& music = engine.getMusicPlayer();\n    music.pause();\n}\n

"},{"location":"api_reference/audio/music_player/#void-resume","title":"void resume()","text":"

Resumes playback.

Returns: - void

Notes: - Only works if playback was paused - Resumes from where it was paused - Use to unpause after pause menu

Example:

void onResume() {\n    auto& music = engine.getMusicPlayer();\n    music.resume();\n}\n

"},{"location":"api_reference/audio/music_player/#void-updateunsigned-long-deltatime","title":"void update(unsigned long deltaTime)","text":"

Updates the player state. Should be called every frame.

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Returns: - void

Notes: - Must be called every frame for proper timing - Advances note playback based on elapsed time - Automatically plays next notes in sequence - Typically called automatically by Engine

Example:

// Called automatically by Engine, but can be called manually:\nvoid update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);\n\n    // Music player is updated automatically by Engine\n    // No need to call manually\n}\n

"},{"location":"api_reference/audio/music_player/#bool-isplaying-const","title":"bool isPlaying() const","text":"

Checks if a track is currently playing.

Returns: - bool: true if playing, false otherwise

Notes: - Returns false if stopped or paused - Use to check playback state before operations

Example:

auto& music = engine.getMusicPlayer();\nif (music.isPlaying()) {\n    // Music is active\n} else {\n    // Music is stopped or paused\n}\n

"},{"location":"api_reference/audio/music_player/#void-settempofactorfloat-factor","title":"void setTempoFactor(float factor)","text":"

Sets the global tempo scaling factor.

Parameters: - factor (float): Tempo multiplier - 1.0f: Normal speed - 2.0f: Double speed - 0.5f: Half speed

Returns: - void

Notes: - Affects all note durations - Useful for speed-up effects or slow-motion - Applied to all tracks

Example:

auto& music = engine.getMusicPlayer();\nmusic.setTempoFactor(1.5f);  // 50% faster\nmusic.setTempoFactor(0.5f);   // 50% slower\nmusic.setTempoFactor(1.0f);   // Normal speed\n

"},{"location":"api_reference/audio/music_player/#float-gettempofactor-const","title":"float getTempoFactor() const","text":"

Gets the current tempo scaling factor.

Returns: - float: Current factor (default 1.0f)

Example:

float currentTempo = musicPlayer.getTempoFactor();\n

"},{"location":"api_reference/audio/music_player/#musictrack-structure","title":"MusicTrack Structure","text":"

A MusicTrack contains:

  • notes (const MusicNote*): Array of music notes
  • noteCount (size_t): Number of notes in the array
  • loop (bool): Whether to loop the track
  • waveType (WaveType): Wave type to use (typically PULSE)
  • volume (float): Volume level (0.0 to 1.0)
"},{"location":"api_reference/audio/music_player/#musicnote-structure","title":"MusicNote Structure","text":"

A MusicNote contains:

  • instrument (InstrumentPreset): Instrument preset to use
  • note (Note): Musical note (C, D, E, etc.)
  • duration (float): Duration in seconds

Use helper functions: - makeNote(instrument, note, duration): Create a note - makeRest(duration): Create a rest (silence)

"},{"location":"api_reference/audio/music_player/#usage-example","title":"Usage Example","text":"
#include \"audio/MusicPlayer.h\"\n#include \"audio/AudioMusicTypes.h\"\n\nusing namespace pixelroot32::audio;\n\n// Define a simple melody\nstatic const MusicNote MAIN_THEME[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.25f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.25f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.1f),\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.5f),\n    makeRest(0.2f),\n};\n\nstatic const MusicTrack MAIN_THEME_TRACK = {\n    MAIN_THEME,\n    sizeof(MAIN_THEME) / sizeof(MusicNote),\n    true,           // loop\n    WaveType::PULSE,\n    0.6f            // volume\n};\n\nclass GameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Start background music\n        auto& music = engine.getMusicPlayer();\n        music.play(MAIN_THEME_TRACK);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Music updates automatically\n    }\n\n    void onPauseMenu() {\n        auto& music = engine.getMusicPlayer();\n        music.pause();\n    }\n\n    void onResumeGame() {\n        auto& music = engine.getMusicPlayer();\n        music.resume();\n    }\n\n    void onGameOver() {\n        auto& music = engine.getMusicPlayer();\n        music.stop();\n    }\n};\n
"},{"location":"api_reference/audio/music_player/#performance-considerations","title":"Performance Considerations","text":"
  • One channel: Music uses one channel, leaving others for sound effects
  • Update frequency: update() must be called every frame
  • Track size: Larger tracks use more memory (store in flash)
  • Tempo factor: Changing tempo is fast (just a multiplier)
"},{"location":"api_reference/audio/music_player/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store tracks in flash (const/constexpr) to save RAM
  • CPU: Music playback is lightweight (simple sequencing)
  • Channel conflict: Music and sound effects share channels; plan accordingly
"},{"location":"api_reference/audio/music_player/#see-also","title":"See Also","text":"
  • AudioEngine - Audio playback engine
  • AudioTypes - Audio data structures
  • AudioMusicTypes - Music data structures
  • Manual - Audio
  • API Overview
"},{"location":"api_reference/core/actor/","title":"Actor","text":"

An Entity capable of physical interaction and collision.

"},{"location":"api_reference/core/actor/#description","title":"Description","text":"

Actor extends Entity with collision layers and masks. Actors are used for dynamic game objects like players, enemies, projectiles, and obstacles that need to interact with each other through collision detection.

Actors participate in the collision system and can detect collisions with other actors based on their collision layers and masks.

"},{"location":"api_reference/core/actor/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Actor : public Entity {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/actor/#inheritance","title":"Inheritance","text":"
  • Inherits from: Entity
  • Inherited by: PhysicsActor and your custom actor classes
"},{"location":"api_reference/core/actor/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/actor/#actorfloat-x-float-y-int-w-int-h","title":"Actor(float x, float y, int w, int h)","text":"

Creates a new actor with specified position and size.

Parameters: - x (float): Initial X position in world space - y (float): Initial Y position in world space - w (int): Actor width in pixels - h (int): Actor height in pixels

Notes: - Actor type is automatically set to EntityType::ACTOR - Collision layer and mask default to DefaultLayers::kNone - Must set collision layer and mask for collision detection to work

Example:

class PlayerActor : public pixelroot32::core::Actor {\npublic:\n    PlayerActor(float x, float y) \n        : Actor(x, y, 16, 16) {\n        // Set collision layer and mask\n        layer = pixelroot32::physics::DefaultLayers::kPlayer;\n        mask = pixelroot32::physics::DefaultLayers::kEnemy | \n               pixelroot32::physics::DefaultLayers::kObstacle;\n    }\n\n    void update(unsigned long deltaTime) override {\n        Actor::update(deltaTime);\n        // Player logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawSprite(playerSprite, \n                           static_cast<int>(x), \n                           static_cast<int>(y), \n                           Color::White);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        // Handle collision\n    }\n};\n

"},{"location":"api_reference/core/actor/#public-properties","title":"Public Properties","text":""},{"location":"api_reference/core/actor/#collisionlayer-layer","title":"CollisionLayer layer","text":"

The collision layer this actor belongs to.

Type: pixelroot32::physics::CollisionLayer (uint16_t)

Access: Read-write

Default: DefaultLayers::kNone

Notes: - Defines which layer this actor is on - Use bit flags to assign multiple layers (e.g., kPlayer | kProjectile) - Only actors with matching layers in their mask will collide

Example:

actor->layer = pixelroot32::physics::DefaultLayers::kPlayer;\n

"},{"location":"api_reference/core/actor/#collisionlayer-mask","title":"CollisionLayer mask","text":"

The collision layers this actor interacts with.

Type: pixelroot32::physics::CollisionLayer (uint16_t)

Access: Read-write

Default: DefaultLayers::kNone

Notes: - Defines which layers this actor can collide with - Use bit flags to check multiple layers (e.g., kEnemy | kObstacle) - Collision only occurs if the other actor's layer matches bits in this mask

Example:

// Actor collides with enemies and obstacles\nactor->mask = pixelroot32::physics::DefaultLayers::kEnemy | \n              pixelroot32::physics::DefaultLayers::kObstacle;\n

"},{"location":"api_reference/core/actor/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/actor/#void-setcollisionlayercollisionlayer-l","title":"void setCollisionLayer(CollisionLayer l)","text":"

Sets the collision layer for this actor.

Parameters: - l (pixelroot32::physics::CollisionLayer): The layer to set

Returns: - void

Notes: - Equivalent to setting layer directly - Use bit flags for multiple layers

Example:

actor->setCollisionLayer(pixelroot32::physics::DefaultLayers::kPlayer);\n

"},{"location":"api_reference/core/actor/#void-setcollisionmaskcollisionlayer-m","title":"void setCollisionMask(CollisionLayer m)","text":"

Sets the collision mask for this actor.

Parameters: - m (pixelroot32::physics::CollisionLayer): The mask to set

Returns: - void

Notes: - Equivalent to setting mask directly - Use bit flags for multiple layers

Example:

actor->setCollisionMask(pixelroot32::physics::DefaultLayers::kEnemy | \n                        pixelroot32::physics::DefaultLayers::kObstacle);\n

"},{"location":"api_reference/core/actor/#bool-isinlayeruint16_t-targetlayer-const","title":"bool isInLayer(uint16_t targetLayer) const","text":"

Checks if the Actor belongs to a specific collision layer.

Parameters: - targetLayer (uint16_t): The bit(s) to check (e.g., DefaultLayers::kPlayer)

Returns: - bool: true if the bit is set in the actor's layer

Notes: - Uses bitwise AND operation - Useful for checking if an actor is on a specific layer

Example:

if (actor->isInLayer(pixelroot32::physics::DefaultLayers::kPlayer)) {\n    // This is a player actor\n}\n

"},{"location":"api_reference/core/actor/#virtual-rect-gethitbox-0","title":"virtual Rect getHitBox() = 0","text":"

Gets the hitbox for collision detection. Must be implemented by derived classes.

Returns: - Rect: A rectangle representing the collision bounds

Notes: - Called by the collision system to check collisions - Should return the actual collision bounds (may differ from visual size) - Use AABB (Axis-Aligned Bounding Box) for efficiency

Example:

Rect getHitBox() override {\n    // Return collision bounds (may be smaller than visual)\n    return {x + 2, y + 2, width - 4, height - 4};\n}\n

"},{"location":"api_reference/core/actor/#virtual-void-oncollisionactor-other-0","title":"virtual void onCollision(Actor* other) = 0","text":"

Callback invoked when a collision occurs. Must be implemented by derived classes.

Parameters: - other (Actor*): The actor that this actor collided with

Notes: - Called automatically by the collision system when a collision is detected - Both actors' onCollision() methods are called - Use to handle collision responses (damage, bouncing, etc.)

Example:

void onCollision(Actor* other) override {\n    // Check what we collided with\n    if (other->isInLayer(pixelroot32::physics::DefaultLayers::kEnemy)) {\n        // Take damage\n        health--;\n        if (health <= 0) {\n            isEnabled = false;\n        }\n    } else if (other->isInLayer(pixelroot32::physics::DefaultLayers::kCollectible)) {\n        // Collect item\n        score += 10;\n        other->isEnabled = false;  // Remove collectible\n    }\n}\n

"},{"location":"api_reference/core/actor/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the actor logic. Default implementation does nothing.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Override to implement actor-specific update logic - Called automatically by Scene if isEnabled is true - Use deltaTime for frame-rate independent movement

Example:

void update(unsigned long deltaTime) override {\n    Actor::update(deltaTime);  // Call base implementation\n\n    // Move actor\n    float speed = 100.0f;  // pixels per second\n    x += (speed * deltaTime) / 1000.0f;\n}\n

"},{"location":"api_reference/core/actor/#collision-layers","title":"Collision Layers","text":"

Collision layers use bit flags to organize actors into groups. Common layers:

  • DefaultLayers::kNone (0): No layer
  • DefaultLayers::kPlayer (1 << 0): Player actors
  • DefaultLayers::kEnemy (1 << 1): Enemy actors
  • DefaultLayers::kObstacle (1 << 2): Obstacles/walls
  • DefaultLayers::kProjectile (1 << 3): Projectiles
  • DefaultLayers::kCollectible (1 << 4): Collectible items

Example:

// Player collides with enemies and obstacles\nplayer->layer = DefaultLayers::kPlayer;\nplayer->mask = DefaultLayers::kEnemy | DefaultLayers::kObstacle;\n\n// Enemy collides with player and obstacles\nenemy->layer = DefaultLayers::kEnemy;\nenemy->mask = DefaultLayers::kPlayer | DefaultLayers::kObstacle;\n\n// Projectile collides with enemies\nprojectile->layer = DefaultLayers::kProjectile;\nprojectile->mask = DefaultLayers::kEnemy;\n

"},{"location":"api_reference/core/actor/#usage-example","title":"Usage Example","text":"
#include \"core/Actor.h\"\n#include \"physics/CollisionTypes.h\"\n\nclass EnemyActor : public pixelroot32::core::Actor {\nprivate:\n    const pixelroot32::graphics::Sprite* sprite;\n    int health = 3;\n\npublic:\n    EnemyActor(float x, float y) \n        : Actor(x, y, 16, 16),\n          sprite(&enemySprite) {\n        // Set collision layer and mask\n        layer = pixelroot32::physics::DefaultLayers::kEnemy;\n        mask = pixelroot32::physics::DefaultLayers::kPlayer | \n               pixelroot32::physics::DefaultLayers::kProjectile;\n    }\n\n    void update(unsigned long deltaTime) override {\n        Actor::update(deltaTime);\n\n        // Move towards player\n        float speed = 50.0f;\n        // ... movement logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawSprite(*sprite, \n                           static_cast<int>(x), \n                           static_cast<int>(y), \n                           Color::Red);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        if (other->isInLayer(pixelroot32::physics::DefaultLayers::kProjectile)) {\n            // Hit by projectile\n            health--;\n            if (health <= 0) {\n                isEnabled = false;  // Remove enemy\n            }\n        }\n    }\n};\n
"},{"location":"api_reference/core/actor/#performance-considerations","title":"Performance Considerations","text":"
  • Collision layers: Use layers efficiently to reduce collision checks
  • Hitbox size: Keep hitboxes simple (AABB) for best performance
  • Collision callbacks: Keep onCollision() fast; avoid expensive operations
  • Layer organization: Group actors by layer to minimize checks
"},{"location":"api_reference/core/actor/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Collision checks: Collision system automatically optimizes using layers
  • Memory: Each actor consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse actors instead of creating/destroying frequently
"},{"location":"api_reference/core/actor/#see-also","title":"See Also","text":"
  • Entity - Base entity class
  • PhysicsActor - Entity with physics
  • CollisionSystem - Collision detection
  • CollisionTypes - Collision layer definitions
  • Manual - Scenes and Entities
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/core/engine/","title":"Engine","text":"

The main engine class that manages the game loop and core subsystems.

"},{"location":"api_reference/core/engine/#description","title":"Description","text":"

Engine acts as the central hub of the PixelRoot32 game engine. It initializes and manages the Renderer, InputManager, AudioEngine, and SceneManager. It runs the main game loop, handling timing (delta time), updating the current scene, and rendering frames.

The engine provides a unified interface for both ESP32 and Native (SDL2) platforms, abstracting platform-specific details while maintaining consistent behavior.

"},{"location":"api_reference/core/engine/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Engine {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/engine/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Application entry point (main.cpp)
"},{"location":"api_reference/core/engine/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/engine/#engineconst-displayconfig-displayconfig-const-inputconfig-inputconfig-const-audioconfig-audioconfig","title":"Engine(const DisplayConfig& displayConfig, const InputConfig& inputConfig, const AudioConfig& audioConfig)","text":"

Creates a new engine instance with custom display, input, and audio configurations.

Parameters: - displayConfig (const pixelroot32::graphics::DisplayConfig&): Configuration settings for the display (width, height, rotation, etc.) - inputConfig (const pixelroot32::input::InputConfig&): Configuration settings for the input system (pins, buttons) - audioConfig (const pixelroot32::audio::AudioConfig&): Configuration settings for the audio system (backend, sample rate, buffer size)

Example:

#include \"core/Engine.h\"\n#include \"graphics/DisplayConfig.h\"\n#include \"input/InputConfig.h\"\n#include \"audio/AudioConfig.h\"\n\npixelroot32::graphics::DisplayConfig displayConfig;\ndisplayConfig.logicalWidth = 128;\ndisplayConfig.logicalHeight = 128;\n\npixelroot32::input::InputConfig inputConfig;\n// Configure input pins...\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = pixelroot32::audio::AudioConfig::Backend::ESP32_DAC;\naudioConfig.sampleRate = 11025;\n\npixelroot32::core::Engine engine(displayConfig, inputConfig, audioConfig);\nengine.init();\nengine.run();\n

"},{"location":"api_reference/core/engine/#engineconst-displayconfig-displayconfig-const-inputconfig-inputconfig","title":"Engine(const DisplayConfig& displayConfig, const InputConfig& inputConfig)","text":"

Creates a new engine instance with custom display and input configurations, using default audio settings.

Parameters: - displayConfig (const pixelroot32::graphics::DisplayConfig&): Configuration settings for the display - inputConfig (const pixelroot32::input::InputConfig&): Configuration settings for the input system

Example:

pixelroot32::core::Engine engine(displayConfig, inputConfig);\nengine.init();\nengine.run();\n

"},{"location":"api_reference/core/engine/#engineconst-displayconfig-displayconfig","title":"Engine(const DisplayConfig& displayConfig)","text":"

Creates a new engine instance with custom display configuration and default input/audio settings.

Parameters: - displayConfig (const pixelroot32::graphics::DisplayConfig&): Configuration settings for the display

Example:

pixelroot32::core::Engine engine(displayConfig);\nengine.init();\nengine.run();\n

"},{"location":"api_reference/core/engine/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/engine/#void-init","title":"void init()","text":"

Initializes the engine subsystems. This method must be called before run().

Returns: - void

Notes: - Initializes the Renderer, InputManager, and sets up the initial state - Must be called after construction and before run() - Safe to call multiple times (idempotent)

Example:

Engine engine(displayConfig);\nengine.init();  // Initialize subsystems\nengine.setScene(myScene);\nengine.run();   // Start game loop\n

"},{"location":"api_reference/core/engine/#void-run","title":"void run()","text":"

Starts the main game loop. This method contains the infinite loop that calls update() and draw() repeatedly until the application exits.

Returns: - void

Notes: - This method blocks until the application exits - Handles frame timing and delta time calculation automatically - Calls update() and draw() once per frame - Do not call this method multiple times

Example:

Engine engine(displayConfig);\nengine.init();\nengine.setScene(myScene);\nengine.run();  // Blocks here, runs game loop\n

"},{"location":"api_reference/core/engine/#unsigned-long-getdeltatime-const","title":"unsigned long getDeltaTime() const","text":"

Gets the time elapsed since the last frame.

Returns: - unsigned long: The delta time in milliseconds

Performance Notes: - Very fast (inline accessor) - Safe to call every frame - Use this value to make movement frame-rate independent

Example:

void update(unsigned long deltaTime) override {\n    auto& engine = getEngine();\n    unsigned long dt = engine.getDeltaTime();\n\n    // Move at constant speed regardless of FPS\n    float speed = 100.0f;  // pixels per second\n    x += (speed * dt) / 1000.0f;\n}\n

"},{"location":"api_reference/core/engine/#void-setscenescene-newscene","title":"void setScene(Scene* newScene)","text":"

Sets the current active scene to be updated and rendered.

Parameters: - newScene (Scene*): Pointer to the new Scene to become active. Can be nullptr to clear the current scene.

Notes: - The previous scene is replaced (not pushed onto a stack) - Use SceneManager for push/pop operations if needed - The scene's init() method will be called automatically - Safe to call during the game loop

Example:

class MainMenuScene : public pixelroot32::core::Scene {\n    // ...\n};\n\nclass GameScene : public pixelroot32::core::Scene {\n    // ...\n};\n\nMainMenuScene menuScene;\nGameScene gameScene;\n\nEngine engine(displayConfig);\nengine.init();\nengine.setScene(&menuScene);  // Start with menu\nengine.run();\n

"},{"location":"api_reference/core/engine/#scene-getcurrentscene-const","title":"Scene* getCurrentScene() const","text":"

Retrieves the currently active scene.

Returns: - Scene*: Pointer to the current Scene, or nullptr if none is set

Example:

auto* currentScene = engine.getCurrentScene();\nif (currentScene) {\n    // Scene is active\n}\n

"},{"location":"api_reference/core/engine/#void-setrendererrenderer-newrenderer","title":"void setRenderer(Renderer& newRenderer)","text":"

Replaces the current renderer instance.

Parameters: - newRenderer (pixelroot32::graphics::Renderer&): Reference to the new Renderer to use

Notes: - Advanced usage: typically not needed unless implementing custom renderer - The renderer must be properly initialized before use - Use with caution: may break existing rendering code

"},{"location":"api_reference/core/engine/#renderer-getrenderer","title":"Renderer& getRenderer()","text":"

Provides access to the Renderer subsystem.

Returns: - pixelroot32::graphics::Renderer&: Reference to the current Renderer

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    auto& engineRenderer = engine.getRenderer();\n    engineRenderer.drawSprite(mySprite, 100, 100, Color::White);\n}\n

"},{"location":"api_reference/core/engine/#inputmanager-getinputmanager","title":"InputManager& getInputManager()","text":"

Provides access to the InputManager subsystem.

Returns: - pixelroot32::input::InputManager&: Reference to the InputManager

Example:

void update(unsigned long deltaTime) override {\n    auto& input = engine.getInputManager();\n    if (input.isButtonPressed(Buttons::A)) {\n        // Handle button press\n    }\n}\n

"},{"location":"api_reference/core/engine/#audioengine-getaudioengine","title":"AudioEngine& getAudioEngine()","text":"

Provides access to the AudioEngine subsystem.

Returns: - pixelroot32::audio::AudioEngine&: Reference to the AudioEngine

Example:

void playSound() {\n    auto& audio = engine.getAudioEngine();\n    pixelroot32::audio::AudioEvent sound{};\n    sound.type = pixelroot32::audio::WaveType::PULSE;\n    sound.frequency = 800.0f;\n    sound.duration = 0.1f;\n    audio.playEvent(sound);\n}\n

"},{"location":"api_reference/core/engine/#musicplayer-getmusicplayer","title":"MusicPlayer& getMusicPlayer()","text":"

Provides access to the MusicPlayer subsystem.

Returns: - pixelroot32::audio::MusicPlayer&: Reference to the MusicPlayer

Example:

void playMusic() {\n    auto& music = engine.getMusicPlayer();\n    music.playTrack(myMusicTrack);\n}\n

"},{"location":"api_reference/core/engine/#optional-debug-statistics-overlay","title":"Optional: Debug Statistics Overlay","text":"

When the engine is built with the preprocessor define PIXELROOT32_ENABLE_DEBUG_OVERLAY, an on-screen technical overlay is drawn each frame.

Metrics Included:

  • FPS: Frames per second (Green).
  • RAM: Used heap memory in KB (Cyan).
  • CPU: Estimated processor load percentage (Yellow).

Behavior:

  • The overlay is drawn in the top-right area of the screen.
  • It is rendered after the scene, making it fixed and independent of the camera.

Performance:

  • Metric values are recalculated and formatted only every 16 frames (DEBUG_UPDATE_INTERVAL).
  • Cached strings are drawn every frame to minimize per-frame cost (division and snprintf).

How to enable:

In platformio.ini, add to your environment's build_flags:

build_flags =\n    -D PIXELROOT32_ENABLE_DEBUG_OVERLAY\n

Alternatively, you can enable it in EngineConfig.h. The implementation uses the private method drawDebugOverlay(Renderer& r), which is only compiled when the define is set.

See also: Performance Tuning - Profiling and Platforms and Drivers - Build flags.

"},{"location":"api_reference/core/engine/#usage-example","title":"Usage Example","text":"
#include \"core/Engine.h\"\n#include \"graphics/DisplayConfig.h\"\n#include \"MyScene.h\"\n\nvoid setup() {\n    // Configure display\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    displayConfig.logicalWidth = 128;\n    displayConfig.logicalHeight = 128;\n    displayConfig.rotation = 0;\n\n    // Create engine\n    pixelroot32::core::Engine engine(displayConfig);\n\n    // Initialize\n    engine.init();\n\n    // Create and set scene\n    MyScene myScene;\n    engine.setScene(&myScene);\n\n    // Run game loop\n    engine.run();\n}\n
"},{"location":"api_reference/core/engine/#performance-considerations","title":"Performance Considerations","text":"
  • Initialization: init() should be called once at startup, not in the game loop
  • Scene switching: Switching scenes is fast but avoid doing it every frame
  • Subsystem access: Getters are inline and very fast; safe to call every frame
  • Delta time: Use getDeltaTime() for frame-rate independent movement
"},{"location":"api_reference/core/engine/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Ensure init() completes before run() to avoid initialization issues
  • Monitor memory usage when switching scenes frequently
  • Use getDeltaTime() for consistent gameplay across different frame rates
"},{"location":"api_reference/core/engine/#see-also","title":"See Also","text":"
  • Scene - Scene management
  • Renderer - Rendering system
  • InputManager - Input handling
  • AudioEngine - Audio system
  • Getting Started - Fundamental Concepts
  • Manual - Scenes and Entities
  • API Overview
"},{"location":"api_reference/core/entity/","title":"Entity","text":"

Abstract base class for all game objects.

"},{"location":"api_reference/core/entity/#description","title":"Description","text":"

Entity is the fundamental building block of the scene. Entities have a position, size, and lifecycle methods (update, draw). All game objects inherit from Entity, including actors, UI elements, and custom game objects.

Entities are managed by Scene and are automatically updated and drawn each frame when enabled and visible.

"},{"location":"api_reference/core/entity/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Entity {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/entity/#inheritance","title":"Inheritance","text":"
  • Base class: None (abstract base class)
  • Inherited by: Actor, UI elements, and your custom entity classes
"},{"location":"api_reference/core/entity/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/entity/#entityfloat-x-float-y-int-w-int-h-entitytype-t","title":"Entity(float x, float y, int w, int h, EntityType t)","text":"

Creates a new entity with specified position, size, and type.

Parameters: - x (float): Initial X position in world space - y (float): Initial Y position in world space - w (int): Width in pixels - h (int): Height in pixels - t (EntityType): The type of entity (GENERIC, ACTOR, UI_ELEMENT)

Example:

class MyEntity : public pixelroot32::core::Entity {\npublic:\n    MyEntity(float x, float y) \n        : Entity(x, y, 16, 16, EntityType::GENERIC) {}\n\n    void update(unsigned long deltaTime) override {\n        // Update logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw logic\n    }\n};\n

"},{"location":"api_reference/core/entity/#public-properties","title":"Public Properties","text":""},{"location":"api_reference/core/entity/#float-x-y","title":"float x, y","text":"

Position of the entity in world space.

Type: float

Access: Read-write

Notes: - Position is in world coordinates, not screen coordinates - Can be modified directly or through helper methods - Use for entity positioning and movement

Example:

entity->x = 100.0f;\nentity->y = 50.0f;\n

"},{"location":"api_reference/core/entity/#int-width-height","title":"int width, height","text":"

Dimensions of the entity in pixels.

Type: int

Access: Read-write

Notes: - Used for collision detection, rendering bounds, and layout - Should match the visual size of the entity - Can be modified at runtime if needed

Example:

entity->width = 32;\nentity->height = 32;\n

"},{"location":"api_reference/core/entity/#entitytype-type","title":"EntityType type","text":"

The specific type of this entity.

Type: EntityType enum

Access: Read-only (set in constructor)

Values: - EntityType::GENERIC: Generic entity - EntityType::ACTOR: Actor entity (with collision) - EntityType::UI_ELEMENT: UI element

Notes: - Used for type-safe casting and logic differentiation - Set once in constructor, typically not changed

"},{"location":"api_reference/core/entity/#bool-isvisible","title":"bool isVisible","text":"

If false, the entity's draw() method will not be called.

Type: bool

Access: Read-write

Default: true

Notes: - Use to hide entities without removing them from the scene - More efficient than removing and re-adding entities - Useful for object pooling

Example:

entity->isVisible = false;  // Hide entity\nentity->setVisible(true);   // Show entity\n

"},{"location":"api_reference/core/entity/#bool-isenabled","title":"bool isEnabled","text":"

If false, the entity's update() method will not be called.

Type: bool

Access: Read-write

Default: true

Notes: - Use to disable entity logic without removing it - Entity still exists but doesn't update - Useful for paused entities or object pooling

Example:

entity->isEnabled = false;  // Disable updates\nentity->setEnabled(true);   // Enable updates\n

"},{"location":"api_reference/core/entity/#unsigned-char-renderlayer","title":"unsigned char renderLayer","text":"

The render layer this entity is drawn on.

Type: unsigned char

Access: Read-write

Default: 1

Notes: - Layers are drawn in ascending order (0 = background, 1 = gameplay, 2 = UI) - Entities on the same layer are drawn in add order - Use to control draw order without changing entity order

Example:

entity->renderLayer = 0;  // Background layer\nentity->setRenderLayer(2); // UI layer\n

"},{"location":"api_reference/core/entity/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/entity/#virtual-void-setvisiblebool-v","title":"virtual void setVisible(bool v)","text":"

Sets the visibility of the entity.

Parameters: - v (bool): true to show, false to hide

Returns: - void

Notes: - Equivalent to setting isVisible directly - Can be overridden for custom visibility logic

Example:

entity->setVisible(false);  // Hide\nentity->setVisible(true);   // Show\n

"},{"location":"api_reference/core/entity/#virtual-void-setenabledbool-e","title":"virtual void setEnabled(bool e)","text":"

Sets the enabled state of the entity.

Parameters: - e (bool): true to enable, false to disable

Returns: - void

Notes: - Equivalent to setting isEnabled directly - Can be overridden for custom enable logic

Example:

entity->setEnabled(false);  // Disable updates\nentity->setEnabled(true);   // Enable updates\n

"},{"location":"api_reference/core/entity/#unsigned-char-getrenderlayer-const","title":"unsigned char getRenderLayer() const","text":"

Gets the current render layer.

Returns: - unsigned char: The render layer (0-255)

Example:

unsigned char layer = entity->getRenderLayer();\n

"},{"location":"api_reference/core/entity/#virtual-void-setrenderlayerunsigned-char-layer","title":"virtual void setRenderLayer(unsigned char layer)","text":"

Sets the render layer for this entity.

Parameters: - layer (unsigned char): The render layer (0 = background, 1 = gameplay, 2 = UI)

Returns: - void

Example:

entity->setRenderLayer(0);  // Background\n

"},{"location":"api_reference/core/entity/#virtual-void-updateunsigned-long-deltatime-0","title":"virtual void update(unsigned long deltaTime) = 0","text":"

Updates the entity's logic. Must be implemented by derived classes.

Parameters: - deltaTime (unsigned long): Time elapsed since the last frame in milliseconds

Returns: - void

Notes: - Called automatically by Scene every frame if isEnabled is true - Use deltaTime for frame-rate independent movement - Override to implement entity-specific update logic

Example:

void update(unsigned long deltaTime) override {\n    // Move entity\n    float speed = 50.0f;  // pixels per second\n    x += (speed * deltaTime) / 1000.0f;\n\n    // Wrap around screen\n    if (x > 128) {\n        x = 0;\n    }\n}\n

"},{"location":"api_reference/core/entity/#virtual-void-drawrenderer-renderer-0","title":"virtual void draw(Renderer& renderer) = 0","text":"

Renders the entity. Must be implemented by derived classes.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer to use for drawing

Returns: - void

Notes: - Called automatically by Scene every frame if isVisible is true - Entities are drawn in render layer order, then in add order - Override to implement entity-specific drawing logic

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Draw sprite at entity position\n    renderer.drawSprite(mySprite, static_cast<int>(x), static_cast<int>(y), Color::White);\n}\n

"},{"location":"api_reference/core/entity/#entitytype-enum","title":"EntityType Enum","text":"

Categorizes entities for type-safe casting and logic differentiation.

Values: - EntityType::GENERIC: Generic entity (default) - EntityType::ACTOR: Actor entity (with collision support) - EntityType::UI_ELEMENT: UI element

Example:

if (entity->type == EntityType::ACTOR) {\n    Actor* actor = static_cast<Actor*>(entity);\n    // Use actor-specific methods\n}\n

"},{"location":"api_reference/core/entity/#rect-structure","title":"Rect Structure","text":"

Represents a 2D rectangle, typically used for hitboxes or bounds.

Members: - float x, y: Top-left corner coordinates - int width, height: Dimensions of the rectangle

Methods: - bool intersects(const Rect& other): Checks if this rectangle intersects with another

Example:

pixelroot32::core::Rect rect1{10.0f, 20.0f, 50, 50};\npixelroot32::core::Rect rect2{30.0f, 40.0f, 50, 50};\n\nif (rect1.intersects(rect2)) {\n    // Rectangles overlap\n}\n

"},{"location":"api_reference/core/entity/#usage-example","title":"Usage Example","text":"
#include \"core/Entity.h\"\n\nclass Collectible : public pixelroot32::core::Entity {\nprivate:\n    const pixelroot32::graphics::Sprite* sprite;\n\npublic:\n    Collectible(float x, float y) \n        : Entity(x, y, 8, 8, EntityType::GENERIC),\n          sprite(&collectibleSprite) {}\n\n    void update(unsigned long deltaTime) override {\n        // Rotate or animate\n        rotation += deltaTime * 0.001f;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        if (isVisible) {\n            renderer.drawSprite(*sprite, \n                               static_cast<int>(x), \n                               static_cast<int>(y), \n                               Color::Yellow);\n        }\n    }\n\nprivate:\n    float rotation = 0.0f;\n};\n
"},{"location":"api_reference/core/entity/#performance-considerations","title":"Performance Considerations","text":"
  • Visibility: Use isVisible = false instead of removing entities when hiding
  • Enable state: Use isEnabled = false to pause entity logic
  • Render layers: Organize entities by layer to minimize layer switches
  • Direct access: Direct property access is fast (no function call overhead)
"},{"location":"api_reference/core/entity/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Each entity consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse entities instead of creating/destroying frequently
  • Update frequency: Disable entities that don't need to update every frame
"},{"location":"api_reference/core/entity/#see-also","title":"See Also","text":"
  • Scene - Scene management
  • Actor - Entity with collision support
  • PhysicsActor - Entity with physics
  • Manual - Scenes and Entities
  • API Overview
"},{"location":"api_reference/core/input_config/","title":"InputConfig","text":"

Configuration structure for the InputManager.

"},{"location":"api_reference/core/input_config/#description","title":"Description","text":"

InputConfig defines the mapping between logical inputs and physical pins (ESP32) or keyboard keys (Native/SDL2). It uses variadic arguments to allow flexible configuration of any number of inputs.

The configuration is platform-specific: ESP32 uses GPIO pin numbers, while Native uses SDL keyboard scancodes.

"},{"location":"api_reference/core/input_config/#namespace","title":"Namespace","text":"
namespace pixelroot32::input {\n    struct InputConfig {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/input_config/#structure","title":"Structure","text":""},{"location":"api_reference/core/input_config/#int-count","title":"int count","text":"

Total number of configured inputs.

Type: int

Access: Read-write

Default: 0

Notes: - Must match the number of arguments provided to constructor - Determines the size of the internal button array

"},{"location":"api_reference/core/input_config/#int-inputpins-esp32-only","title":"int* inputPins (ESP32 only)","text":"

Array of GPIO pin numbers for ESP32.

Type: int*

Access: Read-write

Default: nullptr

Notes: - Only available on ESP32 platform - Array size equals count - Pin numbers correspond to ESP32 GPIO pins - Use nullptr if count is 0

Example:

// ESP32: 6 buttons on pins 0, 2, 4, 5, 18, 19\npixelroot32::input::InputConfig config(6, 0, 2, 4, 5, 18, 19);\n// config.inputPins[0] = 0  (Up)\n// config.inputPins[1] = 2  (Down)\n// config.inputPins[2] = 4  (Left)\n// config.inputPins[3] = 5  (Right)\n// config.inputPins[4] = 18 (Button A)\n// config.inputPins[5] = 19 (Button B)\n

"},{"location":"api_reference/core/input_config/#uint8_t-buttonnames-native-only","title":"uint8_t* buttonNames (Native only)","text":"

Array of button mappings (scancodes) for Native.

Type: uint8_t*

Access: Read-write

Default: nullptr

Notes: - Only available on Native platform - Array size equals count - Values are SDL keyboard scancodes - Use nullptr if count is 0

Example:

// Native: Map to keyboard keys\n#include <SDL2/SDL.h>\n\npixelroot32::input::InputConfig config(6,\n    SDL_SCANCODE_UP,    // Index 0\n    SDL_SCANCODE_DOWN,  // Index 1\n    SDL_SCANCODE_LEFT,  // Index 2\n    SDL_SCANCODE_RIGHT, // Index 3\n    SDL_SCANCODE_X,     // Index 4 (Button A)\n    SDL_SCANCODE_Z      // Index 5 (Button B)\n);\n

"},{"location":"api_reference/core/input_config/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/input_config/#inputconfigint-count","title":"InputConfig(int count, ...)","text":"

Constructs a new InputConfig with variadic arguments.

Parameters: - count (int): Number of inputs to configure - ... (variadic): Variable arguments list of pins (ESP32) or scancodes (Native)

Notes: - If count <= 0, configuration is empty (nullptr arrays) - Allocates arrays dynamically based on count - Arguments must match count in number - Platform-specific: ESP32 expects int (GPIO pins), Native expects int (SDL scancodes)

ESP32 Example:

// Configure 4 directional buttons\npixelroot32::input::InputConfig config(4, 0, 2, 4, 5);\n// Pin 0 = Up, Pin 2 = Down, Pin 4 = Left, Pin 5 = Right\n\n// Configure 6 buttons (4 directions + 2 action buttons)\npixelroot32::input::InputConfig config(6, 0, 2, 4, 5, 18, 19);\n

Native Example:

#include <SDL2/SDL.h>\n\n// Configure 4 directional buttons\npixelroot32::input::InputConfig config(4,\n    SDL_SCANCODE_UP,\n    SDL_SCANCODE_DOWN,\n    SDL_SCANCODE_LEFT,\n    SDL_SCANCODE_RIGHT\n);\n\n// Configure 6 buttons (4 directions + 2 action buttons)\npixelroot32::input::InputConfig config(6,\n    SDL_SCANCODE_UP,\n    SDL_SCANCODE_DOWN,\n    SDL_SCANCODE_LEFT,\n    SDL_SCANCODE_RIGHT,\n    SDL_SCANCODE_X,  // Button A\n    SDL_SCANCODE_Z   // Button B\n);\n

"},{"location":"api_reference/core/input_config/#usage-example","title":"Usage Example","text":""},{"location":"api_reference/core/input_config/#esp32-configuration","title":"ESP32 Configuration","text":"
#include \"input/InputConfig.h\"\n#include \"input/InputManager.h\"\n#include \"core/Engine.h\"\n\nvoid setup() {\n    // Configure input: 6 buttons\n    // Pins: Up=0, Down=2, Left=4, Right=5, A=18, B=19\n    pixelroot32::input::InputConfig inputConfig(6, 0, 2, 4, 5, 18, 19);\n\n    // Create input manager\n    pixelroot32::input::InputManager inputManager(inputConfig);\n    inputManager.init();\n\n    // Or use with Engine\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    pixelroot32::core::Engine engine(displayConfig, inputConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/core/input_config/#native-configuration","title":"Native Configuration","text":"
#include \"input/InputConfig.h\"\n#include <SDL2/SDL.h>\n\nvoid setup() {\n    // Configure input: 6 buttons mapped to keyboard\n    pixelroot32::input::InputConfig inputConfig(6,\n        SDL_SCANCODE_UP,    // Index 0: Up\n        SDL_SCANCODE_DOWN,  // Index 1: Down\n        SDL_SCANCODE_LEFT,  // Index 2: Left\n        SDL_SCANCODE_RIGHT, // Index 3: Right\n        SDL_SCANCODE_X,     // Index 4: Button A\n        SDL_SCANCODE_Z      // Index 5: Button B\n    );\n\n    // Use with Engine\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    pixelroot32::core::Engine engine(displayConfig, inputConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/core/input_config/#platform-agnostic-configuration","title":"Platform-Agnostic Configuration","text":"
#ifdef PLATFORM_ESP32\n    // ESP32: Use GPIO pins\n    pixelroot32::input::InputConfig inputConfig(6, 0, 2, 4, 5, 18, 19);\n#elif PLATFORM_NATIVE\n    // Native: Use SDL scancodes\n    #include <SDL2/SDL.h>\n    pixelroot32::input::InputConfig inputConfig(6,\n        SDL_SCANCODE_UP,\n        SDL_SCANCODE_DOWN,\n        SDL_SCANCODE_LEFT,\n        SDL_SCANCODE_RIGHT,\n        SDL_SCANCODE_X,\n        SDL_SCANCODE_Z\n    );\n#endif\n
"},{"location":"api_reference/core/input_config/#button-index-mapping","title":"Button Index Mapping","text":"

Button indices are determined by the order in the constructor:

Typical Convention: - Index 0: Up / Primary action - Index 1: Down / Secondary action - Index 2: Left - Index 3: Right - Index 4+: Additional buttons

Example:

// 4-button D-pad\nInputConfig config(4, UP_PIN, DOWN_PIN, LEFT_PIN, RIGHT_PIN);\n// Index 0 = Up, Index 1 = Down, Index 2 = Left, Index 3 = Right\n\n// 6-button setup (D-pad + 2 action buttons)\nInputConfig config(6, UP_PIN, DOWN_PIN, LEFT_PIN, RIGHT_PIN, A_PIN, B_PIN);\n// Index 0-3 = D-pad, Index 4 = A, Index 5 = B\n

"},{"location":"api_reference/core/input_config/#esp32-pin-considerations","title":"ESP32 Pin Considerations","text":"
  • GPIO pins: Use any available GPIO pin
  • Pull-up/pull-down: Configure resistors appropriately
  • Input mode: Pins are automatically configured as inputs
  • Restrictions: Some pins have special functions (check ESP32 datasheet)

Common Pin Choices: - GPIO 0, 2, 4, 5: Safe for buttons (watch for boot mode pins) - GPIO 18, 19: Good for additional buttons - Avoid: GPIO 6-11 (flash), GPIO 34-39 (input only, no pull-up)

"},{"location":"api_reference/core/input_config/#native-sdl-scancode-reference","title":"Native SDL Scancode Reference","text":"

Common SDL scancodes:

  • SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT: Arrow keys
  • SDL_SCANCODE_W, SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_D: WASD
  • SDL_SCANCODE_X, SDL_SCANCODE_Z: Common action buttons
  • SDL_SCANCODE_SPACE: Spacebar
  • SDL_SCANCODE_RETURN: Enter key

Example:

// WASD + Space + Enter\npixelroot32::input::InputConfig config(6,\n    SDL_SCANCODE_W,        // Up\n    SDL_SCANCODE_S,        // Down\n    SDL_SCANCODE_A,        // Left\n    SDL_SCANCODE_D,         // Right\n    SDL_SCANCODE_SPACE,    // Jump\n    SDL_SCANCODE_RETURN    // Action\n);\n

"},{"location":"api_reference/core/input_config/#performance-considerations","title":"Performance Considerations","text":"
  • Memory: Arrays are allocated dynamically (small overhead)
  • Configuration: Done once at startup, no runtime cost
  • Access: Button indices are fast (array access)
"},{"location":"api_reference/core/input_config/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Pin configuration: Ensure pins are not used by other peripherals
  • Debouncing: Hardware debouncing recommended for reliable input
  • Power: Buttons should use pull-up resistors to avoid floating pins
"},{"location":"api_reference/core/input_config/#see-also","title":"See Also","text":"
  • InputManager - Input handling
  • Engine - Engine that uses InputConfig
  • Manual - Input and Control
  • API Overview
"},{"location":"api_reference/core/input_manager/","title":"InputManager","text":"

Handles input from physical buttons or keyboard (on PC).

"},{"location":"api_reference/core/input_manager/#description","title":"Description","text":"

The InputManager polls configured pins (ESP32) or keyboard state (Native), handles debouncing, and tracks button states (Pressed, Released, Down, Clicked). It provides a unified input interface for both platforms.

The manager supports edge detection (just pressed/released) and continuous state (held down), making it suitable for both gameplay and UI navigation.

"},{"location":"api_reference/core/input_manager/#namespace","title":"Namespace","text":"
namespace pixelroot32::input {\n    class InputManager {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/input_manager/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages input manager instance)
"},{"location":"api_reference/core/input_manager/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/input_manager/#inputmanagerconst-inputconfig-config","title":"InputManager(const InputConfig& config)","text":"

Constructs the InputManager with a specific configuration.

Parameters: - config (const InputConfig&): The input configuration (pins, button count)

Example:

#include \"input/InputManager.h\"\n#include \"input/InputConfig.h\"\n\n// ESP32: Configure GPIO pins\npixelroot32::input::InputConfig inputConfig(6, 0, 2, 4, 5, 18, 19);\npixelroot32::input::InputManager inputManager(inputConfig);\ninputManager.init();\n\n// Native: Configure keyboard keys\n// (Configuration handled differently on Native)\n

"},{"location":"api_reference/core/input_manager/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/input_manager/#void-init","title":"void init()","text":"

Initializes the input pins.

Returns: - void

Notes: - Must be called after construction and before use - Configures GPIO pins (ESP32) or keyboard state (Native) - Safe to call multiple times (idempotent) - Typically called automatically by Engine::init()

Example:

InputManager inputManager(inputConfig);\ninputManager.init();  // Initialize before use\n

"},{"location":"api_reference/core/input_manager/#void-updateunsigned-long-dt","title":"void update(unsigned long dt)","text":"

Updates input state by polling hardware pins (ESP32) or keyboard state (Native).

Parameters: - dt (unsigned long): Delta time in milliseconds

Returns: - void

Notes: - Must be called every frame for proper input detection - Handles debouncing automatically - Updates button states and edge detection - Typically called automatically by Engine::update()

ESP32 Example:

void update(unsigned long deltaTime) override {\n    // Input is updated automatically by Engine\n    // Access input via engine.getInputManager()\n}\n

Native Example:

// On Native, update is called with keyboard state:\nvoid update(unsigned long dt, const uint8_t* keyboardState);\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttonpresseduint8_t-buttonindex-const","title":"bool isButtonPressed(uint8_t buttonIndex) const","text":"

Checks if a button was just pressed this frame.

Parameters: - buttonIndex (uint8_t): Index of the button to check (0-based)

Returns: - bool: true if the button transitioned from UP to DOWN this frame

Notes: - Returns true only on the frame the button was pressed - Useful for one-time actions (jump, shoot, menu select) - Resets automatically on next frame

Example:

auto& input = engine.getInputManager();\n\nif (input.isButtonPressed(0)) {  // Button A (index 0)\n    // Jump (only once per press)\n    player->jump();\n}\n\nif (input.isButtonPressed(1)) {  // Button B (index 1)\n    // Shoot (only once per press)\n    player->shoot();\n}\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttonreleaseduint8_t-buttonindex-const","title":"bool isButtonReleased(uint8_t buttonIndex) const","text":"

Checks if a button was just released this frame.

Parameters: - buttonIndex (uint8_t): Index of the button to check

Returns: - bool: true if the button transitioned from DOWN to UP this frame

Notes: - Returns true only on the frame the button was released - Useful for detecting button release events - Less commonly used than isButtonPressed()

Example:

auto& input = engine.getInputManager();\n\nif (input.isButtonReleased(0)) {\n    // Button A was just released\n    player->stopCharging();\n}\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttonclickeduint8_t-buttonindex-const","title":"bool isButtonClicked(uint8_t buttonIndex) const","text":"

Checks if a button was clicked (pressed and released).

Parameters: - buttonIndex (uint8_t): Index of the button to check

Returns: - bool: true if the button was clicked (pressed then released)

Notes: - Returns true when button is released after being pressed - Useful for UI buttons and menu selection - Detects complete press-release cycle

Example:

auto& input = engine.getInputManager();\n\nif (input.isButtonClicked(0)) {  // Button A clicked\n    // Select menu item\n    menu->select();\n}\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttondownuint8_t-buttonindex-const","title":"bool isButtonDown(uint8_t buttonIndex) const","text":"

Checks if a button is currently held down.

Parameters: - buttonIndex (uint8_t): Index of the button to check

Returns: - bool: true if the button is currently in the DOWN state

Notes: - Returns true for as long as the button is held - Useful for continuous actions (movement, charging) - Use with deltaTime for frame-rate independent movement

Example:

auto& input = engine.getInputManager();\n\nfloat speed = 100.0f;  // pixels per second\nfloat vx = 0.0f, vy = 0.0f;\n\nif (input.isButtonDown(2)) {  // Left button\n    vx = -speed;\n}\nif (input.isButtonDown(3)) {  // Right button\n    vx = speed;\n}\nif (input.isButtonDown(0)) {  // Up button\n    vy = -speed;\n}\nif (input.isButtonDown(1)) {  // Down button\n    vy = speed;\n}\n\n// Apply movement (frame-rate independent)\nx += (vx * deltaTime) / 1000.0f;\ny += (vy * deltaTime) / 1000.0f;\n

"},{"location":"api_reference/core/input_manager/#button-indices","title":"Button Indices","text":"

Button indices are defined by the order in InputConfig:

Typical Mapping: - 0: Up / Button A - 1: Down / Button B - 2: Left - 3: Right - 4: Additional button 1 - 5: Additional button 2

Example:

// Configure 6 buttons: Up, Down, Left, Right, A, B\npixelroot32::input::InputConfig inputConfig(6, \n    GPIO_UP,    // Index 0\n    GPIO_DOWN,  // Index 1\n    GPIO_LEFT,  // Index 2\n    GPIO_RIGHT, // Index 3\n    GPIO_A,     // Index 4\n    GPIO_B      // Index 5\n);\n\n// Use indices\nif (input.isButtonDown(2)) {  // Left\n    moveLeft();\n}\nif (input.isButtonPressed(4)) {  // A button\n    jump();\n}\n

"},{"location":"api_reference/core/input_manager/#usage-example","title":"Usage Example","text":"
#include \"input/InputManager.h\"\n#include \"core/Engine.h\"\n\nclass PlayerController {\nprivate:\n    pixelroot32::core::Engine& engine;\n\npublic:\n    PlayerController(pixelroot32::core::Engine& eng) : engine(eng) {}\n\n    void update(unsigned long deltaTime) {\n        auto& input = engine.getInputManager();\n\n        // Movement (continuous)\n        float speed = 150.0f;  // pixels per second\n        float vx = 0.0f, vy = 0.0f;\n\n        if (input.isButtonDown(3)) {  // Right\n            vx = speed;\n        }\n        if (input.isButtonDown(2)) {  // Left\n            vx = -speed;\n        }\n        if (input.isButtonDown(0)) {  // Up\n            vy = -speed;\n        }\n        if (input.isButtonDown(1)) {  // Down\n            vy = speed;\n        }\n\n        // Apply movement\n        playerX += (vx * deltaTime) / 1000.0f;\n        playerY += (vy * deltaTime) / 1000.0f;\n\n        // Actions (one-time)\n        if (input.isButtonPressed(4)) {  // A button\n            player->jump();\n        }\n\n        if (input.isButtonPressed(5)) {  // B button\n            player->shoot();\n        }\n    }\n};\n
"},{"location":"api_reference/core/input_manager/#input-state-comparison","title":"Input State Comparison","text":"Method Returns true when Use Case isButtonPressed() Button just pressed this frame One-time actions (jump, shoot) isButtonReleased() Button just released this frame Release events (stop charging) isButtonClicked() Button pressed then released UI buttons, menu selection isButtonDown() Button currently held Continuous actions (movement)"},{"location":"api_reference/core/input_manager/#performance-considerations","title":"Performance Considerations","text":"
  • Update frequency: update() must be called every frame
  • Debouncing: Handled automatically, no performance impact
  • State queries: All query methods are fast (inline accessors)
  • Memory: Button state arrays are small and efficient
"},{"location":"api_reference/core/input_manager/#esp32-considerations","title":"ESP32 Considerations","text":"
  • GPIO pins: Configure pins in InputConfig
  • Pull-up/pull-down: Ensure proper resistor configuration
  • Debouncing: Hardware debouncing recommended for noisy buttons
  • Pin limits: Some ESP32 pins have restrictions (check datasheet)
"},{"location":"api_reference/core/input_manager/#native-considerations","title":"Native Considerations","text":"
  • Keyboard mapping: Uses SDL scancodes
  • Key detection: Automatically handles keyboard state
  • Multiple keys: Can detect multiple keys simultaneously
"},{"location":"api_reference/core/input_manager/#see-also","title":"See Also","text":"
  • InputConfig - Input configuration
  • Engine - Engine that manages InputManager
  • Manual - Input and Control
  • API Overview
"},{"location":"api_reference/core/physics_actor/","title":"PhysicsActor","text":"

An actor with basic 2D physics properties.

"},{"location":"api_reference/core/physics_actor/#description","title":"Description","text":"

PhysicsActor extends the base Actor class by adding velocity, acceleration, friction, restitution (bounciness), and world boundary collision resolution. It is designed for objects that need to move and bounce within a defined area, such as balls, projectiles, or platformer characters.

PhysicsActor automatically handles: - Velocity-based movement - Friction application - World boundary collision and bouncing - Collision callbacks

"},{"location":"api_reference/core/physics_actor/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class PhysicsActor : public Actor {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/physics_actor/#inheritance","title":"Inheritance","text":"
  • Inherits from: Actor
  • Inherited by: Your custom physics-enabled actor classes
"},{"location":"api_reference/core/physics_actor/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/physics_actor/#physicsactorfloat-x-float-y-float-w-float-h","title":"PhysicsActor(float x, float y, float w, float h)","text":"

Creates a physics-enabled actor with specified position and size.

Parameters: - x (float): Initial X position in world space - y (float): Initial Y position in world space - w (float): Actor width in pixels - h (float): Actor height in pixels

Notes: - Velocity starts at (0, 0) - Restitution defaults to 1.0 (perfect bounce) - Friction defaults to 0.0 (no friction) - No world limits by default

Example:

class BallActor : public pixelroot32::core::PhysicsActor {\npublic:\n    BallActor(float x, float y) \n        : PhysicsActor(x, y, 8.0f, 8.0f) {\n        // Set physics properties\n        setRestitution(0.8f);  // 80% bounce\n        setFriction(0.1f);     // Small friction\n        setWorldSize(128, 128); // World bounds\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledCircle(static_cast<int>(x + width/2), \n                                 static_cast<int>(y + height/2), \n                                 width/2, \n                                 Color::White);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        // Bounce off other actors\n    }\n\n    void onWorldCollision() override {\n        // Play bounce sound\n    }\n};\n

"},{"location":"api_reference/core/physics_actor/#protected-properties","title":"Protected Properties","text":""},{"location":"api_reference/core/physics_actor/#float-vx-vy","title":"float vx, vy","text":"

Horizontal and vertical velocity components.

Type: float

Access: Protected (use setVelocity() to modify)

Default: 0.0f

Notes: - Velocity is in pixels per second - Automatically applied during update() - Modified by friction and world collisions

"},{"location":"api_reference/core/physics_actor/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/physics_actor/#void-setvelocityfloat-x-float-y","title":"void setVelocity(float x, float y)","text":"

Sets the linear velocity of the actor.

Parameters: - x (float): Horizontal velocity in pixels per second - y (float): Vertical velocity in pixels per second

Returns: - void

Notes: - Velocity is applied every frame during update() - Use for initial velocity or impulse-based movement - Can be called every frame for continuous control

Example:

// Set initial velocity\nphysicsActor->setVelocity(100.0f, -200.0f);  // Move right and up\n\n// Continuous control (e.g., player movement)\nvoid update(unsigned long deltaTime) override {\n    PhysicsActor::update(deltaTime);\n\n    float speed = 150.0f;\n    float vx = 0.0f, vy = 0.0f;\n\n    if (input.isButtonDown(Buttons::LEFT)) vx = -speed;\n    if (input.isButtonDown(Buttons::RIGHT)) vx = speed;\n    if (input.isButtonDown(Buttons::UP)) vy = -speed;\n    if (input.isButtonDown(Buttons::DOWN)) vy = speed;\n\n    setVelocity(vx, vy);\n}\n

"},{"location":"api_reference/core/physics_actor/#void-setrestitutionfloat-r","title":"void setRestitution(float r)","text":"

Sets the restitution (bounciness) of the actor.

Parameters: - r (float): Restitution value (0.0 to 1.0+) - 0.0: No bounce (stops on impact) - 1.0: Perfect bounce (no energy loss) - > 1.0: Energy gain (unrealistic but possible)

Returns: - void

Notes: - Applied when actor collides with world boundaries - Higher values = more bouncy - Typical values: 0.5-0.9 for realistic bouncing

Example:

ball->setRestitution(0.8f);  // 80% bounce\n

"},{"location":"api_reference/core/physics_actor/#void-setfrictionfloat-f","title":"void setFriction(float f)","text":"

Sets the friction coefficient.

Parameters: - f (float): Friction value - 0.0: No friction (object continues moving) - > 0.0: Friction applied to velocity each frame

Returns: - void

Notes: - Applied every frame to reduce velocity - Higher values = more friction (slower movement) - Typical values: 0.05-0.2 for smooth deceleration

Example:

player->setFriction(0.1f);  // Light friction\n

"},{"location":"api_reference/core/physics_actor/#void-setlimitslimitrect-limits","title":"void setLimits(LimitRect limits)","text":"

Sets custom movement limits for the actor.

Parameters: - limits (LimitRect): A rectangle defining the allowed area

Returns: - void

Notes: - Overrides world size limits - Use -1 for any boundary to disable that limit - Actor will bounce off these boundaries

Example:

pixelroot32::core::LimitRect limits;\nlimits.left = 0;\nlimits.top = 0;\nlimits.right = 128;\nlimits.bottom = 128;\nphysicsActor->setLimits(limits);\n

"},{"location":"api_reference/core/physics_actor/#void-setworldsizeint-width-int-height","title":"void setWorldSize(int width, int height)","text":"

Defines the world size for boundary checking.

Parameters: - width (int): Width of the world in pixels - height (int): Height of the world in pixels

Returns: - void

Notes: - Used as default limits if no custom LimitRect is provided - Actor will bounce off world boundaries - Set to display size for screen boundaries

Example:

physicsActor->setWorldSize(128, 128);  // Match display size\n

"},{"location":"api_reference/core/physics_actor/#worldcollisioninfo-getworldcollisioninfo-const","title":"WorldCollisionInfo getWorldCollisionInfo() const","text":"

Gets information about collisions with the world boundaries.

Returns: - WorldCollisionInfo: A struct containing collision flags (left, right, top, bottom)

Notes: - Updated every frame during update() - Use to detect which boundary was hit - Useful for sound effects or special behaviors

Example:

void update(unsigned long deltaTime) override {\n    PhysicsActor::update(deltaTime);\n\n    auto collision = getWorldCollisionInfo();\n    if (collision.left || collision.right) {\n        // Hit side wall\n        playSound(wallHitSound);\n    }\n    if (collision.top || collision.bottom) {\n        // Hit top or bottom\n        playSound(ceilingHitSound);\n    }\n}\n

"},{"location":"api_reference/core/physics_actor/#virtual-void-oncollisionactor-other-override","title":"virtual void onCollision(Actor* other) override","text":"

Callback triggered when this actor collides with another actor.

Parameters: - other (Actor*): Pointer to the actor involved in the collision

Returns: - void

Notes: - Called automatically by the collision system - Override to implement custom collision responses - Default implementation does nothing

Example:

void onCollision(Actor* other) override {\n    if (other->isInLayer(DefaultLayers::kEnemy)) {\n        // Bounce off enemy\n        vx = -vx * 0.5f;\n        vy = -vy * 0.5f;\n    }\n}\n

"},{"location":"api_reference/core/physics_actor/#virtual-void-onworldcollision","title":"virtual void onWorldCollision()","text":"

Callback triggered when this actor collides with world boundaries.

Returns: - void

Notes: - Called automatically when a world boundary collision occurs - Override to implement custom behavior (sound effects, particles, etc.) - Default implementation does nothing

Example:

void onWorldCollision() override {\n    // Play bounce sound\n    auto& audio = engine.getAudioEngine();\n    pixelroot32::audio::AudioEvent sound{};\n    sound.type = pixelroot32::audio::WaveType::NOISE;\n    sound.frequency = 500.0f;\n    sound.duration = 0.05f;\n    audio.playEvent(sound);\n\n    // Spawn particles\n    spawnBounceParticles();\n}\n

"},{"location":"api_reference/core/physics_actor/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the actor state. Applies physics integration and checks for world boundary collisions.

Parameters: - deltaTime (unsigned long): Time elapsed since the last frame in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Applies velocity to position - Applies friction to velocity - Resolves world boundary collisions - Override to add custom update logic, but call PhysicsActor::update(deltaTime) first

Example:

void update(unsigned long deltaTime) override {\n    // Apply physics\n    PhysicsActor::update(deltaTime);\n\n    // Custom logic\n    if (shouldApplyGravity) {\n        vy += gravity * (deltaTime / 1000.0f);\n    }\n}\n

"},{"location":"api_reference/core/physics_actor/#limitrect-structure","title":"LimitRect Structure","text":"

Bounding rectangle for world-collision resolution.

Members: - int left: Left boundary (-1 means no limit) - int top: Top boundary (-1 means no limit) - int right: Right boundary (-1 means no limit) - int bottom: Bottom boundary (-1 means no limit)

Methods: - int width() const: Calculates width (right - left) - int height() const: Calculates height (bottom - top)

Example:

pixelroot32::core::LimitRect limits(10, 10, 118, 118);  // 10px margin\nphysicsActor->setLimits(limits);\n

"},{"location":"api_reference/core/physics_actor/#worldcollisioninfo-structure","title":"WorldCollisionInfo Structure","text":"

Information about world collisions in the current frame.

Members: - bool left: True if collided with the left boundary - bool right: True if collided with the right boundary - bool top: True if collided with the top boundary - bool bottom: True if collided with the bottom boundary

Example:

auto collision = physicsActor->getWorldCollisionInfo();\nif (collision.bottom) {\n    // On ground\n    canJump = true;\n}\n

"},{"location":"api_reference/core/physics_actor/#usage-example","title":"Usage Example","text":"
#include \"core/PhysicsActor.h\"\n\nclass BouncingBall : public pixelroot32::core::PhysicsActor {\npublic:\n    BouncingBall(float x, float y) \n        : PhysicsActor(x, y, 8.0f, 8.0f) {\n        // Set physics properties\n        setRestitution(0.9f);  // Very bouncy\n        setFriction(0.05f);    // Light friction\n        setWorldSize(128, 128);\n\n        // Set initial velocity\n        setVelocity(100.0f, -150.0f);\n\n        // Set collision layer\n        layer = pixelroot32::physics::DefaultLayers::kProjectile;\n        mask = pixelroot32::physics::DefaultLayers::kObstacle;\n    }\n\n    void update(unsigned long deltaTime) override {\n        PhysicsActor::update(deltaTime);\n\n        // Apply gravity\n        vy += 200.0f * (deltaTime / 1000.0f);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledCircle(static_cast<int>(x + width/2), \n                                 static_cast<int>(y + height/2), \n                                 width/2, \n                                 Color::White);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        // Bounce off obstacles\n        vx = -vx * 0.8f;\n        vy = -vy * 0.8f;\n    }\n\n    void onWorldCollision() override {\n        // Play bounce sound\n        playBounceSound();\n    }\n};\n
"},{"location":"api_reference/core/physics_actor/#performance-considerations","title":"Performance Considerations","text":"
  • Physics integration: Very efficient (simple velocity integration)
  • World bounds: Boundary checks are fast (AABB)
  • Friction: Applied every frame; keep friction values reasonable
  • Collision callbacks: Keep onCollision() and onWorldCollision() fast
"},{"location":"api_reference/core/physics_actor/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Floating point: Uses float math; acceptable for ESP32 but integer math would be faster
  • Frame rate: Physics is frame-rate independent (uses deltaTime)
  • Memory: Each PhysicsActor consumes more memory than Actor (velocity, limits, etc.)
"},{"location":"api_reference/core/physics_actor/#see-also","title":"See Also","text":"
  • Actor - Base actor class
  • CollisionSystem - Collision detection
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/core/scene/","title":"Scene","text":"

Represents a game level or screen containing entities.

"},{"location":"api_reference/core/scene/#description","title":"Description","text":"

A Scene manages a collection of Entities and a CollisionSystem. It is responsible for updating and drawing all entities it contains. Scenes provide lifecycle hooks (init(), update(), draw()) to manage gameplay segments.

Scenes are the primary organizational unit in PixelRoot32, similar to levels or screens in other game engines. Each scene can contain up to MAX_ENTITIES (default 32; overridable via compiler flags) entities, and drawing uses up to MAX_LAYERS (default 3; overridable) render layers.

"},{"location":"api_reference/core/scene/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Scene {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/scene/#inheritance","title":"Inheritance","text":"
  • Base class: None (abstract base class)
  • Inherited by: Your custom scene classes (e.g., MainMenuScene, GameScene)
"},{"location":"api_reference/core/scene/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/scene/#scene_1","title":"Scene()","text":"

Creates an empty scene ready to be populated with entities.

Notes: - The scene starts with no entities - init() should be called when the scene becomes active - The collision system is automatically initialized

Example:

class MyScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Initialize scene resources\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);  // Update entities and collisions\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        Scene::draw(renderer);  // Draw all entities\n    }\n};\n

"},{"location":"api_reference/core/scene/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/scene/#virtual-void-init","title":"virtual void init()","text":"

Initializes the scene. Called when entering the scene.

Returns: - void

Notes: - Called automatically when the scene is set via Engine::setScene() - Override this method to initialize scene-specific resources - Safe to call multiple times (idempotent) - Add entities here or in the constructor

Example:

class GameScene : public pixelroot32::core::Scene {\nprivate:\n    PlayerActor* player;\n    std::array<EnemyActor*, 10> enemies;\n\npublic:\n    void init() override {\n        // Create player\n        player = new PlayerActor();\n        addEntity(player);\n\n        // Create enemies\n        for (int i = 0; i < 10; i++) {\n            enemies[i] = new EnemyActor();\n            addEntity(enemies[i]);\n        }\n    }\n};\n

"},{"location":"api_reference/core/scene/#virtual-void-updateunsigned-long-deltatime","title":"virtual void update(unsigned long deltaTime)","text":"

Updates all entities in the scene and handles collisions.

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Notes: - Called automatically by the engine every frame - Updates all entities in the scene - Processes collisions between actors - Override to add custom update logic, but call Scene::update(deltaTime) to maintain entity updates

Example:

void update(unsigned long deltaTime) override {\n    // Custom update logic\n    gameTimer += deltaTime;\n\n    // Update entities and collisions\n    Scene::update(deltaTime);\n\n    // Additional logic after entity updates\n    if (gameTimer > 60000) {\n        // Game over after 60 seconds\n    }\n}\n

"},{"location":"api_reference/core/scene/#virtual-void-drawrenderer-renderer","title":"virtual void draw(Renderer& renderer)","text":"

Draws all visible entities in the scene.

Parameters: - renderer (pixelroot32::graphics::Renderer&): The renderer to use for drawing

Notes: - Called automatically by the engine every frame after update() - Draws all visible entities in the scene - Override to add custom drawing logic, but call Scene::draw(renderer) to maintain entity rendering - Entities are drawn in the order they were added

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Draw background\n    renderer.drawTileMap(backgroundTileMap, 0, 0, Color::White);\n\n    // Draw all entities\n    Scene::draw(renderer);\n\n    // Draw UI overlay\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n}\n

"},{"location":"api_reference/core/scene/#void-addentityentity-entity","title":"void addEntity(Entity* entity)","text":"

Adds an entity to the scene.

Parameters: - entity (Entity*): Pointer to the Entity to add. Must not be nullptr.

Notes: - Entities are added to an internal queue - Maximum of MAX_ENTITIES (default 32; overridable) entities per scene - If the limit is reached, the entity may not be added (check return value if available) - Entities are updated and drawn in the order they were added - The entity's lifetime is managed by the scene (do not delete manually while in scene)

Example:

void init() override {\n    // Create and add player\n    PlayerActor* player = new PlayerActor();\n    player->setPosition(64, 64);\n    addEntity(player);\n\n    // Create and add enemy\n    EnemyActor* enemy = new EnemyActor();\n    enemy->setPosition(100, 100);\n    addEntity(enemy);\n}\n

"},{"location":"api_reference/core/scene/#void-removeentityentity-entity","title":"void removeEntity(Entity* entity)","text":"

Removes an entity from the scene.

Parameters: - entity (Entity*): Pointer to the Entity to remove

Notes: - The entity is removed from the update and draw queues - The entity is not deleted automatically (you must manage its lifetime) - Safe to call even if the entity is not in the scene - Consider using object pooling instead of frequent add/remove

Example:

void onEnemyDestroyed(EnemyActor* enemy) {\n    removeEntity(enemy);\n    // Return to pool or delete\n    enemyPool.returnToPool(enemy);\n}\n

"},{"location":"api_reference/core/scene/#void-clearentities","title":"void clearEntities()","text":"

Removes all entities from the scene.

Notes: - All entities are removed from the update and draw queues - Entities are not deleted automatically (you must manage their lifetimes) - Useful for scene cleanup or reset - Consider using object pooling to reuse entities

Example:

void reset() {\n    clearEntities();\n    // Return all entities to pool\n    for (auto* entity : entityPool) {\n        entityPool.returnToPool(entity);\n    }\n}\n

"},{"location":"api_reference/core/scene/#protected-members","title":"Protected Members","text":""},{"location":"api_reference/core/scene/#arduinoqueue-entities","title":"ArduinoQueue entities

Queue of entities in the scene. Accessible to derived classes for custom entity management.

Type: ArduinoQueue<Entity*>

Notes: - Maximum capacity: MAX_ENTITIES (default 32; overridable) - Direct access allows custom iteration or filtering - Use with caution: modifying while iterating may cause issues

","text":""},{"location":"api_reference/core/scene/#collisionsystem-collisionsystem","title":"CollisionSystem collisionSystem

System to handle collisions between actors. Accessible to derived classes for custom collision handling.

Type: pixelroot32::physics::CollisionSystem

Notes: - Automatically processes collisions between actors - Uses collision layers and masks for filtering - Can be accessed for custom collision queries

","text":""},{"location":"api_reference/core/scene/#overriding-scene-limits-max_layers-max_entities","title":"Overriding scene limits (MAX_LAYERS / MAX_ENTITIES)","text":"

The engine defines default limits in core/Scene.h: MAX_LAYERS (default 3) and MAX_ENTITIES (default 32). These are guarded with #ifndef, so you can override them from your project without modifying the engine.

ESP32 platform limitation

The default of 3 for MAX_LAYERS is due to ESP32 platform constraints (memory and draw-loop cost). On native/PC you can safely use a higher value; on ESP32, increasing it may affect performance or memory.

"},{"location":"api_reference/core/scene/#option-a-compiler-flags-recommended","title":"Option A: Compiler flags (recommended)

In your project (e.g. in platformio.ini), add the defines to build_flags for the environment you use:

build_flags =\n    -DMAX_LAYERS=5\n    -DMAX_ENTITIES=64\n

The compiler defines MAX_LAYERS and MAX_ENTITIES before processing any .cpp file. Because Scene.h uses #ifndef MAX_LAYERS / #ifndef MAX_ENTITIES, it will not redefine them and your values will be used.

Effect: - MAX_LAYERS: Number of render layers drawn in Scene::draw() (layer 0 = background, 1+ = sprite context). Increasing this allows more distinct draw layers (e.g. background, platforms, gameplay, foreground, UI). - MAX_ENTITIES: On Arduino, the capacity of the scene entity queue when constructed with this value. On native (mock queue), the value is ignored (unbounded).

See also: Platforms and Drivers - Scene limits.

","text":""},{"location":"api_reference/core/scene/#usage-example","title":"Usage Example","text":"
#include \"core/Scene.h\"\n#include \"core/Actor.h\"\n\nclass MyGameScene : public pixelroot32::core::Scene {\nprivate:\n    PlayerActor* player;\n\npublic:\n    void init() override {\n        // Create player\n        player = new PlayerActor();\n        player->setPosition(64, 64);\n        addEntity(player);\n\n        // Create some enemies\n        for (int i = 0; i < 5; i++) {\n            EnemyActor* enemy = new EnemyActor();\n            enemy->setPosition(10 + i * 20, 10);\n            addEntity(enemy);\n        }\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Custom game logic\n        if (player->isDead()) {\n            // Handle game over\n        }\n\n        // Update entities and collisions\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background\n        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n\n        // Draw all entities\n        Scene::draw(renderer);\n\n        // Draw HUD\n        char scoreText[32];\n        snprintf(scoreText, sizeof(scoreText), \"Score: %d\", score);\n        renderer.drawText(scoreText, 10, 10, Color::White, 1);\n    }\n};\n
"},{"location":"api_reference/core/scene/#performance-considerations","title":"Performance Considerations","text":"
  • Entity limit: MAX_ENTITIES (default 32) can be overridden via compiler flags; plan accordingly
  • Add/Remove: Frequent add/remove operations can be expensive; use object pooling
  • Update order: Entities are updated in add order; consider order for dependencies
  • Collision checks: CollisionSystem automatically handles actor collisions efficiently
"},{"location":"api_reference/core/scene/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Each entity consumes memory; stay well below the limit
  • Object pooling: Essential for ESP32 to avoid memory fragmentation
  • Scene switching: Clearing and recreating scenes can fragment memory; reuse scenes when possible
"},{"location":"api_reference/core/scene/#see-also","title":"See Also","text":"
  • Entity - Base entity class
  • Actor - Entity with collision support
  • PhysicsActor - Entity with physics
  • CollisionSystem - Collision detection
  • Manual - Scenes and Entities
  • API Overview
"},{"location":"api_reference/graphics/camera2d/","title":"Camera2D","text":"

2D camera for scrolling and viewport control.

"},{"location":"api_reference/graphics/camera2d/#description","title":"Description","text":"

Camera2D controls viewport position and enables scrolling by shifting the renderer's display offset. It supports following targets, boundary constraints, and can be used for parallax effects.

The camera uses a dead-zone system: it only moves when the target is outside a central zone, creating smooth following behavior.

"},{"location":"api_reference/graphics/camera2d/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    class Camera2D {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/camera2d/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Scenes (for scrolling and camera control)
"},{"location":"api_reference/graphics/camera2d/#constructors","title":"Constructors","text":""},{"location":"api_reference/graphics/camera2d/#camera2dint-viewportwidth-int-viewportheight","title":"Camera2D(int viewportWidth, int viewportHeight)","text":"

Creates a new camera with specified viewport dimensions.

Parameters: - viewportWidth (int): Width of the viewport in pixels - viewportHeight (int): Height of the viewport in pixels

Notes: - Viewport size should match display size - Camera position starts at (0, 0) - No boundaries set by default (camera can move anywhere)

Example:

#include \"graphics/Camera2D.h\"\n\n// Create camera matching display size\npixelroot32::graphics::Camera2D camera(128, 128);\n\n// Or get from renderer\nint width = renderer.getWidth();\nint height = renderer.getHeight();\npixelroot32::graphics::Camera2D camera(width, height);\n

"},{"location":"api_reference/graphics/camera2d/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/graphics/camera2d/#void-setpositionfloat-x-float-y","title":"void setPosition(float x, float y)","text":"

Sets the camera position directly.

Parameters: - x (float): X position in world space - y (float): Y position in world space

Returns: - void

Notes: - Position is clamped to boundaries if set - Use for direct camera control or cutscenes - Overrides any following behavior

Example:

camera.setPosition(100.0f, 200.0f);\n

"},{"location":"api_reference/graphics/camera2d/#void-setboundsfloat-minx-float-maxx","title":"void setBounds(float minX, float maxX)","text":"

Sets horizontal boundaries for the camera.

Parameters: - minX (float): Minimum X position - maxX (float): Maximum X position

Returns: - void

Notes: - Camera position is clamped to these bounds - Use to prevent camera from going outside level bounds - Set both horizontal and vertical bounds for full constraint

Example:

// Level is 512 pixels wide, camera viewport is 128\n// Prevent camera from showing outside level\ncamera.setBounds(0.0f, 512.0f - 128.0f);\n

"},{"location":"api_reference/graphics/camera2d/#void-setverticalboundsfloat-miny-float-maxy","title":"void setVerticalBounds(float minY, float maxY)","text":"

Sets vertical boundaries for the camera.

Parameters: - minY (float): Minimum Y position - maxY (float): Maximum Y position

Returns: - void

Notes: - Camera position is clamped to these bounds - Use to prevent camera from going outside level bounds vertically

Example:

// Level is 512 pixels tall, camera viewport is 128\ncamera.setVerticalBounds(0.0f, 512.0f - 128.0f);\n

"},{"location":"api_reference/graphics/camera2d/#void-followtargetfloat-targetx","title":"void followTarget(float targetX)","text":"

Makes the camera follow a target horizontally only.

Parameters: - targetX (float): X position of the target to follow

Returns: - void

Notes: - Camera follows target with dead-zone behavior - Only horizontal movement; vertical position unchanged - Useful for side-scrolling games

Example:

void update(unsigned long deltaTime) override {\n    // Update player position\n    player->update(deltaTime);\n\n    // Camera follows player horizontally\n    camera.followTarget(player->x);\n    camera.apply(renderer);\n}\n

"},{"location":"api_reference/graphics/camera2d/#void-followtargetfloat-targetx-float-targety","title":"void followTarget(float targetX, float targetY)","text":"

Makes the camera follow a target in both axes.

Parameters: - targetX (float): X position of the target to follow - targetY (float): Y position of the target to follow

Returns: - void

Notes: - Camera follows target with dead-zone behavior - Both horizontal and vertical following - Useful for top-down or platformer games

Example:

void update(unsigned long deltaTime) override {\n    player->update(deltaTime);\n\n    // Camera follows player in both axes\n    camera.followTarget(player->x, player->y);\n    camera.apply(renderer);\n}\n

"},{"location":"api_reference/graphics/camera2d/#float-getx-const","title":"float getX() const","text":"

Gets the current X position of the camera.

Returns: - float: Current X position in world space

Example:

float cameraX = camera.getX();\n

"},{"location":"api_reference/graphics/camera2d/#float-gety-const","title":"float getY() const","text":"

Gets the current Y position of the camera.

Returns: - float: Current Y position in world space

Example:

float cameraY = camera.getY();\n

"},{"location":"api_reference/graphics/camera2d/#void-applyrenderer-renderer-const","title":"void apply(Renderer& renderer) const","text":"

Applies the camera's offset to the renderer.

Parameters: - renderer (Renderer&): The renderer to apply the camera offset to

Returns: - void

Notes: - Sets the renderer's display offset based on camera position - Should be called before drawing world elements - Negative offset is applied (camera moves right = world moves left)

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera offset\n    camera.apply(renderer);\n\n    // Draw world (offset applied automatically)\n    renderer.drawTileMap(levelMap, 0, 0, Color::White);\n    renderer.drawSprite(playerSprite, playerX, playerY, Color::White);\n\n    // UI elements (not affected by camera)\n    renderer.setDisplayOffset(0, 0);  // Reset for UI\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n}\n

"},{"location":"api_reference/graphics/camera2d/#dead-zone-following","title":"Dead-Zone Following","text":"

The camera uses a dead-zone system for smooth following:

  • Dead zone: Central area where camera doesn't move
  • Following: Camera moves only when target leaves dead zone
  • Smooth: Creates natural, non-jarring camera movement

Example:

// Camera follows player with dead zone\nvoid update(unsigned long deltaTime) override {\n    player->update(deltaTime);\n\n    // Camera follows (dead zone handled internally)\n    camera.followTarget(player->x, player->y);\n}\n

"},{"location":"api_reference/graphics/camera2d/#usage-example","title":"Usage Example","text":"
#include \"graphics/Camera2D.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n    TileMap levelMap;\n\npublic:\n    void init() override {\n        // Create camera matching display size\n        auto& renderer = engine.getRenderer();\n        camera = pixelroot32::graphics::Camera2D(\n            renderer.getWidth(), \n            renderer.getHeight()\n        );\n\n        // Set level boundaries\n        // Level is 512x512, viewport is 128x128\n        camera.setBounds(0.0f, 512.0f - 128.0f);\n        camera.setVerticalBounds(0.0f, 512.0f - 128.0f);\n\n        // Create player\n        player = new PlayerActor(64, 64);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Camera follows player\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw world (camera offset applied)\n        renderer.drawTileMap(levelMap, 0, 0, Color::White);\n\n        // Draw entities (Scene::draw handles this)\n        Scene::draw(renderer);\n\n        // Reset offset for UI\n        renderer.setDisplayOffset(0, 0);\n        renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n    }\n};\n
"},{"location":"api_reference/graphics/camera2d/#parallax-scrolling","title":"Parallax Scrolling","text":"

Use multiple cameras or manual offset for parallax:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Background layer (slow parallax)\n    float bgOffsetX = camera.getX() * 0.5f;  // 50% speed\n    renderer.setDisplayOffset(-bgOffsetX, 0);\n    renderer.drawTileMap(backgroundMap, 0, 0, Color::White);\n\n    // Midground layer (normal speed)\n    camera.apply(renderer);\n    renderer.drawTileMap(midgroundMap, 0, 0, Color::White);\n\n    // Foreground (entities, normal speed)\n    Scene::draw(renderer);\n\n    // UI (no offset)\n    renderer.setDisplayOffset(0, 0);\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n}\n
"},{"location":"api_reference/graphics/camera2d/#performance-considerations","title":"Performance Considerations","text":"
  • Apply frequency: apply() is fast; safe to call every frame
  • Boundary checks: Boundary clamping is efficient
  • Following: Dead-zone calculations are lightweight
"},{"location":"api_reference/graphics/camera2d/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Float math: Uses floating point; acceptable but integer math would be faster
  • Memory: Camera is small (few floats); minimal memory usage
"},{"location":"api_reference/graphics/camera2d/#see-also","title":"See Also","text":"
  • Renderer - Rendering system
  • Manual - Cameras and Scrolling
  • API Overview
"},{"location":"api_reference/graphics/color/","title":"Color","text":"

Color constants and palette management system.

"},{"location":"api_reference/graphics/color/#description","title":"Description","text":"

The Color enum provides color constants that map to palette indices. The engine supports both legacy mode (single global palette) and dual palette mode (separate palettes for backgrounds and sprites).

Colors are resolved to 16-bit RGB565 values based on the active palette(s).

"},{"location":"api_reference/graphics/color/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    enum class Color : uint8_t {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/color/#color-enum-values","title":"Color Enum Values","text":""},{"location":"api_reference/graphics/color/#standard-colors-pr32-palette-indices","title":"Standard Colors (PR32 Palette Indices)","text":"
  • Color::Black (0)
  • Color::White (1)
  • Color::Navy (2)
  • Color::Blue (3)
  • Color::Cyan (4)
  • Color::DarkGreen (5)
  • Color::Green (6)
  • Color::LightGreen (7)
  • Color::Yellow (8)
  • Color::Orange (9)
  • Color::LightRed (10)
  • Color::Red (11)
  • Color::DarkRed (12)
  • Color::Purple (13)
  • Color::Magenta (14)
  • Color::Gray (15)
"},{"location":"api_reference/graphics/color/#color-aliases","title":"Color Aliases","text":"

For compatibility, several aliases map to the closest available color:

  • Color::DarkBlue \u2192 Navy
  • Color::LightBlue \u2192 Blue
  • Color::Teal \u2192 Cyan
  • Color::Olive \u2192 DarkGreen
  • Color::Gold \u2192 Yellow
  • Color::Brown \u2192 DarkRed
  • Color::Pink \u2192 Magenta
  • Color::LightPurple \u2192 Magenta
  • Color::Maroon \u2192 DarkRed
  • Color::MidGray \u2192 Gray
  • Color::LightGray \u2192 Gray
  • Color::DarkGray \u2192 Gray
  • Color::Silver \u2192 Gray
"},{"location":"api_reference/graphics/color/#special-colors","title":"Special Colors","text":"
  • Color::Transparent (255): Not a real color; must be handled by renderer (results in no-op)
  • Color::DebugRed \u2192 Red
  • Color::DebugGreen \u2192 Green
  • Color::DebugBlue \u2192 Blue
"},{"location":"api_reference/graphics/color/#palettetype-enum","title":"PaletteType Enum","text":"

Built-in palette types:

  • PaletteType::NES: NES color palette
  • PaletteType::GB: Game Boy (4 shades of green)
  • PaletteType::GBC: Game Boy Color palette
  • PaletteType::PICO8: PICO-8 palette
  • PaletteType::PR32: PixelRoot32 default palette
"},{"location":"api_reference/graphics/color/#palettecontext-enum","title":"PaletteContext Enum","text":"

Context for palette selection in dual palette mode:

  • PaletteContext::Background: For backgrounds, tilemaps, and background primitives
  • PaletteContext::Sprite: For sprites, characters, and gameplay elements
"},{"location":"api_reference/graphics/color/#palette-functions","title":"Palette Functions","text":""},{"location":"api_reference/graphics/color/#void-setpalettepalettetype-palette","title":"void setPalette(PaletteType palette)","text":"

Selects the active color palette (legacy mode). Sets both background and sprite palettes to the same value.

Parameters: - palette (PaletteType): The palette to use

Notes: - Does not enable dual palette mode - All rendering uses the same palette - Use for simple games with single palette

Example:

pixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n

"},{"location":"api_reference/graphics/color/#void-setcustompaletteconst-uint16_t-palette","title":"void setCustomPalette(const uint16_t* palette)","text":"

Sets a custom color palette (legacy mode). Sets both background and sprite palettes to the same value.

Parameters: - palette (const uint16_t*): Pointer to an array of 16 uint16_t RGB565 color values

Notes: - Array must remain valid (use static/global storage) - Engine does not copy the palette - Does not enable dual palette mode

Example:

static const uint16_t MY_PALETTE[16] = {\n    0x0000,  // Black\n    0xFFFF,  // White\n    0x001F,  // Blue\n    // ... 13 more colors\n};\n\npixelroot32::graphics::setCustomPalette(MY_PALETTE);\n

"},{"location":"api_reference/graphics/color/#void-enabledualpalettemodebool-enable","title":"void enableDualPaletteMode(bool enable)","text":"

Enables or disables dual palette mode.

Parameters: - enable (bool): true to enable dual palette mode, false for legacy mode

Notes: - When enabled: backgrounds and sprites use separate palettes - When disabled: single palette for all rendering (legacy mode)

Example:

pixelroot32::graphics::enableDualPaletteMode(true);\n

"},{"location":"api_reference/graphics/color/#void-setbackgroundpalettepalettetype-palette","title":"void setBackgroundPalette(PaletteType palette)","text":"

Sets the background palette (for backgrounds, tilemaps, etc.).

Parameters: - palette (PaletteType): The palette type to use for backgrounds

Notes: - Only used in dual palette mode - Affects tilemaps, background primitives, etc.

Example:

pixelroot32::graphics::enableDualPaletteMode(true);\npixelroot32::graphics::setBackgroundPalette(pixelroot32::graphics::PaletteType::NES);\n

"},{"location":"api_reference/graphics/color/#void-setspritepalettepalettetype-palette","title":"void setSpritePalette(PaletteType palette)","text":"

Sets the sprite palette (for sprites, characters, etc.).

Parameters: - palette (PaletteType): The palette type to use for sprites

Notes: - Only used in dual palette mode - Affects sprites, characters, gameplay elements

Example:

pixelroot32::graphics::setSpritePalette(pixelroot32::graphics::PaletteType::GB);\n

"},{"location":"api_reference/graphics/color/#void-setdualpalettepalettetype-bgpalette-palettetype-spritepalette","title":"void setDualPalette(PaletteType bgPalette, PaletteType spritePalette)","text":"

Sets both background and sprite palettes at once. Automatically enables dual palette mode.

Parameters: - bgPalette (PaletteType): The palette type to use for backgrounds - spritePalette (PaletteType): The palette type to use for sprites

Example:

pixelroot32::graphics::setDualPalette(\n    pixelroot32::graphics::PaletteType::NES,  // Background\n    pixelroot32::graphics::PaletteType::GB     // Sprites\n);\n

"},{"location":"api_reference/graphics/color/#void-setbackgroundcustompaletteconst-uint16_t-palette","title":"void setBackgroundCustomPalette(const uint16_t* palette)","text":"

Sets a custom background palette.

Parameters: - palette (const uint16_t*): Pointer to an array of 16 uint16_t RGB565 color values

Notes: - Array must remain valid (use static/global storage) - Only used in dual palette mode

Example:

static const uint16_t BG_PALETTE[16] = { /* ... */ };\npixelroot32::graphics::enableDualPaletteMode(true);\npixelroot32::graphics::setBackgroundCustomPalette(BG_PALETTE);\n

"},{"location":"api_reference/graphics/color/#void-setspritecustompaletteconst-uint16_t-palette","title":"void setSpriteCustomPalette(const uint16_t* palette)","text":"

Sets a custom sprite palette.

Parameters: - palette (const uint16_t*): Pointer to an array of 16 uint16_t RGB565 color values

Notes: - Array must remain valid (use static/global storage) - Only used in dual palette mode

Example:

static const uint16_t SPRITE_PALETTE[16] = { /* ... */ };\npixelroot32::graphics::setSpriteCustomPalette(SPRITE_PALETTE);\n

"},{"location":"api_reference/graphics/color/#void-setdualcustompaletteconst-uint16_t-bgpalette-const-uint16_t-spritepal","title":"void setDualCustomPalette(const uint16_t bgPalette, const uint16_t spritePal)","text":"

Sets both background and sprite custom palettes at once. Automatically enables dual palette mode.

Parameters: - bgPalette (const uint16_t): Pointer to background palette array (16 RGB565 values) - spritePal (const uint16_t): Pointer to sprite palette array (16 RGB565 values)

Example:

static const uint16_t BG_PAL[16] = { /* ... */ };\nstatic const uint16_t SPRITE_PAL[16] = { /* ... */ };\npixelroot32::graphics::setDualCustomPalette(BG_PAL, SPRITE_PAL);\n

"},{"location":"api_reference/graphics/color/#uint16_t-resolvecolorcolor-color","title":"uint16_t resolveColor(Color color)","text":"

Resolves a Color enum to its corresponding 16-bit color value (legacy mode).

Parameters: - color (Color): The Color enum value

Returns: - uint16_t: The 16-bit RGB565 color value

Notes: - Uses the current active palette (single palette mode) - Color::Transparent must not be resolved (handled by renderer) - Typically called internally by renderer

Example:

uint16_t rgb565 = pixelroot32::graphics::resolveColor(pixelroot32::graphics::Color::Red);\n

"},{"location":"api_reference/graphics/color/#uint16_t-resolvecolorcolor-color-palettecontext-context","title":"uint16_t resolveColor(Color color, PaletteContext context)","text":"

Resolves a Color enum with context (dual palette mode).

Parameters: - color (Color): The Color enum value - context (PaletteContext): The palette context (Background or Sprite)

Returns: - uint16_t: The 16-bit RGB565 color value

Notes: - Uses the appropriate palette based on context - In legacy mode, context is ignored - Color::Transparent must not be resolved

Example:

uint16_t bgColor = pixelroot32::graphics::resolveColor(\n    pixelroot32::graphics::Color::Blue,\n    pixelroot32::graphics::PaletteContext::Background\n);\n

"},{"location":"api_reference/graphics/color/#rgb565-format","title":"RGB565 Format","text":"

Colors are stored as 16-bit RGB565 values:

  • Bits 15-11: Red (5 bits, 0-31)
  • Bits 10-5: Green (6 bits, 0-63)
  • Bits 4-0: Blue (5 bits, 0-31)

Conversion Example:

// Convert RGB to RGB565\nuint16_t rgb565 = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\n

"},{"location":"api_reference/graphics/color/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/graphics/color/#legacy-mode-single-palette","title":"Legacy Mode (Single Palette)","text":"
// Set single palette for all rendering\npixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n\n// Use colors\nrenderer.drawSprite(sprite, 100, 100, pixelroot32::graphics::Color::Red);\nrenderer.drawFilledRectangle(10, 10, 50, 50, pixelroot32::graphics::Color::Blue);\n
"},{"location":"api_reference/graphics/color/#dual-palette-mode","title":"Dual Palette Mode","text":"
// Enable dual palette mode\npixelroot32::graphics::enableDualPaletteMode(true);\n\n// Set different palettes for backgrounds and sprites\npixelroot32::graphics::setBackgroundPalette(pixelroot32::graphics::PaletteType::NES);\npixelroot32::graphics::setSpritePalette(pixelroot32::graphics::PaletteType::GB);\n\n// Or use convenience function\npixelroot32::graphics::setDualPalette(\n    pixelroot32::graphics::PaletteType::NES,\n    pixelroot32::graphics::PaletteType::GB\n);\n
"},{"location":"api_reference/graphics/color/#custom-palettes","title":"Custom Palettes","text":"
// Define custom palette (RGB565 values)\nstatic const uint16_t CUSTOM_PALETTE[16] = {\n    0x0000,  // 0: Black\n    0xFFFF,  // 1: White\n    0x001F,  // 2: Blue\n    0x07E0,  // 3: Green\n    0xF800,  // 4: Red\n    // ... 11 more colors\n};\n\n// Use in legacy mode\npixelroot32::graphics::setCustomPalette(CUSTOM_PALETTE);\n\n// Or use in dual palette mode\npixelroot32::graphics::enableDualPaletteMode(true);\npixelroot32::graphics::setBackgroundCustomPalette(CUSTOM_PALETTE);\npixelroot32::graphics::setSpriteCustomPalette(CUSTOM_PALETTE);\n
"},{"location":"api_reference/graphics/color/#performance-considerations","title":"Performance Considerations","text":"
  • Color resolution: Fast lookup operation
  • Palette switching: Changing palettes is fast (just pointer assignment)
  • Memory: Palettes are stored in flash (const arrays) for best performance
  • Dual mode: Slightly more overhead than legacy mode, but minimal
"},{"location":"api_reference/graphics/color/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Flash storage: Store custom palettes in flash (const/constexpr)
  • Memory: Palettes are small (16 uint16_t = 32 bytes)
  • Palette switching: Avoid switching palettes every frame
"},{"location":"api_reference/graphics/color/#see-also","title":"See Also","text":"
  • Renderer - Rendering system
  • Manual - Color Palettes
  • API Overview
"},{"location":"api_reference/graphics/display_config/","title":"DisplayConfig","text":"

Configuration settings for initializing the display.

"},{"location":"api_reference/graphics/display_config/#description","title":"Description","text":"

DisplayConfig holds display parameters used by the renderer and camera to draw correctly on the target device. It defines the display type, dimensions, rotation, and creates the appropriate DrawSurface implementation for the platform.

"},{"location":"api_reference/graphics/display_config/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    struct DisplayConfig {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/display_config/#displaytype-enum","title":"DisplayType Enum","text":"

Supported display types:

  • DisplayType::ST7789: 240x240 TFT display
  • DisplayType::ST7735: 128x128 TFT display
  • DisplayType::NONE: For SDL2 native (no driver needed)
"},{"location":"api_reference/graphics/display_config/#structure","title":"Structure","text":""},{"location":"api_reference/graphics/display_config/#displaytype-type","title":"DisplayType type","text":"

The type of display.

Type: DisplayType enum

Access: Read-write

Notes: - Determines which driver to use (ESP32) - NONE for Native/SDL2 platform

"},{"location":"api_reference/graphics/display_config/#int-rotation","title":"int rotation","text":"

Display rotation in degrees.

Type: int

Access: Read-write

Default: 0

Notes: - Common values: 0, 90, 180, 270 - Rotation is applied during initialization - Some displays may not support all rotations

"},{"location":"api_reference/graphics/display_config/#uint16_t-physicalwidth","title":"uint16_t physicalWidth","text":"

Physical hardware width of the display.

Type: uint16_t

Access: Read-write

Notes: - Defines the actual resolution of the display hardware.

"},{"location":"api_reference/graphics/display_config/#uint16_t-physicalheight","title":"uint16_t physicalHeight","text":"

Physical hardware height of the display.

Type: uint16_t

Access: Read-write

Notes: - Defines the actual resolution of the display hardware.

"},{"location":"api_reference/graphics/display_config/#uint16_t-logicalwidth","title":"uint16_t logicalWidth","text":"

Logical rendering width. This is the resolution the game \"sees\" and draws to.

Type: uint16_t

Access: Read-write

Notes: - If smaller than physicalWidth, the image will be scaled up. - Used for clipping, camera, and UI calculations. - Recommended values for ESP32: 160, 128, 96 (for 240 physical).

"},{"location":"api_reference/graphics/display_config/#uint16_t-logicalheight","title":"uint16_t logicalHeight","text":"

Logical rendering height. This is the resolution the game \"sees\" and draws to.

Type: uint16_t

Access: Read-write

Notes: - If smaller than physicalHeight, the image will be scaled up. - Used for clipping, camera, and UI calculations.

"},{"location":"api_reference/graphics/display_config/#uint16_t-width-deprecated","title":"uint16_t width() (Deprecated)","text":"

Alias for logicalWidth. Maintained for backward compatibility.

"},{"location":"api_reference/graphics/display_config/#uint16_t-height-deprecated","title":"uint16_t height() (Deprecated)","text":"

Alias for logicalHeight. Maintained for backward compatibility.

"},{"location":"api_reference/graphics/display_config/#int-xoffset","title":"int xOffset","text":"

X offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

"},{"location":"api_reference/graphics/display_config/#int-yoffset","title":"int yOffset","text":"

Y offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

"},{"location":"api_reference/graphics/display_config/#drawsurface-getdrawsurface-const","title":"DrawSurface& getDrawSurface() const","text":"

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed - Provides access to low-level display driver - Platform-specific implementation

"},{"location":"api_reference/graphics/display_config/#resolution-helpers","title":"Resolution Helpers","text":""},{"location":"api_reference/graphics/display_config/#bool-needsscaling-const","title":"bool needsScaling() const","text":"

Checks if the logical resolution differs from the physical resolution.

Returns: - bool: true if scaling is active.

"},{"location":"api_reference/graphics/display_config/#float-getscalex-const","title":"float getScaleX() const","text":"

Gets the horizontal scaling factor (physicalWidth / logicalWidth).

"},{"location":"api_reference/graphics/display_config/#float-getscaley-const","title":"float getScaleY() const","text":"

Gets the vertical scaling factor (physicalHeight / logicalHeight).

"},{"location":"api_reference/graphics/display_config/#constructors","title":"Constructors","text":""},{"location":"api_reference/graphics/display_config/#displayconfigdisplaytype-type-const-int-rot-uint16_t-physw-uint16_t-physh-uint16_t-logw-uint16_t-logh-const-int-xoff-0-const-int-yoff-0","title":"DisplayConfig(DisplayType type, const int rot, uint16_t physW, uint16_t physH, uint16_t logW, uint16_t logH, const int xOff = 0, const int yOff = 0)","text":"

Extended constructor that allows defining separate physical and logical resolutions.

Parameters: - type (DisplayType): The display type. - rot (int): Rotation (0-3 or degrees depending on implementation). - physW (uint16_t): Physical hardware width. - physH (uint16_t): Physical hardware height. - logW (uint16_t): Logical rendering width (0 = same as physical). - logH (uint16_t): Logical rendering height (0 = same as physical). - xOff (int, optional): X alignment offset. - yOff (int, optional): Y alignment offset.

Example:

// 128x128 game logic scaled to 240x240 display\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7789,\n    0,    // rotation\n    240, 240, // physical\n    128, 128  // logical\n);\n

"},{"location":"api_reference/graphics/display_config/#displayconfigdisplaytype-type-const-int-rot-0-uint16_t-w-240-uint16_t-h-240-const-int-xoffset-0-const-int-yoffset-0","title":"DisplayConfig(DisplayType type, const int rot = 0, uint16_t w = 240, uint16_t h = 240, const int xOffset = 0, const int yOffset = 0)","text":"

Legacy constructor for backward compatibility. Sets both logical and physical resolutions to the same values.

Notes: - Automatically creates the appropriate DrawSurface for the platform - ESP32: Creates TFT_eSPI_Drawer based on display type - Native: Creates SDL2_Drawer

Example:

// ST7789 display, 240x240, no rotation\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7789\n);\n\n// ST7735 display, 128x128, rotated 90 degrees\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7735,\n    90,   // rotation\n    128,  // physical width\n    128,  // physical height\n    128,  // logical width\n    128   // logical height\n);\n\n// Native/SDL2 (no specific display type)\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::NONE,\n    0,    // rotation\n    128, 128, // physical\n    128, 128  // logical\n);\n

"},{"location":"api_reference/graphics/display_config/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/graphics/display_config/#esp32-with-st7789","title":"ESP32 with ST7789","text":"
#ifdef PLATFORM_ESP32\n#include \"graphics/DisplayConfig.h\"\n\nvoid setup() {\n    // Configure ST7789 display (240x240 physical, 128x128 logical)\n    pixelroot32::graphics::DisplayConfig displayConfig(\n        pixelroot32::graphics::DisplayType::ST7789,\n        0,    // rotation\n        240, 240, // physical\n        128, 128  // logical\n    );\n\n    // Use with Engine\n    pixelroot32::core::Engine engine(displayConfig);\n    engine.init();\n    engine.run();\n}\n#endif\n
"},{"location":"api_reference/graphics/display_config/#esp32-with-st7735","title":"ESP32 with ST7735","text":"
#ifdef PLATFORM_ESP32\n    // Configure ST7735 display (128x128)\n    pixelroot32::graphics::DisplayConfig displayConfig(\n        pixelroot32::graphics::DisplayType::ST7735,\n        0,    // rotation\n        128, 128 // physical & logical\n    );\n#endif\n
"},{"location":"api_reference/graphics/display_config/#nativesdl2","title":"Native/SDL2","text":"
#ifdef PLATFORM_NATIVE\n    // Native display (SDL2 window)\n    pixelroot32::graphics::DisplayConfig displayConfig(\n        pixelroot32::graphics::DisplayType::NONE,\n        0,    // rotation\n        240, 240 // logical & physical\n    );\n#endif\n
"},{"location":"api_reference/graphics/display_config/#platform-agnostic-setup","title":"Platform-Agnostic Setup","text":"
#include \"graphics/DisplayConfig.h\"\n#include \"core/Engine.h\"\n\nvoid setup() {\n    pixelroot32::graphics::DisplayConfig displayConfig;\n\n    #ifdef PLATFORM_ESP32\n        displayConfig.type = pixelroot32::graphics::DisplayType::ST7789;\n        displayConfig.physicalWidth = 240;\n        displayConfig.physicalHeight = 240;\n        displayConfig.logicalWidth = 160; // 160x160 logic\n        displayConfig.logicalHeight = 160;\n    #elif PLATFORM_NATIVE\n        displayConfig.type = pixelroot32::graphics::DisplayType::NONE;\n        displayConfig.logicalWidth = 128;\n        displayConfig.logicalHeight = 128;\n    #endif\n\n    displayConfig.rotation = 0;\n\n    pixelroot32::core::Engine engine(displayConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/graphics/display_config/#display-type-details","title":"Display Type Details","text":""},{"location":"api_reference/graphics/display_config/#st7789","title":"ST7789","text":"
  • Resolution: Typically 240x240 or 240x320
  • Interface: SPI
  • Driver: TFT_eSPI
  • Common sizes: 240x240, 240x320
"},{"location":"api_reference/graphics/display_config/#st7735","title":"ST7735","text":"
  • Resolution: Typically 128x128 or 128x160
  • Interface: SPI
  • Driver: TFT_eSPI
  • Common sizes: 128x128, 128x160
"},{"location":"api_reference/graphics/display_config/#none-native","title":"NONE (Native)","text":"
  • Platform: Native/SDL2
  • Driver: SDL2_Drawer
  • Resolution: Configurable (any size)
  • Window: Creates SDL2 window
"},{"location":"api_reference/graphics/display_config/#rotation","title":"Rotation","text":"

Display rotation values:

  • 0: Normal orientation
  • 90: Rotated 90 degrees clockwise
  • 180: Rotated 180 degrees
  • 270: Rotated 90 degrees counter-clockwise

Notes: - Rotation affects coordinate system - Some displays may not support all rotations - Test rotation on your specific hardware

"},{"location":"api_reference/graphics/display_config/#performance-considerations","title":"Performance Considerations","text":"
  • Initialization: Display initialization happens once at startup
  • Driver selection: Automatic based on platform and type
  • Memory: DisplayConfig is small (few fields)
"},{"location":"api_reference/graphics/display_config/#esp32-considerations","title":"ESP32 Considerations","text":""},{"location":"api_reference/graphics/display_config/#tft_espi-configuration","title":"TFT_eSPI Configuration","text":"

DisplayConfig uses TFT_eSPI driver. Additional configuration may be needed in platformio.ini:

build_flags =\n    -DUSER_SETUP_LOADED=1\n    -DST7789_DRIVER=1\n    -DTFT_WIDTH=240\n    -DTFT_HEIGHT=240\n    # ... pin configuration\n
"},{"location":"api_reference/graphics/display_config/#pin-configuration","title":"Pin Configuration","text":"

GPIO pins must be configured separately (not in DisplayConfig):

  • MOSI: Data pin
  • SCLK: Clock pin
  • DC: Data/Command pin
  • RST: Reset pin
  • CS: Chip select pin (optional)
"},{"location":"api_reference/graphics/display_config/#see-also","title":"See Also","text":"
  • Renderer - Rendering system
  • Camera2D - Camera that uses display dimensions
  • Manual - Platforms and Drivers
  • API Overview
"},{"location":"api_reference/graphics/font/","title":"Font","text":"

Descriptor for a bitmap font using 1bpp sprites.

"},{"location":"api_reference/graphics/font/#description","title":"Description","text":"

A Font contains an array of Sprite structures, one for each character in the font's character set. Each glyph is rendered as a 1bpp sprite, allowing consistent rendering across platforms.

The font uses fixed-width glyphs for simplicity and performance. All glyphs share the same width and height, with spacing between characters controlled by the spacing field.

"},{"location":"api_reference/graphics/font/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    struct Font {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/font/#structure","title":"Structure","text":""},{"location":"api_reference/graphics/font/#const-sprite-glyphs","title":"const Sprite* glyphs","text":"

Array of sprites, one per character (indexed by character code - firstChar).

Type: const Sprite*

Access: Read-only

Notes: - Array must contain sprites for all characters from firstChar to lastChar - Each sprite represents one character glyph - Should be stored in flash (const/constexpr) for best performance

Example:

static const Sprite FONT_GLYPHS[] = {\n    spaceGlyph,    // Index 0 = ' ' (firstChar = 32)\n    exclamationGlyph, // Index 1 = '!'\n    // ... more glyphs\n};\n\nstatic const Font myFont = {\n    FONT_GLYPHS,\n    32,  // firstChar\n    126, // lastChar\n    5,   // glyphWidth\n    7,   // glyphHeight\n    1,   // spacing\n    8    // lineHeight\n};\n

"},{"location":"api_reference/graphics/font/#uint8_t-firstchar","title":"uint8_t firstChar","text":"

First character code in the font.

Type: uint8_t

Access: Read-only

Default: Typically 32 (space character)

Notes: - ASCII code of the first character - Common: 32 (space ' ') for ASCII fonts - Glyphs array starts at index 0 for this character

Example:

firstChar = 32;  // Starts at space character\n

"},{"location":"api_reference/graphics/font/#uint8_t-lastchar","title":"uint8_t lastChar","text":"

Last character code in the font.

Type: uint8_t

Access: Read-only

Default: Typically 126 (tilde '~')

Notes: - ASCII code of the last character - Common: 126 (tilde '~') for full ASCII fonts - Glyphs array must contain (lastChar - firstChar + 1) sprites

Example:

lastChar = 126;  // Ends at tilde character\n// Font contains characters 32-126 (95 characters)\n

"},{"location":"api_reference/graphics/font/#uint8_t-glyphwidth","title":"uint8_t glyphWidth","text":"

Fixed width of each glyph in pixels.

Type: uint8_t

Access: Read-only

Notes: - All glyphs must have the same width - Typical values: 5, 6, 8 pixels - Smaller = more characters per line, less readable

Example:

glyphWidth = 5;  // 5 pixels wide (like FONT_5X7)\n

"},{"location":"api_reference/graphics/font/#uint8_t-glyphheight","title":"uint8_t glyphHeight","text":"

Fixed height of each glyph in pixels.

Type: uint8_t

Access: Read-only

Notes: - All glyphs must have the same height - Typical values: 7, 8, 10 pixels - Smaller = more lines, less readable

Example:

glyphHeight = 7;  // 7 pixels tall (like FONT_5X7)\n

"},{"location":"api_reference/graphics/font/#uint8_t-spacing","title":"uint8_t spacing","text":"

Horizontal spacing between characters in pixels.

Type: uint8_t

Access: Read-only

Default: Typically 1

Notes: - Space added between characters - 0 = no spacing (characters touch) - 1 = 1 pixel gap (common) - Higher values = more readable but wider text

Example:

spacing = 1;  // 1 pixel between characters\n

"},{"location":"api_reference/graphics/font/#uint8_t-lineheight","title":"uint8_t lineHeight","text":"

Total line height including vertical spacing.

Type: uint8_t

Access: Read-only

Notes: - Should be glyphHeight + verticalSpacing - Used for line breaks and multi-line text - Typical: glyphHeight + 1 or glyphHeight + 2

Example:

lineHeight = 8;  // 7 pixel glyph + 1 pixel spacing\n

"},{"location":"api_reference/graphics/font/#built-in-fonts","title":"Built-in Fonts","text":""},{"location":"api_reference/graphics/font/#font_5x7","title":"FONT_5X7","text":"

Standard 5x7 pixel font (built-in).

Properties: - Width: 5 pixels - Height: 7 pixels - Characters: Typically ASCII 32-126 - Spacing: 1 pixel - Line height: 8 pixels

Usage:

#include \"graphics/Font.h\"\n\nrenderer.drawText(\"Hello\", 10, 10, Color::White, 1, &FONT_5X7);\n

"},{"location":"api_reference/graphics/font/#creating-custom-fonts","title":"Creating Custom Fonts","text":""},{"location":"api_reference/graphics/font/#step-1-create-glyph-sprites","title":"Step 1: Create Glyph Sprites","text":"
// Space character (ASCII 32)\nstatic const uint16_t SPACE_GLYPH[] = {\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000\n};\n\n// 'A' character (ASCII 65)\nstatic const uint16_t A_GLYPH[] = {\n    0b00100,\n    0b01010,\n    0b10001,\n    0b11111,\n    0b10001,\n    0b10001,\n    0b00000\n};\n\n// ... more glyphs\n
"},{"location":"api_reference/graphics/font/#step-2-create-glyph-array","title":"Step 2: Create Glyph Array","text":"
static const Sprite FONT_GLYPHS[] = {\n    {SPACE_GLYPH, 5, 7},  // Index 0 = ' ' (32)\n    // ... more glyphs\n    {A_GLYPH, 5, 7},      // Index 33 = 'A' (65)\n    // ... more glyphs\n};\n
"},{"location":"api_reference/graphics/font/#step-3-create-font-structure","title":"Step 3: Create Font Structure","text":"
static const Font MY_FONT = {\n    FONT_GLYPHS,  // glyphs array\n    32,           // firstChar (space)\n    126,          // lastChar (tilde)\n    5,            // glyphWidth\n    7,            // glyphHeight\n    1,            // spacing\n    8             // lineHeight\n};\n
"},{"location":"api_reference/graphics/font/#step-4-use-font","title":"Step 4: Use Font","text":"
renderer.drawText(\"Hello\", 10, 10, Color::White, 1, &MY_FONT);\n
"},{"location":"api_reference/graphics/font/#usage-example","title":"Usage Example","text":"
#include \"graphics/Font.h\"\n#include \"graphics/Renderer.h\"\n\n// Using built-in font\nvoid draw(Renderer& renderer) override {\n    // Default font\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n\n    // Explicit font\n    renderer.drawText(\"Score: 100\", 10, 30, Color::White, 1, &FONT_5X7);\n\n    // Centered text with font\n    renderer.drawTextCentered(\"Game Over\", 64, Color::Yellow, 2, &FONT_5X7);\n}\n\n// Custom font example\nstatic const uint16_t CUSTOM_GLYPHS[][7] = {\n    // Space, A, B, C, etc.\n};\n\nstatic const Sprite CUSTOM_SPRITES[] = {\n    {CUSTOM_GLYPHS[0], 6, 8},  // Space\n    {CUSTOM_GLYPHS[1], 6, 8},  // A\n    // ... more\n};\n\nstatic const Font CUSTOM_FONT = {\n    CUSTOM_SPRITES,\n    32,   // firstChar\n    90,   // lastChar (A-Z only)\n    6,    // width\n    8,    // height\n    1,    // spacing\n    9     // lineHeight\n};\n\nvoid draw(Renderer& renderer) override {\n    renderer.drawText(\"CUSTOM\", 10, 10, Color::White, 1, &CUSTOM_FONT);\n}\n
"},{"location":"api_reference/graphics/font/#text-sizing","title":"Text Sizing","text":"

Calculate text dimensions:

int getTextWidth(const Font* font, const char* text) {\n    if (!font || !text) return 0;\n\n    int width = 0;\n    for (int i = 0; text[i] != '\\0'; i++) {\n        if (text[i] >= font->firstChar && text[i] <= font->lastChar) {\n            width += font->glyphWidth + font->spacing;\n        }\n    }\n    return width - font->spacing;  // Remove last spacing\n}\n\nint getTextHeight(const Font* font) {\n    return font ? font->lineHeight : 8;\n}\n
"},{"location":"api_reference/graphics/font/#performance-considerations","title":"Performance Considerations","text":"
  • Font storage: Store fonts in flash (const/constexpr) for best performance
  • Glyph lookup: Fast array access (character code - firstChar)
  • Fixed width: Fixed-width fonts are faster than variable-width
  • Font switching: Changing fonts is fast (just pointer assignment)
"},{"location":"api_reference/graphics/font/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store font data in flash, not RAM
  • Font size: Larger fonts use more flash memory
  • Character range: Limit character range to save memory if not needed
"},{"location":"api_reference/graphics/font/#see-also","title":"See Also","text":"
  • Renderer - Rendering system that uses fonts
  • Sprite - Sprite structure used for glyphs
  • Manual - Basic Rendering
  • API Overview
"},{"location":"api_reference/graphics/renderer/","title":"Renderer","text":"

High-level graphics rendering system for drawing shapes, text, sprites, and tilemaps.

"},{"location":"api_reference/graphics/renderer/#description","title":"Description","text":"

The Renderer class provides a unified API for drawing shapes, text, and images. It abstracts the underlying hardware implementation (DrawSurface) and manages display configuration, including rotation and resolution scaling.

All drawing operations are performed in logical screen space. If the logical resolution differs from the physical resolution, the renderer will automatically scale the output to fit the display using a high-performance nearest-neighbor algorithm.

The renderer uses integer-only math for optimal performance on ESP32 and supports multiple sprite formats (1bpp, 2bpp, 4bpp) and multi-layer sprites.

"},{"location":"api_reference/graphics/renderer/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    class Renderer {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/renderer/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages renderer instance)
"},{"location":"api_reference/graphics/renderer/#constructors","title":"Constructors","text":""},{"location":"api_reference/graphics/renderer/#rendererconst-displayconfig-config","title":"Renderer(const DisplayConfig& config)","text":"

Constructs the Renderer with a specific display configuration.

Parameters: - config (const DisplayConfig&): The display configuration settings (width, height, rotation, etc.)

Example:

#include \"graphics/Renderer.h\"\n#include \"graphics/DisplayConfig.h\"\n\n// 128x128 game logic scaled to 240x240 display\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7789,\n    0,      // rotation\n    240, 240, // physical resolution\n    128, 128  // logical resolution (rendering space)\n);\n\npixelroot32::graphics::Renderer renderer(config);\nrenderer.init();\n

"},{"location":"api_reference/graphics/renderer/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/graphics/renderer/#void-init","title":"void init()","text":"

Initializes the renderer and the underlying draw surface.

Returns: - void

Notes: - Must be called after construction and before any drawing operations - Initializes the platform-specific DrawSurface implementation - Safe to call multiple times (idempotent)

Example:

Renderer renderer(displayConfig);\nrenderer.init();  // Initialize before use\n

"},{"location":"api_reference/graphics/renderer/#void-beginframe","title":"void beginFrame()","text":"

Prepares the buffer for a new frame (clears screen).

Returns: - void

Notes: - Should be called once at the start of each frame - Clears the display buffer - Typically called automatically by Engine, but can be called manually

Example:

void draw(Renderer& renderer) override {\n    renderer.beginFrame();\n    // Draw everything...\n    renderer.endFrame();\n}\n

"},{"location":"api_reference/graphics/renderer/#void-endframe","title":"void endFrame()","text":"

Finalizes the frame and sends the buffer to the display.

Returns: - void

Notes: - Should be called once at the end of each frame - Sends the completed frame buffer to the display - Typically called automatically by Engine, but can be called manually

"},{"location":"api_reference/graphics/renderer/#drawsurface-getdrawsurface","title":"DrawSurface& getDrawSurface()","text":"

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed unless implementing custom drawing - Provides low-level access to the display driver

"},{"location":"api_reference/graphics/renderer/#void-drawtextconst-char-text-int16_t-x-int16_t-y-color-color-uint8_t-size","title":"void drawText(const char* text, int16_t x, int16_t y, Color color, uint8_t size)","text":"

Draws a string of text using the default font and scaling.

Parameters: - text (const char*): The text to draw (null-terminated string) - x (int16_t): X coordinate (top-left corner of text) - y (int16_t): Y coordinate (top-left corner of text) - color (Color): Text color - size (uint8_t): Text size multiplier (1 = 5x7 pixels, 2 = 10x14 pixels, etc.)

Performance Notes: - Efficient for small amounts of text - Uses integer-only scaling (no floats)

Example:

renderer.drawText(\"Hello World\", 10, 10, Color::White, 1);\nrenderer.drawText(\"Score: 100\", 10, 30, Color::Yellow, 2);\n

"},{"location":"api_reference/graphics/renderer/#void-drawtextconst-char-text-int16_t-x-int16_t-y-color-color-uint8_t-size-const-font-font","title":"void drawText(const char text, int16_t x, int16_t y, Color color, uint8_t size, const Font font)","text":"

Draws a string of text using a specific font and scaling.

Parameters: - text (const char): The text to draw - x (int16_t): X coordinate - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size multiplier - font (const Font): Pointer to the font to use. If nullptr, uses the default font

Example:

const Font* customFont = &FONT_5X7;\nrenderer.drawText(\"Custom Font\", 10, 10, Color::White, 1, customFont);\n

"},{"location":"api_reference/graphics/renderer/#void-drawtextcenteredconst-char-text-int16_t-y-color-color-uint8_t-size","title":"void drawTextCentered(const char* text, int16_t y, Color color, uint8_t size)","text":"

Draws text centered horizontally at a given Y coordinate using the default font.

Parameters: - text (const char*): The text to draw - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size

Example:

renderer.drawTextCentered(\"Game Over\", 64, Color::White, 2);\n

"},{"location":"api_reference/graphics/renderer/#void-drawtextcenteredconst-char-text-int16_t-y-color-color-uint8_t-size-const-font-font","title":"void drawTextCentered(const char text, int16_t y, Color color, uint8_t size, const Font font)","text":"

Draws text centered horizontally at a given Y coordinate using a specific font.

Parameters: - text (const char): The text to draw - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size - font (const Font): Pointer to the font to use. If nullptr, uses the default font

"},{"location":"api_reference/graphics/renderer/#void-drawfilledcircleint-x-int-y-int-radius-color-color","title":"void drawFilledCircle(int x, int y, int radius, Color color)","text":"

Draws a filled circle.

Parameters: - x (int): Center X coordinate - y (int): Center Y coordinate - radius (int): Radius of the circle in pixels - color (Color): Fill color

Example:

renderer.drawFilledCircle(64, 64, 20, Color::Red);\n

"},{"location":"api_reference/graphics/renderer/#void-drawcircleint-x-int-y-int-radius-color-color","title":"void drawCircle(int x, int y, int radius, Color color)","text":"

Draws a circle outline.

Parameters: - x (int): Center X coordinate - y (int): Center Y coordinate - radius (int): Radius of the circle in pixels - color (Color): Outline color

Example:

renderer.drawCircle(64, 64, 20, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-drawrectangleint-x-int-y-int-width-int-height-color-color","title":"void drawRectangle(int x, int y, int width, int height, Color color)","text":"

Draws a rectangle outline.

Parameters: - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - width (int): Width of the rectangle in pixels - height (int): Height of the rectangle in pixels - color (Color): Outline color

Example:

renderer.drawRectangle(10, 10, 100, 50, Color::Blue);\n

"},{"location":"api_reference/graphics/renderer/#void-drawfilledrectangleint-x-int-y-int-width-int-height-color-color","title":"void drawFilledRectangle(int x, int y, int width, int height, Color color)","text":"

Draws a filled rectangle.

Parameters: - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - width (int): Width of the rectangle in pixels - height (int): Height of the rectangle in pixels - color (Color): Fill color

Example:

renderer.drawFilledRectangle(10, 10, 100, 50, Color::Green);\n

"},{"location":"api_reference/graphics/renderer/#void-drawlineint-x1-int-y1-int-x2-int-y2-color-color","title":"void drawLine(int x1, int y1, int x2, int y2, Color color)","text":"

Draws a line between two points.

Parameters: - x1 (int): Start X coordinate - y1 (int): Start Y coordinate - x2 (int): End X coordinate - y2 (int): End Y coordinate - color (Color): Line color

Example:

renderer.drawLine(0, 0, 128, 128, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-drawpixelint-x-int-y-color-color","title":"void drawPixel(int x, int y, Color color)","text":"

Draws a single pixel.

Parameters: - x (int): X coordinate - y (int): Y coordinate - color (Color): Pixel color

Performance Notes: - Very fast, but avoid calling thousands of times per frame - Use for special effects or debugging

Example:

renderer.drawPixel(64, 64, Color::Red);\n

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite-sprite-int-x-int-y-color-color-bool-flipx-false","title":"void drawSprite(const Sprite& sprite, int x, int y, Color color, bool flipX = false)","text":"

Draws a 1bpp monochrome sprite using the Sprite descriptor.

Parameters: - sprite (const Sprite&): Sprite descriptor (data, width, height) - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space - color (Color): Color used for \"on\" pixels - flipX (bool, optional): If true, sprite is mirrored horizontally. Default: false

Performance Notes: - Very efficient for 1bpp sprites (integer-only operations) - Sprite data should be stored in flash (const/constexpr) for best performance

Example:

renderer.drawSprite(playerSprite, 100, 100, Color::White);\nrenderer.drawSprite(playerSprite, 120, 100, Color::White, true);  // Flipped\n

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite-sprite-int-x-int-y-float-scalex-float-scaley-color-color-bool-flipx-false","title":"void drawSprite(const Sprite& sprite, int x, int y, float scaleX, float scaleY, Color color, bool flipX = false)","text":"

Draws a scaled 1bpp monochrome sprite using nearest-neighbor scaling.

Parameters: - sprite (const Sprite&): Sprite descriptor - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - scaleX (float): Horizontal scaling factor (e.g., 2.0 for double width) - scaleY (float): Vertical scaling factor - color (Color): Color used for \"on\" pixels - flipX (bool, optional): If true, sprite is mirrored horizontally before scaling. Default: false

Performance Notes: - Slower than non-scaled version due to scaling calculations - The destination size is calculated as ceil(width * scaleX) x ceil(height * scaleY)

Example:

renderer.drawSprite(playerSprite, 100, 100, 2.0f, 2.0f, Color::White);  // 2x size\n

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite2bpp-sprite-int-x-int-y-bool-flipx-false","title":"void drawSprite(const Sprite2bpp& sprite, int x, int y, bool flipX = false)","text":"

Draws a 2bpp sprite. Available when PIXELROOT32_ENABLE_2BPP_SPRITES is defined.

Parameters: - sprite (const Sprite2bpp&): 2bpp sprite descriptor - x (int): X coordinate - y (int): Y coordinate - flipX (bool, optional): Horizontal flip. Default: false

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite4bpp-sprite-int-x-int-y-bool-flipx-false","title":"void drawSprite(const Sprite4bpp& sprite, int x, int y, bool flipX = false)","text":"

Draws a 4bpp sprite. Available when PIXELROOT32_ENABLE_4BPP_SPRITES is defined.

Parameters: - sprite (const Sprite4bpp&): 4bpp sprite descriptor - x (int): X coordinate - y (int): Y coordinate - flipX (bool, optional): Horizontal flip. Default: false

"},{"location":"api_reference/graphics/renderer/#void-drawmultispriteconst-multisprite-sprite-int-x-int-y","title":"void drawMultiSprite(const MultiSprite& sprite, int x, int y)","text":"

Draws a multi-layer sprite composed of several 1bpp layers.

Parameters: - sprite (const MultiSprite&): Multi-layer sprite descriptor - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space

Performance Notes: - Each layer is rendered separately, so more layers = more draw calls - Still efficient as each layer uses 1bpp format - Use for multi-color sprites without higher bit-depths

Example:

static const SpriteLayer layers[] = {\n    { outlineData, Color::Black },\n    { fillData, Color::Red },\n    { highlightData, Color::Yellow }\n};\n\nstatic const MultiSprite playerMultiSprite = {\n    8,      // width\n    8,      // height\n    layers, // layers array\n    3       // layer count\n};\n\nrenderer.drawMultiSprite(playerMultiSprite, 100, 100);\n

"},{"location":"api_reference/graphics/renderer/#void-drawmultispriteconst-multisprite-sprite-int-x-int-y-float-scalex-float-scaley","title":"void drawMultiSprite(const MultiSprite& sprite, int x, int y, float scaleX, float scaleY)","text":"

Draws a scaled multi-layer sprite.

Parameters: - sprite (const MultiSprite&): Multi-layer sprite descriptor - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - scaleX (float): Horizontal scaling factor - scaleY (float): Vertical scaling factor

"},{"location":"api_reference/graphics/renderer/#void-drawtilemapconst-tilemap-map-int-originx-int-originy-color-color","title":"void drawTileMap(const TileMap& map, int originX, int originY, Color color)","text":"

Draws a 1bpp tilemap.

Parameters: - map (const TileMap&): Tilemap descriptor (indices, 1bpp tiles, dimensions) - originX (int): X coordinate of the top-left corner - originY (int): Y coordinate of the top-left corner - color (Color): Color used for all tiles in the map

"},{"location":"api_reference/graphics/renderer/#void-drawtilemapconst-tilemap2bpp-map-int-originx-int-originy","title":"void drawTileMap(const TileMap2bpp& map, int originX, int originY)","text":"

Draws a 2bpp tilemap. Available when PIXELROOT32_ENABLE_2BPP_SPRITES is defined.

Parameters: - map (const TileMap2bpp&): Tilemap descriptor (indices, 2bpp tiles, dimensions) - originX (int): X coordinate - originY (int): Y coordinate

"},{"location":"api_reference/graphics/renderer/#void-drawtilemapconst-tilemap4bpp-map-int-originx-int-originy","title":"void drawTileMap(const TileMap4bpp& map, int originX, int originY)","text":"

Draws a 4bpp tilemap. Available when PIXELROOT32_ENABLE_4BPP_SPRITES is defined.

Parameters: - map (const TileMap4bpp&): Tilemap descriptor (indices, 4bpp tiles, dimensions) - originX (int): X coordinate - originY (int): Y coordinate

Performance Notes: - Very efficient for rendering large backgrounds - Only visible tiles are drawn (viewport culling) - Use tilemaps instead of individual sprites for backgrounds

Example:

static const uint8_t levelIndices[] = {\n    0, 1, 2, 3,\n    4, 5, 6, 7,\n    // ... more rows\n};\n\nstatic const TileMap levelMap = {\n    levelIndices,\n    16,        // width in tiles\n    16,        // height in tiles\n    tileSprites, // tile sprite array\n    8,         // tile width\n    8,         // tile height\n    16         // tile count\n};\n\nrenderer.drawTileMap(levelMap, 0, 0, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#int-getlogicalwidth-const","title":"int getLogicalWidth() const","text":"

Gets the logical rendering width.

Returns: - int: The width of the logical screen space.

"},{"location":"api_reference/graphics/renderer/#int-getlogicalheight-const","title":"int getLogicalHeight() const","text":"

Gets the logical rendering height.

Returns: - int: The height of the logical screen space.

Note: These methods replace the deprecated getWidth() and getHeight().

"},{"location":"api_reference/graphics/renderer/#void-setdisplayoffsetint-x-int-y","title":"void setDisplayOffset(int x, int y)","text":"

Sets a global offset for all drawing operations. Useful for camera/parallax effects.

Parameters: - x (int): X offset in pixels - y (int): Y offset in pixels

Notes: - All subsequent drawing operations are offset by this amount - Useful for camera scrolling and parallax effects - Reset to (0, 0) to disable offset

Example:

// Camera scrolling\ncamera.setPosition(playerX - 64, playerY - 64);\nrenderer.setDisplayOffset(-camera.getX(), -camera.getY());\nrenderer.drawTileMap(background, 0, 0, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-setdisplaysizeint-w-int-h","title":"void setDisplaySize(int w, int h)","text":"

Sets the logical display size.

Parameters: - w (int): Width in pixels - h (int): Height in pixels

Notes: - Typically set via DisplayConfig during construction - Use this to change display size at runtime if needed

"},{"location":"api_reference/graphics/renderer/#int-getwidth-const","title":"int getWidth() const","text":"

Gets the display width.

Returns: - int: Display width in pixels

"},{"location":"api_reference/graphics/renderer/#int-getheight-const","title":"int getHeight() const","text":"

Gets the display height.

Returns: - int: Display height in pixels

"},{"location":"api_reference/graphics/renderer/#int-getxoffset-const","title":"int getXOffset() const","text":"

Gets the current X display offset.

Returns: - int: X offset in pixels

"},{"location":"api_reference/graphics/renderer/#int-getyoffset-const","title":"int getYOffset() const","text":"

Gets the current Y display offset.

Returns: - int: Y offset in pixels

"},{"location":"api_reference/graphics/renderer/#void-setcontrastuint8_t-level","title":"void setContrast(uint8_t level)","text":"

Sets the display contrast (brightness).

Parameters: - level (uint8_t): Contrast level (0-255)

Notes: - Platform-specific: may not be supported on all displays - Higher values = brighter display

"},{"location":"api_reference/graphics/renderer/#void-setfontconst-uint8_t-font","title":"void setFont(const uint8_t* font)","text":"

Sets the font for text rendering.

Parameters: - font (const uint8_t*): Pointer to the font data

Notes: - Sets the default font for drawText() calls without font parameter - Use font constants like FONT_5X7 from Font.h

"},{"location":"api_reference/graphics/renderer/#usage-example","title":"Usage Example","text":"
#include \"graphics/Renderer.h\"\n#include \"graphics/DisplayConfig.h\"\n\nvoid draw(Renderer& renderer) override {\n    renderer.beginFrame();\n\n    // Draw background\n    renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n\n    // Draw sprites\n    renderer.drawSprite(playerSprite, playerX, playerY, Color::White);\n    renderer.drawSprite(enemySprite, enemyX, enemyY, Color::Red);\n\n    // Draw UI\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n    renderer.drawTextCentered(\"Game Over\", 64, Color::Yellow, 2);\n\n    renderer.endFrame();\n}\n
"},{"location":"api_reference/graphics/renderer/#performance-considerations","title":"Performance Considerations","text":"
  • Integer-only math: All operations use integer arithmetic for ESP32 efficiency
  • Sprite storage: Store sprite data in flash (const/constexpr) for best performance
  • Batch operations: Group similar draw calls together
  • Tilemaps: Dibuja un mapa de tiles completo. Implementa viewport culling autom\u00e1tico y cach\u00e9 de paleta para m\u00e1ximo rendimiento.
  • Sprites 2bpp/4bpp: Optimizado para ESP32 (IRAM + acceso de 16 bits).
"},{"location":"api_reference/graphics/renderer/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Sprite data should be in flash, not RAM
  • Frame rate: Limit draw calls per frame for consistent FPS
  • Display offset: Use for scrolling instead of redrawing everything
"},{"location":"api_reference/graphics/renderer/#see-also","title":"See Also","text":"
  • Sprite - Sprite structure
  • MultiSprite - Multi-layer sprites
  • TileMap - Tilemap structure
  • Color - Color constants
  • DisplayConfig - Display configuration
  • Camera2D - Camera for scrolling
  • Manual - Basic Rendering
  • Manual - Sprites and Animation
  • API Overview
"},{"location":"api_reference/graphics/sprite/","title":"Sprite","text":"

Low-level bitmap descriptor and multi-layer composition for retro rendering.

"},{"location":"api_reference/graphics/sprite/#description","title":"Description","text":"

Sprites are the fundamental graphics primitive in PixelRoot32. The engine supports multiple sprite formats:

  • 1bpp (Standard): Monochrome sprites, most memory-efficient
  • 2bpp (Experimental): 4 colors per sprite
  • 4bpp (Experimental): 16 colors per sprite
  • MultiSprite: Multi-layer 1bpp sprites for multi-color effects
"},{"location":"api_reference/graphics/sprite/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    struct Sprite {\n        // ...\n    };\n\n    struct MultiSprite {\n        // ...\n    };\n\n    struct SpriteLayer {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/sprite/#sprite-structure-1bpp","title":"Sprite Structure (1bpp)","text":"

Compact sprite descriptor for monochrome bitmapped sprites.

"},{"location":"api_reference/graphics/sprite/#members","title":"Members","text":"
  • const uint16_t* data: Pointer to packed row data (size = height)
  • uint8_t width: Sprite width in pixels (\u2264 16)
  • uint8_t height: Sprite height in pixels
"},{"location":"api_reference/graphics/sprite/#data-format","title":"Data Format","text":"

Sprites are stored as an array of 16-bit rows. Each row packs horizontal pixels into bits:

  • Bit 0: Leftmost pixel of the row
  • Bit (width - 1): Rightmost pixel of the row
  • Bit value 1: Pixel on (colored)
  • Bit value 0: Pixel off (transparent/background)

Only the lowest width bits of each row are used.

"},{"location":"api_reference/graphics/sprite/#example","title":"Example","text":"
// 8x8 sprite (smiley face)\nstatic const uint16_t SMILEY_DATA[] = {\n    0b00111100,  // Row 0:  \u2588\u2588\u2588\u2588\n    0b01111110,  // Row 1:  \u2588\u2588\u2588\u2588\u2588\u2588\n    0b11011011,  // Row 2:  \u2588\u2588 \u2588\u2588 \u2588\u2588\n    0b11111111,  // Row 3:  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\n    0b11011011,  // Row 4:  \u2588\u2588 \u2588\u2588 \u2588\u2588\n    0b01100110,  // Row 5:  \u2588\u2588  \u2588\u2588\n    0b01111110,  // Row 6:  \u2588\u2588\u2588\u2588\u2588\u2588\n    0b00111100   // Row 7:  \u2588\u2588\u2588\u2588\n};\n\nstatic const Sprite SMILEY_SPRITE = {\n    SMILEY_DATA,\n    8,  // width\n    8   // height\n};\n
"},{"location":"api_reference/graphics/sprite/#spritelayer-structure","title":"SpriteLayer Structure","text":"

Single monochrome layer used by layered sprites.

"},{"location":"api_reference/graphics/sprite/#members_1","title":"Members","text":"
  • const uint16_t* data: Pointer to packed row data for this layer
  • Color color: Color used for \"on\" pixels in this layer
"},{"location":"api_reference/graphics/sprite/#notes","title":"Notes","text":"
  • Each layer uses the same width/height as its owning MultiSprite
  • Layers can have different colors
  • Layers are drawn in array order
"},{"location":"api_reference/graphics/sprite/#multisprite-structure","title":"MultiSprite Structure","text":"

Multi-layer, multi-color sprite built from 1bpp layers.

"},{"location":"api_reference/graphics/sprite/#members_2","title":"Members","text":"
  • uint8_t width: Sprite width in pixels (\u2264 16)
  • uint8_t height: Sprite height in pixels
  • const SpriteLayer* layers: Pointer to array of layers
  • uint8_t layerCount: Number of layers in the array
"},{"location":"api_reference/graphics/sprite/#notes_1","title":"Notes","text":"
  • Combines several 1bpp layers with different colors
  • Layers are drawn in array order
  • Enables multi-color sprites without higher bit-depths
  • More layers = more draw calls (but still efficient)
"},{"location":"api_reference/graphics/sprite/#example_1","title":"Example","text":"
// Outline layer\nstatic const uint16_t OUTLINE_DATA[] = {\n    0b11111111,\n    0b10000001,\n    0b10000001,\n    0b11111111\n};\n\n// Fill layer\nstatic const uint16_t FILL_DATA[] = {\n    0b00000000,\n    0b01111110,\n    0b01111110,\n    0b00000000\n};\n\nstatic const SpriteLayer LAYERS[] = {\n    {OUTLINE_DATA, Color::Black},  // Layer 0: Black outline\n    {FILL_DATA, Color::Red}       // Layer 1: Red fill\n};\n\nstatic const MultiSprite PLAYER_MULTISPRITE = {\n    8,      // width\n    8,      // height\n    LAYERS, // layers array\n    2       // layer count\n};\n
"},{"location":"api_reference/graphics/sprite/#sprite2bpp-structure-experimental","title":"Sprite2bpp Structure (Experimental)","text":"

2-bit per pixel sprite (4 colors).

Requires: PIXELROOT32_ENABLE_2BPP_SPRITES build flag

"},{"location":"api_reference/graphics/sprite/#members_3","title":"Members","text":"
  • const uint16_t* data: Datos empaquetados (4 p\u00edxeles por cada 8 bits, alineados a 16 bits)
  • const Color* palette: Local palette (4 colors)
  • uint8_t width: Sprite width
  • uint8_t height: Sprite height
  • uint8_t paletteSize: Number of colors (typically 4)
"},{"location":"api_reference/graphics/sprite/#notes_2","title":"Notes","text":"
  • Experimental feature
  • Uses more memory than 1bpp
  • Each pixel can be one of 4 colors from local palette
"},{"location":"api_reference/graphics/sprite/#sprite4bpp-structure-experimental","title":"Sprite4bpp Structure (Experimental)","text":"

4-bit per pixel sprite (16 colors).

Requires: PIXELROOT32_ENABLE_4BPP_SPRITES build flag

"},{"location":"api_reference/graphics/sprite/#members_4","title":"Members","text":"
  • const uint16_t* data: Datos empaquetados (2 p\u00edxeles por cada 8 bits, alineados a 16 bits)
  • const Color* palette: Local palette (16 colors)
  • uint8_t width: Sprite width
  • uint8_t height: Sprite height
  • uint8_t paletteSize: Number of colors (typically 16)
"},{"location":"api_reference/graphics/sprite/#notes_3","title":"Notes","text":"
  • Experimental feature
  • Uses more memory than 1bpp/2bpp
  • Each pixel can be one of 16 colors from local palette
"},{"location":"api_reference/graphics/sprite/#sprite-animation","title":"Sprite Animation","text":""},{"location":"api_reference/graphics/sprite/#spriteanimationframe-structure","title":"SpriteAnimationFrame Structure","text":"

Frame that can reference either a Sprite or a MultiSprite.

Members: - const Sprite* sprite: Optional pointer to a simple 1bpp sprite frame - const MultiSprite* multiSprite: Optional pointer to a layered sprite frame

Notes: - Exactly one pointer should be non-null for a valid frame - Allows same animation system for both sprite types

"},{"location":"api_reference/graphics/sprite/#spriteanimation-structure","title":"SpriteAnimation Structure","text":"

Lightweight, step-based sprite animation controller.

Members: - const SpriteAnimationFrame* frames: Pointer to immutable frame table - uint8_t frameCount: Number of frames in the table - uint8_t current: Current frame index [0, frameCount)

Methods: - void reset(): Reset to first frame - void step(): Advance to next frame (wrapping) - const SpriteAnimationFrame& getCurrentFrame() const: Get current frame - const Sprite* getCurrentSprite() const: Get current simple sprite - const MultiSprite* getCurrentMultiSprite() const: Get current multi-sprite

Example:

static const SpriteAnimationFrame WALK_FRAMES[] = {\n    {&walkFrame1, nullptr},\n    {&walkFrame2, nullptr},\n    {&walkFrame3, nullptr},\n    {&walkFrame2, nullptr}  // Loop back\n};\n\nstatic SpriteAnimation walkAnimation = {\n    WALK_FRAMES,\n    4,    // frameCount\n    0     // current\n};\n\n// In update\nwalkAnimation.step();\nconst Sprite* currentSprite = walkAnimation.getCurrentSprite();\n

"},{"location":"api_reference/graphics/sprite/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/graphics/sprite/#creating-1bpp-sprites","title":"Creating 1bpp Sprites","text":"
// 8x8 player sprite\nstatic const uint16_t PLAYER_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11011011,\n    0b11111111,\n    0b01111110,\n    0b00111100,\n    0b00011000\n};\n\nstatic const Sprite PLAYER_SPRITE = {\n    PLAYER_DATA,\n    8,  // width\n    8   // height\n};\n\n// Use in rendering\nrenderer.drawSprite(PLAYER_SPRITE, 100, 100, Color::White);\n
"},{"location":"api_reference/graphics/sprite/#creating-multisprite","title":"Creating MultiSprite","text":"
// Outline layer\nstatic const uint16_t OUTLINE[] = {\n    0b11111111,\n    0b10000001,\n    0b10000001,\n    0b11111111\n};\n\n// Fill layer\nstatic const uint16_t FILL[] = {\n    0b00000000,\n    0b01111110,\n    0b01111110,\n    0b00000000\n};\n\nstatic const SpriteLayer LAYERS[] = {\n    {OUTLINE, Color::Black},\n    {FILL, Color::Red}\n};\n\nstatic const MultiSprite ENEMY_SPRITE = {\n    8,      // width\n    8,      // height\n    LAYERS, // layers\n    2       // layer count\n};\n\n// Use in rendering\nrenderer.drawMultiSprite(ENEMY_SPRITE, 100, 100);\n
"},{"location":"api_reference/graphics/sprite/#sprite-animation_1","title":"Sprite Animation","text":"
class AnimatedActor : public pixelroot32::core::Actor {\nprivate:\n    SpriteAnimation animation;\n    unsigned long animTimer = 0;\n    unsigned long animInterval = 200;  // 200ms per frame\n\npublic:\n    void update(unsigned long deltaTime) override {\n        Actor::update(deltaTime);\n\n        animTimer += deltaTime;\n        if (animTimer >= animInterval) {\n            animTimer -= animInterval;\n            animation.step();\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        const Sprite* frame = animation.getCurrentSprite();\n        if (frame) {\n            renderer.drawSprite(*frame, \n                               static_cast<int>(x), \n                               static_cast<int>(y), \n                               Color::White);\n        }\n    }\n};\n
"},{"location":"api_reference/graphics/sprite/#sprite-flipping","title":"Sprite Flipping","text":"

Sprites can be flipped horizontally:

// Draw normal\nrenderer.drawSprite(sprite, 100, 100, Color::White, false);\n\n// Draw flipped\nrenderer.drawSprite(sprite, 100, 100, Color::White, true);\n
"},{"location":"api_reference/graphics/sprite/#performance-considerations","title":"Performance Considerations","text":"
  • 1bpp sprites: Most efficient (integer-only operations)
  • MultiSprite: Each layer is a separate draw call (still efficient)
  • 2bpp/4bpp: Experimental, uses more memory and CPU
  • Storage: Store sprite data in flash (const/constexpr) for best performance
  • Size limit: Sprites are limited to 16 pixels wide for 1bpp format
"},{"location":"api_reference/graphics/sprite/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store sprite data in flash, not RAM
  • Sprite size: Smaller sprites = faster drawing
  • Format choice: Use 1bpp when possible for best performance
  • MultiSprite: More layers = more draw calls (but acceptable)
"},{"location":"api_reference/graphics/sprite/#see-also","title":"See Also","text":"
  • Renderer - Rendering system that draws sprites
  • Color - Color constants for sprites
  • Manual - Sprites and Animation
  • API Overview
"},{"location":"api_reference/graphics/tilemap/","title":"TileMap","text":"

Generic structure for tile-based background rendering.

"},{"location":"api_reference/graphics/tilemap/#description","title":"Description","text":"

TileMapGeneric<T> is a template structure for rendering tile-based backgrounds efficiently. It supports multiple bit-depths (1bpp, 2bpp, 4bpp) by using the appropriate sprite type for tiles.

Tilemaps are ideal for large backgrounds, levels, and static environments. They support viewport culling (only visible tiles are drawn) for optimal performance.

"},{"location":"api_reference/graphics/tilemap/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    template<typename T>\n    struct TileMapGeneric {\n        // ...\n    };\n\n    using TileMap = TileMapGeneric<Sprite>;\n    using TileMap2bpp = TileMapGeneric<Sprite2bpp>;\n    using TileMap4bpp = TileMapGeneric<Sprite4bpp>;\n}\n
"},{"location":"api_reference/graphics/tilemap/#template-parameters","title":"Template Parameters","text":""},{"location":"api_reference/graphics/tilemap/#t","title":"T","text":"

The sprite type used for tiles.

Supported types: - Sprite (1bpp) - Sprite2bpp (2bpp) - Sprite4bpp (4bpp)

"},{"location":"api_reference/graphics/tilemap/#structure","title":"Structure","text":""},{"location":"api_reference/graphics/tilemap/#uint8_t-indices","title":"uint8_t* indices","text":"

Array of tile indices mapping to tile sprites.

Type: uint8_t*

Access: Read-write

Notes: - Array size = width * height - Each value is an index into the tiles array - 0 = first tile, 1 = second tile, etc. - Should be stored in flash (const) for best performance

Example:

// 16x16 tilemap (256 tiles)\nstatic const uint8_t LEVEL_INDICES[] = {\n    0, 0, 0, 0, 1, 1, 1, 1, // Row 0\n    0, 2, 2, 2, 2, 2, 2, 0, // Row 1\n    // ... more rows\n};\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-width","title":"uint8_t width","text":"

Width of the tilemap in tiles.

Type: uint8_t

Access: Read-write

Example:

width = 16;  // 16 tiles wide\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-height","title":"uint8_t height","text":"

Height of the tilemap in tiles.

Type: uint8_t

Access: Read-write

Example:

height = 16;  // 16 tiles tall\n

"},{"location":"api_reference/graphics/tilemap/#const-t-tiles","title":"const T* tiles","text":"

Array of tile sprites of type T.

Type: const T*

Access: Read-only

Notes: - Array of sprite pointers, one per unique tile - Indices reference this array - All tiles should be the same size - Should be stored in flash (const) for best performance

Example (1bpp):

static const Sprite TILE_SPRITES[] = {\n    EMPTY_TILE,   // Index 0\n    WALL_TILE,    // Index 1\n    FLOOR_TILE,   // Index 2\n    // ... more tiles\n};\n

Example (2bpp):

static const Sprite2bpp TILE_SPRITES_2BPP[] = {\n    TILE_GRASS,   // Index 0\n    TILE_DIRT,    // Index 1\n    // ... more tiles\n};\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-tilewidth","title":"uint8_t tileWidth","text":"

Width of each tile in pixels.

Type: uint8_t

Access: Read-write

Notes: - All tiles must have the same width - Common values: 8, 16 pixels - Should match sprite width

Example:

tileWidth = 8;  // 8x8 tiles\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-tileheight","title":"uint8_t tileHeight","text":"

Height of each tile in pixels.

Type: uint8_t

Access: Read-write

Notes: - All tiles must have the same height - Common values: 8, 16 pixels - Should match sprite height

Example:

tileHeight = 8;  // 8x8 tiles\n

"},{"location":"api_reference/graphics/tilemap/#uint16_t-tilecount","title":"uint16_t tileCount","text":"

Number of unique tiles in the tiles array.

Type: uint16_t

Access: Read-write

Notes: - Must match the size of the tiles array - Indices must be < tileCount

Example:

tileCount = 16;  // 16 unique tiles\n

"},{"location":"api_reference/graphics/tilemap/#creating-tilemaps","title":"Creating Tilemaps","text":""},{"location":"api_reference/graphics/tilemap/#step-1-create-tile-sprites","title":"Step 1: Create Tile Sprites","text":"
// Empty tile (index 0)\nstatic const uint16_t EMPTY_DATA[] = {\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000\n};\n\n// Wall tile (index 1)\nstatic const uint16_t WALL_DATA[] = {\n    0b11111111,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b11111111\n};\n\n// Floor tile (index 2)\nstatic const uint16_t FLOOR_DATA[] = {\n    0b00000000,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b00000000\n};\n\nstatic const Sprite TILE_SPRITES[] = {\n    {EMPTY_DATA, 8, 8},  // Index 0\n    {WALL_DATA, 8, 8},   // Index 1\n    {FLOOR_DATA, 8, 8}   // Index 2\n};\n
"},{"location":"api_reference/graphics/tilemap/#step-2-create-index-array","title":"Step 2: Create Index Array","text":"
// 16x16 level (256 tiles)\n// 0 = empty, 1 = wall, 2 = floor\nstatic const uint8_t LEVEL_INDICES[] = {\n    // Row 0: Top wall\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n    // Row 1: Walls on sides\n    1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,\n    // Row 2\n    1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,\n    // ... more rows\n    // Row 15: Bottom wall\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n};\n
"},{"location":"api_reference/graphics/tilemap/#step-3-create-tilemap-structure","title":"Step 3: Create TileMap Structure","text":"
static const TileMap LEVEL_MAP = {\n    const_cast<uint8_t*>(LEVEL_INDICES),  // indices (non-const for struct)\n    16,        // width in tiles\n    16,        // height in tiles\n    TILE_SPRITES, // tile sprites array\n    8,         // tile width\n    8,         // tile height\n    3          // tile count\n};\n
"},{"location":"api_reference/graphics/tilemap/#rendering-tilemaps","title":"Rendering Tilemaps","text":"

Use Renderer::drawTileMap():

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Draw tilemap at origin (0, 0)\n    renderer.drawTileMap(LEVEL_MAP, 0, 0, Color::White);\n\n    // With camera offset\n    camera.apply(renderer);\n    renderer.drawTileMap(LEVEL_MAP, 0, 0, Color::White);\n}\n
"},{"location":"api_reference/graphics/tilemap/#viewport-culling","title":"Viewport Culling","text":"

Tilemaps automatically cull tiles outside the viewport:

  • Only visible tiles are drawn
  • Very efficient for large levels
  • Works with camera scrolling

Example:

// Large level (256x256 tiles)\n// Only tiles visible on screen are drawn\ncamera.apply(renderer);\nrenderer.drawTileMap(LARGE_LEVEL_MAP, 0, 0, Color::White);\n

"},{"location":"api_reference/graphics/tilemap/#collision-detection-with-tilemaps","title":"Collision Detection with Tilemaps","text":"

Check tile at world position:

bool isSolidTile(int worldX, int worldY, const TileMap& map) {\n    int tileX = worldX / map.tileWidth;\n    int tileY = worldY / map.tileHeight;\n\n    if (tileX < 0 || tileX >= map.width || \n        tileY < 0 || tileY >= map.height) {\n        return true;  // Outside map = solid\n    }\n\n    int index = tileY * map.width + tileX;\n    uint8_t tileIndex = map.indices[index];\n\n    // Check if tile is solid (e.g., wall = index 1)\n    return (tileIndex == 1);\n}\n
"},{"location":"api_reference/graphics/tilemap/#usage-example","title":"Usage Example","text":"
#include \"graphics/TileMap.h\"\n#include \"graphics/Renderer.h\"\n\nclass LevelScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::TileMap levelMap;\n    pixelroot32::graphics::Camera2D camera;\n\npublic:\n    void init() override {\n        // Level map is already defined (see above)\n        // Create camera\n        auto& renderer = engine.getRenderer();\n        camera = pixelroot32::graphics::Camera2D(\n            renderer.getWidth(),\n            renderer.getHeight()\n        );\n\n        // Set level boundaries\n        int levelWidth = levelMap.width * levelMap.tileWidth;\n        int levelHeight = levelMap.height * levelMap.tileHeight;\n        camera.setBounds(0.0f, levelWidth - renderer.getWidth());\n        camera.setVerticalBounds(0.0f, levelHeight - renderer.getHeight());\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Camera follows player\n        if (player) {\n            camera.followTarget(player->x, player->y);\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw tilemap (viewport culling automatic)\n        renderer.drawTileMap(levelMap, 0, 0, Color::White);\n\n        // Draw entities\n        Scene::draw(renderer);\n\n        // Reset for UI\n        renderer.setDisplayOffset(0, 0);\n    }\n\n    bool checkTileCollision(float x, float y) {\n        int tileX = static_cast<int>(x) / levelMap.tileWidth;\n        int tileY = static_cast<int>(y) / levelMap.tileHeight;\n\n        if (tileX < 0 || tileX >= levelMap.width || \n            tileY < 0 || tileY >= levelMap.height) {\n            return true;  // Outside = solid\n        }\n\n        int index = tileY * levelMap.width + tileX;\n        uint8_t tile = levelMap.indices[index];\n        return (tile == 1);  // Wall tile\n    }\n};\n
"},{"location":"api_reference/graphics/tilemap/#performance-considerations","title":"Performance Considerations","text":"
  • Viewport culling: Only visible tiles are drawn (automatic)
  • Tile reuse: Reuse tile sprites across the map
  • Index storage: Compact uint8_t indices (1 byte per tile)
  • Memory: Store indices and tiles in flash (const) for best performance
  • Tile size: Smaller tiles = more tiles to draw, but more detail
"},{"location":"api_reference/graphics/tilemap/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store tilemap data in flash, not RAM
  • Map size: Large maps use more flash memory
  • Tile count: Limit unique tiles to save memory
  • Culling: Viewport culling is essential for large levels
"},{"location":"api_reference/graphics/tilemap/#see-also","title":"See Also","text":"
  • Renderer - Rendering system that draws tilemaps
  • Sprite - Sprite structure used for tiles
  • Camera2D - Camera for scrolling tilemaps
  • Manual - Tilemaps
  • API Overview
"},{"location":"api_reference/physics/collision_system/","title":"CollisionSystem","text":"

Manages collision detection between entities.

"},{"location":"api_reference/physics/collision_system/#description","title":"Description","text":"

CollisionSystem iterates through registered entities, checks if they are Actors, and performs AABB (Axis-Aligned Bounding Box) collision checks based on their collision layers and masks.

The system automatically filters collisions using layers and masks, avoiding unnecessary checks. When a collision is detected, it triggers the onCollision() callback on both actors.

"},{"location":"api_reference/physics/collision_system/#namespace","title":"Namespace","text":"
namespace pixelroot32::physics {\n    class CollisionSystem {\n        // ...\n    };\n}\n
"},{"location":"api_reference/physics/collision_system/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Scene (manages collision system instance)
"},{"location":"api_reference/physics/collision_system/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/physics/collision_system/#void-addentityentity-e","title":"void addEntity(Entity* e)","text":"

Adds an entity to the collision system.

Parameters: - e (pixelroot32::core::Entity*): Pointer to the entity to add

Returns: - void

Notes: - Only Actor entities participate in collisions - Entities are automatically added when added to Scene - Typically not called directly (handled by Scene)

Example:

// Typically handled automatically by Scene\nscene->addEntity(actor);  // Automatically added to collision system\n

"},{"location":"api_reference/physics/collision_system/#void-removeentityentity-e","title":"void removeEntity(Entity* e)","text":"

Removes an entity from the collision system.

Parameters: - e (pixelroot32::core::Entity*): Pointer to the entity to remove

Returns: - void

Notes: - Entities are automatically removed when removed from Scene - Typically not called directly

Example:

// Typically handled automatically by Scene\nscene->removeEntity(actor);  // Automatically removed from collision system\n

"},{"location":"api_reference/physics/collision_system/#void-update","title":"void update()","text":"

Performs collision detection for all registered entities.

Returns: - void

Notes: - Called automatically by Scene::update() - Iterates through all pairs of entities - Only checks collisions between Actors with matching layers/masks - Triggers onCollision() callbacks when collisions are detected - Uses AABB (Axis-Aligned Bounding Box) collision detection

Example:

// Called automatically by Scene, but can be called manually:\nvoid update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);  // Calls collisionSystem.update()\n\n    // Or manually:\n    collisionSystem.update();\n}\n

"},{"location":"api_reference/physics/collision_system/#how-it-works","title":"How It Works","text":"
  1. Entity Registration: Entities added to Scene are automatically registered
  2. Layer Filtering: Only actors with matching layers/masks are checked
  3. AABB Check: Uses Rect::intersects() for collision detection
  4. Callback: Calls onCollision() on both actors when collision detected
"},{"location":"api_reference/physics/collision_system/#collision-detection-algorithm","title":"Collision Detection Algorithm","text":"
for each actor1 in entities:\n    if actor1 is not an Actor: continue\n    for each actor2 in entities:\n        if actor2 is not an Actor: continue\n        if actor1 == actor2: continue\n\n        // Check layers/masks\n        if (actor1->layer & actor2->mask) == 0: continue\n        if (actor2->layer & actor1->mask) == 0: continue\n\n        // Check AABB intersection\n        Rect box1 = actor1->getHitBox();\n        Rect box2 = actor2->getHitBox();\n\n        if (box1.intersects(box2)) {\n            actor1->onCollision(actor2);\n            actor2->onCollision(actor1);\n        }\n
"},{"location":"api_reference/physics/collision_system/#usage-example","title":"Usage Example","text":"
#include \"physics/CollisionSystem.h\"\n#include \"core/Actor.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Create actors with collision layers\n        PlayerActor* player = new PlayerActor(64, 64);\n        player->layer = pixelroot32::physics::DefaultLayers::kPlayer;\n        player->mask = pixelroot32::physics::DefaultLayers::kEnemy | \n                       pixelroot32::physics::DefaultLayers::kObstacle;\n        addEntity(player);\n\n        EnemyActor* enemy = new EnemyActor(100, 100);\n        enemy->layer = pixelroot32::physics::DefaultLayers::kEnemy;\n        enemy->mask = pixelroot32::physics::DefaultLayers::kPlayer;\n        addEntity(enemy);\n\n        // Collision system is managed by Scene\n        // Collisions are checked automatically in Scene::update()\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Collision detection happens here automatically\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"api_reference/physics/collision_system/#performance-considerations","title":"Performance Considerations","text":"
  • Layer filtering: Very efficient; avoids most collision checks
  • AABB checks: Fast (simple rectangle intersection)
  • Pair checking: O(n\u00b2) complexity, but n is limited (MAX_ENTITIES = 32)
  • Update frequency: Called every frame; keep hitboxes simple
"},{"location":"api_reference/physics/collision_system/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Entity limit: MAX_ENTITIES = 32 limits collision pairs
  • Layer efficiency: Use layers effectively to minimize checks
  • Hitbox simplicity: Keep hitboxes as simple AABB for best performance
"},{"location":"api_reference/physics/collision_system/#see-also","title":"See Also","text":"
  • Actor - Actors that participate in collisions
  • CollisionTypes - Collision primitives and layers
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/physics/collision_types/","title":"Collision Types","text":"

Basic geometric types and collision layer definitions.

"},{"location":"api_reference/physics/collision_types/#description","title":"Description","text":"

This document describes the collision primitives (Rect, Circle, Segment) and collision layer system used by the collision detection system.

"},{"location":"api_reference/physics/collision_types/#namespace","title":"Namespace","text":"
namespace pixelroot32::physics {\n    // Types and functions\n}\n
"},{"location":"api_reference/physics/collision_types/#collisionlayer-type","title":"CollisionLayer Type","text":"

Collision layer type (bit flags).

Type: uint16_t (typedef)

Notes: - Uses bit flags for layer assignment - Actors can be on multiple layers (bitwise OR) - Masks define which layers an actor can collide with

"},{"location":"api_reference/physics/collision_types/#defaultlayers-namespace","title":"DefaultLayers Namespace","text":"

Predefined collision layers.

"},{"location":"api_reference/physics/collision_types/#knone","title":"kNone","text":"

No layer (0).

Value: 0

Usage:

actor->layer = pixelroot32::physics::DefaultLayers::kNone;\n

"},{"location":"api_reference/physics/collision_types/#kall","title":"kAll","text":"

All layers (0xFFFF).

Value: 0xFFFF

Usage:

actor->mask = pixelroot32::physics::DefaultLayers::kAll;  // Collide with everything\n

"},{"location":"api_reference/physics/collision_types/#custom-layers","title":"Custom Layers","text":"

Define custom layers using bit flags:

namespace MyLayers {\n    const pixelroot32::physics::CollisionLayer kPlayer = 1 << 0;      // Bit 0\n    const pixelroot32::physics::CollisionLayer kEnemy = 1 << 1;       // Bit 1\n    const pixelroot32::physics::CollisionLayer kObstacle = 1 << 2;    // Bit 2\n    const pixelroot32::physics::CollisionLayer kProjectile = 1 << 3;  // Bit 3\n    const pixelroot32::physics::CollisionLayer kCollectible = 1 << 4;  // Bit 4\n}\n\n// Usage\nactor->layer = MyLayers::kPlayer;\nactor->mask = MyLayers::kEnemy | MyLayers::kObstacle;\n
"},{"location":"api_reference/physics/collision_types/#circle-structure","title":"Circle Structure","text":"

Represents a circle for collision detection.

Members: - float x: Center X coordinate - float y: Center Y coordinate - float radius: Radius of the circle

Example:

pixelroot32::physics::Circle circle;\ncircle.x = 100.0f;\ncircle.y = 100.0f;\ncircle.radius = 10.0f;\n

"},{"location":"api_reference/physics/collision_types/#segment-structure","title":"Segment Structure","text":"

Represents a line segment for collision detection.

Members: - float x1, y1: Start point coordinates - float x2, y2: End point coordinates

Example:

pixelroot32::physics::Segment segment;\nsegment.x1 = 0.0f;\nsegment.y1 = 0.0f;\nsegment.x2 = 100.0f;\nsegment.y2 = 100.0f;\n

"},{"location":"api_reference/physics/collision_types/#intersection-functions","title":"Intersection Functions","text":""},{"location":"api_reference/physics/collision_types/#bool-intersectsconst-circle-a-const-circle-b","title":"bool intersects(const Circle& a, const Circle& b)","text":"

Checks if two circles intersect.

Parameters: - a (const Circle&): First circle - b (const Circle&): Second circle

Returns: - bool: true if circles intersect

Example:

pixelroot32::physics::Circle circle1{100.0f, 100.0f, 10.0f};\npixelroot32::physics::Circle circle2{110.0f, 100.0f, 10.0f};\n\nif (pixelroot32::physics::intersects(circle1, circle2)) {\n    // Circles overlap\n}\n

"},{"location":"api_reference/physics/collision_types/#bool-intersectsconst-circle-c-const-rect-r","title":"bool intersects(const Circle& c, const Rect& r)","text":"

Checks if a circle and rectangle intersect.

Parameters: - c (const Circle&): Circle - r (const Rect&): Rectangle

Returns: - bool: true if circle and rectangle intersect

Example:

pixelroot32::physics::Circle circle{100.0f, 100.0f, 10.0f};\npixelroot32::core::Rect rect{95.0f, 95.0f, 20, 20};\n\nif (pixelroot32::physics::intersects(circle, rect)) {\n    // Circle overlaps rectangle\n}\n

"},{"location":"api_reference/physics/collision_types/#bool-intersectsconst-segment-s-const-rect-r","title":"bool intersects(const Segment& s, const Rect& r)","text":"

Checks if a line segment and rectangle intersect.

Parameters: - s (const Segment&): Line segment - r (const Rect&): Rectangle

Returns: - bool: true if segment and rectangle intersect

Example:

pixelroot32::physics::Segment segment{0.0f, 0.0f, 100.0f, 100.0f};\npixelroot32::core::Rect rect{50.0f, 50.0f, 20, 20};\n\nif (pixelroot32::physics::intersects(segment, rect)) {\n    // Segment intersects rectangle\n}\n

"},{"location":"api_reference/physics/collision_types/#bool-sweepcirclevsrectconst-circle-start-const-circle-end-const-rect-target-float-thit","title":"bool sweepCircleVsRect(const Circle& start, const Circle& end, const Rect& target, float& tHit)","text":"

Performs a sweep test: checks if a moving circle collides with a rectangle.

Parameters: - start (const Circle&): Circle at start position - end (const Circle&): Circle at end position - target (const Rect&): Target rectangle - tHit (float&): Output parameter for collision time (0.0 to 1.0)

Returns: - bool: true if collision occurs during sweep

Notes: - Useful for fast-moving projectiles - tHit indicates when collision occurs (0.0 = start, 1.0 = end) - More expensive than simple AABB check

Example:

// Projectile moving from (0, 0) to (100, 100)\npixelroot32::physics::Circle start{0.0f, 0.0f, 5.0f};\npixelroot32::physics::Circle end{100.0f, 100.0f, 5.0f};\npixelroot32::core::Rect wall{50.0f, 50.0f, 20, 20};\n\nfloat tHit = 0.0f;\nif (pixelroot32::physics::sweepCircleVsRect(start, end, wall, tHit)) {\n    // Collision at time tHit\n    float hitX = 0.0f + (100.0f - 0.0f) * tHit;\n    float hitY = 0.0f + (100.0f - 0.0f) * tHit;\n}\n

"},{"location":"api_reference/physics/collision_types/#rect-structure-from-coreentityh","title":"Rect Structure (from core/Entity.h)","text":"

Represents a 2D rectangle for collision detection.

Members: - float x, y: Top-left corner coordinates - int width, height: Dimensions

Methods: - bool intersects(const Rect& other) const: Checks if rectangles overlap

Example:

pixelroot32::core::Rect rect1{10.0f, 20.0f, 50, 50};\npixelroot32::core::Rect rect2{30.0f, 40.0f, 50, 50};\n\nif (rect1.intersects(rect2)) {\n    // Rectangles overlap\n}\n

"},{"location":"api_reference/physics/collision_types/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/physics/collision_types/#layer-based-collision","title":"Layer-Based Collision","text":"
// Define layers\nnamespace GameLayers {\n    const pixelroot32::physics::CollisionLayer kPlayer = 1 << 0;\n    const pixelroot32::physics::CollisionLayer kEnemy = 1 << 1;\n    const pixelroot32::physics::CollisionLayer kObstacle = 1 << 2;\n    const pixelroot32::physics::CollisionLayer kProjectile = 1 << 3;\n}\n\n// Player collides with enemies and obstacles\nplayer->layer = GameLayers::kPlayer;\nplayer->mask = GameLayers::kEnemy | GameLayers::kObstacle;\n\n// Enemy collides with player and obstacles\nenemy->layer = GameLayers::kEnemy;\nenemy->mask = GameLayers::kPlayer | GameLayers::kObstacle;\n\n// Projectile collides with enemies only\nprojectile->layer = GameLayers::kProjectile;\nprojectile->mask = GameLayers::kEnemy;\n
"},{"location":"api_reference/physics/collision_types/#circle-vs-circle-collision","title":"Circle vs Circle Collision","text":"
bool checkCollision(const Circle& a, const Circle& b) {\n    return pixelroot32::physics::intersects(a, b);\n}\n
"},{"location":"api_reference/physics/collision_types/#sweep-test-for-fast-projectiles","title":"Sweep Test for Fast Projectiles","text":"
class ProjectileActor : public pixelroot32::core::Actor {\nprivate:\n    float startX, startY;\n    float endX, endY;\n    float radius = 2.0f;\n\npublic:\n    bool checkWallCollision(const Rect& wall) {\n        pixelroot32::physics::Circle start{startX, startY, radius};\n        pixelroot32::physics::Circle end{endX, endY, radius};\n\n        float tHit = 0.0f;\n        if (pixelroot32::physics::sweepCircleVsRect(start, end, wall, tHit)) {\n            // Collision detected at time tHit\n            return true;\n        }\n        return false;\n    }\n};\n
"},{"location":"api_reference/physics/collision_types/#performance-considerations","title":"Performance Considerations","text":"
  • AABB checks: Very fast (simple rectangle intersection)
  • Circle checks: Slightly slower (distance calculation)
  • Sweep tests: More expensive (use only for fast-moving objects)
  • Layer filtering: Essential for performance with many actors
"},{"location":"api_reference/physics/collision_types/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Float math: Uses floating point; acceptable but integer math would be faster
  • Sweep tests: Use sparingly (more CPU intensive)
  • Layer efficiency: Use layers effectively to minimize checks
"},{"location":"api_reference/physics/collision_types/#see-also","title":"See Also","text":"
  • CollisionSystem - Collision detection system
  • Actor - Actors that use collision layers
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/ui/ui_button/","title":"UIButton","text":"

A clickable button UI element.

"},{"location":"api_reference/ui/ui_button/#description","title":"Description","text":"

UIButton is a clickable button that supports both physical (keyboard/gamepad) and touch input. It can trigger a callback function when pressed and integrates with UI layouts for automatic navigation.

Buttons support selection state (for D-pad navigation), custom styling, and text alignment.

"},{"location":"api_reference/ui/ui_button/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIButton : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_button/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom button classes (if needed)
"},{"location":"api_reference/ui/ui_button/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_button/#uibuttonstring-t-uint8_t-index-float-x-float-y-float-w-float-h-function-callback-textalignment-textalign-center-int-fontsize-2","title":"UIButton(string t, uint8_t index, float x, float y, float w, float h, function callback, TextAlignment textAlign = CENTER, int fontSize = 2)

Constructs a new UIButton.

Parameters: - t (std::string): Button label text - index (uint8_t): Navigation index (for D-pad navigation in layouts) - x (float): X position - y (float): Y position - w (float): Width - h (float): Height - callback (std::function): Function to call when clicked/pressed - textAlign (TextAlignment, optional): Text alignment. Default: CENTER - fontSize (int, optional): Text size multiplier. Default: 2

Example:

#include \"graphics/ui/UIButton.h\"\n\nvoid onStartButtonClicked() {\n    // Start game\n    engine.setScene(&gameScene);\n}\n\nvoid onQuitButtonClicked() {\n    // Quit game\n    engine.stop();\n}\n\n// Create buttons\npixelroot32::graphics::ui::UIButton* startButton = new pixelroot32::graphics::ui::UIButton(\n    \"Start\",\n    0,  // index\n    64.0f, 64.0f,  // position\n    100.0f, 30.0f, // size\n    onStartButtonClicked,\n    pixelroot32::graphics::ui::TextAlignment::CENTER,\n    2\n);\n\npixelroot32::graphics::ui::UIButton* quitButton = new pixelroot32::graphics::ui::UIButton(\n    \"Quit\",\n    1,  // index\n    64.0f, 100.0f,\n    100.0f, 30.0f,\n    onQuitButtonClicked\n);\n

","text":""},{"location":"api_reference/ui/ui_button/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_button/#void-setstylecolor-textcol-color-bgcol-bool-drawbg","title":"void setStyle(Color textCol, Color bgCol, bool drawBg)

Configures the button's visual style.

Parameters: - textCol (Color): Color of the text - bgCol (Color): Color of the background - drawBg (bool): Whether to draw the background rectangle

Returns: - void

Example:

button->setStyle(\n    pixelroot32::graphics::Color::White,  // Text color\n    pixelroot32::graphics::Color::Blue,   // Background color\n    true                                   // Draw background\n);\n

","text":""},{"location":"api_reference/ui/ui_button/#void-setselectedbool-selected","title":"void setSelected(bool selected)

Sets the selection state (e.g., focused via D-pad).

Parameters: - selected (bool): true if selected

Returns: - void

Notes: - Used by layouts for D-pad navigation - Selected buttons typically have different visual style - Can be set manually or automatically by layouts

Example:

button->setSelected(true);  // Highlight button\n

","text":""},{"location":"api_reference/ui/ui_button/#bool-getselected-const","title":"bool getSelected() const

Checks if the button is currently selected.

Returns: - bool: true if selected

Example:

if (button->getSelected()) {\n    // Button is focused\n}\n

","text":""},{"location":"api_reference/ui/ui_button/#bool-isfocusable-const-override","title":"bool isFocusable() const override

Returns true (Buttons are always focusable).

Returns: - bool: Always true

","text":""},{"location":"api_reference/ui/ui_button/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)

Handles input events. Checks for touch events within bounds or confirmation buttons if selected.

Parameters: - input (const pixelroot32::input::InputManager&): The input manager instance

Returns: - void

Notes: - Should be called every frame in update() - Checks if button is selected and action button is pressed - Triggers callback if conditions are met

Example:

void update(unsigned long deltaTime) override {\n    UIElement::update(deltaTime);\n\n    auto& input = engine.getInputManager();\n    button->handleInput(input);\n}\n

","text":""},{"location":"api_reference/ui/ui_button/#void-press","title":"void press()

Manually triggers the button's action.

Returns: - void

Notes: - Calls the button's callback function - Useful for programmatic button presses

Example:

button->press();  // Trigger button action\n

","text":""},{"location":"api_reference/ui/ui_button/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override

Updates the button state.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Handles input and updates button state - Override to add custom update logic

Example:

void update(unsigned long deltaTime) override {\n    UIButton::update(deltaTime);\n\n    // Custom update logic\n    if (shouldPulse) {\n        // Animate button\n    }\n}\n

","text":""},{"location":"api_reference/ui/ui_button/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override

Renders the button.

Parameters: - renderer (pixelroot32::graphics::Renderer&): The renderer to use

Returns: - void

Notes: - Called automatically by Scene if isVisible is true - Draws background (if enabled) and text - Selected state may change appearance

Example:

// Drawing is handled automatically\n// Override only for custom rendering\n

","text":""},{"location":"api_reference/ui/ui_button/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIButton.h\"\n#include \"core/Scene.h\"\n\nclass MainMenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIButton* startButton;\n    pixelroot32::graphics::ui::UIButton* quitButton;\n\npublic:\n    void init() override {\n        // Start button\n        startButton = new pixelroot32::graphics::ui::UIButton(\n            \"Start Game\",\n            0,  // index\n            64.0f, 50.0f,  // position (centered)\n            120.0f, 30.0f, // size\n            [this]() {\n                // Lambda callback\n                engine.setScene(&gameScene);\n            },\n            pixelroot32::graphics::ui::TextAlignment::CENTER,\n            2\n        );\n        startButton->setStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Blue,\n            true\n        );\n        addEntity(startButton);\n\n        // Quit button\n        quitButton = new pixelroot32::graphics::ui::UIButton(\n            \"Quit\",\n            1,  // index\n            64.0f, 90.0f,\n            120.0f, 30.0f,\n            [this]() {\n                // Quit game\n                engine.stop();\n            }\n        );\n        quitButton->setStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Red,\n            true\n        );\n        addEntity(quitButton);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Buttons handle input automatically\n        // Layouts handle navigation automatically\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background\n        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n\n        // Draw UI elements (buttons)\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"api_reference/ui/ui_button/#button-navigation","title":"Button Navigation","text":"

Buttons can be navigated with D-pad when in layouts:

// Buttons in a vertical layout\npixelroot32::graphics::ui::UIVerticalLayout* layout = new UIVerticalLayout(64.0f, 50.0f);\nlayout->addChild(startButton);  // Index 0\nlayout->addChild(quitButton);   // Index 1\n\n// D-pad navigation is automatic\n// UP/DOWN moves selection\n// Action button (A) triggers selected button\n
"},{"location":"api_reference/ui/ui_button/#performance-considerations","title":"Performance Considerations","text":"
  • Input handling: handleInput() is fast; safe to call every frame
  • Rendering: Simple rectangle and text; very efficient
  • Memory: Each button consumes memory (stay within MAX_ENTITIES)
"},{"location":"api_reference/ui/ui_button/#esp32-considerations","title":"ESP32 Considerations","text":"
  • String storage: Button labels use std::string; consider memory usage
  • Callback functions: Use function pointers or lambdas (both efficient)
"},{"location":"api_reference/ui/ui_button/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UILabel - Text label
  • UILayouts - Layout containers
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_checkbox/","title":"UICheckBox","text":"

A clickable checkbox UI element.

"},{"location":"api_reference/ui/ui_checkbox/#description","title":"Description","text":"

UICheckBox is a clickable checkbox that can be toggled between checked and unchecked states. It supports both physical (keyboard/gamepad) and touch input. It can trigger a callback function when its state changes and integrates with UI layouts for automatic navigation.

"},{"location":"api_reference/ui/ui_checkbox/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UICheckBox : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_checkbox/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
"},{"location":"api_reference/ui/ui_checkbox/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_checkbox/#uicheckboxstring-label-uint8_t-index-float-x-float-y-float-w-float-h-bool-checked-false-function-callback-nullptr-int-fontsize-2","title":"UICheckBox(string label, uint8_t index, float x, float y, float w, float h, bool checked = false, function callback = nullptr, int fontSize = 2)

Constructs a new UICheckBox.

Parameters: - label (std::string): Checkbox label text - index (uint8_t): Navigation index (for D-pad navigation in layouts) - x (float): X position - y (float): Y position - w (float): Width - h (float): Height - checked (bool, optional): Initial checked state. Default: false - callback (std::function, optional): Function to call when the state changes. Default: nullptr - fontSize (int, optional): Text size multiplier. Default: 2

Example:

#include \"graphics/ui/UICheckBox.h\"\n\nvoid onCheckChanged(bool checked) {\n    if (checked) {\n        // Sound enabled\n    } else {\n        // Sound disabled\n    }\n}\n\n// Create checkbox\npixelroot32::graphics::ui::UICheckBox* soundCheckbox = new pixelroot32::graphics::ui::UICheckBox(\n    \"Enable Sound\",\n    0,  // index\n    64.0f, 64.0f,  // position\n    120.0f, 20.0f, // size\n    true,          // initial state\n    onCheckChanged,\n    1              // font size\n);\n

","text":""},{"location":"api_reference/ui/ui_checkbox/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_checkbox/#void-setstylecolor-textcol-color-bgcol-bool-drawbg-false","title":"void setStyle(Color textCol, Color bgCol, bool drawBg = false)

Configures the checkbox's visual style.

Parameters: - textCol (Color): Color of the text - bgCol (Color): Color of the background - drawBg (bool, optional): Whether to draw the background rectangle. Default: false

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#void-setcheckedbool-checked","title":"void setChecked(bool checked)

Sets the checked state.

Parameters: - checked (bool): True if checked

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#bool-ischecked-const","title":"bool isChecked() const

Checks if the checkbox is currently checked.

Returns: - bool: true if checked

","text":""},{"location":"api_reference/ui/ui_checkbox/#void-toggle","title":"void toggle()

Toggles the checkbox state and triggers the callback.

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#void-setselectedbool-selected","title":"void setSelected(bool selected)

Sets the selection state (e.g., focused via D-pad).

Parameters: - selected (bool): True if selected

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#bool-getselected-const","title":"bool getSelected() const

Checks if the checkbox is currently selected.

Returns: - bool: true if selected

","text":""},{"location":"api_reference/ui/ui_checkbox/#callbacks","title":"Callbacks","text":""},{"location":"api_reference/ui/ui_checkbox/#oncheckchanged","title":"onCheckChanged

The onCheckChanged callback is a std::function<void(bool)> that is triggered whenever the checkbox state changes via setChecked() or toggle().

checkbox->onCheckChanged = [](bool isChecked) {\n    Serial.println(isChecked ? \"Checked!\" : \"Unchecked!\");\n};\n
","text":""},{"location":"api_reference/ui/ui_checkbox/#navigation-layouts","title":"Navigation & Layouts","text":"

UICheckBox is designed to work seamlessly with UILayout containers (like UIVerticalLayout).

  • Focusable: Returns true for isFocusable(), allowing it to receive focus in a layout.
  • Input Handling: When selected (focused), it listens for the button index provided in the constructor (typically the 'A' button) to toggle its state.
  • Visual Feedback: When selected, it displays a selection indicator (usually a > character) if no background is drawn, or highlights its text/border.
"},{"location":"api_reference/ui/ui_element/","title":"UIElement","text":"

Base class for all user interface elements.

"},{"location":"api_reference/ui/ui_element/#description","title":"Description","text":"

UIElement is the base class for all UI components (buttons, labels, panels, etc.). It inherits from Entity to integrate with the scene graph and automatically sets the entity type to UI_ELEMENT and render layer to 2 (UI layer).

"},{"location":"api_reference/ui/ui_element/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    enum class UIElementType {\n        GENERIC,\n        BUTTON,\n        LABEL,\n        CHECKBOX,\n        LAYOUT\n    };\n\n    class UIElement : public pixelroot32::core::Entity {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_element/#inheritance","title":"Inheritance","text":"
  • Inherits from: pixelroot32::core::Entity
  • Inherited by: UIButton, UICheckBox, UILabel, UIPanel, and all UI layouts
"},{"location":"api_reference/ui/ui_element/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_element/#uielementfloat-x-float-y-float-w-float-h-uielementtype-type-uielementtypegeneric","title":"UIElement(float x, float y, float w, float h, UIElementType type = UIElementType::GENERIC)","text":"

Constructs a new UIElement.

Parameters: - x (float): X position - y (float): Y position - w (float): Width - h (float): Height - type (UIElementType): The type of the element (default: GENERIC)

Notes: - Entity type is automatically set to UI_ELEMENT - Render layer is automatically set to 2 (UI layer) - Position and size can be modified after construction

Example:

class MyUIElement : public pixelroot32::graphics::ui::UIElement {\npublic:\n    MyUIElement(float x, float y) \n        : UIElement(x, y, 100.0f, 50.0f) {}\n\n    void update(unsigned long deltaTime) override {\n        // UI logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // UI rendering\n    }\n};\n

"},{"location":"api_reference/ui/ui_element/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_element/#uielementtype-gettype-const","title":"UIElementType getType() const","text":"

Returns the type of the UI element.

Returns: - UIElementType: The type enum value (GENERIC, BUTTON, LABEL, CHECKBOX, or LAYOUT)

"},{"location":"api_reference/ui/ui_element/#virtual-bool-isfocusable-const","title":"virtual bool isFocusable() const","text":"

Checks if the element is focusable/selectable. Useful for navigation logic.

Returns: - bool: true if focusable, false otherwise (default: false)

"},{"location":"api_reference/ui/ui_element/#void-setpositionfloat-newx-float-newy","title":"void setPosition(float newX, float newY)","text":"

Sets the position of the element.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Updates element position immediately - Use for manual positioning or animations

Example:

uiElement->setPosition(100.0f, 50.0f);\n

"},{"location":"api_reference/ui/ui_element/#virtual-void-getpreferredsizefloat-preferredwidth-float-preferredheight-const","title":"virtual void getPreferredSize(float& preferredWidth, float& preferredHeight) const","text":"

Gets the preferred size of the element. Used by layouts to determine how much space the element needs.

Parameters: - preferredWidth (float&): Output parameter for preferred width (or -1 if flexible) - preferredHeight (float&): Output parameter for preferred height (or -1 if flexible)

Returns: - void

Notes: - Default implementation returns current width/height - Override in derived classes for custom sizing logic - Layouts use this to arrange elements

Example:

void getPreferredSize(float& w, float& h) const override {\n    // Custom sizing logic\n    w = static_cast<float>(width);\n    h = static_cast<float>(height);\n}\n

"},{"location":"api_reference/ui/ui_element/#inherited-from-entity","title":"Inherited from Entity","text":"

UIElement inherits all properties and methods from Entity:

  • float x, y: Position
  • int width, height: Dimensions
  • bool isVisible: Visibility state
  • bool isEnabled: Enabled state
  • unsigned char renderLayer: Render layer (automatically set to 2)
  • void setVisible(bool v): Set visibility
  • void setEnabled(bool e): Set enabled state
  • virtual void update(unsigned long deltaTime): Update logic
  • virtual void draw(Renderer& renderer): Drawing logic
"},{"location":"api_reference/ui/ui_element/#textalignment-enum","title":"TextAlignment Enum","text":"

Text alignment options for UI elements.

Values: - TextAlignment::LEFT: Left-aligned text - TextAlignment::CENTER: Center-aligned text - TextAlignment::RIGHT: Right-aligned text

"},{"location":"api_reference/ui/ui_element/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIElement.h\"\n\nclass CustomUIElement : public pixelroot32::graphics::ui::UIElement {\nprivate:\n    pixelroot32::graphics::Color bgColor;\n\npublic:\n    CustomUIElement(float x, float y, float w, float h) \n        : UIElement(x, y, w, h),\n          bgColor(pixelroot32::graphics::Color::Blue) {}\n\n    void update(unsigned long deltaTime) override {\n        // Update logic (if needed)\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        if (isVisible) {\n            // Draw background\n            renderer.drawFilledRectangle(\n                static_cast<int>(x),\n                static_cast<int>(y),\n                width,\n                height,\n                bgColor\n            );\n\n            // Draw border\n            renderer.drawRectangle(\n                static_cast<int>(x),\n                static_cast<int>(y),\n                width,\n                height,\n                pixelroot32::graphics::Color::White\n            );\n        }\n    }\n\n    void getPreferredSize(float& w, float& h) const override {\n        w = static_cast<float>(width);\n        h = static_cast<float>(height);\n    }\n};\n
"},{"location":"api_reference/ui/ui_element/#performance-considerations","title":"Performance Considerations","text":"
  • Render layer: UI elements are on layer 2, drawn after gameplay
  • Visibility: Use isVisible = false to hide elements efficiently
  • Layout integration: Layouts automatically manage element positioning
"},{"location":"api_reference/ui/ui_element/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Each UI element consumes memory (stay within MAX_ENTITIES)
  • Object pooling: Reuse UI elements when possible
  • Update frequency: Disable UI elements that don't need to update
"},{"location":"api_reference/ui/ui_element/#see-also","title":"See Also","text":"
  • Entity - Base entity class
  • UIButton - Clickable button
  • UILabel - Text label
  • UILayout - Layout containers
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_label/","title":"UILabel","text":"

A simple text label UI element.

"},{"location":"api_reference/ui/ui_label/#description","title":"Description","text":"

UILabel displays a string of text on the screen. It auto-calculates its bounds based on text length and font size, making it easy to create dynamic text displays.

Labels are useful for displaying scores, status messages, menu text, and other UI information.

"},{"location":"api_reference/ui/ui_label/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UILabel : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_label/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom label classes (if needed)
"},{"location":"api_reference/ui/ui_label/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_label/#uilabelstring-t-float-x-float-y-color-col-uint8_t-sz","title":"UILabel(string t, float x, float y, Color col, uint8_t sz)","text":"

Constructs a new UILabel.

Parameters: - t (std::string): Initial text - x (float): X position - y (float): Y position - col (Color): Text color - sz (uint8_t): Text size multiplier

Example:

#include \"graphics/ui/UILabel.h\"\n\n// Create label\npixelroot32::graphics::ui::UILabel* scoreLabel = new pixelroot32::graphics::ui::UILabel(\n    \"Score: 0\",\n    10.0f, 10.0f,  // position\n    pixelroot32::graphics::Color::White,\n    1  // size\n);\n\n// Add to scene\nscene->addEntity(scoreLabel);\n

"},{"location":"api_reference/ui/ui_label/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_label/#void-settextconst-string-t","title":"void setText(const string& t)","text":"

Updates the label's text. Recalculates dimensions immediately using the active font metrics to ensure precise layout.

Parameters: - t (const std::string&): New text

Returns: - void

Notes: - Automatically recalculates width and height using FontManager::textWidth - Use for dynamic text (scores, timers, etc.) - Text is stored as std::string (consider memory on ESP32)

Example:

// Update score label\nchar scoreText[32];\nsnprintf(scoreText, sizeof(scoreText), \"Score: %d\", score);\nscoreLabel->setText(scoreText);\n

"},{"location":"api_reference/ui/ui_label/#void-setvisiblebool-v","title":"void setVisible(bool v)","text":"

Sets visibility.

Parameters: - v (bool): true to show, false to hide

Returns: - void

Notes: - Inherited from Entity - Hides label without removing from scene

Example:

label->setVisible(false);  // Hide\nlabel->setVisible(true);   // Show\n

"},{"location":"api_reference/ui/ui_label/#void-centerxint-screenwidth","title":"void centerX(int screenWidth)","text":"

Centers the label horizontally within a given width (typically the screen width). Recalculates dimensions before positioning to ensure perfect centering.

Parameters: - screenWidth (int): The width to center within (e.g., engine.getRenderer().getWidth())

Returns: - void

Example:

label->centerX(128); // Center on a 128px screen\n

"},{"location":"api_reference/ui/ui_label/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the label state.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Default implementation does nothing - Override to add custom update logic (animations, etc.)

Example:

void update(unsigned long deltaTime) override {\n    UILabel::update(deltaTime);\n\n    // Custom logic (e.g., update text based on game state)\n    if (scoreChanged) {\n        updateScoreText();\n    }\n}\n

"},{"location":"api_reference/ui/ui_label/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Renders the label.

Parameters: - renderer (pixelroot32::graphics::Renderer&): The renderer to use

Returns: - void

Notes: - Called automatically by Scene if isVisible is true - Draws text at label position - Uses default font

Example:

// Drawing is handled automatically\n// Override only for custom rendering\n

"},{"location":"api_reference/ui/ui_label/#auto-sizing","title":"Auto-Sizing","text":"

Labels automatically calculate their size based on text:

  • Width: text.length() * (6 * size) pixels
  • Height: 8 * size pixels

Example:

// Label with text \"Hello\" (5 characters), size 1\n// Width: 5 * 6 * 1 = 30 pixels\n// Height: 8 * 1 = 8 pixels\n\nUILabel label(\"Hello\", 10, 10, Color::White, 1);\n// label.width = 30, label.height = 8\n

"},{"location":"api_reference/ui/ui_label/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UILabel.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n    int score = 0;\n    int lives = 3;\n\npublic:\n    void init() override {\n        // Score label\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\",\n            10.0f, 10.0f,\n            pixelroot32::graphics::Color::White,\n            1\n        );\n        addEntity(scoreLabel);\n\n        // Lives label\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\",\n            10.0f, 25.0f,\n            pixelroot32::graphics::Color::Yellow,\n            1\n        );\n        addEntity(livesLabel);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Update labels\n        char text[32];\n        snprintf(text, sizeof(text), \"Score: %d\", score);\n        scoreLabel->setText(text);\n\n        snprintf(text, sizeof(text), \"Lives: %d\", lives);\n        livesLabel->setText(text);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw game\n        Scene::draw(renderer);\n\n        // Labels are drawn automatically by Scene::draw()\n    }\n};\n
"},{"location":"api_reference/ui/ui_label/#centered-labels","title":"Centered Labels","text":"
// Create centered title\npixelroot32::graphics::ui::UILabel* title = new pixelroot32::graphics::ui::UILabel(\n    \"Game Title\",\n    0, 20.0f,  // X will be adjusted\n    pixelroot32::graphics::Color::Yellow,\n    2  // Large text\n);\ntitle->centerX(128);  // Center on screen\naddEntity(title);\n
"},{"location":"api_reference/ui/ui_label/#performance-considerations","title":"Performance Considerations","text":"
  • Text updates: setText() recalculates size; avoid calling every frame if text doesn't change
  • String storage: Uses std::string; consider memory on ESP32
  • Rendering: Simple text drawing; very efficient
  • Static text: For static text, create once and don't update
"},{"location":"api_reference/ui/ui_label/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: std::string uses heap memory; use static buffers when possible
  • Text updates: Limit frequency of text updates
  • String length: Keep text short to save memory
"},{"location":"api_reference/ui/ui_label/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UIButton - Clickable button
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layout/","title":"UILayout","text":"

Base class for UI layout containers.

"},{"location":"api_reference/ui/ui_layout/#description","title":"Description","text":"

UILayout is the base class for all layout containers. Layouts organize UI elements automatically, handling positioning, spacing, and optional scrolling. Layouts are themselves UI elements that can be added to scenes.

"},{"location":"api_reference/ui/ui_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UILayout : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: UIVerticalLayout, UIHorizontalLayout, UIGridLayout, UIAnchorLayout
"},{"location":"api_reference/ui/ui_layout/#scrollbehavior-enum","title":"ScrollBehavior Enum","text":"

Defines how scrolling behaves in layouts.

Values: - ScrollBehavior::NONE: No scrolling allowed - ScrollBehavior::SCROLL: Scroll freely within bounds - ScrollBehavior::CLAMP: Scroll but clamp to content bounds

"},{"location":"api_reference/ui/ui_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layout/#virtual-void-addelementuielement-element-0","title":"virtual void addElement(UIElement* element) = 0","text":"

Adds a UI element to the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to add

"},{"location":"api_reference/ui/ui_layout/#virtual-void-removeelementuielement-element-0","title":"virtual void removeElement(UIElement* element) = 0","text":"

Removes a UI element from the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to remove

"},{"location":"api_reference/ui/ui_layout/#virtual-void-updatelayout-0","title":"virtual void updateLayout() = 0","text":"

Recalculates positions of all elements in the layout. Must be implemented by derived classes.

Returns: - void

Notes: - Should be called automatically when elements are added/removed

"},{"location":"api_reference/ui/ui_layout/#virtual-void-handleinputconst-inputmanager-input-0","title":"virtual void handleInput(const InputManager& input) = 0","text":"

Handles input for layout navigation (scroll, selection, etc.). Must be implemented by derived classes.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

"},{"location":"api_reference/ui/ui_layout/#void-setpaddingfloat-p","title":"void setPadding(float p)","text":"

Sets the padding (internal spacing) of the layout.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Layout is automatically recalculated

"},{"location":"api_reference/ui/ui_layout/#float-getpadding-const","title":"float getPadding() const","text":"

Gets the current padding.

Returns: - float: Padding value in pixels

"},{"location":"api_reference/ui/ui_layout/#void-setspacingfloat-s","title":"void setSpacing(float s)","text":"

Sets the spacing between elements.

Parameters: - s (float): Spacing value in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Default: 4.0 pixels

"},{"location":"api_reference/ui/ui_layout/#float-getspacing-const","title":"float getSpacing() const","text":"

Gets the current spacing.

Returns: - float: Spacing value in pixels

"},{"location":"api_reference/ui/ui_layout/#size_t-getelementcount-const","title":"size_t getElementCount() const","text":"

Gets the number of elements in the layout.

Returns: - size_t: Element count

"},{"location":"api_reference/ui/ui_layout/#uielement-getelementsize_t-index-const","title":"UIElement* getElement(size_t index) const","text":"

Gets the element at a specific index.

Parameters: - index (size_t): Element index

Returns: - UIElement*: Pointer to the element, or nullptr if index is invalid

"},{"location":"api_reference/ui/ui_layout/#void-clearelements","title":"void clearElements()","text":"

Clears all elements from the layout.

Returns: - void

Notes: - Elements are not deleted (you must manage their lifetimes) - Layout is automatically recalculated

"},{"location":"api_reference/ui/ui_layout/#protected-members","title":"Protected Members","text":"
  • std::vector<UIElement*> elements: List of child elements
  • float padding: Internal padding
  • float spacing: Spacing between elements (default: 4.0)
  • float scrollOffset: Current scroll offset
  • bool enableScroll: Whether scrolling is enabled
  • ScrollBehavior scrollBehavior: Scroll behavior mode
"},{"location":"api_reference/ui/ui_layout/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UIVerticalLayout - Vertical layout
  • UIHorizontalLayout - Horizontal layout
  • UIGridLayout - Grid layout
  • UIAnchorLayout - Anchor layout
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/","title":"UIAnchorLayout","text":"

Layout that positions elements at fixed anchor points on the screen.

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#description","title":"Description","text":"

UIAnchorLayout positions UI elements at fixed anchor points (corners, center, edges) without reflow. Very efficient for HUDs, debug UI, and fixed-position elements. Positions are calculated once or when screen size changes.

This layout is ideal for HUD elements like score, lives, health bars, and other fixed-position UI.

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIAnchorLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom anchor layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#anchor-enum","title":"Anchor Enum","text":"

Defines anchor points for positioning UI elements.

Values: - Anchor::TOP_LEFT: Top-left corner - Anchor::TOP_RIGHT: Top-right corner - Anchor::BOTTOM_LEFT: Bottom-left corner - Anchor::BOTTOM_RIGHT: Bottom-right corner - Anchor::CENTER: Center of screen - Anchor::TOP_CENTER: Top center - Anchor::BOTTOM_CENTER: Bottom center - Anchor::LEFT_CENTER: Left center - Anchor::RIGHT_CENTER: Right center

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/anchor_layout/#uianchorlayoutfloat-x-float-y-float-w-float-h","title":"UIAnchorLayout(float x, float y, float w, float h)","text":"

Constructs a new UIAnchorLayout.

Parameters: - x (float): X position of the layout container (usually 0) - y (float): Y position of the layout container (usually 0) - w (float): Width of the layout container (usually screen width) - h (float): Height of the layout container (usually screen height)

Example:

#include \"graphics/ui/UIAnchorLayout.h\"\n\n// Create full-screen anchor layout for HUD\nauto& renderer = engine.getRenderer();\npixelroot32::graphics::ui::UIAnchorLayout* hud = \n    new pixelroot32::graphics::ui::UIAnchorLayout(\n        0.0f, 0.0f,\n        static_cast<float>(renderer.getWidth()),\n        static_cast<float>(renderer.getHeight())\n    );\nhud->setScreenSize(\n    static_cast<float>(renderer.getWidth()),\n    static_cast<float>(renderer.getHeight())\n);\n

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-addelementuielement-element-anchor-anchor","title":"void addElement(UIElement* element, Anchor anchor)","text":"

Adds a UI element with a specific anchor point.

Parameters: - element (UIElement*): Pointer to the element to add - anchor (Anchor): Anchor point for positioning

Returns: - void

Example:

// Score label at top-right\nhud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\n// Lives label at top-left\nhud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout (defaults to TOP_LEFT anchor).

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements based on anchors.

Returns: - void

Notes: - Called automatically when screen size changes - Can be called manually if needed

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input (no-op for anchor layout, elements handle their own input).

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Anchor layout doesn't handle navigation - Elements handle their own input

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout and child elements.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws all elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-setscreensizefloat-screenwidth-float-screenheight","title":"void setScreenSize(float screenWidth, float screenHeight)","text":"

Sets the screen size for anchor calculations.

Parameters: - screenWidth (float): Screen width in pixels - screenHeight (float): Screen height in pixels

Returns: - void

Notes: - Used to calculate anchor positions - Should match actual display size - Layout is automatically recalculated

Example:

auto& renderer = engine.getRenderer();\nhud->setScreenSize(\n    static_cast<float>(renderer.getWidth()),\n    static_cast<float>(renderer.getHeight())\n);\n

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#float-getscreenwidth-const","title":"float getScreenWidth() const","text":"

Gets the screen width.

Returns: - float: Screen width in pixels

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#float-getscreenheight-const","title":"float getScreenHeight() const","text":"

Gets the screen height.

Returns: - float: Screen height in pixels

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIAnchorLayout.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIAnchorLayout* hud;\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n\npublic:\n    void init() override {\n        auto& renderer = engine.getRenderer();\n\n        // Create HUD layout\n        hud = new pixelroot32::graphics::ui::UIAnchorLayout(\n            0.0f, 0.0f,\n            static_cast<float>(renderer.getWidth()),\n            static_cast<float>(renderer.getHeight())\n        );\n        hud->setScreenSize(\n            static_cast<float>(renderer.getWidth()),\n            static_cast<float>(renderer.getHeight())\n        );\n\n        // Score label (top-right)\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\",\n            0, 0,\n            Color::White,\n            1\n        );\n        hud->addElement(scoreLabel, \n                        pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\n        // Lives label (top-left)\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\",\n            0, 0,\n            Color::Yellow,\n            1\n        );\n        hud->addElement(livesLabel, \n                        pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n\n        addEntity(hud);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Update labels\n        char text[32];\n        snprintf(text, sizeof(text), \"Score: %d\", score);\n        scoreLabel->setText(text);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw game\n        Scene::draw(renderer);\n\n        // HUD is drawn automatically (on layer 2)\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#anchor-positioning","title":"Anchor Positioning","text":"

Elements are positioned based on their anchor:

  • TOP_LEFT: Element's top-left at screen top-left
  • TOP_RIGHT: Element's top-right at screen top-right
  • BOTTOM_LEFT: Element's bottom-left at screen bottom-left
  • BOTTOM_RIGHT: Element's bottom-right at screen bottom-right
  • CENTER: Element centered on screen
  • TOP_CENTER: Element centered horizontally, top-aligned
  • BOTTOM_CENTER: Element centered horizontally, bottom-aligned
  • LEFT_CENTER: Element centered vertically, left-aligned
  • RIGHT_CENTER: Element centered vertically, right-aligned
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#performance-considerations","title":"Performance Considerations","text":"
  • No reflow: Very efficient (positions calculated once)
  • Fixed positions: Ideal for HUD elements
  • Viewport independent: Elements stay in fixed screen positions
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Very efficient (no complex calculations)
  • Update frequency: Positions only recalculate when screen size changes
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class
  • UILabel - Labels for HUD
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/grid_layout/","title":"UIGridLayout","text":"

Grid layout container for organizing elements in a matrix.

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#description","title":"Description","text":"

UIGridLayout organizes UI elements in a fixed grid of rows and columns. It supports navigation in 4 directions (UP/DOWN/LEFT/RIGHT) and automatic positioning based on grid coordinates.

This layout is ideal for inventories, level selection screens, galleries, and any grid-based UI arrangement.

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIGridLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/grid_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom grid layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/grid_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/grid_layout/#uigridlayoutfloat-x-float-y-float-w-float-h","title":"UIGridLayout(float x, float y, float w, float h)","text":"

Constructs a new UIGridLayout.

Parameters: - x (float): X position of the layout container - y (float): Y position of the layout container - w (float): Width of the layout container - h (float): Height of the layout container

Example:

#include \"graphics/ui/UIGridLayout.h\"\n\n// Create 4x4 grid for inventory\npixelroot32::graphics::ui::UIGridLayout* inventory = \n    new pixelroot32::graphics::ui::UIGridLayout(\n        10.0f, 10.0f,  // position\n        108.0f, 108.0f // size\n    );\ninventory->setColumns(4);\n

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout.

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

Notes: - Elements are arranged in grid order (left to right, top to bottom) - Layout is automatically recalculated - Cell size is calculated based on columns and layout size

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements.

Returns: - void

Notes: - Recalculates cell dimensions - Recalculates row count - Repositions all elements

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input for navigation and selection.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Handles UP/DOWN/LEFT/RIGHT navigation - Manages selection state - Wraps around grid edges (if configured)

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout and child elements.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the layout and its visible elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setcolumnsuint8_t-cols","title":"void setColumns(uint8_t cols)","text":"

Sets the number of columns in the grid.

Parameters: - cols (uint8_t): Number of columns (must be > 0)

Returns: - void

Notes: - Layout is automatically recalculated - Row count is calculated based on element count and columns

Example:

inventory->setColumns(4);  // 4 columns\n

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#uint8_t-getcolumns-const","title":"uint8_t getColumns() const","text":"

Gets the number of columns.

Returns: - uint8_t: Number of columns

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#uint8_t-getrows-const","title":"uint8_t getRows() const","text":"

Gets the number of rows (calculated).

Returns: - uint8_t: Number of rows

Notes: - Calculated as ceil(elementCount / columns)

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#int-getselectedindex-const","title":"int getSelectedIndex() const","text":"

Gets the currently selected element index.

Returns: - int: Selected index, or -1 if none selected

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setselectedindexint-index","title":"void setSelectedIndex(int index)","text":"

Sets the selected element index.

Parameters: - index (int): Index to select (-1 to deselect)

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#uielement-getselectedelement-const","title":"UIElement* getSelectedElement() const","text":"

Gets the selected element.

Returns: - UIElement*: Pointer to selected element, or nullptr if none selected

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setnavigationbuttonsuint8_t-upbutton-uint8_t-downbutton-uint8_t-leftbutton-uint8_t-rightbutton","title":"void setNavigationButtons(uint8_t upButton, uint8_t downButton, uint8_t leftButton, uint8_t rightButton)","text":"

Sets the navigation button indices.

Parameters: - upButton (uint8_t): Button index for UP navigation - downButton (uint8_t): Button index for DOWN navigation - leftButton (uint8_t): Button index for LEFT navigation - rightButton (uint8_t): Button index for RIGHT navigation

Returns: - void

Notes: - Default: UP=0, DOWN=1, LEFT=2, RIGHT=3 - Change if your input mapping differs

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setbuttonstylecolor-selectedtextcol-color-selectedbgcol-color-unselectedtextcol-color-unselectedbgcol","title":"void setButtonStyle(Color selectedTextCol, Color selectedBgCol, Color unselectedTextCol, Color unselectedBgCol)","text":"

Sets the style colors for selected and unselected buttons.

Parameters: - selectedTextCol (Color): Text color when selected - selectedBgCol (Color): Background color when selected - unselectedTextCol (Color): Text color when not selected - unselectedBgCol (Color): Background color when not selected

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIGridLayout.h\"\n\nclass InventoryScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIGridLayout* inventory;\n\npublic:\n    void init() override {\n        // Create 4x4 inventory grid\n        inventory = new pixelroot32::graphics::ui::UIGridLayout(\n            10.0f, 10.0f,\n            108.0f, 108.0f\n        );\n        inventory->setColumns(4);\n        inventory->setSpacing(2.0f);\n        inventory->setPadding(4.0f);\n\n        // Add inventory slots\n        for (int i = 0; i < 16; i++) {\n            auto* slot = createInventorySlot(i);\n            inventory->addElement(slot);\n        }\n\n        addEntity(inventory);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/grid_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class (abstract)
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/","title":"UIHorizontalLayout","text":"

Horizontal layout container with scroll support.

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#description","title":"Description","text":"

UIHorizontalLayout organizes UI elements horizontally, one next to another. It supports scrolling when content exceeds the visible viewport and handles keyboard/D-pad navigation automatically.

This layout is ideal for toolbars, tab bars, horizontal menus, and any horizontal arrangement of UI elements.

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIHorizontalLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom horizontal layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#uihorizontallayoutfloat-x-float-y-float-w-float-h","title":"UIHorizontalLayout(float x, float y, float w, float h)","text":"

Constructs a new UIHorizontalLayout.

Parameters: - x (float): X position of the layout container - y (float): Y position of the layout container - w (float): Width of the layout container (viewport width) - h (float): Height of the layout container

Example:

#include \"graphics/ui/UIHorizontalLayout.h\"\n\n// Create horizontal layout for toolbar\npixelroot32::graphics::ui::UIHorizontalLayout* toolbar = \n    new pixelroot32::graphics::ui::UIHorizontalLayout(\n        0.0f, 0.0f,   // position (top of screen)\n        128.0f, 20.0f // size\n    );\n

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout.

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

Notes: - Elements are arranged horizontally, left to right - Layout is automatically recalculated - Elements are positioned based on spacing and padding

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements.

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input for navigation and scrolling.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Handles LEFT/RIGHT navigation - Manages selection state - Handles scrolling if enabled

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout (handles smooth scrolling).

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the layout and its visible elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setscrollenabledbool-enable","title":"void setScrollEnabled(bool enable)","text":"

Enables or disables scrolling.

Parameters: - enable (bool): true to enable scrolling

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setviewportwidthfloat-w","title":"void setViewportWidth(float w)","text":"

Sets the viewport width (visible area).

Parameters: - w (float): Viewport width in pixels

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#float-getscrolloffset-const","title":"float getScrollOffset() const","text":"

Gets the current scroll offset.

Returns: - float: Scroll offset in pixels

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setscrolloffsetfloat-offset","title":"void setScrollOffset(float offset)","text":"

Sets the scroll offset directly.

Parameters: - offset (float): Scroll offset in pixels

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#float-getcontentwidth-const","title":"float getContentWidth() const","text":"

Gets the total content width.

Returns: - float: Content width in pixels

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#int-getselectedindex-const","title":"int getSelectedIndex() const","text":"

Gets the currently selected element index.

Returns: - int: Selected index, or -1 if none selected

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setselectedindexint-index","title":"void setSelectedIndex(int index)","text":"

Sets the selected element index.

Parameters: - index (int): Index to select (-1 to deselect)

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#uielement-getselectedelement-const","title":"UIElement* getSelectedElement() const","text":"

Gets the selected element.

Returns: - UIElement*: Pointer to selected element, or nullptr if none selected

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setscrollspeedfloat-speed","title":"void setScrollSpeed(float speed)","text":"

Sets the scroll speed for smooth scrolling.

Parameters: - speed (float): Pixels per millisecond

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setnavigationbuttonsuint8_t-leftbutton-uint8_t-rightbutton","title":"void setNavigationButtons(uint8_t leftButton, uint8_t rightButton)","text":"

Sets the navigation button indices.

Parameters: - leftButton (uint8_t): Button index for LEFT navigation - rightButton (uint8_t): Button index for RIGHT navigation

Returns: - void

Notes: - Default: LEFT = 2, RIGHT = 3 - Change if your input mapping differs

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setbuttonstylecolor-selectedtextcol-color-selectedbgcol-color-unselectedtextcol-color-unselectedbgcol","title":"void setButtonStyle(Color selectedTextCol, Color selectedBgCol, Color unselectedTextCol, Color unselectedBgCol)","text":"

Sets the style colors for selected and unselected buttons.

Parameters: - selectedTextCol (Color): Text color when selected - selectedBgCol (Color): Background color when selected - unselectedTextCol (Color): Text color when not selected - unselectedBgCol (Color): Background color when not selected

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIHorizontalLayout.h\"\n\nclass ToolbarScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIHorizontalLayout* toolbar;\n\npublic:\n    void init() override {\n        // Create horizontal toolbar\n        toolbar = new pixelroot32::graphics::ui::UIHorizontalLayout(\n            0.0f, 0.0f,    // Top of screen\n            128.0f, 20.0f  // Full width, 20px tall\n        );\n        toolbar->setSpacing(4.0f);\n        toolbar->setPadding(2.0f);\n\n        // Add toolbar buttons\n        toolbar->addElement(newButton(\"File\", ...));\n        toolbar->addElement(newButton(\"Edit\", ...));\n        toolbar->addElement(newButton(\"View\", ...));\n\n        addEntity(toolbar);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class (abstract)
  • UIVerticalLayout - Vertical layout
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/padding_container/","title":"UIPaddingContainer","text":"

Container that wraps a single UI element and applies padding.

"},{"location":"api_reference/ui/ui_layouts/padding_container/#description","title":"Description","text":"

UIPaddingContainer adds padding/margin around a single child element without organizing multiple elements. Useful for adding spacing to individual elements or nesting layouts with custom padding.

This container is simpler than UIPanel (no background/border) and focuses only on spacing.

"},{"location":"api_reference/ui/ui_layouts/padding_container/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIPaddingContainer : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/padding_container/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom padding containers (if needed)
"},{"location":"api_reference/ui/ui_layouts/padding_container/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/padding_container/#uipaddingcontainerfloat-x-float-y-float-w-float-h","title":"UIPaddingContainer(float x, float y, float w, float h)","text":"

Constructs a new UIPaddingContainer.

Parameters: - x (float): X position of the container - y (float): Y position of the container - w (float): Width of the container - h (float): Height of the container

Example:

#include \"graphics/ui/UIPaddingContainer.h\"\n\n// Create padding container\npixelroot32::graphics::ui::UIPaddingContainer* padded = \n    new pixelroot32::graphics::ui::UIPaddingContainer(\n        10.0f, 10.0f,\n        108.0f, 108.0f\n    );\npadded->setPadding(8.0f);  // 8px padding on all sides\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setchilduielement-element","title":"void setChild(UIElement* element)","text":"

Sets the child element.

Parameters: - element (UIElement*): Pointer to the UI element to wrap

Returns: - void

Notes: - Child element is positioned with padding applied - Can wrap any UI element (button, label, layout, etc.)

Example:

padded->setChild(button);\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#uielement-getchild-const","title":"UIElement* getChild() const","text":"

Gets the child element.

Returns: - UIElement*: Pointer to the child element, or nullptr if none set

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setpaddingfloat-p","title":"void setPadding(float p)","text":"

Sets uniform padding on all sides.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Applies same padding to all sides - Child position is automatically updated

Example:

padded->setPadding(10.0f);  // 10px padding all around\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setpaddingfloat-left-float-right-float-top-float-bottom","title":"void setPadding(float left, float right, float top, float bottom)","text":"

Sets asymmetric padding.

Parameters: - left (float): Left padding in pixels - right (float): Right padding in pixels - top (float): Top padding in pixels - bottom (float): Bottom padding in pixels

Returns: - void

Example:

padded->setPadding(10.0f, 5.0f, 8.0f, 12.0f);  // Different padding per side\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingleft-const","title":"float getPaddingLeft() const","text":"

Gets the left padding.

Returns: - float: Left padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingright-const","title":"float getPaddingRight() const","text":"

Gets the right padding.

Returns: - float: Right padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingtop-const","title":"float getPaddingTop() const","text":"

Gets the top padding.

Returns: - float: Top padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingbottom-const","title":"float getPaddingBottom() const","text":"

Gets the bottom padding.

Returns: - float: Bottom padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setpositionfloat-newx-float-newy","title":"void setPosition(float newX, float newY)","text":"

Sets the position of the container. Also updates the child element's position.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Child element position is updated automatically with padding applied

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the container and child element.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Updates child element if set - Called automatically by Scene

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the child element.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

Notes: - Only draws child element (no background/border) - Child is drawn at padded position

"},{"location":"api_reference/ui/ui_layouts/padding_container/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIPaddingContainer.h\"\n\nclass MenuScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Create button\n        auto* button = new UIButton(\"Start\", 0, 0, 0, 100.0f, 30.0f, \n                                    [this]() { startGame(); });\n\n        // Wrap button with padding\n        auto* paddedButton = new pixelroot32::graphics::ui::UIPaddingContainer(\n            64.0f, 50.0f,  // position\n            120.0f, 50.0f  // size (button + padding)\n        );\n        paddedButton->setPadding(10.0f);  // 10px padding\n        paddedButton->setChild(button);\n\n        addEntity(paddedButton);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/padding_container/#nesting-with-layouts","title":"Nesting with Layouts","text":"
// Create layout\nauto* layout = new UIVerticalLayout(10, 10, 108, 108);\n\n// Wrap layout with padding\nauto* paddedLayout = new UIPaddingContainer(0, 0, 128, 128);\npaddedLayout->setPadding(10.0f, 10.0f, 20.0f, 20.0f);  // Asymmetric\npaddedLayout->setChild(layout);\n
"},{"location":"api_reference/ui/ui_layouts/padding_container/#performance-considerations","title":"Performance Considerations","text":"
  • Rendering: Very efficient (just draws child)
  • Position calculation: Fast (simple addition)
  • Memory: Minimal overhead
"},{"location":"api_reference/ui/ui_layouts/padding_container/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Very lightweight
  • Update frequency: Position only recalculates when padding/position changes
"},{"location":"api_reference/ui/ui_layouts/padding_container/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UIPanel - Panel with background and border
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/panel/","title":"UIPanel","text":"

Visual container that draws a background and border around a child element.

"},{"location":"api_reference/ui/ui_layouts/panel/#description","title":"Description","text":"

UIPanel provides a retro-style window/panel appearance with a background color and border. Typically contains a UILayout or other UI elements. Useful for dialogs, menus, and information panels.

The panel wraps a single child element and draws a background rectangle and border around it.

"},{"location":"api_reference/ui/ui_layouts/panel/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIPanel : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/panel/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom panel classes (if needed)
"},{"location":"api_reference/ui/ui_layouts/panel/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/panel/#uipanelfloat-x-float-y-float-w-float-h","title":"UIPanel(float x, float y, float w, float h)","text":"

Constructs a new UIPanel.

Parameters: - x (float): X position of the panel - y (float): Y position of the panel - w (float): Width of the panel - h (float): Height of the panel

Example:

#include \"graphics/ui/UIPanel.h\"\n\n// Create dialog panel\npixelroot32::graphics::ui::UIPanel* dialog = \n    new pixelroot32::graphics::ui::UIPanel(\n        20.0f, 30.0f,  // position\n        88.0f, 68.0f   // size\n    );\n

"},{"location":"api_reference/ui/ui_layouts/panel/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/panel/#void-setchilduielement-element","title":"void setChild(UIElement* element)","text":"

Sets the child element.

Parameters: - element (UIElement*): Pointer to the UI element to wrap (typically a UILayout)

Returns: - void

Notes: - Child element is positioned inside the panel (with padding) - Typically a layout (VerticalLayout, etc.)

Example:

// Create panel\nauto* panel = new UIPanel(20, 30, 88, 68);\n\n// Create layout for panel content\nauto* layout = new UIVerticalLayout(0, 0, 80, 60);\nlayout->addElement(button1);\nlayout->addElement(button2);\n\n// Set layout as panel child\npanel->setChild(layout);\n

"},{"location":"api_reference/ui/ui_layouts/panel/#uielement-getchild-const","title":"UIElement* getChild() const","text":"

Gets the child element.

Returns: - UIElement*: Pointer to the child element, or nullptr if none set

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setbackgroundcolorcolor-color","title":"void setBackgroundColor(Color color)","text":"

Sets the background color.

Parameters: - color (Color): Background color

Returns: - void

Example:

panel->setBackgroundColor(Color::Blue);\n

"},{"location":"api_reference/ui/ui_layouts/panel/#color-getbackgroundcolor-const","title":"Color getBackgroundColor() const","text":"

Gets the background color.

Returns: - Color: Background color

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setbordercolorcolor-color","title":"void setBorderColor(Color color)","text":"

Sets the border color.

Parameters: - color (Color): Border color

Returns: - void

Example:

panel->setBorderColor(Color::White);\n

"},{"location":"api_reference/ui/ui_layouts/panel/#color-getbordercolor-const","title":"Color getBorderColor() const","text":"

Gets the border color.

Returns: - Color: Border color

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setborderwidthuint8_t-width","title":"void setBorderWidth(uint8_t width)","text":"

Sets the border width.

Parameters: - width (uint8_t): Border width in pixels

Returns: - void

Notes: - Default: 1 pixel - Higher values = thicker border

Example:

panel->setBorderWidth(2);  // 2 pixel border\n

"},{"location":"api_reference/ui/ui_layouts/panel/#uint8_t-getborderwidth-const","title":"uint8_t getBorderWidth() const","text":"

Gets the border width.

Returns: - uint8_t: Border width in pixels

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setpositionfloat-newx-float-newy","title":"void setPosition(float newX, float newY)","text":"

Sets the position of the panel. Also updates the child element's position.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Child element position is updated automatically

"},{"location":"api_reference/ui/ui_layouts/panel/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the panel and child element.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Updates child element if set - Called automatically by Scene

"},{"location":"api_reference/ui/ui_layouts/panel/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the panel (background, border) and child element.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

Notes: - Draws background rectangle - Draws border rectangle - Draws child element if set

"},{"location":"api_reference/ui/ui_layouts/panel/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIPanel.h\"\n#include \"graphics/ui/UIVerticalLayout.h\"\n\nclass DialogScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIPanel* dialog;\n\npublic:\n    void init() override {\n        // Create dialog panel\n        dialog = new pixelroot32::graphics::ui::UIPanel(\n            20.0f, 30.0f,  // position\n            88.0f, 68.0f   // size\n        );\n        dialog->setBackgroundColor(Color::Navy);\n        dialog->setBorderColor(Color::White);\n        dialog->setBorderWidth(2);\n\n        // Create layout for dialog content\n        auto* layout = new pixelroot32::graphics::ui::UIVerticalLayout(\n            4.0f, 4.0f,  // Position inside panel\n            80.0f, 60.0f // Size inside panel\n        );\n        layout->setSpacing(8.0f);\n\n        // Add buttons\n        auto* okButton = new UIButton(\"OK\", 0, 0, 0, 70.0f, 20.0f, \n                                     [this]() { closeDialog(); });\n        auto* cancelButton = new UIButton(\"Cancel\", 1, 0, 0, 70.0f, 20.0f,\n                                         [this]() { closeDialog(); });\n\n        layout->addElement(okButton);\n        layout->addElement(cancelButton);\n\n        // Set layout as panel child\n        dialog->setChild(layout);\n\n        addEntity(dialog);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/panel/#performance-considerations","title":"Performance Considerations","text":"
  • Rendering: Simple rectangles; very efficient
  • Child updates: Child element updates are fast
  • Memory: Small overhead (just colors and border width)
"},{"location":"api_reference/ui/ui_layouts/panel/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Panel is lightweight
  • Rendering: Two rectangles (background + border); minimal overhead
"},{"location":"api_reference/ui/ui_layouts/panel/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UILayouts - Layout containers to use inside panels
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/","title":"UIVerticalLayout","text":"

Vertical layout container with scroll support.

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#description","title":"Description","text":"

UIVerticalLayout organizes UI elements vertically, one below another. It supports scrolling when content exceeds the visible viewport and handles keyboard/D-pad navigation automatically.

This layout is ideal for menus, lists, and any vertical arrangement of UI elements.

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIVerticalLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom vertical layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/vertical_layout/#uiverticallayoutfloat-x-float-y-float-w-float-h","title":"UIVerticalLayout(float x, float y, float w, float h)","text":"

Constructs a new UIVerticalLayout.

Parameters: - x (float): X position of the layout container - y (float): Y position of the layout container - w (float): Width of the layout container - h (float): Height of the layout container (viewport height)

Example:

#include \"graphics/ui/UIVerticalLayout.h\"\n\n// Create vertical layout for menu\npixelroot32::graphics::ui::UIVerticalLayout* menuLayout = \n    new pixelroot32::graphics::ui::UIVerticalLayout(\n        20.0f, 20.0f,  // position\n        88.0f, 88.0f   // size (viewport)\n    );\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout.

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

Notes: - Elements are arranged vertically, one below another - Layout is automatically recalculated - Elements are positioned based on spacing and padding

Example:

menuLayout->addElement(startButton);\nmenuLayout->addElement(quitButton);\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

Notes: - Layout is automatically recalculated - Element is not deleted (you must manage its lifetime)

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements.

Returns: - void

Notes: - Called automatically when elements are added/removed - Can be called manually if needed - Recalculates all element positions and content height

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input for navigation and scrolling.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Handles UP/DOWN navigation - Manages selection state - Handles scrolling if enabled - Should be called every frame in update()

Example:

void update(unsigned long deltaTime) override {\n    UIVerticalLayout::update(deltaTime);\n\n    auto& input = engine.getInputManager();\n    menuLayout->handleInput(input);\n}\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout (handles smooth scrolling).

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Updates smooth scrolling animation - Updates child elements

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the layout and its visible elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

Notes: - Called automatically by Scene if isVisible is true - Only draws visible elements (viewport culling) - Draws elements in order

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setscrollenabledbool-enable","title":"void setScrollEnabled(bool enable)","text":"

Enables or disables scrolling.

Parameters: - enable (bool): true to enable scrolling

Returns: - void

Notes: - When disabled, scroll offset is reset to 0 - Scrolling is useful when content exceeds viewport height

Example:

menuLayout->setScrollEnabled(true);  // Enable scrolling\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-enablescrollbool-enable","title":"void enableScroll(bool enable)","text":"

Alias for setScrollEnabled().

Parameters: - enable (bool): true to enable scrolling

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setviewportheightfloat-h","title":"void setViewportHeight(float h)","text":"

Sets the viewport height (visible area).

Parameters: - h (float): Viewport height in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Use to adjust visible area

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#float-getscrolloffset-const","title":"float getScrollOffset() const","text":"

Gets the current scroll offset.

Returns: - float: Scroll offset in pixels

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setscrolloffsetfloat-offset","title":"void setScrollOffset(float offset)","text":"

Sets the scroll offset directly.

Parameters: - offset (float): Scroll offset in pixels

Returns: - void

Notes: - Offset is clamped to valid range automatically - Use for programmatic scrolling

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#float-getcontentheight-const","title":"float getContentHeight() const","text":"

Gets the total content height.

Returns: - float: Content height in pixels

Notes: - Includes all elements plus spacing and padding - Useful for scroll calculations

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#int-getselectedindex-const","title":"int getSelectedIndex() const","text":"

Gets the currently selected element index.

Returns: - int: Selected index, or -1 if none selected

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setselectedindexint-index","title":"void setSelectedIndex(int index)","text":"

Sets the selected element index.

Parameters: - index (int): Index to select (-1 to deselect)

Returns: - void

Notes: - Selected element is highlighted - Selection is scrolled into view if needed

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#uielement-getselectedelement-const","title":"UIElement* getSelectedElement() const","text":"

Gets the selected element.

Returns: - UIElement*: Pointer to selected element, or nullptr if none selected

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setscrollspeedfloat-speed","title":"void setScrollSpeed(float speed)","text":"

Sets the scroll speed for smooth scrolling.

Parameters: - speed (float): Pixels per millisecond

Returns: - void

Notes: - Default: 0.5 pixels per millisecond - Higher values = faster scrolling

Example:

menuLayout->setScrollSpeed(1.0f);  // Faster scrolling\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setnavigationbuttonsuint8_t-upbutton-uint8_t-downbutton","title":"void setNavigationButtons(uint8_t upButton, uint8_t downButton)","text":"

Sets the navigation button indices.

Parameters: - upButton (uint8_t): Button index for UP navigation - downButton (uint8_t): Button index for DOWN navigation

Returns: - void

Notes: - Default: UP = 0, DOWN = 1 - Change if your input mapping differs

Example:

menuLayout->setNavigationButtons(0, 1);  // UP=0, DOWN=1\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setbuttonstylecolor-selectedtextcol-color-selectedbgcol-color-unselectedtextcol-color-unselectedbgcol","title":"void setButtonStyle(Color selectedTextCol, Color selectedBgCol, Color unselectedTextCol, Color unselectedBgCol)","text":"

Sets the style colors for selected and unselected buttons.

Parameters: - selectedTextCol (Color): Text color when selected - selectedBgCol (Color): Background color when selected - unselectedTextCol (Color): Text color when not selected - unselectedBgCol (Color): Background color when not selected

Returns: - void

Example:

menuLayout->setButtonStyle(\n    Color::Yellow,  // Selected text\n    Color::Blue,    // Selected background\n    Color::White,   // Unselected text\n    Color::Black    // Unselected background\n);\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIVerticalLayout.h\"\n#include \"graphics/ui/UIButton.h\"\n\nclass MainMenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIVerticalLayout* menuLayout;\n\npublic:\n    void init() override {\n        // Create menu layout\n        menuLayout = new pixelroot32::graphics::ui::UIVerticalLayout(\n            20.0f, 20.0f,  // position\n            88.0f, 88.0f   // size\n        );\n        menuLayout->setScrollEnabled(true);\n        menuLayout->setSpacing(8.0f);\n        menuLayout->setPadding(4.0f);\n\n        // Create buttons\n        auto* startButton = new pixelroot32::graphics::ui::UIButton(\n            \"Start\",\n            0, 64.0f, 50.0f, 100.0f, 30.0f,\n            [this]() { engine.setScene(&gameScene); }\n        );\n\n        auto* quitButton = new pixelroot32::graphics::ui::UIButton(\n            \"Quit\",\n            1, 64.0f, 50.0f, 100.0f, 30.0f,\n            [this]() { engine.stop(); }\n        );\n\n        // Add buttons to layout\n        menuLayout->addElement(startButton);\n        menuLayout->addElement(quitButton);\n\n        // Add layout to scene\n        addEntity(menuLayout);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Layout handles input automatically\n        auto& input = engine.getInputManager();\n        menuLayout->handleInput(input);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n        Scene::draw(renderer);  // Draws layout and buttons\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#navigation","title":"Navigation","text":"

The layout handles D-pad navigation automatically:

  • UP button: Moves selection up
  • DOWN button: Moves selection down
  • Action button: Triggers selected button's callback
  • Scrolling: Automatically scrolls to keep selected element visible
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#performance-considerations","title":"Performance Considerations","text":"
  • Viewport culling: Only visible elements are drawn
  • Layout recalculation: Fast (simple positioning)
  • Scrolling: Smooth scrolling is efficient
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Element count: Stay within MAX_ENTITIES limit
  • Scrolling: Smooth scrolling uses minimal CPU
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class (abstract)
  • UIButton - Buttons for menus
  • Manual - User Interface
  • API Overview
"},{"location":"getting_started/fundamental_concepts/","title":"Fundamental Concepts","text":"

Before you start programming, it's important to understand the basic concepts that form PixelRoot32's architecture. This section explains how the engine works at a conceptual level, without going into code details.

"},{"location":"getting_started/fundamental_concepts/#engine-architecture","title":"Engine Architecture","text":""},{"location":"getting_started/fundamental_concepts/#engine-the-heart-of-the-engine","title":"Engine: The Heart of the Engine","text":"

The Engine is the main class that orchestrates the entire system. Think of it as the conductor that coordinates all subsystems:

  • Renderer: Handles drawing everything on screen
  • InputManager: Reads and processes user input (buttons, keyboard)
  • AudioEngine: Generates and plays sounds and music
  • SceneManager: Manages game scenes (menus, levels, etc.)

The Engine runs the main game loop: an infinite cycle that updates game logic and draws each frame on screen. It also calculates delta time (time elapsed between frames) so the game runs at the same speed regardless of framerate.

"},{"location":"getting_started/fundamental_concepts/#scene-organizing-your-game","title":"Scene: Organizing Your Game","text":"

A Scene represents a screen or level in your game. For example: - A scene for the main menu - A scene for each game level - A scene for the game over screen - A scene for the pause menu

Each scene contains and manages a set of entities (characters, enemies, objects, etc.). The scene is responsible for: - Initializing its entities when loaded - Updating the logic of all its entities each frame - Drawing all its visible entities each frame - Managing collisions between entities that can collide

The Engine can only have one active scene at a time, but you can easily switch between scenes (for example, go from menu to game, or from game to pause menu).

"},{"location":"getting_started/fundamental_concepts/#entity-the-fundamental-building-blocks","title":"Entity: The Fundamental Building Blocks","text":"

An Entity is any object in your game that has: - Position (x, y) in the world - Size (width and height) - Visibility (can be visible or not) - Active state (can be enabled or disabled) - Render layer (in what order it's drawn)

Entities are the foundation of everything in your game: the player, enemies, projectiles, objects, UI elements\u2014everything is an entity or inherits from Entity.

Each entity has two main methods: - update(): Called each frame to update the entity's logic (movement, animation, etc.) - draw(): Called each frame to draw the entity on screen

"},{"location":"getting_started/fundamental_concepts/#actor-entities-that-can-collide","title":"Actor: Entities That Can Collide","text":"

An Actor is a special entity that can participate in the collision system. In addition to everything an Entity has, an Actor has: - Collision layer: Which group it belongs to (e.g., \"player\", \"enemy\", \"projectile\") - Collision mask: Which other groups it can collide with - Hitbox: The shape used to detect collisions (usually a rectangle)

For example, a player might be on the \"player\" layer and have a mask that allows it to collide with \"enemies\" and \"obstacles\", but not with \"other players\".

When two actors collide, the system calls their onCollision() method so they can react (e.g., player loses health, enemy is destroyed, etc.).

"},{"location":"getting_started/fundamental_concepts/#physicsactor-entities-with-physics","title":"PhysicsActor: Entities with Physics","text":"

A PhysicsActor is an Actor that also has physical properties: - Velocity (vx, vy): Moves automatically according to its velocity - Gravity: Can fall automatically - Friction: Gradually loses velocity - Restitution: Bounces when it collides (like a ball)

The PhysicsActor updates automatically each frame, applying physics and moving the entity. It can also detect collisions with world boundaries (the walls of the play area).

"},{"location":"getting_started/fundamental_concepts/#entity-hierarchy","title":"Entity Hierarchy","text":"

The relationship between these classes is hierarchical:

Entity (base)\n  \u2514\u2500\u2500 Actor (can collide)\n       \u2514\u2500\u2500 PhysicsActor (has physics)\n

This means: - Every Actor is also an Entity - Every PhysicsActor is also an Actor and an Entity - You can use Entity for simple objects that don't need collisions - You can use Actor for objects that need to detect collisions - You can use PhysicsActor for objects that need automatic physics

"},{"location":"getting_started/fundamental_concepts/#rendering-system","title":"Rendering System","text":""},{"location":"getting_started/fundamental_concepts/#render-layers","title":"Render Layers","text":"

To control the order in which things are drawn, PixelRoot32 uses render layers:

  • Layer 0 (Background): Backgrounds, tilemaps, background elements
  • Layer 1 (Gameplay): Characters, enemies, projectiles, game objects
  • Layer 2 (UI): Menus, HUD, text, interface elements

Layers are drawn in order: first 0, then 1, and finally 2. This ensures the background is always behind, gameplay in the middle, and UI always visible in front.

Each entity has a renderLayer property that indicates which layer it should be drawn on. You can change this property to move entities between layers.

"},{"location":"getting_started/fundamental_concepts/#resolution-scaling","title":"Resolution Scaling","text":"

PixelRoot32 supports Independent Resolution Scaling. This means your game logic can run at a different resolution (the logical resolution) than the physical screen (physical resolution).

  • Logical Resolution: The resolution you program for (e.g., 128x128). All coordinates and sizes in your code refer to this space.
  • Physical Resolution: The actual number of pixels on your display (e.g., 240x240).

The engine automatically handles the scaling using an optimized hardware-accelerated process, allowing you to create low-resolution retro games that look crisp on modern high-resolution micro-displays.

"},{"location":"getting_started/fundamental_concepts/#rendering-pipeline","title":"Rendering Pipeline","text":"

The rendering process works like this:

  1. beginFrame(): The screen is cleared (painted black or background color)
  2. Draw entities: All visible entities are traversed, organized by layer
  3. endFrame(): The complete frame is sent to the display

The Renderer abstracts hardware details, so the same code works on both ESP32 (TFT_eSPI) and PC (SDL2).

"},{"location":"getting_started/fundamental_concepts/#coordinates-and-space","title":"Coordinates and Space","text":"

PixelRoot32 uses a standard coordinate system: - Origin (0, 0): Top-left corner - X-axis: Increases to the right - Y-axis: Increases downward

Coordinates are in pixels. If your display is 240x240, coordinates range from (0, 0) to (239, 239).

"},{"location":"getting_started/fundamental_concepts/#lifecycle","title":"Lifecycle","text":""},{"location":"getting_started/fundamental_concepts/#initialization","title":"Initialization","text":"

When your game starts:

  1. Configuration: Configuration objects are created (DisplayConfig, InputConfig, AudioConfig)
  2. Engine: The Engine is created with these configurations
  3. init(): engine.init() is called to initialize all subsystems
  4. Scene: The initial scene is created and configured
  5. setScene(): The scene is assigned to the Engine
"},{"location":"getting_started/fundamental_concepts/#game-loop","title":"Game Loop","text":"

Once initialized, the Engine enters the game loop:

While the game is running:\n  1. Calculate deltaTime (time since last frame)\n  2. Update InputManager (read buttons/keyboard)\n  3. Update AudioEngine (advance sounds and music)\n  4. Update current scene (update all entities)\n  5. Detect collisions in the scene\n  6. Draw the scene (draw all visible entities)\n  7. Repeat\n

This cycle runs continuously, typically at 30-60 FPS on ESP32, or faster on PC.

"},{"location":"getting_started/fundamental_concepts/#update","title":"Update","text":"

Each frame, all enabled entities receive a call to their update(deltaTime) method. This is where: - Entities move - Animations update - Game logic is processed - User input is read - Sound effects are played

The deltaTime is passed in milliseconds and represents how much time has passed since the last frame. This allows movement to be framerate-independent.

"},{"location":"getting_started/fundamental_concepts/#rendering-draw","title":"Rendering (Draw)","text":"

After updating, all visible entities receive a call to their draw(renderer) method. This is where: - Sprites are drawn - Text is drawn - Primitives are drawn (rectangles, circles, etc.)

The renderer is passed as a parameter so entities can draw themselves.

"},{"location":"getting_started/fundamental_concepts/#cleanup","title":"Cleanup","text":"

When you change scenes or end the game: - Entities from the previous scene can be cleaned up - Resources are freed - The new scene is initialized

"},{"location":"getting_started/fundamental_concepts/#conceptual-summary","title":"Conceptual Summary","text":"

To summarize, PixelRoot32 works like this:

  1. Engine coordinates everything and runs the game loop
  2. Scene organizes your game into screens/levels
  3. Entity is any object in your game
  4. Actor is an entity that can collide
  5. PhysicsActor is an actor with automatic physics
  6. Renderer draws everything on screen using layers
  7. Each frame updates logic and then draws

All of this works automatically once you configure the Engine and create your scenes and entities. You don't need to worry about game loop details; you just need to implement update() and draw() in your entities.

"},{"location":"getting_started/fundamental_concepts/#next-step","title":"Next Step","text":"

Now that you understand the fundamental concepts, you're ready to create your first project and see these concepts in action with real code.

See also: - What is PixelRoot32? - Why PixelRoot32? - Your First Project - Manual - Scenes and Entities

"},{"location":"getting_started/installation/","title":"Installation","text":"

This guide covers installing the PixelRoot32 documentation environment and preparing your development setup for ESP32 and Native (PC) targets.

"},{"location":"getting_started/installation/#requirements","title":"Requirements","text":"
  • Python 3.11 or newer
  • Git (recommended for source management)
  • VS Code (or your preferred IDE)
  • For ESP32 targets: PlatformIO (VS Code extension) with ESP32 toolchain
  • For Native targets: a C++ build toolchain (CMake or your OS-native toolchain)
"},{"location":"getting_started/installation/#install-documentation-tooling","title":"Install Documentation Tooling","text":"

To build and preview this documentation locally:

pip install mkdocs mkdocs-material mkdocs-minify-plugin mkdocs-git-revision-date-localized-plugin mike\nmkdocs serve\n

Open http://127.0.0.1:8000 in your browser to preview.

"},{"location":"getting_started/installation/#esp32-setup-recommended","title":"ESP32 Setup (Recommended)","text":"
  1. Install VS Code
  2. Install PlatformIO IDE extension
  3. Install ESP32 platform/toolchain via PlatformIO
  4. Clone the engine repository:
  5. https://github.com/Gperez88/PixelRoot32-Game-Engine
  6. Open the engine or example project in VS Code (PlatformIO)
  7. Build and upload to your ESP32 board

Tip: Use boards based on ESP32-WROOM/WROVER for best compatibility. Ensure a reliable USB cable and correct serial port selection.

"},{"location":"getting_started/installation/#native-pc-setup","title":"Native (PC) Setup","text":"
  1. Install a C++ toolchain (e.g., MSVC or MinGW on Windows)
  2. Install CMake (if the engine provides CMake build files)
  3. Clone the engine repository:
  4. https://github.com/Gperez88/PixelRoot32-Game-Engine
  5. Configure and build the native runtime:
  6. Follow the engine\u2019s native build instructions (Development \u2192 Compiling)
"},{"location":"getting_started/installation/#verify-your-environment","title":"Verify Your Environment","text":"
  • ESP32: Build and flash a minimal sample; confirm serial output and display if applicable
  • Native: Run the executable; confirm window output and input handling
"},{"location":"getting_started/installation/#troubleshooting","title":"Troubleshooting","text":"
  • If PlatformIO cannot find the ESP32 platform, update PlatformIO and retry
  • If native builds fail, verify compiler versions and CMake generator settings
  • Use Community \u2192 Troubleshooting for common issues and fixes
"},{"location":"getting_started/installation/#next-steps","title":"Next Steps","text":"
  • First Project
  • Concepts
"},{"location":"getting_started/what_is_pixelroot32/","title":"What is PixelRoot32?","text":"

PixelRoot32 is a lightweight, modular 2D game engine written in C++ designed specifically for ESP32 microcontrollers, with a native simulation layer for PC (SDL2) that allows you to develop and debug quickly on your desktop before deploying to hardware.

"},{"location":"getting_started/what_is_pixelroot32/#simple-definition","title":"Simple Definition","text":"

PixelRoot32 is a game engine that lets you create retro-style 8-bit/16-bit video games directly on an ESP32 board, with the ability to develop and test on your PC before transferring code to hardware.

"},{"location":"getting_started/what_is_pixelroot32/#key-features","title":"Key Features","text":""},{"location":"getting_started/what_is_pixelroot32/#scene-based-architecture","title":"\ud83c\udfae Scene-Based Architecture","text":"
  • Scene system inspired by Godot Engine
  • Intuitive management of levels, menus, and screens
  • Simple transitions between scenes
"},{"location":"getting_started/what_is_pixelroot32/#optimized-rendering","title":"\ud83c\udfa8 Optimized Rendering","text":"
  • 1bpp (monochrome) sprites as the standard format
  • Support for multi-layer sprites (MultiSprite)
  • Experimental 2bpp and 4bpp formats for higher fidelity
  • Retro color palette system (NES, GameBoy, PICO-8, etc.)
  • Compact tilemaps for backgrounds and levels
  • 2D camera with dead-zone for smooth scrolling
  • Render layer system (background, gameplay, UI)
"},{"location":"getting_started/what_is_pixelroot32/#nes-like-audio","title":"\ud83d\udd0a NES-like Audio","text":"
  • 4 audio channels (2 Pulse, 1 Triangle, 1 Noise)
  • Integrated sound effects system
  • Music player for background melodies
  • Backends for ESP32 (internal DAC or external I2S) and SDL2
"},{"location":"getting_started/what_is_pixelroot32/#physics-and-collisions","title":"\ud83c\udfaf Physics and Collisions","text":"
  • AABB (Axis-Aligned Bounding Box) collision system
  • PhysicsActor with gravity, friction, and restitution
  • Collision layers and masks for fine control
  • World boundary collision detection
"},{"location":"getting_started/what_is_pixelroot32/#user-interface","title":"\ud83d\udda5\ufe0f User Interface","text":"
  • Basic elements: Labels, Buttons, Panels
  • Automatic layouts: Vertical, Horizontal, Grid, Anchor
  • Integrated D-pad navigation
  • Scroll and viewport culling for long lists
"},{"location":"getting_started/what_is_pixelroot32/#optimized-for-esp32","title":"\u26a1 Optimized for ESP32","text":"
  • Efficient memory management
  • Integrated object pooling
  • No dynamic allocations in the game loop
  • Performance optimized for limited hardware
"},{"location":"getting_started/what_is_pixelroot32/#typical-use-cases","title":"Typical Use Cases","text":"

PixelRoot32 is ideal for creating:

  • Arcade Games: Space Invaders, Pong, Breakout
  • Platformers: Horizontal scrolling games with simple physics
  • Puzzles: Tetris, Snake, logic games
  • Simple RPGs: Basic role-playing games with tilemaps
  • Shooters: Vertical or horizontal shooting games
  • Rapid Prototypes: Quick development of game ideas
"},{"location":"getting_started/what_is_pixelroot32/#supported-platforms","title":"Supported Platforms","text":""},{"location":"getting_started/what_is_pixelroot32/#esp32","title":"ESP32","text":"
  • Display: TFT_eSPI (ST7735, ILI9341, ST7789, etc.)
  • Audio: Internal DAC (GPIO 25/26) or external I2S (MAX98357A, PCM5102)
  • Input: Digital buttons, D-pad
  • Hardware: Any ESP32 board (ESP32-WROOM, ESP32-WROVER, etc.)
"},{"location":"getting_started/what_is_pixelroot32/#desktopnative-pc","title":"Desktop/Native (PC)","text":"
  • Display: SDL2 (Windows, Linux, macOS)
  • Audio: SDL2 Audio
  • Input: Keyboard, mouse
  • Usage: Development, debugging, testing

Note: Support for u8g2 (OLEDs) is planned for the future.

"},{"location":"getting_started/what_is_pixelroot32/#project-status","title":"Project Status","text":"

Current Version: v0.2.0-dev

PixelRoot32 is under active development. APIs may change and some subsystems are still experimental. Occasional changes or breaking changes are expected, especially on less-tested configurations.

"},{"location":"getting_started/what_is_pixelroot32/#stable-features","title":"Stable Features","text":"
  • Scene and entity system
  • Basic rendering (1bpp sprites)
  • NES-like audio system
  • Basic physics and collisions
  • Basic UI system
  • ESP32 and Native support
"},{"location":"getting_started/what_is_pixelroot32/#experimental-features","title":"Experimental Features","text":"
  • 2bpp and 4bpp sprites (require compilation flags)
  • Scene Arena (advanced memory management)
"},{"location":"getting_started/what_is_pixelroot32/#planned-features","title":"Planned Features","text":"
  • Support for u8g2 (OLEDs)
  • Music compiler
  • Tilemap compiler
  • Save/load system
  • Spatial partitioning for collisions
"},{"location":"getting_started/what_is_pixelroot32/#quick-comparison","title":"Quick Comparison","text":""},{"location":"getting_started/what_is_pixelroot32/#when-to-use-pixelroot32","title":"When to use PixelRoot32?","text":"

\u2705 Use PixelRoot32 if: - You want to create retro games on ESP32 - You need a lightweight and efficient engine - You prefer a simple and clear architecture - You want to develop on PC and deploy to ESP32 - You like 8-bit/16-bit style games

\u274c Don't use PixelRoot32 if: - You need 3D graphics - You require advanced shaders - You need complex physics (advanced physics engines) - You want to create modern AAA games - You need support for multiple mobile platforms

"},{"location":"getting_started/what_is_pixelroot32/#next-step","title":"Next Step","text":"

Now that you understand what PixelRoot32 is, discover why you should use it or go directly to your first project.

See also: - Fundamental Concepts - Installation - API Reference

"},{"location":"getting_started/why_pixelroot32/","title":"Why PixelRoot32?","text":"

PixelRoot32 is specifically designed to solve the unique challenges of creating video games on embedded hardware like the ESP32, while maintaining the simplicity and productivity of modern development.

"},{"location":"getting_started/why_pixelroot32/#main-advantages","title":"Main Advantages","text":""},{"location":"getting_started/why_pixelroot32/#optimized-for-esp32","title":"\ud83c\udfaf Optimized for ESP32","text":"

Memory Efficient - 1bpp sprite system that minimizes RAM and Flash usage - Integrated object pooling to avoid memory fragmentation - Compact tilemaps that reuse sprites - No dynamic allocations in the game loop

Performance Optimized - Rendering optimized for ESP32 limitations - Efficient render layer system - Viewport culling to reduce draw calls - Rendering pipeline designed for limited hardware

Real Hardware - Direct support for common TFT displays (ST7735, ILI9341, ST7789) - Integrated audio (internal DAC or external I2S) - Simple pin and hardware configuration

"},{"location":"getting_started/why_pixelroot32/#cross-platform-development","title":"\ud83d\udda5\ufe0f Cross-Platform Development","text":"

Develop on PC, Deploy to ESP32 - Same code works on PC (SDL2) and ESP32 - Fast debugging on desktop - Testing without hardware needed - Rapid development iteration

Visual Consistency - Native bitmap font system (pixel-perfect) - Same rendering on PC and ESP32 - Consistent color palettes - No surprises when transferring to hardware

"},{"location":"getting_started/why_pixelroot32/#retro-palette-system","title":"\ud83c\udfa8 Retro Palette System","text":"

Authentic Style - Predefined palettes: NES, GameBoy, GameBoy Color, PICO-8 - Dual palette mode for visual contrasts - Custom palettes for unique styles - Automatic color resolution (RGB565)

Easy to Use - Change palette with one line of code - Consistent visualization across all sprites - No need to manually convert assets

"},{"location":"getting_started/why_pixelroot32/#integrated-audio","title":"\ud83d\udd0a Integrated Audio","text":"

Complete NES-like System - 4 audio channels (2 Pulse, 1 Triangle, 1 Noise) - Simple sound effects to create - Integrated music system - Backends for different hardware configurations

No External Dependencies - Software-generated audio - No heavy audio libraries required - Full control over sound - Deterministic and predictable

"},{"location":"getting_started/why_pixelroot32/#simple-and-clear-architecture","title":"\ud83c\udfd7\ufe0f Simple and Clear Architecture","text":"

Easy to Understand - Intuitive scene system (inspired by Godot) - Clear hierarchy: Entity \u2192 Actor \u2192 PhysicsActor - Consistent and predictable APIs - Clean and well-organized code

Quick to Learn - Familiar concepts for game developers - Clear documentation and complete examples - Smooth learning curve - Active community and support

"},{"location":"getting_started/why_pixelroot32/#complete-features","title":"\ud83c\udfae Complete Features","text":"

Everything Needed for Games - Rendering (sprites, tilemaps, primitives) - Audio (effects and music) - Physics (gravity, collisions, basic physics) - UI (layouts, buttons, navigation) - Input (buttons, keyboard) - Camera (scroll, parallax)

No Bloat - Only the essentials, nothing more - No heavy dependencies - Small and maintainable codebase - Easy to understand and modify

"},{"location":"getting_started/why_pixelroot32/#tools-and-ecosystem","title":"\ud83d\udee0\ufe0f Tools and Ecosystem","text":"

Available Tools - Sprite Compiler to convert PNG to sprites - Complete game examples - Templates and starter code - Extensive documentation

Community and Support - Active and developing project - Open source (MIT License) - Feedback and contributions welcome - Examples available

"},{"location":"getting_started/why_pixelroot32/#comparison-with-alternatives","title":"Comparison with Alternatives","text":""},{"location":"getting_started/why_pixelroot32/#vs-full-engines-unity-godot-etc","title":"vs. Full Engines (Unity, Godot, etc.)","text":"

PixelRoot32 Advantages: - \u2705 Much lighter (fits in ESP32) - \u2705 No unnecessary overhead - \u2705 Full control over code - \u2705 Specifically optimized for limited hardware

Disadvantages: - \u274c Fewer advanced features - \u274c No visual editor - \u274c Fewer resources and community

"},{"location":"getting_started/why_pixelroot32/#vs-writing-everything-from-scratch","title":"vs. Writing Everything from Scratch","text":"

PixelRoot32 Advantages: - \u2705 Rendering system already implemented - \u2705 Integrated and working audio - \u2705 Physics and collisions ready - \u2705 Complete UI system - \u2705 Saves months of development

Disadvantages: - \u274c Less control over internal implementation - \u274c You must learn the engine API

"},{"location":"getting_started/why_pixelroot32/#vs-other-esp32-engines","title":"vs. Other ESP32 Engines","text":"

PixelRoot32 Advantages: - \u2705 More modern and clear architecture - \u2705 Better documentation - \u2705 Unique palette system - \u2705 Integrated NES-like audio - \u2705 Real cross-platform development

"},{"location":"getting_started/why_pixelroot32/#ideal-use-cases","title":"Ideal Use Cases","text":"

PixelRoot32 is perfect for:

  1. Educational Projects
  2. Learn game development
  3. Understand engine architecture
  4. Student projects

  5. Rapid Prototypes

  6. Quickly validate game ideas
  7. Create demos and proof-of-concepts
  8. Test mechanics

  9. Retro Games

  10. 8-bit/16-bit style games
  11. Arcade games
  12. Games with retro aesthetics

  13. Hardware Projects

  14. Games on small displays
  15. DIY portable consoles
  16. Maker/retro projects

  17. C++ Learning

  18. Clean and well-structured code
  19. Good programming practices
  20. Real and functional examples
"},{"location":"getting_started/why_pixelroot32/#limitations-to-consider","title":"Limitations to Consider","text":"

To be honest, PixelRoot32 has limitations:

  • Limited Hardware: Designed for ESP32, not powerful PCs
  • Simple Graphics: No 3D, no advanced shaders
  • Basic Physics: Not a complete physics engine
  • Restricted Memory: MAX_ENTITIES = 32 per scene
  • In Development: Some features are experimental

If you need advanced features or powerful hardware, consider other engines. But for retro games on ESP32, PixelRoot32 is an excellent choice.

"},{"location":"getting_started/why_pixelroot32/#conclusion","title":"Conclusion","text":"

PixelRoot32 combines:

  • \u2705 Simplicity of use
  • \u2705 Efficiency for limited hardware
  • \u2705 Completeness of essential features
  • \u2705 Clarity of architecture
  • \u2705 Productivity in development

If you want to create retro games on ESP32 without the complexity of large engines, PixelRoot32 is the right choice.

"},{"location":"getting_started/why_pixelroot32/#next-step","title":"Next Step","text":"

Now that you understand why PixelRoot32 is a good option, learn the fundamental concepts or start directly with your first project.

See also: - What is PixelRoot32? - Fundamental Concepts - Your First Project

"},{"location":"getting_started/your_first_project/","title":"Your First Project","text":"

This guide will walk you through creating and running your first PixelRoot32 project step by step. By the end, you'll have a working project that displays a simple scene on both ESP32 and PC.

"},{"location":"getting_started/your_first_project/#prerequisites","title":"Prerequisites","text":""},{"location":"getting_started/your_first_project/#required-software","title":"Required Software","text":"
  • PlatformIO: Install the PlatformIO IDE extension in VS Code
  • Open VS Code
  • Go to Extensions (Ctrl+Shift+X)
  • Search for \"PlatformIO IDE\"
  • Install and restart VS Code

  • Python 3.8+: Required for PlatformIO (usually installed automatically)

"},{"location":"getting_started/your_first_project/#for-esp32-development","title":"For ESP32 Development","text":"
  • ESP32 Board: Any ESP32 development board (ESP32-WROOM, ESP32-WROVER, etc.)
  • USB Cable: To connect and program your ESP32
  • TFT Display: Compatible display (ST7735, ST7789, ILI9341, etc.)
  • Buttons: 5-6 digital buttons for input (optional for first project)
  • Audio Hardware (optional): Speaker + amplifier (PAM8302A) or I2S DAC (MAX98357A)
"},{"location":"getting_started/your_first_project/#for-native-pc-development","title":"For Native (PC) Development","text":"
  • SDL2: Development libraries
  • Windows (MSYS2): pacman -S mingw-w64-x86_64-SDL2
  • Linux: sudo apt-get install libsdl2-dev
  • macOS: brew install sdl2
"},{"location":"getting_started/your_first_project/#step-1-create-a-new-platformio-project","title":"Step 1: Create a New PlatformIO Project","text":"
  1. Open VS Code with PlatformIO installed

  2. Create New Project:

  3. Click on the PlatformIO icon in the sidebar
  4. Click \"New Project\"
  5. Name: my-first-pixelroot32-game
  6. Board: Select \"ESP32 Dev Module\" (or your specific board)
  7. Framework: Arduino
  8. Location: Choose your workspace folder
  9. Click \"Finish\"

  10. Project Structure: Your project should now have this structure:

    my-first-pixelroot32-game/\n\u251c\u2500\u2500 .pio/\n\u251c\u2500\u2500 include/\n\u251c\u2500\u2500 lib/\n\u251c\u2500\u2500 src/\n\u2502   \u2514\u2500\u2500 main.cpp\n\u251c\u2500\u2500 test/\n\u2514\u2500\u2500 platformio.ini\n

"},{"location":"getting_started/your_first_project/#step-2-install-pixelroot32-engine","title":"Step 2: Install PixelRoot32 Engine","text":""},{"location":"getting_started/your_first_project/#option-a-via-platformio-library-manager-recommended","title":"Option A: Via PlatformIO Library Manager (Recommended)","text":"
  1. Open platformio.ini

  2. Add the library dependency:

[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = arduino\nlib_deps = \n    gperez88/PixelRoot32-Game-Engine@0.2.0-dev\n

\u26a0\ufe0f IMPORTANT: Use the exact version 0.2.0-dev. Do NOT use ^ or fuzzy versioning.

  1. Save the file. PlatformIO will automatically download the library.
"},{"location":"getting_started/your_first_project/#option-b-git-submodule","title":"Option B: Git Submodule","text":"
  1. Open terminal in your project root

  2. Add as submodule:

    git submodule add https://github.com/Gperez88/PixelRoot32-Game-Engine.git lib/PixelRoot32-Game-Engine\n

  3. Update platformio.ini:

    lib_extra_dirs = lib\n

"},{"location":"getting_started/your_first_project/#step-3-configure-hardware-esp32","title":"Step 3: Configure Hardware (ESP32)","text":""},{"location":"getting_started/your_first_project/#configure-tft_espi-display","title":"Configure TFT_eSPI Display","text":"

Edit platformio.ini and add build flags for your display. Here are two common configurations:

For ST7789 (240x240):

[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = arduino\nlib_deps = \n    gperez88/PixelRoot32-Game-Engine@0.2.0-dev\n    bodmer/TFT_eSPI@^2.5.43\n\nbuild_flags = \n    -D ST7789_DRIVER\n    -D TFT_WIDTH=240\n    -D TFT_HEIGHT=240\n    -D TFT_MOSI=23\n    -D TFT_SCLK=18\n    -D TFT_DC=2\n    -D TFT_RST=4\n    -D TFT_CS=-1\n    -D LOAD_GLCD\n    -D LOAD_FONT2\n    -D LOAD_FONT4\n    -D LOAD_FONT6\n    -D LOAD_FONT7\n    -D LOAD_FONT8\n    -D LOAD_GFXFF\n    -D SMOOTH_FONT\n    -D SPI_FREQUENCY=40000000\n    -D SPI_READ_FREQUENCY=20000000\n

For ST7735 (128x128):

build_flags = \n    -D ST7735_DRIVER\n    -D ST7735_GREENTAB3\n    -D TFT_WIDTH=128\n    -D TFT_HEIGHT=128\n    -D TFT_MOSI=23\n    -D TFT_SCLK=18\n    -D TFT_DC=2\n    -D TFT_RST=4\n    -D TFT_CS=-1\n    -D LOAD_GLCD\n    -D LOAD_FONT2\n    -D LOAD_FONT4\n    -D LOAD_FONT6\n    -D LOAD_FONT7\n    -D LOAD_FONT8\n    -D LOAD_GFXFF\n    -D SMOOTH_FONT\n    -D SPI_FREQUENCY=27000000\n    -D SPI_READ_FREQUENCY=20000000\n

Note: Adjust the pin numbers (TFT_MOSI, TFT_SCLK, TFT_DC, TFT_RST) to match your hardware wiring.

"},{"location":"getting_started/your_first_project/#configure-input-optional-for-first-project","title":"Configure Input (Optional for First Project)","text":"

If you have buttons connected, note the GPIO pins. For now, we'll create a project that works without input.

"},{"location":"getting_started/your_first_project/#configure-audio-optional-for-first-project","title":"Configure Audio (Optional for First Project)","text":"

Audio is optional for the first project. We'll add it later.

"},{"location":"getting_started/your_first_project/#step-4-create-your-first-scene","title":"Step 4: Create Your First Scene","text":"

Create a new file src/MyFirstScene.h:

#pragma once\n#include <core/Scene.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass MyFirstScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Called when the scene is initialized\n        // Set up your scene here\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Called every frame\n        // Update game logic here\n        Scene::update(deltaTime); // Don't forget to call parent update!\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Called every frame to draw\n        // Draw your scene here\n\n        // Example: Draw a simple rectangle\n        renderer.drawFilledRectangle(50, 50, 100, 100, pixelroot32::graphics::Color::Blue);\n\n        // Example: Draw text\n        renderer.drawText(\"Hello PixelRoot32!\", 20, 20, pixelroot32::graphics::Color::White, 2);\n\n        // Don't forget to call parent draw to draw all entities!\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"getting_started/your_first_project/#step-5-create-main-file-esp32","title":"Step 5: Create Main File (ESP32)","text":"

Replace the contents of src/main.cpp with:

#include <Arduino.h>\n#include <core/Engine.h>\n#include <drivers/esp32/TFT_eSPI_Drawer.h>\n#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n#include \"MyFirstScene.h\"\n\nnamespace pr32 = pixelroot32;\n\n// Audio configuration (optional - can be omitted for first project)\nconst int DAC_PIN = 25; // GPIO 25 or 26\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\n// Display configuration\n// 128x128 game logic scaled to 240x240 display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::ST7789, \n    0,      // rotation\n    240, 240, // physical resolution (hardware)\n    128, 128  // logical resolution (rendering space)\n);\n\n// Input configuration (6 buttons: UP, DOWN, LEFT, RIGHT, A, B)\n// For now, we'll use dummy pins - you can change these later\npr32::input::InputConfig inputConfig(\n    6,      // button count\n    32,     // UP pin\n    27,     // DOWN pin\n    33,     // LEFT pin\n    14,     // RIGHT pin\n    13,     // A button pin\n    12      // B button pin\n);\n\n// Audio configuration\npr32::audio::AudioConfig audioConfig(&audioBackend, audioBackend.getSampleRate());\n\n// Create the engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\n// Create your scene\nMyFirstScene myScene;\n\nvoid setup() {\n    Serial.begin(115200);\n\n    // Initialize the engine\n    engine.init();\n\n    // Initialize and set the scene\n    myScene.init();\n    engine.setScene(&myScene);\n\n    Serial.println(\"PixelRoot32 initialized!\");\n}\n\nvoid loop() {\n    // Run the game loop\n    engine.run();\n}\n
"},{"location":"getting_started/your_first_project/#step-6-create-native-version-optional","title":"Step 6: Create Native Version (Optional)","text":"

If you want to test on PC first, create src/main_native.cpp:

#define SDL_MAIN_HANDLED\n#include <SDL2/SDL.h>\n#include <core/Engine.h>\n#include <drivers/native/SDL2_Drawer.h>\n#include <drivers/native/SDL2_AudioBackend.h>\n#include \"MyFirstScene.h\"\n\nnamespace pr32 = pixelroot32;\n\n// Audio configuration\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\n\n// Display configuration (NONE defaults to SDL2 on Native)\n// 128x128 game logic scaled to 240x240 display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::NONE,\n    0,      // rotation\n    240, 240, // physical resolution\n    128, 128  // logical resolution\n);\n\n// Input configuration (SDL scancodes)\npr32::input::InputConfig inputConfig(\n    6,                      // button count\n    SDL_SCANCODE_UP,        // UP\n    SDL_SCANCODE_DOWN,      // DOWN\n    SDL_SCANCODE_LEFT,      // LEFT\n    SDL_SCANCODE_RIGHT,     // RIGHT\n    SDL_SCANCODE_SPACE,     // A button\n    SDL_SCANCODE_RETURN     // B button\n);\n\n// Audio configuration\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n\n// Create the engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\n// Create your scene\nMyFirstScene myScene;\n\nint main(int argc, char* argv[]) {\n    (void)argc;\n    (void)argv;\n\n    // Initialize the engine\n    engine.init();\n\n    // Initialize and set the scene\n    myScene.init();\n    engine.setScene(&myScene);\n\n    // Run the game loop\n    engine.run();\n\n    return 0;\n}\n
"},{"location":"getting_started/your_first_project/#configure-native-build","title":"Configure Native Build","text":"

Add to platformio.ini:

[env:native]\nplatform = native\nbuild_src_filter = \n    +<*>\n    -<main.cpp>\nlib_extra_dirs = lib\nbuild_flags = \n    -D PLATFORM_NATIVE\n    -Isrc\n    -Ilib/PixelRoot32-Game-Engine/include\n    -IC:/msys64/mingw64/include/SDL2    # Windows MSYS2 path - adjust for your system\n    -LC:/msys64/mingw64/lib             # Windows MSYS2 path - adjust for your system\n    -O2\n    -Wall\n    -Wextra\n    -std=c++17\n    -lSDL2\n    -mconsole\n

Note: Adjust the SDL2 include and library paths for your system.

"},{"location":"getting_started/your_first_project/#step-7-build-and-run","title":"Step 7: Build and Run","text":""},{"location":"getting_started/your_first_project/#for-esp32","title":"For ESP32","text":"
  1. Connect your ESP32 via USB
  2. Select the environment: Click on the PlatformIO icon \u2192 Select env:esp32dev
  3. Build: Click the checkmark icon (\u2713) or press Ctrl+Alt+B
  4. Upload: Click the arrow icon (\u2192) or press Ctrl+Alt+U
  5. Monitor: Click the plug icon to open serial monitor

You should see \"PixelRoot32 initialized!\" in the serial monitor and your display should show a blue rectangle and text.

"},{"location":"getting_started/your_first_project/#for-native-pc","title":"For Native (PC)","text":"
  1. Select the environment: Click on the PlatformIO icon \u2192 Select env:native
  2. Build and Run: Click the play icon (\u25b6) or press Ctrl+Alt+R

A window should open showing your scene with a blue rectangle and \"Hello PixelRoot32!\" text.

"},{"location":"getting_started/your_first_project/#step-8-verify-it-works","title":"Step 8: Verify It Works","text":"

If everything is set up correctly, you should see:

  • ESP32: Display shows a blue rectangle at (50, 50) and white text \"Hello PixelRoot32!\" at (20, 20)
  • Native: Window shows the same content

If you see this, congratulations! Your first PixelRoot32 project is working.

"},{"location":"getting_started/your_first_project/#troubleshooting","title":"Troubleshooting","text":""},{"location":"getting_started/your_first_project/#esp32-issues","title":"ESP32 Issues","text":"

Display is blank: - Check wiring connections - Verify pin numbers in platformio.ini match your hardware - Check SPI frequency (try lowering it) - Verify display type (ST7789 vs ST7735)

Compilation errors: - Ensure library version is exactly 0.2.0-dev - Check that TFT_eSPI is installed - Verify all include paths are correct

Upload fails: - Check USB cable connection - Try different USB port - Press BOOT button on ESP32 during upload - Check COM port in PlatformIO

"},{"location":"getting_started/your_first_project/#native-issues","title":"Native Issues","text":"

SDL2 not found: - Verify SDL2 is installed - Check include/library paths in platformio.ini - On Windows, ensure MSYS2 paths are correct

Window doesn't open: - Check console for error messages - Verify SDL2 is properly linked - Try running from terminal to see errors

"},{"location":"getting_started/your_first_project/#next-steps","title":"Next Steps","text":"

Now that you have a working project, you can:

  1. Learn about Scenes and Entities: See how to create game objects
  2. Add Input: Make your scene respond to buttons
  3. Add Sprites: Draw custom graphics
  4. Add Audio: Play sounds and music

Continue with the Development Guide to learn more.

See also: - Fundamental Concepts - Installation - Manual - Scenes and Entities - API Reference

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/","title":"Cameras and Scrolling","text":"

Camera2D allows you to create worlds larger than the screen by scrolling the view. This guide covers camera setup, following targets, boundaries, and parallax effects.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera2d-basics","title":"Camera2D Basics","text":"

A Camera2D defines what portion of your game world is visible on screen.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#creating-a-camera","title":"Creating a Camera","text":"
#include <graphics/Camera2D.h>\n\n// Create camera with viewport size\npixelroot32::graphics::Camera2D camera(240, 240); // Screen width, height\n\n// Set camera position\ncamera.setPosition(0, 0);\n\n// Apply camera to renderer (in draw method)\ncamera.apply(renderer);\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#how-it-works","title":"How It Works","text":"

The camera translates world coordinates to screen coordinates: - Objects at world position (100, 50) with camera at (0, 0) appear at screen (100, 50) - Objects at world position (100, 50) with camera at (50, 0) appear at screen (50, 50) - The camera effectively \"moves\" the world relative to the screen

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#following-a-target","title":"Following a Target","text":"

The most common use is following a player or other target.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#basic-follow","title":"Basic Follow","text":"
class GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        // Create camera\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n\n        // Create player\n        player = new PlayerActor(500, 300); // World position\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Make camera follow player\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera before drawing\n        camera.apply(renderer);\n\n        // Now all drawing uses camera coordinates\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#dead-zone-smooth-following","title":"Dead Zone (Smooth Following)","text":"

For smoother following, you can implement a dead zone where the camera doesn't move until the target leaves the zone:

void update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);\n\n    // Get screen center\n    int screenCenterX = engine.getRenderer().getWidth() / 2;\n    int screenCenterY = engine.getRenderer().getHeight() / 2;\n\n    // Calculate player position relative to screen center\n    float playerScreenX = player->x - camera.getX();\n    float playerScreenY = player->y - camera.getY();\n\n    // Dead zone size\n    const int DEAD_ZONE_X = 40;\n    const int DEAD_ZONE_Y = 40;\n\n    // Move camera if player leaves dead zone\n    if (playerScreenX < screenCenterX - DEAD_ZONE_X) {\n        camera.setPosition(player->x - (screenCenterX - DEAD_ZONE_X), camera.getY());\n    } else if (playerScreenX > screenCenterX + DEAD_ZONE_X) {\n        camera.setPosition(player->x - (screenCenterX + DEAD_ZONE_X), camera.getY());\n    }\n\n    if (playerScreenY < screenCenterY - DEAD_ZONE_Y) {\n        camera.setPosition(camera.getX(), player->y - (screenCenterY - DEAD_ZONE_Y));\n    } else if (playerScreenY > screenCenterY + DEAD_ZONE_Y) {\n        camera.setPosition(camera.getX(), player->y - (screenCenterY + DEAD_ZONE_Y));\n    }\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-boundaries","title":"Camera Boundaries","text":"

Limit camera movement to keep it within your level bounds.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#setting-boundaries","title":"Setting Boundaries","text":"
void init() override {\n    // Create camera\n    camera = pixelroot32::graphics::Camera2D(240, 240);\n\n    // Set horizontal boundaries (level is 2000 pixels wide)\n    camera.setBounds(0, 2000 - 240); // minX, maxX\n\n    // Set vertical boundaries (level is 1000 pixels tall)\n    camera.setVerticalBounds(0, 1000 - 240); // minY, maxY\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#example-side-scroller-with-boundaries","title":"Example: Side-Scroller with Boundaries","text":"
class SideScrollerScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n    static const int LEVEL_WIDTH = 2000;\n    static const int LEVEL_HEIGHT = 240;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n\n        // Set boundaries (camera can't go outside level)\n        camera.setBounds(0, LEVEL_WIDTH - screenWidth);\n        camera.setVerticalBounds(0, LEVEL_HEIGHT - screenHeight);\n\n        // Create player at start\n        player = new PlayerActor(100, 100);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Follow player horizontally\n        camera.followTarget(player->x, camera.getY());\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#parallax-scrolling","title":"Parallax Scrolling","text":"

Parallax creates depth by moving background layers at different speeds.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#basic-parallax","title":"Basic Parallax","text":"
class ParallaxBackground : public pixelroot32::core::Entity {\nprivate:\n    float parallaxSpeed; // 0.0 to 1.0 (1.0 = normal, 0.5 = half speed)\n    float baseX;\n\npublic:\n    ParallaxBackground(float speed)\n        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::GENERIC),\n          parallaxSpeed(speed), baseX(0) {\n        setRenderLayer(0);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Get camera position\n        auto& camera = getCamera(); // You'll need to pass camera reference\n\n        // Calculate parallax offset\n        baseX = camera.getX() * parallaxSpeed;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background with parallax offset\n        renderer.drawTileMap(backgroundTileMap, \n            static_cast<int>(baseX), 0, \n            pixelroot32::graphics::Color::White);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#multiple-parallax-layers","title":"Multiple Parallax Layers","text":"
class ParallaxScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n\n    // Parallax layers (farther = slower)\n    ParallaxLayer* farBackground;    // Speed: 0.2\n    ParallaxLayer* midBackground;      // Speed: 0.5\n    ParallaxLayer* nearBackground;     // Speed: 0.8\n    PlayerActor* player;               // Speed: 1.0 (normal)\n\npublic:\n    void init() override {\n        camera = pixelroot32::graphics::Camera2D(240, 240);\n\n        // Create parallax layers\n        farBackground = new ParallaxLayer(0.2f);  // Moves slowest\n        midBackground = new ParallaxLayer(0.5f);\n        nearBackground = new ParallaxLayer(0.8f);\n\n        addEntity(farBackground);\n        addEntity(midBackground);\n        addEntity(nearBackground);\n\n        player = new PlayerActor(100, 100);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Update parallax layers with camera position\n        farBackground->updateParallax(camera.getX());\n        midBackground->updateParallax(camera.getX());\n        nearBackground->updateParallax(camera.getX());\n\n        // Follow player\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#using-setdisplayoffset-for-parallax","title":"Using setDisplayOffset for Parallax","text":"

For simpler parallax, you can use setDisplayOffset():

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera\n    camera.apply(renderer);\n\n    // Draw far background with offset (moves slower)\n    renderer.setDisplayOffset(\n        static_cast<int>(camera.getX() * 0.3f), \n        0\n    );\n    renderer.drawTileMap(farBackground, 0, 0, Color::White);\n\n    // Draw mid background\n    renderer.setDisplayOffset(\n        static_cast<int>(camera.getX() * 0.6f), \n        0\n    );\n    renderer.drawTileMap(midBackground, 0, 0, Color::White);\n\n    // Reset offset for normal drawing\n    renderer.setDisplayOffset(0, 0);\n\n    // Draw game objects (normal speed)\n    Scene::draw(renderer);\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#complete-example-platformer-with-camera","title":"Complete Example: Platformer with Camera","text":"
class PlatformerScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n    static const int LEVEL_WIDTH = 3000;\n    static const int LEVEL_HEIGHT = 800;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        // Create camera\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n\n        // Set boundaries\n        camera.setBounds(0, LEVEL_WIDTH - screenWidth);\n        camera.setVerticalBounds(0, LEVEL_HEIGHT - screenHeight);\n\n        // Create player\n        player = new PlayerActor(100, 400);\n        addEntity(player);\n\n        // Create platforms, enemies, etc.\n        // ...\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Follow player with dead zone\n        int screenCenterX = engine.getRenderer().getWidth() / 2;\n        int screenCenterY = engine.getRenderer().getHeight() / 2;\n\n        float playerScreenX = player->x - camera.getX();\n        float playerScreenY = player->y - camera.getY();\n\n        const int DEAD_ZONE = 60;\n\n        // Horizontal follow\n        if (playerScreenX < screenCenterX - DEAD_ZONE) {\n            camera.setPosition(player->x - (screenCenterX - DEAD_ZONE), camera.getY());\n        } else if (playerScreenX > screenCenterX + DEAD_ZONE) {\n            camera.setPosition(player->x - (screenCenterX + DEAD_ZONE), camera.getY());\n        }\n\n        // Vertical follow (only when falling or jumping high)\n        if (playerScreenY < screenCenterY - DEAD_ZONE || \n            playerScreenY > screenCenterY + DEAD_ZONE) {\n            camera.setPosition(camera.getX(), player->y - screenCenterY);\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw background (parallax)\n        renderer.setDisplayOffset(\n            static_cast<int>(camera.getX() * 0.3f), \n            0\n        );\n        renderer.drawTileMap(backgroundTileMap, 0, 0, Color::DarkGray);\n        renderer.setDisplayOffset(0, 0);\n\n        // Draw game objects\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-movement","title":"Camera Movement","text":"
  • Use dead zones: Prevents jittery camera movement
  • Smooth transitions: Consider lerping camera position for smoother movement
  • Set boundaries: Always limit camera to level bounds
  • Test on hardware: Camera performance may differ on ESP32
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#parallax","title":"Parallax","text":"
  • Layer speeds: Farther layers move slower (0.2-0.5), closer move faster (0.7-0.9)
  • Limit layers: Too many parallax layers can impact performance
  • Use tilemaps: Parallax works best with tilemaps
  • Test visually: Ensure parallax effect is noticeable but not distracting
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#performance","title":"Performance","text":"
  • Apply once: Call camera.apply() once per frame, at start of draw()
  • Cull off-screen: Don't draw entities outside camera view
  • Limit parallax layers: 2-3 layers is usually enough
  • Optimize tilemaps: Use efficient tilemap rendering
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-helper-class","title":"Camera Helper Class","text":"
class CameraController {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    float targetX, targetY;\n    float smoothSpeed = 0.1f;\n\npublic:\n    void followTarget(float x, float y) {\n        targetX = x;\n        targetY = y;\n    }\n\n    void update(unsigned long deltaTime) {\n        // Smooth camera movement\n        float currentX = camera.getX();\n        float currentY = camera.getY();\n\n        float newX = currentX + (targetX - currentX) * smoothSpeed;\n        float newY = currentY + (targetY - currentY) * smoothSpeed;\n\n        camera.setPosition(newX, newY);\n    }\n\n    void apply(pixelroot32::graphics::Renderer& renderer) {\n        camera.apply(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#viewport-culling","title":"Viewport Culling","text":"

Only draw entities within camera view:

bool isVisible(float x, float y, int width, int height) {\n    float cameraX = camera.getX();\n    float cameraY = camera.getY();\n    int screenWidth = engine.getRenderer().getWidth();\n    int screenHeight = engine.getRenderer().getHeight();\n\n    return !(x + width < cameraX || \n             x > cameraX + screenWidth ||\n             y + height < cameraY || \n             y > cameraY + screenHeight);\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-not-moving","title":"Camera Not Moving","text":"
  • Verify camera.apply() is called in draw()
  • Check followTarget() or setPosition() is called in update()
  • Ensure camera is created with correct viewport size
  • Check boundaries aren't preventing movement
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#objects-not-visible","title":"Objects Not Visible","text":"
  • Verify objects are within camera view
  • Check world coordinates vs screen coordinates
  • Ensure camera is applied before drawing
  • Verify render layers are correct
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#parallax-not-working","title":"Parallax Not Working","text":"
  • Check setDisplayOffset() is used correctly
  • Verify parallax speed values (0.0 to 1.0)
  • Ensure offset is reset after parallax layers
  • Test with different speed values
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#next-steps","title":"Next Steps","text":"

Now that you understand cameras and scrolling, learn about: - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects - Performance Optimization - Optimize your game

See also: - API Reference - Camera2D - Manual - Basic Rendering - Manual - Tilemaps

"},{"location":"manual/advanced_graphics/color_palettes/","title":"Color Palettes","text":"

PixelRoot32 uses a palette-based color system that allows you to easily change the visual style of your game. This guide covers built-in palettes, dual palette mode, and custom palettes.

"},{"location":"manual/advanced_graphics/color_palettes/#built-in-palettes","title":"Built-in Palettes","text":"

PixelRoot32 includes several predefined palettes inspired by classic gaming systems:

"},{"location":"manual/advanced_graphics/color_palettes/#available-palettes","title":"Available Palettes","text":"
#include <graphics/PaletteDefs.h>\n\nnamespace pixelroot32::graphics {\n\nenum class PaletteType {\n    PR32,    // PixelRoot32 default palette\n    NES,     // Nintendo Entertainment System\n    GB,      // GameBoy (4 shades of green)\n    GBC,     // GameBoy Color\n    PICO8    // PICO-8 palette\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#using-built-in-palettes","title":"Using Built-in Palettes","text":"
#include <graphics/PaletteDefs.h>\n\n// Set palette globally (legacy mode)\npixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n\n// All sprites will now use NES colors\nrenderer.drawSprite(MY_SPRITE, 100, 100, pixelroot32::graphics::Color::White);\n
"},{"location":"manual/advanced_graphics/color_palettes/#palette-characteristics","title":"Palette Characteristics","text":"

PR32 (Default) - Modern, balanced colors - Good contrast - Suitable for most games

NES - Classic 8-bit console colors - Limited color range - Nostalgic feel

GB (GameBoy) - 4 shades of green - Monochrome aesthetic - Classic handheld look

GBC (GameBoy Color) - Expanded color range - More vibrant than GB - Classic portable console

PICO8 - PICO-8 fantasy console palette - 16 carefully chosen colors - Popular for retro games

"},{"location":"manual/advanced_graphics/color_palettes/#legacy-mode-single-global-palette","title":"Legacy Mode (Single Global Palette)","text":"

In legacy mode, one palette is used for all sprites:

void MyScene::init() override {\n    // Set global palette\n    pixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n\n    // All sprites use NES colors\n    // This is the simplest mode\n}\n

When to use: - Simple games - Consistent visual style - Maximum compatibility

"},{"location":"manual/advanced_graphics/color_palettes/#dual-palette-mode","title":"Dual Palette Mode","text":"

Dual palette mode allows different palettes for background elements and sprites, creating visual contrast.

"},{"location":"manual/advanced_graphics/color_palettes/#enabling-dual-palette-mode","title":"Enabling Dual Palette Mode","text":"
#include <graphics/PaletteDefs.h>\n\nvoid MyScene::init() override {\n    // Enable dual palette mode\n    pixelroot32::graphics::enableDualPaletteMode();\n\n    // Set background palette\n    pixelroot32::graphics::setBackgroundPalette(\n        pixelroot32::graphics::PaletteType::GB\n    );\n\n    // Set sprite palette\n    pixelroot32::graphics::setSpritePalette(\n        pixelroot32::graphics::PaletteType::NES\n    );\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#how-it-works","title":"How It Works","text":"
  • Background palette: Used for tilemaps, primitives, and background sprites
  • Sprite palette: Used for game objects, characters, and foreground sprites
  • Automatic context: The renderer automatically selects the correct palette based on what you're drawing
"},{"location":"manual/advanced_graphics/color_palettes/#example-contrasting-styles","title":"Example: Contrasting Styles","text":"
void MyScene::init() override {\n    pixelroot32::graphics::enableDualPaletteMode();\n\n    // Dark, muted background (GameBoy green)\n    pixelroot32::graphics::setBackgroundPalette(\n        pixelroot32::graphics::PaletteType::GB\n    );\n\n    // Bright, colorful sprites (NES)\n    pixelroot32::graphics::setSpritePalette(\n        pixelroot32::graphics::PaletteType::NES\n    );\n\n    // Background uses GB palette\n    renderer.drawTileMap(backgroundTileMap, 0, 0, \n        pixelroot32::graphics::Color::White);\n\n    // Sprites use NES palette\n    renderer.drawSprite(playerSprite, 100, 100, \n        pixelroot32::graphics::Color::White);\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#when-to-use-dual-palette-mode","title":"When to Use Dual Palette Mode","text":"
  • Visual contrast: Make sprites stand out from background
  • Artistic style: Different palettes for different layers
  • Retro aesthetics: Classic console color separation
  • Performance: No performance impact, just visual variety
"},{"location":"manual/advanced_graphics/color_palettes/#custom-palettes","title":"Custom Palettes","text":"

Create your own color palettes for unique visual styles.

"},{"location":"manual/advanced_graphics/color_palettes/#creating-a-custom-palette","title":"Creating a Custom Palette","text":"
#include <graphics/PaletteDefs.h>\n#include <graphics/Color.h>\n\n// Define custom colors (RGB565 format)\nstatic const pixelroot32::graphics::Color CUSTOM_PALETTE[] = {\n    pixelroot32::graphics::Color::Black,      // 0: Transparent/background\n    pixelroot32::graphics::Color::DarkBlue,   // 1\n    pixelroot32::graphics::Color::Blue,       // 2\n    pixelroot32::graphics::Color::LightBlue, // 3\n    pixelroot32::graphics::Color::Cyan,      // 4\n    pixelroot32::graphics::Color::White,      // 5\n    // ... more colors\n};\n\n// Set custom palette\npixelroot32::graphics::setCustomPalette(\n    CUSTOM_PALETTE,\n    sizeof(CUSTOM_PALETTE) / sizeof(pixelroot32::graphics::Color)\n);\n
"},{"location":"manual/advanced_graphics/color_palettes/#rgb565-color-format","title":"RGB565 Color Format","text":"

Colors in PixelRoot32 use RGB565 format (16-bit):

// RGB565: 5 bits red, 6 bits green, 5 bits blue\n// Format: RRRRR GGGGGG BBBBB\n\n// Create custom RGB565 color\nuint16_t myColor = (31 << 11) | (63 << 5) | 31; // White\nuint16_t myColor = (0 << 11) | (0 << 5) | 0;    // Black\nuint16_t myColor = (31 << 11) | (0 << 5) | 0;   // Red\n\n// Or use Color constants\npixelroot32::graphics::Color::Red\npixelroot32::graphics::Color::Green\npixelroot32::graphics::Color::Blue\n
"},{"location":"manual/advanced_graphics/color_palettes/#helper-function-for-custom-colors","title":"Helper Function for Custom Colors","text":"
// Create RGB565 color from RGB values (0-255)\nuint16_t rgb565(uint8_t r, uint8_t g, uint8_t b) {\n    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\n}\n\n// Usage\nstatic const pixelroot32::graphics::Color MY_PALETTE[] = {\n    rgb565(0, 0, 0),        // Black\n    rgb565(255, 0, 0),      // Red\n    rgb565(0, 255, 0),      // Green\n    rgb565(0, 0, 255),      // Blue\n    rgb565(255, 255, 255),  // White\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#complete-custom-palette-example","title":"Complete Custom Palette Example","text":"
class CustomPaletteScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Define custom palette (ocean theme)\n        static const pixelroot32::graphics::Color OCEAN_PALETTE[] = {\n            pixelroot32::graphics::Color::Black,      // 0: Deep ocean\n            pixelroot32::graphics::Color::Navy,        // 1: Dark blue\n            pixelroot32::graphics::Color::Blue,       // 2: Medium blue\n            pixelroot32::graphics::Color::Cyan,       // 3: Light blue\n            pixelroot32::graphics::Color::LightBlue, // 4: Surface\n            pixelroot32::graphics::Color::White,      // 5: Foam\n        };\n\n        // Set custom palette\n        pixelroot32::graphics::setCustomPalette(\n            OCEAN_PALETTE,\n            sizeof(OCEAN_PALETTE) / sizeof(pixelroot32::graphics::Color)\n        );\n\n        // Now all sprites use the ocean palette\n    }\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#color-constants","title":"Color Constants","text":"

PixelRoot32 provides predefined color constants:

namespace pixelroot32::graphics {\n    Color::Black\n    Color::White\n    Color::Red\n    Color::Green\n    Color::Blue\n    Color::Yellow\n    Color::Cyan\n    Color::Magenta\n    Color::DarkGray\n    Color::LightGray\n    Color::Navy\n    Color::DarkGreen\n    Color::DarkRed\n    Color::Brown\n    Color::Purple\n    Color::Orange\n    Color::Pink\n    Color::Gold\n    Color::LightBlue\n    Color::LightGreen\n    Color::LightRed\n    Color::Transparent\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/color_palettes/#palette-selection","title":"Palette Selection","text":"
  • Match game style: Choose palette that fits your game's theme
  • Test on hardware: Colors may look different on ESP32 display
  • Consider contrast: Ensure sprites are visible against background
  • Consistency: Stick with one palette per scene (or use dual mode)
"},{"location":"manual/advanced_graphics/color_palettes/#dual-palette-mode_1","title":"Dual Palette Mode","text":"
  • Use sparingly: Not all games need dual palettes
  • Test combinations: Some palette combinations work better than others
  • Clear separation: Use for clear visual distinction between layers
  • Performance: No performance cost, use freely
"},{"location":"manual/advanced_graphics/color_palettes/#custom-palettes_1","title":"Custom Palettes","text":"
  • Limit colors: Keep palette size reasonable (8-16 colors)
  • Plan ahead: Design palette before creating sprites
  • Test thoroughly: Verify colors work well together
  • Document: Comment your palette choices
"},{"location":"manual/advanced_graphics/color_palettes/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/color_palettes/#palette-switching","title":"Palette Switching","text":"
class GameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Set initial palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::NES\n        );\n    }\n\n    void changeToNightMode() {\n        // Switch to darker palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::GB\n        );\n    }\n\n    void changeToDayMode() {\n        // Switch to brighter palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::PICO8\n        );\n    }\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#theme-based-palettes","title":"Theme-Based Palettes","text":"
namespace GamePalettes {\n    // Forest theme\n    static const pixelroot32::graphics::Color FOREST[] = {\n        Color::Black,\n        Color::DarkGreen,\n        Color::Green,\n        Color::LightGreen,\n        Color::Brown,\n        Color::Yellow\n    };\n\n    // Desert theme\n    static const pixelroot32::graphics::Color DESERT[] = {\n        Color::Black,\n        Color::Brown,\n        Color::Yellow,\n        Color::Gold,\n        Color::Orange,\n        Color::White\n    };\n\n    // Ocean theme\n    static const pixelroot32::graphics::Color OCEAN[] = {\n        Color::Black,\n        Color::Navy,\n        Color::Blue,\n        Color::Cyan,\n        Color::LightBlue,\n        Color::White\n    };\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/color_palettes/#colors-not-changing","title":"Colors Not Changing","text":"
  • Verify setPalette() is called before drawing
  • Check palette is set in init(), not update()
  • Ensure dual palette mode is enabled if using separate palettes
  • Verify Color constants are from correct namespace
"},{"location":"manual/advanced_graphics/color_palettes/#colors-look-wrong-on-hardware","title":"Colors Look Wrong on Hardware","text":"
  • ESP32 displays may render colors differently
  • Test on actual hardware, not just PC
  • Adjust palette colors if needed
  • Consider display calibration
"},{"location":"manual/advanced_graphics/color_palettes/#dual-palette-not-working","title":"Dual Palette Not Working","text":"
  • Ensure enableDualPaletteMode() is called first
  • Verify both palettes are set
  • Check that you're drawing in correct context
  • Review renderer documentation
"},{"location":"manual/advanced_graphics/color_palettes/#next-steps","title":"Next Steps","text":"

Now that you understand palettes, learn about: - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects

See also: - API Reference - PaletteDefs - API Reference - Color - Manual - Basic Rendering

"},{"location":"manual/advanced_graphics/particles_and_effects/","title":"Particles and Effects","text":"

The particle system allows you to create visual effects like fire, explosions, smoke, and sparks. This guide covers ParticleEmitter, ParticleConfig, and the included presets.

"},{"location":"manual/advanced_graphics/particles_and_effects/#particleemitter-basics","title":"ParticleEmitter Basics","text":"

A ParticleEmitter is an Entity that manages a pool of particles to create visual effects.

"},{"location":"manual/advanced_graphics/particles_and_effects/#creating-a-particle-emitter","title":"Creating a Particle Emitter","text":"
#include <graphics/particles/ParticleEmitter.h>\n#include <graphics/particles/ParticleConfig.h>\n\n// Create particle configuration\npixelroot32::graphics::particles::ParticleConfig config;\nconfig.startColor = pixelroot32::graphics::Color::Red;\nconfig.endColor = pixelroot32::graphics::Color::Yellow;\nconfig.lifetime = 1.0f; // 1 second\nconfig.speed = 50.0f;\nconfig.gravity = -100.0f; // Upward (negative = up)\n\n// Create emitter\npixelroot32::graphics::particles::ParticleEmitter* emitter = \n    new pixelroot32::graphics::particles::ParticleEmitter(100, 100, config);\n\n// Add to scene\naddEntity(emitter);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#emitting-particles","title":"Emitting Particles","text":"
// Emit a burst of particles\nemitter->burst(100, 100, 10); // x, y, particle count\n\n// Particles will automatically update and draw\n// No additional code needed!\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#particleconfig","title":"ParticleConfig","text":"

ParticleConfig defines how particles behave:

#include <graphics/particles/ParticleConfig.h>\n\npixelroot32::graphics::particles::ParticleConfig config;\n\n// Colors\nconfig.startColor = pixelroot32::graphics::Color::Red;   // Color at spawn\nconfig.endColor = pixelroot32::graphics::Color::Yellow;  // Color at death\n\n// Lifetime\nconfig.lifetime = 0.5f; // Duration in seconds\n\n// Velocity\nconfig.speed = 100.0f;           // Base speed\nconfig.speedVariation = 20.0f;   // Random variation\nconfig.direction = 90.0f;        // Direction in degrees (0 = right, 90 = up)\nconfig.directionVariation = 45.0f; // Random direction spread\n\n// Physics\nconfig.gravity = 200.0f;  // Gravity force (positive = down)\nconfig.friction = 0.95f;   // Friction (0.0 to 1.0, 1.0 = no friction)\n\n// Size\nconfig.startSize = 2;     // Size at spawn (pixels)\nconfig.endSize = 1;       // Size at death\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#complete-config-example","title":"Complete Config Example","text":"
pixelroot32::graphics::particles::ParticleConfig fireConfig;\n\n// Fire colors (red to yellow)\nfireConfig.startColor = pixelroot32::graphics::Color::Red;\nfireConfig.endColor = pixelroot32::graphics::Color::Yellow;\n\n// Short lifetime\nfireConfig.lifetime = 0.3f;\n\n// Upward movement with variation\nfireConfig.speed = 80.0f;\nfireConfig.speedVariation = 30.0f;\nfireConfig.direction = 90.0f; // Up\nfireConfig.directionVariation = 30.0f; // Spread\n\n// Upward gravity (negative)\nfireConfig.gravity = -50.0f;\n\n// Slight friction\nfireConfig.friction = 0.98f;\n\n// Size\nfireConfig.startSize = 3;\nfireConfig.endSize = 1;\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#built-in-presets","title":"Built-in Presets","text":"

PixelRoot32 includes several particle presets for common effects:

"},{"location":"manual/advanced_graphics/particles_and_effects/#fire","title":"Fire","text":"
#include <graphics/particles/ParticlePresets.h>\n\n// Create fire emitter\npixelroot32::graphics::particles::ParticleEmitter* fire = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Fire()\n    );\n\n// Emit continuous fire\nvoid update(unsigned long deltaTime) override {\n    fire->burst(100, 100, 2); // Emit 2 particles per frame\n    Scene::update(deltaTime);\n}\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#explosion","title":"Explosion","text":"
// Create explosion emitter\npixelroot32::graphics::particles::ParticleEmitter* explosion = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Explosion()\n    );\n\n// Emit explosion burst\nexplosion->burst(100, 100, 20); // 20 particles at once\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#sparks","title":"Sparks","text":"
// Create sparks emitter\npixelroot32::graphics::particles::ParticleEmitter* sparks = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Sparks()\n    );\n\n// Emit sparks\nsparks->burst(100, 100, 10);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#smoke","title":"Smoke","text":"
// Create smoke emitter\npixelroot32::graphics::particles::ParticleEmitter* smoke = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Smoke()\n    );\n\n// Emit smoke\nsmoke->burst(100, 100, 3);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#dust","title":"Dust","text":"
// Create dust emitter\npixelroot32::graphics::particles::ParticleEmitter* dust = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Dust()\n    );\n\n// Emit dust\ndust->burst(100, 100, 5);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#complete-example-explosion-effect","title":"Complete Example: Explosion Effect","text":"
#include <core/Scene.h>\n#include <graphics/particles/ParticleEmitter.h>\n#include <graphics/particles/ParticlePresets.h>\n\nclass ExplosionEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* explosion;\n    bool active = false;\n\npublic:\n    ExplosionEffect()\n        : Entity(0, 0, 1, 1, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n\n        // Create explosion emitter\n        explosion = new pixelroot32::graphics::particles::ParticleEmitter(\n            0, 0,\n            pixelroot32::graphics::particles::ParticlePresets::Explosion()\n        );\n    }\n\n    void trigger(float x, float y) {\n        active = true;\n        this->x = x;\n        this->y = y;\n\n        // Emit explosion burst\n        explosion->burst(x, y, 25);\n    }\n\n    void update(unsigned long deltaTime) override {\n        explosion->update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        explosion->draw(renderer);\n    }\n};\n\n// Usage in scene\nvoid MyScene::init() override {\n    explosionEffect = new ExplosionEffect();\n    addEntity(explosionEffect);\n}\n\nvoid MyScene::update(unsigned long deltaTime) override {\n    auto& input = engine.getInputManager();\n\n    // Trigger explosion on button press\n    if (input.isButtonPressed(4)) { // Button A\n        explosionEffect->trigger(player->x, player->y);\n    }\n\n    Scene::update(deltaTime);\n}\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#continuous-effects","title":"Continuous Effects","text":"

For continuous effects like fire or smoke:

class FireEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* fire;\n    unsigned long emitTimer = 0;\n    const unsigned long EMIT_INTERVAL_MS = 50; // Emit every 50ms\n\npublic:\n    FireEffect(float x, float y)\n        : Entity(x, y, 1, 1, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n\n        fire = new pixelroot32::graphics::particles::ParticleEmitter(\n            x, y,\n            pixelroot32::graphics::particles::ParticlePresets::Fire()\n        );\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Emit particles continuously\n        emitTimer += deltaTime;\n        if (emitTimer >= EMIT_INTERVAL_MS) {\n            emitTimer -= EMIT_INTERVAL_MS;\n            fire->burst(x, y, 2); // 2 particles per interval\n        }\n\n        fire->update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        fire->draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#custom-particle-effects","title":"Custom Particle Effects","text":"

Create your own particle effects by customizing ParticleConfig:

"},{"location":"manual/advanced_graphics/particles_and_effects/#magic-spell-effect","title":"Magic Spell Effect","text":"
pixelroot32::graphics::particles::ParticleConfig magicConfig;\n\n// Magical colors (purple to cyan)\nmagicConfig.startColor = pixelroot32::graphics::Color::Purple;\nmagicConfig.endColor = pixelroot32::graphics::Color::Cyan;\n\n// Medium lifetime\nmagicConfig.lifetime = 0.8f;\n\n// Outward spread\nmagicConfig.speed = 60.0f;\nmagicConfig.speedVariation = 20.0f;\nmagicConfig.direction = 0.0f; // Right\nmagicConfig.directionVariation = 360.0f; // Full circle\n\n// Slight upward float\nmagicConfig.gravity = -30.0f;\n\n// Low friction (floaty)\nmagicConfig.friction = 0.92f;\n\n// Size\nmagicConfig.startSize = 2;\nmagicConfig.endSize = 1;\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#rain-effect","title":"Rain Effect","text":"
pixelroot32::graphics::particles::ParticleConfig rainConfig;\n\n// Rain color (light blue)\nrainConfig.startColor = pixelroot32::graphics::Color::LightBlue;\nrainConfig.endColor = pixelroot32::graphics::Color::LightBlue;\n\n// Long lifetime\nrainConfig.lifetime = 2.0f;\n\n// Downward movement\nrainConfig.speed = 150.0f;\nrainConfig.speedVariation = 20.0f;\nrainConfig.direction = 270.0f; // Down\nrainConfig.directionVariation = 5.0f; // Slight angle variation\n\n// Downward gravity\nrainConfig.gravity = 200.0f;\n\n// No friction\nrainConfig.friction = 1.0f;\n\n// Small size\nrainConfig.startSize = 1;\nrainConfig.endSize = 1;\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/particles_and_effects/#performance","title":"Performance","text":"
  • Limit particle count: Each emitter has MAX_PARTICLES_PER_EMITTER (50)
  • Reuse emitters: Don't create new emitters every frame
  • Disable when not visible: Set isVisible = false when off-screen
  • Limit active emitters: Too many emitters can impact performance
"},{"location":"manual/advanced_graphics/particles_and_effects/#visual-design","title":"Visual Design","text":"
  • Match game style: Particle effects should fit your game's aesthetic
  • Use appropriate colors: Match particle colors to game palette
  • Test on hardware: ESP32 may render particles differently
  • Keep it simple: Simple effects often look better than complex ones
"},{"location":"manual/advanced_graphics/particles_and_effects/#timing","title":"Timing","text":"
  • Burst timing: Space out bursts for better visual effect
  • Continuous effects: Use timers to control emission rate
  • Lifetime: Adjust lifetime to match effect duration
  • Cleanup: Particles automatically clean up when lifetime expires
"},{"location":"manual/advanced_graphics/particles_and_effects/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/particles_and_effects/#one-shot-effect","title":"One-Shot Effect","text":"
class OneShotEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* emitter;\n    bool hasEmitted = false;\n\npublic:\n    void trigger(float x, float y) {\n        if (!hasEmitted) {\n            emitter->burst(x, y, 20);\n            hasEmitted = true;\n        }\n    }\n\n    void reset() {\n        hasEmitted = false;\n    }\n};\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#attached-effect","title":"Attached Effect","text":"
class AttachedParticleEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* emitter;\n    pixelroot32::core::Actor* target;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        // Update emitter position to follow target\n        emitter->x = target->x;\n        emitter->y = target->y;\n\n        // Emit particles\n        emitter->burst(target->x, target->y, 1);\n\n        emitter->update(deltaTime);\n    }\n};\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/particles_and_effects/#particles-not-appearing","title":"Particles Not Appearing","text":"
  • Verify emitter is added to scene
  • Check particle config is valid
  • Ensure burst() is being called
  • Verify emitter position is on-screen
"},{"location":"manual/advanced_graphics/particles_and_effects/#performance-issues","title":"Performance Issues","text":"
  • Reduce particle count per burst
  • Limit number of active emitters
  • Use simpler particle configs
  • Disable emitters when not visible
"},{"location":"manual/advanced_graphics/particles_and_effects/#particles-not-moving","title":"Particles Not Moving","text":"
  • Check gravity value (positive = down, negative = up)
  • Verify speed is not 0
  • Check friction isn't too high (1.0 = no movement)
  • Ensure direction is correct (degrees: 0=right, 90=up, 180=left, 270=down)
"},{"location":"manual/advanced_graphics/particles_and_effects/#next-steps","title":"Next Steps","text":"

Now that you understand particles, you've completed the advanced graphics section. Continue with: - Performance Optimization - Optimize your game - Memory Management - Manage memory efficiently - API Reference - Complete API documentation

See also: - API Reference - ParticleEmitter - API Reference - ParticleConfig - API Reference - ParticlePresets - Manual - Basic Rendering

"},{"location":"manual/advanced_graphics/resolution_scaling/","title":"Resolution Scaling","text":"

PixelRoot32 features a powerful Independent Resolution Scaling system. This allows the engine to render internally at a lower resolution (Logical Resolution) and then scale the final image to the display's actual hardware resolution (Physical Resolution).

"},{"location":"manual/advanced_graphics/resolution_scaling/#why-use-resolution-scaling","title":"Why use Resolution Scaling?","text":"

On microcontrollers like the ESP32, memory and processing power are limited. Rendering at a full 240x240 resolution consumes significant RAM and CPU cycles for every pixel drawn.

By using a lower logical resolution (e.g., 128x128): 1. Memory Savings: A 128x128 8bpp buffer uses ~16KB, while 240x240 uses ~57KB (72% reduction). 2. Performance Boost: Fewer pixels to process means more complex scenes and higher FPS. 3. Retro Aesthetic: Nearest-neighbor scaling preserves the pixel-art look perfectly.

"},{"location":"manual/advanced_graphics/resolution_scaling/#logical-vs-physical-resolution","title":"Logical vs Physical Resolution","text":"
  • Logical Resolution: The virtual canvas where your game logic, sprites, and UI are drawn.
  • Physical Resolution: The actual pixel dimensions of your hardware display.
flowchart LR\n    subgraph Logical [Logical Resolution 128x128]\n        A[Game Logic] --> B[Renderer API]\n        B --> C[Internal Framebuffer]\n    end\n\n    subgraph Scaling [Hardware Scaling]\n        C --> D[Nearest Neighbor Scaler]\n    end\n\n    subgraph Physical [Physical Display 240x240]\n        D --> E[SPI/DMA Transfer]\n        E --> F[LCD Hardware]\n    end
"},{"location":"manual/advanced_graphics/resolution_scaling/#configuration","title":"Configuration","text":""},{"location":"manual/advanced_graphics/resolution_scaling/#using-presets","title":"Using Presets","text":"

The easiest way to configure scaling is using the ResolutionPresets helper.

#include <graphics/ResolutionPresets.h>\n\n// Create a config for 128x128 logical resolution scaled to 240x240 physical\nauto config = pr32::graphics::ResolutionPresets::create(\n    pr32::graphics::RES_128x128,\n    pr32::graphics::ST7789\n);\n
"},{"location":"manual/advanced_graphics/resolution_scaling/#manual-configuration","title":"Manual Configuration","text":"

You can also specify custom dimensions in the DisplayConfig constructor.

pr32::graphics::DisplayConfig config(\n    pr32::graphics::ST7789, // Driver\n    0,                      // Rotation\n    240, 240,               // Physical Width, Physical Height\n    160, 160                // Logical Width, Logical Height\n);\n
"},{"location":"manual/advanced_graphics/resolution_scaling/#performance-impact","title":"Performance Impact","text":"

The following table shows estimated savings on an ESP32 for a standard 240x240 display:

Logical Resolution Memory (8bpp) RAM Savings FPS Gain (est.) 240x240 (Full) 57.6 KB 0% Baseline 160x160 25.6 KB ~55% +30% 128x128 16.4 KB ~72% +60% 96x96 9.2 KB ~84% +100%"},{"location":"manual/advanced_graphics/resolution_scaling/#implementation-details","title":"Implementation Details","text":""},{"location":"manual/advanced_graphics/resolution_scaling/#nearest-neighbor-scaling","title":"Nearest Neighbor Scaling","text":"

The engine uses a Nearest Neighbor algorithm optimized for ESP32. It avoids floating-point math by using pre-calculated Lookup Tables (LUTs).

"},{"location":"manual/advanced_graphics/resolution_scaling/#on-the-fly-scaling","title":"On-the-fly Scaling","text":"

To save even more RAM, the engine does not maintain a physical-sized buffer. Instead, it scales the image line-by-line during the SPI DMA transfer. This means the only large buffer in memory is the small logical one.

"},{"location":"manual/advanced_graphics/resolution_scaling/#profiling","title":"Profiling","text":"

You can measure the performance of the scaling system by enabling the Debug Statistics Overlay. This provides real-time data on FPS, CPU load, and RAM usage directly on the screen.

See Engine - Debug Overlay for instructions on how to enable it.

Alternatively, you can enable low-level profiling in EngineConfig.h:

#define PIXELROOT32_ENABLE_PROFILING\n

This will output the time taken for scaling and transfer to the Serial monitor: [PROFILING] Scaled Transfer: 12450 us (80 FPS max)

"},{"location":"manual/advanced_graphics/resolution_scaling/#best-practices","title":"Best Practices","text":"
  1. Aspect Ratio: Keep the logical aspect ratio the same as the physical one to avoid stretching.
  2. Integer Multiples: For the sharpest results, try to use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen).
  3. UI Positioning: Use UIAnchorLayout to ensure your UI elements stay correctly positioned regardless of the logical resolution chosen.
"},{"location":"manual/advanced_graphics/sprites_and_animation/","title":"Sprites and Animation","text":"

This guide covers advanced sprite techniques and animation in PixelRoot32, including different sprite formats, creating animations, and best practices.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-formats","title":"Sprite Formats","text":"

PixelRoot32 supports multiple sprite formats, each optimized for different use cases.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#1bpp-standard-monochrome","title":"1bpp (Standard, Monochrome)","text":"

The standard format uses 1 bit per pixel (monochrome). This is the most memory-efficient format:

#include <graphics/Renderer.h>\n\n// Define sprite data (8x8 example)\nstatic const uint16_t PLAYER_SPRITE_DATA[] = {\n    0b00111100,  // Row 0\n    0b01111110,  // Row 1\n    0b11111111,  // Row 2\n    0b11111111,  // Row 3\n    0b11111111,  // Row 4\n    0b01111110,  // Row 5\n    0b00111100,  // Row 6\n    0b00000000   // Row 7\n};\n\n// Create sprite descriptor\nstatic const pixelroot32::graphics::Sprite PLAYER_SPRITE = {\n    PLAYER_SPRITE_DATA,\n    8,  // width\n    8   // height\n};\n\n// Draw sprite\nrenderer.drawSprite(PLAYER_SPRITE, 100, 100, pixelroot32::graphics::Color::White);\n

Characteristics: - Most memory-efficient - 1 bit per pixel - Maximum width: 16 pixels - Color applied at draw time - Best for: Simple graphics, retro style

"},{"location":"manual/advanced_graphics/sprites_and_animation/#2bpp-experimental-4-colors","title":"2bpp (Experimental, 4 Colors)","text":"

2 bits per pixel allows 4 colors per sprite:

#ifdef PIXELROOT32_ENABLE_2BPP_SPRITES\n#include <graphics/Renderer.h>\n\n// Define 2bpp sprite data\nstatic const uint8_t COLORFUL_SPRITE_DATA[] = {\n    // Each byte represents 4 pixels (2 bits each)\n    // Format: [pixel3][pixel2][pixel1][pixel0]\n    0x00, 0x11, 0x22, 0x33,  // Row 0\n    0x11, 0x22, 0x33, 0x00,  // Row 1\n    // ... more rows\n};\n\n// Define palette (4 colors)\nstatic const pixelroot32::graphics::Color SPRITE_PALETTE[] = {\n    pixelroot32::graphics::Color::Transparent,\n    pixelroot32::graphics::Color::Red,\n    pixelroot32::graphics::Color::Green,\n    pixelroot32::graphics::Color::Blue\n};\n\n// Create 2bpp sprite\nstatic const pixelroot32::graphics::Sprite2bpp COLORFUL_SPRITE = {\n    COLORFUL_SPRITE_DATA,\n    SPRITE_PALETTE,\n    16,  // width\n    8,   // height\n    4    // palette size\n};\n\n// Draw 2bpp sprite\nrenderer.drawSprite(COLORFUL_SPRITE, 100, 100, false);\n#endif\n

Characteristics: - 2 bits per pixel (4 colors) - Requires custom palette - More memory than 1bpp - Best for: More colorful sprites without full color

"},{"location":"manual/advanced_graphics/sprites_and_animation/#4bpp-experimental-16-colors","title":"4bpp (Experimental, 16 Colors)","text":"

4 bits per pixel allows 16 colors per sprite:

#ifdef PIXELROOT32_ENABLE_4BPP_SPRITES\n#include <graphics/Renderer.h>\n\n// Define 4bpp sprite data\nstatic const uint8_t RICH_SPRITE_DATA[] = {\n    // Each byte represents 2 pixels (4 bits each)\n    // Format: [pixel1][pixel0]\n    0x01, 0x23, 0x45, 0x67,  // Row 0\n    // ... more rows\n};\n\n// Define palette (16 colors)\nstatic const pixelroot32::graphics::Color RICH_PALETTE[] = {\n    pixelroot32::graphics::Color::Transparent,\n    pixelroot32::graphics::Color::Black,\n    pixelroot32::graphics::Color::DarkGray,\n    // ... 13 more colors\n};\n\n// Create 4bpp sprite\nstatic const pixelroot32::graphics::Sprite4bpp RICH_SPRITE = {\n    RICH_SPRITE_DATA,\n    RICH_PALETTE,\n    16,  // width\n    16,  // height\n    16   // palette size\n};\n\n// Draw 4bpp sprite\nrenderer.drawSprite(RICH_SPRITE, 100, 100, false);\n#endif\n

Characteristics: - 4 bits per pixel (16 colors) - Requires custom palette - Most memory-intensive - Best for: Detailed sprites with many colors

"},{"location":"manual/advanced_graphics/sprites_and_animation/#multisprite-multi-layer","title":"MultiSprite (Multi-Layer)","text":"

MultiSprite combines multiple 1bpp layers to create multi-color sprites:

#include <graphics/Renderer.h>\n\n// Define layers (each is 1bpp)\nstatic const uint16_t BASE_LAYER_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b01111110,\n    0b00111100,\n    0b00000000\n};\n\nstatic const uint16_t HIGHLIGHT_LAYER_DATA[] = {\n    0b00000000,\n    0b00011000,\n    0b00111100,\n    0b00111100,\n    0b00111100,\n    0b00011000,\n    0b00000000,\n    0b00000000\n};\n\n// Create layers\nstatic const pixelroot32::graphics::SpriteLayer LAYERS[] = {\n    { BASE_LAYER_DATA, pixelroot32::graphics::Color::Blue },      // Base layer\n    { HIGHLIGHT_LAYER_DATA, pixelroot32::graphics::Color::Cyan }  // Highlight layer\n};\n\n// Create MultiSprite\nstatic const pixelroot32::graphics::MultiSprite PLAYER_MULTI = {\n    8,      // width\n    8,      // height\n    LAYERS, // layers array\n    2       // layer count\n};\n\n// Draw MultiSprite\nrenderer.drawSprite(PLAYER_MULTI, 100, 100, false);\n

Characteristics: - Combines multiple 1bpp layers - Each layer can have different color - Layers drawn in order (first = bottom) - Best for: Complex sprites with highlights, outlines, etc.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#creating-sprites","title":"Creating Sprites","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#manual-creation-1bpp","title":"Manual Creation (1bpp)","text":"

For simple sprites, you can create them manually:

// 8x8 sprite: Simple circle\nstatic const uint16_t CIRCLE_SPRITE_DATA[] = {\n    0b00111100,  //   ####\n    0b01111110,  //  ######\n    0b11111111,  // ########\n    0b11111111,  // ########\n    0b11111111,  // ########\n    0b11111111,  // ########\n    0b01111110,  //  ######\n    0b00111100   //   ####\n};\n\nstatic const pixelroot32::graphics::Sprite CIRCLE_SPRITE = {\n    CIRCLE_SPRITE_DATA,\n    8,\n    8\n};\n

Tips: - Use binary notation for clarity - Comment each row to visualize - Keep sprites small (8x8, 16x16) - Reuse sprites when possible

"},{"location":"manual/advanced_graphics/sprites_and_animation/#using-sprite-compiler","title":"Using Sprite Compiler","text":"

For complex sprites, use the Sprite Compiler tool (if available) to convert PNG images to sprite data.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-animation","title":"Sprite Animation","text":"

PixelRoot32 uses a step-based animation system that's lightweight and efficient.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#spriteanimation-structure","title":"SpriteAnimation Structure","text":"
#include <graphics/Renderer.h>\n\n// Define animation frames\nstatic const uint16_t FRAME1_DATA[] = { /* ... */ };\nstatic const uint16_t FRAME2_DATA[] = { /* ... */ };\nstatic const uint16_t FRAME3_DATA[] = { /* ... */ };\n\nstatic const pixelroot32::graphics::Sprite FRAME1 = { FRAME1_DATA, 8, 8 };\nstatic const pixelroot32::graphics::Sprite FRAME2 = { FRAME2_DATA, 8, 8 };\nstatic const pixelroot32::graphics::Sprite FRAME3 = { FRAME3_DATA, 8, 8 };\n\n// Create animation frames\nstatic const pixelroot32::graphics::SpriteAnimationFrame ANIMATION_FRAMES[] = {\n    { &FRAME1, nullptr },  // Frame 1 (no mask)\n    { &FRAME2, nullptr },  // Frame 2\n    { &FRAME3, nullptr }   // Frame 3\n};\n\n// Create animation\npixelroot32::graphics::SpriteAnimation walkAnimation;\nwalkAnimation.frames = ANIMATION_FRAMES;\nwalkAnimation.frameCount = 3;\nwalkAnimation.current = 0;\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#using-animations-in-actors","title":"Using Animations in Actors","text":"
#include <core/Actor.h>\n#include <graphics/Renderer.h>\n\nclass AnimatedPlayer : public pixelroot32::core::Actor {\nprivate:\n    pixelroot32::graphics::SpriteAnimation walkAnimation;\n    unsigned long animationTimer = 0;\n    const unsigned long FRAME_DURATION_MS = 100; // 100ms per frame\n\npublic:\n    AnimatedPlayer(float x, float y)\n        : Actor(x, y, 8, 8) {\n        setRenderLayer(1);\n\n        // Initialize animation\n        walkAnimation.frames = WALK_ANIMATION_FRAMES;\n        walkAnimation.frameCount = 3;\n        walkAnimation.current = 0;\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update animation\n        animationTimer += deltaTime;\n        if (animationTimer >= FRAME_DURATION_MS) {\n            animationTimer -= FRAME_DURATION_MS;\n            walkAnimation.step(); // Advance to next frame\n        }\n\n        // Movement logic...\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Get current frame\n        const pixelroot32::graphics::Sprite* currentFrame = \n            walkAnimation.frames[walkAnimation.current].sprite;\n\n        // Draw current frame\n        renderer.drawSprite(\n            *currentFrame,\n            static_cast<int>(x),\n            static_cast<int>(y),\n            pixelroot32::graphics::Color::White,\n            false // flipX\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collision\n    }\n};\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#animation-control","title":"Animation Control","text":"
// Reset animation to first frame\nwalkAnimation.reset();\n\n// Step to next frame (loops automatically)\nwalkAnimation.step();\n\n// Get current frame\nconst pixelroot32::graphics::Sprite* frame = \n    walkAnimation.frames[walkAnimation.current].sprite;\n\n// Check if animation is at specific frame\nif (walkAnimation.current == 0) {\n    // At first frame\n}\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#multiple-animations","title":"Multiple Animations","text":"

For actors with multiple animations (idle, walk, jump):

class PlayerActor : public pixelroot32::core::Actor {\nprivate:\n    enum class AnimationState {\n        IDLE,\n        WALK,\n        JUMP\n    };\n\n    AnimationState currentState = AnimationState::IDLE;\n    pixelroot32::graphics::SpriteAnimation idleAnim;\n    pixelroot32::graphics::SpriteAnimation walkAnim;\n    pixelroot32::graphics::SpriteAnimation jumpAnim;\n\n    pixelroot32::graphics::SpriteAnimation* getCurrentAnimation() {\n        switch (currentState) {\n            case AnimationState::IDLE: return &idleAnim;\n            case AnimationState::WALK: return &walkAnim;\n            case AnimationState::JUMP: return &jumpAnim;\n        }\n        return &idleAnim;\n    }\n\npublic:\n    void update(unsigned long deltaTime) override {\n        // Update current animation\n        auto* anim = getCurrentAnimation();\n        animationTimer += deltaTime;\n        if (animationTimer >= FRAME_DURATION_MS) {\n            animationTimer -= FRAME_DURATION_MS;\n            anim->step();\n        }\n\n        // Change animation state based on game logic\n        if (isMoving) {\n            if (currentState != AnimationState::WALK) {\n                currentState = AnimationState::WALK;\n                walkAnim.reset();\n            }\n        } else if (isJumping) {\n            if (currentState != AnimationState::JUMP) {\n                currentState = AnimationState::JUMP;\n                jumpAnim.reset();\n            }\n        } else {\n            if (currentState != AnimationState::IDLE) {\n                currentState = AnimationState::IDLE;\n                idleAnim.reset();\n            }\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        auto* anim = getCurrentAnimation();\n        const auto* frame = anim->frames[anim->current].sprite;\n        renderer.drawSprite(*frame, static_cast<int>(x), static_cast<int>(y), \n            pixelroot32::graphics::Color::White);\n    }\n};\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-flipping","title":"Sprite Flipping","text":"

Flip sprites horizontally for facing direction:

bool facingRight = true;\n\nvoid draw(pixelroot32::graphics::Renderer& renderer) override {\n    renderer.drawSprite(\n        PLAYER_SPRITE,\n        static_cast<int>(x),\n        static_cast<int>(y),\n        pixelroot32::graphics::Color::White,\n        !facingRight // Flip if facing left\n    );\n}\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#memory-optimization","title":"Memory Optimization","text":"
  • Reuse sprites: Define sprites once, use many times
  • Use 1bpp when possible: Most memory-efficient
  • Store in flash: Use static const to keep in flash memory
  • Limit sprite count: Too many unique sprites can exhaust memory
"},{"location":"manual/advanced_graphics/sprites_and_animation/#performance","title":"Performance","text":"
  • Pre-calculate animations: Set up animations in init(), not update()
  • Limit active animations: Only animate visible entities
  • Use appropriate formats: Don't use 4bpp if 1bpp works
  • Batch similar sprites: Draw similar sprites together
"},{"location":"manual/advanced_graphics/sprites_and_animation/#organization","title":"Organization","text":"
  • Group related sprites: Keep sprite data together
  • Use meaningful names: Name sprites clearly
  • Document complex sprites: Comment sprite bit patterns
  • Create sprite libraries: Reusable sprite collections
"},{"location":"manual/advanced_graphics/sprites_and_animation/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-sheet-pattern","title":"Sprite Sheet Pattern","text":"

Organize multiple sprites in arrays:

namespace PlayerSprites {\n    static const uint16_t IDLE_FRAME1[] = { /* ... */ };\n    static const uint16_t IDLE_FRAME2[] = { /* ... */ };\n    static const uint16_t WALK_FRAME1[] = { /* ... */ };\n    static const uint16_t WALK_FRAME2[] = { /* ... */ };\n\n    static const pixelroot32::graphics::Sprite IDLE[] = {\n        { IDLE_FRAME1, 8, 8 },\n        { IDLE_FRAME2, 8, 8 }\n    };\n\n    static const pixelroot32::graphics::Sprite WALK[] = {\n        { WALK_FRAME1, 8, 8 },\n        { WALK_FRAME2, 8, 8 }\n    };\n}\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#animation-helper","title":"Animation Helper","text":"

Create a helper class for animation management:

class AnimationController {\nprivate:\n    pixelroot32::graphics::SpriteAnimation* currentAnim;\n    unsigned long timer = 0;\n    unsigned long frameDuration;\n\npublic:\n    void setAnimation(pixelroot32::graphics::SpriteAnimation* anim) {\n        if (currentAnim != anim) {\n            currentAnim = anim;\n            currentAnim->reset();\n            timer = 0;\n        }\n    }\n\n    void update(unsigned long deltaTime) {\n        if (currentAnim) {\n            timer += deltaTime;\n            if (timer >= frameDuration) {\n                timer -= frameDuration;\n                currentAnim->step();\n            }\n        }\n    }\n\n    const pixelroot32::graphics::Sprite* getCurrentFrame() {\n        if (currentAnim && currentAnim->frameCount > 0) {\n            return currentAnim->frames[currentAnim->current].sprite;\n        }\n        return nullptr;\n    }\n};\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#sprites-not-displaying","title":"Sprites Not Displaying","text":"
  • Check sprite data is valid
  • Verify width/height match data
  • Ensure sprite is within screen bounds
  • Check render layer is correct
"},{"location":"manual/advanced_graphics/sprites_and_animation/#animation-not-playing","title":"Animation Not Playing","text":"
  • Verify animation frames are set
  • Check step() is being called
  • Ensure timer logic is correct
  • Verify frame count matches array size
"},{"location":"manual/advanced_graphics/sprites_and_animation/#memory-issues","title":"Memory Issues","text":"
  • Reduce sprite count
  • Use 1bpp instead of 2bpp/4bpp
  • Reuse sprites more
  • Check available flash memory
"},{"location":"manual/advanced_graphics/sprites_and_animation/#next-steps","title":"Next Steps","text":"

Now that you understand sprites and animation, learn about: - Color Palettes - Use different color schemes - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles

See also: - API Reference - Sprite - API Reference - SpriteAnimation - Manual - Basic Rendering

"},{"location":"manual/advanced_graphics/tilemaps/","title":"Tilemaps","text":"

Tilemaps allow you to build levels efficiently by reusing small tile sprites. This guide covers creating tilemaps, rendering them, and using them with scrolling cameras.

"},{"location":"manual/advanced_graphics/tilemaps/#what-are-tilemaps","title":"What are Tilemaps?","text":"

A tilemap is a 2D grid where each cell references a tile sprite. Instead of placing individual sprites, you define which tile appears at each grid position.

Advantages: - Memory efficient: Reuse tile sprites many times - Easy level design: Edit level data, not code - Fast rendering: Optimized tilemap drawing - Large levels: Create levels bigger than screen - Multiple Bit-Depths: Support for 1bpp, 2bpp, and 4bpp tilemaps for higher graphical fidelity

"},{"location":"manual/advanced_graphics/tilemaps/#creating-a-tilemap","title":"Creating a Tilemap","text":""},{"location":"manual/advanced_graphics/tilemaps/#1-define-tiles","title":"1. Define Tiles","text":"

First, create the tile sprites you'll reuse. You can use standard 1bpp sprites or multi-bpp sprites (2bpp/4bpp) if enabled.

"},{"location":"manual/advanced_graphics/tilemaps/#1bpp-tiles-example","title":"1bpp Tiles Example","text":"
#include <graphics/Renderer.h>\n\n// Ground tile (solid)\nstatic const uint16_t TILE_GROUND_BITS[] = {\n    0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,\n    0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF\n};\n\n// Create tile sprites (8x8 tiles)\nstatic const pixelroot32::graphics::Sprite TILES[] = {\n    { TILE_EMPTY_BITS, 8, 8 },  // Index 0: Empty\n    { TILE_GROUND_BITS, 8, 8 }  // Index 1: Ground\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#2bpp-tiles-example-multi-color","title":"2bpp Tiles Example (Multi-color)","text":"
#include <graphics/Renderer.h>\n\n// 2bpp grass tile\nstatic const uint8_t TILE_GRASS_DATA[] = {\n    0b01010101, 0b01010101, // Packed 2bpp data\n    // ...\n};\n\nstatic const Color GRASS_PALETTE[] = {\n    Color::Transparent, Color::DarkGreen, Color::Green, Color::LightGreen\n};\n\nstatic const pixelroot32::graphics::Sprite2bpp TILES_2BPP[] = {\n    { TILE_GRASS_DATA, GRASS_PALETTE, 8, 8, 4 }\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#2-create-tile-index-array","title":"2. Create Tile Index Array","text":"

Define which tile appears at each position:

// Tilemap dimensions (30 tiles wide, 20 tiles tall)\nstatic const int TILEMAP_WIDTH = 30;\nstatic const int TILEMAP_HEIGHT = 20;\n\n// Array of tile indices (each byte is a tile index)\nstatic uint8_t TILEMAP_INDICES[TILEMAP_WIDTH * TILEMAP_HEIGHT];\n\n// Initialize to empty\nvoid initTilemap() {\n    for (int i = 0; i < TILEMAP_WIDTH * TILEMAP_HEIGHT; i++) {\n        TILEMAP_INDICES[i] = 0; // Empty\n    }\n\n    // Draw ground at bottom\n    int groundRow = TILEMAP_HEIGHT - 1;\n    for (int x = 0; x < TILEMAP_WIDTH; x++) {\n        TILEMAP_INDICES[groundRow * TILEMAP_WIDTH + x] = 1; // Ground tile\n    }\n\n    // Add some walls\n    TILEMAP_INDICES[5 * TILEMAP_WIDTH + 10] = 2; // Wall at (10, 5)\n    TILEMAP_INDICES[5 * TILEMAP_WIDTH + 11] = 2;\n    TILEMAP_INDICES[5 * TILEMAP_WIDTH + 12] = 2;\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#3-create-tilemap-structure","title":"3. Create TileMap Structure","text":"
#include <graphics/Renderer.h>\n\nstatic pixelroot32::graphics::TileMap myTileMap = {\n    TILEMAP_INDICES,                    // indices array\n    TILEMAP_WIDTH,                      // width (in tiles)\n    TILEMAP_HEIGHT,                     // height (in tiles)\n    TILES,                              // tiles array\n    8,                                  // tile width (pixels)\n    8,                                  // tile height (pixels)\n    sizeof(TILES) / sizeof(pixelroot32::graphics::Sprite) // tile count\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#rendering-tilemaps","title":"Rendering Tilemaps","text":""},{"location":"manual/advanced_graphics/tilemaps/#basic-rendering","title":"Basic Rendering","text":"
void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // 1bpp Tilemap (requires a color)\n    renderer.drawTileMap(\n        myTileMap,\n        0, 0,\n        pixelroot32::graphics::Color::White\n    );\n\n    // 2bpp/4bpp Tilemap (colors are in the sprite palettes)\n    renderer.drawTileMap(myTileMap2bpp, 0, 100);\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#with-camerascrolling","title":"With Camera/Scrolling","text":"
void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera first\n    camera.apply(renderer);\n\n    // Draw tilemap (camera offset is automatically applied)\n    renderer.drawTileMap(\n        myTileMap,\n        0,                              // World position (0, 0)\n        0,\n        pixelroot32::graphics::Color::White\n    );\n\n    // Draw game objects\n    Scene::draw(renderer);\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#complete-example-platformer-level","title":"Complete Example: Platformer Level","text":"
#include <core/Scene.h>\n#include <graphics/Renderer.h>\n#include <graphics/Camera2D.h>\n\nclass PlatformerLevel : public pixelroot32::core::Scene {\nprivate:\n    static const int TILE_SIZE = 8;\n    static const int TILEMAP_WIDTH = 100;  // 800 pixels wide\n    static const int TILEMAP_HEIGHT = 30;   // 240 pixels tall\n\n    // Tile definitions\n    static const uint16_t TILE_EMPTY_BITS[] = {\n        0x0000, 0x0000, 0x0000, 0x0000,\n        0x0000, 0x0000, 0x0000, 0x0000\n    };\n\n    static const uint16_t TILE_GROUND_BITS[] = {\n        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,\n        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF\n    };\n\n    static const uint16_t TILE_GRASS_BITS[] = {\n        0x0000, 0x0000, 0x0000, 0x0000,\n        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF\n    };\n\n    static const pixelroot32::graphics::Sprite TILES[] = {\n        { TILE_EMPTY_BITS, TILE_SIZE, TILE_SIZE },  // 0: Empty\n        { TILE_GROUND_BITS, TILE_SIZE, TILE_SIZE }, // 1: Ground\n        { TILE_GRASS_BITS, TILE_SIZE, TILE_SIZE }   // 2: Grass top\n    };\n\n    static uint8_t LEVEL_INDICES[TILEMAP_WIDTH * TILEMAP_HEIGHT];\n\n    pixelroot32::graphics::TileMap levelTileMap;\n    pixelroot32::graphics::Camera2D camera;\n\npublic:\n    PlatformerLevel() \n        : camera(240, 240) {\n        // Initialize tilemap structure\n        levelTileMap = {\n            LEVEL_INDICES,\n            TILEMAP_WIDTH,\n            TILEMAP_HEIGHT,\n            TILES,\n            TILE_SIZE,\n            TILE_SIZE,\n            sizeof(TILES) / sizeof(pixelroot32::graphics::Sprite)\n        };\n    }\n\n    void init() override {\n        // Initialize all tiles to empty\n        for (int i = 0; i < TILEMAP_WIDTH * TILEMAP_HEIGHT; i++) {\n            LEVEL_INDICES[i] = 0;\n        }\n\n        // Create ground level\n        int groundY = TILEMAP_HEIGHT - 1;\n        for (int x = 0; x < TILEMAP_WIDTH; x++) {\n            LEVEL_INDICES[groundY * TILEMAP_WIDTH + x] = 1; // Ground\n        }\n\n        // Add grass on top of ground\n        int grassY = groundY - 1;\n        for (int x = 0; x < TILEMAP_WIDTH; x++) {\n            LEVEL_INDICES[grassY * TILEMAP_WIDTH + x] = 2; // Grass\n        }\n\n        // Add platforms\n        // Platform 1: x=10 to x=15, y=20\n        for (int x = 10; x < 16; x++) {\n            LEVEL_INDICES[20 * TILEMAP_WIDTH + x] = 1; // Ground tile\n        }\n\n        // Platform 2: x=30 to x=35, y=15\n        for (int x = 30; x < 36; x++) {\n            LEVEL_INDICES[15 * TILEMAP_WIDTH + x] = 1;\n        }\n\n        // Set camera boundaries\n        camera.setBounds(0, TILEMAP_WIDTH * TILE_SIZE - 240);\n        camera.setVerticalBounds(0, TILEMAP_HEIGHT * TILE_SIZE - 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Follow player (example)\n        // camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw tilemap\n        renderer.drawTileMap(\n            levelTileMap,\n            0, 0,\n            pixelroot32::graphics::Color::White\n        );\n\n        // Draw game objects\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#tilemap-with-scroll","title":"Tilemap with Scroll","text":"

For scrolling levels, combine tilemaps with cameras:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera (handles scrolling)\n    camera.apply(renderer);\n\n    // Draw tilemap (automatically scrolled by camera)\n    renderer.drawTileMap(\n        levelTileMap,\n        0, 0,\n        pixelroot32::graphics::Color::White\n    );\n\n    // Draw entities (also scrolled)\n    Scene::draw(renderer);\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#optimizing-tilemap-rendering","title":"Optimizing Tilemap Rendering","text":""},{"location":"manual/advanced_graphics/tilemaps/#viewport-culling","title":"Viewport Culling","text":"

Only draw visible tiles:

void drawTileMapOptimized(\n    pixelroot32::graphics::Renderer& renderer,\n    const pixelroot32::graphics::TileMap& tileMap,\n    int offsetX, int offsetY,\n    pixelroot32::graphics::Color color\n) {\n    int screenWidth = renderer.getWidth();\n    int screenHeight = renderer.getHeight();\n\n    // Calculate which tiles are visible\n    int startTileX = (offsetX < 0) ? (-offsetX / tileMap.tileWidth) : 0;\n    int startTileY = (offsetY < 0) ? (-offsetY / tileMap.tileHeight) : 0;\n    int endTileX = startTileX + (screenWidth / tileMap.tileWidth) + 1;\n    int endTileY = startTileY + (screenHeight / tileMap.tileHeight) + 1;\n\n    // Clamp to tilemap bounds\n    if (startTileX < 0) startTileX = 0;\n    if (startTileY < 0) startTileY = 0;\n    if (endTileX > tileMap.width) endTileX = tileMap.width;\n    if (endTileY > tileMap.height) endTileY = tileMap.height;\n\n    // Draw only visible tiles\n    for (int ty = startTileY; ty < endTileY; ty++) {\n        for (int tx = startTileX; tx < endTileX; tx++) {\n            uint8_t tileIndex = tileMap.indices[ty * tileMap.width + tx];\n            if (tileIndex < tileMap.tileCount) {\n                int x = tx * tileMap.tileWidth + offsetX;\n                int y = ty * tileMap.tileHeight + offsetY;\n                renderer.drawSprite(\n                    tileMap.tiles[tileIndex],\n                    x, y,\n                    color,\n                    false\n                );\n            }\n        }\n    }\n}\n

Note: The built-in drawTileMap() already performs viewport culling, so you typically don't need to implement this yourself.

"},{"location":"manual/advanced_graphics/tilemaps/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/tilemaps/#tile-design","title":"Tile Design","text":"
  • Keep tiles small: 8x8 or 16x16 pixels work best
  • Reuse tiles: Design tiles that can be used in multiple ways
  • Consistent style: All tiles should match visually
  • Limit tile count: Too many unique tiles uses more memory
"},{"location":"manual/advanced_graphics/tilemaps/#level-design","title":"Level Design","text":"
  • Use indices efficiently: 0 = empty, 1+ = different tiles
  • Plan layout: Design level on paper/grid first
  • Test on hardware: Large tilemaps may impact performance
  • Optimize data: Use compact level data format
"},{"location":"manual/advanced_graphics/tilemaps/#performance","title":"Performance","text":"
  • Limit tilemap size: Very large tilemaps can be slow
  • Use appropriate tile size: Smaller tiles = more tiles to draw
  • Combine with culling: Only draw visible area
  • Test scrolling: Ensure smooth scrolling performance
"},{"location":"manual/advanced_graphics/tilemaps/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/tilemaps/#level-data-in-code","title":"Level Data in Code","text":"
// Define level as 2D array (easier to read)\nstatic const uint8_t LEVEL_DATA[][TILEMAP_WIDTH] = {\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, // Ground\n};\n\n// Copy to tilemap indices\nvoid loadLevel() {\n    for (int y = 0; y < TILEMAP_HEIGHT; y++) {\n        for (int x = 0; x < TILEMAP_WIDTH; x++) {\n            TILEMAP_INDICES[y * TILEMAP_WIDTH + x] = LEVEL_DATA[y][x];\n        }\n    }\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#collision-detection-with-tilemaps","title":"Collision Detection with Tilemaps","text":"
bool isTileSolid(int tileX, int tileY) {\n    if (tileX < 0 || tileX >= TILEMAP_WIDTH ||\n        tileY < 0 || tileY >= TILEMAP_HEIGHT) {\n        return true; // Out of bounds = solid\n    }\n\n    uint8_t tileIndex = TILEMAP_INDICES[tileY * TILEMAP_WIDTH + tileX];\n    return tileIndex != 0; // 0 = empty, others = solid\n}\n\nbool checkCollision(float x, float y, int width, int height) {\n    // Convert world position to tile coordinates\n    int tileX1 = static_cast<int>(x) / TILE_SIZE;\n    int tileY1 = static_cast<int>(y) / TILE_SIZE;\n    int tileX2 = static_cast<int>(x + width) / TILE_SIZE;\n    int tileY2 = static_cast<int>(y + height) / TILE_SIZE;\n\n    // Check all tiles actor overlaps\n    for (int ty = tileY1; ty <= tileY2; ty++) {\n        for (int tx = tileX1; tx <= tileX2; tx++) {\n            if (isTileSolid(tx, ty)) {\n                return true; // Collision!\n            }\n        }\n    }\n\n    return false; // No collision\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/tilemaps/#tiles-not-appearing","title":"Tiles Not Appearing","text":"
  • Verify tile indices are correct (0 = first tile, 1 = second, etc.)
  • Check tilemap dimensions match indices array size
  • Ensure tiles array has enough entries
  • Verify tile size matches sprite size
"},{"location":"manual/advanced_graphics/tilemaps/#performance-issues","title":"Performance Issues","text":"
  • Reduce tilemap size
  • Use smaller tiles
  • Limit number of unique tiles
  • Test viewport culling
"},{"location":"manual/advanced_graphics/tilemaps/#scrolling-problems","title":"Scrolling Problems","text":"
  • Ensure camera is applied before drawing tilemap
  • Check tilemap position matches camera offset
  • Verify tilemap boundaries are correct
  • Test with simple tilemap first
"},{"location":"manual/advanced_graphics/tilemaps/#next-steps","title":"Next Steps","text":"

Now that you understand tilemaps, learn about: - Particles and Effects - Add visual effects - Cameras and Scrolling - Combine with scrolling - Performance Optimization - Optimize rendering

See also: - API Reference - TileMap - API Reference - Renderer - Manual - Cameras and Scrolling

"},{"location":"manual/game_development/audio/","title":"Audio","text":"

PixelRoot32 includes a complete NES-like audio system with 4 channels for sound effects and background music. This guide shows you how to add sound and music to your games.

"},{"location":"manual/game_development/audio/#audio-configuration","title":"Audio Configuration","text":"

Before using audio, you need to configure an AudioBackend. This is done when creating the Engine:

"},{"location":"manual/game_development/audio/#esp32-internal-dac","title":"ESP32: Internal DAC","text":"
#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nconst int DAC_PIN = 25; // GPIO 25 or 26\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\npr32::audio::AudioConfig audioConfig(&audioBackend, audioBackend.getSampleRate());\n
"},{"location":"manual/game_development/audio/#esp32-external-i2s-dac","title":"ESP32: External I2S DAC","text":"
#include <drivers/esp32/ESP32_I2S_AudioBackend.h>\n\nconst int I2S_BCLK = 26;  // Bit clock\nconst int I2S_LRCK = 25;  // Left/Right clock\nconst int I2S_DOUT = 22;  // Data out\n\npr32::drivers::esp32::ESP32_I2S_AudioBackend audioBackend(\n    I2S_BCLK, I2S_LRCK, I2S_DOUT, 22050\n);\n\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n
"},{"location":"manual/game_development/audio/#native-pc-sdl2","title":"Native (PC): SDL2","text":"
#include <drivers/native/SDL2_AudioBackend.h>\n\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\n\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n
"},{"location":"manual/game_development/audio/#sound-effects","title":"Sound Effects","text":"

Sound effects are created using AudioEvent structures and played through the AudioEngine.

"},{"location":"manual/game_development/audio/#audioevent-structure","title":"AudioEvent Structure","text":"
#include <audio/AudioTypes.h>\n\npr32::audio::AudioEvent soundEffect{};\nsoundEffect.type = pr32::audio::WaveType::PULSE;  // Waveform type\nsoundEffect.frequency = 1500.0f;                  // Frequency in Hz\nsoundEffect.duration = 0.12f;                      // Duration in seconds\nsoundEffect.volume = 0.8f;                         // Volume (0.0 to 1.0)\nsoundEffect.duty = 0.5f;                           // Duty cycle (for PULSE only)\n
"},{"location":"manual/game_development/audio/#wave-types","title":"Wave Types","text":"

PixelRoot32 supports three wave types:

  • PULSE: Square wave with variable duty cycle
  • Duty cycles: 0.125 (thin), 0.25 (classic NES), 0.5 (symmetric), 0.75 (fat)
  • Good for: Beeps, jumps, UI sounds, leads

  • TRIANGLE: Triangle wave (fixed volume/duty)

  • Softer, smoother sound
  • Good for: Bass lines, pads, background tones

  • NOISE: Pseudo-random noise

  • Harsh, chaotic sound
  • Good for: Explosions, hits, impacts, drums
"},{"location":"manual/game_development/audio/#playing-sound-effects","title":"Playing Sound Effects","text":"
// Get the audio engine\nauto& audio = engine.getAudioEngine();\n\n// Create and play a sound\npr32::audio::AudioEvent jumpSound{};\njumpSound.type = pr32::audio::WaveType::PULSE;\njumpSound.frequency = 800.0f;\njumpSound.duration = 0.1f;\njumpSound.volume = 0.7f;\njumpSound.duty = 0.25f;\n\naudio.playEvent(jumpSound);\n
"},{"location":"manual/game_development/audio/#common-sound-effects","title":"Common Sound Effects","text":"

Here are some example sound effects you can use:

namespace SoundEffects {\n    // Jump sound\n    inline pr32::audio::AudioEvent jump() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::PULSE;\n        evt.frequency = 600.0f;\n        evt.duration = 0.1f;\n        evt.volume = 0.7f;\n        evt.duty = 0.25f;\n        return evt;\n    }\n\n    // Coin/collect sound\n    inline pr32::audio::AudioEvent coin() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::PULSE;\n        evt.frequency = 1500.0f;\n        evt.duration = 0.12f;\n        evt.volume = 0.8f;\n        evt.duty = 0.5f;\n        return evt;\n    }\n\n    // Explosion\n    inline pr32::audio::AudioEvent explosion() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::NOISE;\n        evt.frequency = 200.0f;\n        evt.duration = 0.3f;\n        evt.volume = 0.9f;\n        return evt;\n    }\n\n    // Hit/damage\n    inline pr32::audio::AudioEvent hit() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::NOISE;\n        evt.frequency = 300.0f;\n        evt.duration = 0.15f;\n        evt.volume = 0.6f;\n        return evt;\n    }\n}\n\n// Usage\naudio.playEvent(SoundEffects::jump());\n
"},{"location":"manual/game_development/audio/#background-music","title":"Background Music","text":"

Background music uses the MusicPlayer system, which sequences notes over time.

"},{"location":"manual/game_development/audio/#music-notes","title":"Music Notes","text":"

Music is built from MusicNote structures:

#include <audio/AudioMusicTypes.h>\n\nusing namespace pr32::audio;\n\nMusicNote note{};\nnote.note = Note::C;        // Musical note (C, D, E, F, G, A, B, or Rest)\nnote.octave = 4;            // Octave (0-8)\nnote.duration = 0.2f;       // Duration in seconds\nnote.volume = 0.7f;         // Volume (0.0 to 1.0)\n
"},{"location":"manual/game_development/audio/#instrument-presets","title":"Instrument Presets","text":"

For convenience, use predefined instrument presets:

using namespace pr32::audio;\n\n// Available presets:\n// - INSTR_PULSE_LEAD: Main lead pulse (octave 4)\n// - INSTR_PULSE_BASS: Bass pulse (octave 3)\n// - INSTR_PULSE_CHIP_HIGH: High-pitched chiptune (octave 5)\n// - INSTR_TRIANGLE_PAD: Soft triangle pad (octave 4)\n
"},{"location":"manual/game_development/audio/#creating-a-melody","title":"Creating a Melody","text":"
#include <audio/AudioMusicTypes.h>\n\nusing namespace pr32::audio;\n\n// Define melody notes\nstatic const MusicNote MELODY_NOTES[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),  // Rest (silence)\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),\n};\n\n// Create music track\nstatic const MusicTrack GAME_MUSIC = {\n    MELODY_NOTES,                              // notes array\n    sizeof(MELODY_NOTES) / sizeof(MusicNote),  // note count\n    true,                                       // loop\n    WaveType::PULSE,                           // channel type\n    0.5f                                       // duty cycle\n};\n
"},{"location":"manual/game_development/audio/#playing-music","title":"Playing Music","text":"
// Get the music player\nauto& music = engine.getMusicPlayer();\n\n// Play a track\nmusic.play(GAME_MUSIC);\n\n// Control playback\nmusic.stop();   // Stop playback\nmusic.pause();  // Pause (time doesn't advance)\nmusic.resume(); // Resume after pause\n\n// Check status\nif (music.isPlaying()) {\n    // Music is currently playing\n}\n
"},{"location":"manual/game_development/audio/#music-in-scene","title":"Music in Scene","text":"

Typically, you start music in your scene's init():

void MyGameScene::init() override {\n    // Start background music\n    engine.getMusicPlayer().play(GAME_MUSIC);\n\n    // ... rest of initialization\n}\n
"},{"location":"manual/game_development/audio/#master-volume","title":"Master Volume","text":"

Control overall volume without changing individual sounds:

auto& audio = engine.getAudioEngine();\n\n// Set master volume (0.0 to 1.0)\naudio.setMasterVolume(0.5f); // 50% volume\n\n// Get current volume\nfloat currentVolume = audio.getMasterVolume();\n
"},{"location":"manual/game_development/audio/#complete-example","title":"Complete Example","text":"

Here's a complete example combining sound effects and music:

#include <core/Scene.h>\n#include <audio/AudioTypes.h>\n#include <audio/AudioMusicTypes.h>\n\nusing namespace pr32::audio;\n\n// Background music\nstatic const MusicNote GAME_MELODY[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),\n};\n\nstatic const MusicTrack BACKGROUND_MUSIC = {\n    GAME_MELODY,\n    sizeof(GAME_MELODY) / sizeof(MusicNote),\n    true,  // loop\n    WaveType::PULSE,\n    0.5f\n};\n\nclass AudioExampleScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Start background music\n        engine.getMusicPlayer().play(BACKGROUND_MUSIC);\n\n        // Set master volume\n        engine.getAudioEngine().setMasterVolume(0.8f);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        auto& audio = engine.getAudioEngine();\n\n        // Play sound effect on button press\n        if (input.isButtonPressed(4)) { // Button A\n            AudioEvent jumpSound{};\n            jumpSound.type = WaveType::PULSE;\n            jumpSound.frequency = 800.0f;\n            jumpSound.duration = 0.1f;\n            jumpSound.volume = 0.7f;\n            jumpSound.duty = 0.25f;\n\n            audio.playEvent(jumpSound);\n        }\n\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/audio/#designing-nes-like-sounds","title":"Designing NES-like Sounds","text":""},{"location":"manual/game_development/audio/#frequency-guidelines","title":"Frequency Guidelines","text":"
  • Low frequencies (200-400 Hz): Bass, impacts, explosions
  • Mid frequencies (400-1000 Hz): Main sounds, jumps, UI
  • High frequencies (1000-2000 Hz): Beeps, coins, pickups
  • Very high (2000+ Hz): Sharp sounds, alerts
"},{"location":"manual/game_development/audio/#duration-guidelines","title":"Duration Guidelines","text":"
  • Short (0.05-0.1s): UI clicks, small effects
  • Medium (0.1-0.2s): Jumps, hits, pickups
  • Long (0.2-0.5s): Explosions, power-ups, transitions
"},{"location":"manual/game_development/audio/#duty-cycle-pulse-only","title":"Duty Cycle (PULSE only)","text":"
  • 0.125: Thin, sharp, piercing
  • 0.25: Classic NES lead sound
  • 0.5: Symmetric, full, fat
  • 0.75: Very fat, bass-like
"},{"location":"manual/game_development/audio/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/audio/#sound-design","title":"Sound Design","text":"
  • Keep sounds short: Long sounds can overlap and cause issues
  • Use appropriate volumes: 0.6-0.8 is usually good for effects
  • Vary frequencies: Don't use the same frequency for everything
  • Test on hardware: ESP32 audio may sound different than PC
"},{"location":"manual/game_development/audio/#music","title":"Music","text":"
  • Use one channel for music: Leave other channels for SFX
  • Keep melodies simple: Complex melodies can be hard to follow
  • Loop seamlessly: End your melody where it can loop naturally
  • Consider tempo: Faster games need faster music
"},{"location":"manual/game_development/audio/#performance","title":"Performance","text":"
  • Limit simultaneous sounds: Only 4 channels total
  • Music uses one channel: Plan your SFX accordingly
  • Don't spam sounds: Too many sounds can cause audio glitches
  • Use master volume: Easier than adjusting individual sounds
"},{"location":"manual/game_development/audio/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/audio/#sound-effect-helper-function","title":"Sound Effect Helper Function","text":"
void playJumpSound() {\n    auto& audio = engine.getAudioEngine();\n    AudioEvent evt{};\n    evt.type = WaveType::PULSE;\n    evt.frequency = 600.0f;\n    evt.duration = 0.1f;\n    evt.volume = 0.7f;\n    evt.duty = 0.25f;\n    audio.playEvent(evt);\n}\n
"},{"location":"manual/game_development/audio/#music-state-management","title":"Music State Management","text":"
class GameScene : public Scene {\n    bool musicStarted = false;\n\n    void init() override {\n        // Don't start music here if scene can be re-initialized\n    }\n\n    void update(unsigned long deltaTime) override {\n        if (!musicStarted) {\n            engine.getMusicPlayer().play(GAME_MUSIC);\n            musicStarted = true;\n        }\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"manual/game_development/audio/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/game_development/audio/#no-sound","title":"No Sound","text":"
  • Check audio backend is configured correctly
  • Verify sample rate matches backend
  • Check master volume is not 0
  • Ensure audio is initialized (engine.init())
"},{"location":"manual/game_development/audio/#distorted-sound","title":"Distorted Sound","text":"
  • Lower volume levels
  • Reduce sample rate (ESP32 DAC works better at 11025 Hz)
  • Check for too many simultaneous sounds
  • Verify hardware connections (ESP32)
"},{"location":"manual/game_development/audio/#music-not-playing","title":"Music Not Playing","text":"
  • Check music.isPlaying() status
  • Ensure track is properly defined
  • Verify MusicPlayer is updated (happens automatically)
  • Check that music channel is not being used by SFX
"},{"location":"manual/game_development/audio/#next-steps","title":"Next Steps","text":"

Now that you can add audio, learn about: - NES Audio Reference - Advanced audio techniques - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs

See also: - API Reference - AudioEngine - API Reference - MusicPlayer - API Reference - Audio Types - Manual - Audio Overview

"},{"location":"manual/game_development/basic_rendering/","title":"Basic Rendering","text":"

Rendering is how you draw everything on screen. This guide covers the fundamental drawing operations in PixelRoot32: primitives, sprites, and text.

"},{"location":"manual/game_development/basic_rendering/#accessing-the-renderer","title":"Accessing the Renderer","text":"

You can access the renderer in two ways:

"},{"location":"manual/game_development/basic_rendering/#from-the-engine","title":"From the Engine","text":"
auto& renderer = engine.getRenderer();\n
"},{"location":"manual/game_development/basic_rendering/#from-a-scene","title":"From a Scene","text":"
void MyScene::draw(pixelroot32::graphics::Renderer& renderer) override {\n    // renderer is passed as parameter\n    // Drawing covers the entire logical screen (e.g., 128x128)\n    renderer.drawFilledRectangle(0, 0, renderer.getLogicalWidth(), renderer.getLogicalHeight(), Color::Black);\n}\n
"},{"location":"manual/game_development/basic_rendering/#drawing-primitives","title":"Drawing Primitives","text":""},{"location":"manual/game_development/basic_rendering/#pixels","title":"Pixels","text":"

Draw a single pixel:

renderer.drawPixel(100, 100, pixelroot32::graphics::Color::White);\n
"},{"location":"manual/game_development/basic_rendering/#lines","title":"Lines","text":"

Draw a line between two points:

renderer.drawLine(10, 10, 200, 200, pixelroot32::graphics::Color::Red);\n
"},{"location":"manual/game_development/basic_rendering/#rectangles","title":"Rectangles","text":"

Draw a rectangle outline:

renderer.drawRectangle(50, 50, 100, 80, pixelroot32::graphics::Color::Blue);\n

Draw a filled rectangle:

renderer.drawFilledRectangle(50, 50, 100, 80, pixelroot32::graphics::Color::Blue);\n
"},{"location":"manual/game_development/basic_rendering/#circles","title":"Circles","text":"

Draw a circle outline:

renderer.drawCircle(120, 120, 30, pixelroot32::graphics::Color::Green);\n

Draw a filled circle:

renderer.drawFilledCircle(120, 120, 30, pixelroot32::graphics::Color::Green);\n
"},{"location":"manual/game_development/basic_rendering/#simple-sprites-1bpp","title":"Simple Sprites (1bpp)","text":"

Sprites are the primary way to draw game graphics. The standard format is 1bpp (1 bit per pixel), which is memory-efficient and perfect for retro-style graphics.

"},{"location":"manual/game_development/basic_rendering/#creating-a-sprite-manually","title":"Creating a Sprite Manually","text":"

A 1bpp sprite is defined as an array of uint16_t, where each value represents one row:

#include <graphics/Renderer.h>\n\n// Example: 8x8 sprite (8 rows, each row is a uint16_t)\n// Bit 0 = leftmost pixel, bit 7 = rightmost pixel\nstatic const uint16_t MY_SPRITE_DATA[] = {\n    0b00111100,  // Row 0:   ..####..\n    0b01111110,  // Row 1:  .######.\n    0b11111111,  // Row 2:  ########\n    0b11111111,  // Row 3:  ########\n    0b11111111,  // Row 4:  ########\n    0b01111110,  // Row 5:  .######.\n    0b00111100,  // Row 6:   ..####..\n    0b00000000   // Row 7:  ........\n};\n\n// Create sprite descriptor\nstatic const pixelroot32::graphics::Sprite MY_SPRITE = {\n    MY_SPRITE_DATA,  // data pointer\n    8,                // width\n    8                 // height\n};\n
"},{"location":"manual/game_development/basic_rendering/#drawing-a-sprite","title":"Drawing a Sprite","text":"
renderer.drawSprite(\n    MY_SPRITE,                                    // sprite\n    100,                                          // x position\n    100,                                          // y position\n    pixelroot32::graphics::Color::White,         // color\n    false                                         // flipX (optional, default false)\n);\n
"},{"location":"manual/game_development/basic_rendering/#sprite-bit-convention","title":"Sprite Bit Convention","text":"
  • Each uint16_t represents one row
  • Bit 0 (rightmost bit) = leftmost pixel
  • Bit (width - 1) = rightmost pixel
  • 0 = transparent/off, 1 = on (colored)

Example: For an 8-pixel wide sprite:

Row value: 0b00111100\nPixels:    ..####..\n           ^      ^\n         bit 7  bit 0 (leftmost)\n

"},{"location":"manual/game_development/basic_rendering/#flipping-sprites","title":"Flipping Sprites","text":"

You can flip a sprite horizontally:

renderer.drawSprite(MY_SPRITE, 100, 100, Color::White, true); // flipped\n
"},{"location":"manual/game_development/basic_rendering/#text-rendering","title":"Text Rendering","text":"

PixelRoot32 uses a native bitmap font system for pixel-perfect text rendering.

"},{"location":"manual/game_development/basic_rendering/#drawing-text","title":"Drawing Text","text":"
renderer.drawText(\n    \"Hello World!\",                           // text string\n    10,                                       // x position\n    20,                                       // y position\n    pixelroot32::graphics::Color::White,     // color\n    1                                         // size multiplier (1=normal, 2=double, etc.)\n);\n
"},{"location":"manual/game_development/basic_rendering/#centered-text","title":"Centered Text","text":"
renderer.drawTextCentered(\n    \"Game Over\",                              // text\n    120,                                      // y position (centered horizontally)\n    pixelroot32::graphics::Color::Red,       // color\n    2                                         // size\n);\n
"},{"location":"manual/game_development/basic_rendering/#text-size","title":"Text Size","text":"

The size parameter multiplies the font size: - 1 = normal size (5x7 pixels per character with default font) - 2 = double size (10x14 pixels) - 3 = triple size (15x21 pixels) - etc.

"},{"location":"manual/game_development/basic_rendering/#supported-characters","title":"Supported Characters","text":"

The default font (FONT_5X7) supports ASCII characters 32-126: - Letters: A-Z, a-z - Numbers: 0-9 - Symbols: !@#$%^&*()_+-=[]{}|;:'\",.<>?/ etc.

"},{"location":"manual/game_development/basic_rendering/#render-layers","title":"Render Layers","text":"

Entities are drawn in order based on their renderLayer property:

  • Layer 0 (Background): Drawn first (behind everything)
  • Layer 1 (Gameplay): Drawn second (main game objects)
  • Layer 2 (UI): Drawn last (on top of everything)

Set the render layer when creating an entity:

myEntity->setRenderLayer(0); // Background\nmyEntity->setRenderLayer(1); // Gameplay (default)\nmyEntity->setRenderLayer(2); // UI\n
"},{"location":"manual/game_development/basic_rendering/#complete-example","title":"Complete Example","text":"

Here's a complete example that draws various primitives and a sprite:

#include <core/Scene.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\n// Simple sprite data (8x8 circle)\nstatic const uint16_t CIRCLE_SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b01111110,\n    0b00111100\n};\n\nstatic const pixelroot32::graphics::Sprite CIRCLE_SPRITE = {\n    CIRCLE_SPRITE_DATA,\n    8,\n    8\n};\n\nclass RenderingExampleScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Set palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::NES\n        );\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background (layer 0)\n        renderer.drawFilledRectangle(0, 0, 240, 240, \n            pixelroot32::graphics::Color::Navy);\n\n        // Draw primitives (layer 1)\n        renderer.drawRectangle(10, 10, 100, 80, \n            pixelroot32::graphics::Color::White);\n        renderer.drawFilledCircle(120, 120, 30, \n            pixelroot32::graphics::Color::Red);\n        renderer.drawLine(0, 0, 240, 240, \n            pixelroot32::graphics::Color::Yellow);\n\n        // Draw sprite\n        renderer.drawSprite(CIRCLE_SPRITE, 50, 50, \n            pixelroot32::graphics::Color::Cyan);\n\n        // Draw text (layer 2 - UI)\n        renderer.drawText(\"Score: 100\", 10, 10, \n            pixelroot32::graphics::Color::White, 1);\n        renderer.drawTextCentered(\"Rendering Demo\", 200, \n            pixelroot32::graphics::Color::Yellow, 2);\n\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/basic_rendering/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/basic_rendering/#performance","title":"Performance","text":"
  • Minimize draw calls: Batch similar operations when possible
  • Use render layers efficiently: Don't mix layers unnecessarily
  • Avoid drawing off-screen: Check bounds before drawing
  • Reuse sprites: Define sprites once, use many times
"},{"location":"manual/game_development/basic_rendering/#organization","title":"Organization","text":"
  • Define sprites as static const: Keep them in flash memory
  • Use meaningful names: Name your sprites clearly
  • Group related sprites: Organize sprite data logically
  • Document complex sprites: Comment sprite bit patterns if needed
"},{"location":"manual/game_development/basic_rendering/#text","title":"Text","text":"
  • Avoid frequent text updates: Text rendering has overhead
  • Use appropriate sizes: Larger text uses more memory
  • Cache text dimensions: Use FontManager::textWidth() if needed
  • Keep text simple: Complex formatting is not supported
"},{"location":"manual/game_development/basic_rendering/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/basic_rendering/#drawing-a-background","title":"Drawing a Background","text":"
void drawBackground(Renderer& renderer) {\n    // Solid color background\n    renderer.drawFilledRectangle(0, 0, 240, 240, Color::Black);\n\n    // Or use a tilemap (see Advanced Graphics section)\n}\n
"},{"location":"manual/game_development/basic_rendering/#drawing-a-hud","title":"Drawing a HUD","text":"
void drawHUD(Renderer& renderer, int score, int lives) {\n    char buffer[32];\n    snprintf(buffer, sizeof(buffer), \"Score: %d\", score);\n    renderer.drawText(buffer, 10, 10, Color::White, 1);\n\n    snprintf(buffer, sizeof(buffer), \"Lives: %d\", lives);\n    renderer.drawText(buffer, 10, 20, Color::White, 1);\n}\n
"},{"location":"manual/game_development/basic_rendering/#drawing-multiple-sprites","title":"Drawing Multiple Sprites","text":"
void drawSpriteArray(Renderer& renderer, const Sprite& sprite, \n                     int count, int startX, int startY, int spacing) {\n    for (int i = 0; i < count; i++) {\n        int x = startX + (i * (sprite.width + spacing));\n        renderer.drawSprite(sprite, x, startY, Color::White);\n    }\n}\n
"},{"location":"manual/game_development/basic_rendering/#next-steps","title":"Next Steps","text":"

Now that you can draw basic graphics, learn about: - Sprites and Animation - Advanced sprite techniques - Input and Control - Make your game interactive - Palettes - Use different color schemes

See also: - API Reference - Renderer - API Reference - Sprite - Render Layers

"},{"location":"manual/game_development/input_and_control/","title":"Input and Control","text":"

Handling user input is essential for any interactive game. This guide covers how to read and process input from buttons (ESP32) or keyboard (Native) in PixelRoot32.

"},{"location":"manual/game_development/input_and_control/#input-configuration","title":"Input Configuration","text":"

Before you can read input, you need to configure the InputManager. This is done when creating the Engine:

"},{"location":"manual/game_development/input_and_control/#esp32-configuration","title":"ESP32 Configuration","text":"
#include <input/InputConfig.h>\n\n// InputConfig(buttonCount, UP, DOWN, LEFT, RIGHT, A, B)\npr32::input::InputConfig inputConfig(\n    6,      // Total number of buttons\n    32,     // UP button GPIO pin\n    27,     // DOWN button GPIO pin\n    33,     // LEFT button GPIO pin\n    14,     // RIGHT button GPIO pin\n    13,     // A button GPIO pin\n    12      // B button GPIO pin\n);\n
"},{"location":"manual/game_development/input_and_control/#native-pc-configuration","title":"Native (PC) Configuration","text":"
#include <SDL2/SDL.h>\n#include <input/InputConfig.h>\n\n// InputConfig(buttonCount, UP, DOWN, LEFT, RIGHT, A, B)\npr32::input::InputConfig inputConfig(\n    6,                      // Total number of buttons\n    SDL_SCANCODE_UP,        // UP key\n    SDL_SCANCODE_DOWN,      // DOWN key\n    SDL_SCANCODE_LEFT,      // LEFT key\n    SDL_SCANCODE_RIGHT,     // RIGHT key\n    SDL_SCANCODE_SPACE,     // A button (Space)\n    SDL_SCANCODE_RETURN     // B button (Enter)\n);\n
"},{"location":"manual/game_development/input_and_control/#reading-input","title":"Reading Input","text":"

Access the InputManager through the Engine:

auto& input = engine.getInputManager();\n
"},{"location":"manual/game_development/input_and_control/#input-states","title":"Input States","text":"

The InputManager provides four different ways to check button state:

"},{"location":"manual/game_development/input_and_control/#1-isbuttonpressed","title":"1. isButtonPressed()","text":"

Returns true only on the frame when the button was just pressed:

if (input.isButtonPressed(4)) { // Button A (index 4)\n    // This code runs only once when button is first pressed\n    jump();\n}\n

Use for: Actions that should trigger once per press (jump, shoot, select menu item).

"},{"location":"manual/game_development/input_and_control/#2-isbuttonreleased","title":"2. isButtonReleased()","text":"

Returns true only on the frame when the button was just released:

if (input.isButtonReleased(4)) {\n    // This code runs only once when button is released\n    stopCharging();\n}\n

Use for: Actions that trigger on release (charge attacks, menu confirmation).

"},{"location":"manual/game_development/input_and_control/#3-isbuttondown","title":"3. isButtonDown()","text":"

Returns true while the button is currently held down:

if (input.isButtonDown(2)) { // LEFT button (index 2)\n    // This code runs every frame while button is held\n    playerX -= speed * (deltaTime * 0.001f);\n}\n

Use for: Continuous actions (movement, holding, charging).

"},{"location":"manual/game_development/input_and_control/#4-isbuttonclicked","title":"4. isButtonClicked()","text":"

Returns true when the button was pressed and then released:

if (input.isButtonClicked(4)) {\n    // This code runs once per click (press + release cycle)\n    toggleMenu();\n}\n

Use for: Toggle actions, menu selections, click interactions.

"},{"location":"manual/game_development/input_and_control/#button-indices","title":"Button Indices","text":"

The button indices correspond to the order in InputConfig:

  • Index 0: UP
  • Index 1: DOWN
  • Index 2: LEFT
  • Index 3: RIGHT
  • Index 4: A button
  • Index 5: B button

For convenience, you can define constants:

namespace Buttons {\n    constexpr uint8_t UP = 0;\n    constexpr uint8_t DOWN = 1;\n    constexpr uint8_t LEFT = 2;\n    constexpr uint8_t RIGHT = 3;\n    constexpr uint8_t A = 4;\n    constexpr uint8_t B = 5;\n}\n\n// Usage\nif (input.isButtonPressed(Buttons::A)) {\n    // ...\n}\n
"},{"location":"manual/game_development/input_and_control/#character-control-example","title":"Character Control Example","text":"

Here's a complete example of character movement:

#include <core/Actor.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass PlayerActor : public pixelroot32::core::Actor {\npublic:\n    float speed = 100.0f; // pixels per second\n\n    PlayerActor(float x, float y)\n        : Actor(x, y, 16, 16) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f; // Convert to seconds\n\n        // Horizontal movement\n        if (input.isButtonDown(Buttons::LEFT)) {\n            x -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::RIGHT)) {\n            x += speed * dt;\n        }\n\n        // Vertical movement\n        if (input.isButtonDown(Buttons::UP)) {\n            y -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::DOWN)) {\n            y += speed * dt;\n        }\n\n        // Keep player on screen\n        if (x < 0) x = 0;\n        if (x > 224) x = 224;\n        if (y < 0) y = 0;\n        if (y > 224) y = 224;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width,\n            height,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collisions\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#jumping-example","title":"Jumping Example","text":"

For platformer-style jumping:

class PlatformerPlayer : public pixelroot32::core::PhysicsActor {\npublic:\n    bool canJump = true;\n    float jumpForce = 200.0f;\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        // Horizontal movement\n        float moveSpeed = 80.0f;\n        if (input.isButtonDown(Buttons::LEFT)) {\n            setVelocity(-moveSpeed, vy);\n        } else if (input.isButtonDown(Buttons::RIGHT)) {\n            setVelocity(moveSpeed, vy);\n        } else {\n            setVelocity(0, vy);\n        }\n\n        // Jump (only on press, and only if on ground)\n        if (input.isButtonPressed(Buttons::A) && canJump) {\n            setVelocity(vx, -jumpForce);\n            canJump = false;\n        }\n\n        // Check if on ground (for jump reset)\n        auto collisionInfo = getWorldCollisionInfo();\n        if (collisionInfo.bottom) {\n            canJump = true;\n        }\n\n        PhysicsActor::update(deltaTime);\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#shooting-example","title":"Shooting Example","text":"

For shooting projectiles:

class ShooterActor : public pixelroot32::core::Actor {\nprivate:\n    bool fireInputReady = true;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n\n        // Shooting (with cooldown)\n        if (input.isButtonPressed(Buttons::A) && fireInputReady) {\n            shoot();\n            fireInputReady = false;\n        }\n\n        // Reset fire input when button is released\n        if (input.isButtonReleased(Buttons::A)) {\n            fireInputReady = true;\n        }\n    }\n\n    void shoot() {\n        // Create projectile\n        // ...\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#menu-navigation-example","title":"Menu Navigation Example","text":"

For menu navigation:

class MenuScene : public pixelroot32::core::Scene {\nprivate:\n    int selectedIndex = 0;\n    static const int MENU_ITEMS = 3;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n\n        // Navigate menu\n        if (input.isButtonPressed(Buttons::UP)) {\n            selectedIndex--;\n            if (selectedIndex < 0) selectedIndex = MENU_ITEMS - 1;\n        }\n\n        if (input.isButtonPressed(Buttons::DOWN)) {\n            selectedIndex++;\n            if (selectedIndex >= MENU_ITEMS) selectedIndex = 0;\n        }\n\n        // Select menu item\n        if (input.isButtonPressed(Buttons::A)) {\n            selectMenuItem(selectedIndex);\n        }\n\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/input_and_control/#frame-rate-independence","title":"Frame-Rate Independence","text":"

Always multiply movement by delta time:

// \u2705 GOOD: Framerate-independent\nx += speed * (deltaTime * 0.001f);\n\n// \u274c BAD: Framerate-dependent\nx += speed;\n
"},{"location":"manual/game_development/input_and_control/#input-debouncing","title":"Input Debouncing","text":"

For actions that should only trigger once:

// Use isButtonPressed() instead of isButtonDown()\nif (input.isButtonPressed(Buttons::A)) {\n    // Triggers once per press\n}\n
"},{"location":"manual/game_development/input_and_control/#input-buffering","title":"Input Buffering","text":"

For responsive controls, you can buffer input:

class InputBuffer {\n    uint8_t bufferedInput = 0;\n\npublic:\n    void update(const InputManager& input) {\n        if (input.isButtonPressed(Buttons::A)) {\n            bufferedInput = Buttons::A;\n        }\n    }\n\n    bool hasBufferedInput() const { return bufferedInput != 0; }\n    uint8_t consumeInput() {\n        uint8_t result = bufferedInput;\n        bufferedInput = 0;\n        return result;\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#multiple-input-methods","title":"Multiple Input Methods","text":"

Support both button presses and held buttons:

// Allow both tap and hold for rapid fire\nif (input.isButtonPressed(Buttons::A) || \n    (input.isButtonDown(Buttons::A) && rapidFireTimer <= 0)) {\n    shoot();\n    rapidFireTimer = RAPID_FIRE_DELAY;\n}\n
"},{"location":"manual/game_development/input_and_control/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/input_and_control/#directional-input","title":"Directional Input","text":"
float getHorizontalInput() {\n    auto& input = engine.getInputManager();\n    float dir = 0.0f;\n    if (input.isButtonDown(Buttons::LEFT)) dir -= 1.0f;\n    if (input.isButtonDown(Buttons::RIGHT)) dir += 1.0f;\n    return dir;\n}\n\nfloat getVerticalInput() {\n    auto& input = engine.getInputManager();\n    float dir = 0.0f;\n    if (input.isButtonDown(Buttons::UP)) dir -= 1.0f;\n    if (input.isButtonDown(Buttons::DOWN)) dir += 1.0f;\n    return dir;\n}\n
"},{"location":"manual/game_development/input_and_control/#input-state-machine","title":"Input State Machine","text":"

For complex input handling:

enum class InputState {\n    IDLE,\n    PRESSED,\n    HELD,\n    RELEASED\n};\n\nInputState getButtonState(const InputManager& input, uint8_t button) {\n    if (input.isButtonPressed(button)) return InputState::PRESSED;\n    if (input.isButtonDown(button)) return InputState::HELD;\n    if (input.isButtonReleased(button)) return InputState::RELEASED;\n    return InputState::IDLE;\n}\n
"},{"location":"manual/game_development/input_and_control/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/game_development/input_and_control/#button-not-responding","title":"Button Not Responding","text":"
  • Check button indices match your InputConfig
  • Verify GPIO pins (ESP32) or scancodes (Native) are correct
  • Ensure InputManager is being updated (happens automatically in Engine)
"},{"location":"manual/game_development/input_and_control/#input-feels-laggy","title":"Input Feels Laggy","text":"
  • Ensure you're using deltaTime for movement
  • Check that input is read in update(), not draw()
  • Verify framerate is stable
"},{"location":"manual/game_development/input_and_control/#multiple-triggers","title":"Multiple Triggers","text":"
  • Use isButtonPressed() instead of isButtonDown() for one-time actions
  • Implement input buffering or cooldown timers
"},{"location":"manual/game_development/input_and_control/#next-steps","title":"Next Steps","text":"

Now that you can handle input, learn about: - Audio - Add sound effects and music - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs

See also: - API Reference - InputManager - API Reference - InputConfig - Manual - Input Overview

"},{"location":"manual/game_development/physics_and_collisions/","title":"Physics and Collisions","text":"

PixelRoot32 provides a physics system for moving objects and collision detection. This guide covers PhysicsActor for automatic physics and the collision system for detecting interactions between objects.

"},{"location":"manual/game_development/physics_and_collisions/#physicsactor","title":"PhysicsActor","text":"

A PhysicsActor is an Actor that automatically handles physics: velocity, gravity, friction, and world boundary collisions.

"},{"location":"manual/game_development/physics_and_collisions/#creating-a-physicsactor","title":"Creating a PhysicsActor","text":"
#include <core/PhysicsActor.h>\n\nclass Ball : public pixelroot32::core::PhysicsActor {\npublic:\n    Ball(float x, float y, float radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRenderLayer(1);\n\n        // Set physics properties\n        setRestitution(0.8f);  // Bounciness (0.8 = 80% bounce)\n        setFriction(0.1f);     // Friction (0.1 = slight friction)\n\n        // Set world boundaries\n        setWorldSize(240, 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Apply gravity\n        // (PhysicsActor handles this automatically, but you can add custom forces)\n\n        // Call parent update to apply physics\n        PhysicsActor::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        int radius = width / 2;\n        renderer.drawFilledCircle(\n            static_cast<int>(x + radius),\n            static_cast<int>(y + radius),\n            radius,\n            pixelroot32::graphics::Color::White\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collision with other actors\n    }\n\n    void onWorldCollision() override {\n        // Called when hitting world boundaries\n        // You can play a sound effect here, for example\n    }\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#physics-properties","title":"Physics Properties","text":""},{"location":"manual/game_development/physics_and_collisions/#velocity","title":"Velocity","text":"

Set the velocity directly:

ball->setVelocity(100.0f, -50.0f); // Move right at 100 px/s, up at 50 px/s\n

Or modify existing velocity:

float vx = ball->vx; // Access velocity components (protected, use getter if needed)\nball->setVelocity(vx + 10.0f, ball->vy); // Accelerate horizontally\n
"},{"location":"manual/game_development/physics_and_collisions/#restitution-bounciness","title":"Restitution (Bounciness)","text":"

Controls how much energy is conserved in collisions:

ball->setRestitution(1.0f);  // Perfect bounce (no energy loss)\nball->setRestitution(0.5f);  // 50% energy loss\nball->setRestitution(0.0f);  // No bounce (stops on impact)\n
"},{"location":"manual/game_development/physics_and_collisions/#friction","title":"Friction","text":"

Applies gradual velocity reduction:

ball->setFriction(0.0f);  // No friction (slides forever)\nball->setFriction(0.5f);  // Moderate friction\nball->setFriction(1.0f);  // High friction (stops quickly)\n
"},{"location":"manual/game_development/physics_and_collisions/#world-boundaries","title":"World Boundaries","text":"

Set the playable area:

// Set world size (used as default boundaries)\nball->setWorldSize(240, 240);\n\n// Or set custom boundaries\npixelroot32::core::LimitRect limits(10, 10, 230, 230); // Left, Top, Right, Bottom\nball->setLimits(limits);\n
"},{"location":"manual/game_development/physics_and_collisions/#world-collision-detection","title":"World Collision Detection","text":"

Check if the actor hit world boundaries:

void update(unsigned long deltaTime) override {\n    PhysicsActor::update(deltaTime);\n\n    auto collisionInfo = getWorldCollisionInfo();\n\n    if (collisionInfo.left || collisionInfo.right) {\n        // Hit side walls\n    }\n\n    if (collisionInfo.top || collisionInfo.bottom) {\n        // Hit top/bottom walls\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#collision-system","title":"Collision System","text":"

The collision system detects when Actors overlap and triggers callbacks.

"},{"location":"manual/game_development/physics_and_collisions/#collision-layers","title":"Collision Layers","text":"

Use bit flags to organize actors into groups:

// Define layers (typically in GameLayers.h)\nnamespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;    // Bit 0\n    constexpr uint16_t ENEMY = 0x0002;     // Bit 1\n    constexpr uint16_t PROJECTILE = 0x0004; // Bit 2\n    constexpr uint16_t WALL = 0x0008;      // Bit 3\n    constexpr uint16_t PICKUP = 0x0010;    // Bit 4\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#setting-up-collisions","title":"Setting Up Collisions","text":"

Configure each actor's collision layer and mask:

class PlayerActor : public pixelroot32::core::Actor {\npublic:\n    PlayerActor(float x, float y)\n        : Actor(x, y, 16, 16) {\n        // This actor belongs to the PLAYER layer\n        setCollisionLayer(Layers::PLAYER);\n\n        // This actor can collide with ENEMY, WALL, and PICKUP\n        setCollisionMask(Layers::ENEMY | Layers::WALL | Layers::PICKUP);\n    }\n\n    // ... rest of implementation\n};\n\nclass EnemyActor : public pixelroot32::core::Actor {\npublic:\n    EnemyActor(float x, float y)\n        : Actor(x, y, 16, 16) {\n        // This actor belongs to the ENEMY layer\n        setCollisionLayer(Layers::ENEMY);\n\n        // This actor can collide with PLAYER and PROJECTILE\n        setCollisionMask(Layers::PLAYER | Layers::PROJECTILE);\n    }\n\n    // ... rest of implementation\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#collision-detection","title":"Collision Detection","text":"

Collisions are automatically detected by the Scene's CollisionSystem. You handle collisions in onCollision():

void PlayerActor::onCollision(pixelroot32::core::Actor* other) override {\n    // Check what we collided with\n    if (other->isInLayer(Layers::ENEMY)) {\n        // Hit an enemy - take damage\n        takeDamage();\n    } else if (other->isInLayer(Layers::PICKUP)) {\n        // Hit a pickup - collect it\n        collectPickup(other);\n    } else if (other->isInLayer(Layers::WALL)) {\n        // Hit a wall - stop movement\n        stopMovement();\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#hitbox","title":"Hitbox","text":"

Define the collision shape:

pixelroot32::core::Rect getHitBox() override {\n    // Simple AABB (Axis-Aligned Bounding Box)\n    return {x, y, width, height};\n\n    // Or use a smaller hitbox for more forgiving collisions\n    // return {x + 2, y + 2, width - 4, height - 4};\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#complete-example-bouncing-ball","title":"Complete Example: Bouncing Ball","text":"
#include <core/PhysicsActor.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass BouncingBall : public pixelroot32::core::PhysicsActor {\npublic:\n    BouncingBall(float x, float y, float radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRenderLayer(1);\n\n        // Physics setup\n        setRestitution(0.9f);  // Very bouncy\n        setFriction(0.05f);    // Low friction\n        setWorldSize(240, 240); // World boundaries\n\n        // Initial velocity\n        setVelocity(50.0f, -30.0f);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Apply gravity\n        float gravity = 200.0f; // pixels per second squared\n        float dt = deltaTime * 0.001f;\n        setVelocity(vx, vy + gravity * dt);\n\n        // Update physics\n        PhysicsActor::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        int radius = width / 2;\n        renderer.drawFilledCircle(\n            static_cast<int>(x + radius),\n            static_cast<int>(y + radius),\n            radius,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Bounce off other objects\n        // (PhysicsActor handles world boundaries automatically)\n    }\n\n    void onWorldCollision() override {\n        // Play bounce sound when hitting walls\n        // (Implementation depends on your audio setup)\n    }\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#complete-example-platformer-player","title":"Complete Example: Platformer Player","text":"
class PlatformerPlayer : public pixelroot32::core::PhysicsActor {\nprivate:\n    bool onGround = false;\n    float jumpForce = 250.0f;\n    float moveSpeed = 100.0f;\n\npublic:\n    PlatformerPlayer(float x, float y)\n        : PhysicsActor(x, y, 16, 16) {\n        setRenderLayer(1);\n        setFriction(0.3f);  // Ground friction\n        setWorldSize(240, 240);\n\n        // Collision setup\n        setCollisionLayer(Layers::PLAYER);\n        setCollisionMask(Layers::ENEMY | Layers::PLATFORM);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        // Horizontal movement\n        float moveDir = 0.0f;\n        if (input.isButtonDown(Buttons::LEFT)) moveDir -= 1.0f;\n        if (input.isButtonDown(Buttons::RIGHT)) moveDir += 1.0f;\n\n        setVelocity(moveDir * moveSpeed, vy);\n\n        // Apply gravity\n        float gravity = 300.0f;\n        setVelocity(vx, vy + gravity * dt);\n\n        // Jump\n        if (input.isButtonPressed(Buttons::A) && onGround) {\n            setVelocity(vx, -jumpForce);\n            onGround = false;\n        }\n\n        // Update physics\n        PhysicsActor::update(deltaTime);\n\n        // Check if on ground\n        auto collisionInfo = getWorldCollisionInfo();\n        onGround = collisionInfo.bottom;\n\n        // Also check collision with platforms\n        // (This would be handled in onCollision)\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        if (other->isInLayer(Layers::PLATFORM)) {\n            // Land on platform\n            auto platformRect = other->getHitBox();\n            if (y + height <= platformRect.y + 5) { // Within 5 pixels of top\n                y = platformRect.y - height;\n                vy = 0;\n                onGround = true;\n            }\n        } else if (other->isInLayer(Layers::ENEMY)) {\n            // Hit enemy\n            takeDamage();\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width,\n            height,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#sweep-tests","title":"Sweep Tests","text":"

For fast-moving projectiles, use sweep tests to detect collisions between positions:

#include <physics/CollisionPrimitives.h>\n\nbool checkProjectileHit(PhysicsActor* projectile, Actor* target) {\n    // Get previous and current positions\n    float prevX = projectile->x - (projectile->vx * deltaTime * 0.001f);\n    float prevY = projectile->y - (projectile->vy * deltaTime * 0.001f);\n\n    // Create circles for sweep test\n    pixelroot32::physics::Circle startCircle;\n    startCircle.x = prevX + projectile->width / 2;\n    startCircle.y = prevY + projectile->height / 2;\n    startCircle.radius = projectile->width / 2;\n\n    pixelroot32::physics::Circle endCircle;\n    endCircle.x = projectile->x + projectile->width / 2;\n    endCircle.y = projectile->y + projectile->height / 2;\n    endCircle.radius = projectile->width / 2;\n\n    // Get target rectangle\n    auto targetRect = target->getHitBox();\n\n    // Perform sweep test\n    float tHit;\n    if (pixelroot32::physics::sweepCircleVsRect(\n        startCircle, endCircle, targetRect, tHit)) {\n        // Collision detected at time tHit (0.0 = at start, 1.0 = at end)\n        return true;\n    }\n\n    return false;\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/physics_and_collisions/#collision-layers_1","title":"Collision Layers","text":"
  • Plan your layers: Design the layer system before coding
  • Use bit flags: Makes combining layers easy with | operator
  • Keep it simple: Don't create too many layers
  • Document layers: Create a GameLayers.h file with all definitions
"},{"location":"manual/game_development/physics_and_collisions/#physics","title":"Physics","text":"
  • Use appropriate values: Test gravity, speed, and forces
  • Frame-rate independence: Always use deltaTime
  • Limit world size: Keep boundaries reasonable
  • Test on hardware: Physics may behave differently on ESP32 vs PC
"},{"location":"manual/game_development/physics_and_collisions/#performance","title":"Performance","text":"
  • Limit active actors: Fewer actors = faster collision checks
  • Use layers efficiently: Reduce unnecessary collision pairs
  • Simple hitboxes: AABB is fast, complex shapes are slow
  • Sweep tests sparingly: Only for fast-moving objects
"},{"location":"manual/game_development/physics_and_collisions/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/physics_and_collisions/#collision-layer-helper","title":"Collision Layer Helper","text":"
namespace CollisionLayers {\n    constexpr uint16_t PLAYER = 0x0001;\n    constexpr uint16_t ENEMY = 0x0002;\n    constexpr uint16_t PROJECTILE = 0x0004;\n    constexpr uint16_t WALL = 0x0008;\n    constexpr uint16_t PICKUP = 0x0010;\n\n    // Helper to check if actor is in specific layer\n    bool isPlayer(Actor* actor) {\n        return actor->isInLayer(PLAYER);\n    }\n\n    bool isEnemy(Actor* actor) {\n        return actor->isInLayer(ENEMY);\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#platform-collision","title":"Platform Collision","text":"
void PlatformerPlayer::onCollision(Actor* other) override {\n    if (other->isInLayer(Layers::PLATFORM)) {\n        auto platform = other->getHitBox();\n\n        // Check if landing on top of platform\n        float playerBottom = y + height;\n        float platformTop = platform.y;\n\n        if (playerBottom <= platformTop + 5 && vy > 0) {\n            // Land on platform\n            y = platformTop - height;\n            vy = 0;\n            onGround = true;\n        }\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/game_development/physics_and_collisions/#collisions-not-detected","title":"Collisions Not Detected","text":"
  • Verify collision layers and masks overlap
  • Check that actors are added to the scene
  • Ensure Scene::update() is called
  • Verify hitboxes are correct
"},{"location":"manual/game_development/physics_and_collisions/#physics-too-fastslow","title":"Physics Too Fast/Slow","text":"
  • Adjust values based on deltaTime
  • Check gravity and velocity values
  • Test on actual hardware (ESP32 may run slower)
"},{"location":"manual/game_development/physics_and_collisions/#objects-passing-through","title":"Objects Passing Through","text":"
  • Use sweep tests for fast objects
  • Increase collision detection frequency
  • Check hitbox sizes match visual size
"},{"location":"manual/game_development/physics_and_collisions/#next-steps","title":"Next Steps","text":"

Now that you understand physics and collisions, learn about: - User Interface - Create menus and HUDs - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels

See also: - API Reference - PhysicsActor - API Reference - CollisionSystem - Manual - Physics Overview - Manual - Collision Detection

"},{"location":"manual/game_development/scenes_and_entities/","title":"Scenes and Entities","text":"

Scenes and entities are the foundation of every PixelRoot32 game. This guide teaches you how to organize your game using scenes and create interactive game objects with entities.

"},{"location":"manual/game_development/scenes_and_entities/#creating-a-scene","title":"Creating a Scene","text":"

A Scene represents a screen or level in your game. To create a scene, inherit from pixelroot32::core::Scene and implement the three main methods:

#include <core/Scene.h>\n#include <graphics/Renderer.h>\n\nclass MyGameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Called once when the scene is initialized\n        // Set up your scene here: create entities, load resources, etc.\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Called every frame\n        // Update game logic here\n\n        // IMPORTANT: Always call parent update to update all entities\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Called every frame to draw\n        // Draw your scene here\n\n        // IMPORTANT: Always call parent draw to draw all entities\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#scene-lifecycle","title":"Scene Lifecycle","text":"
  1. init(): Called once when the scene is set as active
  2. Create and initialize entities
  3. Set up game state
  4. Load resources
  5. Configure palettes, audio, etc.

  6. update(deltaTime): Called every frame

  7. Process input
  8. Update game logic
  9. Handle collisions
  10. Must call Scene::update(deltaTime) to update all entities

  11. draw(renderer): Called every frame

  12. Draw background elements
  13. Draw UI elements
  14. Must call Scene::draw(renderer) to draw all entities
"},{"location":"manual/game_development/scenes_and_entities/#basic-entities","title":"Basic Entities","text":"

An Entity is any object in your game. To create an entity, inherit from pixelroot32::core::Entity:

#include <core/Entity.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass SimpleEntity : public pixelroot32::core::Entity {\npublic:\n    SimpleEntity(float x, float y)\n        : Entity(x, y, 16, 16, pixelroot32::core::EntityType::GENERIC) {\n        // Set render layer (0=background, 1=gameplay, 2=UI)\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update entity logic\n        // For example, move the entity\n        this->x += 1.0f * (deltaTime * 0.001f); // Move right at 1 pixel per second\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw the entity\n        renderer.drawFilledRectangle(\n            static_cast<int>(x), \n            static_cast<int>(y), \n            width, \n            height, \n            pixelroot32::graphics::Color::Red\n        );\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#entity-properties","title":"Entity Properties","text":"

Every entity has these properties:

  • x, y: Position in world space (float)
  • width, height: Dimensions (int)
  • isVisible: If false, draw() is not called
  • isEnabled: If false, update() is not called
  • renderLayer: Which layer to draw on (0, 1, or 2)
"},{"location":"manual/game_development/scenes_and_entities/#adding-entities-to-a-scene","title":"Adding Entities to a Scene","text":"

Add entities to your scene in init():

void MyGameScene::init() override {\n    // Create entities\n    SimpleEntity* entity1 = new SimpleEntity(50, 50);\n    SimpleEntity* entity2 = new SimpleEntity(100, 100);\n\n    // Add them to the scene\n    addEntity(entity1);\n    addEntity(entity2);\n}\n

The scene automatically manages these entities: - Calls update() on all enabled entities each frame - Calls draw() on all visible entities each frame - Handles cleanup when the scene is destroyed

"},{"location":"manual/game_development/scenes_and_entities/#actors-entities-with-collisions","title":"Actors: Entities with Collisions","text":"

An Actor is an entity that can participate in collision detection. Inherit from pixelroot32::core::Actor:

#include <core/Actor.h>\n#include <physics/CollisionTypes.h>\n\nclass MyActor : public pixelroot32::core::Actor {\npublic:\n    MyActor(float x, float y, int w, int h)\n        : Actor(x, y, w, h) {\n        // Set collision layer (what group this actor belongs to)\n        setCollisionLayer(0x0001); // Example: layer 1\n\n        // Set collision mask (what groups this actor can collide with)\n        setCollisionMask(0x0002); // Example: can collide with layer 2\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update actor logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw the actor\n    }\n\n    // REQUIRED: Define the hitbox for collision detection\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    // REQUIRED: Handle collisions\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // React to collision\n        // For example: take damage, destroy self, etc.\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#collision-layers-and-masks","title":"Collision Layers and Masks","text":"

Collision layers use bit flags to organize actors into groups:

// Define your layers (typically in a GameLayers.h file)\nnamespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;  // Bit 0\n    constexpr uint16_t ENEMY = 0x0002;  // Bit 1\n    constexpr uint16_t PROJECTILE = 0x0004; // Bit 2\n    constexpr uint16_t WALL = 0x0008;   // Bit 3\n}\n\n// Set up a player actor\nplayer->setCollisionLayer(Layers::PLAYER);\nplayer->setCollisionMask(Layers::ENEMY | Layers::WALL); // Can collide with enemies and walls\n\n// Set up an enemy actor\nenemy->setCollisionLayer(Layers::ENEMY);\nenemy->setCollisionMask(Layers::PLAYER | Layers::PROJECTILE); // Can collide with player and projectiles\n

The collision system only checks collisions between actors whose layers and masks overlap. This is much more efficient than checking every pair.

"},{"location":"manual/game_development/scenes_and_entities/#scene-management","title":"Scene Management","text":""},{"location":"manual/game_development/scenes_and_entities/#setting-the-active-scene","title":"Setting the Active Scene","text":"

From your main code, set the active scene:

MyGameScene gameScene;\n\nvoid setup() {\n    engine.init();\n    gameScene.init();\n    engine.setScene(&gameScene); // Set as active scene\n}\n
"},{"location":"manual/game_development/scenes_and_entities/#switching-scenes","title":"Switching Scenes","text":"

To switch to a different scene:

MenuScene menuScene;\nGameScene gameScene;\n\nvoid switchToGame() {\n    gameScene.init();\n    engine.setScene(&gameScene); // Replaces current scene\n}\n
"},{"location":"manual/game_development/scenes_and_entities/#scene-stack-pushpop","title":"Scene Stack (Push/Pop)","text":"

For menus and pause screens, use the scene stack:

// Push a pause menu (game scene stays in background)\nvoid pauseGame() {\n    pauseMenu.init();\n    engine.getCurrentScene()->getSceneManager().pushScene(&pauseMenu);\n}\n\n// Pop the pause menu (resume game)\nvoid resumeGame() {\n    engine.getCurrentScene()->getSceneManager().popScene();\n}\n

Note: Scene stack management is handled internally by the Engine's SceneManager. You typically access it through engine.getCurrentScene().

"},{"location":"manual/game_development/scenes_and_entities/#complete-example","title":"Complete Example","text":"

Here's a complete example of a scene with multiple entities:

#include <core/Scene.h>\n#include <core/Entity.h>\n#include <core/Actor.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\n// A simple moving entity\nclass MovingBox : public pixelroot32::core::Entity {\npublic:\n    MovingBox(float x, float y) \n        : Entity(x, y, 20, 20, pixelroot32::core::EntityType::GENERIC),\n          speedX(50.0f), speedY(30.0f) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        float dt = deltaTime * 0.001f; // Convert to seconds\n\n        x += speedX * dt;\n        y += speedY * dt;\n\n        // Bounce off screen edges\n        if (x < 0 || x > 220) speedX = -speedX;\n        if (y < 0 || y > 220) speedY = -speedY;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x), \n            static_cast<int>(y), \n            width, \n            height, \n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\nprivate:\n    float speedX, speedY;\n};\n\n// A simple actor that can collide\nclass CollidableBox : public pixelroot32::core::Actor {\npublic:\n    CollidableBox(float x, float y)\n        : Actor(x, y, 30, 30) {\n        setRenderLayer(1);\n        setCollisionLayer(0x0001);\n        setCollisionMask(0x0001);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Static actor, no movement\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x), \n            static_cast<int>(y), \n            width, \n            height, \n            pixelroot32::graphics::Color::Yellow\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Change color when collided\n        // (In a real game, you'd handle collision logic here)\n    }\n};\n\n// The scene\nclass ExampleScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Create and add entities\n        addEntity(new MovingBox(50, 50));\n        addEntity(new MovingBox(150, 100));\n        addEntity(new CollidableBox(100, 100));\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime); // Update all entities\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background\n        renderer.drawFilledRectangle(0, 0, 240, 240, \n            pixelroot32::graphics::Color::Black);\n\n        Scene::draw(renderer); // Draw all entities\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/scenes_and_entities/#entity-management","title":"Entity Management","text":"
  • Pre-allocate entities: Create entities in init(), not in update()
  • Reuse entities: Instead of creating/destroying, enable/disable entities
  • Limit entity count: MAX_ENTITIES = 32 per scene
  • Use object pooling: For frequently created/destroyed entities (projectiles, particles)
"},{"location":"manual/game_development/scenes_and_entities/#scene-organization","title":"Scene Organization","text":"
  • One scene per screen: Menu, game, game over, etc.
  • Keep scenes focused: Each scene should have a single responsibility
  • Initialize in init(): Don't do heavy work in the constructor
  • Clean up properly: Remove entities when switching scenes
"},{"location":"manual/game_development/scenes_and_entities/#collision-layers","title":"Collision Layers","text":"
  • Plan your layers: Design your layer system before coding
  • Use bit flags: Makes layer combinations easy
  • Keep it simple: Don't over-complicate with too many layers
  • Document your layers: Create a GameLayers.h file
"},{"location":"manual/game_development/scenes_and_entities/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/scenes_and_entities/#entity-pool-pattern","title":"Entity Pool Pattern","text":"

For entities that are frequently created and destroyed (like projectiles):

class ProjectilePool {\n    static const int POOL_SIZE = 10;\n    ProjectileActor pool[POOL_SIZE];\n\npublic:\n    ProjectileActor* getAvailable() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!pool[i].isActive) {\n                pool[i].isActive = true;\n                return &pool[i];\n            }\n        }\n        return nullptr; // Pool exhausted\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#entity-factory-pattern","title":"Entity Factory Pattern","text":"

Create entities through factory functions:

Entity* createEnemy(EnemyType type, float x, float y) {\n    switch (type) {\n        case EnemyType::BASIC:\n            return new BasicEnemy(x, y);\n        case EnemyType::FAST:\n            return new FastEnemy(x, y);\n        // ...\n    }\n}\n
"},{"location":"manual/game_development/scenes_and_entities/#next-steps","title":"Next Steps","text":"

Now that you understand scenes and entities, learn about: - Basic Rendering - Draw sprites, text, and primitives - Input and Control - Handle user input - Physics and Collisions - Advanced collision handling

See also: - Fundamental Concepts - API Reference - Scene - API Reference - Entity - API Reference - Actor

"},{"location":"manual/game_development/user_interface/","title":"User Interface","text":"

PixelRoot32 provides a complete UI system for creating menus, HUDs, and interface elements. This guide covers all UI components and layout systems.

"},{"location":"manual/game_development/user_interface/#ui-elements","title":"UI Elements","text":"

All UI elements inherit from UIElement, which itself inherits from Entity. This means UI elements can be added to scenes just like any other entity.

"},{"location":"manual/game_development/user_interface/#uilabel","title":"UILabel","text":"

Display text on screen:

#include <graphics/ui/UILabel.h>\n\n// Create a label\npixelroot32::graphics::ui::UILabel* scoreLabel = new pixelroot32::graphics::ui::UILabel(\n    \"Score: 0\",                    // text\n    10,                            // x position\n    10,                            // y position\n    pixelroot32::graphics::Color::White,  // color\n    1                              // size multiplier\n);\n\n// Add to scene\naddEntity(scoreLabel);\n\n// Update text dynamically\nscoreLabel->setText(\"Score: 100\");\n\n// Center horizontally\nscoreLabel->centerX(240); // Screen width\n
"},{"location":"manual/game_development/user_interface/#uibutton","title":"UIButton","text":"

Create clickable buttons:

#include <graphics/ui/UIButton.h>\n\n// Create a button\npixelroot32::graphics::ui::UIButton* startButton = new pixelroot32::graphics::ui::UIButton(\n    \"Start Game\",                  // text\n    4,                             // navigation index\n    50,                            // x position\n    100,                           // y position\n    140,                           // width\n    30,                            // height\n    []() {                         // callback function\n        // Button clicked - start game\n        startGame();\n    }\n);\n\n// Configure style\nstartButton->setStyle(\n    pixelroot32::graphics::Color::White,   // text color\n    pixelroot32::graphics::Color::Blue,    // background color\n    true                                    // draw background\n);\n\n// Add to scene\naddEntity(startButton);\n
"},{"location":"manual/game_development/user_interface/#uicheckbox","title":"UICheckBox","text":"

Create interactive checkboxes:

#include <graphics/ui/UICheckBox.h>\n\n// Create a checkbox\npixelroot32::graphics::ui::UICheckBox* soundCheckbox = new pixelroot32::graphics::ui::UICheckBox(\n    \"Enable Sound\",                // text\n    4,                             // navigation index\n    50,                            // x position\n    140,                           // y position\n    140,                           // width\n    20,                            // height\n    true,                          // initial checked state\n    [](bool checked) {             // callback function\n        // Checkbox state changed\n        setSoundEnabled(checked);\n    },\n    1                              // font size\n);\n\n// Configure style\nsoundCheckbox->setStyle(\n    pixelroot32::graphics::Color::White,   // text color\n    pixelroot32::graphics::Color::Blue,    // background color\n    false                                  // draw background\n);\n\n// Add to scene\naddEntity(soundCheckbox);\n
"},{"location":"manual/game_development/user_interface/#uipanel","title":"UIPanel","text":"

Create visual containers with background and border:

#include <graphics/ui/UIPanel.h>\n\n// Create a panel\npixelroot32::graphics::ui::UIPanel* dialog = new pixelroot32::graphics::ui::UIPanel(\n    50,   // x\n    50,   // y\n    140,  // width\n    140   // height\n);\n\n// Configure appearance\ndialog->setBackgroundColor(pixelroot32::graphics::Color::Black);\ndialog->setBorderColor(pixelroot32::graphics::Color::White);\ndialog->setBorderWidth(2);\n\n// Add content (typically a layout)\ndialog->setChild(menuLayout);\n\n// Add to scene\naddEntity(dialog);\n
"},{"location":"manual/game_development/user_interface/#layouts","title":"Layouts","text":"

Layouts automatically organize UI elements, eliminating the need for manual position calculations.

"},{"location":"manual/game_development/user_interface/#uiverticallayout","title":"UIVerticalLayout","text":"

Organize elements vertically with automatic scrolling:

#include <graphics/ui/UIVerticalLayout.h>\n\n// Create vertical layout\npixelroot32::graphics::ui::UIVerticalLayout* menu = new pixelroot32::graphics::ui::UIVerticalLayout(\n    10,   // x\n    60,   // y\n    220,  // width\n    160   // height (viewport)\n);\n\n// Configure layout\nmenu->setPadding(5);        // Internal padding\nmenu->setSpacing(6);        // Space between elements\nmenu->setScrollEnabled(true); // Enable scrolling\n\n// Set navigation buttons\nmenu->setNavigationButtons(0, 1); // UP=0, DOWN=1\n\n// Set button styles\nmenu->setButtonStyle(\n    pixelroot32::graphics::Color::White,  // selected text\n    pixelroot32::graphics::Color::Cyan,    // selected background\n    pixelroot32::graphics::Color::White,  // unselected text\n    pixelroot32::graphics::Color::Black   // unselected background\n);\n\n// Add buttons (no manual positioning needed!)\nfor (int i = 0; i < 10; i++) {\n    UIButton* btn = new UIButton(\n        \"Option \" + std::to_string(i),\n        i,\n        0, 0,  // Position ignored - layout handles it\n        200, 20,\n        [i]() { handleOption(i); }\n    );\n    menu->addElement(btn);\n}\n\n// Add layout to scene\nmenu->setRenderLayer(2); // UI layer\naddEntity(menu);\n
"},{"location":"manual/game_development/user_interface/#uihorizontallayout","title":"UIHorizontalLayout","text":"

Organize elements horizontally:

#include <graphics/ui/UIHorizontalLayout.h>\n\n// Create horizontal layout (menu bar)\npixelroot32::graphics::ui::UIHorizontalLayout* menuBar = new pixelroot32::graphics::ui::UIHorizontalLayout(\n    0,    // x\n    0,    // y\n    240,  // width\n    30    // height\n);\n\nmenuBar->setPadding(5);\nmenuBar->setSpacing(4);\nmenuBar->setScrollEnabled(true);\nmenuBar->setNavigationButtons(2, 3); // LEFT=2, RIGHT=3\n\n// Add menu items\nmenuBar->addElement(new UIButton(\"File\", 0, 0, 0, 60, 20, []() {}));\nmenuBar->addElement(new UIButton(\"Edit\", 1, 0, 0, 60, 20, []() {}));\nmenuBar->addElement(new UIButton(\"View\", 2, 0, 0, 60, 20, []() {}));\n\naddEntity(menuBar);\n
"},{"location":"manual/game_development/user_interface/#uigridlayout","title":"UIGridLayout","text":"

Organize elements in a grid (matrix):

#include <graphics/ui/UIGridLayout.h>\n\n// Create grid layout (inventory)\npixelroot32::graphics::ui::UIGridLayout* inventory = new pixelroot32::graphics::ui::UIGridLayout(\n    10,   // x\n    60,   // y\n    220,  // width\n    160   // height\n);\n\ninventory->setColumns(4);  // 4 columns\ninventory->setPadding(5);\ninventory->setSpacing(4);\ninventory->setNavigationButtons(0, 1, 2, 3); // UP, DOWN, LEFT, RIGHT\n\n// Add items (automatically arranged in grid)\nfor (int i = 0; i < 16; i++) {\n    UIButton* item = new UIButton(\n        \"Item \" + std::to_string(i),\n        i,\n        0, 0,  // Position ignored\n        50, 50,\n        [i]() { useItem(i); }\n    );\n    inventory->addElement(item);\n}\n\naddEntity(inventory);\n
"},{"location":"manual/game_development/user_interface/#uianchorlayout","title":"UIAnchorLayout","text":"

Position elements at fixed screen positions (perfect for HUDs):

#include <graphics/ui/UIAnchorLayout.h>\n\n// Create anchor layout for HUD\npixelroot32::graphics::ui::UIAnchorLayout* hud = new pixelroot32::graphics::ui::UIAnchorLayout(\n    0,    // x\n    0,    // y\n    240,  // screen width\n    240   // screen height\n);\n\nhud->setScreenSize(240, 240);\n\n// Add HUD elements at different anchor points\nUILabel* scoreLabel = new UILabel(\"Score: 0\", 0, 0, Color::White, 1);\nUILabel* livesLabel = new UILabel(\"Lives: 3\", 0, 0, Color::White, 1);\n\nhud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\nhud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\naddEntity(hud);\n

Available Anchors: - TOP_LEFT, TOP_RIGHT, TOP_CENTER - BOTTOM_LEFT, BOTTOM_RIGHT, BOTTOM_CENTER - LEFT_CENTER, RIGHT_CENTER - CENTER

"},{"location":"manual/game_development/user_interface/#uipaddingcontainer","title":"UIPaddingContainer","text":"

Add padding around a single element:

#include <graphics/ui/UIPaddingContainer.h>\n\n// Create padding container\npixelroot32::graphics::ui::UIPaddingContainer* container = new pixelroot32::graphics::ui::UIPaddingContainer(\n    10,   // x\n    10,   // y\n    200,  // width\n    100   // height\n);\n\n// Set uniform padding\ncontainer->setPadding(10);\n\n// Or set asymmetric padding\ncontainer->setPadding(5, 15, 10, 10); // left, right, top, bottom\n\n// Add child element\ncontainer->setChild(button);\n\naddEntity(container);\n
"},{"location":"manual/game_development/user_interface/#navigation","title":"Navigation","text":"

Layouts handle D-pad navigation automatically:

"},{"location":"manual/game_development/user_interface/#vertical-navigation","title":"Vertical Navigation","text":"
verticalLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN);\n\n// Layout automatically:\n// - Highlights selected button\n// - Scrolls to keep selected button visible\n// - Handles wrapping (optional)\n
"},{"location":"manual/game_development/user_interface/#horizontal-navigation","title":"Horizontal Navigation","text":"
horizontalLayout->setNavigationButtons(Buttons::LEFT, Buttons::RIGHT);\n
"},{"location":"manual/game_development/user_interface/#grid-navigation","title":"Grid Navigation","text":"
gridLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN, Buttons::LEFT, Buttons::RIGHT);\n\n// Layout automatically:\n// - Handles 4-direction navigation\n// - Wraps around edges\n// - Updates selection\n
"},{"location":"manual/game_development/user_interface/#manual-selection","title":"Manual Selection","text":"
// Set selected element programmatically\nlayout->setSelectedIndex(2);\n\n// Get selected element\nint selected = layout->getSelectedIndex();\nUIElement* element = layout->getSelectedElement();\n
"},{"location":"manual/game_development/user_interface/#complete-example-main-menu","title":"Complete Example: Main Menu","text":"
#include <core/Scene.h>\n#include <graphics/ui/UIVerticalLayout.h>\n#include <graphics/ui/UIButton.h>\n#include <graphics/ui/UILabel.h>\n#include <graphics/ui/UIPanel.h>\n\nclass MainMenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIVerticalLayout* menuLayout;\n    pixelroot32::graphics::ui::UIPanel* menuPanel;\n\npublic:\n    void init() override {\n        // Create panel\n        menuPanel = new pixelroot32::graphics::ui::UIPanel(40, 40, 160, 160);\n        menuPanel->setBackgroundColor(pixelroot32::graphics::Color::Black);\n        menuPanel->setBorderColor(pixelroot32::graphics::Color::White);\n        menuPanel->setBorderWidth(2);\n        menuPanel->setRenderLayer(2);\n        addEntity(menuPanel);\n\n        // Create layout inside panel\n        menuLayout = new pixelroot32::graphics::ui::UIVerticalLayout(0, 0, 160, 160);\n        menuLayout->setPadding(10);\n        menuLayout->setSpacing(8);\n        menuLayout->setNavigationButtons(0, 1);\n        menuLayout->setButtonStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Cyan,\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Black\n        );\n\n        // Add title\n        pixelroot32::graphics::ui::UILabel* title = new pixelroot32::graphics::ui::UILabel(\n            \"GAME MENU\", 0, 0, pixelroot32::graphics::Color::Yellow, 2\n        );\n        menuLayout->addElement(title);\n\n        // Add menu buttons\n        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Start Game\", 0, 0, 0, 140, 25, []() { startGame(); }\n        ));\n\n        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Options\", 1, 0, 0, 140, 25, []() { showOptions(); }\n        ));\n\n        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Quit\", 2, 0, 0, 140, 25, []() { quitGame(); }\n        ));\n\n        menuPanel->setChild(menuLayout);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Handle input for layout navigation\n        auto& input = engine.getInputManager();\n        menuLayout->handleInput(input);\n\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/user_interface/#complete-example-hud","title":"Complete Example: HUD","text":"
class GameHUD : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::ui::UIAnchorLayout* hud;\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n    pixelroot32::graphics::ui::UILabel* healthLabel;\n\npublic:\n    GameHUD()\n        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::UI_ELEMENT) {\n        setRenderLayer(2); // UI layer\n\n        // Create HUD layout\n        hud = new pixelroot32::graphics::ui::UIAnchorLayout(0, 0, 240, 240);\n        hud->setScreenSize(240, 240);\n\n        // Create labels\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\", 0, 0, pixelroot32::graphics::Color::White, 1\n        );\n\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\", 0, 0, pixelroot32::graphics::Color::White, 1\n        );\n\n        healthLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Health: 100%\", 0, 0, pixelroot32::graphics::Color::Green, 1\n        );\n\n        // Position labels\n        hud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n        hud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n        hud->addElement(healthLabel, pixelroot32::graphics::ui::Anchor::BOTTOM_CENTER);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update HUD text (example)\n        char buffer[32];\n        snprintf(buffer, sizeof(buffer), \"Score: %d\", currentScore);\n        scoreLabel->setText(buffer);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // HUD draws itself through its layout\n    }\n\n    // Add HUD to scene\n    void addToScene(Scene* scene) {\n        scene->addEntity(hud);\n    }\n};\n
"},{"location":"manual/game_development/user_interface/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/user_interface/#organization","title":"Organization","text":"
  • Use render layer 2: Keep all UI on the top layer
  • Group related elements: Use panels to group menu items
  • Separate HUD from menus: Use different layouts for different UI types
  • Reuse layouts: Create layout factories for common patterns
"},{"location":"manual/game_development/user_interface/#performance","title":"Performance","text":"
  • Layouts use viewport culling: Only visible elements are rendered
  • Minimize text updates: Updating text has overhead
  • Use appropriate layouts: Choose the right layout for your needs
  • Limit element count: Too many elements can impact performance
"},{"location":"manual/game_development/user_interface/#navigation_1","title":"Navigation","text":"
  • Set navigation buttons: Configure D-pad navigation for layouts
  • Handle input in update(): Check for button presses to trigger actions
  • Provide visual feedback: Selected buttons should be clearly visible
  • Test navigation flow: Ensure navigation feels responsive
"},{"location":"manual/game_development/user_interface/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/user_interface/#menu-system","title":"Menu System","text":"
class MenuSystem {\n    UIVerticalLayout* currentMenu;\n\npublic:\n    void showMainMenu() {\n        currentMenu = createMainMenu();\n        scene->addEntity(currentMenu);\n    }\n\n    void showPauseMenu() {\n        currentMenu = createPauseMenu();\n        scene->addEntity(currentMenu);\n    }\n\n    void hideMenu() {\n        if (currentMenu) {\n            scene->removeEntity(currentMenu);\n            currentMenu = nullptr;\n        }\n    }\n};\n
"},{"location":"manual/game_development/user_interface/#dynamic-ui-updates","title":"Dynamic UI Updates","text":"
void updateHUD(int score, int lives, int health) {\n    char buffer[32];\n\n    snprintf(buffer, sizeof(buffer), \"Score: %d\", score);\n    scoreLabel->setText(buffer);\n\n    snprintf(buffer, sizeof(buffer), \"Lives: %d\", lives);\n    livesLabel->setText(buffer);\n\n    snprintf(buffer, sizeof(buffer), \"Health: %d%%\", health);\n    healthLabel->setText(buffer);\n}\n
"},{"location":"manual/game_development/user_interface/#next-steps","title":"Next Steps","text":"

Now that you understand the UI system, you've completed the core game development topics. Continue with: - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels - Performance Tuning - Improve performance

See also: - API Reference - UIElement - API Reference - UIButton - API Reference - UI Layouts - Manual - UI Overview

"},{"location":"manual/optimization/extensibility/","title":"Extensibility","text":"

PixelRoot32 is designed to be extensible. This guide covers how to create custom drivers, audio backends, and extend existing systems.

"},{"location":"manual/optimization/extensibility/#creating-custom-display-drivers","title":"Creating Custom Display Drivers","text":"

To support a new display, implement the DrawSurface interface.

"},{"location":"manual/optimization/extensibility/#drawsurface-interface","title":"DrawSurface Interface","text":"
#include <graphics/DrawSurface.h>\n\nclass MyCustomDrawer : public pixelroot32::graphics::DrawSurface {\npublic:\n    // Required methods\n    void init() override;\n    void setRotation(uint8_t rotation) override;\n    void clearBuffer() override;\n    void sendBuffer() override;\n\n    // Drawing primitives\n    void drawPixel(int x, int y, uint16_t color) override;\n    void drawLine(int x1, int y1, int x2, int y2, uint16_t color) override;\n    void drawRectangle(int x, int y, int width, int height, uint16_t color) override;\n    void drawFilledRectangle(int x, int y, int width, int height, uint16_t color) override;\n    void drawCircle(int x, int y, int radius, uint16_t color) override;\n    void drawFilledCircle(int x, int y, int radius, uint16_t color) override;\n    void drawBitmap(int x, int y, int width, int height, const uint8_t* bitmap, uint16_t color) override;\n\n    // Text (deprecated, but must implement)\n    void drawText(const char* text, int16_t x, int16_t y, uint16_t color, uint8_t size) override;\n    void drawTextCentered(const char* text, int16_t y, uint16_t color, uint8_t size) override;\n\n    // State management\n    void setTextColor(uint16_t color) override;\n    void setTextSize(uint8_t size) override;\n    void setCursor(int16_t x, int16_t y) override;\n    void setContrast(uint8_t level) override;\n    void setDisplaySize(int w, int h) override;\n\n    // Utilities\n    uint16_t color565(uint8_t r, uint8_t g, uint8_t b) override;\n    bool processEvents() override;\n    void present() override;\n};\n
"},{"location":"manual/optimization/extensibility/#example-simple-custom-drawer","title":"Example: Simple Custom Drawer","text":"
#include <graphics/DrawSurface.h>\n\nclass SimpleDrawer : public pixelroot32::graphics::DrawSurface {\nprivate:\n    uint16_t* framebuffer;\n    int width, height;\n\npublic:\n    SimpleDrawer(int w, int h) : width(w), height(h) {\n        framebuffer = new uint16_t[w * h];\n    }\n\n    ~SimpleDrawer() {\n        delete[] framebuffer;\n    }\n\n    void init() override {\n        // Initialize your display hardware\n        // Clear framebuffer\n        clearBuffer();\n    }\n\n    void clearBuffer() override {\n        for (int i = 0; i < width * height; i++) {\n            framebuffer[i] = 0x0000; // Black\n        }\n    }\n\n    void sendBuffer() override {\n        // Send framebuffer to display\n        // Implementation depends on your hardware\n    }\n\n    void drawPixel(int x, int y, uint16_t color) override {\n        if (x >= 0 && x < width && y >= 0 && y < height) {\n            framebuffer[y * width + x] = color;\n        }\n    }\n\n    void drawFilledRectangle(int x, int y, int w, int h, uint16_t color) override {\n        for (int py = y; py < y + h; py++) {\n            for (int px = x; px < x + w; px++) {\n                drawPixel(px, py, color);\n            }\n        }\n    }\n\n    // Implement other required methods...\n    // (See TFT_eSPI_Drawer or SDL2_Drawer for reference implementations)\n};\n
"},{"location":"manual/optimization/extensibility/#integrating-custom-driver","title":"Integrating Custom Driver","text":"
// Create custom drawer\nSimpleDrawer* customDrawer = new SimpleDrawer(240, 240);\n\n// Create renderer with custom drawer\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::NONE, // Use NONE for custom\n    0, 240, 240\n);\n\n// You'll need to modify Engine to accept custom DrawSurface\n// Or create a custom Engine wrapper\n
"},{"location":"manual/optimization/extensibility/#creating-custom-audio-backends","title":"Creating Custom Audio Backends","text":"

Implement the AudioBackend interface for custom audio hardware.

"},{"location":"manual/optimization/extensibility/#audiobackend-interface","title":"AudioBackend Interface","text":"
#include <audio/AudioBackend.h>\n\nclass MyCustomAudioBackend : public pixelroot32::audio::AudioBackend {\npublic:\n    // Required methods\n    void init() override;\n    void start() override;\n    void stop() override;\n    uint32_t getSampleRate() const override;\n\n    // Audio generation\n    int16_t generateSample() override;\n\n    // Channel management\n    void setChannelWave(int channel, pixelroot32::audio::WaveType type, float frequency, float duty) override;\n    void setChannelVolume(int channel, float volume) override;\n    void stopChannel(int channel) override;\n};\n
"},{"location":"manual/optimization/extensibility/#example-custom-audio-backend","title":"Example: Custom Audio Backend","text":"
#include <audio/AudioBackend.h>\n\nclass CustomAudioBackend : public pixelroot32::audio::AudioBackend {\nprivate:\n    uint32_t sampleRate;\n    float phase[4] = {0, 0, 0, 0}; // 4 channels\n    float frequency[4] = {0, 0, 0, 0};\n    float volume[4] = {0, 0, 0, 0};\n    pixelroot32::audio::WaveType waveType[4];\n\npublic:\n    CustomAudioBackend(uint32_t rate) : sampleRate(rate) {\n        for (int i = 0; i < 4; i++) {\n            waveType[i] = pixelroot32::audio::WaveType::PULSE;\n            volume[i] = 0.0f;\n        }\n    }\n\n    void init() override {\n        // Initialize your audio hardware\n    }\n\n    void start() override {\n        // Start audio output\n    }\n\n    void stop() override {\n        // Stop audio output\n    }\n\n    uint32_t getSampleRate() const override {\n        return sampleRate;\n    }\n\n    int16_t generateSample() override {\n        float sample = 0.0f;\n\n        for (int ch = 0; ch < 4; ch++) {\n            if (frequency[ch] > 0 && volume[ch] > 0) {\n                float phaseIncrement = frequency[ch] / sampleRate;\n                phase[ch] += phaseIncrement;\n                if (phase[ch] >= 1.0f) phase[ch] -= 1.0f;\n\n                float channelSample = 0.0f;\n                switch (waveType[ch]) {\n                    case pixelroot32::audio::WaveType::PULSE:\n                        channelSample = (phase[ch] < 0.5f) ? 1.0f : -1.0f;\n                        break;\n                    case pixelroot32::audio::WaveType::TRIANGLE:\n                        channelSample = (phase[ch] < 0.5f) ? \n                            (phase[ch] * 4.0f - 1.0f) : \n                            (3.0f - phase[ch] * 4.0f);\n                        break;\n                    // ... other wave types\n                }\n\n                sample += channelSample * volume[ch];\n            }\n        }\n\n        // Clamp and convert to int16_t\n        if (sample > 1.0f) sample = 1.0f;\n        if (sample < -1.0f) sample = -1.0f;\n        return static_cast<int16_t>(sample * 32767.0f);\n    }\n\n    void setChannelWave(int ch, pixelroot32::audio::WaveType type, \n                       float freq, float duty) override {\n        if (ch >= 0 && ch < 4) {\n            waveType[ch] = type;\n            frequency[ch] = freq;\n        }\n    }\n\n    void setChannelVolume(int ch, float vol) override {\n        if (ch >= 0 && ch < 4) {\n            volume[ch] = vol;\n        }\n    }\n\n    void stopChannel(int ch) override {\n        if (ch >= 0 && ch < 4) {\n            frequency[ch] = 0.0f;\n            volume[ch] = 0.0f;\n        }\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#extending-existing-systems","title":"Extending Existing Systems","text":""},{"location":"manual/optimization/extensibility/#custom-entity-types","title":"Custom Entity Types","text":"

Create specialized entity types:

class PowerUpActor : public pixelroot32::core::Actor {\nprivate:\n    PowerUpType type;\n    float lifetime = 5.0f; // 5 seconds\n\npublic:\n    PowerUpActor(float x, float y, PowerUpType t)\n        : Actor(x, y, 8, 8), type(t) {\n        setRenderLayer(1);\n        setCollisionLayer(Layers::POWERUP);\n        setCollisionMask(Layers::PLAYER);\n    }\n\n    void update(unsigned long deltaTime) override {\n        lifetime -= deltaTime * 0.001f;\n        if (lifetime <= 0) {\n            isEnabled = false;\n            isVisible = false;\n        }\n\n        // Animate (bob up and down)\n        y += sin(millis() * 0.005f) * 0.5f;\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        if (other->isInLayer(Layers::PLAYER)) {\n            applyPowerUp(other);\n            isEnabled = false;\n            isVisible = false;\n        }\n    }\n\nprivate:\n    void applyPowerUp(pixelroot32::core::Actor* player) {\n        switch (type) {\n            case PowerUpType::SPEED:\n                // Increase player speed\n                break;\n            case PowerUpType::HEALTH:\n                // Restore health\n                break;\n            // ...\n        }\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#custom-ui-layouts","title":"Custom UI Layouts","text":"

Create new layout types:

#include <graphics/ui/UILayout.h>\n\nclass UICircularLayout : public pixelroot32::graphics::ui::UILayout {\nprivate:\n    float radius;\n    float startAngle;\n\npublic:\n    UICircularLayout(float x, float y, float w, float h, float r)\n        : UILayout(x, y, w, h), radius(r), startAngle(0.0f) {\n    }\n\n    void updateLayout() override {\n        int count = elements.size();\n        float angleStep = 360.0f / count;\n\n        for (size_t i = 0; i < elements.size(); i++) {\n            float angle = startAngle + (i * angleStep);\n            float rad = angle * M_PI / 180.0f;\n\n            float elementX = x + (radius * cos(rad)) - (elements[i]->width / 2);\n            float elementY = y + (radius * sin(rad)) - (elements[i]->height / 2);\n\n            elements[i]->x = elementX;\n            elements[i]->y = elementY;\n        }\n    }\n\n    void handleInput(const pixelroot32::input::InputManager& input) override {\n        // Implement circular navigation\n        // ...\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#custom-collision-primitives","title":"Custom Collision Primitives","text":"

Extend collision system with new shapes:

// Add to your game code (not engine modification)\nstruct Triangle {\n    float x1, y1, x2, y2, x3, y3;\n};\n\nbool intersects(const Triangle& tri, const pixelroot32::core::Rect& rect) {\n    // Implement triangle-rectangle intersection\n    // ...\n    return false;\n}\n\nbool intersects(const Triangle& tri1, const Triangle& tri2) {\n    // Implement triangle-triangle intersection\n    // ...\n    return false;\n}\n
"},{"location":"manual/optimization/extensibility/#best-practices","title":"Best Practices","text":""},{"location":"manual/optimization/extensibility/#maintain-compatibility","title":"Maintain Compatibility","text":"
  • Don't break existing APIs: Extend, don't modify
  • Use inheritance: Inherit from base classes
  • Follow patterns: Match existing code patterns
  • Document extensions: Comment your custom code
"},{"location":"manual/optimization/extensibility/#testing","title":"Testing","text":"
  • Test on both platforms: ESP32 and Native
  • Test edge cases: Boundary conditions, null pointers
  • Performance testing: Ensure extensions don't hurt performance
  • Memory testing: Check for leaks with custom code
"},{"location":"manual/optimization/extensibility/#documentation","title":"Documentation","text":"
  • Comment your code: Explain why, not just what
  • Provide examples: Show how to use your extensions
  • Document limitations: State what doesn't work
  • Version compatibility: Note which engine version
"},{"location":"manual/optimization/extensibility/#common-extension-patterns","title":"Common Extension Patterns","text":""},{"location":"manual/optimization/extensibility/#factory-pattern","title":"Factory Pattern","text":"
class EntityFactory {\npublic:\n    static pixelroot32::core::Entity* createEnemy(EnemyType type, float x, float y) {\n        switch (type) {\n            case EnemyType::BASIC:\n                return new BasicEnemy(x, y);\n            case EnemyType::FAST:\n                return new FastEnemy(x, y);\n            case EnemyType::TANK:\n                return new TankEnemy(x, y);\n            default:\n                return nullptr;\n        }\n    }\n\n    static pixelroot32::core::Entity* createPowerUp(PowerUpType type, float x, float y) {\n        return new PowerUpActor(x, y, type);\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#strategy-pattern","title":"Strategy Pattern","text":"
class MovementStrategy {\npublic:\n    virtual void update(pixelroot32::core::Actor* actor, unsigned long deltaTime) = 0;\n};\n\nclass LinearMovement : public MovementStrategy {\npublic:\n    void update(pixelroot32::core::Actor* actor, unsigned long deltaTime) override {\n        actor->x += speed * (deltaTime * 0.001f);\n    }\n};\n\nclass CircularMovement : public MovementStrategy {\npublic:\n    void update(pixelroot32::core::Actor* actor, unsigned long deltaTime) override {\n        float angle = millis() * 0.001f;\n        actor->x = centerX + radius * cos(angle);\n        actor->y = centerY + radius * sin(angle);\n    }\n};\n\nclass SmartEnemy : public pixelroot32::core::Actor {\nprivate:\n    MovementStrategy* movement;\n\npublic:\n    void setMovement(MovementStrategy* strat) {\n        movement = strat;\n    }\n\n    void update(unsigned long deltaTime) override {\n        if (movement) {\n            movement->update(this, deltaTime);\n        }\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/extensibility/#driver-not-working","title":"Driver Not Working","text":"
  • Verify all interface methods are implemented
  • Check initialization order
  • Test with simple drawing first
  • Verify hardware connections
"},{"location":"manual/optimization/extensibility/#audio-backend-issues","title":"Audio Backend Issues","text":"
  • Check sample rate matches hardware
  • Verify audio generation logic
  • Test with simple tones first
  • Check channel management
"},{"location":"manual/optimization/extensibility/#extension-conflicts","title":"Extension Conflicts","text":"
  • Ensure namespace isolation
  • Avoid modifying engine code directly
  • Use composition over modification
  • Test with engine updates
"},{"location":"manual/optimization/extensibility/#next-steps","title":"Next Steps","text":"

Now that you understand extensibility, you've completed the optimization section. Continue with: - API Reference - Complete API documentation - Examples - Code examples - Resources - Tools and troubleshooting

See also: - API Reference - DrawSurface - API Reference - AudioBackend - Manual - Platforms and Drivers

"},{"location":"manual/optimization/memory_management/","title":"Memory Management","text":"

ESP32 has limited memory, so efficient memory management is crucial for PixelRoot32 games. This guide covers memory constraints, object pooling, and best practices.

"},{"location":"manual/optimization/memory_management/#esp32-memory-constraints","title":"ESP32 Memory Constraints","text":""},{"location":"manual/optimization/memory_management/#available-memory","title":"Available Memory","text":"

ESP32 typically has: - RAM: ~320KB total (varies by model) - Flash: 4MB+ (for program storage) - Heap: Limited and fragmented over time

"},{"location":"manual/optimization/memory_management/#real-world-limits","title":"Real-World Limits","text":"
  • MAX_ENTITIES: 32 per scene (hard limit)
  • Sprite data: Stored in flash (const/constexpr)
  • Dynamic allocation: Should be avoided in game loop
  • Stack: Limited (~8KB), avoid large stack allocations
"},{"location":"manual/optimization/memory_management/#object-pooling","title":"Object Pooling","text":"

Object pooling reuses objects instead of creating/destroying them, avoiding memory fragmentation.

"},{"location":"manual/optimization/memory_management/#basic-pool-pattern","title":"Basic Pool Pattern","text":"
class ProjectilePool {\nprivate:\n    static const int POOL_SIZE = 10;\n    ProjectileActor pool[POOL_SIZE];\n    bool inUse[POOL_SIZE];\n\npublic:\n    ProjectilePool() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            inUse[i] = false;\n        }\n    }\n\n    ProjectileActor* getAvailable() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!inUse[i]) {\n                inUse[i] = true;\n                return &pool[i];\n            }\n        }\n        return nullptr; // Pool exhausted\n    }\n\n    void release(ProjectileActor* projectile) {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (&pool[i] == projectile) {\n                inUse[i] = false;\n                projectile->isEnabled = false;\n                projectile->isVisible = false;\n                break;\n            }\n        }\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#using-object-pools","title":"Using Object Pools","text":"
class GameScene : public pixelroot32::core::Scene {\nprivate:\n    ProjectilePool projectilePool;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Fire projectile\n        if (input.isButtonPressed(Buttons::A)) {\n            ProjectileActor* proj = projectilePool.getAvailable();\n            if (proj) {\n                proj->x = player->x;\n                proj->y = player->y;\n                proj->isEnabled = true;\n                proj->isVisible = true;\n                // ... initialize projectile\n            }\n        }\n\n        // Clean up projectiles that hit target\n        for (auto* entity : entities) {\n            if (auto* proj = dynamic_cast<ProjectileActor*>(entity)) {\n                if (proj->hitTarget) {\n                    projectilePool.release(proj);\n                }\n            }\n        }\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#complete-example-entity-pool","title":"Complete Example: Entity Pool","text":"
template<typename T, int POOL_SIZE>\nclass EntityPool {\nprivate:\n    T pool[POOL_SIZE];\n    bool inUse[POOL_SIZE];\n    int activeCount = 0;\n\npublic:\n    EntityPool() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            inUse[i] = false;\n        }\n    }\n\n    T* acquire() {\n        if (activeCount >= POOL_SIZE) {\n            return nullptr; // Pool full\n        }\n\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!inUse[i]) {\n                inUse[i] = true;\n                activeCount++;\n                return &pool[i];\n            }\n        }\n        return nullptr;\n    }\n\n    void release(T* obj) {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (&pool[i] == obj) {\n                inUse[i] = false;\n                activeCount--;\n                obj->isEnabled = false;\n                obj->isVisible = false;\n                break;\n            }\n        }\n    }\n\n    int getActiveCount() const { return activeCount; }\n    int getAvailableCount() const { return POOL_SIZE - activeCount; }\n};\n\n// Usage\nEntityPool<EnemyActor, 8> enemyPool;\nEntityPool<ParticleEmitter, 5> particlePool;\n
"},{"location":"manual/optimization/memory_management/#scene-arena-experimental","title":"Scene Arena (Experimental)","text":"

Scene Arena provides a memory arena for scene-specific allocations, reducing fragmentation.

"},{"location":"manual/optimization/memory_management/#what-is-scene-arena","title":"What is Scene Arena?","text":"

Scene Arena is a contiguous memory block pre-allocated for a scene. All scene entities are allocated from this arena instead of the heap.

"},{"location":"manual/optimization/memory_management/#when-to-use","title":"When to Use","text":"
  • Large scenes: Scenes with many entities
  • Frequent allocation: Scenes that create/destroy entities often
  • Memory fragmentation: When heap fragmentation is a problem
  • Performance: When you need predictable allocation performance
"},{"location":"manual/optimization/memory_management/#configuration","title":"Configuration","text":"
#ifdef PIXELROOT32_ENABLE_SCENE_ARENA\n#include <core/Scene.h>\n\n// Define arena buffer (typically in scene header)\nstatic unsigned char MY_SCENE_ARENA_BUFFER[8192]; // 8KB arena\n\nclass MyScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Initialize arena\n        arena.init(MY_SCENE_ARENA_BUFFER, sizeof(MY_SCENE_ARENA_BUFFER));\n\n        // Now entities allocated with arena will use this memory\n        // (Requires custom allocation functions)\n    }\n};\n#endif\n
"},{"location":"manual/optimization/memory_management/#limitations","title":"Limitations","text":"
  • Experimental: May have bugs or limitations
  • Fixed size: Arena size must be determined at compile time
  • No reallocation: Can't resize arena at runtime
  • Manual management: Requires careful memory management

Note: Scene Arena is an experimental feature. Use object pooling for most cases.

"},{"location":"manual/optimization/memory_management/#best-practices","title":"Best Practices","text":""},{"location":"manual/optimization/memory_management/#avoid-dynamic-allocation-in-game-loop","title":"Avoid Dynamic Allocation in Game Loop","text":"
// \u274c BAD: Allocates every frame\nvoid update(unsigned long deltaTime) override {\n    if (shouldSpawnEnemy) {\n        EnemyActor* enemy = new EnemyActor(x, y);\n        addEntity(enemy);\n    }\n}\n\n// \u2705 GOOD: Use pool\nvoid update(unsigned long deltaTime) override {\n    if (shouldSpawnEnemy) {\n        EnemyActor* enemy = enemyPool.getAvailable();\n        if (enemy) {\n            enemy->reset(x, y);\n            enemy->isEnabled = true;\n        }\n    }\n}\n
"},{"location":"manual/optimization/memory_management/#pre-allocate-resources","title":"Pre-allocate Resources","text":"
class GameScene : public pixelroot32::core::Scene {\nprivate:\n    // Pre-allocated pools\n    ProjectilePool projectiles;\n    EnemyPool enemies;\n    ParticlePool particles;\n\npublic:\n    void init() override {\n        // All pools created in constructor\n        // No allocation in init() or update()\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#reuse-objects","title":"Reuse Objects","text":"
class EnemyActor : public pixelroot32::core::Actor {\npublic:\n    void reset(float x, float y) {\n        this->x = x;\n        this->y = y;\n        this->isEnabled = true;\n        this->isVisible = true;\n        this->health = maxHealth;\n        // Reset all state\n    }\n\n    void deactivate() {\n        isEnabled = false;\n        isVisible = false;\n    }\n};\n\n// Usage\nEnemyActor* enemy = enemyPool.getAvailable();\nif (enemy) {\n    enemy->reset(spawnX, spawnY);\n    addEntity(enemy);\n}\n
"},{"location":"manual/optimization/memory_management/#avoid-strings-and-dynamic-memory","title":"Avoid Strings and Dynamic Memory","text":"
// \u274c BAD: String allocation\nvoid draw(Renderer& renderer) override {\n    std::string scoreText = \"Score: \" + std::to_string(score);\n    renderer.drawText(scoreText.c_str(), 10, 10, Color::White, 1);\n}\n\n// \u2705 GOOD: Static buffer\nvoid draw(Renderer& renderer) override {\n    char scoreBuffer[32];\n    snprintf(scoreBuffer, sizeof(scoreBuffer), \"Score: %d\", score);\n    renderer.drawText(scoreBuffer, 10, 10, Color::White, 1);\n}\n
"},{"location":"manual/optimization/memory_management/#store-data-in-flash","title":"Store Data in Flash","text":"
// \u2705 GOOD: Stored in flash (const/constexpr)\nstatic const uint16_t SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    // ...\n};\n\n// \u274c BAD: Stored in RAM\nuint16_t spriteData[] = {\n    0b00111100,\n    0b01111110,\n    // ...\n};\n
"},{"location":"manual/optimization/memory_management/#memory-monitoring","title":"Memory Monitoring","text":""},{"location":"manual/optimization/memory_management/#check-available-memory","title":"Check Available Memory","text":"
#ifdef PLATFORM_ESP32\n#include <Arduino.h>\n\nvoid checkMemory() {\n    Serial.print(\"Free heap: \");\n    Serial.println(ESP.getFreeHeap());\n    Serial.print(\"Largest free block: \");\n    Serial.println(ESP.getMaxAllocHeap());\n}\n#endif\n
"},{"location":"manual/optimization/memory_management/#monitor-entity-count","title":"Monitor Entity Count","text":"
void update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);\n\n    // Check entity count\n    int entityCount = getEntityCount();\n    if (entityCount >= MAX_ENTITIES) {\n        Serial.println(\"WARNING: Entity limit reached!\");\n    }\n}\n
"},{"location":"manual/optimization/memory_management/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/optimization/memory_management/#entity-lifecycle-management","title":"Entity Lifecycle Management","text":"
class ManagedEntity {\nprivate:\n    bool isActive = false;\n\npublic:\n    void activate(float x, float y) {\n        this->x = x;\n        this->y = y;\n        isActive = true;\n        isEnabled = true;\n        isVisible = true;\n    }\n\n    void deactivate() {\n        isActive = false;\n        isEnabled = false;\n        isVisible = false;\n    }\n\n    bool getIsActive() const { return isActive; }\n};\n\n// Pool manages lifecycle\nclass EntityManager {\nprivate:\n    EntityPool<ManagedEntity, 20> pool;\n\npublic:\n    ManagedEntity* spawn(float x, float y) {\n        auto* entity = pool.acquire();\n        if (entity) {\n            entity->activate(x, y);\n        }\n        return entity;\n    }\n\n    void despawn(ManagedEntity* entity) {\n        if (entity) {\n            entity->deactivate();\n            pool.release(entity);\n        }\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#memory-efficient-collections","title":"Memory-Efficient Collections","text":"
// Fixed-size array instead of vector\nclass EntityArray {\nprivate:\n    static const int MAX_SIZE = 32;\n    pixelroot32::core::Entity* entities[MAX_SIZE];\n    int count = 0;\n\npublic:\n    bool add(pixelroot32::core::Entity* entity) {\n        if (count >= MAX_SIZE) return false;\n        entities[count++] = entity;\n        return true;\n    }\n\n    void remove(pixelroot32::core::Entity* entity) {\n        for (int i = 0; i < count; i++) {\n            if (entities[i] == entity) {\n                entities[i] = entities[--count];\n                break;\n            }\n        }\n    }\n\n    int size() const { return count; }\n    pixelroot32::core::Entity* operator[](int index) { return entities[index]; }\n};\n
"},{"location":"manual/optimization/memory_management/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/memory_management/#out-of-memory-errors","title":"Out of Memory Errors","text":"
  • Reduce pool sizes
  • Use fewer entities
  • Store more data in flash
  • Avoid dynamic allocation
  • Check for memory leaks
"},{"location":"manual/optimization/memory_management/#entity-limit-reached","title":"Entity Limit Reached","text":"
  • MAX_ENTITIES = 32 is a hard limit
  • Use object pooling to reuse entities
  • Deactivate entities instead of removing
  • Combine multiple entities into one
"},{"location":"manual/optimization/memory_management/#memory-fragmentation","title":"Memory Fragmentation","text":"
  • Use object pooling
  • Pre-allocate all resources
  • Avoid frequent new/delete
  • Consider Scene Arena (experimental)
"},{"location":"manual/optimization/memory_management/#next-steps","title":"Next Steps","text":"

Now that you understand memory management, learn about: - Performance Optimization - Improve game performance - Platforms and Drivers - Understand platform specifics - Extensibility - Extend the engine

See also: - API Reference - Scene - Manual - Scenes and Entities

"},{"location":"manual/optimization/performance_tuning/","title":"Performance Optimization","text":"

This guide covers techniques to improve game performance on ESP32, including rendering optimization, logic optimization, and profiling.

"},{"location":"manual/optimization/performance_tuning/#esp32-performance-characteristics","title":"ESP32 Performance Characteristics","text":""},{"location":"manual/optimization/performance_tuning/#cpu-limitations","title":"CPU Limitations","text":"
  • Dual-core: 240MHz (typically)
  • Single-threaded game loop: One core handles everything
  • Target FPS: 30-60 FPS (depends on game complexity)
  • Frame budget: ~16-33ms per frame at 60 FPS
"},{"location":"manual/optimization/performance_tuning/#common-bottlenecks","title":"Common Bottlenecks","text":"
  1. Rendering: Too many draw calls
  2. Collision detection: Too many collision checks
  3. Memory allocation: Dynamic allocation in game loop
  4. Complex calculations: Expensive math operations
  5. String operations: String concatenation/formatting
"},{"location":"manual/optimization/performance_tuning/#tecnicas-de-optimizacion","title":"T\u00e9cnicas de Optimizaci\u00f3n","text":"

El motor utiliza varias t\u00e9cnicas para maximizar los FPS, especialmente en hardware limitado como el ESP32.

"},{"location":"manual/optimization/performance_tuning/#1-independent-resolution-scaling-escalado-de-resolucion","title":"1. Independent Resolution Scaling (Escalado de Resoluci\u00f3n)","text":"

Esta es probablemente la optimizaci\u00f3n m\u00e1s impactante para el ESP32. Permite renderizar el juego a una resoluci\u00f3n l\u00f3gica menor (ej: 128x128) y reescalarla autom\u00e1ticamente a la resoluci\u00f3n f\u00edsica de la pantalla (ej: 240x240).

  • Reducci\u00f3n de Memoria: Un buffer de 128x128 (8bpp) consume solo 16KB, comparado con los 57KB de uno de 240x240.
  • Aumento de FPS: Al haber menos p\u00edxeles que procesar por cada primitiva o sprite, el rendimiento puede duplicarse.
  • Implementaci\u00f3n: Se realiza mediante Hardware-accelerated Nearest Neighbor durante la transferencia DMA.

Consulta la gu\u00eda completa de Resolution Scaling para aprender a configurarlo.

"},{"location":"manual/optimization/performance_tuning/#2-viewport-culling-recorte-de-camara","title":"2. Viewport Culling (Recorte de C\u00e1mara)","text":"

No proceses objetos que est\u00e1n fuera de la pantalla. El motor lo hace autom\u00e1ticamente en drawTileMap, pero debes implementarlo en tu l\u00f3gica de actualizaci\u00f3n:

bool isOnScreen(float x, float y, int width, int height, \n                const Camera2D& camera) {\n    float cameraX = camera.getX();\n    float cameraY = camera.getY();\n    int screenWidth = engine.getRenderer().getLogicalWidth();\n    int screenHeight = engine.getRenderer().getLogicalHeight();\n\n    return !(x + width < cameraX || \n             x > cameraX + screenWidth ||\n             y + height < cameraY || \n             y > cameraY + screenHeight);\n}\n
"},{"location":"manual/optimization/performance_tuning/#2-optimizacion-de-memoria-y-cpu-esp32","title":"2. Optimizaci\u00f3n de Memoria y CPU (ESP32)","text":"

Para la plataforma ESP32, se han implementado optimizaciones de bajo nivel cr\u00edticas:

  • IRAM_ATTR: Las funciones cr\u00edticas de renderizado (drawSprite, drawTileMap, etc.) est\u00e1n marcadas para ejecutarse desde la RAM interna (IRAM), eliminando la latencia de lectura de la Flash SPI.
  • DMA (Direct Memory Access): El volcado del buffer a la pantalla TFT se realiza mediante DMA, lo que permite que la CPU comience a procesar el siguiente frame mientras el hardware transfiere los datos.
  • Acceso a Datos de 16 bits: Los sprites de 2bpp y 4bpp utilizan punteros uint16_t* para garantizar accesos alineados a memoria, lo cual es significativamente m\u00e1s r\u00e1pido en la arquitectura Xtensa del ESP32.
"},{"location":"manual/optimization/performance_tuning/#3-optimizacion-de-tilemaps","title":"3. Optimizaci\u00f3n de TileMaps","text":"

El renderizado de mapas de tiles es una de las operaciones m\u00e1s costosas. PixelRoot32 utiliza:

  • Cach\u00e9 de Paleta: Durante el dibujado de un tilemap, se genera una tabla de b\u00fasqueda (LUT) temporal para evitar c\u00e1lculos de color redundantes por cada p\u00edxel.
  • Dibujado por Columnas: Optimizado para minimizar los saltos de memoria en el framebuffer.
"},{"location":"manual/optimization/performance_tuning/#4-colisiones-eficientes","title":"4. Colisiones Eficientes","text":"

Usa colisiones basadas en tiles siempre que sea posible. Acceder a un array de tiles es O(1), mientras que iterar sobre una lista de entidades es O(n).

// Ejemplo de colisi\u00f3n r\u00e1pida con el mapa\nint tileX = x / 8;\nint tileY = y / 8;\nif (levelMap.data[tileY * levelMap.width + tileX] != 0) {\n    // Colisi\u00f3n detectada\n}\n
"},{"location":"manual/optimization/performance_tuning/#recomendaciones-generales","title":"Recomendaciones Generales","text":"
  • Sprites Indexados: Prefiere Sprite2bpp (4 colores) o Sprite4bpp (16 colores) sobre Sprite (1bpp) si necesitas color, ya que est\u00e1n altamente optimizados.
  • Evitar std::string en el Loop: Las concatenaciones de strings generan fragmentaci\u00f3n de memoria. Usa buffers est\u00e1ticos o char[] para textos din\u00e1micos.
  • Perfilado: Activa el overlay de estad\u00edsticas de depuraci\u00f3n compilando con PIXELROOT32_ENABLE_DEBUG_OVERLAY (ver Engine - Debug Overlay) para monitorear FPS, RAM y carga de CPU en tiempo real.
"},{"location":"manual/optimization/performance_tuning/#common-optimization-patterns","title":"Common Optimization Patterns","text":""},{"location":"manual/optimization/performance_tuning/#update-frequency-reduction","title":"Update Frequency Reduction","text":"
class LowFrequencyUpdater {\nprivate:\n    unsigned long timer = 0;\n    unsigned long interval = 100; // Update every 100ms\n\npublic:\n    void update(unsigned long deltaTime) {\n        timer += deltaTime;\n        if (timer >= interval) {\n            timer -= interval;\n            // Do expensive update\n            expensiveUpdate();\n        }\n    }\n};\n
"},{"location":"manual/optimization/performance_tuning/#spatial-partitioning-simple","title":"Spatial Partitioning (Simple)","text":"
// Divide screen into zones\nclass SpatialGrid {\nprivate:\n    static const int GRID_SIZE = 4;\n    static const int CELL_WIDTH = 60;\n    static const int CELL_HEIGHT = 60;\n\n    std::vector<Actor*> grid[GRID_SIZE][GRID_SIZE];\n\npublic:\n    void add(Actor* actor) {\n        int cellX = static_cast<int>(actor->x) / CELL_WIDTH;\n        int cellY = static_cast<int>(actor->y) / CELL_HEIGHT;\n        if (cellX >= 0 && cellX < GRID_SIZE && \n            cellY >= 0 && cellY < GRID_SIZE) {\n            grid[cellY][cellX].push_back(actor);\n        }\n    }\n\n    void checkCollisions() {\n        // Only check collisions within same cell\n        for (int y = 0; y < GRID_SIZE; y++) {\n            for (int x = 0; x < GRID_SIZE; x++) {\n                auto& cell = grid[y][x];\n                for (size_t i = 0; i < cell.size(); i++) {\n                    for (size_t j = i + 1; j < cell.size(); j++) {\n                        checkCollision(cell[i], cell[j]);\n                    }\n                }\n            }\n        }\n    }\n};\n
"},{"location":"manual/optimization/performance_tuning/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/performance_tuning/#low-fps","title":"Low FPS","text":"
  • Profile to find bottlenecks
  • Reduce entity count
  • Optimize rendering (culling, batching)
  • Simplify collision detection
  • Reduce update frequency
"},{"location":"manual/optimization/performance_tuning/#frame-drops","title":"Frame Drops","text":"
  • Check for expensive operations in update()
  • Avoid dynamic allocation
  • Cache calculations
  • Reduce draw calls
"},{"location":"manual/optimization/performance_tuning/#stuttering","title":"Stuttering","text":"
  • Ensure frame-rate independence (use deltaTime)
  • Avoid blocking operations
  • Pre-load resources
  • Use object pooling
"},{"location":"manual/optimization/performance_tuning/#next-steps","title":"Next Steps","text":"

Now that you understand performance optimization, learn about: - Memory Management - Manage memory efficiently - Platforms and Drivers - Platform-specific optimizations - Extensibility - Extend the engine

See also: - Manual - Basic Rendering - Manual - Physics and Collisions

"},{"location":"manual/optimization/platforms_and_drivers/","title":"Platforms and Drivers","text":"

PixelRoot32 supports multiple platforms through driver abstraction. This guide covers supported platforms, display drivers, audio backends, and build configuration.

"},{"location":"manual/optimization/platforms_and_drivers/#supported-platforms","title":"Supported Platforms","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32","title":"ESP32","text":"

Primary platform for PixelRoot32 games.

Characteristics: - TFT_eSPI display driver - Internal DAC or I2S audio - GPIO button input - Limited RAM/Flash - Real hardware constraints

Use for: - Final game deployment - Hardware testing - Production builds

"},{"location":"manual/optimization/platforms_and_drivers/#nativedesktop-sdl2","title":"Native/Desktop (SDL2)","text":"

Development platform for rapid iteration.

Characteristics: - SDL2 display driver - SDL2 audio backend - Keyboard input - Unlimited resources (for testing) - Fast development cycle

Use for: - Development and debugging - Testing without hardware - Rapid prototyping - CI/CD testing

"},{"location":"manual/optimization/platforms_and_drivers/#display-drivers","title":"Display Drivers","text":""},{"location":"manual/optimization/platforms_and_drivers/#tft_espi-esp32","title":"TFT_eSPI (ESP32)","text":"

TFT_eSPI is the display driver for ESP32, supporting many TFT displays.

"},{"location":"manual/optimization/platforms_and_drivers/#optimizaciones-esp32","title":"Optimizaciones ESP32","text":"

Para maximizar el rendimiento en ESP32, PixelRoot32 utiliza:

  • DMA (Direct Memory Access): Las transferencias al display se realizan en segundo plano, permitiendo que la CPU prepare el siguiente frame mientras se env\u00eda el actual.
  • Independent Resolution Scaling: El driver soporta resoluciones l\u00f3gicas menores que las f\u00edsicas, realizando el escalado Nearest-Neighbor on-the-fly durante la transferencia DMA para ahorrar RAM y ganar FPS.
  • Doble Buffer con IRAM: El motor utiliza un buffer de pantalla (Sprite de TFT_eSPI) optimizado para transferencias r\u00e1pidas.
  • Alineaci\u00f3n de 16 bits: Los datos de sprites 2bpp/4bpp est\u00e1n alineados a palabras de 16 bits para aprovechar la arquitectura Xtensa.
  • IRAM_ATTR: Las funciones cr\u00edticas de renderizado est\u00e1n marcadas para residir en la RAM de instrucciones, evitando cuellos de botella por acceso a la Flash.
"},{"location":"manual/optimization/platforms_and_drivers/#configuracion-dma","title":"Configuraci\u00f3n DMA","text":"

El DMA se activa autom\u00e1ticamente si el hardware lo soporta. Aseg\u00farate de configurar la frecuencia SPI adecuada para tu display (usualmente 40MHz u 80MHz).

[env:esp32dev]\nbuild_flags = \n    -D ST7789_DRIVER          # Display type\n    -D TFT_WIDTH=240          # Display width\n    -D TFT_HEIGHT=240         # Display height\n    -D TFT_MOSI=23            # SPI MOSI pin\n    -D TFT_SCLK=18            # SPI clock pin\n    -D TFT_DC=2               # Data/Command pin\n    -D TFT_RST=4              # Reset pin\n    -D TFT_CS=-1              # Chip select (-1 if not used)\n    -D SPI_FREQUENCY=40000000 # SPI frequency\n
"},{"location":"manual/optimization/platforms_and_drivers/#supported-displays","title":"Supported Displays","text":"
  • ST7735: 128x128, 128x160
  • ST7789: 240x240, 240x320
  • ILI9341: 240x320
  • And more: See TFT_eSPI documentation
"},{"location":"manual/optimization/platforms_and_drivers/#usage","title":"Usage","text":"
#include <drivers/esp32/TFT_eSPI_Drawer.h>\n\n// Display configuration\n// 128x128 logic scaled to 240x240 hardware\npixelroot32::graphics::DisplayConfig displayConfig(\n    pixelroot32::graphics::DisplayType::ST7789,\n    0,      // rotation\n    240, 240, // physical width, height\n    128, 128  // logical width, height\n);\n\n// TFT_eSPI_Drawer is created automatically by Engine\n// No manual driver creation needed\n
"},{"location":"manual/optimization/platforms_and_drivers/#sdl2_drawer-native","title":"SDL2_Drawer (Native)","text":"

SDL2_Drawer provides display output for PC/desktop development.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration","title":"Configuration","text":"
#include <drivers/native/SDL2_Drawer.h>\n\n// Display configuration (NONE defaults to SDL2)\npixelroot32::graphics::DisplayConfig displayConfig(\n    pixelroot32::graphics::DisplayType::NONE,\n    0,      // rotation\n    240,    // width\n    240     // height\n);\n\n// SDL2_Drawer is created automatically\n
"},{"location":"manual/optimization/platforms_and_drivers/#sdl2-installation","title":"SDL2 Installation","text":"

Windows (MSYS2):

pacman -S mingw-w64-x86_64-SDL2\n

Linux:

sudo apt-get install libsdl2-dev\n

macOS:

brew install sdl2\n

"},{"location":"manual/optimization/platforms_and_drivers/#audio-backends","title":"Audio Backends","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32_dac_audiobackend","title":"ESP32_DAC_AudioBackend","text":"

Uses ESP32's internal DAC for audio output.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration_1","title":"Configuration","text":"
#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nconst int DAC_PIN = 25; // GPIO 25 or 26\npixelroot32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(\n    DAC_PIN,    // DAC pin (25 or 26)\n    11025       // Sample rate (Hz)\n);\n\npixelroot32::audio::AudioConfig audioConfig(\n    &audioBackend, \n    audioBackend.getSampleRate()\n);\n

Characteristics: - Simple setup (just one pin) - Lower quality than I2S - Good for basic audio - Sample rate: 11025 Hz recommended

"},{"location":"manual/optimization/platforms_and_drivers/#esp32_i2s_audiobackend","title":"ESP32_I2S_AudioBackend","text":"

Uses ESP32's I2S peripheral for higher quality audio.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration_2","title":"Configuration","text":"
#include <drivers/esp32/ESP32_I2S_AudioBackend.h>\n\nconst int I2S_BCLK = 26;  // Bit clock pin\nconst int I2S_LRCK = 25;  // Left/Right clock pin\nconst int I2S_DOUT = 22;  // Data out pin\n\npixelroot32::drivers::esp32::ESP32_I2S_AudioBackend audioBackend(\n    I2S_BCLK,\n    I2S_LRCK,\n    I2S_DOUT,\n    22050  // Sample rate (Hz)\n);\n\npixelroot32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n

Characteristics: - Higher quality than DAC - Requires external I2S DAC (e.g., MAX98357A) - Better for music - Sample rate: 22050 Hz recommended

"},{"location":"manual/optimization/platforms_and_drivers/#sdl2_audiobackend-native","title":"SDL2_AudioBackend (Native)","text":"

SDL2 audio for PC development.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration_3","title":"Configuration","text":"
#include <drivers/native/SDL2_AudioBackend.h>\n\npixelroot32::drivers::native::SDL2_AudioBackend audioBackend(\n    22050,  // Sample rate\n    1024    // Buffer size\n);\n\npixelroot32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n
"},{"location":"manual/optimization/platforms_and_drivers/#build-flags","title":"Build Flags","text":""},{"location":"manual/optimization/platforms_and_drivers/#experimental-features","title":"Experimental Features","text":"

Enable experimental features with build flags:

[env:esp32dev]\nbuild_flags = \n    -D PIXELROOT32_ENABLE_2BPP_SPRITES    # Enable 2bpp sprite format\n    - D PIXELROOT32_ENABLE_4BPP_SPRITES   # Enable 4bpp sprite format\n    - D PIXELROOT32_ENABLE_SCENE_ARENA    # Enable Scene Arena (experimental)\n    - D PIXELROOT32_ENABLE_DEBUG_OVERLAY  # On-screen debug statistics (FPS, RAM, CPU load; throttled update)\n
"},{"location":"manual/optimization/platforms_and_drivers/#debug-statistics-overlay-pixelroot32_enable_debug_overlay","title":"Debug Statistics Overlay (PIXELROOT32_ENABLE_DEBUG_OVERLAY)","text":"

When defined, the engine draws a technical overlay (FPS, RAM, CPU load) in the top-right area of the screen each frame. Values are updated every 16 frames to maintain performance. No code changes are required. See API Reference - Engine - Optional: Debug Overlay for details.

"},{"location":"manual/optimization/platforms_and_drivers/#scene-limits-max_layers-max_entities","title":"Scene limits (MAX_LAYERS / MAX_ENTITIES)","text":"

You can override the default scene limits from your project without modifying the engine. The default of 3 for MAX_LAYERS is due to ESP32 platform constraints (memory and draw-loop cost); on native/PC you can use a higher value.

Option A: Compiler flags (recommended) \u2014 in platformio.ini, add to build_flags for your environment:

build_flags =\n    -DMAX_LAYERS=5\n    -DMAX_ENTITIES=64\n

The compiler defines these before any .cpp is processed. Because Scene.h uses #ifndef MAX_LAYERS / #ifndef MAX_ENTITIES, your values are used (more render layers drawn in Scene::draw, and on Arduino the entity queue capacity when built with MAX_ENTITIES).

See API Reference - Scene - Overriding scene limits for details.

"},{"location":"manual/optimization/platforms_and_drivers/#platform-detection","title":"Platform Detection","text":"
#ifdef PLATFORM_ESP32\n    // ESP32-specific code\n    Serial.println(\"Running on ESP32\");\n#endif\n\n#ifdef PLATFORM_NATIVE\n    // Native/PC-specific code\n    printf(\"Running on PC\\n\");\n#endif\n
"},{"location":"manual/optimization/platforms_and_drivers/#optimization-flags","title":"Optimization Flags","text":"
[env:esp32dev]\nbuild_flags = \n    -O2              # Optimization level\n    -ffunction-sections\n    -fdata-sections\n    -Wl,--gc-sections\n
"},{"location":"manual/optimization/platforms_and_drivers/#complete-platform-setup-examples","title":"Complete Platform Setup Examples","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32-complete-setup","title":"ESP32 Complete Setup","text":"
#include <Arduino.h>\n#include <core/Engine.h>\n#include <drivers/esp32/TFT_eSPI_Drawer.h>\n#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\n// Audio\nconst int DAC_PIN = 25;\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\n// Display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::ST7789,\n    0, 240, 240\n);\n\n// Input\npr32::input::InputConfig inputConfig(\n    6, 32, 27, 33, 14, 13, 12  // 6 buttons, pins\n);\n\n// Audio config\npr32::audio::AudioConfig audioConfig(&audioBackend, 11025);\n\n// Engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nvoid setup() {\n    Serial.begin(115200);\n    engine.init();\n    // ... scene setup\n}\n\nvoid loop() {\n    engine.run();\n}\n
"},{"location":"manual/optimization/platforms_and_drivers/#native-complete-setup","title":"Native Complete Setup","text":"
#define SDL_MAIN_HANDLED\n#include <SDL2/SDL.h>\n#include <core/Engine.h>\n#include <drivers/native/SDL2_Drawer.h>\n#include <drivers/native/SDL2_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\n// Audio\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\n\n// Display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::NONE,\n    0, 240, 240\n);\n\n// Input (SDL scancodes)\npr32::input::InputConfig inputConfig(\n    6,\n    SDL_SCANCODE_UP,\n    SDL_SCANCODE_DOWN,\n    SDL_SCANCODE_LEFT,\n    SDL_SCANCODE_RIGHT,\n    SDL_SCANCODE_SPACE,\n    SDL_SCANCODE_RETURN\n);\n\n// Audio config\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n\n// Engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nint main(int argc, char* argv[]) {\n    engine.init();\n    // ... scene setup\n    engine.run();\n    return 0;\n}\n
"},{"location":"manual/optimization/platforms_and_drivers/#platform-specific-considerations","title":"Platform-Specific Considerations","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32_1","title":"ESP32","text":"

Memory: - Limited RAM (~320KB) - Use object pooling - Store data in flash - Avoid dynamic allocation

Performance: - Target 30-60 FPS - Optimize rendering - Reduce entity count - Profile on hardware

Hardware: - GPIO pin configuration - SPI display setup - Audio hardware connections - Power considerations

"},{"location":"manual/optimization/platforms_and_drivers/#native","title":"Native","text":"

Development: - Fast iteration - Easy debugging - Unlimited resources - Visual debugging tools

Testing: - Test logic without hardware - Rapid prototyping - CI/CD integration - Cross-platform testing

"},{"location":"manual/optimization/platforms_and_drivers/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32-display-issues","title":"ESP32 Display Issues","text":"
  • Check wiring connections
  • Verify pin numbers
  • Lower SPI frequency
  • Check display type matches
  • Verify power supply
"},{"location":"manual/optimization/platforms_and_drivers/#esp32-audio-issues","title":"ESP32 Audio Issues","text":"
  • Check DAC/I2S pin configuration
  • Verify sample rate
  • Check hardware connections
  • Lower volume if distorted
  • Test with different sample rates
"},{"location":"manual/optimization/platforms_and_drivers/#native-build-issues","title":"Native Build Issues","text":"
  • Verify SDL2 installation
  • Check include/library paths
  • Ensure SDL2 version compatibility
  • Check linker flags
"},{"location":"manual/optimization/platforms_and_drivers/#next-steps","title":"Next Steps","text":"

Now that you understand platforms and drivers, learn about: - Extensibility - Create custom drivers - Memory Management - ESP32 memory constraints - Performance Optimization - Platform-specific optimization

See also: - API Reference - DrawSurface - API Reference - AudioBackend - Getting Started - Your First Project

"},{"location":"reference/api_overview/","title":"API Reference Overview","text":"

This document provides a complete technical reference for all PixelRoot32 APIs, organized by module. Each class includes descriptions, constructors, methods, properties, and usage examples.

"},{"location":"reference/api_overview/#organization","title":"Organization","text":"

The API is organized into the following modules:

  • Core: Engine, Scene, Entity, Actor, PhysicsActor, SceneManager
  • Graphics: Renderer, Camera2D, Color, Font, Sprite, TileMap, DrawSurface
  • Audio: AudioEngine, MusicPlayer, AudioTypes, AudioConfig, AudioBackend
  • Input: InputManager, InputConfig
  • Physics: CollisionSystem, CollisionTypes
  • UI: UIElement, UIButton, UILabel, UILayouts
  • Particles: ParticleEmitter, ParticleConfig, ParticlePresets
"},{"location":"reference/api_overview/#quick-navigation","title":"Quick Navigation","text":""},{"location":"reference/api_overview/#core-module","title":"Core Module","text":"
  • Engine - Main engine class, game loop management
  • Scene - Scene/level management
  • Entity - Base game object class
  • Actor - Entity with collision support
  • PhysicsActor - Actor with automatic physics
  • InputManager - Input handling
  • InputConfig - Input configuration
"},{"location":"reference/api_overview/#graphics-module","title":"Graphics Module","text":"
  • Renderer - High-level rendering API
  • Camera2D - 2D camera for scrolling
  • Color - Color constants and utilities
  • Font - Bitmap font system
  • Sprite - Sprite structures and formats
  • TileMap - Tilemap structure
  • DisplayConfig - Display configuration
"},{"location":"reference/api_overview/#audio-module","title":"Audio Module","text":"
  • AudioEngine - Sound effects playback
  • MusicPlayer - Background music playback
  • AudioTypes - Audio data structures
  • AudioConfig - Audio configuration
"},{"location":"reference/api_overview/#physics-module","title":"Physics Module","text":"
  • CollisionSystem - Collision detection
  • CollisionTypes - Collision primitives
"},{"location":"reference/api_overview/#ui-module","title":"UI Module","text":"
  • UIElement - Base UI element class
  • UIButton - Clickable button
  • UILabel - Text label
  • UILayouts - Layout containers
"},{"location":"reference/api_overview/#api-documentation-format","title":"API Documentation Format","text":"

Each API reference page follows this structure:

"},{"location":"reference/api_overview/#class-name","title":"Class Name","text":"

Brief description of the class and its purpose.

"},{"location":"reference/api_overview/#namespace","title":"Namespace","text":"
namespace pixelroot32::module {\n    class ClassName {\n        // ...\n    };\n}\n
"},{"location":"reference/api_overview/#constructors","title":"Constructors","text":"

List of all constructors with parameters.

"},{"location":"reference/api_overview/#public-methods","title":"Public Methods","text":"Method Description Parameters Returns methodName() Description param: type return type"},{"location":"reference/api_overview/#properties","title":"Properties","text":"Property Type Description property type Description"},{"location":"reference/api_overview/#usage-example","title":"Usage Example","text":"
// Example code showing typical usage\n
"},{"location":"reference/api_overview/#performance-notes","title":"Performance Notes","text":"

Any performance considerations or limitations.

"},{"location":"reference/api_overview/#see-also","title":"See Also","text":"

Links to related APIs and documentation.

"},{"location":"reference/api_overview/#finding-apis","title":"Finding APIs","text":""},{"location":"reference/api_overview/#by-functionality","title":"By Functionality","text":"
  • Game Loop: See Engine
  • Rendering: See Renderer
  • Input: See InputManager
  • Audio: See AudioEngine and MusicPlayer
  • Physics: See PhysicsActor and CollisionSystem
  • UI: See UIElement and layouts
"},{"location":"reference/api_overview/#by-module","title":"By Module","text":"

Navigate to the specific module folder: - api_reference/core/ - Core engine classes - api_reference/graphics/ - Rendering and graphics - api_reference/audio/ - Audio system - api_reference/physics/ - Physics and collisions - api_reference/ui/ - User interface

"},{"location":"reference/api_overview/#complete-api-list","title":"Complete API List","text":""},{"location":"reference/api_overview/#core","title":"Core","text":"
  • Engine
  • Scene
  • Entity
  • Actor
  • PhysicsActor
  • InputManager
  • InputConfig
"},{"location":"reference/api_overview/#graphics","title":"Graphics","text":"
  • Renderer
  • Camera2D
  • Color
  • Font
  • Sprite
  • TileMap
  • DisplayConfig
"},{"location":"reference/api_overview/#audio","title":"Audio","text":"
  • AudioEngine
  • MusicPlayer
  • AudioTypes
  • AudioConfig
"},{"location":"reference/api_overview/#physics","title":"Physics","text":"
  • CollisionSystem
  • CollisionTypes
"},{"location":"reference/api_overview/#ui","title":"UI","text":"
  • UIElement
  • UIButton
  • UILabel
  • UIVerticalLayout
  • UIHorizontalLayout
  • UIGridLayout
  • UIAnchorLayout
  • UIPanel
  • UIPaddingContainer
"},{"location":"reference/api_overview/#related-documentation","title":"Related Documentation","text":"
  • Manual - Game Development - How to use the APIs
  • Manual - Advanced Graphics - Advanced techniques
  • Code Examples - Reusable code snippets
  • Game Examples Guide - Learn from complete games

Note: This is an overview. For detailed API documentation, see the individual reference pages linked above.

"},{"location":"reference/code_examples/","title":"Code Examples","text":"

A library of reusable code snippets for common PixelRoot32 tasks. All examples are complete and functional.

"},{"location":"reference/code_examples/#initialization","title":"Initialization","text":""},{"location":"reference/code_examples/#basic-engine-setup-esp32","title":"Basic Engine Setup (ESP32)","text":"
#include <Arduino.h>\n#include <core/Engine.h>\n#include <drivers/esp32/TFT_eSPI_Drawer.h>\n#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\n// Audio\nconst int DAC_PIN = 25;\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\n// Display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::ST7789,\n    0, 240, 240\n);\n\n// Input\npr32::input::InputConfig inputConfig(6, 32, 27, 33, 14, 13, 12);\n\n// Audio config\npr32::audio::AudioConfig audioConfig(&audioBackend, 11025);\n\n// Engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nvoid setup() {\n    Serial.begin(115200);\n    engine.init();\n    // ... scene setup\n}\n\nvoid loop() {\n    engine.run();\n}\n
"},{"location":"reference/code_examples/#basic-engine-setup-native","title":"Basic Engine Setup (Native)","text":"
#define SDL_MAIN_HANDLED\n#include <SDL2/SDL.h>\n#include <core/Engine.h>\n#include <drivers/native/SDL2_Drawer.h>\n#include <drivers/native/SDL2_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::NONE, 0, 240, 240\n);\npr32::input::InputConfig inputConfig(\n    6, SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, \n    SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT,\n    SDL_SCANCODE_SPACE, SDL_SCANCODE_RETURN\n);\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nint main(int argc, char* argv[]) {\n    engine.init();\n    // ... scene setup\n    engine.run();\n    return 0;\n}\n
"},{"location":"reference/code_examples/#entity-movement","title":"Entity Movement","text":""},{"location":"reference/code_examples/#simple-movement","title":"Simple Movement","text":"
class MovingEntity : public pixelroot32::core::Entity {\nprivate:\n    float speedX = 50.0f;\n    float speedY = 30.0f;\n\npublic:\n    MovingEntity(float x, float y)\n        : Entity(x, y, 16, 16, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        float dt = deltaTime * 0.001f;\n        x += speedX * dt;\n        y += speedY * dt;\n\n        // Bounce off edges\n        if (x < 0 || x > 224) speedX = -speedX;\n        if (y < 0 || y > 224) speedY = -speedY;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width, height,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n};\n
"},{"location":"reference/code_examples/#input-based-movement","title":"Input-Based Movement","text":"
class PlayerEntity : public pixelroot32::core::Actor {\nprivate:\n    float speed = 100.0f;\n\npublic:\n    PlayerEntity(float x, float y)\n        : Actor(x, y, 16, 16) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        if (input.isButtonDown(Buttons::LEFT)) {\n            x -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::RIGHT)) {\n            x += speed * dt;\n        }\n        if (input.isButtonDown(Buttons::UP)) {\n            y -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::DOWN)) {\n            y += speed * dt;\n        }\n\n        // Keep on screen\n        if (x < 0) x = 0;\n        if (x > 224) x = 224;\n        if (y < 0) y = 0;\n        if (y > 224) y = 224;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width, height,\n            pixelroot32::graphics::Color::White\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collision\n    }\n};\n
"},{"location":"reference/code_examples/#collisions","title":"Collisions","text":""},{"location":"reference/code_examples/#basic-collision-detection","title":"Basic Collision Detection","text":"
class CollidableEntity : public pixelroot32::core::Actor {\npublic:\n    CollidableEntity(float x, float y)\n        : Actor(x, y, 16, 16) {\n        setRenderLayer(1);\n        setCollisionLayer(Layers::PLAYER);\n        setCollisionMask(Layers::ENEMY | Layers::WALL);\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        if (other->isInLayer(Layers::ENEMY)) {\n            // Hit enemy\n            takeDamage();\n        } else if (other->isInLayer(Layers::WALL)) {\n            // Hit wall\n            stopMovement();\n        }\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"reference/code_examples/#collision-layers-setup","title":"Collision Layers Setup","text":"
// Define in GameLayers.h\nnamespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;\n    constexpr uint16_t ENEMY = 0x0002;\n    constexpr uint16_t PROJECTILE = 0x0004;\n    constexpr uint16_t WALL = 0x0008;\n    constexpr uint16_t PICKUP = 0x0010;\n}\n\n// Usage\nplayer->setCollisionLayer(Layers::PLAYER);\nplayer->setCollisionMask(Layers::ENEMY | Layers::WALL);\n\nenemy->setCollisionLayer(Layers::ENEMY);\nenemy->setCollisionMask(Layers::PLAYER | Layers::PROJECTILE);\n
"},{"location":"reference/code_examples/#sound-effects","title":"Sound Effects","text":""},{"location":"reference/code_examples/#common-sound-effects","title":"Common Sound Effects","text":"
namespace SoundEffects {\n    inline pixelroot32::audio::AudioEvent jump() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 600.0f;\n        evt.duration = 0.1f;\n        evt.volume = 0.7f;\n        evt.duty = 0.25f;\n        return evt;\n    }\n\n    inline pixelroot32::audio::AudioEvent coin() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 1500.0f;\n        evt.duration = 0.12f;\n        evt.volume = 0.8f;\n        evt.duty = 0.5f;\n        return evt;\n    }\n\n    inline pixelroot32::audio::AudioEvent explosion() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::NOISE;\n        evt.frequency = 200.0f;\n        evt.duration = 0.3f;\n        evt.volume = 0.9f;\n        return evt;\n    }\n}\n\n// Usage\nengine.getAudioEngine().playEvent(SoundEffects::jump());\n
"},{"location":"reference/code_examples/#playing-sound-on-event","title":"Playing Sound on Event","text":"
class PlayerActor : public pixelroot32::core::Actor {\npublic:\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n\n        if (input.isButtonPressed(Buttons::A)) {\n            // Play jump sound\n            pixelroot32::audio::AudioEvent jumpSound{};\n            jumpSound.type = pixelroot32::audio::WaveType::PULSE;\n            jumpSound.frequency = 800.0f;\n            jumpSound.duration = 0.1f;\n            jumpSound.volume = 0.7f;\n            jumpSound.duty = 0.25f;\n\n            engine.getAudioEngine().playEvent(jumpSound);\n\n            // Jump logic\n            jump();\n        }\n    }\n};\n
"},{"location":"reference/code_examples/#ui-components","title":"UI Components","text":""},{"location":"reference/code_examples/#simple-menu","title":"Simple Menu","text":"
class MenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIVerticalLayout* menu;\n\npublic:\n    void init() override {\n        menu = new pixelroot32::graphics::ui::UIVerticalLayout(40, 60, 160, 160);\n        menu->setPadding(10);\n        menu->setSpacing(8);\n        menu->setNavigationButtons(0, 1);\n        menu->setButtonStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Cyan,\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Black\n        );\n\n        menu->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Start\", 0, 0, 0, 140, 25, []() { startGame(); }\n        ));\n\n        menu->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Options\", 1, 0, 0, 140, 25, []() { showOptions(); }\n        ));\n\n        addEntity(menu);\n    }\n\n    void update(unsigned long deltaTime) override {\n        menu->handleInput(engine.getInputManager());\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"reference/code_examples/#hud-with-labels","title":"HUD with Labels","text":"
class GameHUD : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n\npublic:\n    GameHUD()\n        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::UI_ELEMENT) {\n        setRenderLayer(2);\n\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\", 10, 10,\n            pixelroot32::graphics::Color::White, 1\n        );\n\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\", 10, 20,\n            pixelroot32::graphics::Color::White, 1\n        );\n    }\n\n    void updateHUD(int score, int lives) {\n        char buffer[32];\n        snprintf(buffer, sizeof(buffer), \"Score: %d\", score);\n        scoreLabel->setText(buffer);\n\n        snprintf(buffer, sizeof(buffer), \"Lives: %d\", lives);\n        livesLabel->setText(buffer);\n    }\n};\n
"},{"location":"reference/code_examples/#physics","title":"Physics","text":""},{"location":"reference/code_examples/#bouncing-ball","title":"Bouncing Ball","text":"
class BouncingBall : public pixelroot32::core::PhysicsActor {\npublic:\n    BouncingBall(float x, float y, float radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRenderLayer(1);\n        setRestitution(0.9f);\n        setFriction(0.05f);\n        setWorldSize(240, 240);\n        setVelocity(50.0f, -30.0f);\n    }\n\n    void update(unsigned long deltaTime) override {\n        float gravity = 200.0f;\n        float dt = deltaTime * 0.001f;\n        setVelocity(vx, vy + gravity * dt);\n        PhysicsActor::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        int radius = width / 2;\n        renderer.drawFilledCircle(\n            static_cast<int>(x + radius),\n            static_cast<int>(y + radius),\n            radius,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"reference/code_examples/#platformer-player","title":"Platformer Player","text":"
class PlatformerPlayer : public pixelroot32::core::PhysicsActor {\nprivate:\n    bool canJump = true;\n    float jumpForce = 250.0f;\n    float moveSpeed = 100.0f;\n\npublic:\n    PlatformerPlayer(float x, float y)\n        : PhysicsActor(x, y, 16, 16) {\n        setRenderLayer(1);\n        setFriction(0.3f);\n        setWorldSize(240, 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        // Horizontal movement\n        float moveDir = 0.0f;\n        if (input.isButtonDown(Buttons::LEFT)) moveDir -= 1.0f;\n        if (input.isButtonDown(Buttons::RIGHT)) moveDir += 1.0f;\n        setVelocity(moveDir * moveSpeed, vy);\n\n        // Gravity\n        float gravity = 300.0f;\n        setVelocity(vx, vy + gravity * dt);\n\n        // Jump\n        if (input.isButtonPressed(Buttons::A) && canJump) {\n            setVelocity(vx, -jumpForce);\n            canJump = false;\n        }\n\n        PhysicsActor::update(deltaTime);\n\n        // Check if on ground\n        auto collisionInfo = getWorldCollisionInfo();\n        if (collisionInfo.bottom) {\n            canJump = true;\n        }\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"reference/code_examples/#sprites-and-animation","title":"Sprites and Animation","text":""},{"location":"reference/code_examples/#simple-sprite","title":"Simple Sprite","text":"
// Define sprite data\nstatic const uint16_t PLAYER_SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b01111110,\n    0b00111100,\n    0b00000000\n};\n\nstatic const pixelroot32::graphics::Sprite PLAYER_SPRITE = {\n    PLAYER_SPRITE_DATA, 8, 8\n};\n\n// Draw sprite\nrenderer.drawSprite(PLAYER_SPRITE, 100, 100, \n    pixelroot32::graphics::Color::White);\n
"},{"location":"reference/code_examples/#sprite-animation","title":"Sprite Animation","text":"
class AnimatedActor : public pixelroot32::core::Actor {\nprivate:\n    pixelroot32::graphics::SpriteAnimation animation;\n    unsigned long timer = 0;\n    const unsigned long FRAME_DURATION_MS = 100;\n\npublic:\n    AnimatedActor(float x, float y)\n        : Actor(x, y, 8, 8) {\n        setRenderLayer(1);\n        animation.frames = WALK_ANIMATION_FRAMES;\n        animation.frameCount = 3;\n        animation.current = 0;\n    }\n\n    void update(unsigned long deltaTime) override {\n        timer += deltaTime;\n        if (timer >= FRAME_DURATION_MS) {\n            timer -= FRAME_DURATION_MS;\n            animation.step();\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        const auto* frame = animation.frames[animation.current].sprite;\n        renderer.drawSprite(*frame, static_cast<int>(x), static_cast<int>(y),\n            pixelroot32::graphics::Color::White);\n    }\n};\n
"},{"location":"reference/code_examples/#camera-and-scrolling","title":"Camera and Scrolling","text":""},{"location":"reference/code_examples/#basic-camera-follow","title":"Basic Camera Follow","text":"
class ScrollingScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n        camera.setBounds(0, 2000 - screenWidth);\n\n        player = new PlayerActor(100, 100);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"reference/code_examples/#tilemaps","title":"Tilemaps","text":""},{"location":"reference/code_examples/#simple-tilemap","title":"Simple Tilemap","text":"
// Define tiles\nstatic const uint16_t TILE_EMPTY_BITS[] = { /* ... */ };\nstatic const uint16_t TILE_GROUND_BITS[] = { /* ... */ };\n\nstatic const pixelroot32::graphics::Sprite TILES[] = {\n    { TILE_EMPTY_BITS, 8, 8 },\n    { TILE_GROUND_BITS, 8, 8 }\n};\n\n// Create tilemap\nstatic uint8_t TILEMAP_INDICES[30 * 20];\nstatic pixelroot32::graphics::TileMap levelTileMap = {\n    TILEMAP_INDICES, 30, 20, TILES, 8, 8, 2\n};\n\n// Initialize\nvoid initTilemap() {\n    for (int i = 0; i < 30 * 20; i++) {\n        TILEMAP_INDICES[i] = 0;\n    }\n    // Set ground row\n    for (int x = 0; x < 30; x++) {\n        TILEMAP_INDICES[19 * 30 + x] = 1; // Ground tile\n    }\n}\n\n// Draw\nrenderer.drawTileMap(levelTileMap, 0, 0, \n    pixelroot32::graphics::Color::White);\n
"},{"location":"reference/code_examples/#particles","title":"Particles","text":""},{"location":"reference/code_examples/#explosion-effect","title":"Explosion Effect","text":"
#include <graphics/particles/ParticleEmitter.h>\n#include <graphics/particles/ParticlePresets.h>\n\nclass ExplosionEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* emitter;\n\npublic:\n    ExplosionEffect()\n        : Entity(0, 0, 1, 1, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n        emitter = new pixelroot32::graphics::particles::ParticleEmitter(\n            0, 0,\n            pixelroot32::graphics::particles::ParticlePresets::Explosion()\n        );\n    }\n\n    void trigger(float x, float y) {\n        this->x = x;\n        this->y = y;\n        emitter->burst(x, y, 25);\n    }\n\n    void update(unsigned long deltaTime) override {\n        emitter->update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        emitter->draw(renderer);\n    }\n};\n
"},{"location":"reference/code_examples/#object-pooling","title":"Object Pooling","text":""},{"location":"reference/code_examples/#entity-pool","title":"Entity Pool","text":"
template<typename T, int POOL_SIZE>\nclass EntityPool {\nprivate:\n    T pool[POOL_SIZE];\n    bool inUse[POOL_SIZE];\n    int activeCount = 0;\n\npublic:\n    EntityPool() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            inUse[i] = false;\n        }\n    }\n\n    T* acquire() {\n        if (activeCount >= POOL_SIZE) return nullptr;\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!inUse[i]) {\n                inUse[i] = true;\n                activeCount++;\n                return &pool[i];\n            }\n        }\n        return nullptr;\n    }\n\n    void release(T* obj) {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (&pool[i] == obj) {\n                inUse[i] = false;\n                activeCount--;\n                obj->isEnabled = false;\n                obj->isVisible = false;\n                break;\n            }\n        }\n    }\n};\n
"},{"location":"reference/code_examples/#common-patterns","title":"Common Patterns","text":""},{"location":"reference/code_examples/#state-machine","title":"State Machine","text":"
enum class GameState {\n    MENU,\n    PLAYING,\n    PAUSED,\n    GAME_OVER\n};\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    GameState currentState = GameState::MENU;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        switch (currentState) {\n            case GameState::MENU:\n                updateMenu();\n                break;\n            case GameState::PLAYING:\n                updateGame();\n                break;\n            case GameState::PAUSED:\n                updatePause();\n                break;\n            case GameState::GAME_OVER:\n                updateGameOver();\n                break;\n        }\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"reference/code_examples/#timer-pattern","title":"Timer Pattern","text":"
class Timer {\nprivate:\n    unsigned long duration;\n    unsigned long elapsed = 0;\n    bool active = false;\n\npublic:\n    Timer(unsigned long ms) : duration(ms) {}\n\n    void start() {\n        active = true;\n        elapsed = 0;\n    }\n\n    void update(unsigned long deltaTime) {\n        if (active) {\n            elapsed += deltaTime;\n            if (elapsed >= duration) {\n                active = false;\n            }\n        }\n    }\n\n    bool isFinished() const { return !active && elapsed >= duration; }\n    bool isActive() const { return active; }\n    float getProgress() const { return static_cast<float>(elapsed) / duration; }\n};\n
"},{"location":"reference/code_examples/#see-also","title":"See Also","text":"
  • API Reference Overview - Complete API documentation
  • Game Examples Guide - Learn from complete games
  • Manual - Game Development - Detailed guides
"},{"location":"reference/game_examples_guide/","title":"Game Examples Guide","text":"

This guide analyzes the complete game examples included with PixelRoot32, explaining their architecture, patterns, and lessons learned.

"},{"location":"reference/game_examples_guide/#available-examples","title":"Available Examples","text":"

PixelRoot32 (in the PixelRoot32 Game Samples project) includes these games and demos:

  • Metroidvania: 2D platformer with multi-layer 4bpp tilemap and tile-based collision (requires PIXELROOT32_ENABLE_4BPP_SPRITES; no scroll/camera)
  • Space Invaders: Full shooter with enemies, projectiles, bunkers and audio
  • Pong: Classic with physics and collisions
  • BrickBreaker: Breakout-style with particles and advanced audio
  • Snake: Grid-based game with entity pooling
  • TicTacToe: Turn-based with simple AI
  • CameraDemo: Platformer with camera and parallax
  • SpritesDemo: 2bpp and 4bpp sprites
  • TileMapDemo: 4bpp tilemaps (with viewport culling)
"},{"location":"reference/game_examples_guide/#space-invaders","title":"Space Invaders","text":"

Location: src/examples/SpaceInvaders/

"},{"location":"reference/game_examples_guide/#architecture","title":"Architecture","text":"

Space Invaders demonstrates a complete game with multiple systems:

  • Scene Management: SpaceInvadersScene manages game state
  • Actor Hierarchy: PlayerActor, AlienActor, ProjectileActor, BunkerActor
  • Collision System: Uses collision layers for player, enemies, projectiles
  • Audio Integration: Sound effects for shooting, explosions, music
  • Background: Starfield (code-generated star pattern) or tilemap
"},{"location":"reference/game_examples_guide/#key-systems","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#collision-layers","title":"Collision Layers","text":"
namespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;\n    constexpr uint16_t ALIEN = 0x0002;\n    constexpr uint16_t PROJECTILE = 0x0004;\n    constexpr uint16_t BUNKER = 0x0008;\n}\n\n// Player can collide with aliens and bunkers\nplayer->setCollisionLayer(Layers::PLAYER);\nplayer->setCollisionMask(Layers::ALIEN | Layers::BUNKER);\n\n// Projectiles can hit aliens and bunkers\nprojectile->setCollisionLayer(Layers::PROJECTILE);\nprojectile->setCollisionMask(Layers::ALIEN | Layers::BUNKER);\n
"},{"location":"reference/game_examples_guide/#entity-management","title":"Entity Management","text":"
  • Uses object pooling for projectiles
  • Manages alien formation with grid layout
  • Handles game state (playing, game over)
"},{"location":"reference/game_examples_guide/#audio-integration","title":"Audio Integration","text":"
  • Background music using MusicPlayer
  • Sound effects for various events
  • Audio events triggered on collisions
"},{"location":"reference/game_examples_guide/#patterns-used","title":"Patterns Used","text":"
  • Object Pooling: Projectiles are pooled and reused
  • State Machine: Game states (playing, game over, victory)
  • Grid Layout: Alien formation uses grid-based positioning
  • Event-Driven Audio: Sounds triggered by game events
"},{"location":"reference/game_examples_guide/#lessons-learned","title":"Lessons Learned","text":"
  • Collision layers are essential for complex games
  • Object pooling improves performance
  • Starfield or tilemap backgrounds are efficient
  • Audio enhances game feel significantly
"},{"location":"reference/game_examples_guide/#metroidvania","title":"Metroidvania","text":"

Location: src/examples/Games/Metroidvania/

Assets: Sprites and tilesets for this example come from the Tiny Metroidvania 8x8 pack by Kenmi (kenmi-art.itch.io).

"},{"location":"reference/game_examples_guide/#architecture_1","title":"Architecture","text":"

Metroidvania is a 2D platformer example with multi-layer tilemap and optimizations aimed at ESP32. It does not use scroll or camera; the level is drawn with a fixed origin (0,0).

  • Scene: MetroidvaniaScene with a single PlayerActor and several tilemap layers (background, platforms, details, stairs).
  • PlayerActor: Horizontal and vertical movement, stairs, tile-based collision (no rectangle lists).
  • Tilemap: 4bpp (TileMap4bpp), with viewport culling and palette cache in the engine. Level 40\u00d730 tiles (320\u00d7240 px).
  • No camera: The view does not follow the player; for scroll you would use Camera2D and apply offset in the renderer (as in CameraDemo).
"},{"location":"reference/game_examples_guide/#engine-features-used","title":"Engine features used","text":"
  • Tile-based collision: Direct tile checks around the player (getTileAt), instead of iterating over platformRects.
  • 4bpp sprites: Player with animations (idle, run, jump) from generated headers (e.g. Sprite Compiler).
  • Rendering optimizations: Viewport culling in drawTileMap, optimized 4bpp drawSprite, layers culled by viewport.
  • Optional: Scene arena, DMA, IRAM_ATTR on critical paths (per example optimization plan).
"},{"location":"reference/game_examples_guide/#patterns-used_1","title":"Patterns used","text":"
  • Tile-based collision: Single O(1) access per tile instead of O(N) rectangles.
  • Stair detection: Single result reused for collision and state change.
  • Simplified hitbox: Fewer vertical check points (head and feet).
"},{"location":"reference/game_examples_guide/#lessons-learned_1","title":"Lessons learned","text":"
  • Tile-based collision scales better than rectangle lists on large levels.
  • Viewport and 4bpp optimizations improve FPS on ESP32.
  • Metroidvania serves as a reference for platformers with tilemap and camera.
"},{"location":"reference/game_examples_guide/#pong","title":"Pong","text":"

Location: src/examples/Pong/

"},{"location":"reference/game_examples_guide/#architecture_2","title":"Architecture","text":"

Pong demonstrates physics and collision handling:

  • PhysicsActor: Ball uses PhysicsActor for automatic physics
  • Collision Callbacks: Paddles and ball handle collisions
  • Score System: Simple score tracking and display
  • Game State: Reset and game over handling
"},{"location":"reference/game_examples_guide/#key-systems_1","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#physics-setup","title":"Physics Setup","text":"
class BallActor : public pixelroot32::core::PhysicsActor {\npublic:\n    BallActor(float x, float y, float speed, int radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRestitution(0.8f);  // Bouncy\n        setFriction(0.1f);     // Low friction\n        setWorldSize(240, 240);\n    }\n};\n
"},{"location":"reference/game_examples_guide/#collision-response","title":"Collision Response","text":"
void BallActor::onCollision(pixelroot32::core::Actor* other) {\n    // Adjust ball position\n    // Modify velocity based on impact point\n    // Play bounce sound\n}\n
"},{"location":"reference/game_examples_guide/#patterns-used_2","title":"Patterns Used","text":"
  • Physics Integration: Uses PhysicsActor for automatic movement
  • Collision Response: Custom collision handling
  • Score Management: Simple state tracking
  • Audio Feedback: Sound on collision
"},{"location":"reference/game_examples_guide/#lessons-learned_2","title":"Lessons Learned","text":"
  • PhysicsActor simplifies physics-based games
  • Collision callbacks allow custom response logic
  • Simple games can be very effective
"},{"location":"reference/game_examples_guide/#snake","title":"Snake","text":"

Location: src/examples/Snake/

"},{"location":"reference/game_examples_guide/#architecture_3","title":"Architecture","text":"

Snake demonstrates entity pooling and grid-based movement:

  • Entity Pooling: Snake segments are pooled
  • Grid Movement: Movement constrained to grid
  • Game Logic: Food spawning, collision detection
  • State Management: Game over, reset functionality
"},{"location":"reference/game_examples_guide/#key-systems_2","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#entity-pooling","title":"Entity Pooling","text":"
class SnakeScene {\nprivate:\n    std::vector<SnakeSegmentActor*> segmentPool;\n    std::vector<SnakeSegmentActor*> snakeSegments;\n\n    void resetGame() {\n        // Reuse pooled segments\n        for (int i = 0; i < initialLength; ++i) {\n            SnakeSegmentActor* segment = segmentPool[i];\n            segment->resetAlive();\n            snakeSegments.push_back(segment);\n            addEntity(segment);\n        }\n    }\n};\n
"},{"location":"reference/game_examples_guide/#grid-based-movement","title":"Grid-Based Movement","text":"
class SnakeSegmentActor : public pixelroot32::core::Actor {\nprivate:\n    int cellX, cellY;  // Grid position\n\npublic:\n    void setCellPosition(int x, int y) {\n        cellX = x;\n        cellY = y;\n        // Convert to world position\n        this->x = cellX * CELL_SIZE;\n        this->y = cellY * CELL_SIZE;\n    }\n};\n
"},{"location":"reference/game_examples_guide/#patterns-used_3","title":"Patterns Used","text":"
  • Object Pooling: Segments are pre-allocated and reused
  • Grid System: Discrete grid-based movement
  • Linked List: Snake segments form a linked structure
  • Food Spawning: Random food placement with collision checking
"},{"location":"reference/game_examples_guide/#lessons-learned_3","title":"Lessons Learned","text":"
  • Entity pooling is essential for dynamic entities
  • Grid-based movement simplifies collision detection
  • Pre-allocation avoids memory fragmentation
"},{"location":"reference/game_examples_guide/#tictactoe","title":"TicTacToe","text":"

Location: src/examples/TicTacToe/

"},{"location":"reference/game_examples_guide/#architecture_4","title":"Architecture","text":"

TicTacToe demonstrates turn-based logic and simple AI:

  • Turn Management: Player vs AI turns
  • Game Board: 3x3 grid representation
  • Win Detection: Check for winning conditions
  • Simple AI: Random move selection
"},{"location":"reference/game_examples_guide/#key-systems_3","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#board-representation","title":"Board Representation","text":"
class TicTacToeScene {\nprivate:\n    int board[3][3];  // 0=empty, 1=X, 2=O\n    bool playerTurn = true;\n\n    bool makeMove(int row, int col, int player) {\n        if (board[row][col] == 0) {\n            board[row][col] = player;\n            return true;\n        }\n        return false;\n    }\n};\n
"},{"location":"reference/game_examples_guide/#win-detection","title":"Win Detection","text":"
int checkWinner() {\n    // Check rows\n    for (int i = 0; i < 3; i++) {\n        if (board[i][0] == board[i][1] && board[i][1] == board[i][2]) {\n            return board[i][0];\n        }\n    }\n    // Check columns, diagonals...\n    return 0; // No winner\n}\n
"},{"location":"reference/game_examples_guide/#patterns-used_4","title":"Patterns Used","text":"
  • State Machine: Turn-based state management
  • Grid Logic: 2D array for board representation
  • Simple AI: Random valid move selection
  • UI Integration: Buttons for player input
"},{"location":"reference/game_examples_guide/#lessons-learned_4","title":"Lessons Learned","text":"
  • Turn-based games are straightforward to implement
  • Simple AI can be effective for basic games
  • Grid-based logic is easy to reason about
"},{"location":"reference/game_examples_guide/#camerademo","title":"CameraDemo","text":"

Location: src/examples/CameraDemo/

"},{"location":"reference/game_examples_guide/#architecture_5","title":"Architecture","text":"

CameraDemo demonstrates scrolling and parallax:

  • Camera2D: Camera following player
  • Tilemap: Level built with tilemap
  • Parallax: Multiple background layers
  • Platformer Physics: Player with jumping and gravity
"},{"location":"reference/game_examples_guide/#key-systems_4","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#camera-setup","title":"Camera Setup","text":"
class CameraDemoScene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    float levelWidth;\n\npublic:\n    void init() override {\n        camera = pixelroot32::graphics::Camera2D(240, 240);\n        camera.setBounds(0, levelWidth - 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        renderer.drawTileMap(levelTileMap, 0, 0, Color::White);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"reference/game_examples_guide/#platformer-physics","title":"Platformer Physics","text":"
class PlayerCube : public pixelroot32::core::PhysicsActor {\npublic:\n    void update(unsigned long deltaTime) override {\n        // Input handling\n        // Gravity application\n        // Jump logic\n        // Platform collision\n        PhysicsActor::update(deltaTime);\n    }\n};\n
"},{"location":"reference/game_examples_guide/#patterns-used_5","title":"Patterns Used","text":"
  • Camera Following: Dead-zone camera following
  • Tilemap Rendering: Efficient level rendering
  • Parallax Scrolling: Multiple background layers
  • Platform Collision: Custom collision with platforms
"},{"location":"reference/game_examples_guide/#lessons-learned_5","title":"Lessons Learned","text":"
  • Camera system enables large levels
  • Tilemaps are efficient for level data
  • Parallax adds depth to 2D games
  • Platform collision requires custom logic
"},{"location":"reference/game_examples_guide/#spritesdemo","title":"SpritesDemo","text":"

Location: src/examples/SpritesDemo/

"},{"location":"reference/game_examples_guide/#architecture_6","title":"Architecture","text":"

SpritesDemo showcases advanced sprite formats:

  • 2bpp Sprites: 4-color sprite format
  • 4bpp Sprites: 16-color sprite format (if enabled)
  • Animation: Sprite animation examples
  • Format Comparison: Side-by-side format display
"},{"location":"reference/game_examples_guide/#key-systems_5","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#2bpp-sprite-usage","title":"2bpp Sprite Usage","text":"
#ifdef PIXELROOT32_ENABLE_2BPP_SPRITES\nstatic const pixelroot32::graphics::Sprite2bpp SPRITE_2BPP = {\n    SPRITE_DATA,\n    SPRITE_PALETTE,\n    16, 32, 4\n};\n\nrenderer.drawSprite(SPRITE_2BPP, x, y, false);\n#endif\n
"},{"location":"reference/game_examples_guide/#animation-display","title":"Animation Display","text":"
class SpritesDemoActor : public pixelroot32::core::Entity {\nprivate:\n    unsigned long timer = 0;\n    uint8_t currentFrame = 0;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        timer += deltaTime;\n        if (timer >= 150) {\n            timer -= 150;\n            currentFrame = (currentFrame + 1) % 9;\n        }\n    }\n};\n
"},{"location":"reference/game_examples_guide/#patterns-used_6","title":"Patterns Used","text":"
  • Format Comparison: Shows different sprite formats
  • Animation Loop: Frame-based animation
  • Conditional Compilation: Uses build flags
"},{"location":"reference/game_examples_guide/#lessons-learned_6","title":"Lessons Learned","text":"
  • Advanced formats provide more color options
  • Animation is straightforward with frame arrays
  • Build flags enable/disable experimental features
"},{"location":"reference/game_examples_guide/#common-patterns-across-examples","title":"Common Patterns Across Examples","text":""},{"location":"reference/game_examples_guide/#screen-resolution","title":"Screen Resolution","text":"

All examples are configured for a 240x240 screen resolution.

"},{"location":"reference/game_examples_guide/#scene-initialization","title":"Scene Initialization","text":"

All examples follow this pattern:

void init() override {\n    // 1. Set palette\n    pixelroot32::graphics::setPalette(PaletteType::NES);\n\n    // 2. Create background entity\n    addEntity(new BackgroundEntity());\n\n    // 3. Create game entities\n    player = new PlayerActor(...);\n    addEntity(player);\n\n    // 4. Initialize game state\n    resetGame();\n}\n
"},{"location":"reference/game_examples_guide/#update-pattern","title":"Update Pattern","text":"
void update(unsigned long deltaTime) override {\n    // 1. Process input\n    handleInput();\n\n    // 2. Update game logic\n    updateGameLogic();\n\n    // 3. Call parent update (updates all entities)\n    Scene::update(deltaTime);\n\n    // 4. Post-update logic\n    checkGameState();\n}\n
"},{"location":"reference/game_examples_guide/#draw-pattern","title":"Draw Pattern","text":"
void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // 1. Apply camera (if used)\n    camera.apply(renderer);\n\n    // 2. Draw background/tilemap\n    renderer.drawTileMap(background, 0, 0, Color::White);\n\n    // 3. Call parent draw (draws all entities)\n    Scene::draw(renderer);\n\n    // 4. Draw UI/HUD\n    drawHUD(renderer);\n}\n
"},{"location":"reference/game_examples_guide/#learning-path","title":"Learning Path","text":""},{"location":"reference/game_examples_guide/#beginner-examples","title":"Beginner Examples","text":"
  1. Pong: Basic physics and collisions
  2. TicTacToe: Turn-based logic
  3. Snake: Entity pooling and grid
"},{"location":"reference/game_examples_guide/#intermediate-examples","title":"Intermediate Examples","text":"
  1. CameraDemo: Camera and parallax
  2. SpritesDemo: 2bpp and 4bpp formats
  3. BrickBreaker: Physics, particles and audio
"},{"location":"reference/game_examples_guide/#advanced-examples","title":"Advanced Examples","text":"
  1. Space Invaders: Full game (1bpp sprites, collisions, audio)
  2. Metroidvania: Platformer with multi-layer 4bpp tilemap, tile-based collision and ESP32 optimizations (no scroll/camera)
"},{"location":"reference/game_examples_guide/#code-study-recommendations","title":"Code Study Recommendations","text":""},{"location":"reference/game_examples_guide/#for-learning-physics","title":"For Learning Physics","text":"
  • Study Pong/BallActor.cpp - PhysicsActor usage
  • Study CameraDemo/PlayerCube.cpp - Platformer physics
"},{"location":"reference/game_examples_guide/#for-learning-collisions","title":"For Learning Collisions","text":"
  • Study SpaceInvaders - Complex collision layers
  • Study Pong - Simple collision response
"},{"location":"reference/game_examples_guide/#for-learning-memory-management","title":"For Learning Memory Management","text":"
  • Study Snake/SnakeScene.cpp - Entity pooling
  • Study SpaceInvaders - Projectile pooling
"},{"location":"reference/game_examples_guide/#for-learning-audio","title":"For Learning Audio","text":"
  • Study SpaceInvaders - Music and sound effects
  • Study Pong - Simple audio integration
"},{"location":"reference/game_examples_guide/#for-learning-ui","title":"For Learning UI","text":"
  • Study TicTacToe - Button-based UI
  • Study menu scenes - Layout usage
"},{"location":"reference/game_examples_guide/#extending-examples","title":"Extending Examples","text":""},{"location":"reference/game_examples_guide/#adding-features","title":"Adding Features","text":"
  • Pong: Add power-ups, multiple balls
  • Snake: Add obstacles, multiple food types
  • Space Invaders: Add boss battles, power-ups
"},{"location":"reference/game_examples_guide/#creating-variations","title":"Creating Variations","text":"
  • Pong: Make it vertical, add walls
  • Snake: Change to hexagonal grid
  • TicTacToe: Make it 4x4 or 5x5
"},{"location":"reference/game_examples_guide/#best-practices-from-examples","title":"Best Practices from Examples","text":"
  1. Pre-allocate Resources: All examples pre-allocate entities
  2. Use Object Pooling: For frequently created/destroyed entities
  3. Organize by Layers: Clear collision layer organization
  4. Separate Concerns: Game logic separate from rendering
  5. State Management: Clear game state handling
"},{"location":"reference/game_examples_guide/#see-also","title":"See Also","text":"
  • Code Examples - Reusable code snippets
  • API Reference Overview - Complete API documentation
  • Manual - Game Development - Detailed guides

Note: All example code is available in the src/examples/ directory of the PixelRoot32 Game Samples project.

"},{"location":"resources/available_tools/","title":"Available Tools","text":"

This guide documents tools available to facilitate PixelRoot32 game development.

"},{"location":"resources/available_tools/#sprite-compiler-pr32-sprite-compiler","title":"Sprite Compiler (pr32-sprite-compiler)","text":"

The Sprite Compiler converts PNG images to PixelRoot32 sprite data formats, making it easy to create sprites from image files.

Read more in the Sprite Compiler Guide

From Source:

git clone https://github.com/Gperez88/pr32-sprite-compiler.git\ncd pr32-sprite-compiler\nnpm install\nnpm link  # Optional: install globally\n

As NPM Package:

npm install -g pr32-sprite-compiler\n
"},{"location":"resources/available_tools/#basic-usage","title":"Basic Usage","text":"

Command Line:

pr32-sprite-compiler input.png output.h\n

With Options:

pr32-sprite-compiler input.png output.h --format 1bpp --name MY_SPRITE\n
"},{"location":"resources/available_tools/#supported-formats","title":"Supported Formats","text":"
  • 1bpp (default): Monochrome, most memory-efficient
  • 2bpp: 4 colors per sprite (requires PIXELROOT32_ENABLE_2BPP_SPRITES)
  • 4bpp: 16 colors per sprite (requires PIXELROOT32_ENABLE_4BPP_SPRITES)
"},{"location":"resources/available_tools/#output-format","title":"Output Format","text":"

The compiler generates C++ header files with sprite data:

// output.h\n#ifndef SPRITE_DATA_H\n#define SPRITE_DATA_H\n\n#include <stdint.h>\n\nstatic const uint16_t MY_SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    // ... more rows\n};\n\nstatic const pixelroot32::graphics::Sprite MY_SPRITE = {\n    MY_SPRITE_DATA,\n    8,  // width\n    8   // height\n};\n\n#endif\n
"},{"location":"resources/available_tools/#advanced-options","title":"Advanced Options","text":"

Batch Processing:

pr32-sprite-compiler --batch sprites/*.png --output-dir sprites/out/\n

Custom Palette:

pr32-sprite-compiler input.png output.h --palette custom_palette.json\n

Sprite Sheet:

pr32-sprite-compiler sheet.png output.h --sheet 8x8 --count 16\n
"},{"location":"resources/available_tools/#gui-version","title":"GUI Version","text":"

If available, a GUI version provides visual feedback:

  • Drag and drop images
  • Preview sprite data
  • Adjust settings visually
  • Export to header files
"},{"location":"resources/available_tools/#step-by-step-example","title":"Step-by-Step Example","text":"
  1. Create or find a PNG image (8x8, 16x16, etc.)

  2. Run the compiler:

pr32-sprite-compiler player.png player_sprite.h --name PLAYER_SPRITE\n
  1. Include in your project:
#include \"player_sprite.h\"\n\nvoid draw() {\n    renderer.drawSprite(PLAYER_SPRITE, 100, 100, Color::White);\n}\n
"},{"location":"resources/available_tools/#troubleshooting","title":"Troubleshooting","text":"

Image too large:

  • Sprites must be \u2264 16 pixels wide for 1bpp
  • Reduce image size or split into multiple sprites

Colors not converting correctly:

  • Ensure image uses indexed colors
  • Use black/white for 1bpp
  • Use 4 colors for 2bpp, 16 for 4bpp

Output file not found:

  • Check write permissions
  • Verify output path exists
"},{"location":"resources/available_tools/#future-tools","title":"Future Tools","text":""},{"location":"resources/available_tools/#music-compiler-planned","title":"Music Compiler (Planned)","text":"

A tool to convert music files or MIDI to PixelRoot32 MusicTrack format.

Planned Features:

  • MIDI to MusicTrack conversion
  • Visual music editor
  • Instrument preset management
  • Export to C++ header files
"},{"location":"resources/available_tools/#tilemap-compiler-planned","title":"Tilemap Compiler (Planned)","text":"

A tool to create tilemaps from image files or tile editors.

Planned Features:

  • Image to tilemap conversion
  • Tile editor integration
  • Export to C++ arrays
  • Collision data generation
"},{"location":"resources/available_tools/#other-planned-tools","title":"Other Planned Tools","text":"
  • Save System Generator: Generate save/load code
  • Asset Packer: Bundle assets for distribution
  • Performance Profiler: Analyze game performance
"},{"location":"resources/available_tools/#using-tools-in-development","title":"Using Tools in Development","text":""},{"location":"resources/available_tools/#workflow-integration","title":"Workflow Integration","text":"

Typical Workflow:

  1. Create/edit sprites in image editor
  2. Compile sprites to C++ headers
  3. Include headers in project
  4. Use sprites in code

Automation:

# Build script example\n#!/bin/bash\npr32-sprite-compiler assets/sprites/*.png --output-dir src/sprites/\n# Continue with build...\n
"},{"location":"resources/available_tools/#best-practices","title":"Best Practices","text":"
  • Organize assets: Keep source images separate from generated code
  • Version control: Commit generated headers, not source images (or both)
  • Naming conventions: Use consistent naming for sprites
  • Batch processing: Process multiple sprites at once when possible
"},{"location":"resources/available_tools/#see-also","title":"See Also","text":"
  • Sprite Compiler Documentation - Detailed sprite compiler guide
  • Manual - Sprites and Animation - Using sprites in games
  • Troubleshooting - Common tool issues

Note: Tool availability may vary. Check the PixelRoot32 repository for the latest tool information.

"},{"location":"resources/faq/","title":"Frequently Asked Questions","text":"

Common questions about PixelRoot32, organized by category.

"},{"location":"resources/faq/#general","title":"General","text":""},{"location":"resources/faq/#what-is-pixelroot32","title":"What is PixelRoot32?","text":"

PixelRoot32 is a lightweight, modular 2D game engine designed for ESP32 microcontrollers. It provides a complete game development framework with rendering, audio, physics, input, and UI systems, optimized for limited hardware resources.

"},{"location":"resources/faq/#what-platforms-does-it-support","title":"What platforms does it support?","text":"
  • ESP32: Primary platform (TFT displays, GPIO buttons, DAC/I2S audio)
  • Native/Desktop: Development platform (SDL2, keyboard, SDL2 audio)
"},{"location":"resources/faq/#what-kind-of-games-can-i-make","title":"What kind of games can I make?","text":"

PixelRoot32 is ideal for: - Retro/arcade-style games - 2D platformers - Shooters - Puzzle games - Simple RPGs - Educational games

See Limitations and Considerations for what's not suitable.

"},{"location":"resources/faq/#is-it-free-to-use","title":"Is it free to use?","text":"

Yes, PixelRoot32 is open source and licensed under the MIT License. You can use it freely for personal and commercial projects.

"},{"location":"resources/faq/#where-can-i-find-the-source-code","title":"Where can I find the source code?","text":"
  • Engine: https://github.com/Gperez88/PixelRoot32-Game-Engine
  • Samples: https://github.com/Gperez88/PixelRoot32-Game-Samples
  • Documentation: https://github.com/PixelRoot32-Game-Engine/PixelRoot32-Docs
"},{"location":"resources/faq/#installation-and-configuration","title":"Installation and Configuration","text":""},{"location":"resources/faq/#how-do-i-install-pixelroot32","title":"How do I install PixelRoot32?","text":"

See Your First Project for detailed installation instructions.

Quick answer: 1. Install PlatformIO in VS Code 2. Create new ESP32 project 3. Add library dependency: gperez88/PixelRoot32-Game-Engine@0.2.0-dev 4. Configure hardware in platformio.ini

"},{"location":"resources/faq/#what-version-should-i-use","title":"What version should I use?","text":"

Use the exact version 0.2.0-dev. Do NOT use ^ or fuzzy versioning, as the API may change.

"},{"location":"resources/faq/#how-do-i-configure-my-display","title":"How do I configure my display?","text":"

Configure TFT_eSPI via build flags in platformio.ini. See Your First Project for examples.

"},{"location":"resources/faq/#how-do-i-set-up-audio","title":"How do I set up audio?","text":"

Choose an audio backend: - ESP32_DAC: Simple, one pin (GPIO 25 or 26) - ESP32_I2S: Higher quality, requires external DAC - SDL2_AudioBackend: For Native/PC development

See Audio for details.

"},{"location":"resources/faq/#development","title":"Development","text":""},{"location":"resources/faq/#how-do-i-create-a-scene","title":"How do I create a scene?","text":"

Inherit from pixelroot32::core::Scene and implement init(), update(), and draw(). See Scenes and Entities.

"},{"location":"resources/faq/#how-do-i-add-entities-to-a-scene","title":"How do I add entities to a scene?","text":"

Create entities and call addEntity() in init(). The scene manages them automatically.

"},{"location":"resources/faq/#whats-the-difference-between-entity-actor-and-physicsactor","title":"What's the difference between Entity, Actor, and PhysicsActor?","text":"
  • Entity: Base class, can be drawn and updated
  • Actor: Entity with collision detection
  • PhysicsActor: Actor with automatic physics (velocity, gravity, friction)

See Scenes and Entities for details.

"},{"location":"resources/faq/#how-do-i-handle-input","title":"How do I handle input?","text":"

Access InputManager through the engine:

auto& input = engine.getInputManager();\nif (input.isButtonPressed(Buttons::A)) {\n    // Handle input\n}\n

See Input and Control.

"},{"location":"resources/faq/#how-do-i-play-sounds","title":"How do I play sounds?","text":"

Create an AudioEvent and play it:

pixelroot32::audio::AudioEvent sound{};\nsound.type = pixelroot32::audio::WaveType::PULSE;\nsound.frequency = 800.0f;\nsound.duration = 0.1f;\nengine.getAudioEngine().playEvent(sound);\n

See Audio.

"},{"location":"resources/faq/#how-do-i-create-sprites","title":"How do I create sprites?","text":"

Define sprite data manually or use the Sprite Compiler tool. See Sprites and Animation.

"},{"location":"resources/faq/#can-i-use-images-instead-of-manual-sprite-data","title":"Can I use images instead of manual sprite data?","text":"

Yes, use the Sprite Compiler tool to convert PNG images to sprite data. See Available Tools.

"},{"location":"resources/faq/#performance","title":"Performance","text":""},{"location":"resources/faq/#why-is-my-game-running-slowly","title":"Why is my game running slowly?","text":"

Common causes: - Too many entities (MAX_ENTITIES = 32) - Too many draw calls - Expensive calculations in update() - Memory issues

See Performance Tuning for solutions.

"},{"location":"resources/faq/#what-fps-should-i-target","title":"What FPS should I target?","text":"

30-60 FPS is typical. Lower complexity games can achieve 60 FPS, more complex games may need to target 30 FPS.

"},{"location":"resources/faq/#how-do-i-optimize-my-game","title":"How do I optimize my game?","text":"
  • Use object pooling
  • Implement viewport culling
  • Reduce entity count
  • Cache calculations
  • Use tilemaps for backgrounds

See Performance Tuning.

"},{"location":"resources/faq/#memory","title":"Memory","text":""},{"location":"resources/faq/#why-do-i-get-out-of-memory-errors","title":"Why do I get \"out of memory\" errors?","text":"

ESP32 has limited RAM (~320KB). Solutions: - Use object pooling - Store data in flash (const/constexpr) - Reduce entity count - Avoid dynamic allocation

See Memory Management.

"},{"location":"resources/faq/#what-is-max_entities","title":"What is MAX_ENTITIES?","text":"

MAX_ENTITIES = 32 is a hard limit per scene. This includes all entities: actors, UI elements, particles, etc.

Solutions: - Use object pooling to reuse entities - Disable entities instead of removing - Combine multiple entities into one

"},{"location":"resources/faq/#how-do-i-check-available-memory","title":"How do I check available memory?","text":"
#ifdef PLATFORM_ESP32\nSerial.print(\"Free heap: \");\nSerial.println(ESP.getFreeHeap());\n#endif\n
"},{"location":"resources/faq/#hardware","title":"Hardware","text":""},{"location":"resources/faq/#which-esp32-board-should-i-use","title":"Which ESP32 board should I use?","text":"

Any ESP32 board works. Common choices: - ESP32-WROOM-32 - ESP32-WROVER (more RAM) - ESP32-DevKit

"},{"location":"resources/faq/#which-display-should-i-use","title":"Which display should I use?","text":"

Popular choices: - ST7789: 240x240, good quality - ST7735: 128x128, smaller/cheaper - ILI9341: 240x320, larger

See Platforms and Drivers.

"},{"location":"resources/faq/#how-many-buttons-do-i-need","title":"How many buttons do I need?","text":"

Minimum: 4 (UP, DOWN, LEFT, RIGHT) Recommended: 6 (add A and B buttons) More buttons can be added if needed.

"},{"location":"resources/faq/#can-i-use-analog-joysticks","title":"Can I use analog joysticks?","text":"

Not directly supported. You can read analog pins manually and convert to digital input, but the engine expects digital buttons.

"},{"location":"resources/faq/#troubleshooting","title":"Troubleshooting","text":""},{"location":"resources/faq/#my-display-is-blank-whats-wrong","title":"My display is blank. What's wrong?","text":"
  1. Check wiring connections
  2. Verify pin numbers in platformio.ini
  3. Lower SPI frequency
  4. Check display type matches hardware
  5. Verify power supply

See Troubleshooting.

"},{"location":"resources/faq/#buttons-dont-work-why","title":"Buttons don't work. Why?","text":"
  1. Check button wiring
  2. Verify pin numbers in InputConfig
  3. Check pull-up/pull-down resistors
  4. Ensure InputManager is being updated
  5. Test with isButtonDown() vs isButtonPressed()
"},{"location":"resources/faq/#audio-is-distorted-how-do-i-fix-it","title":"Audio is distorted. How do I fix it?","text":"
  1. Lower volume levels
  2. Reduce sample rate (try 11025 Hz)
  3. Check for too many simultaneous sounds
  4. Verify hardware connections
  5. Check power supply
"},{"location":"resources/faq/#game-crashes-randomly-whats-happening","title":"Game crashes randomly. What's happening?","text":"

Common causes: - Out of memory - Too many entities - Infinite loops - Stack overflow - Watchdog timeout

See Troubleshooting for debugging techniques.

"},{"location":"resources/faq/#advanced","title":"Advanced","text":""},{"location":"resources/faq/#can-i-extend-the-engine","title":"Can I extend the engine?","text":"

Yes, PixelRoot32 is designed to be extensible. You can: - Create custom display drivers - Create custom audio backends - Extend existing systems

See Extensibility.

"},{"location":"resources/faq/#can-i-use-3d-graphics","title":"Can I use 3D graphics?","text":"

No, PixelRoot32 is 2D-only. It's designed for sprite-based 2D games.

"},{"location":"resources/faq/#can-i-add-networking","title":"Can I add networking?","text":"

Not currently supported. The engine focuses on single-player games.

"},{"location":"resources/faq/#can-i-save-game-data","title":"Can I save game data?","text":"

Not currently supported. A save system is planned for future versions.

"},{"location":"resources/faq/#can-i-use-multiple-scenes-at-once","title":"Can I use multiple scenes at once?","text":"

Yes, use SceneManager to push/pop scenes. This is useful for menus and pause screens.

"},{"location":"resources/faq/#getting-help","title":"Getting Help","text":""},{"location":"resources/faq/#where-can-i-get-help","title":"Where can I get help?","text":"
  • Documentation: This documentation site
  • Examples: Study example games in the samples project
  • Discord: Community Discord server
  • GitHub: Open an issue for bugs
"},{"location":"resources/faq/#how-do-i-report-a-bug","title":"How do I report a bug?","text":"

Create a detailed bug report with: - Platform (ESP32 or Native) - Hardware details - Minimal reproduction code - Error messages - Expected vs actual behavior

"},{"location":"resources/faq/#can-i-contribute","title":"Can I contribute?","text":"

Yes! PixelRoot32 is open source. Check the main repository for contribution guidelines.

"},{"location":"resources/faq/#see-also","title":"See Also","text":"
  • Troubleshooting - Detailed problem solving
  • Limitations and Considerations - What the engine can/can't do
  • Getting Started - Start here if you're new
  • Manual - Complete development guides

Can't find your question? Check the Troubleshooting guide or ask on the Discord server.

"},{"location":"resources/limitations_and_considerations/","title":"Limitations and Considerations","text":"

This document honestly documents what PixelRoot32 can and cannot do, helping you make informed decisions about using the engine.

"},{"location":"resources/limitations_and_considerations/#hardware-limitations-esp32","title":"Hardware Limitations (ESP32)","text":""},{"location":"resources/limitations_and_considerations/#memory-constraints","title":"Memory Constraints","text":"

RAM: - Available: ~320KB total (varies by ESP32 model) - Heap: Limited and fragmented over time - Stack: ~8KB, avoid large stack allocations - Impact: Limits entity count, sprite data, and dynamic allocation

Flash: - Available: 4MB+ (varies by model) - Usage: Program code, sprite data, assets - Impact: Large games may approach limits

Recommendations: - Use object pooling - Store data in flash (const/constexpr) - Avoid dynamic allocation in game loop - Keep entity count low

"},{"location":"resources/limitations_and_considerations/#cpu-limitations","title":"CPU Limitations","text":"

Performance: - Clock Speed: 240MHz (typically) - Single-threaded: One core handles everything - Target FPS: 30-60 FPS (depends on complexity) - Frame Budget: ~16-33ms per frame at 60 FPS

Impact: - Complex games may struggle - Many entities reduce performance - Expensive calculations hurt FPS

Recommendations: - Optimize rendering - Reduce entity count - Cache calculations - Profile on hardware

"},{"location":"resources/limitations_and_considerations/#display-limitations","title":"Display Limitations","text":"

Supported Displays: - TFT displays via SPI (ST7735, ST7789, ILI9341, etc.) - Limited to SPI displays - Resolution typically 128x128 to 320x240

Constraints: - SPI communication speed limits - Display initialization complexity - Power consumption

"},{"location":"resources/limitations_and_considerations/#audio-limitations","title":"Audio Limitations","text":"

Hardware: - Internal DAC: Lower quality, simple setup - I2S: Higher quality, requires external DAC - Sample rates: 11025 Hz (DAC) or 22050 Hz (I2S)

Constraints: - 4 channels total (2 Pulse, 1 Triangle, 1 Noise) - Music uses one channel - Limited simultaneous sounds - Quality limited by hardware

"},{"location":"resources/limitations_and_considerations/#software-limitations","title":"Software Limitations","text":""},{"location":"resources/limitations_and_considerations/#entity-system","title":"Entity System","text":"

MAX_ENTITIES = 32 per scene - Hard limit, cannot be changed easily - Applies to all entities (actors, UI, particles, etc.) - Must manage entity count carefully

Workarounds: - Use object pooling - Reuse entities - Disable entities instead of removing - Combine multiple entities into one

"},{"location":"resources/limitations_and_considerations/#no-rtti-runtime-type-information","title":"No RTTI (Runtime Type Information)","text":"

Impact: - Cannot use dynamic_cast in most code - Type checking must be done manually - Limits polymorphism patterns

Alternatives: - Use virtual functions - Manual type checking - Tag-based systems

"},{"location":"resources/limitations_and_considerations/#no-exceptions-in-critical-code","title":"No Exceptions in Critical Code","text":"

Impact: - Cannot use try/catch in game loop - Error handling must be explicit - Crashes instead of exceptions

Best Practices: - Validate inputs - Check return values - Use assertions for debugging - Handle errors explicitly

"},{"location":"resources/limitations_and_considerations/#no-dynamic-allocation-in-game-loop","title":"No Dynamic Allocation in Game Loop","text":"

Impact: - Cannot use new/delete during gameplay - Must pre-allocate resources - Limits flexibility

Solutions: - Object pooling - Pre-allocation in init() - Static buffers - Fixed-size arrays

"},{"location":"resources/limitations_and_considerations/#no-advanced-features","title":"No Advanced Features","text":"

Not Supported: - 3D graphics - Shaders - Advanced physics (joints, constraints) - Networking - File system (ESP32) - Advanced audio effects

Focus: - 2D sprite-based games - Simple physics - Retro-style games - Embedded-friendly features

"},{"location":"resources/limitations_and_considerations/#experimental-features","title":"Experimental Features","text":""},{"location":"resources/limitations_and_considerations/#2bpp-sprites","title":"2bpp Sprites","text":"

Status: Experimental - Requires PIXELROOT32_ENABLE_2BPP_SPRITES flag - May have bugs or limitations - Not fully tested

Use with caution: - Test thoroughly - May change in future versions - Report issues if found

"},{"location":"resources/limitations_and_considerations/#4bpp-sprites","title":"4bpp Sprites","text":"

Status: Experimental - Requires PIXELROOT32_ENABLE_4BPP_SPRITES flag - More experimental than 2bpp - Higher memory usage

Use with caution: - Test extensively - Monitor memory usage - May be unstable

"},{"location":"resources/limitations_and_considerations/#scene-arena","title":"Scene Arena","text":"

Status: Experimental - Requires PIXELROOT32_ENABLE_SCENE_ARENA flag - Alternative memory management - May have bugs

Recommendations: - Use object pooling instead (more stable) - Test thoroughly if using - May be removed or changed

"},{"location":"resources/limitations_and_considerations/#unsupported-features-current","title":"Unsupported Features (Current)","text":""},{"location":"resources/limitations_and_considerations/#planned-but-not-available","title":"Planned but Not Available","text":"
  • u8g2 Driver: Alternative display driver (planned)
  • Music Compiler: Tool to convert music files (planned)
  • Tilemap Compiler: Tool to create tilemaps (planned)
  • Save System: Persistent storage system (planned)
  • Spatial Partitioning: Advanced collision optimization (planned)
"},{"location":"resources/limitations_and_considerations/#not-planned","title":"Not Planned","text":"
  • 3D Graphics: 2D-only engine
  • Networking: No network support
  • File System: No file I/O on ESP32
  • Advanced Audio: NES-like audio only
  • Scripting: No Lua/JavaScript support
"},{"location":"resources/limitations_and_considerations/#best-practices-for-esp32","title":"Best Practices for ESP32","text":""},{"location":"resources/limitations_and_considerations/#memory-management","title":"Memory Management","text":"
  • Pre-allocate: All resources in init()
  • Object pooling: Reuse entities
  • Flash storage: Use const/constexpr for data
  • Avoid strings: Use static buffers
  • Monitor usage: Check heap regularly
"},{"location":"resources/limitations_and_considerations/#performance","title":"Performance","text":"
  • Limit entities: Stay well below MAX_ENTITIES
  • Optimize rendering: Use culling, batching
  • Cache calculations: Avoid repeated work
  • Profile on hardware: PC performance \u2260 ESP32
"},{"location":"resources/limitations_and_considerations/#development","title":"Development","text":"
  • Test on hardware: Don't rely only on Native
  • Start simple: Add complexity gradually
  • Monitor memory: Watch for leaks
  • Optimize incrementally: Profile and optimize
"},{"location":"resources/limitations_and_considerations/#what-pixelroot32-is-good-for","title":"What PixelRoot32 IS Good For","text":"

\u2705 Retro-style 2D games \u2705 Arcade games \u2705 Puzzle games \u2705 Platformers \u2705 Shooters \u2705 Educational projects \u2705 Prototyping \u2705 Embedded game development

"},{"location":"resources/limitations_and_considerations/#what-pixelroot32-is-not-good-for","title":"What PixelRoot32 is NOT Good For","text":"

\u274c 3D games \u274c Complex physics simulations \u274c Large open worlds \u274c Games requiring many entities \u274c Games with complex graphics \u274c Network multiplayer \u274c Games requiring file I/O

"},{"location":"resources/limitations_and_considerations/#making-informed-decisions","title":"Making Informed Decisions","text":""},{"location":"resources/limitations_and_considerations/#before-starting-a-project","title":"Before Starting a Project","text":"
  1. Assess requirements: Does PixelRoot32 fit?
  2. Check limitations: Can you work within constraints?
  3. Plan architecture: Design around limitations
  4. Test early: Verify on hardware early
"},{"location":"resources/limitations_and_considerations/#if-limitations-are-a-problem","title":"If Limitations Are a Problem","text":"

Consider alternatives: - Full game engines (Unity, Godot) for complex games - Custom solutions for specific needs - Different hardware for more resources

Or work within limits: - Simplify game design - Optimize aggressively - Use creative solutions

"},{"location":"resources/limitations_and_considerations/#version-compatibility","title":"Version Compatibility","text":""},{"location":"resources/limitations_and_considerations/#current-version","title":"Current Version","text":"
  • Engine Version: 0.2.0-dev
  • API Stability: May change
  • Breaking Changes: Possible in future versions

Recommendations: - Pin exact version in platformio.ini - Don't use ^ or fuzzy versioning - Test after engine updates - Review changelog

"},{"location":"resources/limitations_and_considerations/#honest-assessment","title":"Honest Assessment","text":"

PixelRoot32 is designed for: - Simple to medium complexity games - Retro/arcade style - ESP32 hardware constraints - Rapid development

It is not designed for: - AAA game complexity - Modern graphics - Large-scale games - Unlimited resources

"},{"location":"resources/limitations_and_considerations/#see-also","title":"See Also","text":"
  • Memory Management - Working with memory limits
  • Performance Tuning - Optimizing performance
  • Troubleshooting - Solving problems
  • FAQ - Common questions

Remember: Understanding limitations helps you build better games within PixelRoot32's capabilities.

"},{"location":"resources/troubleshooting/","title":"Troubleshooting","text":"

This guide helps you diagnose and fix common issues when developing with PixelRoot32.

"},{"location":"resources/troubleshooting/#compilation-problems","title":"Compilation Problems","text":""},{"location":"resources/troubleshooting/#common-compilation-errors","title":"Common Compilation Errors","text":"

Error: Library not found

Solution: Ensure PixelRoot32-Game-Engine is properly installed\n- Check platformio.ini has correct lib_deps\n- Verify library version matches (use exact version, not ^)\n- Try: pio lib install\n

Error: Include file not found

Solution: Check include paths\n- Verify lib_extra_dirs in platformio.ini\n- Check that library is in lib/ directory\n- Ensure correct namespace (pixelroot32::)\n

Error: Undefined reference

Solution: Link missing libraries\n- Check all required libraries are listed\n- Verify TFT_eSPI is installed for ESP32\n- Check SDL2 is installed for Native builds\n

Error: Build flags not recognized

Solution: Verify build flag syntax\n- Use -D FLAG_NAME (not --define)\n- Check flag names are correct\n- Ensure flags are in correct environment section\n

"},{"location":"resources/troubleshooting/#configuration-issues","title":"Configuration Issues","text":"

Wrong display type: - Verify DisplayType matches your hardware - Check TFT_eSPI build flags match display - Test with different display types

Incorrect pin configuration: - Verify GPIO pins match your wiring - Check pin numbers in platformio.ini - Ensure pins aren't used by other peripherals

"},{"location":"resources/troubleshooting/#hardware-problems-esp32","title":"Hardware Problems (ESP32)","text":""},{"location":"resources/troubleshooting/#display-not-working","title":"Display Not Working","text":"

Symptoms: - Blank screen - Garbled display - No output

Solutions: 1. Check wiring: - Verify SPI connections (MOSI, SCLK, DC, RST) - Check power supply (3.3V or 5V as required) - Ensure ground connections

  1. Verify configuration:
  2. Check display type matches hardware
  3. Verify pin numbers in platformio.ini
  4. Test with known working configuration

  5. SPI frequency:

  6. Lower SPI frequency (try 20MHz instead of 40MHz)
  7. Some displays need slower speeds
  8. Check display datasheet for max frequency

  9. Display initialization:

  10. Try different rotation values
  11. Check display width/height settings
  12. Verify TFT_eSPI driver is correct
"},{"location":"resources/troubleshooting/#resolution-scaling-issues","title":"Resolution Scaling Issues","text":"

Symptoms: - Image is not scaled to full screen - Visual artifacts (jittery pixels) - Frame rate drops when scaling is enabled

Solutions: 1. Verify DisplayConfig: - Ensure physicalWidth and physicalHeight match your hardware resolution (e.g., 240x240). - Check that logicalWidth and logicalHeight are set correctly (e.g., 128x128). - Use displayConfig.needsScaling() to check if the engine thinks scaling is required.

  1. Check Scaling Performance:
  2. Enabling scaling is generally faster than native high resolution, but still has some overhead.
  3. Use the Debug Statistics Overlay to check CPU load.
  4. Ensure you are using integer-only coordinates for drawing.

  5. Visual Quality:

  6. The engine uses nearest-neighbor scaling. Some aspect ratios might look \"blocky\" or have uneven pixel sizes.
  7. For best results, use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen).
"},{"location":"resources/troubleshooting/#buttons-not-responding","title":"Buttons Not Responding","text":"

Symptoms: - No input detected - Buttons don't trigger actions - Input feels laggy

Solutions: 1. Check wiring: - Verify button connections to GPIO pins - Check pull-up/pull-down resistors - Test buttons with multimeter

  1. Verify pin configuration:
  2. Check InputConfig pin numbers
  3. Ensure pins match hardware
  4. Verify pins aren't used elsewhere

  5. Input debouncing:

  6. Add hardware debouncing (capacitor)
  7. Check InputManager is being updated
  8. Verify input is read in update(), not draw()

  9. Button logic:

  10. Test with isButtonDown() vs isButtonPressed()
  11. Check button indices match configuration
  12. Verify input is accessed correctly
"},{"location":"resources/troubleshooting/#audio-not-working","title":"Audio Not Working","text":"

Symptoms: - No sound output - Distorted audio - Audio glitches

Solutions: 1. DAC Configuration: - Verify DAC pin (25 or 26 for ESP32) - Check sample rate (11025 Hz recommended) - Ensure audio backend is initialized

  1. I2S Configuration:
  2. Verify I2S pin connections (BCLK, LRCK, DOUT)
  3. Check external DAC is powered
  4. Verify I2S DAC is compatible

  5. Audio quality:

  6. Lower sample rate if distorted
  7. Reduce volume levels
  8. Check for too many simultaneous sounds
  9. Verify audio buffer size

  10. Hardware:

  11. Check speaker connections
  12. Verify amplifier is powered
  13. Test with different audio hardware
  14. Check audio cable connections
"},{"location":"resources/troubleshooting/#power-issues","title":"Power Issues","text":"

Symptoms: - ESP32 resets randomly - Display flickers - Unstable operation

Solutions: 1. Power supply: - Use adequate power supply (500mA+ recommended) - Check voltage is stable (3.3V) - Add decoupling capacitors

  1. Current draw:
  2. Display draws significant current
  3. Audio amplifier adds load
  4. Reduce brightness if possible

  5. Wiring:

  6. Use thick wires for power
  7. Keep power wires short
  8. Add capacitors near ESP32
"},{"location":"resources/troubleshooting/#performance-problems","title":"Performance Problems","text":""},{"location":"resources/troubleshooting/#low-fps","title":"Low FPS","text":"

Symptoms: - Game runs slowly - Laggy movement - Stuttering

Solutions: 1. Reduce entity count: - Limit active entities (MAX_ENTITIES = 32) - Disable off-screen entities - Use object pooling

  1. Optimize rendering:
  2. Use viewport culling
  3. Reduce draw calls
  4. Use tilemaps instead of individual sprites
  5. Limit sprite count

  6. Simplify logic:

  7. Cache expensive calculations
  8. Reduce collision checks
  9. Lower update frequency for non-critical entities

  10. Check hardware:

  11. Verify ESP32 is running at full speed (240MHz)
  12. Check for thermal throttling
  13. Ensure adequate power supply
"},{"location":"resources/troubleshooting/#frame-drops","title":"Frame Drops","text":"

Symptoms: - Occasional stuttering - Inconsistent frame times - Periodic freezes

Solutions: 1. Identify bottlenecks: - Profile frame time - Check for expensive operations - Look for blocking code

  1. Optimize update loop:
  2. Avoid dynamic allocation
  3. Cache calculations
  4. Reduce string operations

  5. Memory issues:

  6. Check for memory leaks
  7. Reduce memory usage
  8. Use object pooling
"},{"location":"resources/troubleshooting/#freezescrashes","title":"Freezes/Crashes","text":"

Symptoms: - Game stops responding - ESP32 resets - Watchdog resets

Solutions: 1. Memory issues: - Check available heap memory - Reduce entity count - Avoid dynamic allocation - Use object pooling

  1. Infinite loops:
  2. Check for infinite loops in update()
  3. Verify collision detection doesn't loop
  4. Check animation logic

  5. Stack overflow:

  6. Avoid large stack allocations
  7. Reduce recursion depth
  8. Move large data to heap (carefully)

  9. Watchdog:

  10. Ensure update() completes quickly
  11. Add yield() calls if needed
  12. Check for blocking operations
"},{"location":"resources/troubleshooting/#memory-problems","title":"Memory Problems","text":""},{"location":"resources/troubleshooting/#out-of-memory","title":"Out of Memory","text":"

Symptoms: - Compilation fails - Runtime crashes - \"Allocation failed\" errors

Solutions: 1. Reduce memory usage: - Use 1bpp sprites instead of 2bpp/4bpp - Store data in flash (const/constexpr) - Reduce entity count - Use object pooling

  1. Optimize data:
  2. Reuse sprites
  3. Compress tilemap data
  4. Remove unused code/data

  5. Memory management:

  6. Avoid dynamic allocation in game loop
  7. Pre-allocate all resources
  8. Use static buffers
"},{"location":"resources/troubleshooting/#memory-fragmentation","title":"Memory Fragmentation","text":"

Symptoms: - Gradual performance degradation - Allocation failures over time - Crashes after running for a while

Solutions: 1. Use object pooling: - Pre-allocate entities - Reuse objects instead of creating/destroying - Avoid frequent new/delete

  1. Pre-allocate resources:
  2. Allocate everything in init()
  3. Use fixed-size arrays
  4. Avoid dynamic containers
"},{"location":"resources/troubleshooting/#native-build-problems","title":"Native Build Problems","text":""},{"location":"resources/troubleshooting/#sdl2-not-found","title":"SDL2 Not Found","text":"

Symptoms: - Compilation fails - Linker errors - Missing SDL2 symbols

Solutions: 1. Install SDL2: - Windows (MSYS2): pacman -S mingw-w64-x86_64-SDL2 - Linux: sudo apt-get install libsdl2-dev - macOS: brew install sdl2

  1. Check paths:
  2. Verify include paths in platformio.ini
  3. Check library paths
  4. Ensure SDL2 version is compatible

  5. Linker flags:

  6. Verify -lSDL2 is in build flags
  7. Check library search paths
  8. Ensure SDL2 DLL is accessible (Windows)
"},{"location":"resources/troubleshooting/#window-not-opening","title":"Window Not Opening","text":"

Symptoms: - Program runs but no window - Console shows errors - Immediate exit

Solutions: 1. Check SDL2 initialization: - Verify SDL2 is properly initialized - Check for SDL2 error messages - Ensure display config is correct

  1. Graphics drivers:
  2. Update graphics drivers
  3. Check SDL2 video backend
  4. Test with simple SDL2 program

  5. Console output:

  6. Run from terminal to see errors
  7. Check for error messages
  8. Verify SDL2 is working
"},{"location":"resources/troubleshooting/#debugging-techniques","title":"Debugging Techniques","text":""},{"location":"resources/troubleshooting/#serial-debugging-esp32","title":"Serial Debugging (ESP32)","text":"
void setup() {\n    Serial.begin(115200);\n    // ... initialization\n\n    Serial.println(\"Engine initialized\");\n}\n\nvoid update(unsigned long deltaTime) override {\n    // Debug output\n    if (frameCount % 60 == 0) {\n        Serial.print(\"FPS: \");\n        Serial.println(1000.0f / deltaTime);\n    }\n    frameCount++;\n}\n
"},{"location":"resources/troubleshooting/#memory-monitoring","title":"Memory Monitoring","text":"
#ifdef PLATFORM_ESP32\n#include <Arduino.h>\n\nvoid checkMemory() {\n    Serial.print(\"Free heap: \");\n    Serial.println(ESP.getFreeHeap());\n    Serial.print(\"Largest block: \");\n    Serial.println(ESP.getMaxAllocHeap());\n}\n#endif\n
"},{"location":"resources/troubleshooting/#performance-profiling","title":"Performance Profiling","text":"
class Profiler {\nprivate:\n    unsigned long updateTime = 0;\n    unsigned long drawTime = 0;\n\npublic:\n    void startUpdate() {\n        updateTime = micros();\n    }\n\n    void endUpdate() {\n        updateTime = micros() - updateTime;\n    }\n\n    void log() {\n        Serial.print(\"Update: \");\n        Serial.print(updateTime);\n        Serial.print(\"us, Draw: \");\n        Serial.println(drawTime);\n    }\n};\n
"},{"location":"resources/troubleshooting/#visual-debugging","title":"Visual Debugging","text":"
  • Draw hitboxes: Visualize collision boxes
  • Show FPS: Display frame rate on screen
  • Entity count: Show active entity count
  • Memory usage: Display memory statistics
"},{"location":"resources/troubleshooting/#common-patterns-for-debugging","title":"Common Patterns for Debugging","text":""},{"location":"resources/troubleshooting/#isolate-the-problem","title":"Isolate the Problem","text":"
  1. Minimal reproduction: Create smallest code that shows issue
  2. Disable features: Turn off systems one by one
  3. Test incrementally: Add features back one at a time
"},{"location":"resources/troubleshooting/#check-the-basics","title":"Check the Basics","text":"
  1. Verify initialization: Ensure engine.init() is called
  2. Check scene setup: Verify scene is set and initialized
  3. Test on both platforms: Compare ESP32 vs Native behavior
  4. Review recent changes: What changed before the issue?
"},{"location":"resources/troubleshooting/#use-logging","title":"Use Logging","text":"
#define DEBUG_MODE\n\n#ifdef DEBUG_MODE\n    #define DEBUG_LOG(x) Serial.println(x)\n#else\n    #define DEBUG_LOG(x)\n#endif\n\n// Usage\nDEBUG_LOG(\"Entity created\");\nDEBUG_LOG(\"Collision detected\");\n
"},{"location":"resources/troubleshooting/#getting-help","title":"Getting Help","text":"

If you can't resolve an issue:

  1. Check documentation: Review relevant guides
  2. Search examples: Look at example games
  3. Review code: Check engine source code
  4. Community: Ask on Discord or GitHub
  5. Report issue: Create detailed bug report
"},{"location":"resources/troubleshooting/#bug-report-template","title":"Bug Report Template","text":"

When reporting issues, include:

  • Platform: ESP32 or Native
  • Hardware: Display type, ESP32 model
  • Code: Minimal reproduction code
  • Error messages: Full error output
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Steps to reproduce: How to trigger the issue
"},{"location":"resources/troubleshooting/#see-also","title":"See Also","text":"
  • Limitations and Considerations - Known limitations
  • Performance Tuning - Performance optimization
  • Memory Management - Memory optimization
  • FAQ - Frequently asked questions

Note: Many issues are configuration-related. Double-check your setup before assuming a bug.

"},{"location":"tools/sprite_compiler/advanced_features/","title":"Sprite Compiler Advanced Features","text":"

Advanced features and options for the PixelRoot32 Sprite Compiler to optimize sprite conversion and handle complex scenarios.

"},{"location":"tools/sprite_compiler/advanced_features/#automatic-palette-detection","title":"Automatic Palette Detection","text":"

The Sprite Compiler automatically detects if your sprite uses one of the engine's built-in palettes. This simplifies your workflow and ensures color consistency.

"},{"location":"tools/sprite_compiler/advanced_features/#predefined-engine-palettes","title":"Predefined Engine Palettes","text":"

The engine includes 5 optimized palettes: - PR32 (Default PixelRoot32 palette) - NES (Nintendo style) - GB (GameBoy style) - GBC (GameBoy Color style) - PICO8 (Fantasy console style)

"},{"location":"tools/sprite_compiler/advanced_features/#how-it-works","title":"How it works","text":"
  1. Detection: When you compile an image, the tool compares all unique colors found in the sprite with the colors in the 5 engine palettes.
  2. Match: If all colors in your sprite belong to one of these palettes, the compiler:
  3. Omits generating a color array in the header.
  4. Assumes you will use the engine's built-in palette definitions at runtime.
  5. Custom Palette: If your sprite uses colors not found in the engine palettes, it automatically generates a {PREFIX}_PALETTE_MAPPING[16] array in the header file.
"},{"location":"tools/sprite_compiler/advanced_features/#naming-with-prefixes","title":"Naming with Prefixes","text":"

You can organize your generated code by using the --prefix parameter (or the Prefix field in the GUI).

"},{"location":"tools/sprite_compiler/advanced_features/#using-prefixes","title":"Using Prefixes","text":"

By default, sprites are named SPRITE_N_.... Using a prefix allows you to create more descriptive names and avoid naming collisions.

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --prefix PLAYER_JUM\n

Generated names will follow this pattern: - PLAYER_JUM_SPRITE_0_LAYER_0 - PLAYER_JUM_SPRITE_0_2BPP - PLAYER_JUM_SPRITE_0_4BPP - PLAYER_JUM_PALETTE_MAPPING (if a custom palette is used)

"},{"location":"tools/sprite_compiler/advanced_features/#export-modes","title":"Export Modes","text":""},{"location":"tools/sprite_compiler/advanced_features/#layered-1bpp","title":"Layered (1bpp)","text":"

Best for standard PixelRoot32 rendering. It extracts each color into its own bitmask (1bpp). The engine then renders these layers sequentially.

"},{"location":"tools/sprite_compiler/advanced_features/#packed-2bpp-4bpp","title":"Packed (2bpp / 4bpp)","text":"

Generates a single packed array where each pixel uses multiple bits. - 2bpp: 4 colors max (Index 0 is always transparent). - 4bpp: 16 colors max (Index 0 is always transparent).

These modes are more efficient for sprites with many colors as they require only a single draw call.

"},{"location":"tools/sprite_compiler/installation/","title":"Sprite Compiler Installation","text":"

This guide walks you through installing the PixelRoot32 Sprite Compiler on your system.

"},{"location":"tools/sprite_compiler/installation/#prerequisites","title":"Prerequisites","text":""},{"location":"tools/sprite_compiler/installation/#required-software","title":"Required Software","text":"
  • Python: Version 3.8 or higher
  • pip: Usually included with Python
"},{"location":"tools/sprite_compiler/installation/#verify-prerequisites","title":"Verify Prerequisites","text":"

Check if Python is installed:

python --version\n# Should show 3.8.0 or higher\n

Check if pip is installed:

pip --version\n# Should show version number\n

If not installed, download from python.org

"},{"location":"tools/sprite_compiler/installation/#installation-methods","title":"Installation Methods","text":""},{"location":"tools/sprite_compiler/installation/#method-1-from-source-recommended","title":"Method 1: From Source (Recommended)","text":""},{"location":"tools/sprite_compiler/installation/#step-1-clone-repository","title":"Step 1: Clone Repository","text":"
git clone https://github.com/Gperez88/PixelRoot32-Sprite-Compiler.git\ncd PixelRoot32-Sprite-Compiler\n
"},{"location":"tools/sprite_compiler/installation/#step-2-install-dependencies","title":"Step 2: Install Dependencies","text":"
pip install -r requirements.txt\n
"},{"location":"tools/sprite_compiler/installation/#step-3-verify-installation","title":"Step 3: Verify Installation","text":"
python main.py --help\n
"},{"location":"tools/sprite_compiler/installation/#method-2-standalone-executable-windows","title":"Method 2: Standalone Executable (Windows)","text":"

If you are on Windows, you can download the latest standalone .exe from the Releases section of the repository. This does not require Python or any dependencies to be installed.

"},{"location":"tools/sprite_compiler/installation/#platform-specific-instructions","title":"Platform-Specific Instructions","text":""},{"location":"tools/sprite_compiler/installation/#windows","title":"Windows","text":""},{"location":"tools/sprite_compiler/installation/#using-npm-recommended","title":"Using npm (Recommended)","text":"
  1. Install Node.js from nodejs.org
  2. Download the Windows installer
  3. Run the installer
  4. Restart your terminal/command prompt

  5. Open Command Prompt or PowerShell

  6. Install globally:

    npm install -g pr32-sprite-compiler\n

  7. Verify:

    pr32-sprite-compiler --version\n

"},{"location":"tools/sprite_compiler/installation/#troubleshooting-windows-issues","title":"Troubleshooting Windows Issues","text":"

\"pr32-sprite-compiler is not recognized\": - Ensure Node.js is in your PATH - Restart terminal after installation - Try using full path: C:\\Users\\YourName\\AppData\\Roaming\\npm\\pr32-sprite-compiler.cmd

Permission errors: - Run terminal as Administrator - Or install locally: npm install pr32-sprite-compiler (without -g)

"},{"location":"tools/sprite_compiler/installation/#linux","title":"Linux","text":""},{"location":"tools/sprite_compiler/installation/#using-npm","title":"Using npm","text":"
  1. Install Node.js (if not already installed):

Ubuntu/Debian:

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -\nsudo apt-get install -y nodejs\n

Fedora/RHEL:

sudo dnf install nodejs npm\n

  1. Install Sprite Compiler:

    sudo npm install -g pr32-sprite-compiler\n

  2. Verify:

    pr32-sprite-compiler --version\n

"},{"location":"tools/sprite_compiler/installation/#troubleshooting-linux-issues","title":"Troubleshooting Linux Issues","text":"

Permission denied: - Use sudo for global installation - Or install locally without -g flag

Command not found: - Check npm global bin path: npm config get prefix - Add to PATH if needed: export PATH=$PATH:$(npm config get prefix)/bin

"},{"location":"tools/sprite_compiler/installation/#macos","title":"macOS","text":""},{"location":"tools/sprite_compiler/installation/#using-npm_1","title":"Using npm","text":"
  1. Install Node.js:
  2. Download from nodejs.org
  3. Or use Homebrew: brew install node

  4. Install Sprite Compiler:

    npm install -g pr32-sprite-compiler\n

  5. Verify:

    pr32-sprite-compiler --version\n

"},{"location":"tools/sprite_compiler/installation/#using-homebrew-alternative","title":"Using Homebrew (Alternative)","text":"

If available as a Homebrew formula:

brew install pr32-sprite-compiler\n

"},{"location":"tools/sprite_compiler/installation/#gui-version-installation","title":"GUI Version Installation","text":"

If a GUI version is available:

"},{"location":"tools/sprite_compiler/installation/#windows_1","title":"Windows","text":"

Download the installer from the releases page and run it.

"},{"location":"tools/sprite_compiler/installation/#linux_1","title":"Linux","text":"
# Download AppImage or .deb package\n# Make executable and run\nchmod +x pr32-sprite-compiler-gui.AppImage\n./pr32-sprite-compiler-gui.AppImage\n
"},{"location":"tools/sprite_compiler/installation/#macos_1","title":"macOS","text":"

Download the .dmg file from releases and install.

"},{"location":"tools/sprite_compiler/installation/#verification","title":"Verification","text":"

After installation, verify everything works:

"},{"location":"tools/sprite_compiler/installation/#test-basic-functionality","title":"Test Basic Functionality","text":"
  1. Create a test image:
  2. Create an 8x8 pixel PNG image (black and white)
  3. Save as test.png

  4. Run compiler:

    pr32-sprite-compiler test.png test_output.h\n

  5. Check output:

  6. File test_output.h should be created
  7. Should contain sprite data arrays
"},{"location":"tools/sprite_compiler/installation/#check-version","title":"Check Version","text":"
pr32-sprite-compiler --version\n
"},{"location":"tools/sprite_compiler/installation/#check-help","title":"Check Help","text":"
pr32-sprite-compiler --help\n
"},{"location":"tools/sprite_compiler/installation/#updating","title":"Updating","text":""},{"location":"tools/sprite_compiler/installation/#update-via-npm","title":"Update via npm","text":"
npm update -g pr32-sprite-compiler\n
"},{"location":"tools/sprite_compiler/installation/#update-from-source","title":"Update from Source","text":"
cd pr32-sprite-compiler\ngit pull\nnpm install\n
"},{"location":"tools/sprite_compiler/installation/#uninstallation","title":"Uninstallation","text":""},{"location":"tools/sprite_compiler/installation/#remove-global-installation","title":"Remove Global Installation","text":"
npm uninstall -g pr32-sprite-compiler\n
"},{"location":"tools/sprite_compiler/installation/#remove-local-installation","title":"Remove Local Installation","text":"
npm uninstall pr32-sprite-compiler\n
"},{"location":"tools/sprite_compiler/installation/#troubleshooting","title":"Troubleshooting","text":""},{"location":"tools/sprite_compiler/installation/#common-issues","title":"Common Issues","text":"

\"Command not found\" after installation: - Restart your terminal - Check npm global bin path: npm config get prefix - Verify PATH includes npm bin directory

Permission errors: - On Linux/macOS: Use sudo for global install - Or install locally without -g flag - On Windows: Run terminal as Administrator

Module not found errors: - Reinstall: npm install -g pr32-sprite-compiler - Clear npm cache: npm cache clean --force

Version conflicts: - Check Node.js version: node --version - Update Node.js if version is too old - Use nvm (Node Version Manager) to manage versions

"},{"location":"tools/sprite_compiler/installation/#getting-help","title":"Getting Help","text":"
  • Check the Usage Guide for usage examples
  • Review Troubleshooting for common issues
  • Open an issue on GitHub if problems persist
"},{"location":"tools/sprite_compiler/installation/#next-steps","title":"Next Steps","text":"

Once installed, proceed to: - Usage Guide - Learn how to use the compiler - Advanced Features - Explore advanced options

"},{"location":"tools/sprite_compiler/installation/#see-also","title":"See Also","text":"
  • Overview - What the Sprite Compiler does
  • Available Tools - All PixelRoot32 tools
"},{"location":"tools/sprite_compiler/overview/","title":"Sprite Compiler Overview","text":"

The Sprite Compiler is a tool that converts PNG images into PixelRoot32 sprite data formats. It provides both a graphical interface (GUI) and a command-line interface (CLI) to automate the process of creating sprite arrays from image files.

"},{"location":"tools/sprite_compiler/overview/#what-it-does","title":"What It Does","text":"

The Sprite Compiler takes bitmap images (PNG) and converts them into C header files containing:

  • Sprite data arrays: Optimized uint16_t arrays for various formats.
  • Layered support: Generates multiple 1bpp layers for complex sprites.
  • Packed formats: Supports 2bpp and 4bpp packed formats.
  • Sprite sheets: Handles grid-based sprite sheets with auto-detection.
"},{"location":"tools/sprite_compiler/overview/#key-features","title":"Key Features","text":""},{"location":"tools/sprite_compiler/overview/#format-support","title":"\u2705 Format Support","text":"
  • Layered (1bpp): Standard format, generates one array per color.
  • 2bpp (4 colors): Packed format, 2 bits per pixel.
  • 4bpp (16 colors): Packed format, 4 bits per pixel.
"},{"location":"tools/sprite_compiler/overview/#gui-cli","title":"\u2705 GUI & CLI","text":"
  • Modern GUI: Step-by-step card-based interface for easy configuration.
  • Powerful CLI: Perfect for build scripts and automation.
"},{"location":"tools/sprite_compiler/overview/#sprite-sheets","title":"\u2705 Sprite Sheets","text":"

Automatically split sprite sheets into individual sprites:

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --sprite 1,0,1,1 --out output.h\n

"},{"location":"tools/sprite_compiler/overview/#gui-interface","title":"GUI Interface","text":"

The GUI is designed to be intuitive and follows a 5-step process:

  1. Input Image: Select your PNG source.
  2. Grid Settings: Define the cell size and offsets.
  3. Sprite Selection: Pick which cells to export.
  4. Export Settings: Choose the mode (Layered, 2bpp, 4bpp), set a Prefix, and choose the output path.
  5. About: Quick access to version info and credits (via the ? button).
  6. Log: Technical feedback and performance alerts.
"},{"location":"tools/sprite_compiler/overview/#input-requirements","title":"Input Requirements","text":""},{"location":"tools/sprite_compiler/overview/#supported-formats","title":"Supported Formats","text":"
  • PNG: Primary format (recommended)
  • Indexed color PNG: Best for 1bpp conversion
  • Grayscale PNG: Automatically converted to 1bpp
  • RGB PNG: Converted using threshold or palette
"},{"location":"tools/sprite_compiler/overview/#image-constraints","title":"Image Constraints","text":"

For 1bpp sprites: - Maximum width: 16 pixels - Height: Any (typically 8, 16, 32 pixels) - Colors: Black and white (or converted automatically)

For 2bpp sprites: - Maximum width: 16 pixels - Colors: Up to 4 colors

For 4bpp sprites: - Maximum width: 16 pixels - Colors: Up to 16 colors

"},{"location":"tools/sprite_compiler/overview/#output-format","title":"Output Format","text":"

The compiler generates C header files with optimized arrays:

// Generated by PixelRoot32 Sprite Compiler\n\n// Optional palette mapping if using custom colors\nstatic const Color PLAYER_PALETTE_MAPPING[16] = {\n    (Color)0, (Color)1, (Color)2, (Color)3,\n    // ...\n};\n\n// Sprite data array (4bpp example)\nstatic const uint16_t PLAYER_SPRITE_0_4BPP[] = {\n    0x0000, 0x1234, 0x5678, // Row 0\n    // ... more rows\n};\n
"},{"location":"tools/sprite_compiler/overview/#use-cases","title":"Use Cases","text":""},{"location":"tools/sprite_compiler/overview/#1-single-sprite-conversion","title":"1. Single Sprite Conversion","text":"

Convert a single image to a sprite:

pr32-sprite-compiler player.png player_sprite.h --name PLAYER_SPRITE\n

"},{"location":"tools/sprite_compiler/overview/#2-animation-frames","title":"2. Animation Frames","text":"

Convert multiple frames for animation:

pr32-sprite-compiler --batch walk_*.png --output-dir animations/ --prefix WALK_\n

"},{"location":"tools/sprite_compiler/overview/#3-sprite-sheet-processing","title":"3. Sprite Sheet Processing","text":"

Split a sprite sheet into individual sprites:

pr32-sprite-compiler characters.png output.h --sheet 16x16 --count 8\n

"},{"location":"tools/sprite_compiler/overview/#4-batch-asset-processing","title":"4. Batch Asset Processing","text":"

Process entire asset directories:

pr32-sprite-compiler --batch assets/sprites/*.png --output-dir src/sprites/\n

"},{"location":"tools/sprite_compiler/overview/#workflow-integration","title":"Workflow Integration","text":""},{"location":"tools/sprite_compiler/overview/#typical-development-workflow","title":"Typical Development Workflow","text":"
  1. Create sprites in your image editor (Aseprite, Piskel, GIMP, etc.)
  2. Save as PNG with appropriate dimensions
  3. Run compiler to generate header files
  4. Include headers in your PixelRoot32 project
  5. Use sprites in your game code
"},{"location":"tools/sprite_compiler/overview/#automation-example","title":"Automation Example","text":"
#!/bin/bash\n# build-sprites.sh\n\n# Compile all sprites\npr32-sprite-compiler assets/sprites/*.png --output-dir src/sprites/\n\n# Continue with your build process\nplatformio run\n
"},{"location":"tools/sprite_compiler/overview/#advantages-over-manual-creation","title":"Advantages Over Manual Creation","text":""},{"location":"tools/sprite_compiler/overview/#time-saving","title":"\u2705 Time Saving","text":"
  • No manual bit pattern conversion
  • Automatic format optimization
  • Batch processing multiple sprites
"},{"location":"tools/sprite_compiler/overview/#accuracy","title":"\u2705 Accuracy","text":"
  • Correct bit ordering
  • Proper array formatting
  • Valid C++ syntax
"},{"location":"tools/sprite_compiler/overview/#consistency","title":"\u2705 Consistency","text":"
  • Uniform naming conventions
  • Standardized output format
  • Consistent code structure
"},{"location":"tools/sprite_compiler/overview/#maintainability","title":"\u2705 Maintainability","text":"
  • Easy to regenerate from source images
  • Version control friendly
  • Clear separation of assets and code
"},{"location":"tools/sprite_compiler/overview/#limitations","title":"Limitations","text":"
  • Width limit: 16 pixels for 1bpp (hardware constraint)
  • Color depth: Limited by format (1bpp = 2 colors, 2bpp = 4 colors, etc.)
  • File format: Primarily PNG (other formats may require conversion)
"},{"location":"tools/sprite_compiler/overview/#next-steps","title":"Next Steps","text":"
  • Installation Guide - Set up the compiler
  • Usage Guide - Learn how to use it
  • Advanced Features - Explore advanced options
"},{"location":"tools/sprite_compiler/overview/#see-also","title":"See Also","text":"
  • Manual - Sprites and Animation - Using sprites in games
  • Code Examples - Sprites - Sprite usage examples
  • Available Tools - All PixelRoot32 tools
"},{"location":"tools/sprite_compiler/usage_guide/","title":"Sprite Compiler Usage Guide","text":"

Complete guide to using the PixelRoot32 Sprite Compiler for converting images to sprite data.

"},{"location":"tools/sprite_compiler/usage_guide/#basic-usage","title":"Basic Usage","text":""},{"location":"tools/sprite_compiler/usage_guide/#launching-the-gui","title":"Launching the GUI","text":"

The easiest way to use the compiler is via the Graphical User Interface (GUI).

python main.py\n

This will open the application where you can interactively load images, configure the grid, and export sprites.

"},{"location":"tools/sprite_compiler/usage_guide/#command-line-interface-cli","title":"Command Line Interface (CLI)","text":"

For automation, you can use the CLI mode by passing arguments to the script.

python main.py [input] [options]\n

Required:

  • input: Input PNG image file
  • --grid WxH: Grid cell size (e.g., 16x16)
  • --sprite gx,gy,gw,gh: Sprite definition (can be repeated)

Optional:

  • --prefix NAME: Prefix for generated arrays (e.g., PLAYER_JUM)
  • --out FILE: Output header file (default: sprites.h)
  • --offset X,Y: Initial offset in pixels (default: 0,0)
  • --mode MODE: Export mode (layered, 2bpp, 4bpp)
"},{"location":"tools/sprite_compiler/usage_guide/#cli-examples","title":"CLI Examples","text":""},{"location":"tools/sprite_compiler/usage_guide/#simple-conversion","title":"Simple Conversion","text":"

Convert a single 16x16 sprite located at the top-left corner:

python main.py player.png --grid 16x16 --sprite 0,0,1,1 --out player.h\n
"},{"location":"tools/sprite_compiler/usage_guide/#multiple-sprites","title":"Multiple Sprites","text":"

Convert multiple sprites from a single sheet:

python main.py sheet.png --grid 16x16 \\\n  --sprite 0,0,1,1 \\\n  --sprite 1,0,1,1 \\\n  --sprite 2,0,1,1 \\\n  --out animations.h\n
"},{"location":"tools/sprite_compiler/usage_guide/#export-modes","title":"Export Modes","text":"

Layered (Default): Generates multiple uint16_t arrays, one for each color layer. Best for standard PixelRoot32 rendering.

python main.py icon.png --grid 16x16 --sprite 0,0,1,1 --mode layered\n

Packed 2bpp: Generates a single array with 2 bits per pixel (4 colors max).

python main.py icon.png --grid 16x16 --sprite 0,0,1,1 --mode 2bpp\n
"},{"location":"tools/sprite_compiler/usage_guide/#step-by-step-examples","title":"Step-by-Step Examples","text":""},{"location":"tools/sprite_compiler/usage_guide/#example-1-simple-player-sprite","title":"Example 1: Simple Player Sprite","text":"

Step 1: Create Image

  • Create an 8x8 pixel PNG image
  • Use black and white colors
  • Save as player.png

Step 2: Compile

python main.py player.png --grid 8x8 --sprite 0,0,1,1 --prefix PLAYER --out player_sprite.h\n

Step 3: Use in Code

#include \"player_sprite.h\"\n\nvoid draw() {\n    // PLAYER_SPRITE_0_LAYER_0 is generated automatically\n    renderer.drawSprite(PLAYER_SPRITE_0_LAYER_0, 100, 100, Color::White);\n}\n
"},{"location":"tools/sprite_compiler/usage_guide/#example-2-multiple-animation-frames","title":"Example 2: Multiple Animation Frames","text":"

Step 1: Prepare Images

  • Create frames: walk_0.png, walk_1.png, walk_2.png
  • All same size (e.g., 16x16)

Step 2: Batch Compile

pr32-sprite-compiler --batch walk_*.png --output-dir animations/ --prefix WALK_\n

Step 3: Use in Animation

#include \"animations/walk_0.h\"\n#include \"animations/walk_1.h\"\n#include \"animations/walk_2.h\"\n\nconst Sprite* WALK_FRAMES[] = {\n    &WALK_0_SPRITE,\n    &WALK_1_SPRITE,\n    &WALK_2_SPRITE\n};\n
"},{"location":"tools/sprite_compiler/usage_guide/#example-3-sprite-sheet","title":"Example 3: Sprite Sheet","text":"

Step 1: Create Sprite Sheet

  • Create a 64x64 image with 4x4 grid of 16x16 sprites
  • Save as characters.png

Step 2: Split Sheet

pr32-sprite-compiler characters.png characters.h --sheet 16x16 --count 16\n

Step 3: Use Individual Sprites

#include \"characters.h\"\n\n// Sprites named CHARACTER_0, CHARACTER_1, etc.\nrenderer.drawSprite(CHARACTER_0, 50, 50, Color::White);\nrenderer.drawSprite(CHARACTER_1, 70, 50, Color::White);\n
"},{"location":"tools/sprite_compiler/usage_guide/#batch-processing","title":"Batch Processing","text":""},{"location":"tools/sprite_compiler/usage_guide/#process-multiple-files","title":"Process Multiple Files","text":"

Process all PNG files in a directory:

pr32-sprite-compiler --batch sprites/*.png --output-dir generated/\n
"},{"location":"tools/sprite_compiler/usage_guide/#with-options","title":"With Options","text":"

Apply options to all files:

pr32-sprite-compiler --batch assets/*.png \\\n    --output-dir src/sprites/ \\\n    --format 1bpp \\\n    --prefix SPRITE_\n
"},{"location":"tools/sprite_compiler/usage_guide/#recursive-processing","title":"Recursive Processing","text":"

Process subdirectories:

pr32-sprite-compiler --batch assets/**/*.png --output-dir generated/\n
"},{"location":"tools/sprite_compiler/usage_guide/#sprite-sheets","title":"Sprite Sheets","text":""},{"location":"tools/sprite_compiler/usage_guide/#automatic-splitting","title":"Automatic Splitting","text":"

Split a sprite sheet into individual sprites:

pr32-sprite-compiler sheet.png output.h --sheet 8x8 --count 16\n

Parameters:

  • --sheet WxH: Tile size (width x height)
  • --count N: Number of sprites in sheet
"},{"location":"tools/sprite_compiler/usage_guide/#grid-layout","title":"Grid Layout","text":"

Specify grid dimensions:

pr32-sprite-compiler sheet.png output.h \\\n    --sheet 16x16 \\\n    --grid 4x4 \\\n    --count 16\n

Parameters:

  • --grid WxH: Grid dimensions (columns x rows)
"},{"location":"tools/sprite_compiler/usage_guide/#custom-naming","title":"Custom Naming","text":"

Name sprites with index:

pr32-sprite-compiler sheet.png output.h \\\n    --sheet 8x8 \\\n    --count 8 \\\n    --prefix CHARACTER_ \\\n    --indexed\n

Generates: CHARACTER_0, CHARACTER_1, etc.

"},{"location":"tools/sprite_compiler/usage_guide/#custom-palettes","title":"Custom Palettes","text":""},{"location":"tools/sprite_compiler/usage_guide/#using-palette-file","title":"Using Palette File","text":"

Convert with custom color palette:

pr32-sprite-compiler sprite.png output.h --palette palette.json\n

Palette JSON format:

{\n  \"colors\": [\n    {\"r\": 0, \"g\": 0, \"b\": 0, \"name\": \"black\"},\n    {\"r\": 255, \"g\": 255, \"b\": 255, \"name\": \"white\"}\n  ]\n}\n
"},{"location":"tools/sprite_compiler/usage_guide/#built-in-palettes","title":"Built-in Palettes","text":"

Use predefined palettes:

pr32-sprite-compiler sprite.png output.h --palette nes\npr32-sprite-compiler sprite.png output.h --palette gb\npr32-sprite-compiler sprite.png output.h --palette pico8\n
"},{"location":"tools/sprite_compiler/usage_guide/#advanced-options","title":"Advanced Options","text":""},{"location":"tools/sprite_compiler/usage_guide/#threshold-for-grayscale","title":"Threshold for Grayscale","text":"

Set threshold for black/white conversion:

pr32-sprite-compiler sprite.png output.h --threshold 128\n

Values: 0-255 (default: 127)

"},{"location":"tools/sprite_compiler/usage_guide/#dithering","title":"Dithering","text":"

Enable dithering for better gradients:

pr32-sprite-compiler sprite.png output.h --dither\n
"},{"location":"tools/sprite_compiler/usage_guide/#alignment","title":"Alignment","text":"

Control output alignment:

pr32-sprite-compiler sprite.png output.h --align 4\n
"},{"location":"tools/sprite_compiler/usage_guide/#endianness","title":"Endianness","text":"

Specify byte order:

pr32-sprite-compiler sprite.png output.h --endian little\npr32-sprite-compiler sprite.png output.h --endian big\n
"},{"location":"tools/sprite_compiler/usage_guide/#output-customization","title":"Output Customization","text":""},{"location":"tools/sprite_compiler/usage_guide/#namespace","title":"Namespace","text":"

Wrap output in namespace:

pr32-sprite-compiler sprite.png output.h --namespace MyGame\n
"},{"location":"tools/sprite_compiler/usage_guide/#header-guard","title":"Header Guard","text":"

Custom header guard:

pr32-sprite-compiler sprite.png output.h --guard MY_SPRITE_H\n
"},{"location":"tools/sprite_compiler/usage_guide/#include-paths","title":"Include Paths","text":"

Custom include paths:

pr32-sprite-compiler sprite.png output.h \\\n    --include \"<graphics/Sprite.h>\" \\\n    --include \"<stdint.h>\"\n
"},{"location":"tools/sprite_compiler/usage_guide/#integration-with-build-systems","title":"Integration with Build Systems","text":""},{"location":"tools/sprite_compiler/usage_guide/#platformio","title":"PlatformIO","text":"

Add to platformio.ini:

[env:esp32dev]\nextra_scripts = \n    pre:scripts/compile_sprites.py\n

compile_sprites.py:

Import(\"env\")\nimport subprocess\n\nsubprocess.run([\n    \"pr32-sprite-compiler\",\n    \"--batch\", \"assets/sprites/*.png\",\n    \"--output-dir\", \"src/sprites/\"\n])\n
"},{"location":"tools/sprite_compiler/usage_guide/#makefile","title":"Makefile","text":"
SPRITES = $(wildcard assets/sprites/*.png)\nSPRITE_HEADERS = $(SPRITES:assets/sprites/%.png=src/sprites/%.h)\n\nsrc/sprites/%.h: assets/sprites/%.png\n pr32-sprite-compiler $< $@ --name $(shell basename $< .png | tr '[:lower:]' '[:upper:]')_SPRITE\n\nsprites: $(SPRITE_HEADERS)\n
"},{"location":"tools/sprite_compiler/usage_guide/#cmake","title":"CMake","text":"
file(GLOB SPRITE_FILES \"assets/sprites/*.png\")\n\nforeach(SPRITE ${SPRITE_FILES})\n    get_filename_component(SPRITE_NAME ${SPRITE} NAME_WE)\n    add_custom_command(\n        OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/sprites/${SPRITE_NAME}.h\n        COMMAND pr32-sprite-compiler\n        ARGS ${SPRITE} ${CMAKE_CURRENT_SOURCE_DIR}/src/sprites/${SPRITE_NAME}.h\n        DEPENDS ${SPRITE}\n    )\nendforeach()\n
"},{"location":"tools/sprite_compiler/usage_guide/#gui-usage-if-available","title":"GUI Usage (If Available)","text":""},{"location":"tools/sprite_compiler/usage_guide/#opening-gui","title":"Opening GUI","text":"
pr32-sprite-compiler --gui\n

Or launch the GUI application directly.

"},{"location":"tools/sprite_compiler/usage_guide/#gui-workflow","title":"GUI Workflow","text":"
  1. Drag and drop images into the window
  2. Preview sprite data in real-time
  3. Adjust settings visually (format, threshold, etc.)
  4. Export to header files
  5. Batch process multiple files
"},{"location":"tools/sprite_compiler/usage_guide/#gui-features","title":"GUI Features","text":"
  • Visual preview of sprite conversion
  • Real-time threshold adjustment
  • Palette selection
  • Batch processing interface
  • Export options
"},{"location":"tools/sprite_compiler/usage_guide/#best-practices","title":"Best Practices","text":""},{"location":"tools/sprite_compiler/usage_guide/#image-preparation","title":"Image Preparation","text":"
  • Use indexed color PNG for best results
  • Keep sprites small (8x8, 16x16, 32x32)
  • Use black and white for 1bpp
  • Limit colors for 2bpp/4bpp formats
"},{"location":"tools/sprite_compiler/usage_guide/#file-organization","title":"File Organization","text":"
project/\n\u251c\u2500\u2500 assets/\n\u2502   \u2514\u2500\u2500 sprites/\n\u2502       \u251c\u2500\u2500 player.png\n\u2502       \u251c\u2500\u2500 enemy.png\n\u2502       \u2514\u2500\u2500 items.png\n\u251c\u2500\u2500 src/\n\u2502   \u2514\u2500\u2500 sprites/          # Generated headers\n\u2502       \u251c\u2500\u2500 player.h\n\u2502       \u251c\u2500\u2500 enemy.h\n\u2502       \u2514\u2500\u2500 items.h\n\u2514\u2500\u2500 platformio.ini\n
"},{"location":"tools/sprite_compiler/usage_guide/#naming-conventions","title":"Naming Conventions","text":"
  • Use descriptive names: player_walk_0.png \u2192 PLAYER_WALK_0_SPRITE
  • Be consistent: All caps for sprite names
  • Use prefixes: ENEMY_, PLAYER_, ITEM_
"},{"location":"tools/sprite_compiler/usage_guide/#version-control","title":"Version Control","text":"
  • Commit generated headers (they're part of the build)
  • Or add to .gitignore and regenerate on build
  • Keep source images in version control
"},{"location":"tools/sprite_compiler/usage_guide/#troubleshooting","title":"Troubleshooting","text":""},{"location":"tools/sprite_compiler/usage_guide/#common-issues","title":"Common Issues","text":"

\"Image too large\":

  • Sprites must be \u2264 16 pixels wide for 1bpp
  • Resize image or split into multiple sprites

\"Colors not converting correctly\":

  • Use indexed color PNG
  • For 1bpp: Use only black and white
  • For 2bpp: Use exactly 4 colors
  • For 4bpp: Use up to 16 colors

\"Output file not found\":

  • Check write permissions
  • Verify output directory exists
  • Use absolute paths if needed

\"Invalid format\":

  • Ensure input is PNG format
  • Check file is not corrupted
  • Try re-saving image in image editor
"},{"location":"tools/sprite_compiler/usage_guide/#getting-help","title":"Getting Help","text":"
pr32-sprite-compiler --help\n

Shows all available options and usage.

"},{"location":"tools/sprite_compiler/usage_guide/#next-steps","title":"Next Steps","text":"
  • Advanced Features - Explore advanced options
  • Overview - Learn more about the compiler
  • Manual - Sprites - Using sprites in games
"},{"location":"tools/sprite_compiler/usage_guide/#see-also","title":"See Also","text":"
  • Code Examples - Sprites - Sprite usage examples
  • Troubleshooting - Common issues and solutions
"},{"location":"tools/tilemap_editor/installation/","title":"Installation Guide","text":"

The PixelRoot32 Tilemap Editor can be run directly from source or as a standalone executable on Windows.

"},{"location":"tools/tilemap_editor/installation/#1-requirements","title":"1. Requirements","text":"
  • Python 3.13+ (if running from source).
  • Windows 10/11 (recommended).
"},{"location":"tools/tilemap_editor/installation/#2-install-from-source","title":"2. Install from Source","text":""},{"location":"tools/tilemap_editor/installation/#21-clone-the-repository","title":"2.1 Clone the Repository","text":"
git clone https://github.com/Gperez88/PixelRoot32-Tilemap-Editor.git\ncd PixelRoot32-Tilemap-Editor\n
"},{"location":"tools/tilemap_editor/installation/#22-install-dependencies","title":"2.2 Install Dependencies","text":"

The editor uses several Python libraries for the GUI and image processing:

pip install ttkbootstrap pillow jinja2\n
"},{"location":"tools/tilemap_editor/installation/#23-run-the-editor","title":"2.3 Run the Editor","text":"
python main.py\n
"},{"location":"tools/tilemap_editor/installation/#3-standalone-executable-windows","title":"3. Standalone Executable (Windows)","text":"

For a more convenient experience, you can use the pre-compiled version:

  1. Go to the Releases section of the repository.
  2. Download the latest PixelRoot32-Editor-win64.zip.
  3. Extract the contents to a folder.
  4. Run PixelRoot32-Editor.exe.

Note: No Python installation is required to run the standalone executable.

"},{"location":"tools/tilemap_editor/installation/#4-building-your-own-executable","title":"4. Building your own Executable","text":"

If you want to package the editor yourself:

  1. Install PyInstaller:
pip install pyinstaller\n
  1. Run the build command using the provided .spec file:
pyinstaller pixelroot32_editor.spec\n
  1. The executable will be available in the dist/ folder.
"},{"location":"tools/tilemap_editor/overview/","title":"Tilemap Editor Overview","text":"

The PixelRoot32 Tilemap Editor is a powerful visual tool designed to create complex multi-layered tile-based maps for the PixelRoot32 engine. It simplifies the process of designing game environments, managing tilesets, and exporting optimized C++ code.

"},{"location":"tools/tilemap_editor/overview/#what-it-does","title":"What It Does","text":"

The Tilemap Editor allows you to:

  • Visual Design: Paint tiles directly onto a canvas with layers and transparency.
  • Tileset Management: Import PNG images as tilesets and select single or multiple tiles.
  • Multi-Layer Support: Organize your map into up to 8 layers for parallax effects or depth.
  • Optimized Export: Generate C++ header and source files compatible with the PixelRoot32 renderer.
  • BPP Support: Export maps in 1bpp, 2bpp, or 4bpp formats to balance memory usage and color depth.
"},{"location":"tools/tilemap_editor/overview/#key-features","title":"Key Features","text":""},{"location":"tools/tilemap_editor/overview/#visual-editing-tools","title":"\u2705 Visual Editing Tools","text":"
  • Brush: Paint individual tiles or patterns.
  • Eraser: Remove tiles from the active layer.
  • Rectangle Fill: Quickly fill areas with a specific tile.
  • Pipette: Pick an existing tile from the canvas.
"},{"location":"tools/tilemap_editor/overview/#multi-layer-system","title":"\u2705 Multi-Layer System","text":"
  • Visibility Toggle: Hide/show layers to focus on specific parts of the map.
  • Opacity Control: Adjust layer transparency for complex blending effects.
  • Layer Reordering: Change the render order of your tilemaps.
"},{"location":"tools/tilemap_editor/overview/#tileset-selector","title":"\u2705 Tileset Selector","text":"
  • Smart Selection: Drag and select a rectangular area of tiles.
  • Multiple Tilesets: Support for multiple tilesets per project (planned).
  • Auto-import: Automatically detects tile size from the imported image.
"},{"location":"tools/tilemap_editor/overview/#engine-integration","title":"\u2705 Engine Integration","text":"
  • Workspace Selection: Link the editor to your PixelRoot32 projects directory.
  • Direct Export: Files are generated with the correct namespaces and structures for immediate use.
  • BPP Compatibility: Ensures exported data matches the engine's expected format for 1bpp, 2bpp, and 4bpp.
"},{"location":"tools/tilemap_editor/overview/#data-formats","title":"Data Formats","text":""},{"location":"tools/tilemap_editor/overview/#project-file-pr32scene","title":"Project File (.pr32scene)","text":"

The editor uses a custom JSON-based format to save your project state, including:

  • Tileset metadata (path, tile size, spacing).
  • Layer data (tile indices, width, height, position).
  • Project settings (BPP, namespace).
"},{"location":"tools/tilemap_editor/overview/#exported-c","title":"Exported C++","text":"

The editor generates <namespace>.h and <namespace>.cpp files containing:

  • Tilemap Data: One packed array of tile indices per layer (*_INDICES[]). Each layer is exposed as a TileMap4bpp (or TileMap2bpp/TileMap) with an indices pointer; use the same data for rendering and for tile-based collision in your game code.
  • Tilemap Structures: pixelroot32::graphics::TileMap (or TileMap2bpp/TileMap4bpp) definitions, plus tileset pool and palette.
  • Export options: Store data in Flash (ESP32) (default) emits static data with PROGMEM to reduce RAM use; Legacy format disables Flash attributes for backward compatibility or non-ESP32 builds.
  • Scene init: Call init() once before drawing; the generated code registers the palette and configures each layer for the engine.
"},{"location":"tools/tilemap_editor/usage_guide/","title":"Usage Guide","text":"

This guide covers the basic workflow for creating and exporting a tilemap using the PixelRoot32 Tilemap Editor.

"},{"location":"tools/tilemap_editor/usage_guide/#1-creating-a-new-project","title":"1. Creating a New Project","text":"
  1. Launch the editor.
  2. Go to File > New Project.
  3. Enter the project name and select the base Color Depth (BPP):
  4. 1bpp: Monochrome (2 colors).
  5. 2bpp: 4 colors.
  6. 4bpp: 16 colors.
  7. Set the Tile Size (e.g., 8x8, 16x16).
"},{"location":"tools/tilemap_editor/usage_guide/#2-importing-a-tileset","title":"2. Importing a Tileset","text":"
  1. In the Tileset panel, click on Load Tileset.
  2. Select a PNG image containing your tiles.
  3. The image will be sliced into tiles based on the tile size set in the project.
"},{"location":"tools/tilemap_editor/usage_guide/#3-painting-tiles","title":"3. Painting Tiles","text":"
  1. Select a tile (or a range of tiles) from the Tileset panel.
  2. Select the Brush tool (Shortcut: B).
  3. Click and drag on the canvas to paint.
  4. Use the Layers panel to switch between different layers.
"},{"location":"tools/tilemap_editor/usage_guide/#4-selection-and-transformations","title":"4. Selection and Transformations","text":"
  • Single Selection: Click on a tile in the tileset.
  • Area Selection: Click and drag in the tileset to select a rectangular block of tiles.
  • Pipette: Press P and click on the canvas to pick the tile under the cursor.
"},{"location":"tools/tilemap_editor/usage_guide/#5-exporting-to-c","title":"5. Exporting to C++","text":"
  1. Ensure you have at least one tileset imported.
  2. Click the Export button in the top right (or File > Export / Ctrl+E).
  3. In the export dialog:
  4. Set the C++ Namespace (e.g. forest_level); it defaults to the project name.
  5. Review the Color Depth (BPP); it is auto-detected from your tileset colors (1bpp, 2bpp, or 4bpp).
  6. Store data in Flash (ESP32): Checked by default; emits PROGMEM for palette, tileset, and layer data to reduce RAM on ESP32.
  7. Legacy format (no Flash attribute): Use for older projects or non-ESP32 builds.
  8. Click Export Now and choose the output directory.
  9. The editor generates:
  10. <namespace>.h: Declarations (e.g. TILE_SIZE, MAP_WIDTH, MAP_HEIGHT, layer TileMap4bpp externs, init()).
  11. <namespace>.cpp: Definitions (palette, tileset pool, layer indices, init() implementation). Use each layer's .indices in your game for drawing and tile-based collision.
"},{"location":"tools/tilemap_editor/usage_guide/#6-keyboard-shortcuts","title":"6. Keyboard Shortcuts","text":"Shortcut Action B Brush Tool E Eraser Tool R Rectangle Fill Tool P Pipette Tool Space + Drag Pan Canvas Mouse Wheel Zoom In/Out Ctrl + N New Project Ctrl + S Save Project Ctrl + E Export Project Esc Close floating panels"}]} \ No newline at end of file diff --git a/site/sitemap.xml b/site/sitemap.xml index 18ff6f0..d4029de 100644 --- a/site/sitemap.xml +++ b/site/sitemap.xml @@ -2,266 +2,270 @@ https://pixelroot32-game-engine.github.io/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/audio/audio_config/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/audio/audio_engine/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/audio/audio_types/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/audio/music_player/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/core/actor/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/core/engine/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/core/entity/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/core/input_config/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/core/input_manager/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/core/physics_actor/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/core/scene/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/graphics/camera2d/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/graphics/color/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/graphics/display_config/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/graphics/font/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/graphics/renderer/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/graphics/sprite/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/graphics/tilemap/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/physics/collision_system/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/physics/collision_types/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_button/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_checkbox/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_element/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_label/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layout/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layouts/anchor_layout/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layouts/grid_layout/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layouts/horizontal_layout/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layouts/padding_container/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layouts/panel/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layouts/vertical_layout/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/getting_started/fundamental_concepts/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/getting_started/installation/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/getting_started/what_is_pixelroot32/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/getting_started/why_pixelroot32/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/getting_started/your_first_project/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/advanced_graphics/cameras_and_scrolling/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/advanced_graphics/color_palettes/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/advanced_graphics/particles_and_effects/ - 2026-01-29 + 2026-01-30 + + + https://pixelroot32-game-engine.github.io/manual/advanced_graphics/resolution_scaling/ + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/advanced_graphics/sprites_and_animation/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/advanced_graphics/tilemaps/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/game_development/audio/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/game_development/basic_rendering/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/game_development/input_and_control/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/game_development/physics_and_collisions/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/game_development/scenes_and_entities/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/game_development/user_interface/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/optimization/extensibility/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/optimization/memory_management/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/optimization/performance_tuning/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/manual/optimization/platforms_and_drivers/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/reference/api_overview/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/reference/code_examples/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/reference/game_examples_guide/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/resources/available_tools/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/resources/faq/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/resources/limitations_and_considerations/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/resources/troubleshooting/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/tools/sprite_compiler/advanced_features/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/tools/sprite_compiler/installation/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/tools/sprite_compiler/overview/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/tools/sprite_compiler/usage_guide/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/tools/tilemap_editor/installation/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/tools/tilemap_editor/overview/ - 2026-01-29 + 2026-01-30 https://pixelroot32-game-engine.github.io/tools/tilemap_editor/usage_guide/ - 2026-01-29 + 2026-01-30 \ No newline at end of file diff --git a/site/sitemap.xml.gz b/site/sitemap.xml.gz index 122963a449c21e4bf4dea3b4ad3e1cb11f592612..18757df8c3db411feb3088e77003d941458def78 100644 GIT binary patch literal 872 zcmV-u1DE_CiwFpS^m}On|8r?{Wo=<_E_iKh0L_}sZreBz$M1cLz;|123M_UPiF@l4 zbkD??9Lcjwkz8`TMPpQ+zrI1dfZX$p1L;w_2p1_ zjPCHbfBbE`f4}{(mnqBG{Jievfxq@>NMthhn8hmCL3M4c{Wdm+o(7$4^HiN|d`nog zp^deWHOa#bvmQ1ZvjAF-+L*M(*8;`FH)T*1Qe|~o@d|B(0E4=qPp6wCWHB0pzgW~1 z`$L9w5?ggvCTDnb8quQH|t zqOmPGJ+=DZlv|O)T{EGw;<1wam}6y*K^v9yV)mb7ylUe@NdwfRYBQFHBYJ&Mw^&&x zRp}tuQ_RXChfGd6q8O3B$U+ZZIcNgcHilZc#2}Yty`VvBGMDa*naQef_JGXIp@ktc zx~{LmK~ra;6DM0tTr}}fkayk#)4J>JTdvCq*ibRAuGEEh(~2e;kWEjyut_=ojds<1 z7$H>f9k{csZRpIK-ntkF&J>$lJsJj`q^;F93A`A3-BS6dhzXhidYsLPeJ@_uNt&@l zUwP_{M6tE{eC~N?b3&kTb$$FP>Cyyi@OJyBad<`_)6|g6Cjkn;4+=ye$x8?L@?fsB@fJvMh^Vsy;a1A60~+F-CoWU_8pE29uMU-^ z{fmNgCcNk%veBWzD~!pb5+hA=@(sxhl^m`MR-_lPVjVaGc{q9r{1|=F0oB95IzYT+ zAWs?iZ6y_vmC9ru(!nSdNEQE;lT2S(x#kd>D|E5dn4|*E-z(!DfoonjCGR6@*=xB^ yr$JrslhqW*otibK#J5~wC^8}y}#aLE)>JV;&yejxW-_k zqtHDpzJ2|&{Iq!7T-^`Z7vyW{9LmFD$DBSl&EarZ6=Liml~v4LQ|wL-N;5S!H>@b;Ho3u4cisP=Dw-@U!M+z`{*|7 zoAt-#&Fyl1Ctaqt@qW$A4gc-dkjP|gF^g5Ofx*?b`fY3sEp{0{L+gh^ z)+7%n%zD^t%mQdRYGcwiz9uLpJ}HBukOo$lD_)`X5TH{x=+o{b0a=X3!Cx$D8v9*_ zv=du3Ryt=`JB?`3YjWcYm!nd1zPk8)0c>Mng;;Xvq)nqsOUj}?6@oGOvnW@H^IkXwZrilDyQI_VQiB=mpT^-HeN1PiKbF`Pf^DHz{l{X4j(GkHaV*l-@mEEcBp!{BFV)&J z=CoEP+2z;JNCCQ318Jl!4 ziUJwLe`P1#XU<&X5E>P_*s4#Wfb(x<+#>Lh=MBlrh+2vmm+3TQ*UMx>kr{pdbT-0G k>n($h>Kh8WeEJ4Xk4xWx{TGj(e+u&E7e@k(hRi4c0Pi}c!T Advanced Features - PixelRoot32 Documentation

Sprite Compiler Advanced Features

Advanced features and options for the PixelRoot32 Sprite Compiler to optimize sprite conversion and handle complex scenarios.

Automatic Palette Detection

The Sprite Compiler automatically detects if your sprite uses one of the engine's built-in palettes. This simplifies your workflow and ensures color consistency.

Predefined Engine Palettes

The engine includes 5 optimized palettes: - PR32 (Default PixelRoot32 palette) - NES (Nintendo style) - GB (GameBoy style) - GBC (GameBoy Color style) - PICO8 (Fantasy console style)

How it works

  1. Detection: When you compile an image, the tool compares all unique colors found in the sprite with the colors in the 5 engine palettes.
  2. Match: If all colors in your sprite belong to one of these palettes, the compiler:
  3. Omits generating a color array in the header.
  4. Assumes you will use the engine's built-in palette definitions at runtime.
  5. Custom Palette: If your sprite uses colors not found in the engine palettes, it automatically generates a {PREFIX}_PALETTE_MAPPING[16] array in the header file.

Naming with Prefixes

You can organize your generated code by using the --prefix parameter (or the Prefix field in the GUI).

Using Prefixes

By default, sprites are named SPRITE_N_.... Using a prefix allows you to create more descriptive names and avoid naming collisions.

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --prefix PLAYER_JUM
-

Generated names will follow this pattern: - PLAYER_JUM_SPRITE_0_LAYER_0 - PLAYER_JUM_SPRITE_0_2BPP - PLAYER_JUM_SPRITE_0_4BPP - PLAYER_JUM_PALETTE_MAPPING (if a custom palette is used)

Export Modes

Layered (1bpp)

Best for standard PixelRoot32 rendering. It extracts each color into its own bitmask (1bpp). The engine then renders these layers sequentially.

Packed (2bpp / 4bpp)

Generates a single packed array where each pixel uses multiple bits. - 2bpp: 4 colors max (Index 0 is always transparent). - 4bpp: 16 colors max (Index 0 is always transparent).

These modes are more efficient for sprites with many colors as they require only a single draw call.

\ No newline at end of file + Advanced Features - PixelRoot32 Documentation

Sprite Compiler Advanced Features

Advanced features and options for the PixelRoot32 Sprite Compiler to optimize sprite conversion and handle complex scenarios.

Automatic Palette Detection

The Sprite Compiler automatically detects if your sprite uses one of the engine's built-in palettes. This simplifies your workflow and ensures color consistency.

Predefined Engine Palettes

The engine includes 5 optimized palettes: - PR32 (Default PixelRoot32 palette) - NES (Nintendo style) - GB (GameBoy style) - GBC (GameBoy Color style) - PICO8 (Fantasy console style)

How it works

  1. Detection: When you compile an image, the tool compares all unique colors found in the sprite with the colors in the 5 engine palettes.
  2. Match: If all colors in your sprite belong to one of these palettes, the compiler:
  3. Omits generating a color array in the header.
  4. Assumes you will use the engine's built-in palette definitions at runtime.
  5. Custom Palette: If your sprite uses colors not found in the engine palettes, it automatically generates a {PREFIX}_PALETTE_MAPPING[16] array in the header file.

Naming with Prefixes

You can organize your generated code by using the --prefix parameter (or the Prefix field in the GUI).

Using Prefixes

By default, sprites are named SPRITE_N_.... Using a prefix allows you to create more descriptive names and avoid naming collisions.

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --prefix PLAYER_JUM
+

Generated names will follow this pattern: - PLAYER_JUM_SPRITE_0_LAYER_0 - PLAYER_JUM_SPRITE_0_2BPP - PLAYER_JUM_SPRITE_0_4BPP - PLAYER_JUM_PALETTE_MAPPING (if a custom palette is used)

Export Modes

Layered (1bpp)

Best for standard PixelRoot32 rendering. It extracts each color into its own bitmask (1bpp). The engine then renders these layers sequentially.

Packed (2bpp / 4bpp)

Generates a single packed array where each pixel uses multiple bits. - 2bpp: 4 colors max (Index 0 is always transparent). - 4bpp: 16 colors max (Index 0 is always transparent).

These modes are more efficient for sprites with many colors as they require only a single draw call.

\ No newline at end of file diff --git a/site/tools/sprite_compiler/installation/index.html b/site/tools/sprite_compiler/installation/index.html index 5d3e2a4..e101658 100644 --- a/site/tools/sprite_compiler/installation/index.html +++ b/site/tools/sprite_compiler/installation/index.html @@ -1,4 +1,4 @@ - Installation - PixelRoot32 Documentation

Sprite Compiler Installation

This guide walks you through installing the PixelRoot32 Sprite Compiler on your system.

Prerequisites

Required Software

  • Python: Version 3.8 or higher
  • pip: Usually included with Python

Verify Prerequisites

Check if Python is installed:

python --version
+ Installation - PixelRoot32 Documentation      

Sprite Compiler Installation

This guide walks you through installing the PixelRoot32 Sprite Compiler on your system.

Prerequisites

Required Software

  • Python: Version 3.8 or higher
  • pip: Usually included with Python

Verify Prerequisites

Check if Python is installed:

python --version
 # Should show 3.8.0 or higher
 

Check if pip is installed:

pip --version
 # Should show version number
@@ -29,4 +29,4 @@
 npm install
 

Uninstallation

Remove Global Installation

npm uninstall -g pr32-sprite-compiler
 

Remove Local Installation

npm uninstall pr32-sprite-compiler
-

Troubleshooting

Common Issues

"Command not found" after installation: - Restart your terminal - Check npm global bin path: npm config get prefix - Verify PATH includes npm bin directory

Permission errors: - On Linux/macOS: Use sudo for global install - Or install locally without -g flag - On Windows: Run terminal as Administrator

Module not found errors: - Reinstall: npm install -g pr32-sprite-compiler - Clear npm cache: npm cache clean --force

Version conflicts: - Check Node.js version: node --version - Update Node.js if version is too old - Use nvm (Node Version Manager) to manage versions

Getting Help

Next Steps

Once installed, proceed to: - Usage Guide - Learn how to use the compiler - Advanced Features - Explore advanced options

See Also

\ No newline at end of file +

Troubleshooting

Common Issues

"Command not found" after installation: - Restart your terminal - Check npm global bin path: npm config get prefix - Verify PATH includes npm bin directory

Permission errors: - On Linux/macOS: Use sudo for global install - Or install locally without -g flag - On Windows: Run terminal as Administrator

Module not found errors: - Reinstall: npm install -g pr32-sprite-compiler - Clear npm cache: npm cache clean --force

Version conflicts: - Check Node.js version: node --version - Update Node.js if version is too old - Use nvm (Node Version Manager) to manage versions

Getting Help

Next Steps

Once installed, proceed to: - Usage Guide - Learn how to use the compiler - Advanced Features - Explore advanced options

See Also

\ No newline at end of file diff --git a/site/tools/sprite_compiler/overview/index.html b/site/tools/sprite_compiler/overview/index.html index 5cb599f..ce0f6d7 100644 --- a/site/tools/sprite_compiler/overview/index.html +++ b/site/tools/sprite_compiler/overview/index.html @@ -1,4 +1,4 @@ - Overview - PixelRoot32 Documentation

Sprite Compiler Overview

The Sprite Compiler is a tool that converts PNG images into PixelRoot32 sprite data formats. It provides both a graphical interface (GUI) and a command-line interface (CLI) to automate the process of creating sprite arrays from image files.

What It Does

The Sprite Compiler takes bitmap images (PNG) and converts them into C header files containing:

  • Sprite data arrays: Optimized uint16_t arrays for various formats.
  • Layered support: Generates multiple 1bpp layers for complex sprites.
  • Packed formats: Supports 2bpp and 4bpp packed formats.
  • Sprite sheets: Handles grid-based sprite sheets with auto-detection.

Key Features

✅ Format Support

  • Layered (1bpp): Standard format, generates one array per color.
  • 2bpp (4 colors): Packed format, 2 bits per pixel.
  • 4bpp (16 colors): Packed format, 4 bits per pixel.

✅ GUI & CLI

  • Modern GUI: Step-by-step card-based interface for easy configuration.
  • Powerful CLI: Perfect for build scripts and automation.

✅ Sprite Sheets

Automatically split sprite sheets into individual sprites:

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --sprite 1,0,1,1 --out output.h
+ Overview - PixelRoot32 Documentation      

Sprite Compiler Overview

The Sprite Compiler is a tool that converts PNG images into PixelRoot32 sprite data formats. It provides both a graphical interface (GUI) and a command-line interface (CLI) to automate the process of creating sprite arrays from image files.

What It Does

The Sprite Compiler takes bitmap images (PNG) and converts them into C header files containing:

  • Sprite data arrays: Optimized uint16_t arrays for various formats.
  • Layered support: Generates multiple 1bpp layers for complex sprites.
  • Packed formats: Supports 2bpp and 4bpp packed formats.
  • Sprite sheets: Handles grid-based sprite sheets with auto-detection.

Key Features

✅ Format Support

  • Layered (1bpp): Standard format, generates one array per color.
  • 2bpp (4 colors): Packed format, 2 bits per pixel.
  • 4bpp (16 colors): Packed format, 4 bits per pixel.

✅ GUI & CLI

  • Modern GUI: Step-by-step card-based interface for easy configuration.
  • Powerful CLI: Perfect for build scripts and automation.

✅ Sprite Sheets

Automatically split sprite sheets into individual sprites:

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --sprite 1,0,1,1 --out output.h
 

GUI Interface

The GUI is designed to be intuitive and follows a 5-step process:

  1. Input Image: Select your PNG source.
  2. Grid Settings: Define the cell size and offsets.
  3. Sprite Selection: Pick which cells to export.
  4. Export Settings: Choose the mode (Layered, 2bpp, 4bpp), set a Prefix, and choose the output path.
  5. About: Quick access to version info and credits (via the ? button).
  6. Log: Technical feedback and performance alerts.

Input Requirements

Supported Formats

  • PNG: Primary format (recommended)
  • Indexed color PNG: Best for 1bpp conversion
  • Grayscale PNG: Automatically converted to 1bpp
  • RGB PNG: Converted using threshold or palette

Image Constraints

For 1bpp sprites: - Maximum width: 16 pixels - Height: Any (typically 8, 16, 32 pixels) - Colors: Black and white (or converted automatically)

For 2bpp sprites: - Maximum width: 16 pixels - Colors: Up to 4 colors

For 4bpp sprites: - Maximum width: 16 pixels - Colors: Up to 16 colors

Output Format

The compiler generates C header files with optimized arrays:

// Generated by PixelRoot32 Sprite Compiler
 
 // Optional palette mapping if using custom colors
@@ -24,4 +24,4 @@
 
 # Continue with your build process
 platformio run
-

Advantages Over Manual Creation

✅ Time Saving

  • No manual bit pattern conversion
  • Automatic format optimization
  • Batch processing multiple sprites

✅ Accuracy

  • Correct bit ordering
  • Proper array formatting
  • Valid C++ syntax

✅ Consistency

  • Uniform naming conventions
  • Standardized output format
  • Consistent code structure

✅ Maintainability

  • Easy to regenerate from source images
  • Version control friendly
  • Clear separation of assets and code

Limitations

  • Width limit: 16 pixels for 1bpp (hardware constraint)
  • Color depth: Limited by format (1bpp = 2 colors, 2bpp = 4 colors, etc.)
  • File format: Primarily PNG (other formats may require conversion)

Next Steps

See Also

\ No newline at end of file +

Advantages Over Manual Creation

✅ Time Saving

  • No manual bit pattern conversion
  • Automatic format optimization
  • Batch processing multiple sprites

✅ Accuracy

  • Correct bit ordering
  • Proper array formatting
  • Valid C++ syntax

✅ Consistency

  • Uniform naming conventions
  • Standardized output format
  • Consistent code structure

✅ Maintainability

  • Easy to regenerate from source images
  • Version control friendly
  • Clear separation of assets and code

Limitations

  • Width limit: 16 pixels for 1bpp (hardware constraint)
  • Color depth: Limited by format (1bpp = 2 colors, 2bpp = 4 colors, etc.)
  • File format: Primarily PNG (other formats may require conversion)

Next Steps

See Also

\ No newline at end of file diff --git a/site/tools/sprite_compiler/usage_guide/index.html b/site/tools/sprite_compiler/usage_guide/index.html index b97fa27..7af22e4 100644 --- a/site/tools/sprite_compiler/usage_guide/index.html +++ b/site/tools/sprite_compiler/usage_guide/index.html @@ -1,4 +1,4 @@ - Usage Guide - PixelRoot32 Documentation

Sprite Compiler Usage Guide

Complete guide to using the PixelRoot32 Sprite Compiler for converting images to sprite data.

Basic Usage

Launching the GUI

The easiest way to use the compiler is via the Graphical User Interface (GUI).

python main.py
+ Usage Guide - PixelRoot32 Documentation      

Sprite Compiler Usage Guide

Complete guide to using the PixelRoot32 Sprite Compiler for converting images to sprite data.

Basic Usage

Launching the GUI

The easiest way to use the compiler is via the Graphical User Interface (GUI).

python main.py
 

This will open the application where you can interactively load images, configure the grid, and export sprites.

Command Line Interface (CLI)

For automation, you can use the CLI mode by passing arguments to the script.

python main.py [input] [options]
 

Required:

  • input: Input PNG image file
  • --grid WxH: Grid cell size (e.g., 16x16)
  • --sprite gx,gy,gw,gh: Sprite definition (can be repeated)

Optional:

  • --prefix NAME: Prefix for generated arrays (e.g., PLAYER_JUM)
  • --out FILE: Output header file (default: sprites.h)
  • --offset X,Y: Initial offset in pixels (default: 0,0)
  • --mode MODE: Export mode (layered, 2bpp, 4bpp)

CLI Examples

Simple Conversion

Convert a single 16x16 sprite located at the top-left corner:

python main.py player.png --grid 16x16 --sprite 0,0,1,1 --out player.h
 

Multiple Sprites

Convert multiple sprites from a single sheet:

python main.py sheet.png --grid 16x16 \
@@ -110,4 +110,4 @@
 │       └── items.h
 └── platformio.ini
 

Naming Conventions

  • Use descriptive names: player_walk_0.pngPLAYER_WALK_0_SPRITE
  • Be consistent: All caps for sprite names
  • Use prefixes: ENEMY_, PLAYER_, ITEM_

Version Control

  • Commit generated headers (they're part of the build)
  • Or add to .gitignore and regenerate on build
  • Keep source images in version control

Troubleshooting

Common Issues

"Image too large":

  • Sprites must be ≤ 16 pixels wide for 1bpp
  • Resize image or split into multiple sprites

"Colors not converting correctly":

  • Use indexed color PNG
  • For 1bpp: Use only black and white
  • For 2bpp: Use exactly 4 colors
  • For 4bpp: Use up to 16 colors

"Output file not found":

  • Check write permissions
  • Verify output directory exists
  • Use absolute paths if needed

"Invalid format":

  • Ensure input is PNG format
  • Check file is not corrupted
  • Try re-saving image in image editor

Getting Help

pr32-sprite-compiler --help
-

Shows all available options and usage.

Next Steps

See Also

\ No newline at end of file +

Shows all available options and usage.

Next Steps

See Also

\ No newline at end of file diff --git a/site/tools/tilemap_editor/installation/index.html b/site/tools/tilemap_editor/installation/index.html index c9c64cb..6b87957 100644 --- a/site/tools/tilemap_editor/installation/index.html +++ b/site/tools/tilemap_editor/installation/index.html @@ -1,7 +1,7 @@ - Installation Guide - PixelRoot32 Documentation

Installation Guide

The PixelRoot32 Tilemap Editor can be run directly from source or as a standalone executable on Windows.

1. Requirements

  • Python 3.13+ (if running from source).
  • Windows 10/11 (recommended).

2. Install from Source

2.1 Clone the Repository

git clone https://github.com/Gperez88/PixelRoot32-Tilemap-Editor.git
+ Installation Guide - PixelRoot32 Documentation      

Installation Guide

The PixelRoot32 Tilemap Editor can be run directly from source or as a standalone executable on Windows.

1. Requirements

  • Python 3.13+ (if running from source).
  • Windows 10/11 (recommended).

2. Install from Source

2.1 Clone the Repository

git clone https://github.com/Gperez88/PixelRoot32-Tilemap-Editor.git
 cd PixelRoot32-Tilemap-Editor
 

2.2 Install Dependencies

The editor uses several Python libraries for the GUI and image processing:

pip install ttkbootstrap pillow jinja2
 

2.3 Run the Editor

python main.py
 

3. Standalone Executable (Windows)

For a more convenient experience, you can use the pre-compiled version:

  1. Go to the Releases section of the repository.
  2. Download the latest PixelRoot32-Editor-win64.zip.
  3. Extract the contents to a folder.
  4. Run PixelRoot32-Editor.exe.

Note: No Python installation is required to run the standalone executable.

4. Building your own Executable

If you want to package the editor yourself:

  1. Install PyInstaller:
pip install pyinstaller
 
  1. Run the build command using the provided .spec file:
pyinstaller pixelroot32_editor.spec
-
  1. The executable will be available in the dist/ folder.
\ No newline at end of file +
  1. The executable will be available in the dist/ folder.
\ No newline at end of file diff --git a/site/tools/tilemap_editor/overview/index.html b/site/tools/tilemap_editor/overview/index.html index 3edff91..5651751 100644 --- a/site/tools/tilemap_editor/overview/index.html +++ b/site/tools/tilemap_editor/overview/index.html @@ -1 +1 @@ - Tilemap Editor Overview - PixelRoot32 Documentation

Tilemap Editor Overview

The PixelRoot32 Tilemap Editor is a powerful visual tool designed to create complex multi-layered tile-based maps for the PixelRoot32 engine. It simplifies the process of designing game environments, managing tilesets, and exporting optimized C++ code.

What It Does

The Tilemap Editor allows you to:

  • Visual Design: Paint tiles directly onto a canvas with layers and transparency.
  • Tileset Management: Import PNG images as tilesets and select single or multiple tiles.
  • Multi-Layer Support: Organize your map into up to 8 layers for parallax effects or depth.
  • Optimized Export: Generate C++ header and source files compatible with the PixelRoot32 renderer.
  • BPP Support: Export maps in 1bpp, 2bpp, or 4bpp formats to balance memory usage and color depth.

Key Features

✅ Visual Editing Tools

  • Brush: Paint individual tiles or patterns.
  • Eraser: Remove tiles from the active layer.
  • Rectangle Fill: Quickly fill areas with a specific tile.
  • Pipette: Pick an existing tile from the canvas.

✅ Multi-Layer System

  • Visibility Toggle: Hide/show layers to focus on specific parts of the map.
  • Opacity Control: Adjust layer transparency for complex blending effects.
  • Layer Reordering: Change the render order of your tilemaps.

✅ Tileset Selector

  • Smart Selection: Drag and select a rectangular area of tiles.
  • Multiple Tilesets: Support for multiple tilesets per project (planned).
  • Auto-import: Automatically detects tile size from the imported image.

✅ Engine Integration

  • Workspace Selection: Link the editor to your PixelRoot32 projects directory.
  • Direct Export: Files are generated with the correct namespaces and structures for immediate use.
  • BPP Compatibility: Ensures exported data matches the engine's expected format for 1bpp, 2bpp, and 4bpp.

Data Formats

Project File (.pr32scene)

The editor uses a custom JSON-based format to save your project state, including:

  • Tileset metadata (path, tile size, spacing).
  • Layer data (tile indices, width, height, position).
  • Project settings (BPP, namespace).

Exported C++

The editor generates <namespace>.h and <namespace>.cpp files containing:

  • Tilemap Data: One packed array of tile indices per layer (*_INDICES[]). Each layer is exposed as a TileMap4bpp (or TileMap2bpp/TileMap) with an indices pointer; use the same data for rendering and for tile-based collision in your game code.
  • Tilemap Structures: pixelroot32::graphics::TileMap (or TileMap2bpp/TileMap4bpp) definitions, plus tileset pool and palette.
  • Export options: Store data in Flash (ESP32) (default) emits static data with PROGMEM to reduce RAM use; Legacy format disables Flash attributes for backward compatibility or non-ESP32 builds.
  • Scene init: Call init() once before drawing; the generated code registers the palette and configures each layer for the engine.
\ No newline at end of file + Tilemap Editor Overview - PixelRoot32 Documentation

Tilemap Editor Overview

The PixelRoot32 Tilemap Editor is a powerful visual tool designed to create complex multi-layered tile-based maps for the PixelRoot32 engine. It simplifies the process of designing game environments, managing tilesets, and exporting optimized C++ code.

What It Does

The Tilemap Editor allows you to:

  • Visual Design: Paint tiles directly onto a canvas with layers and transparency.
  • Tileset Management: Import PNG images as tilesets and select single or multiple tiles.
  • Multi-Layer Support: Organize your map into up to 8 layers for parallax effects or depth.
  • Optimized Export: Generate C++ header and source files compatible with the PixelRoot32 renderer.
  • BPP Support: Export maps in 1bpp, 2bpp, or 4bpp formats to balance memory usage and color depth.

Key Features

✅ Visual Editing Tools

  • Brush: Paint individual tiles or patterns.
  • Eraser: Remove tiles from the active layer.
  • Rectangle Fill: Quickly fill areas with a specific tile.
  • Pipette: Pick an existing tile from the canvas.

✅ Multi-Layer System

  • Visibility Toggle: Hide/show layers to focus on specific parts of the map.
  • Opacity Control: Adjust layer transparency for complex blending effects.
  • Layer Reordering: Change the render order of your tilemaps.

✅ Tileset Selector

  • Smart Selection: Drag and select a rectangular area of tiles.
  • Multiple Tilesets: Support for multiple tilesets per project (planned).
  • Auto-import: Automatically detects tile size from the imported image.

✅ Engine Integration

  • Workspace Selection: Link the editor to your PixelRoot32 projects directory.
  • Direct Export: Files are generated with the correct namespaces and structures for immediate use.
  • BPP Compatibility: Ensures exported data matches the engine's expected format for 1bpp, 2bpp, and 4bpp.

Data Formats

Project File (.pr32scene)

The editor uses a custom JSON-based format to save your project state, including:

  • Tileset metadata (path, tile size, spacing).
  • Layer data (tile indices, width, height, position).
  • Project settings (BPP, namespace).

Exported C++

The editor generates <namespace>.h and <namespace>.cpp files containing:

  • Tilemap Data: One packed array of tile indices per layer (*_INDICES[]). Each layer is exposed as a TileMap4bpp (or TileMap2bpp/TileMap) with an indices pointer; use the same data for rendering and for tile-based collision in your game code.
  • Tilemap Structures: pixelroot32::graphics::TileMap (or TileMap2bpp/TileMap4bpp) definitions, plus tileset pool and palette.
  • Export options: Store data in Flash (ESP32) (default) emits static data with PROGMEM to reduce RAM use; Legacy format disables Flash attributes for backward compatibility or non-ESP32 builds.
  • Scene init: Call init() once before drawing; the generated code registers the palette and configures each layer for the engine.
\ No newline at end of file diff --git a/site/tools/tilemap_editor/usage_guide/index.html b/site/tools/tilemap_editor/usage_guide/index.html index 04eb3a8..05de26a 100644 --- a/site/tools/tilemap_editor/usage_guide/index.html +++ b/site/tools/tilemap_editor/usage_guide/index.html @@ -1 +1 @@ - Usage Guide - PixelRoot32 Documentation

Usage Guide

This guide covers the basic workflow for creating and exporting a tilemap using the PixelRoot32 Tilemap Editor.

1. Creating a New Project

  1. Launch the editor.
  2. Go to File > New Project.
  3. Enter the project name and select the base Color Depth (BPP):
  4. 1bpp: Monochrome (2 colors).
  5. 2bpp: 4 colors.
  6. 4bpp: 16 colors.
  7. Set the Tile Size (e.g., 8x8, 16x16).

2. Importing a Tileset

  1. In the Tileset panel, click on Load Tileset.
  2. Select a PNG image containing your tiles.
  3. The image will be sliced into tiles based on the tile size set in the project.

3. Painting Tiles

  1. Select a tile (or a range of tiles) from the Tileset panel.
  2. Select the Brush tool (Shortcut: B).
  3. Click and drag on the canvas to paint.
  4. Use the Layers panel to switch between different layers.

4. Selection and Transformations

  • Single Selection: Click on a tile in the tileset.
  • Area Selection: Click and drag in the tileset to select a rectangular block of tiles.
  • Pipette: Press P and click on the canvas to pick the tile under the cursor.

5. Exporting to C++

  1. Ensure you have at least one tileset imported.
  2. Click the Export button in the top right (or File > Export / Ctrl+E).
  3. In the export dialog:
  4. Set the C++ Namespace (e.g. forest_level); it defaults to the project name.
  5. Review the Color Depth (BPP); it is auto-detected from your tileset colors (1bpp, 2bpp, or 4bpp).
  6. Store data in Flash (ESP32): Checked by default; emits PROGMEM for palette, tileset, and layer data to reduce RAM on ESP32.
  7. Legacy format (no Flash attribute): Use for older projects or non-ESP32 builds.
  8. Click Export Now and choose the output directory.
  9. The editor generates:
  10. <namespace>.h: Declarations (e.g. TILE_SIZE, MAP_WIDTH, MAP_HEIGHT, layer TileMap4bpp externs, init()).
  11. <namespace>.cpp: Definitions (palette, tileset pool, layer indices, init() implementation). Use each layer's .indices in your game for drawing and tile-based collision.

6. Keyboard Shortcuts

Shortcut Action
B Brush Tool
E Eraser Tool
R Rectangle Fill Tool
P Pipette Tool
Space + Drag Pan Canvas
Mouse Wheel Zoom In/Out
Ctrl + N New Project
Ctrl + S Save Project
Ctrl + E Export Project
Esc Close floating panels
\ No newline at end of file + Usage Guide - PixelRoot32 Documentation

Usage Guide

This guide covers the basic workflow for creating and exporting a tilemap using the PixelRoot32 Tilemap Editor.

1. Creating a New Project

  1. Launch the editor.
  2. Go to File > New Project.
  3. Enter the project name and select the base Color Depth (BPP):
  4. 1bpp: Monochrome (2 colors).
  5. 2bpp: 4 colors.
  6. 4bpp: 16 colors.
  7. Set the Tile Size (e.g., 8x8, 16x16).

2. Importing a Tileset

  1. In the Tileset panel, click on Load Tileset.
  2. Select a PNG image containing your tiles.
  3. The image will be sliced into tiles based on the tile size set in the project.

3. Painting Tiles

  1. Select a tile (or a range of tiles) from the Tileset panel.
  2. Select the Brush tool (Shortcut: B).
  3. Click and drag on the canvas to paint.
  4. Use the Layers panel to switch between different layers.

4. Selection and Transformations

  • Single Selection: Click on a tile in the tileset.
  • Area Selection: Click and drag in the tileset to select a rectangular block of tiles.
  • Pipette: Press P and click on the canvas to pick the tile under the cursor.

5. Exporting to C++

  1. Ensure you have at least one tileset imported.
  2. Click the Export button in the top right (or File > Export / Ctrl+E).
  3. In the export dialog:
  4. Set the C++ Namespace (e.g. forest_level); it defaults to the project name.
  5. Review the Color Depth (BPP); it is auto-detected from your tileset colors (1bpp, 2bpp, or 4bpp).
  6. Store data in Flash (ESP32): Checked by default; emits PROGMEM for palette, tileset, and layer data to reduce RAM on ESP32.
  7. Legacy format (no Flash attribute): Use for older projects or non-ESP32 builds.
  8. Click Export Now and choose the output directory.
  9. The editor generates:
  10. <namespace>.h: Declarations (e.g. TILE_SIZE, MAP_WIDTH, MAP_HEIGHT, layer TileMap4bpp externs, init()).
  11. <namespace>.cpp: Definitions (palette, tileset pool, layer indices, init() implementation). Use each layer's .indices in your game for drawing and tile-based collision.

6. Keyboard Shortcuts

Shortcut Action
B Brush Tool
E Eraser Tool
R Rectangle Fill Tool
P Pipette Tool
Space + Drag Pan Canvas
Mouse Wheel Zoom In/Out
Ctrl + N New Project
Ctrl + S Save Project
Ctrl + E Export Project
Esc Close floating panels
\ No newline at end of file From 255e671bc26c95a3a267a334e46faa2871f83d1d Mon Sep 17 00:00:00 2001 From: Gperez88 Date: Fri, 30 Jan 2026 16:40:04 -0400 Subject: [PATCH 2/7] docs: clarify display rotation, FPS limits, and CPU metrics - Update display rotation documentation to show index-based and degree-based values - Add important note about physical SPI bus limits affecting FPS in resolution scaling - Explain platform differences in CPU load metrics for debug overlay - Update generated HTML timestamps --- docs/api_reference/core/engine.md | 6 ++++++ docs/api_reference/graphics/display_config.md | 12 ++++++++---- docs/manual/advanced_graphics/resolution_scaling.md | 8 ++++++++ site/api_reference/audio/audio_config/index.html | 2 +- site/api_reference/audio/audio_engine/index.html | 2 +- site/api_reference/audio/audio_types/index.html | 2 +- site/api_reference/audio/music_player/index.html | 2 +- site/api_reference/core/actor/index.html | 2 +- site/api_reference/core/engine/index.html | 2 +- site/api_reference/core/entity/index.html | 2 +- site/api_reference/core/input_config/index.html | 2 +- site/api_reference/core/input_manager/index.html | 2 +- site/api_reference/core/physics_actor/index.html | 2 +- site/api_reference/core/scene/index.html | 2 +- site/api_reference/graphics/camera2d/index.html | 2 +- site/api_reference/graphics/color/index.html | 2 +- .../api_reference/graphics/display_config/index.html | 2 +- site/api_reference/graphics/font/index.html | 2 +- site/api_reference/graphics/renderer/index.html | 2 +- site/api_reference/graphics/sprite/index.html | 2 +- site/api_reference/graphics/tilemap/index.html | 2 +- .../physics/collision_system/index.html | 2 +- .../api_reference/physics/collision_types/index.html | 2 +- site/api_reference/ui/ui_button/index.html | 2 +- site/api_reference/ui/ui_checkbox/index.html | 2 +- site/api_reference/ui/ui_element/index.html | 2 +- site/api_reference/ui/ui_label/index.html | 2 +- site/api_reference/ui/ui_layout/index.html | 2 +- .../ui/ui_layouts/anchor_layout/index.html | 2 +- .../ui/ui_layouts/grid_layout/index.html | 2 +- .../ui/ui_layouts/horizontal_layout/index.html | 2 +- .../ui/ui_layouts/padding_container/index.html | 2 +- site/api_reference/ui/ui_layouts/panel/index.html | 2 +- .../ui/ui_layouts/vertical_layout/index.html | 2 +- site/getting_started/fundamental_concepts/index.html | 2 +- site/getting_started/installation/index.html | 2 +- site/getting_started/what_is_pixelroot32/index.html | 2 +- site/getting_started/why_pixelroot32/index.html | 2 +- site/getting_started/your_first_project/index.html | 2 +- site/index.html | 2 +- .../cameras_and_scrolling/index.html | 2 +- .../advanced_graphics/color_palettes/index.html | 2 +- .../particles_and_effects/index.html | 2 +- .../advanced_graphics/resolution_scaling/index.html | 2 +- .../sprites_and_animation/index.html | 2 +- site/manual/advanced_graphics/tilemaps/index.html | 2 +- site/manual/game_development/audio/index.html | 2 +- .../game_development/basic_rendering/index.html | 2 +- .../game_development/input_and_control/index.html | 2 +- .../physics_and_collisions/index.html | 2 +- .../game_development/scenes_and_entities/index.html | 2 +- .../game_development/user_interface/index.html | 2 +- site/manual/optimization/extensibility/index.html | 2 +- .../manual/optimization/memory_management/index.html | 2 +- .../optimization/performance_tuning/index.html | 2 +- .../optimization/platforms_and_drivers/index.html | 2 +- site/reference/api_overview/index.html | 2 +- site/reference/code_examples/index.html | 2 +- site/reference/game_examples_guide/index.html | 2 +- site/resources/available_tools/index.html | 2 +- site/resources/faq/index.html | 2 +- .../limitations_and_considerations/index.html | 2 +- site/resources/troubleshooting/index.html | 2 +- .../sprite_compiler/advanced_features/index.html | 2 +- site/tools/sprite_compiler/installation/index.html | 2 +- site/tools/sprite_compiler/overview/index.html | 2 +- site/tools/sprite_compiler/usage_guide/index.html | 2 +- site/tools/tilemap_editor/installation/index.html | 2 +- site/tools/tilemap_editor/overview/index.html | 2 +- site/tools/tilemap_editor/usage_guide/index.html | 2 +- 70 files changed, 89 insertions(+), 71 deletions(-) diff --git a/docs/api_reference/core/engine.md b/docs/api_reference/core/engine.md index 6d6ddf8..09c4906 100644 --- a/docs/api_reference/core/engine.md +++ b/docs/api_reference/core/engine.md @@ -288,6 +288,12 @@ When the engine is built with the preprocessor define **`PIXELROOT32_ENABLE_DEBU - **RAM**: Used heap memory in KB (Cyan). - **CPU**: Estimated processor load percentage (Yellow). +!!! note "Platform Differences & CPU Metric" + The **CPU Load** metric is an estimation based on the processing time vs. a 60 FPS target (16.6ms). + + * **On ESP32**: This is a realistic representation of how much time the CPU is spending on engine logic within its power limits. + * **On Native (PC)**: This metric may frequently show **100%** or high values even if your PC is idle. This happens because the native loop is synchronized with the monitor's VSYNC (via SDL2), which often causes the frame time to exceed 16.6ms (e.g., 33ms for 30 FPS). This is a result of the operating system's scheduling and SDL's synchronization, not actual hardware saturation. + **Behavior:** - The overlay is drawn in the top-right area of the screen. diff --git a/docs/api_reference/graphics/display_config.md b/docs/api_reference/graphics/display_config.md index e6414c9..8bb5c5d 100644 --- a/docs/api_reference/graphics/display_config.md +++ b/docs/api_reference/graphics/display_config.md @@ -40,7 +40,7 @@ The type of display. ### int rotation -Display rotation in degrees. +Display rotation. Supports both index-based (0-3) and degree-based (0, 90, 180, 270) values. **Type:** `int` @@ -49,9 +49,13 @@ Display rotation in degrees. **Default:** `0` **Notes:** -- Common values: 0, 90, 180, 270 -- Rotation is applied during initialization -- Some displays may not support all rotations +- `0`: Normal orientation (0°) +- `1` or `90`: Rotated 90 degrees clockwise +- `2` or `180`: Rotated 180 degrees +- `3` or `270`: Rotated 90 degrees counter-clockwise (270°) +- Rotation is applied during initialization. +- On ESP32, this affects both the hardware display orientation and the internal framebuffer. +- On Native (SDL2), this rotates the rendered texture before presenting it. ### uint16_t physicalWidth diff --git a/docs/manual/advanced_graphics/resolution_scaling.md b/docs/manual/advanced_graphics/resolution_scaling.md index 52549a5..da6f0a2 100644 --- a/docs/manual/advanced_graphics/resolution_scaling.md +++ b/docs/manual/advanced_graphics/resolution_scaling.md @@ -73,6 +73,14 @@ The following table shows estimated savings on an ESP32 for a standard 240x240 d | **128x128** | 16.4 KB | ~72% | +60% | | **96x96** | 9.2 KB | ~84% | +100% | +!!! important "Final FPS Analysis" + It is very important to understand that at 240x240 physical pixels, your maximum limit is **~14 FPS** due to the SPI bus speed (40MHz). + + - **128x128 physical pixels**: You send 16k pixels → **~43 FPS**. + - **240x240 physical pixels**: You send 57k pixels (3.5 times more) → The bus takes 3.5 times longer to transmit, dropping to **~12-14 FPS**. + + Even if you render internally at 128x128 (logical), the system must ultimately send 57,600 pixels to the physical display to fill it. There is no way to bypass this physical limit unless a smaller display or a faster bus is used. + ## Implementation Details ### Nearest Neighbor Scaling diff --git a/site/api_reference/audio/audio_config/index.html b/site/api_reference/audio/audio_config/index.html index 24db741..4b421d2 100644 --- a/site/api_reference/audio/audio_config/index.html +++ b/site/api_reference/audio/audio_config/index.html @@ -84,4 +84,4 @@ engine.init(); engine.run(); } -

Platform-Specific Considerations

ESP32 DAC Backend

  • Sample rate: 11025 Hz recommended (lower CPU usage)
  • Quality: Lower quality, but simple setup
  • Pin: Uses GPIO 25 or 26
  • Hardware: Requires simple amplifier circuit

ESP32 I2S Backend

  • Sample rate: 22050 Hz recommended
  • Quality: Higher quality than DAC
  • Pins: Requires I2S pins (BCLK, LRCK, DOUT)
  • Hardware: Requires external I2S DAC

Native SDL2 Backend

  • Sample rate: 44100 Hz typical
  • Quality: High quality
  • Setup: Requires SDL2 library installed
  • Platforms: Windows, Linux, macOS

Performance Considerations

  • Sample rate: Lower rates use less CPU and memory
  • Backend choice: DAC is simpler but lower quality than I2S
  • Buffer size: Configured in backend, affects latency vs stability

See Also

\ No newline at end of file +

Platform-Specific Considerations

ESP32 DAC Backend

  • Sample rate: 11025 Hz recommended (lower CPU usage)
  • Quality: Lower quality, but simple setup
  • Pin: Uses GPIO 25 or 26
  • Hardware: Requires simple amplifier circuit

ESP32 I2S Backend

  • Sample rate: 22050 Hz recommended
  • Quality: Higher quality than DAC
  • Pins: Requires I2S pins (BCLK, LRCK, DOUT)
  • Hardware: Requires external I2S DAC

Native SDL2 Backend

  • Sample rate: 44100 Hz typical
  • Quality: High quality
  • Setup: Requires SDL2 library installed
  • Platforms: Windows, Linux, macOS

Performance Considerations

  • Sample rate: Lower rates use less CPU and memory
  • Backend choice: DAC is simpler but lower quality than I2S
  • Buffer size: Configured in backend, affects latency vs stability

See Also

\ No newline at end of file diff --git a/site/api_reference/audio/audio_engine/index.html b/site/api_reference/audio/audio_engine/index.html index 31088de..2892842 100644 --- a/site/api_reference/audio/audio_engine/index.html +++ b/site/api_reference/audio/audio_engine/index.html @@ -88,4 +88,4 @@ } } }; -

Performance Considerations

  • Channel limit: Only 4 channels total; plan sound effects accordingly
  • Event dropping: If all channels are busy, new events are silently dropped
  • Update frequency: update() must be called every frame for proper timing
  • Sample generation: generateSamples() is called by backend at audio rate (not game rate)

ESP32 Considerations

  • Sample rate: Lower sample rates (11025 Hz) use less CPU and memory
  • Backend choice: DAC backend is simpler but lower quality than I2S
  • Buffer size: Larger buffers reduce underruns but increase latency
  • Channel management: Limit simultaneous sounds to avoid channel conflicts

See Also

\ No newline at end of file +

Performance Considerations

  • Channel limit: Only 4 channels total; plan sound effects accordingly
  • Event dropping: If all channels are busy, new events are silently dropped
  • Update frequency: update() must be called every frame for proper timing
  • Sample generation: generateSamples() is called by backend at audio rate (not game rate)

ESP32 Considerations

  • Sample rate: Lower sample rates (11025 Hz) use less CPU and memory
  • Backend choice: DAC backend is simpler but lower quality than I2S
  • Buffer size: Larger buffers reduce underruns but increase latency
  • Channel management: Limit simultaneous sounds to avoid channel conflicts

See Also

\ No newline at end of file diff --git a/site/api_reference/audio/audio_types/index.html b/site/api_reference/audio/audio_types/index.html index 566764e..a3babbb 100644 --- a/site/api_reference/audio/audio_types/index.html +++ b/site/api_reference/audio/audio_types/index.html @@ -97,4 +97,4 @@ delay(50); // Small delay between events } } -

Performance Considerations

  • Event creation: Creating events is fast (just struct initialization)
  • Channel allocation: Events are queued and played when channels are available
  • Frequency range: Keep frequencies in reasonable range (100-5000 Hz) for best results
  • Duration: Shorter durations free channels faster

ESP32 Considerations

  • Memory: Events are small structs, safe to create frequently
  • CPU: Audio generation is efficient but limit simultaneous sounds
  • Quality: Lower sample rates reduce CPU usage

See Also

\ No newline at end of file +

Performance Considerations

  • Event creation: Creating events is fast (just struct initialization)
  • Channel allocation: Events are queued and played when channels are available
  • Frequency range: Keep frequencies in reasonable range (100-5000 Hz) for best results
  • Duration: Shorter durations free channels faster

ESP32 Considerations

  • Memory: Events are small structs, safe to create frequently
  • CPU: Audio generation is efficient but limit simultaneous sounds
  • Quality: Lower sample rates reduce CPU usage

See Also

\ No newline at end of file diff --git a/site/api_reference/audio/music_player/index.html b/site/api_reference/audio/music_player/index.html index 2a4f12c..36e7aab 100644 --- a/site/api_reference/audio/music_player/index.html +++ b/site/api_reference/audio/music_player/index.html @@ -106,4 +106,4 @@ music.stop(); } }; -

Performance Considerations

  • One channel: Music uses one channel, leaving others for sound effects
  • Update frequency: update() must be called every frame
  • Track size: Larger tracks use more memory (store in flash)
  • Tempo factor: Changing tempo is fast (just a multiplier)

ESP32 Considerations

  • Memory: Store tracks in flash (const/constexpr) to save RAM
  • CPU: Music playback is lightweight (simple sequencing)
  • Channel conflict: Music and sound effects share channels; plan accordingly

See Also

\ No newline at end of file +

Performance Considerations

  • One channel: Music uses one channel, leaving others for sound effects
  • Update frequency: update() must be called every frame
  • Track size: Larger tracks use more memory (store in flash)
  • Tempo factor: Changing tempo is fast (just a multiplier)

ESP32 Considerations

  • Memory: Store tracks in flash (const/constexpr) to save RAM
  • CPU: Music playback is lightweight (simple sequencing)
  • Channel conflict: Music and sound effects share channels; plan accordingly

See Also

\ No newline at end of file diff --git a/site/api_reference/core/actor/index.html b/site/api_reference/core/actor/index.html index 4fef897..a017b6d 100644 --- a/site/api_reference/core/actor/index.html +++ b/site/api_reference/core/actor/index.html @@ -126,4 +126,4 @@ } } }; -

Performance Considerations

  • Collision layers: Use layers efficiently to reduce collision checks
  • Hitbox size: Keep hitboxes simple (AABB) for best performance
  • Collision callbacks: Keep onCollision() fast; avoid expensive operations
  • Layer organization: Group actors by layer to minimize checks

ESP32 Considerations

  • Collision checks: Collision system automatically optimizes using layers
  • Memory: Each actor consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse actors instead of creating/destroying frequently

See Also

\ No newline at end of file +

Performance Considerations

  • Collision layers: Use layers efficiently to reduce collision checks
  • Hitbox size: Keep hitboxes simple (AABB) for best performance
  • Collision callbacks: Keep onCollision() fast; avoid expensive operations
  • Layer organization: Group actors by layer to minimize checks

ESP32 Considerations

  • Collision checks: Collision system automatically optimizes using layers
  • Memory: Each actor consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse actors instead of creating/destroying frequently

See Also

\ No newline at end of file diff --git a/site/api_reference/core/engine/index.html b/site/api_reference/core/engine/index.html index a044ef4..7ec40dd 100644 --- a/site/api_reference/core/engine/index.html +++ b/site/api_reference/core/engine/index.html @@ -111,4 +111,4 @@ // Run game loop engine.run(); } -

Performance Considerations

  • Initialization: init() should be called once at startup, not in the game loop
  • Scene switching: Switching scenes is fast but avoid doing it every frame
  • Subsystem access: Getters are inline and very fast; safe to call every frame
  • Delta time: Use getDeltaTime() for frame-rate independent movement

ESP32 Considerations

  • Ensure init() completes before run() to avoid initialization issues
  • Monitor memory usage when switching scenes frequently
  • Use getDeltaTime() for consistent gameplay across different frame rates

See Also

\ No newline at end of file +

Performance Considerations

  • Initialization: init() should be called once at startup, not in the game loop
  • Scene switching: Switching scenes is fast but avoid doing it every frame
  • Subsystem access: Getters are inline and very fast; safe to call every frame
  • Delta time: Use getDeltaTime() for frame-rate independent movement

ESP32 Considerations

  • Ensure init() completes before run() to avoid initialization issues
  • Monitor memory usage when switching scenes frequently
  • Use getDeltaTime() for consistent gameplay across different frame rates

See Also

\ No newline at end of file diff --git a/site/api_reference/core/entity/index.html b/site/api_reference/core/entity/index.html index 47151c9..2d0fd9d 100644 --- a/site/api_reference/core/entity/index.html +++ b/site/api_reference/core/entity/index.html @@ -84,4 +84,4 @@ private: float rotation = 0.0f; }; -

Performance Considerations

  • Visibility: Use isVisible = false instead of removing entities when hiding
  • Enable state: Use isEnabled = false to pause entity logic
  • Render layers: Organize entities by layer to minimize layer switches
  • Direct access: Direct property access is fast (no function call overhead)

ESP32 Considerations

  • Memory: Each entity consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse entities instead of creating/destroying frequently
  • Update frequency: Disable entities that don't need to update every frame

See Also

\ No newline at end of file +

Performance Considerations

  • Visibility: Use isVisible = false instead of removing entities when hiding
  • Enable state: Use isEnabled = false to pause entity logic
  • Render layers: Organize entities by layer to minimize layer switches
  • Direct access: Direct property access is fast (no function call overhead)

ESP32 Considerations

  • Memory: Each entity consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse entities instead of creating/destroying frequently
  • Update frequency: Disable entities that don't need to update every frame

See Also

\ No newline at end of file diff --git a/site/api_reference/core/input_config/index.html b/site/api_reference/core/input_config/index.html index 3e08d9a..24222be 100644 --- a/site/api_reference/core/input_config/index.html +++ b/site/api_reference/core/input_config/index.html @@ -117,4 +117,4 @@ SDL_SCANCODE_SPACE, // Jump SDL_SCANCODE_RETURN // Action ); -

Performance Considerations

  • Memory: Arrays are allocated dynamically (small overhead)
  • Configuration: Done once at startup, no runtime cost
  • Access: Button indices are fast (array access)

ESP32 Considerations

  • Pin configuration: Ensure pins are not used by other peripherals
  • Debouncing: Hardware debouncing recommended for reliable input
  • Power: Buttons should use pull-up resistors to avoid floating pins

See Also

\ No newline at end of file +

Performance Considerations

  • Memory: Arrays are allocated dynamically (small overhead)
  • Configuration: Done once at startup, no runtime cost
  • Access: Button indices are fast (array access)

ESP32 Considerations

  • Pin configuration: Ensure pins are not used by other peripherals
  • Debouncing: Hardware debouncing recommended for reliable input
  • Power: Buttons should use pull-up resistors to avoid floating pins

See Also

\ No newline at end of file diff --git a/site/api_reference/core/input_manager/index.html b/site/api_reference/core/input_manager/index.html index 5cf90a2..d420d9b 100644 --- a/site/api_reference/core/input_manager/index.html +++ b/site/api_reference/core/input_manager/index.html @@ -126,4 +126,4 @@ } } }; -

Input State Comparison

Method Returns true when Use Case
isButtonPressed() Button just pressed this frame One-time actions (jump, shoot)
isButtonReleased() Button just released this frame Release events (stop charging)
isButtonClicked() Button pressed then released UI buttons, menu selection
isButtonDown() Button currently held Continuous actions (movement)

Performance Considerations

  • Update frequency: update() must be called every frame
  • Debouncing: Handled automatically, no performance impact
  • State queries: All query methods are fast (inline accessors)
  • Memory: Button state arrays are small and efficient

ESP32 Considerations

  • GPIO pins: Configure pins in InputConfig
  • Pull-up/pull-down: Ensure proper resistor configuration
  • Debouncing: Hardware debouncing recommended for noisy buttons
  • Pin limits: Some ESP32 pins have restrictions (check datasheet)

Native Considerations

  • Keyboard mapping: Uses SDL scancodes
  • Key detection: Automatically handles keyboard state
  • Multiple keys: Can detect multiple keys simultaneously

See Also

\ No newline at end of file +

Input State Comparison

Method Returns true when Use Case
isButtonPressed() Button just pressed this frame One-time actions (jump, shoot)
isButtonReleased() Button just released this frame Release events (stop charging)
isButtonClicked() Button pressed then released UI buttons, menu selection
isButtonDown() Button currently held Continuous actions (movement)

Performance Considerations

  • Update frequency: update() must be called every frame
  • Debouncing: Handled automatically, no performance impact
  • State queries: All query methods are fast (inline accessors)
  • Memory: Button state arrays are small and efficient

ESP32 Considerations

  • GPIO pins: Configure pins in InputConfig
  • Pull-up/pull-down: Ensure proper resistor configuration
  • Debouncing: Hardware debouncing recommended for noisy buttons
  • Pin limits: Some ESP32 pins have restrictions (check datasheet)

Native Considerations

  • Keyboard mapping: Uses SDL scancodes
  • Key detection: Automatically handles keyboard state
  • Multiple keys: Can detect multiple keys simultaneously

See Also

\ No newline at end of file diff --git a/site/api_reference/core/physics_actor/index.html b/site/api_reference/core/physics_actor/index.html index 7e192a2..8c23ddc 100644 --- a/site/api_reference/core/physics_actor/index.html +++ b/site/api_reference/core/physics_actor/index.html @@ -154,4 +154,4 @@ playBounceSound(); } }; -

Performance Considerations

  • Physics integration: Very efficient (simple velocity integration)
  • World bounds: Boundary checks are fast (AABB)
  • Friction: Applied every frame; keep friction values reasonable
  • Collision callbacks: Keep onCollision() and onWorldCollision() fast

ESP32 Considerations

  • Floating point: Uses float math; acceptable for ESP32 but integer math would be faster
  • Frame rate: Physics is frame-rate independent (uses deltaTime)
  • Memory: Each PhysicsActor consumes more memory than Actor (velocity, limits, etc.)

See Also

\ No newline at end of file +

Performance Considerations

  • Physics integration: Very efficient (simple velocity integration)
  • World bounds: Boundary checks are fast (AABB)
  • Friction: Applied every frame; keep friction values reasonable
  • Collision callbacks: Keep onCollision() and onWorldCollision() fast

ESP32 Considerations

  • Floating point: Uses float math; acceptable for ESP32 but integer math would be faster
  • Frame rate: Physics is frame-rate independent (uses deltaTime)
  • Memory: Each PhysicsActor consumes more memory than Actor (velocity, limits, etc.)

See Also

\ No newline at end of file diff --git a/site/api_reference/core/scene/index.html b/site/api_reference/core/scene/index.html index ae5e58f..477fbf4 100644 --- a/site/api_reference/core/scene/index.html +++ b/site/api_reference/core/scene/index.html @@ -128,4 +128,4 @@ renderer.drawText(scoreText, 10, 10, Color::White, 1); } }; -

Performance Considerations

  • Entity limit: MAX_ENTITIES (default 32) can be overridden via compiler flags; plan accordingly
  • Add/Remove: Frequent add/remove operations can be expensive; use object pooling
  • Update order: Entities are updated in add order; consider order for dependencies
  • Collision checks: CollisionSystem automatically handles actor collisions efficiently

ESP32 Considerations

  • Memory: Each entity consumes memory; stay well below the limit
  • Object pooling: Essential for ESP32 to avoid memory fragmentation
  • Scene switching: Clearing and recreating scenes can fragment memory; reuse scenes when possible

See Also

\ No newline at end of file +

Performance Considerations

  • Entity limit: MAX_ENTITIES (default 32) can be overridden via compiler flags; plan accordingly
  • Add/Remove: Frequent add/remove operations can be expensive; use object pooling
  • Update order: Entities are updated in add order; consider order for dependencies
  • Collision checks: CollisionSystem automatically handles actor collisions efficiently

ESP32 Considerations

  • Memory: Each entity consumes memory; stay well below the limit
  • Object pooling: Essential for ESP32 to avoid memory fragmentation
  • Scene switching: Clearing and recreating scenes can fragment memory; reuse scenes when possible

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/camera2d/index.html b/site/api_reference/graphics/camera2d/index.html index 917ce1f..39bb9d8 100644 --- a/site/api_reference/graphics/camera2d/index.html +++ b/site/api_reference/graphics/camera2d/index.html @@ -120,4 +120,4 @@ renderer.setDisplayOffset(0, 0); renderer.drawText("Score: 100", 10, 10, Color::White, 1); } -

Performance Considerations

  • Apply frequency: apply() is fast; safe to call every frame
  • Boundary checks: Boundary clamping is efficient
  • Following: Dead-zone calculations are lightweight

ESP32 Considerations

  • Float math: Uses floating point; acceptable but integer math would be faster
  • Memory: Camera is small (few floats); minimal memory usage

See Also

\ No newline at end of file +

Performance Considerations

  • Apply frequency: apply() is fast; safe to call every frame
  • Boundary checks: Boundary clamping is efficient
  • Following: Dead-zone calculations are lightweight

ESP32 Considerations

  • Float math: Uses floating point; acceptable but integer math would be faster
  • Memory: Camera is small (few floats); minimal memory usage

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/color/index.html b/site/api_reference/graphics/color/index.html index e0072e2..b127f79 100644 --- a/site/api_reference/graphics/color/index.html +++ b/site/api_reference/graphics/color/index.html @@ -70,4 +70,4 @@ pixelroot32::graphics::enableDualPaletteMode(true); pixelroot32::graphics::setBackgroundCustomPalette(CUSTOM_PALETTE); pixelroot32::graphics::setSpriteCustomPalette(CUSTOM_PALETTE); -

Performance Considerations

  • Color resolution: Fast lookup operation
  • Palette switching: Changing palettes is fast (just pointer assignment)
  • Memory: Palettes are stored in flash (const arrays) for best performance
  • Dual mode: Slightly more overhead than legacy mode, but minimal

ESP32 Considerations

  • Flash storage: Store custom palettes in flash (const/constexpr)
  • Memory: Palettes are small (16 uint16_t = 32 bytes)
  • Palette switching: Avoid switching palettes every frame

See Also

\ No newline at end of file +

Performance Considerations

  • Color resolution: Fast lookup operation
  • Palette switching: Changing palettes is fast (just pointer assignment)
  • Memory: Palettes are stored in flash (const arrays) for best performance
  • Dual mode: Slightly more overhead than legacy mode, but minimal

ESP32 Considerations

  • Flash storage: Store custom palettes in flash (const/constexpr)
  • Memory: Palettes are small (16 uint16_t = 32 bytes)
  • Palette switching: Avoid switching palettes every frame

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/display_config/index.html b/site/api_reference/graphics/display_config/index.html index 1251e64..1c2a7a9 100644 --- a/site/api_reference/graphics/display_config/index.html +++ b/site/api_reference/graphics/display_config/index.html @@ -96,4 +96,4 @@ -DTFT_WIDTH=240 -DTFT_HEIGHT=240 # ... pin configuration -

Pin Configuration

GPIO pins must be configured separately (not in DisplayConfig):

  • MOSI: Data pin
  • SCLK: Clock pin
  • DC: Data/Command pin
  • RST: Reset pin
  • CS: Chip select pin (optional)

See Also

\ No newline at end of file +

Pin Configuration

GPIO pins must be configured separately (not in DisplayConfig):

  • MOSI: Data pin
  • SCLK: Clock pin
  • DC: Data/Command pin
  • RST: Reset pin
  • CS: Chip select pin (optional)

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/font/index.html b/site/api_reference/graphics/font/index.html index bcc80aa..8536cf0 100644 --- a/site/api_reference/graphics/font/index.html +++ b/site/api_reference/graphics/font/index.html @@ -121,4 +121,4 @@ int getTextHeight(const Font* font) { return font ? font->lineHeight : 8; } -

Performance Considerations

  • Font storage: Store fonts in flash (const/constexpr) for best performance
  • Glyph lookup: Fast array access (character code - firstChar)
  • Fixed width: Fixed-width fonts are faster than variable-width
  • Font switching: Changing fonts is fast (just pointer assignment)

ESP32 Considerations

  • Memory: Store font data in flash, not RAM
  • Font size: Larger fonts use more flash memory
  • Character range: Limit character range to save memory if not needed

See Also

\ No newline at end of file +

Performance Considerations

  • Font storage: Store fonts in flash (const/constexpr) for best performance
  • Glyph lookup: Fast array access (character code - firstChar)
  • Fixed width: Fixed-width fonts are faster than variable-width
  • Font switching: Changing fonts is fast (just pointer assignment)

ESP32 Considerations

  • Memory: Store font data in flash, not RAM
  • Font size: Larger fonts use more flash memory
  • Character range: Limit character range to save memory if not needed

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/renderer/index.html b/site/api_reference/graphics/renderer/index.html index 1de607b..421972e 100644 --- a/site/api_reference/graphics/renderer/index.html +++ b/site/api_reference/graphics/renderer/index.html @@ -91,4 +91,4 @@ renderer.endFrame(); } -

Performance Considerations

  • Integer-only math: All operations use integer arithmetic for ESP32 efficiency
  • Sprite storage: Store sprite data in flash (const/constexpr) for best performance
  • Batch operations: Group similar draw calls together
  • Tilemaps: Dibuja un mapa de tiles completo. Implementa viewport culling automático y caché de paleta para máximo rendimiento.
  • Sprites 2bpp/4bpp: Optimizado para ESP32 (IRAM + acceso de 16 bits).

ESP32 Considerations

  • Memory: Sprite data should be in flash, not RAM
  • Frame rate: Limit draw calls per frame for consistent FPS
  • Display offset: Use for scrolling instead of redrawing everything

See Also

\ No newline at end of file +

Performance Considerations

  • Integer-only math: All operations use integer arithmetic for ESP32 efficiency
  • Sprite storage: Store sprite data in flash (const/constexpr) for best performance
  • Batch operations: Group similar draw calls together
  • Tilemaps: Dibuja un mapa de tiles completo. Implementa viewport culling automático y caché de paleta para máximo rendimiento.
  • Sprites 2bpp/4bpp: Optimizado para ESP32 (IRAM + acceso de 16 bits).

ESP32 Considerations

  • Memory: Sprite data should be in flash, not RAM
  • Frame rate: Limit draw calls per frame for consistent FPS
  • Display offset: Use for scrolling instead of redrawing everything

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/sprite/index.html b/site/api_reference/graphics/sprite/index.html index 47eb8ac..12f5b7a 100644 --- a/site/api_reference/graphics/sprite/index.html +++ b/site/api_reference/graphics/sprite/index.html @@ -153,4 +153,4 @@ // Draw flipped renderer.drawSprite(sprite, 100, 100, Color::White, true); -

Performance Considerations

  • 1bpp sprites: Most efficient (integer-only operations)
  • MultiSprite: Each layer is a separate draw call (still efficient)
  • 2bpp/4bpp: Experimental, uses more memory and CPU
  • Storage: Store sprite data in flash (const/constexpr) for best performance
  • Size limit: Sprites are limited to 16 pixels wide for 1bpp format

ESP32 Considerations

  • Memory: Store sprite data in flash, not RAM
  • Sprite size: Smaller sprites = faster drawing
  • Format choice: Use 1bpp when possible for best performance
  • MultiSprite: More layers = more draw calls (but acceptable)

See Also

\ No newline at end of file +

Performance Considerations

  • 1bpp sprites: Most efficient (integer-only operations)
  • MultiSprite: Each layer is a separate draw call (still efficient)
  • 2bpp/4bpp: Experimental, uses more memory and CPU
  • Storage: Store sprite data in flash (const/constexpr) for best performance
  • Size limit: Sprites are limited to 16 pixels wide for 1bpp format

ESP32 Considerations

  • Memory: Store sprite data in flash, not RAM
  • Sprite size: Smaller sprites = faster drawing
  • Format choice: Use 1bpp when possible for best performance
  • MultiSprite: More layers = more draw calls (but acceptable)

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/tilemap/index.html b/site/api_reference/graphics/tilemap/index.html index 0647253..e19cbe0 100644 --- a/site/api_reference/graphics/tilemap/index.html +++ b/site/api_reference/graphics/tilemap/index.html @@ -182,4 +182,4 @@ return (tile == 1); // Wall tile } }; -

Performance Considerations

  • Viewport culling: Only visible tiles are drawn (automatic)
  • Tile reuse: Reuse tile sprites across the map
  • Index storage: Compact uint8_t indices (1 byte per tile)
  • Memory: Store indices and tiles in flash (const) for best performance
  • Tile size: Smaller tiles = more tiles to draw, but more detail

ESP32 Considerations

  • Memory: Store tilemap data in flash, not RAM
  • Map size: Large maps use more flash memory
  • Tile count: Limit unique tiles to save memory
  • Culling: Viewport culling is essential for large levels

See Also

\ No newline at end of file +

Performance Considerations

  • Viewport culling: Only visible tiles are drawn (automatic)
  • Tile reuse: Reuse tile sprites across the map
  • Index storage: Compact uint8_t indices (1 byte per tile)
  • Memory: Store indices and tiles in flash (const) for best performance
  • Tile size: Smaller tiles = more tiles to draw, but more detail

ESP32 Considerations

  • Memory: Store tilemap data in flash, not RAM
  • Map size: Large maps use more flash memory
  • Tile count: Limit unique tiles to save memory
  • Culling: Viewport culling is essential for large levels

See Also

\ No newline at end of file diff --git a/site/api_reference/physics/collision_system/index.html b/site/api_reference/physics/collision_system/index.html index ffdf9bc..19cc268 100644 --- a/site/api_reference/physics/collision_system/index.html +++ b/site/api_reference/physics/collision_system/index.html @@ -59,4 +59,4 @@ Scene::update(deltaTime); } }; -

Performance Considerations

  • Layer filtering: Very efficient; avoids most collision checks
  • AABB checks: Fast (simple rectangle intersection)
  • Pair checking: O(n²) complexity, but n is limited (MAX_ENTITIES = 32)
  • Update frequency: Called every frame; keep hitboxes simple

ESP32 Considerations

  • Entity limit: MAX_ENTITIES = 32 limits collision pairs
  • Layer efficiency: Use layers effectively to minimize checks
  • Hitbox simplicity: Keep hitboxes as simple AABB for best performance

See Also

\ No newline at end of file +

Performance Considerations

  • Layer filtering: Very efficient; avoids most collision checks
  • AABB checks: Fast (simple rectangle intersection)
  • Pair checking: O(n²) complexity, but n is limited (MAX_ENTITIES = 32)
  • Update frequency: Called every frame; keep hitboxes simple

ESP32 Considerations

  • Entity limit: MAX_ENTITIES = 32 limits collision pairs
  • Layer efficiency: Use layers effectively to minimize checks
  • Hitbox simplicity: Keep hitboxes as simple AABB for best performance

See Also

\ No newline at end of file diff --git a/site/api_reference/physics/collision_types/index.html b/site/api_reference/physics/collision_types/index.html index 7e05fef..73bf43c 100644 --- a/site/api_reference/physics/collision_types/index.html +++ b/site/api_reference/physics/collision_types/index.html @@ -99,4 +99,4 @@ return false; } }; -

Performance Considerations

  • AABB checks: Very fast (simple rectangle intersection)
  • Circle checks: Slightly slower (distance calculation)
  • Sweep tests: More expensive (use only for fast-moving objects)
  • Layer filtering: Essential for performance with many actors

ESP32 Considerations

  • Float math: Uses floating point; acceptable but integer math would be faster
  • Sweep tests: Use sparingly (more CPU intensive)
  • Layer efficiency: Use layers effectively to minimize checks

See Also

\ No newline at end of file +

Performance Considerations

  • AABB checks: Very fast (simple rectangle intersection)
  • Circle checks: Slightly slower (distance calculation)
  • Sweep tests: More expensive (use only for fast-moving objects)
  • Layer filtering: Essential for performance with many actors

ESP32 Considerations

  • Float math: Uses floating point; acceptable but integer math would be faster
  • Sweep tests: Use sparingly (more CPU intensive)
  • Layer efficiency: Use layers effectively to minimize checks

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_button/index.html b/site/api_reference/ui/ui_button/index.html index ae5f75e..c63badf 100644 --- a/site/api_reference/ui/ui_button/index.html +++ b/site/api_reference/ui/ui_button/index.html @@ -131,4 +131,4 @@ // D-pad navigation is automatic // UP/DOWN moves selection // Action button (A) triggers selected button -

Performance Considerations

  • Input handling: handleInput() is fast; safe to call every frame
  • Rendering: Simple rectangle and text; very efficient
  • Memory: Each button consumes memory (stay within MAX_ENTITIES)

ESP32 Considerations

  • String storage: Button labels use std::string; consider memory usage
  • Callback functions: Use function pointers or lambdas (both efficient)

See Also

\ No newline at end of file +

Performance Considerations

  • Input handling: handleInput() is fast; safe to call every frame
  • Rendering: Simple rectangle and text; very efficient
  • Memory: Each button consumes memory (stay within MAX_ENTITIES)

ESP32 Considerations

  • String storage: Button labels use std::string; consider memory usage
  • Callback functions: Use function pointers or lambdas (both efficient)

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_checkbox/index.html b/site/api_reference/ui/ui_checkbox/index.html index 0204b41..53a2688 100644 --- a/site/api_reference/ui/ui_checkbox/index.html +++ b/site/api_reference/ui/ui_checkbox/index.html @@ -26,4 +26,4 @@

Public Methods

void setStyle(Color textCol, Color bgCol, bool drawBg = false)

Configures the checkbox's visual style.

Parameters: - textCol (Color): Color of the text - bgCol (Color): Color of the background - drawBg (bool, optional): Whether to draw the background rectangle. Default: false

Returns: - void

void setChecked(bool checked)

Sets the checked state.

Parameters: - checked (bool): True if checked

Returns: - void

bool isChecked() const

Checks if the checkbox is currently checked.

Returns: - bool: true if checked

void toggle()

Toggles the checkbox state and triggers the callback.

Returns: - void

void setSelected(bool selected)

Sets the selection state (e.g., focused via D-pad).

Parameters: - selected (bool): True if selected

Returns: - void

bool getSelected() const

Checks if the checkbox is currently selected.

Returns: - bool: true if selected

Callbacks

onCheckChanged

The onCheckChanged callback is a std::function<void(bool)> that is triggered whenever the checkbox state changes via setChecked() or toggle().

checkbox->onCheckChanged = [](bool isChecked) {
     Serial.println(isChecked ? "Checked!" : "Unchecked!");
 };
-

UICheckBox is designed to work seamlessly with UILayout containers (like UIVerticalLayout).

  • Focusable: Returns true for isFocusable(), allowing it to receive focus in a layout.
  • Input Handling: When selected (focused), it listens for the button index provided in the constructor (typically the 'A' button) to toggle its state.
  • Visual Feedback: When selected, it displays a selection indicator (usually a > character) if no background is drawn, or highlights its text/border.
\ No newline at end of file +

UICheckBox is designed to work seamlessly with UILayout containers (like UIVerticalLayout).

  • Focusable: Returns true for isFocusable(), allowing it to receive focus in a layout.
  • Input Handling: When selected (focused), it listens for the button index provided in the constructor (typically the 'A' button) to toggle its state.
  • Visual Feedback: When selected, it displays a selection indicator (usually a > character) if no background is drawn, or highlights its text/border.
\ No newline at end of file diff --git a/site/api_reference/ui/ui_element/index.html b/site/api_reference/ui/ui_element/index.html index 7a468eb..48ce646 100644 --- a/site/api_reference/ui/ui_element/index.html +++ b/site/api_reference/ui/ui_element/index.html @@ -72,4 +72,4 @@ h = static_cast<float>(height); } }; -

Performance Considerations

  • Render layer: UI elements are on layer 2, drawn after gameplay
  • Visibility: Use isVisible = false to hide elements efficiently
  • Layout integration: Layouts automatically manage element positioning

ESP32 Considerations

  • Memory: Each UI element consumes memory (stay within MAX_ENTITIES)
  • Object pooling: Reuse UI elements when possible
  • Update frequency: Disable UI elements that don't need to update

See Also

\ No newline at end of file +

Performance Considerations

  • Render layer: UI elements are on layer 2, drawn after gameplay
  • Visibility: Use isVisible = false to hide elements efficiently
  • Layout integration: Layouts automatically manage element positioning

ESP32 Considerations

  • Memory: Each UI element consumes memory (stay within MAX_ENTITIES)
  • Object pooling: Reuse UI elements when possible
  • Update frequency: Disable UI elements that don't need to update

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_label/index.html b/site/api_reference/ui/ui_label/index.html index e93f04f..4d9c273 100644 --- a/site/api_reference/ui/ui_label/index.html +++ b/site/api_reference/ui/ui_label/index.html @@ -96,4 +96,4 @@ ); title->centerX(128); // Center on screen addEntity(title); -

Performance Considerations

  • Text updates: setText() recalculates size; avoid calling every frame if text doesn't change
  • String storage: Uses std::string; consider memory on ESP32
  • Rendering: Simple text drawing; very efficient
  • Static text: For static text, create once and don't update

ESP32 Considerations

  • Memory: std::string uses heap memory; use static buffers when possible
  • Text updates: Limit frequency of text updates
  • String length: Keep text short to save memory

See Also

\ No newline at end of file +

Performance Considerations

  • Text updates: setText() recalculates size; avoid calling every frame if text doesn't change
  • String storage: Uses std::string; consider memory on ESP32
  • Rendering: Simple text drawing; very efficient
  • Static text: For static text, create once and don't update

ESP32 Considerations

  • Memory: std::string uses heap memory; use static buffers when possible
  • Text updates: Limit frequency of text updates
  • String length: Keep text short to save memory

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layout/index.html b/site/api_reference/ui/ui_layout/index.html index 317ef39..8c4e74f 100644 --- a/site/api_reference/ui/ui_layout/index.html +++ b/site/api_reference/ui/ui_layout/index.html @@ -3,4 +3,4 @@ // ... }; } -

Inheritance

  • Inherits from: UIElement
  • Inherited by: UIVerticalLayout, UIHorizontalLayout, UIGridLayout, UIAnchorLayout

ScrollBehavior Enum

Defines how scrolling behaves in layouts.

Values: - ScrollBehavior::NONE: No scrolling allowed - ScrollBehavior::SCROLL: Scroll freely within bounds - ScrollBehavior::CLAMP: Scroll but clamp to content bounds

Public Methods

virtual void addElement(UIElement* element) = 0

Adds a UI element to the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to add

virtual void removeElement(UIElement* element) = 0

Removes a UI element from the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to remove

virtual void updateLayout() = 0

Recalculates positions of all elements in the layout. Must be implemented by derived classes.

Returns: - void

Notes: - Should be called automatically when elements are added/removed

virtual void handleInput(const InputManager& input) = 0

Handles input for layout navigation (scroll, selection, etc.). Must be implemented by derived classes.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

void setPadding(float p)

Sets the padding (internal spacing) of the layout.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Layout is automatically recalculated

float getPadding() const

Gets the current padding.

Returns: - float: Padding value in pixels

void setSpacing(float s)

Sets the spacing between elements.

Parameters: - s (float): Spacing value in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Default: 4.0 pixels

float getSpacing() const

Gets the current spacing.

Returns: - float: Spacing value in pixels

size_t getElementCount() const

Gets the number of elements in the layout.

Returns: - size_t: Element count

UIElement* getElement(size_t index) const

Gets the element at a specific index.

Parameters: - index (size_t): Element index

Returns: - UIElement*: Pointer to the element, or nullptr if index is invalid

void clearElements()

Clears all elements from the layout.

Returns: - void

Notes: - Elements are not deleted (you must manage their lifetimes) - Layout is automatically recalculated

Protected Members

  • std::vector<UIElement*> elements: List of child elements
  • float padding: Internal padding
  • float spacing: Spacing between elements (default: 4.0)
  • float scrollOffset: Current scroll offset
  • bool enableScroll: Whether scrolling is enabled
  • ScrollBehavior scrollBehavior: Scroll behavior mode

See Also

\ No newline at end of file +

Inheritance

  • Inherits from: UIElement
  • Inherited by: UIVerticalLayout, UIHorizontalLayout, UIGridLayout, UIAnchorLayout

ScrollBehavior Enum

Defines how scrolling behaves in layouts.

Values: - ScrollBehavior::NONE: No scrolling allowed - ScrollBehavior::SCROLL: Scroll freely within bounds - ScrollBehavior::CLAMP: Scroll but clamp to content bounds

Public Methods

virtual void addElement(UIElement* element) = 0

Adds a UI element to the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to add

virtual void removeElement(UIElement* element) = 0

Removes a UI element from the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to remove

virtual void updateLayout() = 0

Recalculates positions of all elements in the layout. Must be implemented by derived classes.

Returns: - void

Notes: - Should be called automatically when elements are added/removed

virtual void handleInput(const InputManager& input) = 0

Handles input for layout navigation (scroll, selection, etc.). Must be implemented by derived classes.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

void setPadding(float p)

Sets the padding (internal spacing) of the layout.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Layout is automatically recalculated

float getPadding() const

Gets the current padding.

Returns: - float: Padding value in pixels

void setSpacing(float s)

Sets the spacing between elements.

Parameters: - s (float): Spacing value in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Default: 4.0 pixels

float getSpacing() const

Gets the current spacing.

Returns: - float: Spacing value in pixels

size_t getElementCount() const

Gets the number of elements in the layout.

Returns: - size_t: Element count

UIElement* getElement(size_t index) const

Gets the element at a specific index.

Parameters: - index (size_t): Element index

Returns: - UIElement*: Pointer to the element, or nullptr if index is invalid

void clearElements()

Clears all elements from the layout.

Returns: - void

Notes: - Elements are not deleted (you must manage their lifetimes) - Layout is automatically recalculated

Protected Members

  • std::vector<UIElement*> elements: List of child elements
  • float padding: Internal padding
  • float spacing: Spacing between elements (default: 4.0)
  • float scrollOffset: Current scroll offset
  • bool enableScroll: Whether scrolling is enabled
  • ScrollBehavior scrollBehavior: Scroll behavior mode

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/anchor_layout/index.html b/site/api_reference/ui/ui_layouts/anchor_layout/index.html index 56adc1f..eccc957 100644 --- a/site/api_reference/ui/ui_layouts/anchor_layout/index.html +++ b/site/api_reference/ui/ui_layouts/anchor_layout/index.html @@ -89,4 +89,4 @@ // HUD is drawn automatically (on layer 2) } }; -

Anchor Positioning

Elements are positioned based on their anchor:

  • TOP_LEFT: Element's top-left at screen top-left
  • TOP_RIGHT: Element's top-right at screen top-right
  • BOTTOM_LEFT: Element's bottom-left at screen bottom-left
  • BOTTOM_RIGHT: Element's bottom-right at screen bottom-right
  • CENTER: Element centered on screen
  • TOP_CENTER: Element centered horizontally, top-aligned
  • BOTTOM_CENTER: Element centered horizontally, bottom-aligned
  • LEFT_CENTER: Element centered vertically, left-aligned
  • RIGHT_CENTER: Element centered vertically, right-aligned

Performance Considerations

  • No reflow: Very efficient (positions calculated once)
  • Fixed positions: Ideal for HUD elements
  • Viewport independent: Elements stay in fixed screen positions

ESP32 Considerations

  • Memory: Very efficient (no complex calculations)
  • Update frequency: Positions only recalculate when screen size changes

See Also

\ No newline at end of file +

Anchor Positioning

Elements are positioned based on their anchor:

  • TOP_LEFT: Element's top-left at screen top-left
  • TOP_RIGHT: Element's top-right at screen top-right
  • BOTTOM_LEFT: Element's bottom-left at screen bottom-left
  • BOTTOM_RIGHT: Element's bottom-right at screen bottom-right
  • CENTER: Element centered on screen
  • TOP_CENTER: Element centered horizontally, top-aligned
  • BOTTOM_CENTER: Element centered horizontally, bottom-aligned
  • LEFT_CENTER: Element centered vertically, left-aligned
  • RIGHT_CENTER: Element centered vertically, right-aligned

Performance Considerations

  • No reflow: Very efficient (positions calculated once)
  • Fixed positions: Ideal for HUD elements
  • Viewport independent: Elements stay in fixed screen positions

ESP32 Considerations

  • Memory: Very efficient (no complex calculations)
  • Update frequency: Positions only recalculate when screen size changes

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/grid_layout/index.html b/site/api_reference/ui/ui_layouts/grid_layout/index.html index ae4064c..f4bfa2f 100644 --- a/site/api_reference/ui/ui_layouts/grid_layout/index.html +++ b/site/api_reference/ui/ui_layouts/grid_layout/index.html @@ -39,4 +39,4 @@ addEntity(inventory); } }; -

See Also

\ No newline at end of file +

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/horizontal_layout/index.html b/site/api_reference/ui/ui_layouts/horizontal_layout/index.html index 8962748..a41a63a 100644 --- a/site/api_reference/ui/ui_layouts/horizontal_layout/index.html +++ b/site/api_reference/ui/ui_layouts/horizontal_layout/index.html @@ -35,4 +35,4 @@ addEntity(toolbar); } }; -

See Also

\ No newline at end of file +

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/padding_container/index.html b/site/api_reference/ui/ui_layouts/padding_container/index.html index de8184c..9e7647a 100644 --- a/site/api_reference/ui/ui_layouts/padding_container/index.html +++ b/site/api_reference/ui/ui_layouts/padding_container/index.html @@ -42,4 +42,4 @@ auto* paddedLayout = new UIPaddingContainer(0, 0, 128, 128); paddedLayout->setPadding(10.0f, 10.0f, 20.0f, 20.0f); // Asymmetric paddedLayout->setChild(layout); -

Performance Considerations

  • Rendering: Very efficient (just draws child)
  • Position calculation: Fast (simple addition)
  • Memory: Minimal overhead

ESP32 Considerations

  • Memory: Very lightweight
  • Update frequency: Position only recalculates when padding/position changes

See Also

\ No newline at end of file +

Performance Considerations

  • Rendering: Very efficient (just draws child)
  • Position calculation: Fast (simple addition)
  • Memory: Minimal overhead

ESP32 Considerations

  • Memory: Very lightweight
  • Update frequency: Position only recalculates when padding/position changes

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/panel/index.html b/site/api_reference/ui/ui_layouts/panel/index.html index 522574d..3ae04da 100644 --- a/site/api_reference/ui/ui_layouts/panel/index.html +++ b/site/api_reference/ui/ui_layouts/panel/index.html @@ -64,4 +64,4 @@ addEntity(dialog); } }; -

Performance Considerations

  • Rendering: Simple rectangles; very efficient
  • Child updates: Child element updates are fast
  • Memory: Small overhead (just colors and border width)

ESP32 Considerations

  • Memory: Panel is lightweight
  • Rendering: Two rectangles (background + border); minimal overhead

See Also

\ No newline at end of file +

Performance Considerations

  • Rendering: Simple rectangles; very efficient
  • Child updates: Child element updates are fast
  • Memory: Small overhead (just colors and border width)

ESP32 Considerations

  • Memory: Panel is lightweight
  • Rendering: Two rectangles (background + border); minimal overhead

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/vertical_layout/index.html b/site/api_reference/ui/ui_layouts/vertical_layout/index.html index b235c16..57271c8 100644 --- a/site/api_reference/ui/ui_layouts/vertical_layout/index.html +++ b/site/api_reference/ui/ui_layouts/vertical_layout/index.html @@ -80,4 +80,4 @@ Scene::draw(renderer); // Draws layout and buttons } }; -

The layout handles D-pad navigation automatically:

  • UP button: Moves selection up
  • DOWN button: Moves selection down
  • Action button: Triggers selected button's callback
  • Scrolling: Automatically scrolls to keep selected element visible

Performance Considerations

  • Viewport culling: Only visible elements are drawn
  • Layout recalculation: Fast (simple positioning)
  • Scrolling: Smooth scrolling is efficient

ESP32 Considerations

  • Element count: Stay within MAX_ENTITIES limit
  • Scrolling: Smooth scrolling uses minimal CPU

See Also

\ No newline at end of file +

The layout handles D-pad navigation automatically:

  • UP button: Moves selection up
  • DOWN button: Moves selection down
  • Action button: Triggers selected button's callback
  • Scrolling: Automatically scrolls to keep selected element visible

Performance Considerations

  • Viewport culling: Only visible elements are drawn
  • Layout recalculation: Fast (simple positioning)
  • Scrolling: Smooth scrolling is efficient

ESP32 Considerations

  • Element count: Stay within MAX_ENTITIES limit
  • Scrolling: Smooth scrolling uses minimal CPU

See Also

\ No newline at end of file diff --git a/site/getting_started/fundamental_concepts/index.html b/site/getting_started/fundamental_concepts/index.html index 6f4b5b3..7c6c665 100644 --- a/site/getting_started/fundamental_concepts/index.html +++ b/site/getting_started/fundamental_concepts/index.html @@ -9,4 +9,4 @@ 5. Detect collisions in the scene 6. Draw the scene (draw all visible entities) 7. Repeat -

This cycle runs continuously, typically at 30-60 FPS on ESP32, or faster on PC.

Update

Each frame, all enabled entities receive a call to their update(deltaTime) method. This is where: - Entities move - Animations update - Game logic is processed - User input is read - Sound effects are played

The deltaTime is passed in milliseconds and represents how much time has passed since the last frame. This allows movement to be framerate-independent.

Rendering (Draw)

After updating, all visible entities receive a call to their draw(renderer) method. This is where: - Sprites are drawn - Text is drawn - Primitives are drawn (rectangles, circles, etc.)

The renderer is passed as a parameter so entities can draw themselves.

Cleanup

When you change scenes or end the game: - Entities from the previous scene can be cleaned up - Resources are freed - The new scene is initialized

Conceptual Summary

To summarize, PixelRoot32 works like this:

  1. Engine coordinates everything and runs the game loop
  2. Scene organizes your game into screens/levels
  3. Entity is any object in your game
  4. Actor is an entity that can collide
  5. PhysicsActor is an actor with automatic physics
  6. Renderer draws everything on screen using layers
  7. Each frame updates logic and then draws

All of this works automatically once you configure the Engine and create your scenes and entities. You don't need to worry about game loop details; you just need to implement update() and draw() in your entities.

Next Step

Now that you understand the fundamental concepts, you're ready to create your first project and see these concepts in action with real code.


See also: - What is PixelRoot32? - Why PixelRoot32? - Your First Project - Manual - Scenes and Entities

\ No newline at end of file +

This cycle runs continuously, typically at 30-60 FPS on ESP32, or faster on PC.

Update

Each frame, all enabled entities receive a call to their update(deltaTime) method. This is where: - Entities move - Animations update - Game logic is processed - User input is read - Sound effects are played

The deltaTime is passed in milliseconds and represents how much time has passed since the last frame. This allows movement to be framerate-independent.

Rendering (Draw)

After updating, all visible entities receive a call to their draw(renderer) method. This is where: - Sprites are drawn - Text is drawn - Primitives are drawn (rectangles, circles, etc.)

The renderer is passed as a parameter so entities can draw themselves.

Cleanup

When you change scenes or end the game: - Entities from the previous scene can be cleaned up - Resources are freed - The new scene is initialized

Conceptual Summary

To summarize, PixelRoot32 works like this:

  1. Engine coordinates everything and runs the game loop
  2. Scene organizes your game into screens/levels
  3. Entity is any object in your game
  4. Actor is an entity that can collide
  5. PhysicsActor is an actor with automatic physics
  6. Renderer draws everything on screen using layers
  7. Each frame updates logic and then draws

All of this works automatically once you configure the Engine and create your scenes and entities. You don't need to worry about game loop details; you just need to implement update() and draw() in your entities.

Next Step

Now that you understand the fundamental concepts, you're ready to create your first project and see these concepts in action with real code.


See also: - What is PixelRoot32? - Why PixelRoot32? - Your First Project - Manual - Scenes and Entities

\ No newline at end of file diff --git a/site/getting_started/installation/index.html b/site/getting_started/installation/index.html index 3088e92..45b9ebb 100644 --- a/site/getting_started/installation/index.html +++ b/site/getting_started/installation/index.html @@ -1,3 +1,3 @@ Installation - PixelRoot32 Documentation

Installation

This guide covers installing the PixelRoot32 documentation environment and preparing your development setup for ESP32 and Native (PC) targets.

Requirements

  • Python 3.11 or newer
  • Git (recommended for source management)
  • VS Code (or your preferred IDE)
  • For ESP32 targets: PlatformIO (VS Code extension) with ESP32 toolchain
  • For Native targets: a C++ build toolchain (CMake or your OS-native toolchain)

Install Documentation Tooling

To build and preview this documentation locally:

pip install mkdocs mkdocs-material mkdocs-minify-plugin mkdocs-git-revision-date-localized-plugin mike
 mkdocs serve
-

Open http://127.0.0.1:8000 in your browser to preview.

  1. Install VS Code
  2. Install PlatformIO IDE extension
  3. Install ESP32 platform/toolchain via PlatformIO
  4. Clone the engine repository:
  5. https://github.com/Gperez88/PixelRoot32-Game-Engine
  6. Open the engine or example project in VS Code (PlatformIO)
  7. Build and upload to your ESP32 board

Tip: Use boards based on ESP32-WROOM/WROVER for best compatibility. Ensure a reliable USB cable and correct serial port selection.

Native (PC) Setup

  1. Install a C++ toolchain (e.g., MSVC or MinGW on Windows)
  2. Install CMake (if the engine provides CMake build files)
  3. Clone the engine repository:
  4. https://github.com/Gperez88/PixelRoot32-Game-Engine
  5. Configure and build the native runtime:
  6. Follow the engine’s native build instructions (Development → Compiling)

Verify Your Environment

  • ESP32: Build and flash a minimal sample; confirm serial output and display if applicable
  • Native: Run the executable; confirm window output and input handling

Troubleshooting

  • If PlatformIO cannot find the ESP32 platform, update PlatformIO and retry
  • If native builds fail, verify compiler versions and CMake generator settings
  • Use Community → Troubleshooting for common issues and fixes

Next Steps

\ No newline at end of file +

Open http://127.0.0.1:8000 in your browser to preview.

  1. Install VS Code
  2. Install PlatformIO IDE extension
  3. Install ESP32 platform/toolchain via PlatformIO
  4. Clone the engine repository:
  5. https://github.com/Gperez88/PixelRoot32-Game-Engine
  6. Open the engine or example project in VS Code (PlatformIO)
  7. Build and upload to your ESP32 board

Tip: Use boards based on ESP32-WROOM/WROVER for best compatibility. Ensure a reliable USB cable and correct serial port selection.

Native (PC) Setup

  1. Install a C++ toolchain (e.g., MSVC or MinGW on Windows)
  2. Install CMake (if the engine provides CMake build files)
  3. Clone the engine repository:
  4. https://github.com/Gperez88/PixelRoot32-Game-Engine
  5. Configure and build the native runtime:
  6. Follow the engine’s native build instructions (Development → Compiling)

Verify Your Environment

  • ESP32: Build and flash a minimal sample; confirm serial output and display if applicable
  • Native: Run the executable; confirm window output and input handling

Troubleshooting

  • If PlatformIO cannot find the ESP32 platform, update PlatformIO and retry
  • If native builds fail, verify compiler versions and CMake generator settings
  • Use Community → Troubleshooting for common issues and fixes

Next Steps

\ No newline at end of file diff --git a/site/getting_started/what_is_pixelroot32/index.html b/site/getting_started/what_is_pixelroot32/index.html index 259e538..28600cc 100644 --- a/site/getting_started/what_is_pixelroot32/index.html +++ b/site/getting_started/what_is_pixelroot32/index.html @@ -1 +1 @@ - What is PixelRoot32? - PixelRoot32 Documentation

What is PixelRoot32?

PixelRoot32 is a lightweight, modular 2D game engine written in C++ designed specifically for ESP32 microcontrollers, with a native simulation layer for PC (SDL2) that allows you to develop and debug quickly on your desktop before deploying to hardware.

Simple Definition

PixelRoot32 is a game engine that lets you create retro-style 8-bit/16-bit video games directly on an ESP32 board, with the ability to develop and test on your PC before transferring code to hardware.

Key Features

🎮 Scene-Based Architecture

  • Scene system inspired by Godot Engine
  • Intuitive management of levels, menus, and screens
  • Simple transitions between scenes

🎨 Optimized Rendering

  • 1bpp (monochrome) sprites as the standard format
  • Support for multi-layer sprites (MultiSprite)
  • Experimental 2bpp and 4bpp formats for higher fidelity
  • Retro color palette system (NES, GameBoy, PICO-8, etc.)
  • Compact tilemaps for backgrounds and levels
  • 2D camera with dead-zone for smooth scrolling
  • Render layer system (background, gameplay, UI)

🔊 NES-like Audio

  • 4 audio channels (2 Pulse, 1 Triangle, 1 Noise)
  • Integrated sound effects system
  • Music player for background melodies
  • Backends for ESP32 (internal DAC or external I2S) and SDL2

🎯 Physics and Collisions

  • AABB (Axis-Aligned Bounding Box) collision system
  • PhysicsActor with gravity, friction, and restitution
  • Collision layers and masks for fine control
  • World boundary collision detection

🖥️ User Interface

  • Basic elements: Labels, Buttons, Panels
  • Automatic layouts: Vertical, Horizontal, Grid, Anchor
  • Integrated D-pad navigation
  • Scroll and viewport culling for long lists

⚡ Optimized for ESP32

  • Efficient memory management
  • Integrated object pooling
  • No dynamic allocations in the game loop
  • Performance optimized for limited hardware

Typical Use Cases

PixelRoot32 is ideal for creating:

  • Arcade Games: Space Invaders, Pong, Breakout
  • Platformers: Horizontal scrolling games with simple physics
  • Puzzles: Tetris, Snake, logic games
  • Simple RPGs: Basic role-playing games with tilemaps
  • Shooters: Vertical or horizontal shooting games
  • Rapid Prototypes: Quick development of game ideas

Supported Platforms

ESP32

  • Display: TFT_eSPI (ST7735, ILI9341, ST7789, etc.)
  • Audio: Internal DAC (GPIO 25/26) or external I2S (MAX98357A, PCM5102)
  • Input: Digital buttons, D-pad
  • Hardware: Any ESP32 board (ESP32-WROOM, ESP32-WROVER, etc.)

Desktop/Native (PC)

  • Display: SDL2 (Windows, Linux, macOS)
  • Audio: SDL2 Audio
  • Input: Keyboard, mouse
  • Usage: Development, debugging, testing

Note: Support for u8g2 (OLEDs) is planned for the future.

Project Status

Current Version: v0.2.0-dev

PixelRoot32 is under active development. APIs may change and some subsystems are still experimental. Occasional changes or breaking changes are expected, especially on less-tested configurations.

Stable Features

  • Scene and entity system
  • Basic rendering (1bpp sprites)
  • NES-like audio system
  • Basic physics and collisions
  • Basic UI system
  • ESP32 and Native support

Experimental Features

  • 2bpp and 4bpp sprites (require compilation flags)
  • Scene Arena (advanced memory management)

Planned Features

  • Support for u8g2 (OLEDs)
  • Music compiler
  • Tilemap compiler
  • Save/load system
  • Spatial partitioning for collisions

Quick Comparison

When to use PixelRoot32?

✅ Use PixelRoot32 if: - You want to create retro games on ESP32 - You need a lightweight and efficient engine - You prefer a simple and clear architecture - You want to develop on PC and deploy to ESP32 - You like 8-bit/16-bit style games

❌ Don't use PixelRoot32 if: - You need 3D graphics - You require advanced shaders - You need complex physics (advanced physics engines) - You want to create modern AAA games - You need support for multiple mobile platforms

Next Step

Now that you understand what PixelRoot32 is, discover why you should use it or go directly to your first project.


See also: - Fundamental Concepts - Installation - API Reference

\ No newline at end of file + What is PixelRoot32? - PixelRoot32 Documentation

What is PixelRoot32?

PixelRoot32 is a lightweight, modular 2D game engine written in C++ designed specifically for ESP32 microcontrollers, with a native simulation layer for PC (SDL2) that allows you to develop and debug quickly on your desktop before deploying to hardware.

Simple Definition

PixelRoot32 is a game engine that lets you create retro-style 8-bit/16-bit video games directly on an ESP32 board, with the ability to develop and test on your PC before transferring code to hardware.

Key Features

🎮 Scene-Based Architecture

  • Scene system inspired by Godot Engine
  • Intuitive management of levels, menus, and screens
  • Simple transitions between scenes

🎨 Optimized Rendering

  • 1bpp (monochrome) sprites as the standard format
  • Support for multi-layer sprites (MultiSprite)
  • Experimental 2bpp and 4bpp formats for higher fidelity
  • Retro color palette system (NES, GameBoy, PICO-8, etc.)
  • Compact tilemaps for backgrounds and levels
  • 2D camera with dead-zone for smooth scrolling
  • Render layer system (background, gameplay, UI)

🔊 NES-like Audio

  • 4 audio channels (2 Pulse, 1 Triangle, 1 Noise)
  • Integrated sound effects system
  • Music player for background melodies
  • Backends for ESP32 (internal DAC or external I2S) and SDL2

🎯 Physics and Collisions

  • AABB (Axis-Aligned Bounding Box) collision system
  • PhysicsActor with gravity, friction, and restitution
  • Collision layers and masks for fine control
  • World boundary collision detection

🖥️ User Interface

  • Basic elements: Labels, Buttons, Panels
  • Automatic layouts: Vertical, Horizontal, Grid, Anchor
  • Integrated D-pad navigation
  • Scroll and viewport culling for long lists

⚡ Optimized for ESP32

  • Efficient memory management
  • Integrated object pooling
  • No dynamic allocations in the game loop
  • Performance optimized for limited hardware

Typical Use Cases

PixelRoot32 is ideal for creating:

  • Arcade Games: Space Invaders, Pong, Breakout
  • Platformers: Horizontal scrolling games with simple physics
  • Puzzles: Tetris, Snake, logic games
  • Simple RPGs: Basic role-playing games with tilemaps
  • Shooters: Vertical or horizontal shooting games
  • Rapid Prototypes: Quick development of game ideas

Supported Platforms

ESP32

  • Display: TFT_eSPI (ST7735, ILI9341, ST7789, etc.)
  • Audio: Internal DAC (GPIO 25/26) or external I2S (MAX98357A, PCM5102)
  • Input: Digital buttons, D-pad
  • Hardware: Any ESP32 board (ESP32-WROOM, ESP32-WROVER, etc.)

Desktop/Native (PC)

  • Display: SDL2 (Windows, Linux, macOS)
  • Audio: SDL2 Audio
  • Input: Keyboard, mouse
  • Usage: Development, debugging, testing

Note: Support for u8g2 (OLEDs) is planned for the future.

Project Status

Current Version: v0.2.0-dev

PixelRoot32 is under active development. APIs may change and some subsystems are still experimental. Occasional changes or breaking changes are expected, especially on less-tested configurations.

Stable Features

  • Scene and entity system
  • Basic rendering (1bpp sprites)
  • NES-like audio system
  • Basic physics and collisions
  • Basic UI system
  • ESP32 and Native support

Experimental Features

  • 2bpp and 4bpp sprites (require compilation flags)
  • Scene Arena (advanced memory management)

Planned Features

  • Support for u8g2 (OLEDs)
  • Music compiler
  • Tilemap compiler
  • Save/load system
  • Spatial partitioning for collisions

Quick Comparison

When to use PixelRoot32?

✅ Use PixelRoot32 if: - You want to create retro games on ESP32 - You need a lightweight and efficient engine - You prefer a simple and clear architecture - You want to develop on PC and deploy to ESP32 - You like 8-bit/16-bit style games

❌ Don't use PixelRoot32 if: - You need 3D graphics - You require advanced shaders - You need complex physics (advanced physics engines) - You want to create modern AAA games - You need support for multiple mobile platforms

Next Step

Now that you understand what PixelRoot32 is, discover why you should use it or go directly to your first project.


See also: - Fundamental Concepts - Installation - API Reference

\ No newline at end of file diff --git a/site/getting_started/why_pixelroot32/index.html b/site/getting_started/why_pixelroot32/index.html index ad5444a..8f8f640 100644 --- a/site/getting_started/why_pixelroot32/index.html +++ b/site/getting_started/why_pixelroot32/index.html @@ -1 +1 @@ - Why PixelRoot32? - PixelRoot32 Documentation

Why PixelRoot32?

PixelRoot32 is specifically designed to solve the unique challenges of creating video games on embedded hardware like the ESP32, while maintaining the simplicity and productivity of modern development.

Main Advantages

🎯 Optimized for ESP32

Memory Efficient - 1bpp sprite system that minimizes RAM and Flash usage - Integrated object pooling to avoid memory fragmentation - Compact tilemaps that reuse sprites - No dynamic allocations in the game loop

Performance Optimized - Rendering optimized for ESP32 limitations - Efficient render layer system - Viewport culling to reduce draw calls - Rendering pipeline designed for limited hardware

Real Hardware - Direct support for common TFT displays (ST7735, ILI9341, ST7789) - Integrated audio (internal DAC or external I2S) - Simple pin and hardware configuration

🖥️ Cross-Platform Development

Develop on PC, Deploy to ESP32 - Same code works on PC (SDL2) and ESP32 - Fast debugging on desktop - Testing without hardware needed - Rapid development iteration

Visual Consistency - Native bitmap font system (pixel-perfect) - Same rendering on PC and ESP32 - Consistent color palettes - No surprises when transferring to hardware

🎨 Retro Palette System

Authentic Style - Predefined palettes: NES, GameBoy, GameBoy Color, PICO-8 - Dual palette mode for visual contrasts - Custom palettes for unique styles - Automatic color resolution (RGB565)

Easy to Use - Change palette with one line of code - Consistent visualization across all sprites - No need to manually convert assets

🔊 Integrated Audio

Complete NES-like System - 4 audio channels (2 Pulse, 1 Triangle, 1 Noise) - Simple sound effects to create - Integrated music system - Backends for different hardware configurations

No External Dependencies - Software-generated audio - No heavy audio libraries required - Full control over sound - Deterministic and predictable

🏗️ Simple and Clear Architecture

Easy to Understand - Intuitive scene system (inspired by Godot) - Clear hierarchy: Entity → Actor → PhysicsActor - Consistent and predictable APIs - Clean and well-organized code

Quick to Learn - Familiar concepts for game developers - Clear documentation and complete examples - Smooth learning curve - Active community and support

🎮 Complete Features

Everything Needed for Games - Rendering (sprites, tilemaps, primitives) - Audio (effects and music) - Physics (gravity, collisions, basic physics) - UI (layouts, buttons, navigation) - Input (buttons, keyboard) - Camera (scroll, parallax)

No Bloat - Only the essentials, nothing more - No heavy dependencies - Small and maintainable codebase - Easy to understand and modify

🛠️ Tools and Ecosystem

Available Tools - Sprite Compiler to convert PNG to sprites - Complete game examples - Templates and starter code - Extensive documentation

Community and Support - Active and developing project - Open source (MIT License) - Feedback and contributions welcome - Examples available

Comparison with Alternatives

vs. Full Engines (Unity, Godot, etc.)

PixelRoot32 Advantages: - ✅ Much lighter (fits in ESP32) - ✅ No unnecessary overhead - ✅ Full control over code - ✅ Specifically optimized for limited hardware

Disadvantages: - ❌ Fewer advanced features - ❌ No visual editor - ❌ Fewer resources and community

vs. Writing Everything from Scratch

PixelRoot32 Advantages: - ✅ Rendering system already implemented - ✅ Integrated and working audio - ✅ Physics and collisions ready - ✅ Complete UI system - ✅ Saves months of development

Disadvantages: - ❌ Less control over internal implementation - ❌ You must learn the engine API

vs. Other ESP32 Engines

PixelRoot32 Advantages: - ✅ More modern and clear architecture - ✅ Better documentation - ✅ Unique palette system - ✅ Integrated NES-like audio - ✅ Real cross-platform development

Ideal Use Cases

PixelRoot32 is perfect for:

  1. Educational Projects
  2. Learn game development
  3. Understand engine architecture
  4. Student projects

  5. Rapid Prototypes

  6. Quickly validate game ideas
  7. Create demos and proof-of-concepts
  8. Test mechanics

  9. Retro Games

  10. 8-bit/16-bit style games
  11. Arcade games
  12. Games with retro aesthetics

  13. Hardware Projects

  14. Games on small displays
  15. DIY portable consoles
  16. Maker/retro projects

  17. C++ Learning

  18. Clean and well-structured code
  19. Good programming practices
  20. Real and functional examples

Limitations to Consider

To be honest, PixelRoot32 has limitations:

  • Limited Hardware: Designed for ESP32, not powerful PCs
  • Simple Graphics: No 3D, no advanced shaders
  • Basic Physics: Not a complete physics engine
  • Restricted Memory: MAX_ENTITIES = 32 per scene
  • In Development: Some features are experimental

If you need advanced features or powerful hardware, consider other engines. But for retro games on ESP32, PixelRoot32 is an excellent choice.

Conclusion

PixelRoot32 combines:

  • Simplicity of use
  • Efficiency for limited hardware
  • Completeness of essential features
  • Clarity of architecture
  • Productivity in development

If you want to create retro games on ESP32 without the complexity of large engines, PixelRoot32 is the right choice.

Next Step

Now that you understand why PixelRoot32 is a good option, learn the fundamental concepts or start directly with your first project.


See also: - What is PixelRoot32? - Fundamental Concepts - Your First Project

\ No newline at end of file + Why PixelRoot32? - PixelRoot32 Documentation

Why PixelRoot32?

PixelRoot32 is specifically designed to solve the unique challenges of creating video games on embedded hardware like the ESP32, while maintaining the simplicity and productivity of modern development.

Main Advantages

🎯 Optimized for ESP32

Memory Efficient - 1bpp sprite system that minimizes RAM and Flash usage - Integrated object pooling to avoid memory fragmentation - Compact tilemaps that reuse sprites - No dynamic allocations in the game loop

Performance Optimized - Rendering optimized for ESP32 limitations - Efficient render layer system - Viewport culling to reduce draw calls - Rendering pipeline designed for limited hardware

Real Hardware - Direct support for common TFT displays (ST7735, ILI9341, ST7789) - Integrated audio (internal DAC or external I2S) - Simple pin and hardware configuration

🖥️ Cross-Platform Development

Develop on PC, Deploy to ESP32 - Same code works on PC (SDL2) and ESP32 - Fast debugging on desktop - Testing without hardware needed - Rapid development iteration

Visual Consistency - Native bitmap font system (pixel-perfect) - Same rendering on PC and ESP32 - Consistent color palettes - No surprises when transferring to hardware

🎨 Retro Palette System

Authentic Style - Predefined palettes: NES, GameBoy, GameBoy Color, PICO-8 - Dual palette mode for visual contrasts - Custom palettes for unique styles - Automatic color resolution (RGB565)

Easy to Use - Change palette with one line of code - Consistent visualization across all sprites - No need to manually convert assets

🔊 Integrated Audio

Complete NES-like System - 4 audio channels (2 Pulse, 1 Triangle, 1 Noise) - Simple sound effects to create - Integrated music system - Backends for different hardware configurations

No External Dependencies - Software-generated audio - No heavy audio libraries required - Full control over sound - Deterministic and predictable

🏗️ Simple and Clear Architecture

Easy to Understand - Intuitive scene system (inspired by Godot) - Clear hierarchy: Entity → Actor → PhysicsActor - Consistent and predictable APIs - Clean and well-organized code

Quick to Learn - Familiar concepts for game developers - Clear documentation and complete examples - Smooth learning curve - Active community and support

🎮 Complete Features

Everything Needed for Games - Rendering (sprites, tilemaps, primitives) - Audio (effects and music) - Physics (gravity, collisions, basic physics) - UI (layouts, buttons, navigation) - Input (buttons, keyboard) - Camera (scroll, parallax)

No Bloat - Only the essentials, nothing more - No heavy dependencies - Small and maintainable codebase - Easy to understand and modify

🛠️ Tools and Ecosystem

Available Tools - Sprite Compiler to convert PNG to sprites - Complete game examples - Templates and starter code - Extensive documentation

Community and Support - Active and developing project - Open source (MIT License) - Feedback and contributions welcome - Examples available

Comparison with Alternatives

vs. Full Engines (Unity, Godot, etc.)

PixelRoot32 Advantages: - ✅ Much lighter (fits in ESP32) - ✅ No unnecessary overhead - ✅ Full control over code - ✅ Specifically optimized for limited hardware

Disadvantages: - ❌ Fewer advanced features - ❌ No visual editor - ❌ Fewer resources and community

vs. Writing Everything from Scratch

PixelRoot32 Advantages: - ✅ Rendering system already implemented - ✅ Integrated and working audio - ✅ Physics and collisions ready - ✅ Complete UI system - ✅ Saves months of development

Disadvantages: - ❌ Less control over internal implementation - ❌ You must learn the engine API

vs. Other ESP32 Engines

PixelRoot32 Advantages: - ✅ More modern and clear architecture - ✅ Better documentation - ✅ Unique palette system - ✅ Integrated NES-like audio - ✅ Real cross-platform development

Ideal Use Cases

PixelRoot32 is perfect for:

  1. Educational Projects
  2. Learn game development
  3. Understand engine architecture
  4. Student projects

  5. Rapid Prototypes

  6. Quickly validate game ideas
  7. Create demos and proof-of-concepts
  8. Test mechanics

  9. Retro Games

  10. 8-bit/16-bit style games
  11. Arcade games
  12. Games with retro aesthetics

  13. Hardware Projects

  14. Games on small displays
  15. DIY portable consoles
  16. Maker/retro projects

  17. C++ Learning

  18. Clean and well-structured code
  19. Good programming practices
  20. Real and functional examples

Limitations to Consider

To be honest, PixelRoot32 has limitations:

  • Limited Hardware: Designed for ESP32, not powerful PCs
  • Simple Graphics: No 3D, no advanced shaders
  • Basic Physics: Not a complete physics engine
  • Restricted Memory: MAX_ENTITIES = 32 per scene
  • In Development: Some features are experimental

If you need advanced features or powerful hardware, consider other engines. But for retro games on ESP32, PixelRoot32 is an excellent choice.

Conclusion

PixelRoot32 combines:

  • Simplicity of use
  • Efficiency for limited hardware
  • Completeness of essential features
  • Clarity of architecture
  • Productivity in development

If you want to create retro games on ESP32 without the complexity of large engines, PixelRoot32 is the right choice.

Next Step

Now that you understand why PixelRoot32 is a good option, learn the fundamental concepts or start directly with your first project.


See also: - What is PixelRoot32? - Fundamental Concepts - Your First Project

\ No newline at end of file diff --git a/site/getting_started/your_first_project/index.html b/site/getting_started/your_first_project/index.html index 0f8e497..a623e5f 100644 --- a/site/getting_started/your_first_project/index.html +++ b/site/getting_started/your_first_project/index.html @@ -227,4 +227,4 @@ -std=c++17 -lSDL2 -mconsole -

Note: Adjust the SDL2 include and library paths for your system.

Step 7: Build and Run

For ESP32

  1. Connect your ESP32 via USB
  2. Select the environment: Click on the PlatformIO icon → Select env:esp32dev
  3. Build: Click the checkmark icon (✓) or press Ctrl+Alt+B
  4. Upload: Click the arrow icon (→) or press Ctrl+Alt+U
  5. Monitor: Click the plug icon to open serial monitor

You should see "PixelRoot32 initialized!" in the serial monitor and your display should show a blue rectangle and text.

For Native (PC)

  1. Select the environment: Click on the PlatformIO icon → Select env:native
  2. Build and Run: Click the play icon (▶) or press Ctrl+Alt+R

A window should open showing your scene with a blue rectangle and "Hello PixelRoot32!" text.

Step 8: Verify It Works

If everything is set up correctly, you should see:

  • ESP32: Display shows a blue rectangle at (50, 50) and white text "Hello PixelRoot32!" at (20, 20)
  • Native: Window shows the same content

If you see this, congratulations! Your first PixelRoot32 project is working.

Troubleshooting

ESP32 Issues

Display is blank: - Check wiring connections - Verify pin numbers in platformio.ini match your hardware - Check SPI frequency (try lowering it) - Verify display type (ST7789 vs ST7735)

Compilation errors: - Ensure library version is exactly 0.2.0-dev - Check that TFT_eSPI is installed - Verify all include paths are correct

Upload fails: - Check USB cable connection - Try different USB port - Press BOOT button on ESP32 during upload - Check COM port in PlatformIO

Native Issues

SDL2 not found: - Verify SDL2 is installed - Check include/library paths in platformio.ini - On Windows, ensure MSYS2 paths are correct

Window doesn't open: - Check console for error messages - Verify SDL2 is properly linked - Try running from terminal to see errors

Next Steps

Now that you have a working project, you can:

  1. Learn about Scenes and Entities: See how to create game objects
  2. Add Input: Make your scene respond to buttons
  3. Add Sprites: Draw custom graphics
  4. Add Audio: Play sounds and music

Continue with the Development Guide to learn more.


See also: - Fundamental Concepts - Installation - Manual - Scenes and Entities - API Reference

\ No newline at end of file +

Note: Adjust the SDL2 include and library paths for your system.

Step 7: Build and Run

For ESP32

  1. Connect your ESP32 via USB
  2. Select the environment: Click on the PlatformIO icon → Select env:esp32dev
  3. Build: Click the checkmark icon (✓) or press Ctrl+Alt+B
  4. Upload: Click the arrow icon (→) or press Ctrl+Alt+U
  5. Monitor: Click the plug icon to open serial monitor

You should see "PixelRoot32 initialized!" in the serial monitor and your display should show a blue rectangle and text.

For Native (PC)

  1. Select the environment: Click on the PlatformIO icon → Select env:native
  2. Build and Run: Click the play icon (▶) or press Ctrl+Alt+R

A window should open showing your scene with a blue rectangle and "Hello PixelRoot32!" text.

Step 8: Verify It Works

If everything is set up correctly, you should see:

  • ESP32: Display shows a blue rectangle at (50, 50) and white text "Hello PixelRoot32!" at (20, 20)
  • Native: Window shows the same content

If you see this, congratulations! Your first PixelRoot32 project is working.

Troubleshooting

ESP32 Issues

Display is blank: - Check wiring connections - Verify pin numbers in platformio.ini match your hardware - Check SPI frequency (try lowering it) - Verify display type (ST7789 vs ST7735)

Compilation errors: - Ensure library version is exactly 0.2.0-dev - Check that TFT_eSPI is installed - Verify all include paths are correct

Upload fails: - Check USB cable connection - Try different USB port - Press BOOT button on ESP32 during upload - Check COM port in PlatformIO

Native Issues

SDL2 not found: - Verify SDL2 is installed - Check include/library paths in platformio.ini - On Windows, ensure MSYS2 paths are correct

Window doesn't open: - Check console for error messages - Verify SDL2 is properly linked - Try running from terminal to see errors

Next Steps

Now that you have a working project, you can:

  1. Learn about Scenes and Entities: See how to create game objects
  2. Add Input: Make your scene respond to buttons
  3. Add Sprites: Draw custom graphics
  4. Add Audio: Play sounds and music

Continue with the Development Guide to learn more.


See also: - Fundamental Concepts - Installation - Manual - Scenes and Entities - API Reference

\ No newline at end of file diff --git a/site/index.html b/site/index.html index 2ed7ede..6bfb671 100644 --- a/site/index.html +++ b/site/index.html @@ -1 +1 @@ - PixelRoot32 Documentation

PixelRoot32 Documentation

PixelRoot32 is a lightweight 2D game engine designed for ESP32 and native desktop targets. This site provides official, versioned documentation with clear guides, conceptual explanations, API references, and complete examples to help you build games efficiently.

Getting Started

New to PixelRoot32? Follow this learning path:

  1. What is PixelRoot32? - Understand what the engine is and what it can do
  2. Why PixelRoot32? - Learn the advantages and use cases
  3. Fundamental Concepts - Learn the core architecture concepts
  4. Your First Project - Create and run your first project

About This Documentation

  • Professional technical English across all pages
  • Search-enabled, mobile-friendly UI
  • Versioned with mike (stable/dev/experimental)
  • Cross-linked concepts, API, and examples
  • Progressive learning path from basics to advanced topics
\ No newline at end of file + PixelRoot32 Documentation

PixelRoot32 Documentation

PixelRoot32 is a lightweight 2D game engine designed for ESP32 and native desktop targets. This site provides official, versioned documentation with clear guides, conceptual explanations, API references, and complete examples to help you build games efficiently.

Getting Started

New to PixelRoot32? Follow this learning path:

  1. What is PixelRoot32? - Understand what the engine is and what it can do
  2. Why PixelRoot32? - Learn the advantages and use cases
  3. Fundamental Concepts - Learn the core architecture concepts
  4. Your First Project - Create and run your first project

About This Documentation

  • Professional technical English across all pages
  • Search-enabled, mobile-friendly UI
  • Versioned with mike (stable/dev/experimental)
  • Cross-linked concepts, API, and examples
  • Progressive learning path from basics to advanced topics
\ No newline at end of file diff --git a/site/manual/advanced_graphics/cameras_and_scrolling/index.html b/site/manual/advanced_graphics/cameras_and_scrolling/index.html index 8250e13..80bb8af 100644 --- a/site/manual/advanced_graphics/cameras_and_scrolling/index.html +++ b/site/manual/advanced_graphics/cameras_and_scrolling/index.html @@ -316,4 +316,4 @@ y + height < cameraY || y > cameraY + screenHeight); } -

Troubleshooting

Camera Not Moving

  • Verify camera.apply() is called in draw()
  • Check followTarget() or setPosition() is called in update()
  • Ensure camera is created with correct viewport size
  • Check boundaries aren't preventing movement

Objects Not Visible

  • Verify objects are within camera view
  • Check world coordinates vs screen coordinates
  • Ensure camera is applied before drawing
  • Verify render layers are correct

Parallax Not Working

  • Check setDisplayOffset() is used correctly
  • Verify parallax speed values (0.0 to 1.0)
  • Ensure offset is reset after parallax layers
  • Test with different speed values

Next Steps

Now that you understand cameras and scrolling, learn about: - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects - Performance Optimization - Optimize your game


See also: - API Reference - Camera2D - Manual - Basic Rendering - Manual - Tilemaps

\ No newline at end of file +

Troubleshooting

Camera Not Moving

  • Verify camera.apply() is called in draw()
  • Check followTarget() or setPosition() is called in update()
  • Ensure camera is created with correct viewport size
  • Check boundaries aren't preventing movement

Objects Not Visible

  • Verify objects are within camera view
  • Check world coordinates vs screen coordinates
  • Ensure camera is applied before drawing
  • Verify render layers are correct

Parallax Not Working

  • Check setDisplayOffset() is used correctly
  • Verify parallax speed values (0.0 to 1.0)
  • Ensure offset is reset after parallax layers
  • Test with different speed values

Next Steps

Now that you understand cameras and scrolling, learn about: - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects - Performance Optimization - Optimize your game


See also: - API Reference - Camera2D - Manual - Basic Rendering - Manual - Tilemaps

\ No newline at end of file diff --git a/site/manual/advanced_graphics/color_palettes/index.html b/site/manual/advanced_graphics/color_palettes/index.html index 29bad25..0b927f2 100644 --- a/site/manual/advanced_graphics/color_palettes/index.html +++ b/site/manual/advanced_graphics/color_palettes/index.html @@ -204,4 +204,4 @@ Color::White }; } -

Troubleshooting

Colors Not Changing

  • Verify setPalette() is called before drawing
  • Check palette is set in init(), not update()
  • Ensure dual palette mode is enabled if using separate palettes
  • Verify Color constants are from correct namespace

Colors Look Wrong on Hardware

  • ESP32 displays may render colors differently
  • Test on actual hardware, not just PC
  • Adjust palette colors if needed
  • Consider display calibration

Dual Palette Not Working

  • Ensure enableDualPaletteMode() is called first
  • Verify both palettes are set
  • Check that you're drawing in correct context
  • Review renderer documentation

Next Steps

Now that you understand palettes, learn about: - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects


See also: - API Reference - PaletteDefs - API Reference - Color - Manual - Basic Rendering

\ No newline at end of file +

Troubleshooting

Colors Not Changing

  • Verify setPalette() is called before drawing
  • Check palette is set in init(), not update()
  • Ensure dual palette mode is enabled if using separate palettes
  • Verify Color constants are from correct namespace

Colors Look Wrong on Hardware

  • ESP32 displays may render colors differently
  • Test on actual hardware, not just PC
  • Adjust palette colors if needed
  • Consider display calibration

Dual Palette Not Working

  • Ensure enableDualPaletteMode() is called first
  • Verify both palettes are set
  • Check that you're drawing in correct context
  • Review renderer documentation

Next Steps

Now that you understand palettes, learn about: - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects


See also: - API Reference - PaletteDefs - API Reference - Color - Manual - Basic Rendering

\ No newline at end of file diff --git a/site/manual/advanced_graphics/particles_and_effects/index.html b/site/manual/advanced_graphics/particles_and_effects/index.html index d59882b..81eafd2 100644 --- a/site/manual/advanced_graphics/particles_and_effects/index.html +++ b/site/manual/advanced_graphics/particles_and_effects/index.html @@ -287,4 +287,4 @@ emitter->update(deltaTime); } }; -

Troubleshooting

Particles Not Appearing

  • Verify emitter is added to scene
  • Check particle config is valid
  • Ensure burst() is being called
  • Verify emitter position is on-screen

Performance Issues

  • Reduce particle count per burst
  • Limit number of active emitters
  • Use simpler particle configs
  • Disable emitters when not visible

Particles Not Moving

  • Check gravity value (positive = down, negative = up)
  • Verify speed is not 0
  • Check friction isn't too high (1.0 = no movement)
  • Ensure direction is correct (degrees: 0=right, 90=up, 180=left, 270=down)

Next Steps

Now that you understand particles, you've completed the advanced graphics section. Continue with: - Performance Optimization - Optimize your game - Memory Management - Manage memory efficiently - API Reference - Complete API documentation


See also: - API Reference - ParticleEmitter - API Reference - ParticleConfig - API Reference - ParticlePresets - Manual - Basic Rendering

\ No newline at end of file +

Troubleshooting

Particles Not Appearing

  • Verify emitter is added to scene
  • Check particle config is valid
  • Ensure burst() is being called
  • Verify emitter position is on-screen

Performance Issues

  • Reduce particle count per burst
  • Limit number of active emitters
  • Use simpler particle configs
  • Disable emitters when not visible

Particles Not Moving

  • Check gravity value (positive = down, negative = up)
  • Verify speed is not 0
  • Check friction isn't too high (1.0 = no movement)
  • Ensure direction is correct (degrees: 0=right, 90=up, 180=left, 270=down)

Next Steps

Now that you understand particles, you've completed the advanced graphics section. Continue with: - Performance Optimization - Optimize your game - Memory Management - Manage memory efficiently - API Reference - Complete API documentation


See also: - API Reference - ParticleEmitter - API Reference - ParticleConfig - API Reference - ParticlePresets - Manual - Basic Rendering

\ No newline at end of file diff --git a/site/manual/advanced_graphics/resolution_scaling/index.html b/site/manual/advanced_graphics/resolution_scaling/index.html index 96c71c6..9fbcbd0 100644 --- a/site/manual/advanced_graphics/resolution_scaling/index.html +++ b/site/manual/advanced_graphics/resolution_scaling/index.html @@ -25,4 +25,4 @@ 160, 160 // Logical Width, Logical Height );

Performance Impact

The following table shows estimated savings on an ESP32 for a standard 240x240 display:

Logical Resolution Memory (8bpp) RAM Savings FPS Gain (est.)
240x240 (Full) 57.6 KB 0% Baseline
160x160 25.6 KB ~55% +30%
128x128 16.4 KB ~72% +60%
96x96 9.2 KB ~84% +100%

Implementation Details

Nearest Neighbor Scaling

The engine uses a Nearest Neighbor algorithm optimized for ESP32. It avoids floating-point math by using pre-calculated Lookup Tables (LUTs).

On-the-fly Scaling

To save even more RAM, the engine does not maintain a physical-sized buffer. Instead, it scales the image line-by-line during the SPI DMA transfer. This means the only large buffer in memory is the small logical one.

Profiling

You can measure the performance of the scaling system by enabling the Debug Statistics Overlay. This provides real-time data on FPS, CPU load, and RAM usage directly on the screen.

See Engine - Debug Overlay for instructions on how to enable it.

Alternatively, you can enable low-level profiling in EngineConfig.h:

#define PIXELROOT32_ENABLE_PROFILING
-

This will output the time taken for scaling and transfer to the Serial monitor: [PROFILING] Scaled Transfer: 12450 us (80 FPS max)

Best Practices

  1. Aspect Ratio: Keep the logical aspect ratio the same as the physical one to avoid stretching.
  2. Integer Multiples: For the sharpest results, try to use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen).
  3. UI Positioning: Use UIAnchorLayout to ensure your UI elements stay correctly positioned regardless of the logical resolution chosen.
\ No newline at end of file +

This will output the time taken for scaling and transfer to the Serial monitor: [PROFILING] Scaled Transfer: 12450 us (80 FPS max)

Best Practices

  1. Aspect Ratio: Keep the logical aspect ratio the same as the physical one to avoid stretching.
  2. Integer Multiples: For the sharpest results, try to use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen).
  3. UI Positioning: Use UIAnchorLayout to ensure your UI elements stay correctly positioned regardless of the logical resolution chosen.
\ No newline at end of file diff --git a/site/manual/advanced_graphics/sprites_and_animation/index.html b/site/manual/advanced_graphics/sprites_and_animation/index.html index c67e88b..af4a58d 100644 --- a/site/manual/advanced_graphics/sprites_and_animation/index.html +++ b/site/manual/advanced_graphics/sprites_and_animation/index.html @@ -350,4 +350,4 @@ return nullptr; } }; -

Troubleshooting

Sprites Not Displaying

  • Check sprite data is valid
  • Verify width/height match data
  • Ensure sprite is within screen bounds
  • Check render layer is correct

Animation Not Playing

  • Verify animation frames are set
  • Check step() is being called
  • Ensure timer logic is correct
  • Verify frame count matches array size

Memory Issues

  • Reduce sprite count
  • Use 1bpp instead of 2bpp/4bpp
  • Reuse sprites more
  • Check available flash memory

Next Steps

Now that you understand sprites and animation, learn about: - Color Palettes - Use different color schemes - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles


See also: - API Reference - Sprite - API Reference - SpriteAnimation - Manual - Basic Rendering

\ No newline at end of file +

Troubleshooting

Sprites Not Displaying

  • Check sprite data is valid
  • Verify width/height match data
  • Ensure sprite is within screen bounds
  • Check render layer is correct

Animation Not Playing

  • Verify animation frames are set
  • Check step() is being called
  • Ensure timer logic is correct
  • Verify frame count matches array size

Memory Issues

  • Reduce sprite count
  • Use 1bpp instead of 2bpp/4bpp
  • Reuse sprites more
  • Check available flash memory

Next Steps

Now that you understand sprites and animation, learn about: - Color Palettes - Use different color schemes - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles


See also: - API Reference - Sprite - API Reference - SpriteAnimation - Manual - Basic Rendering

\ No newline at end of file diff --git a/site/manual/advanced_graphics/tilemaps/index.html b/site/manual/advanced_graphics/tilemaps/index.html index 68c37bb..af0f26b 100644 --- a/site/manual/advanced_graphics/tilemaps/index.html +++ b/site/manual/advanced_graphics/tilemaps/index.html @@ -297,4 +297,4 @@ return false; // No collision } -

Troubleshooting

Tiles Not Appearing

  • Verify tile indices are correct (0 = first tile, 1 = second, etc.)
  • Check tilemap dimensions match indices array size
  • Ensure tiles array has enough entries
  • Verify tile size matches sprite size

Performance Issues

  • Reduce tilemap size
  • Use smaller tiles
  • Limit number of unique tiles
  • Test viewport culling

Scrolling Problems

  • Ensure camera is applied before drawing tilemap
  • Check tilemap position matches camera offset
  • Verify tilemap boundaries are correct
  • Test with simple tilemap first

Next Steps

Now that you understand tilemaps, learn about: - Particles and Effects - Add visual effects - Cameras and Scrolling - Combine with scrolling - Performance Optimization - Optimize rendering


See also: - API Reference - TileMap - API Reference - Renderer - Manual - Cameras and Scrolling

\ No newline at end of file +

Troubleshooting

Tiles Not Appearing

  • Verify tile indices are correct (0 = first tile, 1 = second, etc.)
  • Check tilemap dimensions match indices array size
  • Ensure tiles array has enough entries
  • Verify tile size matches sprite size

Performance Issues

  • Reduce tilemap size
  • Use smaller tiles
  • Limit number of unique tiles
  • Test viewport culling

Scrolling Problems

  • Ensure camera is applied before drawing tilemap
  • Check tilemap position matches camera offset
  • Verify tilemap boundaries are correct
  • Test with simple tilemap first

Next Steps

Now that you understand tilemaps, learn about: - Particles and Effects - Add visual effects - Cameras and Scrolling - Combine with scrolling - Performance Optimization - Optimize rendering


See also: - API Reference - TileMap - API Reference - Renderer - Manual - Cameras and Scrolling

\ No newline at end of file diff --git a/site/manual/game_development/audio/index.html b/site/manual/game_development/audio/index.html index 3e5fcd8..fc51ec2 100644 --- a/site/manual/game_development/audio/index.html +++ b/site/manual/game_development/audio/index.html @@ -234,4 +234,4 @@ Scene::update(deltaTime); } }; -

Troubleshooting

No Sound

  • Check audio backend is configured correctly
  • Verify sample rate matches backend
  • Check master volume is not 0
  • Ensure audio is initialized (engine.init())

Distorted Sound

  • Lower volume levels
  • Reduce sample rate (ESP32 DAC works better at 11025 Hz)
  • Check for too many simultaneous sounds
  • Verify hardware connections (ESP32)

Music Not Playing

  • Check music.isPlaying() status
  • Ensure track is properly defined
  • Verify MusicPlayer is updated (happens automatically)
  • Check that music channel is not being used by SFX

Next Steps

Now that you can add audio, learn about: - NES Audio Reference - Advanced audio techniques - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs


See also: - API Reference - AudioEngine - API Reference - MusicPlayer - API Reference - Audio Types - Manual - Audio Overview

\ No newline at end of file +

Troubleshooting

No Sound

  • Check audio backend is configured correctly
  • Verify sample rate matches backend
  • Check master volume is not 0
  • Ensure audio is initialized (engine.init())

Distorted Sound

  • Lower volume levels
  • Reduce sample rate (ESP32 DAC works better at 11025 Hz)
  • Check for too many simultaneous sounds
  • Verify hardware connections (ESP32)

Music Not Playing

  • Check music.isPlaying() status
  • Ensure track is properly defined
  • Verify MusicPlayer is updated (happens automatically)
  • Check that music channel is not being used by SFX

Next Steps

Now that you can add audio, learn about: - NES Audio Reference - Advanced audio techniques - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs


See also: - API Reference - AudioEngine - API Reference - MusicPlayer - API Reference - Audio Types - Manual - Audio Overview

\ No newline at end of file diff --git a/site/manual/game_development/basic_rendering/index.html b/site/manual/game_development/basic_rendering/index.html index bca2a18..38350c0 100644 --- a/site/manual/game_development/basic_rendering/index.html +++ b/site/manual/game_development/basic_rendering/index.html @@ -141,4 +141,4 @@ renderer.drawSprite(sprite, x, startY, Color::White); } } -

Next Steps

Now that you can draw basic graphics, learn about: - Sprites and Animation - Advanced sprite techniques - Input and Control - Make your game interactive - Palettes - Use different color schemes


See also: - API Reference - Renderer - API Reference - Sprite - Render Layers

\ No newline at end of file +

Next Steps

Now that you can draw basic graphics, learn about: - Sprites and Animation - Advanced sprite techniques - Input and Control - Make your game interactive - Palettes - Use different color schemes


See also: - API Reference - Renderer - API Reference - Sprite - Render Layers

\ No newline at end of file diff --git a/site/manual/game_development/input_and_control/index.html b/site/manual/game_development/input_and_control/index.html index b75d7d1..db5765a 100644 --- a/site/manual/game_development/input_and_control/index.html +++ b/site/manual/game_development/input_and_control/index.html @@ -258,4 +258,4 @@ if (input.isButtonReleased(button)) return InputState::RELEASED; return InputState::IDLE; } -

Troubleshooting

Button Not Responding

  • Check button indices match your InputConfig
  • Verify GPIO pins (ESP32) or scancodes (Native) are correct
  • Ensure InputManager is being updated (happens automatically in Engine)

Input Feels Laggy

  • Ensure you're using deltaTime for movement
  • Check that input is read in update(), not draw()
  • Verify framerate is stable

Multiple Triggers

  • Use isButtonPressed() instead of isButtonDown() for one-time actions
  • Implement input buffering or cooldown timers

Next Steps

Now that you can handle input, learn about: - Audio - Add sound effects and music - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs


See also: - API Reference - InputManager - API Reference - InputConfig - Manual - Input Overview

\ No newline at end of file +

Troubleshooting

Button Not Responding

  • Check button indices match your InputConfig
  • Verify GPIO pins (ESP32) or scancodes (Native) are correct
  • Ensure InputManager is being updated (happens automatically in Engine)

Input Feels Laggy

  • Ensure you're using deltaTime for movement
  • Check that input is read in update(), not draw()
  • Verify framerate is stable

Multiple Triggers

  • Use isButtonPressed() instead of isButtonDown() for one-time actions
  • Implement input buffering or cooldown timers

Next Steps

Now that you can handle input, learn about: - Audio - Add sound effects and music - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs


See also: - API Reference - InputManager - API Reference - InputConfig - Manual - Input Overview

\ No newline at end of file diff --git a/site/manual/game_development/physics_and_collisions/index.html b/site/manual/game_development/physics_and_collisions/index.html index cd87c1d..2f44f27 100644 --- a/site/manual/game_development/physics_and_collisions/index.html +++ b/site/manual/game_development/physics_and_collisions/index.html @@ -323,4 +323,4 @@ } } } -

Troubleshooting

Collisions Not Detected

  • Verify collision layers and masks overlap
  • Check that actors are added to the scene
  • Ensure Scene::update() is called
  • Verify hitboxes are correct

Physics Too Fast/Slow

  • Adjust values based on deltaTime
  • Check gravity and velocity values
  • Test on actual hardware (ESP32 may run slower)

Objects Passing Through

  • Use sweep tests for fast objects
  • Increase collision detection frequency
  • Check hitbox sizes match visual size

Next Steps

Now that you understand physics and collisions, learn about: - User Interface - Create menus and HUDs - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels


See also: - API Reference - PhysicsActor - API Reference - CollisionSystem - Manual - Physics Overview - Manual - Collision Detection

\ No newline at end of file +

Troubleshooting

Collisions Not Detected

  • Verify collision layers and masks overlap
  • Check that actors are added to the scene
  • Ensure Scene::update() is called
  • Verify hitboxes are correct

Physics Too Fast/Slow

  • Adjust values based on deltaTime
  • Check gravity and velocity values
  • Test on actual hardware (ESP32 may run slower)

Objects Passing Through

  • Use sweep tests for fast objects
  • Increase collision detection frequency
  • Check hitbox sizes match visual size

Next Steps

Now that you understand physics and collisions, learn about: - User Interface - Create menus and HUDs - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels


See also: - API Reference - PhysicsActor - API Reference - CollisionSystem - Manual - Physics Overview - Manual - Collision Detection

\ No newline at end of file diff --git a/site/manual/game_development/scenes_and_entities/index.html b/site/manual/game_development/scenes_and_entities/index.html index 1c97f3c..9d1b3f2 100644 --- a/site/manual/game_development/scenes_and_entities/index.html +++ b/site/manual/game_development/scenes_and_entities/index.html @@ -254,4 +254,4 @@ // ... } } -

Next Steps

Now that you understand scenes and entities, learn about: - Basic Rendering - Draw sprites, text, and primitives - Input and Control - Handle user input - Physics and Collisions - Advanced collision handling


See also: - Fundamental Concepts - API Reference - Scene - API Reference - Entity - API Reference - Actor

\ No newline at end of file +

Next Steps

Now that you understand scenes and entities, learn about: - Basic Rendering - Draw sprites, text, and primitives - Input and Control - Handle user input - Physics and Collisions - Advanced collision handling


See also: - Fundamental Concepts - API Reference - Scene - API Reference - Entity - API Reference - Actor

\ No newline at end of file diff --git a/site/manual/game_development/user_interface/index.html b/site/manual/game_development/user_interface/index.html index cfa5ca0..ea2db43 100644 --- a/site/manual/game_development/user_interface/index.html +++ b/site/manual/game_development/user_interface/index.html @@ -389,4 +389,4 @@ snprintf(buffer, sizeof(buffer), "Health: %d%%", health); healthLabel->setText(buffer); } -

Next Steps

Now that you understand the UI system, you've completed the core game development topics. Continue with: - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels - Performance Tuning - Improve performance


See also: - API Reference - UIElement - API Reference - UIButton - API Reference - UI Layouts - Manual - UI Overview

\ No newline at end of file +

Next Steps

Now that you understand the UI system, you've completed the core game development topics. Continue with: - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels - Performance Tuning - Improve performance


See also: - API Reference - UIElement - API Reference - UIButton - API Reference - UI Layouts - Manual - UI Overview

\ No newline at end of file diff --git a/site/manual/optimization/extensibility/index.html b/site/manual/optimization/extensibility/index.html index b9e9e51..d0fe630 100644 --- a/site/manual/optimization/extensibility/index.html +++ b/site/manual/optimization/extensibility/index.html @@ -348,4 +348,4 @@ } } }; -

Troubleshooting

Driver Not Working

  • Verify all interface methods are implemented
  • Check initialization order
  • Test with simple drawing first
  • Verify hardware connections

Audio Backend Issues

  • Check sample rate matches hardware
  • Verify audio generation logic
  • Test with simple tones first
  • Check channel management

Extension Conflicts

  • Ensure namespace isolation
  • Avoid modifying engine code directly
  • Use composition over modification
  • Test with engine updates

Next Steps

Now that you understand extensibility, you've completed the optimization section. Continue with: - API Reference - Complete API documentation - Examples - Code examples - Resources - Tools and troubleshooting


See also: - API Reference - DrawSurface - API Reference - AudioBackend - Manual - Platforms and Drivers

\ No newline at end of file +

Troubleshooting

Driver Not Working

  • Verify all interface methods are implemented
  • Check initialization order
  • Test with simple drawing first
  • Verify hardware connections

Audio Backend Issues

  • Check sample rate matches hardware
  • Verify audio generation logic
  • Test with simple tones first
  • Check channel management

Extension Conflicts

  • Ensure namespace isolation
  • Avoid modifying engine code directly
  • Use composition over modification
  • Test with engine updates

Next Steps

Now that you understand extensibility, you've completed the optimization section. Continue with: - API Reference - Complete API documentation - Examples - Code examples - Resources - Tools and troubleshooting


See also: - API Reference - DrawSurface - API Reference - AudioBackend - Manual - Platforms and Drivers

\ No newline at end of file diff --git a/site/manual/optimization/memory_management/index.html b/site/manual/optimization/memory_management/index.html index b711b79..705db99 100644 --- a/site/manual/optimization/memory_management/index.html +++ b/site/manual/optimization/memory_management/index.html @@ -294,4 +294,4 @@ int size() const { return count; } pixelroot32::core::Entity* operator[](int index) { return entities[index]; } }; -

Troubleshooting

Out of Memory Errors

  • Reduce pool sizes
  • Use fewer entities
  • Store more data in flash
  • Avoid dynamic allocation
  • Check for memory leaks

Entity Limit Reached

  • MAX_ENTITIES = 32 is a hard limit
  • Use object pooling to reuse entities
  • Deactivate entities instead of removing
  • Combine multiple entities into one

Memory Fragmentation

  • Use object pooling
  • Pre-allocate all resources
  • Avoid frequent new/delete
  • Consider Scene Arena (experimental)

Next Steps

Now that you understand memory management, learn about: - Performance Optimization - Improve game performance - Platforms and Drivers - Understand platform specifics - Extensibility - Extend the engine


See also: - API Reference - Scene - Manual - Scenes and Entities

\ No newline at end of file +

Troubleshooting

Out of Memory Errors

  • Reduce pool sizes
  • Use fewer entities
  • Store more data in flash
  • Avoid dynamic allocation
  • Check for memory leaks

Entity Limit Reached

  • MAX_ENTITIES = 32 is a hard limit
  • Use object pooling to reuse entities
  • Deactivate entities instead of removing
  • Combine multiple entities into one

Memory Fragmentation

  • Use object pooling
  • Pre-allocate all resources
  • Avoid frequent new/delete
  • Consider Scene Arena (experimental)

Next Steps

Now that you understand memory management, learn about: - Performance Optimization - Improve game performance - Platforms and Drivers - Understand platform specifics - Extensibility - Extend the engine


See also: - API Reference - Scene - Manual - Scenes and Entities

\ No newline at end of file diff --git a/site/manual/optimization/performance_tuning/index.html b/site/manual/optimization/performance_tuning/index.html index 9402cd2..609e3e4 100644 --- a/site/manual/optimization/performance_tuning/index.html +++ b/site/manual/optimization/performance_tuning/index.html @@ -64,4 +64,4 @@ } } }; -

Troubleshooting

Low FPS

  • Profile to find bottlenecks
  • Reduce entity count
  • Optimize rendering (culling, batching)
  • Simplify collision detection
  • Reduce update frequency

Frame Drops

  • Check for expensive operations in update()
  • Avoid dynamic allocation
  • Cache calculations
  • Reduce draw calls

Stuttering

  • Ensure frame-rate independence (use deltaTime)
  • Avoid blocking operations
  • Pre-load resources
  • Use object pooling

Next Steps

Now that you understand performance optimization, learn about: - Memory Management - Manage memory efficiently - Platforms and Drivers - Platform-specific optimizations - Extensibility - Extend the engine


See also: - Manual - Basic Rendering - Manual - Physics and Collisions

\ No newline at end of file +

Troubleshooting

Low FPS

  • Profile to find bottlenecks
  • Reduce entity count
  • Optimize rendering (culling, batching)
  • Simplify collision detection
  • Reduce update frequency

Frame Drops

  • Check for expensive operations in update()
  • Avoid dynamic allocation
  • Cache calculations
  • Reduce draw calls

Stuttering

  • Ensure frame-rate independence (use deltaTime)
  • Avoid blocking operations
  • Pre-load resources
  • Use object pooling

Next Steps

Now that you understand performance optimization, learn about: - Memory Management - Manage memory efficiently - Platforms and Drivers - Platform-specific optimizations - Extensibility - Extend the engine


See also: - Manual - Basic Rendering - Manual - Physics and Collisions

\ No newline at end of file diff --git a/site/manual/optimization/platforms_and_drivers/index.html b/site/manual/optimization/platforms_and_drivers/index.html index f57bac0..63c8f39 100644 --- a/site/manual/optimization/platforms_and_drivers/index.html +++ b/site/manual/optimization/platforms_and_drivers/index.html @@ -171,4 +171,4 @@ engine.run(); return 0; } -

Platform-Specific Considerations

ESP32

Memory: - Limited RAM (~320KB) - Use object pooling - Store data in flash - Avoid dynamic allocation

Performance: - Target 30-60 FPS - Optimize rendering - Reduce entity count - Profile on hardware

Hardware: - GPIO pin configuration - SPI display setup - Audio hardware connections - Power considerations

Native

Development: - Fast iteration - Easy debugging - Unlimited resources - Visual debugging tools

Testing: - Test logic without hardware - Rapid prototyping - CI/CD integration - Cross-platform testing

Troubleshooting

ESP32 Display Issues

  • Check wiring connections
  • Verify pin numbers
  • Lower SPI frequency
  • Check display type matches
  • Verify power supply

ESP32 Audio Issues

  • Check DAC/I2S pin configuration
  • Verify sample rate
  • Check hardware connections
  • Lower volume if distorted
  • Test with different sample rates

Native Build Issues

  • Verify SDL2 installation
  • Check include/library paths
  • Ensure SDL2 version compatibility
  • Check linker flags

Next Steps

Now that you understand platforms and drivers, learn about: - Extensibility - Create custom drivers - Memory Management - ESP32 memory constraints - Performance Optimization - Platform-specific optimization


See also: - API Reference - DrawSurface - API Reference - AudioBackend - Getting Started - Your First Project

\ No newline at end of file +

Platform-Specific Considerations

ESP32

Memory: - Limited RAM (~320KB) - Use object pooling - Store data in flash - Avoid dynamic allocation

Performance: - Target 30-60 FPS - Optimize rendering - Reduce entity count - Profile on hardware

Hardware: - GPIO pin configuration - SPI display setup - Audio hardware connections - Power considerations

Native

Development: - Fast iteration - Easy debugging - Unlimited resources - Visual debugging tools

Testing: - Test logic without hardware - Rapid prototyping - CI/CD integration - Cross-platform testing

Troubleshooting

ESP32 Display Issues

  • Check wiring connections
  • Verify pin numbers
  • Lower SPI frequency
  • Check display type matches
  • Verify power supply

ESP32 Audio Issues

  • Check DAC/I2S pin configuration
  • Verify sample rate
  • Check hardware connections
  • Lower volume if distorted
  • Test with different sample rates

Native Build Issues

  • Verify SDL2 installation
  • Check include/library paths
  • Ensure SDL2 version compatibility
  • Check linker flags

Next Steps

Now that you understand platforms and drivers, learn about: - Extensibility - Create custom drivers - Memory Management - ESP32 memory constraints - Performance Optimization - Platform-specific optimization


See also: - API Reference - DrawSurface - API Reference - AudioBackend - Getting Started - Your First Project

\ No newline at end of file diff --git a/site/reference/api_overview/index.html b/site/reference/api_overview/index.html index c8ee7ff..2cde716 100644 --- a/site/reference/api_overview/index.html +++ b/site/reference/api_overview/index.html @@ -4,4 +4,4 @@ }; }

Constructors

List of all constructors with parameters.

Public Methods

Method Description Parameters Returns
methodName() Description param: type return type

Properties

Property Type Description
property type Description

Usage Example

// Example code showing typical usage
-

Performance Notes

Any performance considerations or limitations.

See Also

Links to related APIs and documentation.

Finding APIs

By Functionality

By Module

Navigate to the specific module folder: - api_reference/core/ - Core engine classes - api_reference/graphics/ - Rendering and graphics - api_reference/audio/ - Audio system - api_reference/physics/ - Physics and collisions - api_reference/ui/ - User interface

Complete API List

Core

Graphics

Audio

Physics

UI


Note: This is an overview. For detailed API documentation, see the individual reference pages linked above.

\ No newline at end of file +

Performance Notes

Any performance considerations or limitations.

See Also

Links to related APIs and documentation.

Finding APIs

By Functionality

By Module

Navigate to the specific module folder: - api_reference/core/ - Core engine classes - api_reference/graphics/ - Rendering and graphics - api_reference/audio/ - Audio system - api_reference/physics/ - Physics and collisions - api_reference/ui/ - User interface

Complete API List

Core

Graphics

Audio

Physics

UI


Note: This is an overview. For detailed API documentation, see the individual reference pages linked above.

\ No newline at end of file diff --git a/site/reference/code_examples/index.html b/site/reference/code_examples/index.html index 1085910..dd51a5a 100644 --- a/site/reference/code_examples/index.html +++ b/site/reference/code_examples/index.html @@ -605,4 +605,4 @@ bool isActive() const { return active; } float getProgress() const { return static_cast<float>(elapsed) / duration; } }; -

See Also

\ No newline at end of file +

See Also

\ No newline at end of file diff --git a/site/reference/game_examples_guide/index.html b/site/reference/game_examples_guide/index.html index fe60544..45e7fad 100644 --- a/site/reference/game_examples_guide/index.html +++ b/site/reference/game_examples_guide/index.html @@ -171,4 +171,4 @@ // 4. Draw UI/HUD drawHUD(renderer); } -

Learning Path

Beginner Examples

  1. Pong: Basic physics and collisions
  2. TicTacToe: Turn-based logic
  3. Snake: Entity pooling and grid

Intermediate Examples

  1. CameraDemo: Camera and parallax
  2. SpritesDemo: 2bpp and 4bpp formats
  3. BrickBreaker: Physics, particles and audio

Advanced Examples

  1. Space Invaders: Full game (1bpp sprites, collisions, audio)
  2. Metroidvania: Platformer with multi-layer 4bpp tilemap, tile-based collision and ESP32 optimizations (no scroll/camera)

Code Study Recommendations

For Learning Physics

  • Study Pong/BallActor.cpp - PhysicsActor usage
  • Study CameraDemo/PlayerCube.cpp - Platformer physics

For Learning Collisions

  • Study SpaceInvaders - Complex collision layers
  • Study Pong - Simple collision response

For Learning Memory Management

  • Study Snake/SnakeScene.cpp - Entity pooling
  • Study SpaceInvaders - Projectile pooling

For Learning Audio

  • Study SpaceInvaders - Music and sound effects
  • Study Pong - Simple audio integration

For Learning UI

  • Study TicTacToe - Button-based UI
  • Study menu scenes - Layout usage

Extending Examples

Adding Features

  • Pong: Add power-ups, multiple balls
  • Snake: Add obstacles, multiple food types
  • Space Invaders: Add boss battles, power-ups

Creating Variations

  • Pong: Make it vertical, add walls
  • Snake: Change to hexagonal grid
  • TicTacToe: Make it 4x4 or 5x5

Best Practices from Examples

  1. Pre-allocate Resources: All examples pre-allocate entities
  2. Use Object Pooling: For frequently created/destroyed entities
  3. Organize by Layers: Clear collision layer organization
  4. Separate Concerns: Game logic separate from rendering
  5. State Management: Clear game state handling

See Also


Note: All example code is available in the src/examples/ directory of the PixelRoot32 Game Samples project.

\ No newline at end of file +

Learning Path

Beginner Examples

  1. Pong: Basic physics and collisions
  2. TicTacToe: Turn-based logic
  3. Snake: Entity pooling and grid

Intermediate Examples

  1. CameraDemo: Camera and parallax
  2. SpritesDemo: 2bpp and 4bpp formats
  3. BrickBreaker: Physics, particles and audio

Advanced Examples

  1. Space Invaders: Full game (1bpp sprites, collisions, audio)
  2. Metroidvania: Platformer with multi-layer 4bpp tilemap, tile-based collision and ESP32 optimizations (no scroll/camera)

Code Study Recommendations

For Learning Physics

  • Study Pong/BallActor.cpp - PhysicsActor usage
  • Study CameraDemo/PlayerCube.cpp - Platformer physics

For Learning Collisions

  • Study SpaceInvaders - Complex collision layers
  • Study Pong - Simple collision response

For Learning Memory Management

  • Study Snake/SnakeScene.cpp - Entity pooling
  • Study SpaceInvaders - Projectile pooling

For Learning Audio

  • Study SpaceInvaders - Music and sound effects
  • Study Pong - Simple audio integration

For Learning UI

  • Study TicTacToe - Button-based UI
  • Study menu scenes - Layout usage

Extending Examples

Adding Features

  • Pong: Add power-ups, multiple balls
  • Snake: Add obstacles, multiple food types
  • Space Invaders: Add boss battles, power-ups

Creating Variations

  • Pong: Make it vertical, add walls
  • Snake: Change to hexagonal grid
  • TicTacToe: Make it 4x4 or 5x5

Best Practices from Examples

  1. Pre-allocate Resources: All examples pre-allocate entities
  2. Use Object Pooling: For frequently created/destroyed entities
  3. Organize by Layers: Clear collision layer organization
  4. Separate Concerns: Game logic separate from rendering
  5. State Management: Clear game state handling

See Also


Note: All example code is available in the src/examples/ directory of the PixelRoot32 Game Samples project.

\ No newline at end of file diff --git a/site/resources/available_tools/index.html b/site/resources/available_tools/index.html index 5aabd6a..bf46cf9 100644 --- a/site/resources/available_tools/index.html +++ b/site/resources/available_tools/index.html @@ -61,4 +61,4 @@ #!/bin/bash pr32-sprite-compiler assets/sprites/*.png --output-dir src/sprites/ # Continue with build... -

Best Practices

  • Organize assets: Keep source images separate from generated code
  • Version control: Commit generated headers, not source images (or both)
  • Naming conventions: Use consistent naming for sprites
  • Batch processing: Process multiple sprites at once when possible

See Also


Note: Tool availability may vary. Check the PixelRoot32 repository for the latest tool information.

\ No newline at end of file +

Best Practices

  • Organize assets: Keep source images separate from generated code
  • Version control: Commit generated headers, not source images (or both)
  • Naming conventions: Use consistent naming for sprites
  • Batch processing: Process multiple sprites at once when possible

See Also


Note: Tool availability may vary. Check the PixelRoot32 repository for the latest tool information.

\ No newline at end of file diff --git a/site/resources/faq/index.html b/site/resources/faq/index.html index 85f86c6..eaf71d2 100644 --- a/site/resources/faq/index.html +++ b/site/resources/faq/index.html @@ -11,4 +11,4 @@ Serial.print("Free heap: "); Serial.println(ESP.getFreeHeap()); #endif -

Hardware

Which ESP32 board should I use?

Any ESP32 board works. Common choices: - ESP32-WROOM-32 - ESP32-WROVER (more RAM) - ESP32-DevKit

Which display should I use?

Popular choices: - ST7789: 240x240, good quality - ST7735: 128x128, smaller/cheaper - ILI9341: 240x320, larger

See Platforms and Drivers.

How many buttons do I need?

Minimum: 4 (UP, DOWN, LEFT, RIGHT) Recommended: 6 (add A and B buttons) More buttons can be added if needed.

Can I use analog joysticks?

Not directly supported. You can read analog pins manually and convert to digital input, but the engine expects digital buttons.

Troubleshooting

My display is blank. What's wrong?

  1. Check wiring connections
  2. Verify pin numbers in platformio.ini
  3. Lower SPI frequency
  4. Check display type matches hardware
  5. Verify power supply

See Troubleshooting.

Buttons don't work. Why?

  1. Check button wiring
  2. Verify pin numbers in InputConfig
  3. Check pull-up/pull-down resistors
  4. Ensure InputManager is being updated
  5. Test with isButtonDown() vs isButtonPressed()

Audio is distorted. How do I fix it?

  1. Lower volume levels
  2. Reduce sample rate (try 11025 Hz)
  3. Check for too many simultaneous sounds
  4. Verify hardware connections
  5. Check power supply

Game crashes randomly. What's happening?

Common causes: - Out of memory - Too many entities - Infinite loops - Stack overflow - Watchdog timeout

See Troubleshooting for debugging techniques.

Advanced

Can I extend the engine?

Yes, PixelRoot32 is designed to be extensible. You can: - Create custom display drivers - Create custom audio backends - Extend existing systems

See Extensibility.

Can I use 3D graphics?

No, PixelRoot32 is 2D-only. It's designed for sprite-based 2D games.

Can I add networking?

Not currently supported. The engine focuses on single-player games.

Can I save game data?

Not currently supported. A save system is planned for future versions.

Can I use multiple scenes at once?

Yes, use SceneManager to push/pop scenes. This is useful for menus and pause screens.

Getting Help

Where can I get help?

  • Documentation: This documentation site
  • Examples: Study example games in the samples project
  • Discord: Community Discord server
  • GitHub: Open an issue for bugs

How do I report a bug?

Create a detailed bug report with: - Platform (ESP32 or Native) - Hardware details - Minimal reproduction code - Error messages - Expected vs actual behavior

Can I contribute?

Yes! PixelRoot32 is open source. Check the main repository for contribution guidelines.

See Also


Can't find your question? Check the Troubleshooting guide or ask on the Discord server.

\ No newline at end of file +

Hardware

Which ESP32 board should I use?

Any ESP32 board works. Common choices: - ESP32-WROOM-32 - ESP32-WROVER (more RAM) - ESP32-DevKit

Which display should I use?

Popular choices: - ST7789: 240x240, good quality - ST7735: 128x128, smaller/cheaper - ILI9341: 240x320, larger

See Platforms and Drivers.

How many buttons do I need?

Minimum: 4 (UP, DOWN, LEFT, RIGHT) Recommended: 6 (add A and B buttons) More buttons can be added if needed.

Can I use analog joysticks?

Not directly supported. You can read analog pins manually and convert to digital input, but the engine expects digital buttons.

Troubleshooting

My display is blank. What's wrong?

  1. Check wiring connections
  2. Verify pin numbers in platformio.ini
  3. Lower SPI frequency
  4. Check display type matches hardware
  5. Verify power supply

See Troubleshooting.

Buttons don't work. Why?

  1. Check button wiring
  2. Verify pin numbers in InputConfig
  3. Check pull-up/pull-down resistors
  4. Ensure InputManager is being updated
  5. Test with isButtonDown() vs isButtonPressed()

Audio is distorted. How do I fix it?

  1. Lower volume levels
  2. Reduce sample rate (try 11025 Hz)
  3. Check for too many simultaneous sounds
  4. Verify hardware connections
  5. Check power supply

Game crashes randomly. What's happening?

Common causes: - Out of memory - Too many entities - Infinite loops - Stack overflow - Watchdog timeout

See Troubleshooting for debugging techniques.

Advanced

Can I extend the engine?

Yes, PixelRoot32 is designed to be extensible. You can: - Create custom display drivers - Create custom audio backends - Extend existing systems

See Extensibility.

Can I use 3D graphics?

No, PixelRoot32 is 2D-only. It's designed for sprite-based 2D games.

Can I add networking?

Not currently supported. The engine focuses on single-player games.

Can I save game data?

Not currently supported. A save system is planned for future versions.

Can I use multiple scenes at once?

Yes, use SceneManager to push/pop scenes. This is useful for menus and pause screens.

Getting Help

Where can I get help?

  • Documentation: This documentation site
  • Examples: Study example games in the samples project
  • Discord: Community Discord server
  • GitHub: Open an issue for bugs

How do I report a bug?

Create a detailed bug report with: - Platform (ESP32 or Native) - Hardware details - Minimal reproduction code - Error messages - Expected vs actual behavior

Can I contribute?

Yes! PixelRoot32 is open source. Check the main repository for contribution guidelines.

See Also


Can't find your question? Check the Troubleshooting guide or ask on the Discord server.

\ No newline at end of file diff --git a/site/resources/limitations_and_considerations/index.html b/site/resources/limitations_and_considerations/index.html index 87e4ecb..19ef915 100644 --- a/site/resources/limitations_and_considerations/index.html +++ b/site/resources/limitations_and_considerations/index.html @@ -1 +1 @@ - Limitations and Considerations - PixelRoot32 Documentation

Limitations and Considerations

This document honestly documents what PixelRoot32 can and cannot do, helping you make informed decisions about using the engine.

Hardware Limitations (ESP32)

Memory Constraints

RAM: - Available: ~320KB total (varies by ESP32 model) - Heap: Limited and fragmented over time - Stack: ~8KB, avoid large stack allocations - Impact: Limits entity count, sprite data, and dynamic allocation

Flash: - Available: 4MB+ (varies by model) - Usage: Program code, sprite data, assets - Impact: Large games may approach limits

Recommendations: - Use object pooling - Store data in flash (const/constexpr) - Avoid dynamic allocation in game loop - Keep entity count low

CPU Limitations

Performance: - Clock Speed: 240MHz (typically) - Single-threaded: One core handles everything - Target FPS: 30-60 FPS (depends on complexity) - Frame Budget: ~16-33ms per frame at 60 FPS

Impact: - Complex games may struggle - Many entities reduce performance - Expensive calculations hurt FPS

Recommendations: - Optimize rendering - Reduce entity count - Cache calculations - Profile on hardware

Display Limitations

Supported Displays: - TFT displays via SPI (ST7735, ST7789, ILI9341, etc.) - Limited to SPI displays - Resolution typically 128x128 to 320x240

Constraints: - SPI communication speed limits - Display initialization complexity - Power consumption

Audio Limitations

Hardware: - Internal DAC: Lower quality, simple setup - I2S: Higher quality, requires external DAC - Sample rates: 11025 Hz (DAC) or 22050 Hz (I2S)

Constraints: - 4 channels total (2 Pulse, 1 Triangle, 1 Noise) - Music uses one channel - Limited simultaneous sounds - Quality limited by hardware

Software Limitations

Entity System

MAX_ENTITIES = 32 per scene - Hard limit, cannot be changed easily - Applies to all entities (actors, UI, particles, etc.) - Must manage entity count carefully

Workarounds: - Use object pooling - Reuse entities - Disable entities instead of removing - Combine multiple entities into one

No RTTI (Runtime Type Information)

Impact: - Cannot use dynamic_cast in most code - Type checking must be done manually - Limits polymorphism patterns

Alternatives: - Use virtual functions - Manual type checking - Tag-based systems

No Exceptions in Critical Code

Impact: - Cannot use try/catch in game loop - Error handling must be explicit - Crashes instead of exceptions

Best Practices: - Validate inputs - Check return values - Use assertions for debugging - Handle errors explicitly

No Dynamic Allocation in Game Loop

Impact: - Cannot use new/delete during gameplay - Must pre-allocate resources - Limits flexibility

Solutions: - Object pooling - Pre-allocation in init() - Static buffers - Fixed-size arrays

No Advanced Features

Not Supported: - 3D graphics - Shaders - Advanced physics (joints, constraints) - Networking - File system (ESP32) - Advanced audio effects

Focus: - 2D sprite-based games - Simple physics - Retro-style games - Embedded-friendly features

Experimental Features

2bpp Sprites

Status: Experimental - Requires PIXELROOT32_ENABLE_2BPP_SPRITES flag - May have bugs or limitations - Not fully tested

Use with caution: - Test thoroughly - May change in future versions - Report issues if found

4bpp Sprites

Status: Experimental - Requires PIXELROOT32_ENABLE_4BPP_SPRITES flag - More experimental than 2bpp - Higher memory usage

Use with caution: - Test extensively - Monitor memory usage - May be unstable

Scene Arena

Status: Experimental - Requires PIXELROOT32_ENABLE_SCENE_ARENA flag - Alternative memory management - May have bugs

Recommendations: - Use object pooling instead (more stable) - Test thoroughly if using - May be removed or changed

Unsupported Features (Current)

Planned but Not Available

  • u8g2 Driver: Alternative display driver (planned)
  • Music Compiler: Tool to convert music files (planned)
  • Tilemap Compiler: Tool to create tilemaps (planned)
  • Save System: Persistent storage system (planned)
  • Spatial Partitioning: Advanced collision optimization (planned)

Not Planned

  • 3D Graphics: 2D-only engine
  • Networking: No network support
  • File System: No file I/O on ESP32
  • Advanced Audio: NES-like audio only
  • Scripting: No Lua/JavaScript support

Best Practices for ESP32

Memory Management

  • Pre-allocate: All resources in init()
  • Object pooling: Reuse entities
  • Flash storage: Use const/constexpr for data
  • Avoid strings: Use static buffers
  • Monitor usage: Check heap regularly

Performance

  • Limit entities: Stay well below MAX_ENTITIES
  • Optimize rendering: Use culling, batching
  • Cache calculations: Avoid repeated work
  • Profile on hardware: PC performance ≠ ESP32

Development

  • Test on hardware: Don't rely only on Native
  • Start simple: Add complexity gradually
  • Monitor memory: Watch for leaks
  • Optimize incrementally: Profile and optimize

What PixelRoot32 IS Good For

Retro-style 2D gamesArcade gamesPuzzle gamesPlatformersShootersEducational projectsPrototypingEmbedded game development

What PixelRoot32 is NOT Good For

3D gamesComplex physics simulationsLarge open worldsGames requiring many entitiesGames with complex graphicsNetwork multiplayerGames requiring file I/O

Making Informed Decisions

Before Starting a Project

  1. Assess requirements: Does PixelRoot32 fit?
  2. Check limitations: Can you work within constraints?
  3. Plan architecture: Design around limitations
  4. Test early: Verify on hardware early

If Limitations Are a Problem

Consider alternatives: - Full game engines (Unity, Godot) for complex games - Custom solutions for specific needs - Different hardware for more resources

Or work within limits: - Simplify game design - Optimize aggressively - Use creative solutions

Version Compatibility

Current Version

  • Engine Version: 0.2.0-dev
  • API Stability: May change
  • Breaking Changes: Possible in future versions

Recommendations: - Pin exact version in platformio.ini - Don't use ^ or fuzzy versioning - Test after engine updates - Review changelog

Honest Assessment

PixelRoot32 is designed for: - Simple to medium complexity games - Retro/arcade style - ESP32 hardware constraints - Rapid development

It is not designed for: - AAA game complexity - Modern graphics - Large-scale games - Unlimited resources

See Also


Remember: Understanding limitations helps you build better games within PixelRoot32's capabilities.

\ No newline at end of file + Limitations and Considerations - PixelRoot32 Documentation

Limitations and Considerations

This document honestly documents what PixelRoot32 can and cannot do, helping you make informed decisions about using the engine.

Hardware Limitations (ESP32)

Memory Constraints

RAM: - Available: ~320KB total (varies by ESP32 model) - Heap: Limited and fragmented over time - Stack: ~8KB, avoid large stack allocations - Impact: Limits entity count, sprite data, and dynamic allocation

Flash: - Available: 4MB+ (varies by model) - Usage: Program code, sprite data, assets - Impact: Large games may approach limits

Recommendations: - Use object pooling - Store data in flash (const/constexpr) - Avoid dynamic allocation in game loop - Keep entity count low

CPU Limitations

Performance: - Clock Speed: 240MHz (typically) - Single-threaded: One core handles everything - Target FPS: 30-60 FPS (depends on complexity) - Frame Budget: ~16-33ms per frame at 60 FPS

Impact: - Complex games may struggle - Many entities reduce performance - Expensive calculations hurt FPS

Recommendations: - Optimize rendering - Reduce entity count - Cache calculations - Profile on hardware

Display Limitations

Supported Displays: - TFT displays via SPI (ST7735, ST7789, ILI9341, etc.) - Limited to SPI displays - Resolution typically 128x128 to 320x240

Constraints: - SPI communication speed limits - Display initialization complexity - Power consumption

Audio Limitations

Hardware: - Internal DAC: Lower quality, simple setup - I2S: Higher quality, requires external DAC - Sample rates: 11025 Hz (DAC) or 22050 Hz (I2S)

Constraints: - 4 channels total (2 Pulse, 1 Triangle, 1 Noise) - Music uses one channel - Limited simultaneous sounds - Quality limited by hardware

Software Limitations

Entity System

MAX_ENTITIES = 32 per scene - Hard limit, cannot be changed easily - Applies to all entities (actors, UI, particles, etc.) - Must manage entity count carefully

Workarounds: - Use object pooling - Reuse entities - Disable entities instead of removing - Combine multiple entities into one

No RTTI (Runtime Type Information)

Impact: - Cannot use dynamic_cast in most code - Type checking must be done manually - Limits polymorphism patterns

Alternatives: - Use virtual functions - Manual type checking - Tag-based systems

No Exceptions in Critical Code

Impact: - Cannot use try/catch in game loop - Error handling must be explicit - Crashes instead of exceptions

Best Practices: - Validate inputs - Check return values - Use assertions for debugging - Handle errors explicitly

No Dynamic Allocation in Game Loop

Impact: - Cannot use new/delete during gameplay - Must pre-allocate resources - Limits flexibility

Solutions: - Object pooling - Pre-allocation in init() - Static buffers - Fixed-size arrays

No Advanced Features

Not Supported: - 3D graphics - Shaders - Advanced physics (joints, constraints) - Networking - File system (ESP32) - Advanced audio effects

Focus: - 2D sprite-based games - Simple physics - Retro-style games - Embedded-friendly features

Experimental Features

2bpp Sprites

Status: Experimental - Requires PIXELROOT32_ENABLE_2BPP_SPRITES flag - May have bugs or limitations - Not fully tested

Use with caution: - Test thoroughly - May change in future versions - Report issues if found

4bpp Sprites

Status: Experimental - Requires PIXELROOT32_ENABLE_4BPP_SPRITES flag - More experimental than 2bpp - Higher memory usage

Use with caution: - Test extensively - Monitor memory usage - May be unstable

Scene Arena

Status: Experimental - Requires PIXELROOT32_ENABLE_SCENE_ARENA flag - Alternative memory management - May have bugs

Recommendations: - Use object pooling instead (more stable) - Test thoroughly if using - May be removed or changed

Unsupported Features (Current)

Planned but Not Available

  • u8g2 Driver: Alternative display driver (planned)
  • Music Compiler: Tool to convert music files (planned)
  • Tilemap Compiler: Tool to create tilemaps (planned)
  • Save System: Persistent storage system (planned)
  • Spatial Partitioning: Advanced collision optimization (planned)

Not Planned

  • 3D Graphics: 2D-only engine
  • Networking: No network support
  • File System: No file I/O on ESP32
  • Advanced Audio: NES-like audio only
  • Scripting: No Lua/JavaScript support

Best Practices for ESP32

Memory Management

  • Pre-allocate: All resources in init()
  • Object pooling: Reuse entities
  • Flash storage: Use const/constexpr for data
  • Avoid strings: Use static buffers
  • Monitor usage: Check heap regularly

Performance

  • Limit entities: Stay well below MAX_ENTITIES
  • Optimize rendering: Use culling, batching
  • Cache calculations: Avoid repeated work
  • Profile on hardware: PC performance ≠ ESP32

Development

  • Test on hardware: Don't rely only on Native
  • Start simple: Add complexity gradually
  • Monitor memory: Watch for leaks
  • Optimize incrementally: Profile and optimize

What PixelRoot32 IS Good For

Retro-style 2D gamesArcade gamesPuzzle gamesPlatformersShootersEducational projectsPrototypingEmbedded game development

What PixelRoot32 is NOT Good For

3D gamesComplex physics simulationsLarge open worldsGames requiring many entitiesGames with complex graphicsNetwork multiplayerGames requiring file I/O

Making Informed Decisions

Before Starting a Project

  1. Assess requirements: Does PixelRoot32 fit?
  2. Check limitations: Can you work within constraints?
  3. Plan architecture: Design around limitations
  4. Test early: Verify on hardware early

If Limitations Are a Problem

Consider alternatives: - Full game engines (Unity, Godot) for complex games - Custom solutions for specific needs - Different hardware for more resources

Or work within limits: - Simplify game design - Optimize aggressively - Use creative solutions

Version Compatibility

Current Version

  • Engine Version: 0.2.0-dev
  • API Stability: May change
  • Breaking Changes: Possible in future versions

Recommendations: - Pin exact version in platformio.ini - Don't use ^ or fuzzy versioning - Test after engine updates - Review changelog

Honest Assessment

PixelRoot32 is designed for: - Simple to medium complexity games - Retro/arcade style - ESP32 hardware constraints - Rapid development

It is not designed for: - AAA game complexity - Modern graphics - Large-scale games - Unlimited resources

See Also


Remember: Understanding limitations helps you build better games within PixelRoot32's capabilities.

\ No newline at end of file diff --git a/site/resources/troubleshooting/index.html b/site/resources/troubleshooting/index.html index a378ba5..4de5d9b 100644 --- a/site/resources/troubleshooting/index.html +++ b/site/resources/troubleshooting/index.html @@ -71,4 +71,4 @@ // Usage DEBUG_LOG("Entity created"); DEBUG_LOG("Collision detected"); -

Getting Help

If you can't resolve an issue:

  1. Check documentation: Review relevant guides
  2. Search examples: Look at example games
  3. Review code: Check engine source code
  4. Community: Ask on Discord or GitHub
  5. Report issue: Create detailed bug report

Bug Report Template

When reporting issues, include:

  • Platform: ESP32 or Native
  • Hardware: Display type, ESP32 model
  • Code: Minimal reproduction code
  • Error messages: Full error output
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Steps to reproduce: How to trigger the issue

See Also


Note: Many issues are configuration-related. Double-check your setup before assuming a bug.

\ No newline at end of file +

Getting Help

If you can't resolve an issue:

  1. Check documentation: Review relevant guides
  2. Search examples: Look at example games
  3. Review code: Check engine source code
  4. Community: Ask on Discord or GitHub
  5. Report issue: Create detailed bug report

Bug Report Template

When reporting issues, include:

  • Platform: ESP32 or Native
  • Hardware: Display type, ESP32 model
  • Code: Minimal reproduction code
  • Error messages: Full error output
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Steps to reproduce: How to trigger the issue

See Also


Note: Many issues are configuration-related. Double-check your setup before assuming a bug.

\ No newline at end of file diff --git a/site/tools/sprite_compiler/advanced_features/index.html b/site/tools/sprite_compiler/advanced_features/index.html index c2b3840..8027367 100644 --- a/site/tools/sprite_compiler/advanced_features/index.html +++ b/site/tools/sprite_compiler/advanced_features/index.html @@ -1,2 +1,2 @@ Advanced Features - PixelRoot32 Documentation

Sprite Compiler Advanced Features

Advanced features and options for the PixelRoot32 Sprite Compiler to optimize sprite conversion and handle complex scenarios.

Automatic Palette Detection

The Sprite Compiler automatically detects if your sprite uses one of the engine's built-in palettes. This simplifies your workflow and ensures color consistency.

Predefined Engine Palettes

The engine includes 5 optimized palettes: - PR32 (Default PixelRoot32 palette) - NES (Nintendo style) - GB (GameBoy style) - GBC (GameBoy Color style) - PICO8 (Fantasy console style)

How it works

  1. Detection: When you compile an image, the tool compares all unique colors found in the sprite with the colors in the 5 engine palettes.
  2. Match: If all colors in your sprite belong to one of these palettes, the compiler:
  3. Omits generating a color array in the header.
  4. Assumes you will use the engine's built-in palette definitions at runtime.
  5. Custom Palette: If your sprite uses colors not found in the engine palettes, it automatically generates a {PREFIX}_PALETTE_MAPPING[16] array in the header file.

Naming with Prefixes

You can organize your generated code by using the --prefix parameter (or the Prefix field in the GUI).

Using Prefixes

By default, sprites are named SPRITE_N_.... Using a prefix allows you to create more descriptive names and avoid naming collisions.

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --prefix PLAYER_JUM
-

Generated names will follow this pattern: - PLAYER_JUM_SPRITE_0_LAYER_0 - PLAYER_JUM_SPRITE_0_2BPP - PLAYER_JUM_SPRITE_0_4BPP - PLAYER_JUM_PALETTE_MAPPING (if a custom palette is used)

Export Modes

Layered (1bpp)

Best for standard PixelRoot32 rendering. It extracts each color into its own bitmask (1bpp). The engine then renders these layers sequentially.

Packed (2bpp / 4bpp)

Generates a single packed array where each pixel uses multiple bits. - 2bpp: 4 colors max (Index 0 is always transparent). - 4bpp: 16 colors max (Index 0 is always transparent).

These modes are more efficient for sprites with many colors as they require only a single draw call.

\ No newline at end of file +

Generated names will follow this pattern: - PLAYER_JUM_SPRITE_0_LAYER_0 - PLAYER_JUM_SPRITE_0_2BPP - PLAYER_JUM_SPRITE_0_4BPP - PLAYER_JUM_PALETTE_MAPPING (if a custom palette is used)

Export Modes

Layered (1bpp)

Best for standard PixelRoot32 rendering. It extracts each color into its own bitmask (1bpp). The engine then renders these layers sequentially.

Packed (2bpp / 4bpp)

Generates a single packed array where each pixel uses multiple bits. - 2bpp: 4 colors max (Index 0 is always transparent). - 4bpp: 16 colors max (Index 0 is always transparent).

These modes are more efficient for sprites with many colors as they require only a single draw call.

\ No newline at end of file diff --git a/site/tools/sprite_compiler/installation/index.html b/site/tools/sprite_compiler/installation/index.html index e101658..c40b365 100644 --- a/site/tools/sprite_compiler/installation/index.html +++ b/site/tools/sprite_compiler/installation/index.html @@ -29,4 +29,4 @@ npm install

Uninstallation

Remove Global Installation

npm uninstall -g pr32-sprite-compiler
 

Remove Local Installation

npm uninstall pr32-sprite-compiler
-

Troubleshooting

Common Issues

"Command not found" after installation: - Restart your terminal - Check npm global bin path: npm config get prefix - Verify PATH includes npm bin directory

Permission errors: - On Linux/macOS: Use sudo for global install - Or install locally without -g flag - On Windows: Run terminal as Administrator

Module not found errors: - Reinstall: npm install -g pr32-sprite-compiler - Clear npm cache: npm cache clean --force

Version conflicts: - Check Node.js version: node --version - Update Node.js if version is too old - Use nvm (Node Version Manager) to manage versions

Getting Help

Next Steps

Once installed, proceed to: - Usage Guide - Learn how to use the compiler - Advanced Features - Explore advanced options

See Also

\ No newline at end of file +

Troubleshooting

Common Issues

"Command not found" after installation: - Restart your terminal - Check npm global bin path: npm config get prefix - Verify PATH includes npm bin directory

Permission errors: - On Linux/macOS: Use sudo for global install - Or install locally without -g flag - On Windows: Run terminal as Administrator

Module not found errors: - Reinstall: npm install -g pr32-sprite-compiler - Clear npm cache: npm cache clean --force

Version conflicts: - Check Node.js version: node --version - Update Node.js if version is too old - Use nvm (Node Version Manager) to manage versions

Getting Help

Next Steps

Once installed, proceed to: - Usage Guide - Learn how to use the compiler - Advanced Features - Explore advanced options

See Also

\ No newline at end of file diff --git a/site/tools/sprite_compiler/overview/index.html b/site/tools/sprite_compiler/overview/index.html index ce0f6d7..faecac0 100644 --- a/site/tools/sprite_compiler/overview/index.html +++ b/site/tools/sprite_compiler/overview/index.html @@ -24,4 +24,4 @@ # Continue with your build process platformio run -

Advantages Over Manual Creation

✅ Time Saving

  • No manual bit pattern conversion
  • Automatic format optimization
  • Batch processing multiple sprites

✅ Accuracy

  • Correct bit ordering
  • Proper array formatting
  • Valid C++ syntax

✅ Consistency

  • Uniform naming conventions
  • Standardized output format
  • Consistent code structure

✅ Maintainability

  • Easy to regenerate from source images
  • Version control friendly
  • Clear separation of assets and code

Limitations

  • Width limit: 16 pixels for 1bpp (hardware constraint)
  • Color depth: Limited by format (1bpp = 2 colors, 2bpp = 4 colors, etc.)
  • File format: Primarily PNG (other formats may require conversion)

Next Steps

See Also

\ No newline at end of file +

Advantages Over Manual Creation

✅ Time Saving

  • No manual bit pattern conversion
  • Automatic format optimization
  • Batch processing multiple sprites

✅ Accuracy

  • Correct bit ordering
  • Proper array formatting
  • Valid C++ syntax

✅ Consistency

  • Uniform naming conventions
  • Standardized output format
  • Consistent code structure

✅ Maintainability

  • Easy to regenerate from source images
  • Version control friendly
  • Clear separation of assets and code

Limitations

  • Width limit: 16 pixels for 1bpp (hardware constraint)
  • Color depth: Limited by format (1bpp = 2 colors, 2bpp = 4 colors, etc.)
  • File format: Primarily PNG (other formats may require conversion)

Next Steps

See Also

\ No newline at end of file diff --git a/site/tools/sprite_compiler/usage_guide/index.html b/site/tools/sprite_compiler/usage_guide/index.html index 7af22e4..d7a8d28 100644 --- a/site/tools/sprite_compiler/usage_guide/index.html +++ b/site/tools/sprite_compiler/usage_guide/index.html @@ -110,4 +110,4 @@ │ └── items.h └── platformio.ini

Naming Conventions

  • Use descriptive names: player_walk_0.pngPLAYER_WALK_0_SPRITE
  • Be consistent: All caps for sprite names
  • Use prefixes: ENEMY_, PLAYER_, ITEM_

Version Control

  • Commit generated headers (they're part of the build)
  • Or add to .gitignore and regenerate on build
  • Keep source images in version control

Troubleshooting

Common Issues

"Image too large":

  • Sprites must be ≤ 16 pixels wide for 1bpp
  • Resize image or split into multiple sprites

"Colors not converting correctly":

  • Use indexed color PNG
  • For 1bpp: Use only black and white
  • For 2bpp: Use exactly 4 colors
  • For 4bpp: Use up to 16 colors

"Output file not found":

  • Check write permissions
  • Verify output directory exists
  • Use absolute paths if needed

"Invalid format":

  • Ensure input is PNG format
  • Check file is not corrupted
  • Try re-saving image in image editor

Getting Help

pr32-sprite-compiler --help
-

Shows all available options and usage.

Next Steps

See Also

\ No newline at end of file +

Shows all available options and usage.

Next Steps

See Also

\ No newline at end of file diff --git a/site/tools/tilemap_editor/installation/index.html b/site/tools/tilemap_editor/installation/index.html index 6b87957..6cca496 100644 --- a/site/tools/tilemap_editor/installation/index.html +++ b/site/tools/tilemap_editor/installation/index.html @@ -4,4 +4,4 @@

2.3 Run the Editor

python main.py
 

3. Standalone Executable (Windows)

For a more convenient experience, you can use the pre-compiled version:

  1. Go to the Releases section of the repository.
  2. Download the latest PixelRoot32-Editor-win64.zip.
  3. Extract the contents to a folder.
  4. Run PixelRoot32-Editor.exe.

Note: No Python installation is required to run the standalone executable.

4. Building your own Executable

If you want to package the editor yourself:

  1. Install PyInstaller:
pip install pyinstaller
 
  1. Run the build command using the provided .spec file:
pyinstaller pixelroot32_editor.spec
-
  1. The executable will be available in the dist/ folder.
\ No newline at end of file +
  1. The executable will be available in the dist/ folder.
\ No newline at end of file diff --git a/site/tools/tilemap_editor/overview/index.html b/site/tools/tilemap_editor/overview/index.html index 5651751..4edb0c5 100644 --- a/site/tools/tilemap_editor/overview/index.html +++ b/site/tools/tilemap_editor/overview/index.html @@ -1 +1 @@ - Tilemap Editor Overview - PixelRoot32 Documentation

Tilemap Editor Overview

The PixelRoot32 Tilemap Editor is a powerful visual tool designed to create complex multi-layered tile-based maps for the PixelRoot32 engine. It simplifies the process of designing game environments, managing tilesets, and exporting optimized C++ code.

What It Does

The Tilemap Editor allows you to:

  • Visual Design: Paint tiles directly onto a canvas with layers and transparency.
  • Tileset Management: Import PNG images as tilesets and select single or multiple tiles.
  • Multi-Layer Support: Organize your map into up to 8 layers for parallax effects or depth.
  • Optimized Export: Generate C++ header and source files compatible with the PixelRoot32 renderer.
  • BPP Support: Export maps in 1bpp, 2bpp, or 4bpp formats to balance memory usage and color depth.

Key Features

✅ Visual Editing Tools

  • Brush: Paint individual tiles or patterns.
  • Eraser: Remove tiles from the active layer.
  • Rectangle Fill: Quickly fill areas with a specific tile.
  • Pipette: Pick an existing tile from the canvas.

✅ Multi-Layer System

  • Visibility Toggle: Hide/show layers to focus on specific parts of the map.
  • Opacity Control: Adjust layer transparency for complex blending effects.
  • Layer Reordering: Change the render order of your tilemaps.

✅ Tileset Selector

  • Smart Selection: Drag and select a rectangular area of tiles.
  • Multiple Tilesets: Support for multiple tilesets per project (planned).
  • Auto-import: Automatically detects tile size from the imported image.

✅ Engine Integration

  • Workspace Selection: Link the editor to your PixelRoot32 projects directory.
  • Direct Export: Files are generated with the correct namespaces and structures for immediate use.
  • BPP Compatibility: Ensures exported data matches the engine's expected format for 1bpp, 2bpp, and 4bpp.

Data Formats

Project File (.pr32scene)

The editor uses a custom JSON-based format to save your project state, including:

  • Tileset metadata (path, tile size, spacing).
  • Layer data (tile indices, width, height, position).
  • Project settings (BPP, namespace).

Exported C++

The editor generates <namespace>.h and <namespace>.cpp files containing:

  • Tilemap Data: One packed array of tile indices per layer (*_INDICES[]). Each layer is exposed as a TileMap4bpp (or TileMap2bpp/TileMap) with an indices pointer; use the same data for rendering and for tile-based collision in your game code.
  • Tilemap Structures: pixelroot32::graphics::TileMap (or TileMap2bpp/TileMap4bpp) definitions, plus tileset pool and palette.
  • Export options: Store data in Flash (ESP32) (default) emits static data with PROGMEM to reduce RAM use; Legacy format disables Flash attributes for backward compatibility or non-ESP32 builds.
  • Scene init: Call init() once before drawing; the generated code registers the palette and configures each layer for the engine.
\ No newline at end of file + Tilemap Editor Overview - PixelRoot32 Documentation

Tilemap Editor Overview

The PixelRoot32 Tilemap Editor is a powerful visual tool designed to create complex multi-layered tile-based maps for the PixelRoot32 engine. It simplifies the process of designing game environments, managing tilesets, and exporting optimized C++ code.

What It Does

The Tilemap Editor allows you to:

  • Visual Design: Paint tiles directly onto a canvas with layers and transparency.
  • Tileset Management: Import PNG images as tilesets and select single or multiple tiles.
  • Multi-Layer Support: Organize your map into up to 8 layers for parallax effects or depth.
  • Optimized Export: Generate C++ header and source files compatible with the PixelRoot32 renderer.
  • BPP Support: Export maps in 1bpp, 2bpp, or 4bpp formats to balance memory usage and color depth.

Key Features

✅ Visual Editing Tools

  • Brush: Paint individual tiles or patterns.
  • Eraser: Remove tiles from the active layer.
  • Rectangle Fill: Quickly fill areas with a specific tile.
  • Pipette: Pick an existing tile from the canvas.

✅ Multi-Layer System

  • Visibility Toggle: Hide/show layers to focus on specific parts of the map.
  • Opacity Control: Adjust layer transparency for complex blending effects.
  • Layer Reordering: Change the render order of your tilemaps.

✅ Tileset Selector

  • Smart Selection: Drag and select a rectangular area of tiles.
  • Multiple Tilesets: Support for multiple tilesets per project (planned).
  • Auto-import: Automatically detects tile size from the imported image.

✅ Engine Integration

  • Workspace Selection: Link the editor to your PixelRoot32 projects directory.
  • Direct Export: Files are generated with the correct namespaces and structures for immediate use.
  • BPP Compatibility: Ensures exported data matches the engine's expected format for 1bpp, 2bpp, and 4bpp.

Data Formats

Project File (.pr32scene)

The editor uses a custom JSON-based format to save your project state, including:

  • Tileset metadata (path, tile size, spacing).
  • Layer data (tile indices, width, height, position).
  • Project settings (BPP, namespace).

Exported C++

The editor generates <namespace>.h and <namespace>.cpp files containing:

  • Tilemap Data: One packed array of tile indices per layer (*_INDICES[]). Each layer is exposed as a TileMap4bpp (or TileMap2bpp/TileMap) with an indices pointer; use the same data for rendering and for tile-based collision in your game code.
  • Tilemap Structures: pixelroot32::graphics::TileMap (or TileMap2bpp/TileMap4bpp) definitions, plus tileset pool and palette.
  • Export options: Store data in Flash (ESP32) (default) emits static data with PROGMEM to reduce RAM use; Legacy format disables Flash attributes for backward compatibility or non-ESP32 builds.
  • Scene init: Call init() once before drawing; the generated code registers the palette and configures each layer for the engine.
\ No newline at end of file diff --git a/site/tools/tilemap_editor/usage_guide/index.html b/site/tools/tilemap_editor/usage_guide/index.html index 05de26a..e870840 100644 --- a/site/tools/tilemap_editor/usage_guide/index.html +++ b/site/tools/tilemap_editor/usage_guide/index.html @@ -1 +1 @@ - Usage Guide - PixelRoot32 Documentation

Usage Guide

This guide covers the basic workflow for creating and exporting a tilemap using the PixelRoot32 Tilemap Editor.

1. Creating a New Project

  1. Launch the editor.
  2. Go to File > New Project.
  3. Enter the project name and select the base Color Depth (BPP):
  4. 1bpp: Monochrome (2 colors).
  5. 2bpp: 4 colors.
  6. 4bpp: 16 colors.
  7. Set the Tile Size (e.g., 8x8, 16x16).

2. Importing a Tileset

  1. In the Tileset panel, click on Load Tileset.
  2. Select a PNG image containing your tiles.
  3. The image will be sliced into tiles based on the tile size set in the project.

3. Painting Tiles

  1. Select a tile (or a range of tiles) from the Tileset panel.
  2. Select the Brush tool (Shortcut: B).
  3. Click and drag on the canvas to paint.
  4. Use the Layers panel to switch between different layers.

4. Selection and Transformations

  • Single Selection: Click on a tile in the tileset.
  • Area Selection: Click and drag in the tileset to select a rectangular block of tiles.
  • Pipette: Press P and click on the canvas to pick the tile under the cursor.

5. Exporting to C++

  1. Ensure you have at least one tileset imported.
  2. Click the Export button in the top right (or File > Export / Ctrl+E).
  3. In the export dialog:
  4. Set the C++ Namespace (e.g. forest_level); it defaults to the project name.
  5. Review the Color Depth (BPP); it is auto-detected from your tileset colors (1bpp, 2bpp, or 4bpp).
  6. Store data in Flash (ESP32): Checked by default; emits PROGMEM for palette, tileset, and layer data to reduce RAM on ESP32.
  7. Legacy format (no Flash attribute): Use for older projects or non-ESP32 builds.
  8. Click Export Now and choose the output directory.
  9. The editor generates:
  10. <namespace>.h: Declarations (e.g. TILE_SIZE, MAP_WIDTH, MAP_HEIGHT, layer TileMap4bpp externs, init()).
  11. <namespace>.cpp: Definitions (palette, tileset pool, layer indices, init() implementation). Use each layer's .indices in your game for drawing and tile-based collision.

6. Keyboard Shortcuts

Shortcut Action
B Brush Tool
E Eraser Tool
R Rectangle Fill Tool
P Pipette Tool
Space + Drag Pan Canvas
Mouse Wheel Zoom In/Out
Ctrl + N New Project
Ctrl + S Save Project
Ctrl + E Export Project
Esc Close floating panels
\ No newline at end of file + Usage Guide - PixelRoot32 Documentation

Usage Guide

This guide covers the basic workflow for creating and exporting a tilemap using the PixelRoot32 Tilemap Editor.

1. Creating a New Project

  1. Launch the editor.
  2. Go to File > New Project.
  3. Enter the project name and select the base Color Depth (BPP):
  4. 1bpp: Monochrome (2 colors).
  5. 2bpp: 4 colors.
  6. 4bpp: 16 colors.
  7. Set the Tile Size (e.g., 8x8, 16x16).

2. Importing a Tileset

  1. In the Tileset panel, click on Load Tileset.
  2. Select a PNG image containing your tiles.
  3. The image will be sliced into tiles based on the tile size set in the project.

3. Painting Tiles

  1. Select a tile (or a range of tiles) from the Tileset panel.
  2. Select the Brush tool (Shortcut: B).
  3. Click and drag on the canvas to paint.
  4. Use the Layers panel to switch between different layers.

4. Selection and Transformations

  • Single Selection: Click on a tile in the tileset.
  • Area Selection: Click and drag in the tileset to select a rectangular block of tiles.
  • Pipette: Press P and click on the canvas to pick the tile under the cursor.

5. Exporting to C++

  1. Ensure you have at least one tileset imported.
  2. Click the Export button in the top right (or File > Export / Ctrl+E).
  3. In the export dialog:
  4. Set the C++ Namespace (e.g. forest_level); it defaults to the project name.
  5. Review the Color Depth (BPP); it is auto-detected from your tileset colors (1bpp, 2bpp, or 4bpp).
  6. Store data in Flash (ESP32): Checked by default; emits PROGMEM for palette, tileset, and layer data to reduce RAM on ESP32.
  7. Legacy format (no Flash attribute): Use for older projects or non-ESP32 builds.
  8. Click Export Now and choose the output directory.
  9. The editor generates:
  10. <namespace>.h: Declarations (e.g. TILE_SIZE, MAP_WIDTH, MAP_HEIGHT, layer TileMap4bpp externs, init()).
  11. <namespace>.cpp: Definitions (palette, tileset pool, layer indices, init() implementation). Use each layer's .indices in your game for drawing and tile-based collision.

6. Keyboard Shortcuts

Shortcut Action
B Brush Tool
E Eraser Tool
R Rectangle Fill Tool
P Pipette Tool
Space + Drag Pan Canvas
Mouse Wheel Zoom In/Out
Ctrl + N New Project
Ctrl + S Save Project
Ctrl + E Export Project
Esc Close floating panels
\ No newline at end of file From 55c05fbd6aa63b760998418b3aa3b709451b4fcb Mon Sep 17 00:00:00 2001 From: Gperez88 Date: Fri, 30 Jan 2026 16:51:26 -0400 Subject: [PATCH 3/7] docs: add hardware recommendation for high FPS in resolution scaling guide Add note about 128x128 physical display being required for 30+ FPS in high-action games, as larger displays are limited by SPI bus speed. --- docs/manual/advanced_graphics/resolution_scaling.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/manual/advanced_graphics/resolution_scaling.md b/docs/manual/advanced_graphics/resolution_scaling.md index da6f0a2..18205a6 100644 --- a/docs/manual/advanced_graphics/resolution_scaling.md +++ b/docs/manual/advanced_graphics/resolution_scaling.md @@ -108,4 +108,5 @@ This will output the time taken for scaling and transfer to the Serial monitor: 1. **Aspect Ratio**: Keep the logical aspect ratio the same as the physical one to avoid stretching. 2. **Integer Multiples**: For the sharpest results, try to use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen). -3. **UI Positioning**: Use [UIAnchorLayout](file:///c:/Users/gperez88/Documents/Proyects/Games/pixelroot32%20workspace/PixelRoot32-Docs/docs/api_reference/ui/ui_layouts/anchor_layout.md) to ensure your UI elements stay correctly positioned regardless of the logical resolution chosen. +3. **Hardware Recommendation**: For high-action games requiring 30+ FPS (like the Metroidvania sample), it is highly recommended to use a **128x128 physical display**. Larger displays like 240x240 are limited to ~14 FPS by the 40MHz SPI bus, regardless of the logical resolution used. +4. **UI Positioning**: Use [UIAnchorLayout](../../api_reference/ui/ui_layouts/anchor_layout.md) to ensure your UI elements stay correctly positioned regardless of the logical resolution chosen. From 827ca45ea50c8cbdb06999f69a94eff3dce3d60b Mon Sep 17 00:00:00 2001 From: Gperez88 Date: Sat, 31 Jan 2026 03:26:16 -0400 Subject: [PATCH 4/7] docs: update tilemap editor documentation for multi-scene support - Add description of multi-scene system with onion skinning feature - Update workflow to include scene management and onion skinning steps - Clarify that layers are now per-scene rather than global - Update export documentation for modular scene files and shared assets - Reorganize sections to reflect new multi-scene workflow --- docs/tools/tilemap_editor/overview.md | 18 +++++++++--- docs/tools/tilemap_editor/usage_guide.md | 35 +++++++++++++++++------- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/docs/tools/tilemap_editor/overview.md b/docs/tools/tilemap_editor/overview.md index a780988..e62120e 100644 --- a/docs/tools/tilemap_editor/overview.md +++ b/docs/tools/tilemap_editor/overview.md @@ -8,7 +8,9 @@ The Tilemap Editor allows you to: - **Visual Design**: Paint tiles directly onto a canvas with layers and transparency. - **Tileset Management**: Import PNG images as tilesets and select single or multiple tiles. -- **Multi-Layer Support**: Organize your map into up to 8 layers for parallax effects or depth. +- **Multi-Scene Support**: Create multiple scenes within a single project, sharing the same tilesets. +- **Onion Skinning**: Visualize adjacent scenes as translucent overlays for seamless transitions. +- **Multi-Layer Support**: Organize each scene into up to 8 layers for parallax effects or depth. - **Optimized Export**: Generate C++ header and source files compatible with the PixelRoot32 renderer. - **BPP Support**: Export maps in 1bpp, 2bpp, or 4bpp formats to balance memory usage and color depth. @@ -21,8 +23,15 @@ The Tilemap Editor allows you to: - **Rectangle Fill**: Quickly fill areas with a specific tile. - **Pipette**: Pick an existing tile from the canvas. +### ✅ Multi-Scene System + +- **Multiple Scenes**: Manage levels, rooms, or map sections within one project. +- **Onion Skinning**: Overlay other scenes with adjustable opacity to ensure continuity. +- **Independent Dimensions**: Each scene can have its own width and height. + ### ✅ Multi-Layer System +- **Per-Scene Layers**: Each scene maintains its own independent stack of up to 8 layers. - **Visibility Toggle**: Hide/show layers to focus on specific parts of the map. - **Opacity Control**: Adjust layer transparency for complex blending effects. - **Layer Reordering**: Change the render order of your tilemaps. @@ -51,9 +60,10 @@ The editor uses a custom JSON-based format to save your project state, including ### Exported C++ -The editor generates `.h` and `.cpp` files containing: +The editor generates modular C++ files for each scene: +- **Scene Files**: `scene_.h` and `scene_.cpp` for each individual scene. +- **Global Header**: `scenes.h` acts as a master entry point. - **Tilemap Data**: One packed array of tile indices per layer (`*_INDICES[]`). Each layer is exposed as a `TileMap4bpp` (or `TileMap2bpp`/`TileMap`) with an `indices` pointer; use the same data for rendering and for tile-based collision in your game code. -- **Tilemap Structures**: `pixelroot32::graphics::TileMap` (or `TileMap2bpp`/`TileMap4bpp`) definitions, plus tileset pool and palette. +- **Global Assets**: Tilesets and palettes are exported once and shared across all scenes to minimize memory footprint. - **Export options**: **Store data in Flash (ESP32)** (default) emits static data with `PROGMEM` to reduce RAM use; **Legacy format** disables Flash attributes for backward compatibility or non-ESP32 builds. -- **Scene init**: Call `init()` once before drawing; the generated code registers the palette and configures each layer for the engine. diff --git a/docs/tools/tilemap_editor/usage_guide.md b/docs/tools/tilemap_editor/usage_guide.md index 5b270ec..39af663 100644 --- a/docs/tools/tilemap_editor/usage_guide.md +++ b/docs/tools/tilemap_editor/usage_guide.md @@ -18,22 +18,35 @@ This guide covers the basic workflow for creating and exporting a tilemap using 2. Select a PNG image containing your tiles. 3. The image will be sliced into tiles based on the tile size set in the project. -## 3. Painting Tiles +## 3. Managing Scenes + +1. In the **Scenes** panel, click the **+** button to add a new scene. +2. Select a scene from the list to make it active. +3. Use the icons to **rename**, **delete**, or **duplicate** scenes. +4. Adjust the dimensions of the active scene via the **Settings** cog in the toolbar. + +## 4. Using Onion Skinning + +1. To see another scene behind your active one, click the **Onion** icon (layers icon) next to that scene in the **Scenes** list. +2. Ensure the **Show Onion Skin** master checkbox is enabled. +3. Use the **Opacity Slider** at the bottom of the panel to adjust the visibility of the overlays. + +## 5. Painting Tiles 1. Select a tile (or a range of tiles) from the **Tileset** panel. 2. Select the **Brush** tool (Shortcut: `B`). -3. Click and drag on the canvas to paint. -4. Use the **Layers** panel to switch between different layers. +3. Click and drag on the canvas to paint on the **active scene's** layers. +4. Use the **Layers** panel to switch between different layers of the **active scene**. -## 4. Selection and Transformations +## 6. Selection and Transformations - **Single Selection**: Click on a tile in the tileset. - **Area Selection**: Click and drag in the tileset to select a rectangular block of tiles. - **Pipette**: Press `P` and click on the canvas to pick the tile under the cursor. -## 5. Exporting to C++ +## 7. Exporting to C++ -1. Ensure you have at least one **tileset** imported. +1. Ensure you have at least one **tileset** imported and at least one **scene** designed. 2. Click the **Export** button in the top right (or **File > Export** / **Ctrl+E**). 3. In the export dialog: - Set the **C++ Namespace** (e.g. `forest_level`); it defaults to the project name. @@ -41,11 +54,13 @@ This guide covers the basic workflow for creating and exporting a tilemap using - **Store data in Flash (ESP32)**: Checked by default; emits `PROGMEM` for palette, tileset, and layer data to reduce RAM on ESP32. - **Legacy format (no Flash attribute)**: Use for older projects or non-ESP32 builds. 4. Click **Export Now** and choose the output directory. -5. The editor generates: - - `.h`: Declarations (e.g. `TILE_SIZE`, `MAP_WIDTH`, `MAP_HEIGHT`, layer `TileMap4bpp` externs, `init()`). - - `.cpp`: Definitions (palette, tileset pool, layer indices, `init()` implementation). Use each layer's `.indices` in your game for drawing and tile-based collision. +5. The editor generates a modular output: + - `scene_.h / .cpp`: Independent data files for each scene. + - `scenes.h`: Master entry point including all scenes. + - Global assets (shared tilesets and palettes) are exported once. + - Each layer is exported as a `TileMap` object (BPP-specific) with its own indices array. -## 6. Keyboard Shortcuts +## 8. Keyboard Shortcuts | Shortcut | Action | | :--- | :--- | From 705dfc96a6f6955cec66d4d06a1e093e5bc1162c Mon Sep 17 00:00:00 2001 From: Gperez88 Date: Sat, 31 Jan 2026 04:10:19 -0400 Subject: [PATCH 5/7] docs: add fixed position UI documentation for HUDs Add documentation for the new fixed position UI feature that allows creating HUDs and overlays that stay fixed on screen regardless of camera movement. The update includes API reference documentation for setFixedPosition/isFixedPosition methods in UILayout and corresponding renderer methods, plus a practical usage example in the user interface manual. --- docs/api_reference/graphics/renderer.md | 18 +++++++++++++++ docs/api_reference/ui/ui_layout.md | 17 ++++++++++++++ .../manual/game_development/user_interface.md | 22 ++++++++++++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/docs/api_reference/graphics/renderer.md b/docs/api_reference/graphics/renderer.md index 2ef5c15..43deb46 100644 --- a/docs/api_reference/graphics/renderer.md +++ b/docs/api_reference/graphics/renderer.md @@ -104,6 +104,24 @@ Finalizes the frame and sends the buffer to the display. - Sends the completed frame buffer to the display - Typically called automatically by `Engine`, but can be called manually +### void setOffsetBypass(bool bypass) + +Enables or disables camera offset bypass. + +**Parameters:** +- `bypass` (bool): `true` to ignore global offsets, `false` to apply them. + +**Notes:** +- When enabled, all subsequent draw calls will ignore `xOffset` and `yOffset`. +- Useful for drawing fixed UI elements that should not move with the camera. + +### bool isOffsetBypassEnabled() const + +Checks if the offset bypass is currently active. + +**Returns:** +- `bool`: `true` if bypass is enabled. + ### DrawSurface& getDrawSurface() Gets the underlying DrawSurface implementation. diff --git a/docs/api_reference/ui/ui_layout.md b/docs/api_reference/ui/ui_layout.md index 978581a..472c376 100644 --- a/docs/api_reference/ui/ui_layout.md +++ b/docs/api_reference/ui/ui_layout.md @@ -132,6 +132,23 @@ Clears all elements from the layout. - Elements are not deleted (you must manage their lifetimes) - Layout is automatically recalculated +### void setFixedPosition(bool fixed) + +Enables or disables fixed positioning for the layout. + +**Parameters:** +- `fixed` (bool): `true` to stay fixed on screen, `false` to move with the camera. + +**Notes:** +- When enabled, the layout will automatically bypass camera offsets during its `draw()` cycle. + +### bool isFixedPosition() const + +Checks if the layout is in fixed position mode. + +**Returns:** +- `bool`: `true` if fixed positioning is enabled. + ## Protected Members - `std::vector elements`: List of child elements diff --git a/docs/manual/game_development/user_interface.md b/docs/manual/game_development/user_interface.md index 55c733f..2efe46c 100644 --- a/docs/manual/game_development/user_interface.md +++ b/docs/manual/game_development/user_interface.md @@ -487,7 +487,27 @@ public: - **Use appropriate layouts**: Choose the right layout for your needs - **Limit element count**: Too many elements can impact performance -### Navigation +### Fixed Position UI (HUDs & Overlays) + +By default, UI elements placed in a scene will move with the `Camera2D` just like any other entity. To create a HUD or a menu that stays fixed on the screen regardless of camera movement, use the `fixedPosition` flag on your layouts: + +```cpp +// Create a HUD layout +pixelroot32::graphics::ui::UIVerticalLayout* hud = new pixelroot32::graphics::ui::UIVerticalLayout(10, 10, 100, 50); + +// Enable fixed positioning +hud->setFixedPosition(true); // <--- This layout will now ignore Camera2D scrolling + +// Add to scene +addEntity(hud); +``` + +When `setFixedPosition(true)` is called: +1. The layout and all its children will ignore the global camera offset. +2. The coordinates (x, y) of the layout become relative to the screen, not the world. +3. This is the recommended way to implement HUDs, pause menus, and screen-space overlays. + +## Navigation - **Set navigation buttons**: Configure D-pad navigation for layouts - **Handle input in update()**: Check for button presses to trigger actions From 7387797fd550d005d2732120f78e418cfbd57052 Mon Sep 17 00:00:00 2001 From: Gperez88 Date: Sat, 31 Jan 2026 04:32:08 -0400 Subject: [PATCH 6/7] docs: add documentation for fixed position UI/HUDs Add documentation for the new setFixedPosition/isFixedPosition API methods and explain how to create fixed-position UI elements that don't scroll with the camera. Include practical examples for HUD implementation and update related documentation files. --- docs/api_reference/ui/ui_element.md | 18 +++++++++++ .../ui/ui_layouts/anchor_layout.md | 2 ++ .../manual/game_development/user_interface.md | 32 ++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/docs/api_reference/ui/ui_element.md b/docs/api_reference/ui/ui_element.md index b9567df..57d4d8f 100644 --- a/docs/api_reference/ui/ui_element.md +++ b/docs/api_reference/ui/ui_element.md @@ -101,6 +101,24 @@ Sets the position of the element. uiElement->setPosition(100.0f, 50.0f); ``` +### void setFixedPosition(bool fixed) + +Sets whether the element is in a fixed position (HUD/Overlay). + +**Parameters:** +- `fixed` (bool): `true` to enable fixed position, `false` to disable. + +**Notes:** +- If `true`, this element (and its children if it's a container) will ignore `Camera2D` scroll and stay fixed at its logical screen coordinates. +- This is essential for HUDs, overlays, and persistent menus. + +### bool isFixedPosition() const + +Checks if the element is in a fixed position. + +**Returns:** +- `bool`: `true` if fixed position is enabled. + ### virtual void getPreferredSize(float& preferredWidth, float& preferredHeight) const Gets the preferred size of the element. Used by layouts to determine how much space the element needs. diff --git a/docs/api_reference/ui/ui_layouts/anchor_layout.md b/docs/api_reference/ui/ui_layouts/anchor_layout.md index 6fcafba..9a0b8dc 100644 --- a/docs/api_reference/ui/ui_layouts/anchor_layout.md +++ b/docs/api_reference/ui/ui_layouts/anchor_layout.md @@ -8,6 +8,8 @@ Layout that positions elements at fixed anchor points on the screen. This layout is ideal for HUD elements like score, lives, health bars, and other fixed-position UI. +> **Tip:** For HUDs, remember to call `setFixedPosition(true)` on the layout so it doesn't move when the camera scrolls. + ## Namespace ```cpp diff --git a/docs/manual/game_development/user_interface.md b/docs/manual/game_development/user_interface.md index 2efe46c..00d88f6 100644 --- a/docs/manual/game_development/user_interface.md +++ b/docs/manual/game_development/user_interface.md @@ -293,13 +293,43 @@ container->setPadding(10); // Or set asymmetric padding container->setPadding(5, 15, 10, 10); // left, right, top, bottom - +```cpp // Add child element container->setChild(button); addEntity(container); ``` +## Fixed Position UI (HUDs) + +By default, UI elements behave like world objects: if you move the `Camera2D`, the UI elements will scroll with the world. For elements that should stay fixed on screen (like a HUD, health bar, or pause menu), you can use the `fixedPosition` property. + +When `setFixedPosition(true)` is called on an element: +1. It ignores any `Camera2D` offsets (xOffset/yOffset). +2. It remains at its logical screen coordinates regardless of camera movement. +3. If the element is a layout (like `UIAnchorLayout`), all its children will also become fixed on screen. + +### Example: Fixed HUD + +```cpp +// Create an anchor layout for HUD +pixelroot32::graphics::ui::UIAnchorLayout* hud = new pixelroot32::graphics::ui::UIAnchorLayout(0, 0, 240, 240); +hud->setScreenSize(240, 240); + +// IMPORTANT: Make the HUD stay fixed on screen +hud->setFixedPosition(true); + +// Add health label at TOP_LEFT +UILabel* healthLabel = new UILabel("HP: 100", 0, 0, Color::Red, 1); +hud->addElement(healthLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT); + +// Add score label at TOP_RIGHT +UILabel* scoreLabel = new UILabel("Score: 0", 0, 0, Color::White, 1); +hud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT); + +addEntity(hud); +``` + ## Navigation Layouts handle D-pad navigation automatically: From bbc731a04632745a4a4b47da8ff4ca2f1dae8321 Mon Sep 17 00:00:00 2001 From: Gperez88 Date: Sat, 31 Jan 2026 04:50:50 -0400 Subject: [PATCH 7/7] docs: update API overview links and regenerate site Update relative links in API overview documentation to use correct path prefix. Regenerate static site files including sitemap with updated timestamps. --- docs/reference/api_overview.md | 118 +++--- .../audio/audio_config/index.html | 2 +- .../audio/audio_engine/index.html | 2 +- .../audio/audio_types/index.html | 2 +- .../audio/music_player/index.html | 2 +- site/api_reference/core/actor/index.html | 2 +- site/api_reference/core/engine/index.html | 4 +- site/api_reference/core/entity/index.html | 2 +- .../core/input_config/index.html | 2 +- .../core/input_manager/index.html | 2 +- .../core/physics_actor/index.html | 2 +- site/api_reference/core/scene/index.html | 2 +- .../graphics/camera2d/index.html | 2 +- site/api_reference/graphics/color/index.html | 2 +- .../graphics/display_config/index.html | 4 +- site/api_reference/graphics/font/index.html | 2 +- .../graphics/renderer/index.html | 6 +- site/api_reference/graphics/sprite/index.html | 2 +- .../api_reference/graphics/tilemap/index.html | 2 +- .../physics/collision_system/index.html | 2 +- .../physics/collision_types/index.html | 2 +- site/api_reference/ui/ui_button/index.html | 2 +- site/api_reference/ui/ui_checkbox/index.html | 2 +- site/api_reference/ui/ui_element/index.html | 6 +- site/api_reference/ui/ui_label/index.html | 2 +- site/api_reference/ui/ui_layout/index.html | 4 +- .../ui/ui_layouts/anchor_layout/index.html | 4 +- .../ui/ui_layouts/grid_layout/index.html | 2 +- .../ui_layouts/horizontal_layout/index.html | 2 +- .../ui_layouts/padding_container/index.html | 2 +- .../ui/ui_layouts/panel/index.html | 2 +- .../ui/ui_layouts/vertical_layout/index.html | 2 +- .../fundamental_concepts/index.html | 2 +- site/getting_started/installation/index.html | 2 +- .../what_is_pixelroot32/index.html | 2 +- .../why_pixelroot32/index.html | 2 +- .../your_first_project/index.html | 2 +- site/index.html | 2 +- .../cameras_and_scrolling/index.html | 2 +- .../color_palettes/index.html | 2 +- .../particles_and_effects/index.html | 2 +- .../resolution_scaling/index.html | 4 +- .../sprites_and_animation/index.html | 2 +- .../advanced_graphics/tilemaps/index.html | 2 +- site/manual/game_development/audio/index.html | 2 +- .../basic_rendering/index.html | 2 +- .../input_and_control/index.html | 2 +- .../physics_and_collisions/index.html | 2 +- .../scenes_and_entities/index.html | 2 +- .../user_interface/index.html | 364 ++++++++++-------- .../optimization/extensibility/index.html | 2 +- .../optimization/memory_management/index.html | 2 +- .../performance_tuning/index.html | 2 +- .../platforms_and_drivers/index.html | 2 +- site/reference/api_overview/index.html | 4 +- site/reference/code_examples/index.html | 2 +- site/reference/game_examples_guide/index.html | 2 +- site/resources/available_tools/index.html | 2 +- site/resources/faq/index.html | 2 +- .../limitations_and_considerations/index.html | 2 +- site/resources/troubleshooting/index.html | 2 +- site/search/search_index.json | 2 +- site/sitemap.xml | 134 +++---- site/sitemap.xml.gz | Bin 872 -> 872 bytes .../advanced_features/index.html | 2 +- .../sprite_compiler/installation/index.html | 2 +- .../tools/sprite_compiler/overview/index.html | 2 +- .../sprite_compiler/usage_guide/index.html | 2 +- .../tilemap_editor/installation/index.html | 2 +- site/tools/tilemap_editor/overview/index.html | 2 +- .../tilemap_editor/usage_guide/index.html | 2 +- 71 files changed, 397 insertions(+), 373 deletions(-) diff --git a/docs/reference/api_overview.md b/docs/reference/api_overview.md index 50442e2..716ca1e 100644 --- a/docs/reference/api_overview.md +++ b/docs/reference/api_overview.md @@ -18,42 +18,42 @@ The API is organized into the following modules: ### Core Module -- [Engine](api_reference/core/engine.md) - Main engine class, game loop management -- [Scene](api_reference/core/scene.md) - Scene/level management -- [Entity](api_reference/core/entity.md) - Base game object class -- [Actor](api_reference/core/actor.md) - Entity with collision support -- [PhysicsActor](api_reference/core/physics_actor.md) - Actor with automatic physics -- [InputManager](api_reference/core/input_manager.md) - Input handling -- [InputConfig](api_reference/core/input_config.md) - Input configuration +- [Engine](../api_reference/core/engine.md) - Main engine class, game loop management +- [Scene](../api_reference/core/scene.md) - Scene/level management +- [Entity](../api_reference/core/entity.md) - Base game object class +- [Actor](../api_reference/core/actor.md) - Entity with collision support +- [PhysicsActor](../api_reference/core/physics_actor.md) - Actor with automatic physics +- [InputManager](../api_reference/core/input_manager.md) - Input handling +- [InputConfig](../api_reference/core/input_config.md) - Input configuration ### Graphics Module -- [Renderer](api_reference/graphics/renderer.md) - High-level rendering API -- [Camera2D](api_reference/graphics/camera2d.md) - 2D camera for scrolling -- [Color](api_reference/graphics/color.md) - Color constants and utilities -- [Font](api_reference/graphics/font.md) - Bitmap font system -- [Sprite](api_reference/graphics/sprite.md) - Sprite structures and formats -- [TileMap](api_reference/graphics/tilemap.md) - Tilemap structure -- [DisplayConfig](api_reference/graphics/display_config.md) - Display configuration +- [Renderer](../api_reference/graphics/renderer.md) - High-level rendering API +- [Camera2D](../api_reference/graphics/camera2d.md) - 2D camera for scrolling +- [Color](../api_reference/graphics/color.md) - Color constants and utilities +- [Font](../api_reference/graphics/font.md) - Bitmap font system +- [Sprite](../api_reference/graphics/sprite.md) - Sprite structures and formats +- [TileMap](../api_reference/graphics/tilemap.md) - Tilemap structure +- [DisplayConfig](../api_reference/graphics/display_config.md) - Display configuration ### Audio Module -- [AudioEngine](api_reference/audio/audio_engine.md) - Sound effects playback -- [MusicPlayer](api_reference/audio/music_player.md) - Background music playback -- [AudioTypes](api_reference/audio/audio_types.md) - Audio data structures -- [AudioConfig](api_reference/audio/audio_config.md) - Audio configuration +- [AudioEngine](../api_reference/audio/audio_engine.md) - Sound effects playback +- [MusicPlayer](../api_reference/audio/music_player.md) - Background music playback +- [AudioTypes](../api_reference/audio/audio_types.md) - Audio data structures +- [AudioConfig](../api_reference/audio/audio_config.md) - Audio configuration ### Physics Module -- [CollisionSystem](api_reference/physics/collision_system.md) - Collision detection -- [CollisionTypes](api_reference/physics/collision_types.md) - Collision primitives +- [CollisionSystem](../api_reference/physics/collision_system.md) - Collision detection +- [CollisionTypes](../api_reference/physics/collision_types.md) - Collision primitives ### UI Module -- [UIElement](api_reference/ui/ui_element.md) - Base UI element class -- [UIButton](api_reference/ui/ui_button.md) - Clickable button -- [UILabel](api_reference/ui/ui_label.md) - Text label -- [UILayouts](api_reference/ui/ui_layouts/) - Layout containers +- [UIElement](../api_reference/ui/ui_element.md) - Base UI element class +- [UIButton](../api_reference/ui/ui_button.md) - Clickable button +- [UILabel](../api_reference/ui/ui_label.md) - Text label +- [UILayouts](../api_reference/ui/ui_layouts/) - Layout containers ## API Documentation Format @@ -107,12 +107,12 @@ Links to related APIs and documentation. ### By Functionality -- **Game Loop**: See [Engine](api_reference/core/engine.md) -- **Rendering**: See [Renderer](api_reference/graphics/renderer.md) -- **Input**: See [InputManager](api_reference/core/input_manager.md) -- **Audio**: See [AudioEngine](api_reference/audio/audio_engine.md) and [MusicPlayer](api_reference/audio/music_player.md) -- **Physics**: See [PhysicsActor](api_reference/core/physics_actor.md) and [CollisionSystem](api_reference/physics/collision_system.md) -- **UI**: See [UIElement](api_reference/ui/ui_element.md) and layouts +- **Game Loop**: See [Engine](../api_reference/core/engine.md) +- **Rendering**: See [Renderer](../api_reference/graphics/renderer.md) +- **Input**: See [InputManager](../api_reference/core/input_manager.md) +- **Audio**: See [AudioEngine](../api_reference/audio/audio_engine.md) and [MusicPlayer](../api_reference/audio/music_player.md) +- **Physics**: See [PhysicsActor](../api_reference/core/physics_actor.md) and [CollisionSystem](../api_reference/physics/collision_system.md) +- **UI**: See [UIElement](../api_reference/ui/ui_element.md) and layouts ### By Module @@ -127,47 +127,47 @@ Navigate to the specific module folder: ### Core -- [Engine](api_reference/core/engine.md) -- [Scene](api_reference/core/scene.md) -- [Entity](api_reference/core/entity.md) -- [Actor](api_reference/core/actor.md) -- [PhysicsActor](api_reference/core/physics_actor.md) -- [InputManager](api_reference/core/input_manager.md) -- [InputConfig](api_reference/core/input_config.md) +- [Engine](../api_reference/core/engine.md) +- [Scene](../api_reference/core/scene.md) +- [Entity](../api_reference/core/entity.md) +- [Actor](../api_reference/core/actor.md) +- [PhysicsActor](../api_reference/core/physics_actor.md) +- [InputManager](../api_reference/core/input_manager.md) +- [InputConfig](../api_reference/core/input_config.md) ### Graphics -- [Renderer](api_reference/graphics/renderer.md) -- [Camera2D](api_reference/graphics/camera2d.md) -- [Color](api_reference/graphics/color.md) -- [Font](api_reference/graphics/font.md) -- [Sprite](api_reference/graphics/sprite.md) -- [TileMap](api_reference/graphics/tilemap.md) -- [DisplayConfig](api_reference/graphics/display_config.md) +- [Renderer](../api_reference/graphics/renderer.md) +- [Camera2D](../api_reference/graphics/camera2d.md) +- [Color](../api_reference/graphics/color.md) +- [Font](../api_reference/graphics/font.md) +- [Sprite](../api_reference/graphics/sprite.md) +- [TileMap](../api_reference/graphics/tilemap.md) +- [DisplayConfig](../api_reference/graphics/display_config.md) ### Audio -- [AudioEngine](api_reference/audio/audio_engine.md) -- [MusicPlayer](api_reference/audio/music_player.md) -- [AudioTypes](api_reference/audio/audio_types.md) -- [AudioConfig](api_reference/audio/audio_config.md) +- [AudioEngine](../api_reference/audio/audio_engine.md) +- [MusicPlayer](../api_reference/audio/music_player.md) +- [AudioTypes](../api_reference/audio/audio_types.md) +- [AudioConfig](../api_reference/audio/audio_config.md) ### Physics -- [CollisionSystem](api_reference/physics/collision_system.md) -- [CollisionTypes](api_reference/physics/collision_types.md) +- [CollisionSystem](../api_reference/physics/collision_system.md) +- [CollisionTypes](../api_reference/physics/collision_types.md) ### UI -- [UIElement](api_reference/ui/ui_element.md) -- [UIButton](api_reference/ui/ui_button.md) -- [UILabel](api_reference/ui/ui_label.md) -- [UIVerticalLayout](api_reference/ui/ui_layouts/vertical_layout.md) -- [UIHorizontalLayout](api_reference/ui/ui_layouts/horizontal_layout.md) -- [UIGridLayout](api_reference/ui/ui_layouts/grid_layout.md) -- [UIAnchorLayout](api_reference/ui/ui_layouts/anchor_layout.md) -- [UIPanel](api_reference/ui/ui_layouts/panel.md) -- [UIPaddingContainer](api_reference/ui/ui_layouts/padding_container.md) +- [UIElement](../api_reference/ui/ui_element.md) +- [UIButton](../api_reference/ui/ui_button.md) +- [UILabel](../api_reference/ui/ui_label.md) +- [UIVerticalLayout](../api_reference/ui/ui_layouts/vertical_layout.md) +- [UIHorizontalLayout](../api_reference/ui/ui_layouts/horizontal_layout.md) +- [UIGridLayout](../api_reference/ui/ui_layouts/grid_layout.md) +- [UIAnchorLayout](../api_reference/ui/ui_layouts/anchor_layout.md) +- [UIPanel](../api_reference/ui/ui_layouts/panel.md) +- [UIPaddingContainer](../api_reference/ui/ui_layouts/padding_container.md) ## Related Documentation diff --git a/site/api_reference/audio/audio_config/index.html b/site/api_reference/audio/audio_config/index.html index 4b421d2..70dca54 100644 --- a/site/api_reference/audio/audio_config/index.html +++ b/site/api_reference/audio/audio_config/index.html @@ -84,4 +84,4 @@ engine.init(); engine.run(); } -

Platform-Specific Considerations

ESP32 DAC Backend

  • Sample rate: 11025 Hz recommended (lower CPU usage)
  • Quality: Lower quality, but simple setup
  • Pin: Uses GPIO 25 or 26
  • Hardware: Requires simple amplifier circuit

ESP32 I2S Backend

  • Sample rate: 22050 Hz recommended
  • Quality: Higher quality than DAC
  • Pins: Requires I2S pins (BCLK, LRCK, DOUT)
  • Hardware: Requires external I2S DAC

Native SDL2 Backend

  • Sample rate: 44100 Hz typical
  • Quality: High quality
  • Setup: Requires SDL2 library installed
  • Platforms: Windows, Linux, macOS

Performance Considerations

  • Sample rate: Lower rates use less CPU and memory
  • Backend choice: DAC is simpler but lower quality than I2S
  • Buffer size: Configured in backend, affects latency vs stability

See Also

\ No newline at end of file +

Platform-Specific Considerations

ESP32 DAC Backend

  • Sample rate: 11025 Hz recommended (lower CPU usage)
  • Quality: Lower quality, but simple setup
  • Pin: Uses GPIO 25 or 26
  • Hardware: Requires simple amplifier circuit

ESP32 I2S Backend

  • Sample rate: 22050 Hz recommended
  • Quality: Higher quality than DAC
  • Pins: Requires I2S pins (BCLK, LRCK, DOUT)
  • Hardware: Requires external I2S DAC

Native SDL2 Backend

  • Sample rate: 44100 Hz typical
  • Quality: High quality
  • Setup: Requires SDL2 library installed
  • Platforms: Windows, Linux, macOS

Performance Considerations

  • Sample rate: Lower rates use less CPU and memory
  • Backend choice: DAC is simpler but lower quality than I2S
  • Buffer size: Configured in backend, affects latency vs stability

See Also

\ No newline at end of file diff --git a/site/api_reference/audio/audio_engine/index.html b/site/api_reference/audio/audio_engine/index.html index 2892842..a85d918 100644 --- a/site/api_reference/audio/audio_engine/index.html +++ b/site/api_reference/audio/audio_engine/index.html @@ -88,4 +88,4 @@ } } }; -

Performance Considerations

  • Channel limit: Only 4 channels total; plan sound effects accordingly
  • Event dropping: If all channels are busy, new events are silently dropped
  • Update frequency: update() must be called every frame for proper timing
  • Sample generation: generateSamples() is called by backend at audio rate (not game rate)

ESP32 Considerations

  • Sample rate: Lower sample rates (11025 Hz) use less CPU and memory
  • Backend choice: DAC backend is simpler but lower quality than I2S
  • Buffer size: Larger buffers reduce underruns but increase latency
  • Channel management: Limit simultaneous sounds to avoid channel conflicts

See Also

\ No newline at end of file +

Performance Considerations

  • Channel limit: Only 4 channels total; plan sound effects accordingly
  • Event dropping: If all channels are busy, new events are silently dropped
  • Update frequency: update() must be called every frame for proper timing
  • Sample generation: generateSamples() is called by backend at audio rate (not game rate)

ESP32 Considerations

  • Sample rate: Lower sample rates (11025 Hz) use less CPU and memory
  • Backend choice: DAC backend is simpler but lower quality than I2S
  • Buffer size: Larger buffers reduce underruns but increase latency
  • Channel management: Limit simultaneous sounds to avoid channel conflicts

See Also

\ No newline at end of file diff --git a/site/api_reference/audio/audio_types/index.html b/site/api_reference/audio/audio_types/index.html index a3babbb..663de8a 100644 --- a/site/api_reference/audio/audio_types/index.html +++ b/site/api_reference/audio/audio_types/index.html @@ -97,4 +97,4 @@ delay(50); // Small delay between events } } -

Performance Considerations

  • Event creation: Creating events is fast (just struct initialization)
  • Channel allocation: Events are queued and played when channels are available
  • Frequency range: Keep frequencies in reasonable range (100-5000 Hz) for best results
  • Duration: Shorter durations free channels faster

ESP32 Considerations

  • Memory: Events are small structs, safe to create frequently
  • CPU: Audio generation is efficient but limit simultaneous sounds
  • Quality: Lower sample rates reduce CPU usage

See Also

\ No newline at end of file +

Performance Considerations

  • Event creation: Creating events is fast (just struct initialization)
  • Channel allocation: Events are queued and played when channels are available
  • Frequency range: Keep frequencies in reasonable range (100-5000 Hz) for best results
  • Duration: Shorter durations free channels faster

ESP32 Considerations

  • Memory: Events are small structs, safe to create frequently
  • CPU: Audio generation is efficient but limit simultaneous sounds
  • Quality: Lower sample rates reduce CPU usage

See Also

\ No newline at end of file diff --git a/site/api_reference/audio/music_player/index.html b/site/api_reference/audio/music_player/index.html index 36e7aab..1e9f0ae 100644 --- a/site/api_reference/audio/music_player/index.html +++ b/site/api_reference/audio/music_player/index.html @@ -106,4 +106,4 @@ music.stop(); } }; -

Performance Considerations

  • One channel: Music uses one channel, leaving others for sound effects
  • Update frequency: update() must be called every frame
  • Track size: Larger tracks use more memory (store in flash)
  • Tempo factor: Changing tempo is fast (just a multiplier)

ESP32 Considerations

  • Memory: Store tracks in flash (const/constexpr) to save RAM
  • CPU: Music playback is lightweight (simple sequencing)
  • Channel conflict: Music and sound effects share channels; plan accordingly

See Also

\ No newline at end of file +

Performance Considerations

  • One channel: Music uses one channel, leaving others for sound effects
  • Update frequency: update() must be called every frame
  • Track size: Larger tracks use more memory (store in flash)
  • Tempo factor: Changing tempo is fast (just a multiplier)

ESP32 Considerations

  • Memory: Store tracks in flash (const/constexpr) to save RAM
  • CPU: Music playback is lightweight (simple sequencing)
  • Channel conflict: Music and sound effects share channels; plan accordingly

See Also

\ No newline at end of file diff --git a/site/api_reference/core/actor/index.html b/site/api_reference/core/actor/index.html index a017b6d..f63c896 100644 --- a/site/api_reference/core/actor/index.html +++ b/site/api_reference/core/actor/index.html @@ -126,4 +126,4 @@ } } }; -

Performance Considerations

  • Collision layers: Use layers efficiently to reduce collision checks
  • Hitbox size: Keep hitboxes simple (AABB) for best performance
  • Collision callbacks: Keep onCollision() fast; avoid expensive operations
  • Layer organization: Group actors by layer to minimize checks

ESP32 Considerations

  • Collision checks: Collision system automatically optimizes using layers
  • Memory: Each actor consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse actors instead of creating/destroying frequently

See Also

\ No newline at end of file +

Performance Considerations

  • Collision layers: Use layers efficiently to reduce collision checks
  • Hitbox size: Keep hitboxes simple (AABB) for best performance
  • Collision callbacks: Keep onCollision() fast; avoid expensive operations
  • Layer organization: Group actors by layer to minimize checks

ESP32 Considerations

  • Collision checks: Collision system automatically optimizes using layers
  • Memory: Each actor consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse actors instead of creating/destroying frequently

See Also

\ No newline at end of file diff --git a/site/api_reference/core/engine/index.html b/site/api_reference/core/engine/index.html index 7ec40dd..3de0d5c 100644 --- a/site/api_reference/core/engine/index.html +++ b/site/api_reference/core/engine/index.html @@ -85,7 +85,7 @@ auto& music = engine.getMusicPlayer(); music.playTrack(myMusicTrack); } -

Optional: Debug Statistics Overlay

When the engine is built with the preprocessor define PIXELROOT32_ENABLE_DEBUG_OVERLAY, an on-screen technical overlay is drawn each frame.

Metrics Included:

  • FPS: Frames per second (Green).
  • RAM: Used heap memory in KB (Cyan).
  • CPU: Estimated processor load percentage (Yellow).

Behavior:

  • The overlay is drawn in the top-right area of the screen.
  • It is rendered after the scene, making it fixed and independent of the camera.

Performance:

  • Metric values are recalculated and formatted only every 16 frames (DEBUG_UPDATE_INTERVAL).
  • Cached strings are drawn every frame to minimize per-frame cost (division and snprintf).

How to enable:

In platformio.ini, add to your environment's build_flags:

build_flags =
+

Optional: Debug Statistics Overlay

When the engine is built with the preprocessor define PIXELROOT32_ENABLE_DEBUG_OVERLAY, an on-screen technical overlay is drawn each frame.

Metrics Included:

  • FPS: Frames per second (Green).
  • RAM: Used heap memory in KB (Cyan).
  • CPU: Estimated processor load percentage (Yellow).

Platform Differences & CPU Metric

The CPU Load metric is an estimation based on the processing time vs. a 60 FPS target (16.6ms).

  • On ESP32: This is a realistic representation of how much time the CPU is spending on engine logic within its power limits.
  • On Native (PC): This metric may frequently show 100% or high values even if your PC is idle. This happens because the native loop is synchronized with the monitor's VSYNC (via SDL2), which often causes the frame time to exceed 16.6ms (e.g., 33ms for 30 FPS). This is a result of the operating system's scheduling and SDL's synchronization, not actual hardware saturation.

Behavior:

  • The overlay is drawn in the top-right area of the screen.
  • It is rendered after the scene, making it fixed and independent of the camera.

Performance:

  • Metric values are recalculated and formatted only every 16 frames (DEBUG_UPDATE_INTERVAL).
  • Cached strings are drawn every frame to minimize per-frame cost (division and snprintf).

How to enable:

In platformio.ini, add to your environment's build_flags:

build_flags =
     -D PIXELROOT32_ENABLE_DEBUG_OVERLAY
 

Alternatively, you can enable it in EngineConfig.h. The implementation uses the private method drawDebugOverlay(Renderer& r), which is only compiled when the define is set.

See also: Performance Tuning - Profiling and Platforms and Drivers - Build flags.

Usage Example

#include "core/Engine.h"
 #include "graphics/DisplayConfig.h"
@@ -111,4 +111,4 @@
     // Run game loop
     engine.run();
 }
-

Performance Considerations

  • Initialization: init() should be called once at startup, not in the game loop
  • Scene switching: Switching scenes is fast but avoid doing it every frame
  • Subsystem access: Getters are inline and very fast; safe to call every frame
  • Delta time: Use getDeltaTime() for frame-rate independent movement

ESP32 Considerations

  • Ensure init() completes before run() to avoid initialization issues
  • Monitor memory usage when switching scenes frequently
  • Use getDeltaTime() for consistent gameplay across different frame rates

See Also

\ No newline at end of file +

Performance Considerations

  • Initialization: init() should be called once at startup, not in the game loop
  • Scene switching: Switching scenes is fast but avoid doing it every frame
  • Subsystem access: Getters are inline and very fast; safe to call every frame
  • Delta time: Use getDeltaTime() for frame-rate independent movement

ESP32 Considerations

  • Ensure init() completes before run() to avoid initialization issues
  • Monitor memory usage when switching scenes frequently
  • Use getDeltaTime() for consistent gameplay across different frame rates

See Also

\ No newline at end of file diff --git a/site/api_reference/core/entity/index.html b/site/api_reference/core/entity/index.html index 2d0fd9d..2fa17d1 100644 --- a/site/api_reference/core/entity/index.html +++ b/site/api_reference/core/entity/index.html @@ -84,4 +84,4 @@ private: float rotation = 0.0f; }; -

Performance Considerations

  • Visibility: Use isVisible = false instead of removing entities when hiding
  • Enable state: Use isEnabled = false to pause entity logic
  • Render layers: Organize entities by layer to minimize layer switches
  • Direct access: Direct property access is fast (no function call overhead)

ESP32 Considerations

  • Memory: Each entity consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse entities instead of creating/destroying frequently
  • Update frequency: Disable entities that don't need to update every frame

See Also

\ No newline at end of file +

Performance Considerations

  • Visibility: Use isVisible = false instead of removing entities when hiding
  • Enable state: Use isEnabled = false to pause entity logic
  • Render layers: Organize entities by layer to minimize layer switches
  • Direct access: Direct property access is fast (no function call overhead)

ESP32 Considerations

  • Memory: Each entity consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse entities instead of creating/destroying frequently
  • Update frequency: Disable entities that don't need to update every frame

See Also

\ No newline at end of file diff --git a/site/api_reference/core/input_config/index.html b/site/api_reference/core/input_config/index.html index 24222be..9875736 100644 --- a/site/api_reference/core/input_config/index.html +++ b/site/api_reference/core/input_config/index.html @@ -117,4 +117,4 @@ SDL_SCANCODE_SPACE, // Jump SDL_SCANCODE_RETURN // Action ); -

Performance Considerations

  • Memory: Arrays are allocated dynamically (small overhead)
  • Configuration: Done once at startup, no runtime cost
  • Access: Button indices are fast (array access)

ESP32 Considerations

  • Pin configuration: Ensure pins are not used by other peripherals
  • Debouncing: Hardware debouncing recommended for reliable input
  • Power: Buttons should use pull-up resistors to avoid floating pins

See Also

\ No newline at end of file +

Performance Considerations

  • Memory: Arrays are allocated dynamically (small overhead)
  • Configuration: Done once at startup, no runtime cost
  • Access: Button indices are fast (array access)

ESP32 Considerations

  • Pin configuration: Ensure pins are not used by other peripherals
  • Debouncing: Hardware debouncing recommended for reliable input
  • Power: Buttons should use pull-up resistors to avoid floating pins

See Also

\ No newline at end of file diff --git a/site/api_reference/core/input_manager/index.html b/site/api_reference/core/input_manager/index.html index d420d9b..cd7a1f8 100644 --- a/site/api_reference/core/input_manager/index.html +++ b/site/api_reference/core/input_manager/index.html @@ -126,4 +126,4 @@ } } }; -

Input State Comparison

Method Returns true when Use Case
isButtonPressed() Button just pressed this frame One-time actions (jump, shoot)
isButtonReleased() Button just released this frame Release events (stop charging)
isButtonClicked() Button pressed then released UI buttons, menu selection
isButtonDown() Button currently held Continuous actions (movement)

Performance Considerations

  • Update frequency: update() must be called every frame
  • Debouncing: Handled automatically, no performance impact
  • State queries: All query methods are fast (inline accessors)
  • Memory: Button state arrays are small and efficient

ESP32 Considerations

  • GPIO pins: Configure pins in InputConfig
  • Pull-up/pull-down: Ensure proper resistor configuration
  • Debouncing: Hardware debouncing recommended for noisy buttons
  • Pin limits: Some ESP32 pins have restrictions (check datasheet)

Native Considerations

  • Keyboard mapping: Uses SDL scancodes
  • Key detection: Automatically handles keyboard state
  • Multiple keys: Can detect multiple keys simultaneously

See Also

\ No newline at end of file +

Input State Comparison

Method Returns true when Use Case
isButtonPressed() Button just pressed this frame One-time actions (jump, shoot)
isButtonReleased() Button just released this frame Release events (stop charging)
isButtonClicked() Button pressed then released UI buttons, menu selection
isButtonDown() Button currently held Continuous actions (movement)

Performance Considerations

  • Update frequency: update() must be called every frame
  • Debouncing: Handled automatically, no performance impact
  • State queries: All query methods are fast (inline accessors)
  • Memory: Button state arrays are small and efficient

ESP32 Considerations

  • GPIO pins: Configure pins in InputConfig
  • Pull-up/pull-down: Ensure proper resistor configuration
  • Debouncing: Hardware debouncing recommended for noisy buttons
  • Pin limits: Some ESP32 pins have restrictions (check datasheet)

Native Considerations

  • Keyboard mapping: Uses SDL scancodes
  • Key detection: Automatically handles keyboard state
  • Multiple keys: Can detect multiple keys simultaneously

See Also

\ No newline at end of file diff --git a/site/api_reference/core/physics_actor/index.html b/site/api_reference/core/physics_actor/index.html index 8c23ddc..b352d87 100644 --- a/site/api_reference/core/physics_actor/index.html +++ b/site/api_reference/core/physics_actor/index.html @@ -154,4 +154,4 @@ playBounceSound(); } }; -

Performance Considerations

  • Physics integration: Very efficient (simple velocity integration)
  • World bounds: Boundary checks are fast (AABB)
  • Friction: Applied every frame; keep friction values reasonable
  • Collision callbacks: Keep onCollision() and onWorldCollision() fast

ESP32 Considerations

  • Floating point: Uses float math; acceptable for ESP32 but integer math would be faster
  • Frame rate: Physics is frame-rate independent (uses deltaTime)
  • Memory: Each PhysicsActor consumes more memory than Actor (velocity, limits, etc.)

See Also

\ No newline at end of file +

Performance Considerations

  • Physics integration: Very efficient (simple velocity integration)
  • World bounds: Boundary checks are fast (AABB)
  • Friction: Applied every frame; keep friction values reasonable
  • Collision callbacks: Keep onCollision() and onWorldCollision() fast

ESP32 Considerations

  • Floating point: Uses float math; acceptable for ESP32 but integer math would be faster
  • Frame rate: Physics is frame-rate independent (uses deltaTime)
  • Memory: Each PhysicsActor consumes more memory than Actor (velocity, limits, etc.)

See Also

\ No newline at end of file diff --git a/site/api_reference/core/scene/index.html b/site/api_reference/core/scene/index.html index 477fbf4..00c4a04 100644 --- a/site/api_reference/core/scene/index.html +++ b/site/api_reference/core/scene/index.html @@ -128,4 +128,4 @@ renderer.drawText(scoreText, 10, 10, Color::White, 1); } }; -

Performance Considerations

  • Entity limit: MAX_ENTITIES (default 32) can be overridden via compiler flags; plan accordingly
  • Add/Remove: Frequent add/remove operations can be expensive; use object pooling
  • Update order: Entities are updated in add order; consider order for dependencies
  • Collision checks: CollisionSystem automatically handles actor collisions efficiently

ESP32 Considerations

  • Memory: Each entity consumes memory; stay well below the limit
  • Object pooling: Essential for ESP32 to avoid memory fragmentation
  • Scene switching: Clearing and recreating scenes can fragment memory; reuse scenes when possible

See Also

\ No newline at end of file +

Performance Considerations

  • Entity limit: MAX_ENTITIES (default 32) can be overridden via compiler flags; plan accordingly
  • Add/Remove: Frequent add/remove operations can be expensive; use object pooling
  • Update order: Entities are updated in add order; consider order for dependencies
  • Collision checks: CollisionSystem automatically handles actor collisions efficiently

ESP32 Considerations

  • Memory: Each entity consumes memory; stay well below the limit
  • Object pooling: Essential for ESP32 to avoid memory fragmentation
  • Scene switching: Clearing and recreating scenes can fragment memory; reuse scenes when possible

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/camera2d/index.html b/site/api_reference/graphics/camera2d/index.html index 39bb9d8..90113c9 100644 --- a/site/api_reference/graphics/camera2d/index.html +++ b/site/api_reference/graphics/camera2d/index.html @@ -120,4 +120,4 @@ renderer.setDisplayOffset(0, 0); renderer.drawText("Score: 100", 10, 10, Color::White, 1); } -

Performance Considerations

  • Apply frequency: apply() is fast; safe to call every frame
  • Boundary checks: Boundary clamping is efficient
  • Following: Dead-zone calculations are lightweight

ESP32 Considerations

  • Float math: Uses floating point; acceptable but integer math would be faster
  • Memory: Camera is small (few floats); minimal memory usage

See Also

\ No newline at end of file +

Performance Considerations

  • Apply frequency: apply() is fast; safe to call every frame
  • Boundary checks: Boundary clamping is efficient
  • Following: Dead-zone calculations are lightweight

ESP32 Considerations

  • Float math: Uses floating point; acceptable but integer math would be faster
  • Memory: Camera is small (few floats); minimal memory usage

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/color/index.html b/site/api_reference/graphics/color/index.html index b127f79..c1200aa 100644 --- a/site/api_reference/graphics/color/index.html +++ b/site/api_reference/graphics/color/index.html @@ -70,4 +70,4 @@ pixelroot32::graphics::enableDualPaletteMode(true); pixelroot32::graphics::setBackgroundCustomPalette(CUSTOM_PALETTE); pixelroot32::graphics::setSpriteCustomPalette(CUSTOM_PALETTE); -

Performance Considerations

  • Color resolution: Fast lookup operation
  • Palette switching: Changing palettes is fast (just pointer assignment)
  • Memory: Palettes are stored in flash (const arrays) for best performance
  • Dual mode: Slightly more overhead than legacy mode, but minimal

ESP32 Considerations

  • Flash storage: Store custom palettes in flash (const/constexpr)
  • Memory: Palettes are small (16 uint16_t = 32 bytes)
  • Palette switching: Avoid switching palettes every frame

See Also

\ No newline at end of file +

Performance Considerations

  • Color resolution: Fast lookup operation
  • Palette switching: Changing palettes is fast (just pointer assignment)
  • Memory: Palettes are stored in flash (const arrays) for best performance
  • Dual mode: Slightly more overhead than legacy mode, but minimal

ESP32 Considerations

  • Flash storage: Store custom palettes in flash (const/constexpr)
  • Memory: Palettes are small (16 uint16_t = 32 bytes)
  • Palette switching: Avoid switching palettes every frame

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/display_config/index.html b/site/api_reference/graphics/display_config/index.html index 1c2a7a9..5609896 100644 --- a/site/api_reference/graphics/display_config/index.html +++ b/site/api_reference/graphics/display_config/index.html @@ -3,7 +3,7 @@ // ... }; } -

DisplayType Enum

Supported display types:

  • DisplayType::ST7789: 240x240 TFT display
  • DisplayType::ST7735: 128x128 TFT display
  • DisplayType::NONE: For SDL2 native (no driver needed)

Structure

DisplayType type

The type of display.

Type: DisplayType enum

Access: Read-write

Notes: - Determines which driver to use (ESP32) - NONE for Native/SDL2 platform

int rotation

Display rotation in degrees.

Type: int

Access: Read-write

Default: 0

Notes: - Common values: 0, 90, 180, 270 - Rotation is applied during initialization - Some displays may not support all rotations

uint16_t physicalWidth

Physical hardware width of the display.

Type: uint16_t

Access: Read-write

Notes: - Defines the actual resolution of the display hardware.

uint16_t physicalHeight

Physical hardware height of the display.

Type: uint16_t

Access: Read-write

Notes: - Defines the actual resolution of the display hardware.

uint16_t logicalWidth

Logical rendering width. This is the resolution the game "sees" and draws to.

Type: uint16_t

Access: Read-write

Notes: - If smaller than physicalWidth, the image will be scaled up. - Used for clipping, camera, and UI calculations. - Recommended values for ESP32: 160, 128, 96 (for 240 physical).

uint16_t logicalHeight

Logical rendering height. This is the resolution the game "sees" and draws to.

Type: uint16_t

Access: Read-write

Notes: - If smaller than physicalHeight, the image will be scaled up. - Used for clipping, camera, and UI calculations.

uint16_t width() (Deprecated)

Alias for logicalWidth. Maintained for backward compatibility.

uint16_t height() (Deprecated)

Alias for logicalHeight. Maintained for backward compatibility.

int xOffset

X offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

int yOffset

Y offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

DrawSurface& getDrawSurface() const

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed - Provides access to low-level display driver - Platform-specific implementation

Resolution Helpers

bool needsScaling() const

Checks if the logical resolution differs from the physical resolution.

Returns: - bool: true if scaling is active.

float getScaleX() const

Gets the horizontal scaling factor (physicalWidth / logicalWidth).

float getScaleY() const

Gets the vertical scaling factor (physicalHeight / logicalHeight).

Constructors

DisplayConfig(DisplayType type, const int rot, uint16_t physW, uint16_t physH, uint16_t logW, uint16_t logH, const int xOff = 0, const int yOff = 0)

Extended constructor that allows defining separate physical and logical resolutions.

Parameters: - type (DisplayType): The display type. - rot (int): Rotation (0-3 or degrees depending on implementation). - physW (uint16_t): Physical hardware width. - physH (uint16_t): Physical hardware height. - logW (uint16_t): Logical rendering width (0 = same as physical). - logH (uint16_t): Logical rendering height (0 = same as physical). - xOff (int, optional): X alignment offset. - yOff (int, optional): Y alignment offset.

Example:

// 128x128 game logic scaled to 240x240 display
+

DisplayType Enum

Supported display types:

  • DisplayType::ST7789: 240x240 TFT display
  • DisplayType::ST7735: 128x128 TFT display
  • DisplayType::NONE: For SDL2 native (no driver needed)

Structure

DisplayType type

The type of display.

Type: DisplayType enum

Access: Read-write

Notes: - Determines which driver to use (ESP32) - NONE for Native/SDL2 platform

int rotation

Display rotation. Supports both index-based (0-3) and degree-based (0, 90, 180, 270) values.

Type: int

Access: Read-write

Default: 0

Notes: - 0: Normal orientation (0°) - 1 or 90: Rotated 90 degrees clockwise - 2 or 180: Rotated 180 degrees - 3 or 270: Rotated 90 degrees counter-clockwise (270°) - Rotation is applied during initialization. - On ESP32, this affects both the hardware display orientation and the internal framebuffer. - On Native (SDL2), this rotates the rendered texture before presenting it.

uint16_t physicalWidth

Physical hardware width of the display.

Type: uint16_t

Access: Read-write

Notes: - Defines the actual resolution of the display hardware.

uint16_t physicalHeight

Physical hardware height of the display.

Type: uint16_t

Access: Read-write

Notes: - Defines the actual resolution of the display hardware.

uint16_t logicalWidth

Logical rendering width. This is the resolution the game "sees" and draws to.

Type: uint16_t

Access: Read-write

Notes: - If smaller than physicalWidth, the image will be scaled up. - Used for clipping, camera, and UI calculations. - Recommended values for ESP32: 160, 128, 96 (for 240 physical).

uint16_t logicalHeight

Logical rendering height. This is the resolution the game "sees" and draws to.

Type: uint16_t

Access: Read-write

Notes: - If smaller than physicalHeight, the image will be scaled up. - Used for clipping, camera, and UI calculations.

uint16_t width() (Deprecated)

Alias for logicalWidth. Maintained for backward compatibility.

uint16_t height() (Deprecated)

Alias for logicalHeight. Maintained for backward compatibility.

int xOffset

X offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

int yOffset

Y offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

DrawSurface& getDrawSurface() const

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed - Provides access to low-level display driver - Platform-specific implementation

Resolution Helpers

bool needsScaling() const

Checks if the logical resolution differs from the physical resolution.

Returns: - bool: true if scaling is active.

float getScaleX() const

Gets the horizontal scaling factor (physicalWidth / logicalWidth).

float getScaleY() const

Gets the vertical scaling factor (physicalHeight / logicalHeight).

Constructors

DisplayConfig(DisplayType type, const int rot, uint16_t physW, uint16_t physH, uint16_t logW, uint16_t logH, const int xOff = 0, const int yOff = 0)

Extended constructor that allows defining separate physical and logical resolutions.

Parameters: - type (DisplayType): The display type. - rot (int): Rotation (0-3 or degrees depending on implementation). - physW (uint16_t): Physical hardware width. - physH (uint16_t): Physical hardware height. - logW (uint16_t): Logical rendering width (0 = same as physical). - logH (uint16_t): Logical rendering height (0 = same as physical). - xOff (int, optional): X alignment offset. - yOff (int, optional): Y alignment offset.

Example:

// 128x128 game logic scaled to 240x240 display
 pixelroot32::graphics::DisplayConfig config(
     pixelroot32::graphics::DisplayType::ST7789,
     0,    // rotation
@@ -96,4 +96,4 @@
     -DTFT_WIDTH=240
     -DTFT_HEIGHT=240
     # ... pin configuration
-

Pin Configuration

GPIO pins must be configured separately (not in DisplayConfig):

  • MOSI: Data pin
  • SCLK: Clock pin
  • DC: Data/Command pin
  • RST: Reset pin
  • CS: Chip select pin (optional)

See Also

\ No newline at end of file +

Pin Configuration

GPIO pins must be configured separately (not in DisplayConfig):

  • MOSI: Data pin
  • SCLK: Clock pin
  • DC: Data/Command pin
  • RST: Reset pin
  • CS: Chip select pin (optional)

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/font/index.html b/site/api_reference/graphics/font/index.html index 8536cf0..71bf60f 100644 --- a/site/api_reference/graphics/font/index.html +++ b/site/api_reference/graphics/font/index.html @@ -121,4 +121,4 @@ int getTextHeight(const Font* font) { return font ? font->lineHeight : 8; } -

Performance Considerations

  • Font storage: Store fonts in flash (const/constexpr) for best performance
  • Glyph lookup: Fast array access (character code - firstChar)
  • Fixed width: Fixed-width fonts are faster than variable-width
  • Font switching: Changing fonts is fast (just pointer assignment)

ESP32 Considerations

  • Memory: Store font data in flash, not RAM
  • Font size: Larger fonts use more flash memory
  • Character range: Limit character range to save memory if not needed

See Also

\ No newline at end of file +

Performance Considerations

  • Font storage: Store fonts in flash (const/constexpr) for best performance
  • Glyph lookup: Fast array access (character code - firstChar)
  • Fixed width: Fixed-width fonts are faster than variable-width
  • Font switching: Changing fonts is fast (just pointer assignment)

ESP32 Considerations

  • Memory: Store font data in flash, not RAM
  • Font size: Larger fonts use more flash memory
  • Character range: Limit character range to save memory if not needed

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/renderer/index.html b/site/api_reference/graphics/renderer/index.html index 421972e..9fa31b2 100644 --- a/site/api_reference/graphics/renderer/index.html +++ b/site/api_reference/graphics/renderer/index.html @@ -1,4 +1,4 @@ - Renderer - PixelRoot32 Documentation

Renderer

High-level graphics rendering system for drawing shapes, text, sprites, and tilemaps.

Description

The Renderer class provides a unified API for drawing shapes, text, and images. It abstracts the underlying hardware implementation (DrawSurface) and manages display configuration, including rotation and resolution scaling.

All drawing operations are performed in logical screen space. If the logical resolution differs from the physical resolution, the renderer will automatically scale the output to fit the display using a high-performance nearest-neighbor algorithm.

The renderer uses integer-only math for optimal performance on ESP32 and supports multiple sprite formats (1bpp, 2bpp, 4bpp) and multi-layer sprites.

Namespace

namespace pixelroot32::graphics {
+ Renderer - PixelRoot32 Documentation      

Renderer

High-level graphics rendering system for drawing shapes, text, sprites, and tilemaps.

Description

The Renderer class provides a unified API for drawing shapes, text, and images. It abstracts the underlying hardware implementation (DrawSurface) and manages display configuration, including rotation and resolution scaling.

All drawing operations are performed in logical screen space. If the logical resolution differs from the physical resolution, the renderer will automatically scale the output to fit the display using a high-performance nearest-neighbor algorithm.

The renderer uses integer-only math for optimal performance on ESP32 and supports multiple sprite formats (1bpp, 2bpp, 4bpp) and multi-layer sprites.

Namespace

namespace pixelroot32::graphics {
     class Renderer {
         // ...
     };
@@ -23,7 +23,7 @@
     // Draw everything...
     renderer.endFrame();
 }
-

void endFrame()

Finalizes the frame and sends the buffer to the display.

Returns: - void

Notes: - Should be called once at the end of each frame - Sends the completed frame buffer to the display - Typically called automatically by Engine, but can be called manually

DrawSurface& getDrawSurface()

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed unless implementing custom drawing - Provides low-level access to the display driver

void drawText(const char* text, int16_t x, int16_t y, Color color, uint8_t size)

Draws a string of text using the default font and scaling.

Parameters: - text (const char*): The text to draw (null-terminated string) - x (int16_t): X coordinate (top-left corner of text) - y (int16_t): Y coordinate (top-left corner of text) - color (Color): Text color - size (uint8_t): Text size multiplier (1 = 5x7 pixels, 2 = 10x14 pixels, etc.)

Performance Notes: - Efficient for small amounts of text - Uses integer-only scaling (no floats)

Example:

renderer.drawText("Hello World", 10, 10, Color::White, 1);
+

void endFrame()

Finalizes the frame and sends the buffer to the display.

Returns: - void

Notes: - Should be called once at the end of each frame - Sends the completed frame buffer to the display - Typically called automatically by Engine, but can be called manually

void setOffsetBypass(bool bypass)

Enables or disables camera offset bypass.

Parameters: - bypass (bool): true to ignore global offsets, false to apply them.

Notes: - When enabled, all subsequent draw calls will ignore xOffset and yOffset. - Useful for drawing fixed UI elements that should not move with the camera.

bool isOffsetBypassEnabled() const

Checks if the offset bypass is currently active.

Returns: - bool: true if bypass is enabled.

DrawSurface& getDrawSurface()

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed unless implementing custom drawing - Provides low-level access to the display driver

void drawText(const char* text, int16_t x, int16_t y, Color color, uint8_t size)

Draws a string of text using the default font and scaling.

Parameters: - text (const char*): The text to draw (null-terminated string) - x (int16_t): X coordinate (top-left corner of text) - y (int16_t): Y coordinate (top-left corner of text) - color (Color): Text color - size (uint8_t): Text size multiplier (1 = 5x7 pixels, 2 = 10x14 pixels, etc.)

Performance Notes: - Efficient for small amounts of text - Uses integer-only scaling (no floats)

Example:

renderer.drawText("Hello World", 10, 10, Color::White, 1);
 renderer.drawText("Score: 100", 10, 30, Color::Yellow, 2);
 

void drawText(const char text, int16_t x, int16_t y, Color color, uint8_t size, const Font font)

Draws a string of text using a specific font and scaling.

Parameters: - text (const char): The text to draw - x (int16_t): X coordinate - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size multiplier - font (const Font): Pointer to the font to use. If nullptr, uses the default font

Example:

const Font* customFont = &FONT_5X7;
 renderer.drawText("Custom Font", 10, 10, Color::White, 1, customFont);
@@ -91,4 +91,4 @@
 
     renderer.endFrame();
 }
-

Performance Considerations

  • Integer-only math: All operations use integer arithmetic for ESP32 efficiency
  • Sprite storage: Store sprite data in flash (const/constexpr) for best performance
  • Batch operations: Group similar draw calls together
  • Tilemaps: Dibuja un mapa de tiles completo. Implementa viewport culling automático y caché de paleta para máximo rendimiento.
  • Sprites 2bpp/4bpp: Optimizado para ESP32 (IRAM + acceso de 16 bits).

ESP32 Considerations

  • Memory: Sprite data should be in flash, not RAM
  • Frame rate: Limit draw calls per frame for consistent FPS
  • Display offset: Use for scrolling instead of redrawing everything

See Also

\ No newline at end of file +

Performance Considerations

  • Integer-only math: All operations use integer arithmetic for ESP32 efficiency
  • Sprite storage: Store sprite data in flash (const/constexpr) for best performance
  • Batch operations: Group similar draw calls together
  • Tilemaps: Dibuja un mapa de tiles completo. Implementa viewport culling automático y caché de paleta para máximo rendimiento.
  • Sprites 2bpp/4bpp: Optimizado para ESP32 (IRAM + acceso de 16 bits).

ESP32 Considerations

  • Memory: Sprite data should be in flash, not RAM
  • Frame rate: Limit draw calls per frame for consistent FPS
  • Display offset: Use for scrolling instead of redrawing everything

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/sprite/index.html b/site/api_reference/graphics/sprite/index.html index 12f5b7a..99797f3 100644 --- a/site/api_reference/graphics/sprite/index.html +++ b/site/api_reference/graphics/sprite/index.html @@ -153,4 +153,4 @@ // Draw flipped renderer.drawSprite(sprite, 100, 100, Color::White, true); -

Performance Considerations

  • 1bpp sprites: Most efficient (integer-only operations)
  • MultiSprite: Each layer is a separate draw call (still efficient)
  • 2bpp/4bpp: Experimental, uses more memory and CPU
  • Storage: Store sprite data in flash (const/constexpr) for best performance
  • Size limit: Sprites are limited to 16 pixels wide for 1bpp format

ESP32 Considerations

  • Memory: Store sprite data in flash, not RAM
  • Sprite size: Smaller sprites = faster drawing
  • Format choice: Use 1bpp when possible for best performance
  • MultiSprite: More layers = more draw calls (but acceptable)

See Also

\ No newline at end of file +

Performance Considerations

  • 1bpp sprites: Most efficient (integer-only operations)
  • MultiSprite: Each layer is a separate draw call (still efficient)
  • 2bpp/4bpp: Experimental, uses more memory and CPU
  • Storage: Store sprite data in flash (const/constexpr) for best performance
  • Size limit: Sprites are limited to 16 pixels wide for 1bpp format

ESP32 Considerations

  • Memory: Store sprite data in flash, not RAM
  • Sprite size: Smaller sprites = faster drawing
  • Format choice: Use 1bpp when possible for best performance
  • MultiSprite: More layers = more draw calls (but acceptable)

See Also

\ No newline at end of file diff --git a/site/api_reference/graphics/tilemap/index.html b/site/api_reference/graphics/tilemap/index.html index e19cbe0..c781821 100644 --- a/site/api_reference/graphics/tilemap/index.html +++ b/site/api_reference/graphics/tilemap/index.html @@ -182,4 +182,4 @@ return (tile == 1); // Wall tile } }; -

Performance Considerations

  • Viewport culling: Only visible tiles are drawn (automatic)
  • Tile reuse: Reuse tile sprites across the map
  • Index storage: Compact uint8_t indices (1 byte per tile)
  • Memory: Store indices and tiles in flash (const) for best performance
  • Tile size: Smaller tiles = more tiles to draw, but more detail

ESP32 Considerations

  • Memory: Store tilemap data in flash, not RAM
  • Map size: Large maps use more flash memory
  • Tile count: Limit unique tiles to save memory
  • Culling: Viewport culling is essential for large levels

See Also

\ No newline at end of file +

Performance Considerations

  • Viewport culling: Only visible tiles are drawn (automatic)
  • Tile reuse: Reuse tile sprites across the map
  • Index storage: Compact uint8_t indices (1 byte per tile)
  • Memory: Store indices and tiles in flash (const) for best performance
  • Tile size: Smaller tiles = more tiles to draw, but more detail

ESP32 Considerations

  • Memory: Store tilemap data in flash, not RAM
  • Map size: Large maps use more flash memory
  • Tile count: Limit unique tiles to save memory
  • Culling: Viewport culling is essential for large levels

See Also

\ No newline at end of file diff --git a/site/api_reference/physics/collision_system/index.html b/site/api_reference/physics/collision_system/index.html index 19cc268..359ea99 100644 --- a/site/api_reference/physics/collision_system/index.html +++ b/site/api_reference/physics/collision_system/index.html @@ -59,4 +59,4 @@ Scene::update(deltaTime); } }; -

Performance Considerations

  • Layer filtering: Very efficient; avoids most collision checks
  • AABB checks: Fast (simple rectangle intersection)
  • Pair checking: O(n²) complexity, but n is limited (MAX_ENTITIES = 32)
  • Update frequency: Called every frame; keep hitboxes simple

ESP32 Considerations

  • Entity limit: MAX_ENTITIES = 32 limits collision pairs
  • Layer efficiency: Use layers effectively to minimize checks
  • Hitbox simplicity: Keep hitboxes as simple AABB for best performance

See Also

\ No newline at end of file +

Performance Considerations

  • Layer filtering: Very efficient; avoids most collision checks
  • AABB checks: Fast (simple rectangle intersection)
  • Pair checking: O(n²) complexity, but n is limited (MAX_ENTITIES = 32)
  • Update frequency: Called every frame; keep hitboxes simple

ESP32 Considerations

  • Entity limit: MAX_ENTITIES = 32 limits collision pairs
  • Layer efficiency: Use layers effectively to minimize checks
  • Hitbox simplicity: Keep hitboxes as simple AABB for best performance

See Also

\ No newline at end of file diff --git a/site/api_reference/physics/collision_types/index.html b/site/api_reference/physics/collision_types/index.html index 73bf43c..0f933b9 100644 --- a/site/api_reference/physics/collision_types/index.html +++ b/site/api_reference/physics/collision_types/index.html @@ -99,4 +99,4 @@ return false; } }; -

Performance Considerations

  • AABB checks: Very fast (simple rectangle intersection)
  • Circle checks: Slightly slower (distance calculation)
  • Sweep tests: More expensive (use only for fast-moving objects)
  • Layer filtering: Essential for performance with many actors

ESP32 Considerations

  • Float math: Uses floating point; acceptable but integer math would be faster
  • Sweep tests: Use sparingly (more CPU intensive)
  • Layer efficiency: Use layers effectively to minimize checks

See Also

\ No newline at end of file +

Performance Considerations

  • AABB checks: Very fast (simple rectangle intersection)
  • Circle checks: Slightly slower (distance calculation)
  • Sweep tests: More expensive (use only for fast-moving objects)
  • Layer filtering: Essential for performance with many actors

ESP32 Considerations

  • Float math: Uses floating point; acceptable but integer math would be faster
  • Sweep tests: Use sparingly (more CPU intensive)
  • Layer efficiency: Use layers effectively to minimize checks

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_button/index.html b/site/api_reference/ui/ui_button/index.html index c63badf..75d92f9 100644 --- a/site/api_reference/ui/ui_button/index.html +++ b/site/api_reference/ui/ui_button/index.html @@ -131,4 +131,4 @@ // D-pad navigation is automatic // UP/DOWN moves selection // Action button (A) triggers selected button -

Performance Considerations

  • Input handling: handleInput() is fast; safe to call every frame
  • Rendering: Simple rectangle and text; very efficient
  • Memory: Each button consumes memory (stay within MAX_ENTITIES)

ESP32 Considerations

  • String storage: Button labels use std::string; consider memory usage
  • Callback functions: Use function pointers or lambdas (both efficient)

See Also

\ No newline at end of file +

Performance Considerations

  • Input handling: handleInput() is fast; safe to call every frame
  • Rendering: Simple rectangle and text; very efficient
  • Memory: Each button consumes memory (stay within MAX_ENTITIES)

ESP32 Considerations

  • String storage: Button labels use std::string; consider memory usage
  • Callback functions: Use function pointers or lambdas (both efficient)

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_checkbox/index.html b/site/api_reference/ui/ui_checkbox/index.html index 53a2688..f6d130d 100644 --- a/site/api_reference/ui/ui_checkbox/index.html +++ b/site/api_reference/ui/ui_checkbox/index.html @@ -26,4 +26,4 @@

Public Methods

void setStyle(Color textCol, Color bgCol, bool drawBg = false)

Configures the checkbox's visual style.

Parameters: - textCol (Color): Color of the text - bgCol (Color): Color of the background - drawBg (bool, optional): Whether to draw the background rectangle. Default: false

Returns: - void

void setChecked(bool checked)

Sets the checked state.

Parameters: - checked (bool): True if checked

Returns: - void

bool isChecked() const

Checks if the checkbox is currently checked.

Returns: - bool: true if checked

void toggle()

Toggles the checkbox state and triggers the callback.

Returns: - void

void setSelected(bool selected)

Sets the selection state (e.g., focused via D-pad).

Parameters: - selected (bool): True if selected

Returns: - void

bool getSelected() const

Checks if the checkbox is currently selected.

Returns: - bool: true if selected

Callbacks

onCheckChanged

The onCheckChanged callback is a std::function<void(bool)> that is triggered whenever the checkbox state changes via setChecked() or toggle().

checkbox->onCheckChanged = [](bool isChecked) {
     Serial.println(isChecked ? "Checked!" : "Unchecked!");
 };
-

UICheckBox is designed to work seamlessly with UILayout containers (like UIVerticalLayout).

  • Focusable: Returns true for isFocusable(), allowing it to receive focus in a layout.
  • Input Handling: When selected (focused), it listens for the button index provided in the constructor (typically the 'A' button) to toggle its state.
  • Visual Feedback: When selected, it displays a selection indicator (usually a > character) if no background is drawn, or highlights its text/border.
\ No newline at end of file +

UICheckBox is designed to work seamlessly with UILayout containers (like UIVerticalLayout).

  • Focusable: Returns true for isFocusable(), allowing it to receive focus in a layout.
  • Input Handling: When selected (focused), it listens for the button index provided in the constructor (typically the 'A' button) to toggle its state.
  • Visual Feedback: When selected, it displays a selection indicator (usually a > character) if no background is drawn, or highlights its text/border.
\ No newline at end of file diff --git a/site/api_reference/ui/ui_element/index.html b/site/api_reference/ui/ui_element/index.html index 48ce646..6c87bf6 100644 --- a/site/api_reference/ui/ui_element/index.html +++ b/site/api_reference/ui/ui_element/index.html @@ -1,4 +1,4 @@ - UIElement - PixelRoot32 Documentation

UIElement

Base class for all user interface elements.

Description

UIElement is the base class for all UI components (buttons, labels, panels, etc.). It inherits from Entity to integrate with the scene graph and automatically sets the entity type to UI_ELEMENT and render layer to 2 (UI layer).

Namespace

namespace pixelroot32::graphics::ui {
+ UIElement - PixelRoot32 Documentation      

UIElement

Base class for all user interface elements.

Description

UIElement is the base class for all UI components (buttons, labels, panels, etc.). It inherits from Entity to integrate with the scene graph and automatically sets the entity type to UI_ELEMENT and render layer to 2 (UI layer).

Namespace

namespace pixelroot32::graphics::ui {
     enum class UIElementType {
         GENERIC,
         BUTTON,
@@ -25,7 +25,7 @@
     }
 };
 

Public Methods

UIElementType getType() const

Returns the type of the UI element.

Returns: - UIElementType: The type enum value (GENERIC, BUTTON, LABEL, CHECKBOX, or LAYOUT)

virtual bool isFocusable() const

Checks if the element is focusable/selectable. Useful for navigation logic.

Returns: - bool: true if focusable, false otherwise (default: false)

void setPosition(float newX, float newY)

Sets the position of the element.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Updates element position immediately - Use for manual positioning or animations

Example:

uiElement->setPosition(100.0f, 50.0f);
-

virtual void getPreferredSize(float& preferredWidth, float& preferredHeight) const

Gets the preferred size of the element. Used by layouts to determine how much space the element needs.

Parameters: - preferredWidth (float&): Output parameter for preferred width (or -1 if flexible) - preferredHeight (float&): Output parameter for preferred height (or -1 if flexible)

Returns: - void

Notes: - Default implementation returns current width/height - Override in derived classes for custom sizing logic - Layouts use this to arrange elements

Example:

void getPreferredSize(float& w, float& h) const override {
+

void setFixedPosition(bool fixed)

Sets whether the element is in a fixed position (HUD/Overlay).

Parameters: - fixed (bool): true to enable fixed position, false to disable.

Notes: - If true, this element (and its children if it's a container) will ignore Camera2D scroll and stay fixed at its logical screen coordinates. - This is essential for HUDs, overlays, and persistent menus.

bool isFixedPosition() const

Checks if the element is in a fixed position.

Returns: - bool: true if fixed position is enabled.

virtual void getPreferredSize(float& preferredWidth, float& preferredHeight) const

Gets the preferred size of the element. Used by layouts to determine how much space the element needs.

Parameters: - preferredWidth (float&): Output parameter for preferred width (or -1 if flexible) - preferredHeight (float&): Output parameter for preferred height (or -1 if flexible)

Returns: - void

Notes: - Default implementation returns current width/height - Override in derived classes for custom sizing logic - Layouts use this to arrange elements

Example:

void getPreferredSize(float& w, float& h) const override {
     // Custom sizing logic
     w = static_cast<float>(width);
     h = static_cast<float>(height);
@@ -72,4 +72,4 @@
         h = static_cast<float>(height);
     }
 };
-

Performance Considerations

  • Render layer: UI elements are on layer 2, drawn after gameplay
  • Visibility: Use isVisible = false to hide elements efficiently
  • Layout integration: Layouts automatically manage element positioning

ESP32 Considerations

  • Memory: Each UI element consumes memory (stay within MAX_ENTITIES)
  • Object pooling: Reuse UI elements when possible
  • Update frequency: Disable UI elements that don't need to update

See Also

\ No newline at end of file +

Performance Considerations

  • Render layer: UI elements are on layer 2, drawn after gameplay
  • Visibility: Use isVisible = false to hide elements efficiently
  • Layout integration: Layouts automatically manage element positioning

ESP32 Considerations

  • Memory: Each UI element consumes memory (stay within MAX_ENTITIES)
  • Object pooling: Reuse UI elements when possible
  • Update frequency: Disable UI elements that don't need to update

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_label/index.html b/site/api_reference/ui/ui_label/index.html index 4d9c273..f2fc39c 100644 --- a/site/api_reference/ui/ui_label/index.html +++ b/site/api_reference/ui/ui_label/index.html @@ -96,4 +96,4 @@ ); title->centerX(128); // Center on screen addEntity(title); -

Performance Considerations

  • Text updates: setText() recalculates size; avoid calling every frame if text doesn't change
  • String storage: Uses std::string; consider memory on ESP32
  • Rendering: Simple text drawing; very efficient
  • Static text: For static text, create once and don't update

ESP32 Considerations

  • Memory: std::string uses heap memory; use static buffers when possible
  • Text updates: Limit frequency of text updates
  • String length: Keep text short to save memory

See Also

\ No newline at end of file +

Performance Considerations

  • Text updates: setText() recalculates size; avoid calling every frame if text doesn't change
  • String storage: Uses std::string; consider memory on ESP32
  • Rendering: Simple text drawing; very efficient
  • Static text: For static text, create once and don't update

ESP32 Considerations

  • Memory: std::string uses heap memory; use static buffers when possible
  • Text updates: Limit frequency of text updates
  • String length: Keep text short to save memory

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layout/index.html b/site/api_reference/ui/ui_layout/index.html index 8c4e74f..a4bc3b7 100644 --- a/site/api_reference/ui/ui_layout/index.html +++ b/site/api_reference/ui/ui_layout/index.html @@ -1,6 +1,6 @@ - UILayout - PixelRoot32 Documentation

UILayout

Base class for UI layout containers.

Description

UILayout is the base class for all layout containers. Layouts organize UI elements automatically, handling positioning, spacing, and optional scrolling. Layouts are themselves UI elements that can be added to scenes.

Namespace

namespace pixelroot32::graphics::ui {
+ UILayout - PixelRoot32 Documentation      

UILayout

Base class for UI layout containers.

Description

UILayout is the base class for all layout containers. Layouts organize UI elements automatically, handling positioning, spacing, and optional scrolling. Layouts are themselves UI elements that can be added to scenes.

Namespace

namespace pixelroot32::graphics::ui {
     class UILayout : public UIElement {
         // ...
     };
 }
-

Inheritance

  • Inherits from: UIElement
  • Inherited by: UIVerticalLayout, UIHorizontalLayout, UIGridLayout, UIAnchorLayout

ScrollBehavior Enum

Defines how scrolling behaves in layouts.

Values: - ScrollBehavior::NONE: No scrolling allowed - ScrollBehavior::SCROLL: Scroll freely within bounds - ScrollBehavior::CLAMP: Scroll but clamp to content bounds

Public Methods

virtual void addElement(UIElement* element) = 0

Adds a UI element to the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to add

virtual void removeElement(UIElement* element) = 0

Removes a UI element from the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to remove

virtual void updateLayout() = 0

Recalculates positions of all elements in the layout. Must be implemented by derived classes.

Returns: - void

Notes: - Should be called automatically when elements are added/removed

virtual void handleInput(const InputManager& input) = 0

Handles input for layout navigation (scroll, selection, etc.). Must be implemented by derived classes.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

void setPadding(float p)

Sets the padding (internal spacing) of the layout.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Layout is automatically recalculated

float getPadding() const

Gets the current padding.

Returns: - float: Padding value in pixels

void setSpacing(float s)

Sets the spacing between elements.

Parameters: - s (float): Spacing value in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Default: 4.0 pixels

float getSpacing() const

Gets the current spacing.

Returns: - float: Spacing value in pixels

size_t getElementCount() const

Gets the number of elements in the layout.

Returns: - size_t: Element count

UIElement* getElement(size_t index) const

Gets the element at a specific index.

Parameters: - index (size_t): Element index

Returns: - UIElement*: Pointer to the element, or nullptr if index is invalid

void clearElements()

Clears all elements from the layout.

Returns: - void

Notes: - Elements are not deleted (you must manage their lifetimes) - Layout is automatically recalculated

Protected Members

  • std::vector<UIElement*> elements: List of child elements
  • float padding: Internal padding
  • float spacing: Spacing between elements (default: 4.0)
  • float scrollOffset: Current scroll offset
  • bool enableScroll: Whether scrolling is enabled
  • ScrollBehavior scrollBehavior: Scroll behavior mode

See Also

\ No newline at end of file +

Inheritance

  • Inherits from: UIElement
  • Inherited by: UIVerticalLayout, UIHorizontalLayout, UIGridLayout, UIAnchorLayout

ScrollBehavior Enum

Defines how scrolling behaves in layouts.

Values: - ScrollBehavior::NONE: No scrolling allowed - ScrollBehavior::SCROLL: Scroll freely within bounds - ScrollBehavior::CLAMP: Scroll but clamp to content bounds

Public Methods

virtual void addElement(UIElement* element) = 0

Adds a UI element to the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to add

virtual void removeElement(UIElement* element) = 0

Removes a UI element from the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to remove

virtual void updateLayout() = 0

Recalculates positions of all elements in the layout. Must be implemented by derived classes.

Returns: - void

Notes: - Should be called automatically when elements are added/removed

virtual void handleInput(const InputManager& input) = 0

Handles input for layout navigation (scroll, selection, etc.). Must be implemented by derived classes.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

void setPadding(float p)

Sets the padding (internal spacing) of the layout.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Layout is automatically recalculated

float getPadding() const

Gets the current padding.

Returns: - float: Padding value in pixels

void setSpacing(float s)

Sets the spacing between elements.

Parameters: - s (float): Spacing value in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Default: 4.0 pixels

float getSpacing() const

Gets the current spacing.

Returns: - float: Spacing value in pixels

size_t getElementCount() const

Gets the number of elements in the layout.

Returns: - size_t: Element count

UIElement* getElement(size_t index) const

Gets the element at a specific index.

Parameters: - index (size_t): Element index

Returns: - UIElement*: Pointer to the element, or nullptr if index is invalid

void clearElements()

Clears all elements from the layout.

Returns: - void

Notes: - Elements are not deleted (you must manage their lifetimes) - Layout is automatically recalculated

void setFixedPosition(bool fixed)

Enables or disables fixed positioning for the layout.

Parameters: - fixed (bool): true to stay fixed on screen, false to move with the camera.

Notes: - When enabled, the layout will automatically bypass camera offsets during its draw() cycle.

bool isFixedPosition() const

Checks if the layout is in fixed position mode.

Returns: - bool: true if fixed positioning is enabled.

Protected Members

  • std::vector<UIElement*> elements: List of child elements
  • float padding: Internal padding
  • float spacing: Spacing between elements (default: 4.0)
  • float scrollOffset: Current scroll offset
  • bool enableScroll: Whether scrolling is enabled
  • ScrollBehavior scrollBehavior: Scroll behavior mode

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/anchor_layout/index.html b/site/api_reference/ui/ui_layouts/anchor_layout/index.html index eccc957..ee07286 100644 --- a/site/api_reference/ui/ui_layouts/anchor_layout/index.html +++ b/site/api_reference/ui/ui_layouts/anchor_layout/index.html @@ -1,4 +1,4 @@ - Anchor Layout - PixelRoot32 Documentation

UIAnchorLayout

Layout that positions elements at fixed anchor points on the screen.

Description

UIAnchorLayout positions UI elements at fixed anchor points (corners, center, edges) without reflow. Very efficient for HUDs, debug UI, and fixed-position elements. Positions are calculated once or when screen size changes.

This layout is ideal for HUD elements like score, lives, health bars, and other fixed-position UI.

Namespace

namespace pixelroot32::graphics::ui {
+ Anchor Layout - PixelRoot32 Documentation      

UIAnchorLayout

Layout that positions elements at fixed anchor points on the screen.

Description

UIAnchorLayout positions UI elements at fixed anchor points (corners, center, edges) without reflow. Very efficient for HUDs, debug UI, and fixed-position elements. Positions are calculated once or when screen size changes.

This layout is ideal for HUD elements like score, lives, health bars, and other fixed-position UI.

Tip: For HUDs, remember to call setFixedPosition(true) on the layout so it doesn't move when the camera scrolls.

Namespace

namespace pixelroot32::graphics::ui {
     class UIAnchorLayout : public UILayout {
         // ...
     };
@@ -89,4 +89,4 @@
         // HUD is drawn automatically (on layer 2)
     }
 };
-

Anchor Positioning

Elements are positioned based on their anchor:

  • TOP_LEFT: Element's top-left at screen top-left
  • TOP_RIGHT: Element's top-right at screen top-right
  • BOTTOM_LEFT: Element's bottom-left at screen bottom-left
  • BOTTOM_RIGHT: Element's bottom-right at screen bottom-right
  • CENTER: Element centered on screen
  • TOP_CENTER: Element centered horizontally, top-aligned
  • BOTTOM_CENTER: Element centered horizontally, bottom-aligned
  • LEFT_CENTER: Element centered vertically, left-aligned
  • RIGHT_CENTER: Element centered vertically, right-aligned

Performance Considerations

  • No reflow: Very efficient (positions calculated once)
  • Fixed positions: Ideal for HUD elements
  • Viewport independent: Elements stay in fixed screen positions

ESP32 Considerations

  • Memory: Very efficient (no complex calculations)
  • Update frequency: Positions only recalculate when screen size changes

See Also

\ No newline at end of file +

Anchor Positioning

Elements are positioned based on their anchor:

  • TOP_LEFT: Element's top-left at screen top-left
  • TOP_RIGHT: Element's top-right at screen top-right
  • BOTTOM_LEFT: Element's bottom-left at screen bottom-left
  • BOTTOM_RIGHT: Element's bottom-right at screen bottom-right
  • CENTER: Element centered on screen
  • TOP_CENTER: Element centered horizontally, top-aligned
  • BOTTOM_CENTER: Element centered horizontally, bottom-aligned
  • LEFT_CENTER: Element centered vertically, left-aligned
  • RIGHT_CENTER: Element centered vertically, right-aligned

Performance Considerations

  • No reflow: Very efficient (positions calculated once)
  • Fixed positions: Ideal for HUD elements
  • Viewport independent: Elements stay in fixed screen positions

ESP32 Considerations

  • Memory: Very efficient (no complex calculations)
  • Update frequency: Positions only recalculate when screen size changes

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/grid_layout/index.html b/site/api_reference/ui/ui_layouts/grid_layout/index.html index f4bfa2f..695d3f0 100644 --- a/site/api_reference/ui/ui_layouts/grid_layout/index.html +++ b/site/api_reference/ui/ui_layouts/grid_layout/index.html @@ -39,4 +39,4 @@ addEntity(inventory); } }; -

See Also

\ No newline at end of file +

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/horizontal_layout/index.html b/site/api_reference/ui/ui_layouts/horizontal_layout/index.html index a41a63a..c621c67 100644 --- a/site/api_reference/ui/ui_layouts/horizontal_layout/index.html +++ b/site/api_reference/ui/ui_layouts/horizontal_layout/index.html @@ -35,4 +35,4 @@ addEntity(toolbar); } }; -

See Also

\ No newline at end of file +

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/padding_container/index.html b/site/api_reference/ui/ui_layouts/padding_container/index.html index 9e7647a..2c409b5 100644 --- a/site/api_reference/ui/ui_layouts/padding_container/index.html +++ b/site/api_reference/ui/ui_layouts/padding_container/index.html @@ -42,4 +42,4 @@ auto* paddedLayout = new UIPaddingContainer(0, 0, 128, 128); paddedLayout->setPadding(10.0f, 10.0f, 20.0f, 20.0f); // Asymmetric paddedLayout->setChild(layout); -

Performance Considerations

  • Rendering: Very efficient (just draws child)
  • Position calculation: Fast (simple addition)
  • Memory: Minimal overhead

ESP32 Considerations

  • Memory: Very lightweight
  • Update frequency: Position only recalculates when padding/position changes

See Also

\ No newline at end of file +

Performance Considerations

  • Rendering: Very efficient (just draws child)
  • Position calculation: Fast (simple addition)
  • Memory: Minimal overhead

ESP32 Considerations

  • Memory: Very lightweight
  • Update frequency: Position only recalculates when padding/position changes

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/panel/index.html b/site/api_reference/ui/ui_layouts/panel/index.html index 3ae04da..a868037 100644 --- a/site/api_reference/ui/ui_layouts/panel/index.html +++ b/site/api_reference/ui/ui_layouts/panel/index.html @@ -64,4 +64,4 @@ addEntity(dialog); } }; -

Performance Considerations

  • Rendering: Simple rectangles; very efficient
  • Child updates: Child element updates are fast
  • Memory: Small overhead (just colors and border width)

ESP32 Considerations

  • Memory: Panel is lightweight
  • Rendering: Two rectangles (background + border); minimal overhead

See Also

\ No newline at end of file +

Performance Considerations

  • Rendering: Simple rectangles; very efficient
  • Child updates: Child element updates are fast
  • Memory: Small overhead (just colors and border width)

ESP32 Considerations

  • Memory: Panel is lightweight
  • Rendering: Two rectangles (background + border); minimal overhead

See Also

\ No newline at end of file diff --git a/site/api_reference/ui/ui_layouts/vertical_layout/index.html b/site/api_reference/ui/ui_layouts/vertical_layout/index.html index 57271c8..61c49dc 100644 --- a/site/api_reference/ui/ui_layouts/vertical_layout/index.html +++ b/site/api_reference/ui/ui_layouts/vertical_layout/index.html @@ -80,4 +80,4 @@ Scene::draw(renderer); // Draws layout and buttons } }; -

The layout handles D-pad navigation automatically:

  • UP button: Moves selection up
  • DOWN button: Moves selection down
  • Action button: Triggers selected button's callback
  • Scrolling: Automatically scrolls to keep selected element visible

Performance Considerations

  • Viewport culling: Only visible elements are drawn
  • Layout recalculation: Fast (simple positioning)
  • Scrolling: Smooth scrolling is efficient

ESP32 Considerations

  • Element count: Stay within MAX_ENTITIES limit
  • Scrolling: Smooth scrolling uses minimal CPU

See Also

\ No newline at end of file +

The layout handles D-pad navigation automatically:

  • UP button: Moves selection up
  • DOWN button: Moves selection down
  • Action button: Triggers selected button's callback
  • Scrolling: Automatically scrolls to keep selected element visible

Performance Considerations

  • Viewport culling: Only visible elements are drawn
  • Layout recalculation: Fast (simple positioning)
  • Scrolling: Smooth scrolling is efficient

ESP32 Considerations

  • Element count: Stay within MAX_ENTITIES limit
  • Scrolling: Smooth scrolling uses minimal CPU

See Also

\ No newline at end of file diff --git a/site/getting_started/fundamental_concepts/index.html b/site/getting_started/fundamental_concepts/index.html index 7c6c665..73d59d4 100644 --- a/site/getting_started/fundamental_concepts/index.html +++ b/site/getting_started/fundamental_concepts/index.html @@ -9,4 +9,4 @@ 5. Detect collisions in the scene 6. Draw the scene (draw all visible entities) 7. Repeat -

This cycle runs continuously, typically at 30-60 FPS on ESP32, or faster on PC.

Update

Each frame, all enabled entities receive a call to their update(deltaTime) method. This is where: - Entities move - Animations update - Game logic is processed - User input is read - Sound effects are played

The deltaTime is passed in milliseconds and represents how much time has passed since the last frame. This allows movement to be framerate-independent.

Rendering (Draw)

After updating, all visible entities receive a call to their draw(renderer) method. This is where: - Sprites are drawn - Text is drawn - Primitives are drawn (rectangles, circles, etc.)

The renderer is passed as a parameter so entities can draw themselves.

Cleanup

When you change scenes or end the game: - Entities from the previous scene can be cleaned up - Resources are freed - The new scene is initialized

Conceptual Summary

To summarize, PixelRoot32 works like this:

  1. Engine coordinates everything and runs the game loop
  2. Scene organizes your game into screens/levels
  3. Entity is any object in your game
  4. Actor is an entity that can collide
  5. PhysicsActor is an actor with automatic physics
  6. Renderer draws everything on screen using layers
  7. Each frame updates logic and then draws

All of this works automatically once you configure the Engine and create your scenes and entities. You don't need to worry about game loop details; you just need to implement update() and draw() in your entities.

Next Step

Now that you understand the fundamental concepts, you're ready to create your first project and see these concepts in action with real code.


See also: - What is PixelRoot32? - Why PixelRoot32? - Your First Project - Manual - Scenes and Entities

\ No newline at end of file +

This cycle runs continuously, typically at 30-60 FPS on ESP32, or faster on PC.

Update

Each frame, all enabled entities receive a call to their update(deltaTime) method. This is where: - Entities move - Animations update - Game logic is processed - User input is read - Sound effects are played

The deltaTime is passed in milliseconds and represents how much time has passed since the last frame. This allows movement to be framerate-independent.

Rendering (Draw)

After updating, all visible entities receive a call to their draw(renderer) method. This is where: - Sprites are drawn - Text is drawn - Primitives are drawn (rectangles, circles, etc.)

The renderer is passed as a parameter so entities can draw themselves.

Cleanup

When you change scenes or end the game: - Entities from the previous scene can be cleaned up - Resources are freed - The new scene is initialized

Conceptual Summary

To summarize, PixelRoot32 works like this:

  1. Engine coordinates everything and runs the game loop
  2. Scene organizes your game into screens/levels
  3. Entity is any object in your game
  4. Actor is an entity that can collide
  5. PhysicsActor is an actor with automatic physics
  6. Renderer draws everything on screen using layers
  7. Each frame updates logic and then draws

All of this works automatically once you configure the Engine and create your scenes and entities. You don't need to worry about game loop details; you just need to implement update() and draw() in your entities.

Next Step

Now that you understand the fundamental concepts, you're ready to create your first project and see these concepts in action with real code.


See also: - What is PixelRoot32? - Why PixelRoot32? - Your First Project - Manual - Scenes and Entities

\ No newline at end of file diff --git a/site/getting_started/installation/index.html b/site/getting_started/installation/index.html index 45b9ebb..c7b52a7 100644 --- a/site/getting_started/installation/index.html +++ b/site/getting_started/installation/index.html @@ -1,3 +1,3 @@ Installation - PixelRoot32 Documentation

Installation

This guide covers installing the PixelRoot32 documentation environment and preparing your development setup for ESP32 and Native (PC) targets.

Requirements

  • Python 3.11 or newer
  • Git (recommended for source management)
  • VS Code (or your preferred IDE)
  • For ESP32 targets: PlatformIO (VS Code extension) with ESP32 toolchain
  • For Native targets: a C++ build toolchain (CMake or your OS-native toolchain)

Install Documentation Tooling

To build and preview this documentation locally:

pip install mkdocs mkdocs-material mkdocs-minify-plugin mkdocs-git-revision-date-localized-plugin mike
 mkdocs serve
-

Open http://127.0.0.1:8000 in your browser to preview.

  1. Install VS Code
  2. Install PlatformIO IDE extension
  3. Install ESP32 platform/toolchain via PlatformIO
  4. Clone the engine repository:
  5. https://github.com/Gperez88/PixelRoot32-Game-Engine
  6. Open the engine or example project in VS Code (PlatformIO)
  7. Build and upload to your ESP32 board

Tip: Use boards based on ESP32-WROOM/WROVER for best compatibility. Ensure a reliable USB cable and correct serial port selection.

Native (PC) Setup

  1. Install a C++ toolchain (e.g., MSVC or MinGW on Windows)
  2. Install CMake (if the engine provides CMake build files)
  3. Clone the engine repository:
  4. https://github.com/Gperez88/PixelRoot32-Game-Engine
  5. Configure and build the native runtime:
  6. Follow the engine’s native build instructions (Development → Compiling)

Verify Your Environment

  • ESP32: Build and flash a minimal sample; confirm serial output and display if applicable
  • Native: Run the executable; confirm window output and input handling

Troubleshooting

  • If PlatformIO cannot find the ESP32 platform, update PlatformIO and retry
  • If native builds fail, verify compiler versions and CMake generator settings
  • Use Community → Troubleshooting for common issues and fixes

Next Steps

\ No newline at end of file +

Open http://127.0.0.1:8000 in your browser to preview.

  1. Install VS Code
  2. Install PlatformIO IDE extension
  3. Install ESP32 platform/toolchain via PlatformIO
  4. Clone the engine repository:
  5. https://github.com/Gperez88/PixelRoot32-Game-Engine
  6. Open the engine or example project in VS Code (PlatformIO)
  7. Build and upload to your ESP32 board

Tip: Use boards based on ESP32-WROOM/WROVER for best compatibility. Ensure a reliable USB cable and correct serial port selection.

Native (PC) Setup

  1. Install a C++ toolchain (e.g., MSVC or MinGW on Windows)
  2. Install CMake (if the engine provides CMake build files)
  3. Clone the engine repository:
  4. https://github.com/Gperez88/PixelRoot32-Game-Engine
  5. Configure and build the native runtime:
  6. Follow the engine’s native build instructions (Development → Compiling)

Verify Your Environment

  • ESP32: Build and flash a minimal sample; confirm serial output and display if applicable
  • Native: Run the executable; confirm window output and input handling

Troubleshooting

  • If PlatformIO cannot find the ESP32 platform, update PlatformIO and retry
  • If native builds fail, verify compiler versions and CMake generator settings
  • Use Community → Troubleshooting for common issues and fixes

Next Steps

\ No newline at end of file diff --git a/site/getting_started/what_is_pixelroot32/index.html b/site/getting_started/what_is_pixelroot32/index.html index 28600cc..887ce5f 100644 --- a/site/getting_started/what_is_pixelroot32/index.html +++ b/site/getting_started/what_is_pixelroot32/index.html @@ -1 +1 @@ - What is PixelRoot32? - PixelRoot32 Documentation

What is PixelRoot32?

PixelRoot32 is a lightweight, modular 2D game engine written in C++ designed specifically for ESP32 microcontrollers, with a native simulation layer for PC (SDL2) that allows you to develop and debug quickly on your desktop before deploying to hardware.

Simple Definition

PixelRoot32 is a game engine that lets you create retro-style 8-bit/16-bit video games directly on an ESP32 board, with the ability to develop and test on your PC before transferring code to hardware.

Key Features

🎮 Scene-Based Architecture

  • Scene system inspired by Godot Engine
  • Intuitive management of levels, menus, and screens
  • Simple transitions between scenes

🎨 Optimized Rendering

  • 1bpp (monochrome) sprites as the standard format
  • Support for multi-layer sprites (MultiSprite)
  • Experimental 2bpp and 4bpp formats for higher fidelity
  • Retro color palette system (NES, GameBoy, PICO-8, etc.)
  • Compact tilemaps for backgrounds and levels
  • 2D camera with dead-zone for smooth scrolling
  • Render layer system (background, gameplay, UI)

🔊 NES-like Audio

  • 4 audio channels (2 Pulse, 1 Triangle, 1 Noise)
  • Integrated sound effects system
  • Music player for background melodies
  • Backends for ESP32 (internal DAC or external I2S) and SDL2

🎯 Physics and Collisions

  • AABB (Axis-Aligned Bounding Box) collision system
  • PhysicsActor with gravity, friction, and restitution
  • Collision layers and masks for fine control
  • World boundary collision detection

🖥️ User Interface

  • Basic elements: Labels, Buttons, Panels
  • Automatic layouts: Vertical, Horizontal, Grid, Anchor
  • Integrated D-pad navigation
  • Scroll and viewport culling for long lists

⚡ Optimized for ESP32

  • Efficient memory management
  • Integrated object pooling
  • No dynamic allocations in the game loop
  • Performance optimized for limited hardware

Typical Use Cases

PixelRoot32 is ideal for creating:

  • Arcade Games: Space Invaders, Pong, Breakout
  • Platformers: Horizontal scrolling games with simple physics
  • Puzzles: Tetris, Snake, logic games
  • Simple RPGs: Basic role-playing games with tilemaps
  • Shooters: Vertical or horizontal shooting games
  • Rapid Prototypes: Quick development of game ideas

Supported Platforms

ESP32

  • Display: TFT_eSPI (ST7735, ILI9341, ST7789, etc.)
  • Audio: Internal DAC (GPIO 25/26) or external I2S (MAX98357A, PCM5102)
  • Input: Digital buttons, D-pad
  • Hardware: Any ESP32 board (ESP32-WROOM, ESP32-WROVER, etc.)

Desktop/Native (PC)

  • Display: SDL2 (Windows, Linux, macOS)
  • Audio: SDL2 Audio
  • Input: Keyboard, mouse
  • Usage: Development, debugging, testing

Note: Support for u8g2 (OLEDs) is planned for the future.

Project Status

Current Version: v0.2.0-dev

PixelRoot32 is under active development. APIs may change and some subsystems are still experimental. Occasional changes or breaking changes are expected, especially on less-tested configurations.

Stable Features

  • Scene and entity system
  • Basic rendering (1bpp sprites)
  • NES-like audio system
  • Basic physics and collisions
  • Basic UI system
  • ESP32 and Native support

Experimental Features

  • 2bpp and 4bpp sprites (require compilation flags)
  • Scene Arena (advanced memory management)

Planned Features

  • Support for u8g2 (OLEDs)
  • Music compiler
  • Tilemap compiler
  • Save/load system
  • Spatial partitioning for collisions

Quick Comparison

When to use PixelRoot32?

✅ Use PixelRoot32 if: - You want to create retro games on ESP32 - You need a lightweight and efficient engine - You prefer a simple and clear architecture - You want to develop on PC and deploy to ESP32 - You like 8-bit/16-bit style games

❌ Don't use PixelRoot32 if: - You need 3D graphics - You require advanced shaders - You need complex physics (advanced physics engines) - You want to create modern AAA games - You need support for multiple mobile platforms

Next Step

Now that you understand what PixelRoot32 is, discover why you should use it or go directly to your first project.


See also: - Fundamental Concepts - Installation - API Reference

\ No newline at end of file + What is PixelRoot32? - PixelRoot32 Documentation

What is PixelRoot32?

PixelRoot32 is a lightweight, modular 2D game engine written in C++ designed specifically for ESP32 microcontrollers, with a native simulation layer for PC (SDL2) that allows you to develop and debug quickly on your desktop before deploying to hardware.

Simple Definition

PixelRoot32 is a game engine that lets you create retro-style 8-bit/16-bit video games directly on an ESP32 board, with the ability to develop and test on your PC before transferring code to hardware.

Key Features

🎮 Scene-Based Architecture

  • Scene system inspired by Godot Engine
  • Intuitive management of levels, menus, and screens
  • Simple transitions between scenes

🎨 Optimized Rendering

  • 1bpp (monochrome) sprites as the standard format
  • Support for multi-layer sprites (MultiSprite)
  • Experimental 2bpp and 4bpp formats for higher fidelity
  • Retro color palette system (NES, GameBoy, PICO-8, etc.)
  • Compact tilemaps for backgrounds and levels
  • 2D camera with dead-zone for smooth scrolling
  • Render layer system (background, gameplay, UI)

🔊 NES-like Audio

  • 4 audio channels (2 Pulse, 1 Triangle, 1 Noise)
  • Integrated sound effects system
  • Music player for background melodies
  • Backends for ESP32 (internal DAC or external I2S) and SDL2

🎯 Physics and Collisions

  • AABB (Axis-Aligned Bounding Box) collision system
  • PhysicsActor with gravity, friction, and restitution
  • Collision layers and masks for fine control
  • World boundary collision detection

🖥️ User Interface

  • Basic elements: Labels, Buttons, Panels
  • Automatic layouts: Vertical, Horizontal, Grid, Anchor
  • Integrated D-pad navigation
  • Scroll and viewport culling for long lists

⚡ Optimized for ESP32

  • Efficient memory management
  • Integrated object pooling
  • No dynamic allocations in the game loop
  • Performance optimized for limited hardware

Typical Use Cases

PixelRoot32 is ideal for creating:

  • Arcade Games: Space Invaders, Pong, Breakout
  • Platformers: Horizontal scrolling games with simple physics
  • Puzzles: Tetris, Snake, logic games
  • Simple RPGs: Basic role-playing games with tilemaps
  • Shooters: Vertical or horizontal shooting games
  • Rapid Prototypes: Quick development of game ideas

Supported Platforms

ESP32

  • Display: TFT_eSPI (ST7735, ILI9341, ST7789, etc.)
  • Audio: Internal DAC (GPIO 25/26) or external I2S (MAX98357A, PCM5102)
  • Input: Digital buttons, D-pad
  • Hardware: Any ESP32 board (ESP32-WROOM, ESP32-WROVER, etc.)

Desktop/Native (PC)

  • Display: SDL2 (Windows, Linux, macOS)
  • Audio: SDL2 Audio
  • Input: Keyboard, mouse
  • Usage: Development, debugging, testing

Note: Support for u8g2 (OLEDs) is planned for the future.

Project Status

Current Version: v0.2.0-dev

PixelRoot32 is under active development. APIs may change and some subsystems are still experimental. Occasional changes or breaking changes are expected, especially on less-tested configurations.

Stable Features

  • Scene and entity system
  • Basic rendering (1bpp sprites)
  • NES-like audio system
  • Basic physics and collisions
  • Basic UI system
  • ESP32 and Native support

Experimental Features

  • 2bpp and 4bpp sprites (require compilation flags)
  • Scene Arena (advanced memory management)

Planned Features

  • Support for u8g2 (OLEDs)
  • Music compiler
  • Tilemap compiler
  • Save/load system
  • Spatial partitioning for collisions

Quick Comparison

When to use PixelRoot32?

✅ Use PixelRoot32 if: - You want to create retro games on ESP32 - You need a lightweight and efficient engine - You prefer a simple and clear architecture - You want to develop on PC and deploy to ESP32 - You like 8-bit/16-bit style games

❌ Don't use PixelRoot32 if: - You need 3D graphics - You require advanced shaders - You need complex physics (advanced physics engines) - You want to create modern AAA games - You need support for multiple mobile platforms

Next Step

Now that you understand what PixelRoot32 is, discover why you should use it or go directly to your first project.


See also: - Fundamental Concepts - Installation - API Reference

\ No newline at end of file diff --git a/site/getting_started/why_pixelroot32/index.html b/site/getting_started/why_pixelroot32/index.html index 8f8f640..68a7f3d 100644 --- a/site/getting_started/why_pixelroot32/index.html +++ b/site/getting_started/why_pixelroot32/index.html @@ -1 +1 @@ - Why PixelRoot32? - PixelRoot32 Documentation

Why PixelRoot32?

PixelRoot32 is specifically designed to solve the unique challenges of creating video games on embedded hardware like the ESP32, while maintaining the simplicity and productivity of modern development.

Main Advantages

🎯 Optimized for ESP32

Memory Efficient - 1bpp sprite system that minimizes RAM and Flash usage - Integrated object pooling to avoid memory fragmentation - Compact tilemaps that reuse sprites - No dynamic allocations in the game loop

Performance Optimized - Rendering optimized for ESP32 limitations - Efficient render layer system - Viewport culling to reduce draw calls - Rendering pipeline designed for limited hardware

Real Hardware - Direct support for common TFT displays (ST7735, ILI9341, ST7789) - Integrated audio (internal DAC or external I2S) - Simple pin and hardware configuration

🖥️ Cross-Platform Development

Develop on PC, Deploy to ESP32 - Same code works on PC (SDL2) and ESP32 - Fast debugging on desktop - Testing without hardware needed - Rapid development iteration

Visual Consistency - Native bitmap font system (pixel-perfect) - Same rendering on PC and ESP32 - Consistent color palettes - No surprises when transferring to hardware

🎨 Retro Palette System

Authentic Style - Predefined palettes: NES, GameBoy, GameBoy Color, PICO-8 - Dual palette mode for visual contrasts - Custom palettes for unique styles - Automatic color resolution (RGB565)

Easy to Use - Change palette with one line of code - Consistent visualization across all sprites - No need to manually convert assets

🔊 Integrated Audio

Complete NES-like System - 4 audio channels (2 Pulse, 1 Triangle, 1 Noise) - Simple sound effects to create - Integrated music system - Backends for different hardware configurations

No External Dependencies - Software-generated audio - No heavy audio libraries required - Full control over sound - Deterministic and predictable

🏗️ Simple and Clear Architecture

Easy to Understand - Intuitive scene system (inspired by Godot) - Clear hierarchy: Entity → Actor → PhysicsActor - Consistent and predictable APIs - Clean and well-organized code

Quick to Learn - Familiar concepts for game developers - Clear documentation and complete examples - Smooth learning curve - Active community and support

🎮 Complete Features

Everything Needed for Games - Rendering (sprites, tilemaps, primitives) - Audio (effects and music) - Physics (gravity, collisions, basic physics) - UI (layouts, buttons, navigation) - Input (buttons, keyboard) - Camera (scroll, parallax)

No Bloat - Only the essentials, nothing more - No heavy dependencies - Small and maintainable codebase - Easy to understand and modify

🛠️ Tools and Ecosystem

Available Tools - Sprite Compiler to convert PNG to sprites - Complete game examples - Templates and starter code - Extensive documentation

Community and Support - Active and developing project - Open source (MIT License) - Feedback and contributions welcome - Examples available

Comparison with Alternatives

vs. Full Engines (Unity, Godot, etc.)

PixelRoot32 Advantages: - ✅ Much lighter (fits in ESP32) - ✅ No unnecessary overhead - ✅ Full control over code - ✅ Specifically optimized for limited hardware

Disadvantages: - ❌ Fewer advanced features - ❌ No visual editor - ❌ Fewer resources and community

vs. Writing Everything from Scratch

PixelRoot32 Advantages: - ✅ Rendering system already implemented - ✅ Integrated and working audio - ✅ Physics and collisions ready - ✅ Complete UI system - ✅ Saves months of development

Disadvantages: - ❌ Less control over internal implementation - ❌ You must learn the engine API

vs. Other ESP32 Engines

PixelRoot32 Advantages: - ✅ More modern and clear architecture - ✅ Better documentation - ✅ Unique palette system - ✅ Integrated NES-like audio - ✅ Real cross-platform development

Ideal Use Cases

PixelRoot32 is perfect for:

  1. Educational Projects
  2. Learn game development
  3. Understand engine architecture
  4. Student projects

  5. Rapid Prototypes

  6. Quickly validate game ideas
  7. Create demos and proof-of-concepts
  8. Test mechanics

  9. Retro Games

  10. 8-bit/16-bit style games
  11. Arcade games
  12. Games with retro aesthetics

  13. Hardware Projects

  14. Games on small displays
  15. DIY portable consoles
  16. Maker/retro projects

  17. C++ Learning

  18. Clean and well-structured code
  19. Good programming practices
  20. Real and functional examples

Limitations to Consider

To be honest, PixelRoot32 has limitations:

  • Limited Hardware: Designed for ESP32, not powerful PCs
  • Simple Graphics: No 3D, no advanced shaders
  • Basic Physics: Not a complete physics engine
  • Restricted Memory: MAX_ENTITIES = 32 per scene
  • In Development: Some features are experimental

If you need advanced features or powerful hardware, consider other engines. But for retro games on ESP32, PixelRoot32 is an excellent choice.

Conclusion

PixelRoot32 combines:

  • Simplicity of use
  • Efficiency for limited hardware
  • Completeness of essential features
  • Clarity of architecture
  • Productivity in development

If you want to create retro games on ESP32 without the complexity of large engines, PixelRoot32 is the right choice.

Next Step

Now that you understand why PixelRoot32 is a good option, learn the fundamental concepts or start directly with your first project.


See also: - What is PixelRoot32? - Fundamental Concepts - Your First Project

\ No newline at end of file + Why PixelRoot32? - PixelRoot32 Documentation

Why PixelRoot32?

PixelRoot32 is specifically designed to solve the unique challenges of creating video games on embedded hardware like the ESP32, while maintaining the simplicity and productivity of modern development.

Main Advantages

🎯 Optimized for ESP32

Memory Efficient - 1bpp sprite system that minimizes RAM and Flash usage - Integrated object pooling to avoid memory fragmentation - Compact tilemaps that reuse sprites - No dynamic allocations in the game loop

Performance Optimized - Rendering optimized for ESP32 limitations - Efficient render layer system - Viewport culling to reduce draw calls - Rendering pipeline designed for limited hardware

Real Hardware - Direct support for common TFT displays (ST7735, ILI9341, ST7789) - Integrated audio (internal DAC or external I2S) - Simple pin and hardware configuration

🖥️ Cross-Platform Development

Develop on PC, Deploy to ESP32 - Same code works on PC (SDL2) and ESP32 - Fast debugging on desktop - Testing without hardware needed - Rapid development iteration

Visual Consistency - Native bitmap font system (pixel-perfect) - Same rendering on PC and ESP32 - Consistent color palettes - No surprises when transferring to hardware

🎨 Retro Palette System

Authentic Style - Predefined palettes: NES, GameBoy, GameBoy Color, PICO-8 - Dual palette mode for visual contrasts - Custom palettes for unique styles - Automatic color resolution (RGB565)

Easy to Use - Change palette with one line of code - Consistent visualization across all sprites - No need to manually convert assets

🔊 Integrated Audio

Complete NES-like System - 4 audio channels (2 Pulse, 1 Triangle, 1 Noise) - Simple sound effects to create - Integrated music system - Backends for different hardware configurations

No External Dependencies - Software-generated audio - No heavy audio libraries required - Full control over sound - Deterministic and predictable

🏗️ Simple and Clear Architecture

Easy to Understand - Intuitive scene system (inspired by Godot) - Clear hierarchy: Entity → Actor → PhysicsActor - Consistent and predictable APIs - Clean and well-organized code

Quick to Learn - Familiar concepts for game developers - Clear documentation and complete examples - Smooth learning curve - Active community and support

🎮 Complete Features

Everything Needed for Games - Rendering (sprites, tilemaps, primitives) - Audio (effects and music) - Physics (gravity, collisions, basic physics) - UI (layouts, buttons, navigation) - Input (buttons, keyboard) - Camera (scroll, parallax)

No Bloat - Only the essentials, nothing more - No heavy dependencies - Small and maintainable codebase - Easy to understand and modify

🛠️ Tools and Ecosystem

Available Tools - Sprite Compiler to convert PNG to sprites - Complete game examples - Templates and starter code - Extensive documentation

Community and Support - Active and developing project - Open source (MIT License) - Feedback and contributions welcome - Examples available

Comparison with Alternatives

vs. Full Engines (Unity, Godot, etc.)

PixelRoot32 Advantages: - ✅ Much lighter (fits in ESP32) - ✅ No unnecessary overhead - ✅ Full control over code - ✅ Specifically optimized for limited hardware

Disadvantages: - ❌ Fewer advanced features - ❌ No visual editor - ❌ Fewer resources and community

vs. Writing Everything from Scratch

PixelRoot32 Advantages: - ✅ Rendering system already implemented - ✅ Integrated and working audio - ✅ Physics and collisions ready - ✅ Complete UI system - ✅ Saves months of development

Disadvantages: - ❌ Less control over internal implementation - ❌ You must learn the engine API

vs. Other ESP32 Engines

PixelRoot32 Advantages: - ✅ More modern and clear architecture - ✅ Better documentation - ✅ Unique palette system - ✅ Integrated NES-like audio - ✅ Real cross-platform development

Ideal Use Cases

PixelRoot32 is perfect for:

  1. Educational Projects
  2. Learn game development
  3. Understand engine architecture
  4. Student projects

  5. Rapid Prototypes

  6. Quickly validate game ideas
  7. Create demos and proof-of-concepts
  8. Test mechanics

  9. Retro Games

  10. 8-bit/16-bit style games
  11. Arcade games
  12. Games with retro aesthetics

  13. Hardware Projects

  14. Games on small displays
  15. DIY portable consoles
  16. Maker/retro projects

  17. C++ Learning

  18. Clean and well-structured code
  19. Good programming practices
  20. Real and functional examples

Limitations to Consider

To be honest, PixelRoot32 has limitations:

  • Limited Hardware: Designed for ESP32, not powerful PCs
  • Simple Graphics: No 3D, no advanced shaders
  • Basic Physics: Not a complete physics engine
  • Restricted Memory: MAX_ENTITIES = 32 per scene
  • In Development: Some features are experimental

If you need advanced features or powerful hardware, consider other engines. But for retro games on ESP32, PixelRoot32 is an excellent choice.

Conclusion

PixelRoot32 combines:

  • Simplicity of use
  • Efficiency for limited hardware
  • Completeness of essential features
  • Clarity of architecture
  • Productivity in development

If you want to create retro games on ESP32 without the complexity of large engines, PixelRoot32 is the right choice.

Next Step

Now that you understand why PixelRoot32 is a good option, learn the fundamental concepts or start directly with your first project.


See also: - What is PixelRoot32? - Fundamental Concepts - Your First Project

\ No newline at end of file diff --git a/site/getting_started/your_first_project/index.html b/site/getting_started/your_first_project/index.html index a623e5f..8e21030 100644 --- a/site/getting_started/your_first_project/index.html +++ b/site/getting_started/your_first_project/index.html @@ -227,4 +227,4 @@ -std=c++17 -lSDL2 -mconsole -

Note: Adjust the SDL2 include and library paths for your system.

Step 7: Build and Run

For ESP32

  1. Connect your ESP32 via USB
  2. Select the environment: Click on the PlatformIO icon → Select env:esp32dev
  3. Build: Click the checkmark icon (✓) or press Ctrl+Alt+B
  4. Upload: Click the arrow icon (→) or press Ctrl+Alt+U
  5. Monitor: Click the plug icon to open serial monitor

You should see "PixelRoot32 initialized!" in the serial monitor and your display should show a blue rectangle and text.

For Native (PC)

  1. Select the environment: Click on the PlatformIO icon → Select env:native
  2. Build and Run: Click the play icon (▶) or press Ctrl+Alt+R

A window should open showing your scene with a blue rectangle and "Hello PixelRoot32!" text.

Step 8: Verify It Works

If everything is set up correctly, you should see:

  • ESP32: Display shows a blue rectangle at (50, 50) and white text "Hello PixelRoot32!" at (20, 20)
  • Native: Window shows the same content

If you see this, congratulations! Your first PixelRoot32 project is working.

Troubleshooting

ESP32 Issues

Display is blank: - Check wiring connections - Verify pin numbers in platformio.ini match your hardware - Check SPI frequency (try lowering it) - Verify display type (ST7789 vs ST7735)

Compilation errors: - Ensure library version is exactly 0.2.0-dev - Check that TFT_eSPI is installed - Verify all include paths are correct

Upload fails: - Check USB cable connection - Try different USB port - Press BOOT button on ESP32 during upload - Check COM port in PlatformIO

Native Issues

SDL2 not found: - Verify SDL2 is installed - Check include/library paths in platformio.ini - On Windows, ensure MSYS2 paths are correct

Window doesn't open: - Check console for error messages - Verify SDL2 is properly linked - Try running from terminal to see errors

Next Steps

Now that you have a working project, you can:

  1. Learn about Scenes and Entities: See how to create game objects
  2. Add Input: Make your scene respond to buttons
  3. Add Sprites: Draw custom graphics
  4. Add Audio: Play sounds and music

Continue with the Development Guide to learn more.


See also: - Fundamental Concepts - Installation - Manual - Scenes and Entities - API Reference

\ No newline at end of file +

Note: Adjust the SDL2 include and library paths for your system.

Step 7: Build and Run

For ESP32

  1. Connect your ESP32 via USB
  2. Select the environment: Click on the PlatformIO icon → Select env:esp32dev
  3. Build: Click the checkmark icon (✓) or press Ctrl+Alt+B
  4. Upload: Click the arrow icon (→) or press Ctrl+Alt+U
  5. Monitor: Click the plug icon to open serial monitor

You should see "PixelRoot32 initialized!" in the serial monitor and your display should show a blue rectangle and text.

For Native (PC)

  1. Select the environment: Click on the PlatformIO icon → Select env:native
  2. Build and Run: Click the play icon (▶) or press Ctrl+Alt+R

A window should open showing your scene with a blue rectangle and "Hello PixelRoot32!" text.

Step 8: Verify It Works

If everything is set up correctly, you should see:

  • ESP32: Display shows a blue rectangle at (50, 50) and white text "Hello PixelRoot32!" at (20, 20)
  • Native: Window shows the same content

If you see this, congratulations! Your first PixelRoot32 project is working.

Troubleshooting

ESP32 Issues

Display is blank: - Check wiring connections - Verify pin numbers in platformio.ini match your hardware - Check SPI frequency (try lowering it) - Verify display type (ST7789 vs ST7735)

Compilation errors: - Ensure library version is exactly 0.2.0-dev - Check that TFT_eSPI is installed - Verify all include paths are correct

Upload fails: - Check USB cable connection - Try different USB port - Press BOOT button on ESP32 during upload - Check COM port in PlatformIO

Native Issues

SDL2 not found: - Verify SDL2 is installed - Check include/library paths in platformio.ini - On Windows, ensure MSYS2 paths are correct

Window doesn't open: - Check console for error messages - Verify SDL2 is properly linked - Try running from terminal to see errors

Next Steps

Now that you have a working project, you can:

  1. Learn about Scenes and Entities: See how to create game objects
  2. Add Input: Make your scene respond to buttons
  3. Add Sprites: Draw custom graphics
  4. Add Audio: Play sounds and music

Continue with the Development Guide to learn more.


See also: - Fundamental Concepts - Installation - Manual - Scenes and Entities - API Reference

\ No newline at end of file diff --git a/site/index.html b/site/index.html index 6bfb671..e9d3828 100644 --- a/site/index.html +++ b/site/index.html @@ -1 +1 @@ - PixelRoot32 Documentation

PixelRoot32 Documentation

PixelRoot32 is a lightweight 2D game engine designed for ESP32 and native desktop targets. This site provides official, versioned documentation with clear guides, conceptual explanations, API references, and complete examples to help you build games efficiently.

Getting Started

New to PixelRoot32? Follow this learning path:

  1. What is PixelRoot32? - Understand what the engine is and what it can do
  2. Why PixelRoot32? - Learn the advantages and use cases
  3. Fundamental Concepts - Learn the core architecture concepts
  4. Your First Project - Create and run your first project

About This Documentation

  • Professional technical English across all pages
  • Search-enabled, mobile-friendly UI
  • Versioned with mike (stable/dev/experimental)
  • Cross-linked concepts, API, and examples
  • Progressive learning path from basics to advanced topics
\ No newline at end of file + PixelRoot32 Documentation

PixelRoot32 Documentation

PixelRoot32 is a lightweight 2D game engine designed for ESP32 and native desktop targets. This site provides official, versioned documentation with clear guides, conceptual explanations, API references, and complete examples to help you build games efficiently.

Getting Started

New to PixelRoot32? Follow this learning path:

  1. What is PixelRoot32? - Understand what the engine is and what it can do
  2. Why PixelRoot32? - Learn the advantages and use cases
  3. Fundamental Concepts - Learn the core architecture concepts
  4. Your First Project - Create and run your first project

About This Documentation

  • Professional technical English across all pages
  • Search-enabled, mobile-friendly UI
  • Versioned with mike (stable/dev/experimental)
  • Cross-linked concepts, API, and examples
  • Progressive learning path from basics to advanced topics
\ No newline at end of file diff --git a/site/manual/advanced_graphics/cameras_and_scrolling/index.html b/site/manual/advanced_graphics/cameras_and_scrolling/index.html index 80bb8af..336afd5 100644 --- a/site/manual/advanced_graphics/cameras_and_scrolling/index.html +++ b/site/manual/advanced_graphics/cameras_and_scrolling/index.html @@ -316,4 +316,4 @@ y + height < cameraY || y > cameraY + screenHeight); } -

Troubleshooting

Camera Not Moving

  • Verify camera.apply() is called in draw()
  • Check followTarget() or setPosition() is called in update()
  • Ensure camera is created with correct viewport size
  • Check boundaries aren't preventing movement

Objects Not Visible

  • Verify objects are within camera view
  • Check world coordinates vs screen coordinates
  • Ensure camera is applied before drawing
  • Verify render layers are correct

Parallax Not Working

  • Check setDisplayOffset() is used correctly
  • Verify parallax speed values (0.0 to 1.0)
  • Ensure offset is reset after parallax layers
  • Test with different speed values

Next Steps

Now that you understand cameras and scrolling, learn about: - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects - Performance Optimization - Optimize your game


See also: - API Reference - Camera2D - Manual - Basic Rendering - Manual - Tilemaps

\ No newline at end of file +

Troubleshooting

Camera Not Moving

  • Verify camera.apply() is called in draw()
  • Check followTarget() or setPosition() is called in update()
  • Ensure camera is created with correct viewport size
  • Check boundaries aren't preventing movement

Objects Not Visible

  • Verify objects are within camera view
  • Check world coordinates vs screen coordinates
  • Ensure camera is applied before drawing
  • Verify render layers are correct

Parallax Not Working

  • Check setDisplayOffset() is used correctly
  • Verify parallax speed values (0.0 to 1.0)
  • Ensure offset is reset after parallax layers
  • Test with different speed values

Next Steps

Now that you understand cameras and scrolling, learn about: - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects - Performance Optimization - Optimize your game


See also: - API Reference - Camera2D - Manual - Basic Rendering - Manual - Tilemaps

\ No newline at end of file diff --git a/site/manual/advanced_graphics/color_palettes/index.html b/site/manual/advanced_graphics/color_palettes/index.html index 0b927f2..1ced28e 100644 --- a/site/manual/advanced_graphics/color_palettes/index.html +++ b/site/manual/advanced_graphics/color_palettes/index.html @@ -204,4 +204,4 @@ Color::White }; } -

Troubleshooting

Colors Not Changing

  • Verify setPalette() is called before drawing
  • Check palette is set in init(), not update()
  • Ensure dual palette mode is enabled if using separate palettes
  • Verify Color constants are from correct namespace

Colors Look Wrong on Hardware

  • ESP32 displays may render colors differently
  • Test on actual hardware, not just PC
  • Adjust palette colors if needed
  • Consider display calibration

Dual Palette Not Working

  • Ensure enableDualPaletteMode() is called first
  • Verify both palettes are set
  • Check that you're drawing in correct context
  • Review renderer documentation

Next Steps

Now that you understand palettes, learn about: - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects


See also: - API Reference - PaletteDefs - API Reference - Color - Manual - Basic Rendering

\ No newline at end of file +

Troubleshooting

Colors Not Changing

  • Verify setPalette() is called before drawing
  • Check palette is set in init(), not update()
  • Ensure dual palette mode is enabled if using separate palettes
  • Verify Color constants are from correct namespace

Colors Look Wrong on Hardware

  • ESP32 displays may render colors differently
  • Test on actual hardware, not just PC
  • Adjust palette colors if needed
  • Consider display calibration

Dual Palette Not Working

  • Ensure enableDualPaletteMode() is called first
  • Verify both palettes are set
  • Check that you're drawing in correct context
  • Review renderer documentation

Next Steps

Now that you understand palettes, learn about: - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects


See also: - API Reference - PaletteDefs - API Reference - Color - Manual - Basic Rendering

\ No newline at end of file diff --git a/site/manual/advanced_graphics/particles_and_effects/index.html b/site/manual/advanced_graphics/particles_and_effects/index.html index 81eafd2..e1f7bd7 100644 --- a/site/manual/advanced_graphics/particles_and_effects/index.html +++ b/site/manual/advanced_graphics/particles_and_effects/index.html @@ -287,4 +287,4 @@ emitter->update(deltaTime); } }; -

Troubleshooting

Particles Not Appearing

  • Verify emitter is added to scene
  • Check particle config is valid
  • Ensure burst() is being called
  • Verify emitter position is on-screen

Performance Issues

  • Reduce particle count per burst
  • Limit number of active emitters
  • Use simpler particle configs
  • Disable emitters when not visible

Particles Not Moving

  • Check gravity value (positive = down, negative = up)
  • Verify speed is not 0
  • Check friction isn't too high (1.0 = no movement)
  • Ensure direction is correct (degrees: 0=right, 90=up, 180=left, 270=down)

Next Steps

Now that you understand particles, you've completed the advanced graphics section. Continue with: - Performance Optimization - Optimize your game - Memory Management - Manage memory efficiently - API Reference - Complete API documentation


See also: - API Reference - ParticleEmitter - API Reference - ParticleConfig - API Reference - ParticlePresets - Manual - Basic Rendering

\ No newline at end of file +

Troubleshooting

Particles Not Appearing

  • Verify emitter is added to scene
  • Check particle config is valid
  • Ensure burst() is being called
  • Verify emitter position is on-screen

Performance Issues

  • Reduce particle count per burst
  • Limit number of active emitters
  • Use simpler particle configs
  • Disable emitters when not visible

Particles Not Moving

  • Check gravity value (positive = down, negative = up)
  • Verify speed is not 0
  • Check friction isn't too high (1.0 = no movement)
  • Ensure direction is correct (degrees: 0=right, 90=up, 180=left, 270=down)

Next Steps

Now that you understand particles, you've completed the advanced graphics section. Continue with: - Performance Optimization - Optimize your game - Memory Management - Manage memory efficiently - API Reference - Complete API documentation


See also: - API Reference - ParticleEmitter - API Reference - ParticleConfig - API Reference - ParticlePresets - Manual - Basic Rendering

\ No newline at end of file diff --git a/site/manual/advanced_graphics/resolution_scaling/index.html b/site/manual/advanced_graphics/resolution_scaling/index.html index 9fbcbd0..3c871be 100644 --- a/site/manual/advanced_graphics/resolution_scaling/index.html +++ b/site/manual/advanced_graphics/resolution_scaling/index.html @@ -24,5 +24,5 @@ 240, 240, // Physical Width, Physical Height 160, 160 // Logical Width, Logical Height ); -

Performance Impact

The following table shows estimated savings on an ESP32 for a standard 240x240 display:

Logical Resolution Memory (8bpp) RAM Savings FPS Gain (est.)
240x240 (Full) 57.6 KB 0% Baseline
160x160 25.6 KB ~55% +30%
128x128 16.4 KB ~72% +60%
96x96 9.2 KB ~84% +100%

Implementation Details

Nearest Neighbor Scaling

The engine uses a Nearest Neighbor algorithm optimized for ESP32. It avoids floating-point math by using pre-calculated Lookup Tables (LUTs).

On-the-fly Scaling

To save even more RAM, the engine does not maintain a physical-sized buffer. Instead, it scales the image line-by-line during the SPI DMA transfer. This means the only large buffer in memory is the small logical one.

Profiling

You can measure the performance of the scaling system by enabling the Debug Statistics Overlay. This provides real-time data on FPS, CPU load, and RAM usage directly on the screen.

See Engine - Debug Overlay for instructions on how to enable it.

Alternatively, you can enable low-level profiling in EngineConfig.h:

#define PIXELROOT32_ENABLE_PROFILING
-

This will output the time taken for scaling and transfer to the Serial monitor: [PROFILING] Scaled Transfer: 12450 us (80 FPS max)

Best Practices

  1. Aspect Ratio: Keep the logical aspect ratio the same as the physical one to avoid stretching.
  2. Integer Multiples: For the sharpest results, try to use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen).
  3. UI Positioning: Use UIAnchorLayout to ensure your UI elements stay correctly positioned regardless of the logical resolution chosen.
\ No newline at end of file +

Performance Impact

The following table shows estimated savings on an ESP32 for a standard 240x240 display:

Logical Resolution Memory (8bpp) RAM Savings FPS Gain (est.)
240x240 (Full) 57.6 KB 0% Baseline
160x160 25.6 KB ~55% +30%
128x128 16.4 KB ~72% +60%
96x96 9.2 KB ~84% +100%

Final FPS Analysis

It is very important to understand that at 240x240 physical pixels, your maximum limit is ~14 FPS due to the SPI bus speed (40MHz).

  • 128x128 physical pixels: You send 16k pixels → ~43 FPS.
  • 240x240 physical pixels: You send 57k pixels (3.5 times more) → The bus takes 3.5 times longer to transmit, dropping to ~12-14 FPS.

Even if you render internally at 128x128 (logical), the system must ultimately send 57,600 pixels to the physical display to fill it. There is no way to bypass this physical limit unless a smaller display or a faster bus is used.

Implementation Details

Nearest Neighbor Scaling

The engine uses a Nearest Neighbor algorithm optimized for ESP32. It avoids floating-point math by using pre-calculated Lookup Tables (LUTs).

On-the-fly Scaling

To save even more RAM, the engine does not maintain a physical-sized buffer. Instead, it scales the image line-by-line during the SPI DMA transfer. This means the only large buffer in memory is the small logical one.

Profiling

You can measure the performance of the scaling system by enabling the Debug Statistics Overlay. This provides real-time data on FPS, CPU load, and RAM usage directly on the screen.

See Engine - Debug Overlay for instructions on how to enable it.

Alternatively, you can enable low-level profiling in EngineConfig.h:

#define PIXELROOT32_ENABLE_PROFILING
+

This will output the time taken for scaling and transfer to the Serial monitor: [PROFILING] Scaled Transfer: 12450 us (80 FPS max)

Best Practices

  1. Aspect Ratio: Keep the logical aspect ratio the same as the physical one to avoid stretching.
  2. Integer Multiples: For the sharpest results, try to use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen).
  3. Hardware Recommendation: For high-action games requiring 30+ FPS (like the Metroidvania sample), it is highly recommended to use a 128x128 physical display. Larger displays like 240x240 are limited to ~14 FPS by the 40MHz SPI bus, regardless of the logical resolution used.
  4. UI Positioning: Use UIAnchorLayout to ensure your UI elements stay correctly positioned regardless of the logical resolution chosen.
\ No newline at end of file diff --git a/site/manual/advanced_graphics/sprites_and_animation/index.html b/site/manual/advanced_graphics/sprites_and_animation/index.html index af4a58d..96a6e47 100644 --- a/site/manual/advanced_graphics/sprites_and_animation/index.html +++ b/site/manual/advanced_graphics/sprites_and_animation/index.html @@ -350,4 +350,4 @@ return nullptr; } }; -

Troubleshooting

Sprites Not Displaying

  • Check sprite data is valid
  • Verify width/height match data
  • Ensure sprite is within screen bounds
  • Check render layer is correct

Animation Not Playing

  • Verify animation frames are set
  • Check step() is being called
  • Ensure timer logic is correct
  • Verify frame count matches array size

Memory Issues

  • Reduce sprite count
  • Use 1bpp instead of 2bpp/4bpp
  • Reuse sprites more
  • Check available flash memory

Next Steps

Now that you understand sprites and animation, learn about: - Color Palettes - Use different color schemes - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles


See also: - API Reference - Sprite - API Reference - SpriteAnimation - Manual - Basic Rendering

\ No newline at end of file +

Troubleshooting

Sprites Not Displaying

  • Check sprite data is valid
  • Verify width/height match data
  • Ensure sprite is within screen bounds
  • Check render layer is correct

Animation Not Playing

  • Verify animation frames are set
  • Check step() is being called
  • Ensure timer logic is correct
  • Verify frame count matches array size

Memory Issues

  • Reduce sprite count
  • Use 1bpp instead of 2bpp/4bpp
  • Reuse sprites more
  • Check available flash memory

Next Steps

Now that you understand sprites and animation, learn about: - Color Palettes - Use different color schemes - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles


See also: - API Reference - Sprite - API Reference - SpriteAnimation - Manual - Basic Rendering

\ No newline at end of file diff --git a/site/manual/advanced_graphics/tilemaps/index.html b/site/manual/advanced_graphics/tilemaps/index.html index af0f26b..a9379f9 100644 --- a/site/manual/advanced_graphics/tilemaps/index.html +++ b/site/manual/advanced_graphics/tilemaps/index.html @@ -297,4 +297,4 @@ return false; // No collision } -

Troubleshooting

Tiles Not Appearing

  • Verify tile indices are correct (0 = first tile, 1 = second, etc.)
  • Check tilemap dimensions match indices array size
  • Ensure tiles array has enough entries
  • Verify tile size matches sprite size

Performance Issues

  • Reduce tilemap size
  • Use smaller tiles
  • Limit number of unique tiles
  • Test viewport culling

Scrolling Problems

  • Ensure camera is applied before drawing tilemap
  • Check tilemap position matches camera offset
  • Verify tilemap boundaries are correct
  • Test with simple tilemap first

Next Steps

Now that you understand tilemaps, learn about: - Particles and Effects - Add visual effects - Cameras and Scrolling - Combine with scrolling - Performance Optimization - Optimize rendering


See also: - API Reference - TileMap - API Reference - Renderer - Manual - Cameras and Scrolling

\ No newline at end of file +

Troubleshooting

Tiles Not Appearing

  • Verify tile indices are correct (0 = first tile, 1 = second, etc.)
  • Check tilemap dimensions match indices array size
  • Ensure tiles array has enough entries
  • Verify tile size matches sprite size

Performance Issues

  • Reduce tilemap size
  • Use smaller tiles
  • Limit number of unique tiles
  • Test viewport culling

Scrolling Problems

  • Ensure camera is applied before drawing tilemap
  • Check tilemap position matches camera offset
  • Verify tilemap boundaries are correct
  • Test with simple tilemap first

Next Steps

Now that you understand tilemaps, learn about: - Particles and Effects - Add visual effects - Cameras and Scrolling - Combine with scrolling - Performance Optimization - Optimize rendering


See also: - API Reference - TileMap - API Reference - Renderer - Manual - Cameras and Scrolling

\ No newline at end of file diff --git a/site/manual/game_development/audio/index.html b/site/manual/game_development/audio/index.html index fc51ec2..5339256 100644 --- a/site/manual/game_development/audio/index.html +++ b/site/manual/game_development/audio/index.html @@ -234,4 +234,4 @@ Scene::update(deltaTime); } }; -

Troubleshooting

No Sound

  • Check audio backend is configured correctly
  • Verify sample rate matches backend
  • Check master volume is not 0
  • Ensure audio is initialized (engine.init())

Distorted Sound

  • Lower volume levels
  • Reduce sample rate (ESP32 DAC works better at 11025 Hz)
  • Check for too many simultaneous sounds
  • Verify hardware connections (ESP32)

Music Not Playing

  • Check music.isPlaying() status
  • Ensure track is properly defined
  • Verify MusicPlayer is updated (happens automatically)
  • Check that music channel is not being used by SFX

Next Steps

Now that you can add audio, learn about: - NES Audio Reference - Advanced audio techniques - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs


See also: - API Reference - AudioEngine - API Reference - MusicPlayer - API Reference - Audio Types - Manual - Audio Overview

\ No newline at end of file +

Troubleshooting

No Sound

  • Check audio backend is configured correctly
  • Verify sample rate matches backend
  • Check master volume is not 0
  • Ensure audio is initialized (engine.init())

Distorted Sound

  • Lower volume levels
  • Reduce sample rate (ESP32 DAC works better at 11025 Hz)
  • Check for too many simultaneous sounds
  • Verify hardware connections (ESP32)

Music Not Playing

  • Check music.isPlaying() status
  • Ensure track is properly defined
  • Verify MusicPlayer is updated (happens automatically)
  • Check that music channel is not being used by SFX

Next Steps

Now that you can add audio, learn about: - NES Audio Reference - Advanced audio techniques - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs


See also: - API Reference - AudioEngine - API Reference - MusicPlayer - API Reference - Audio Types - Manual - Audio Overview

\ No newline at end of file diff --git a/site/manual/game_development/basic_rendering/index.html b/site/manual/game_development/basic_rendering/index.html index 38350c0..77d263f 100644 --- a/site/manual/game_development/basic_rendering/index.html +++ b/site/manual/game_development/basic_rendering/index.html @@ -141,4 +141,4 @@ renderer.drawSprite(sprite, x, startY, Color::White); } } -

Next Steps

Now that you can draw basic graphics, learn about: - Sprites and Animation - Advanced sprite techniques - Input and Control - Make your game interactive - Palettes - Use different color schemes


See also: - API Reference - Renderer - API Reference - Sprite - Render Layers

\ No newline at end of file +

Next Steps

Now that you can draw basic graphics, learn about: - Sprites and Animation - Advanced sprite techniques - Input and Control - Make your game interactive - Palettes - Use different color schemes


See also: - API Reference - Renderer - API Reference - Sprite - Render Layers

\ No newline at end of file diff --git a/site/manual/game_development/input_and_control/index.html b/site/manual/game_development/input_and_control/index.html index db5765a..c0bc5e9 100644 --- a/site/manual/game_development/input_and_control/index.html +++ b/site/manual/game_development/input_and_control/index.html @@ -258,4 +258,4 @@ if (input.isButtonReleased(button)) return InputState::RELEASED; return InputState::IDLE; } -

Troubleshooting

Button Not Responding

  • Check button indices match your InputConfig
  • Verify GPIO pins (ESP32) or scancodes (Native) are correct
  • Ensure InputManager is being updated (happens automatically in Engine)

Input Feels Laggy

  • Ensure you're using deltaTime for movement
  • Check that input is read in update(), not draw()
  • Verify framerate is stable

Multiple Triggers

  • Use isButtonPressed() instead of isButtonDown() for one-time actions
  • Implement input buffering or cooldown timers

Next Steps

Now that you can handle input, learn about: - Audio - Add sound effects and music - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs


See also: - API Reference - InputManager - API Reference - InputConfig - Manual - Input Overview

\ No newline at end of file +

Troubleshooting

Button Not Responding

  • Check button indices match your InputConfig
  • Verify GPIO pins (ESP32) or scancodes (Native) are correct
  • Ensure InputManager is being updated (happens automatically in Engine)

Input Feels Laggy

  • Ensure you're using deltaTime for movement
  • Check that input is read in update(), not draw()
  • Verify framerate is stable

Multiple Triggers

  • Use isButtonPressed() instead of isButtonDown() for one-time actions
  • Implement input buffering or cooldown timers

Next Steps

Now that you can handle input, learn about: - Audio - Add sound effects and music - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs


See also: - API Reference - InputManager - API Reference - InputConfig - Manual - Input Overview

\ No newline at end of file diff --git a/site/manual/game_development/physics_and_collisions/index.html b/site/manual/game_development/physics_and_collisions/index.html index 2f44f27..2ec4d01 100644 --- a/site/manual/game_development/physics_and_collisions/index.html +++ b/site/manual/game_development/physics_and_collisions/index.html @@ -323,4 +323,4 @@ } } } -

Troubleshooting

Collisions Not Detected

  • Verify collision layers and masks overlap
  • Check that actors are added to the scene
  • Ensure Scene::update() is called
  • Verify hitboxes are correct

Physics Too Fast/Slow

  • Adjust values based on deltaTime
  • Check gravity and velocity values
  • Test on actual hardware (ESP32 may run slower)

Objects Passing Through

  • Use sweep tests for fast objects
  • Increase collision detection frequency
  • Check hitbox sizes match visual size

Next Steps

Now that you understand physics and collisions, learn about: - User Interface - Create menus and HUDs - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels


See also: - API Reference - PhysicsActor - API Reference - CollisionSystem - Manual - Physics Overview - Manual - Collision Detection

\ No newline at end of file +

Troubleshooting

Collisions Not Detected

  • Verify collision layers and masks overlap
  • Check that actors are added to the scene
  • Ensure Scene::update() is called
  • Verify hitboxes are correct

Physics Too Fast/Slow

  • Adjust values based on deltaTime
  • Check gravity and velocity values
  • Test on actual hardware (ESP32 may run slower)

Objects Passing Through

  • Use sweep tests for fast objects
  • Increase collision detection frequency
  • Check hitbox sizes match visual size

Next Steps

Now that you understand physics and collisions, learn about: - User Interface - Create menus and HUDs - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels


See also: - API Reference - PhysicsActor - API Reference - CollisionSystem - Manual - Physics Overview - Manual - Collision Detection

\ No newline at end of file diff --git a/site/manual/game_development/scenes_and_entities/index.html b/site/manual/game_development/scenes_and_entities/index.html index 9d1b3f2..47c1854 100644 --- a/site/manual/game_development/scenes_and_entities/index.html +++ b/site/manual/game_development/scenes_and_entities/index.html @@ -254,4 +254,4 @@ // ... } } -

Next Steps

Now that you understand scenes and entities, learn about: - Basic Rendering - Draw sprites, text, and primitives - Input and Control - Handle user input - Physics and Collisions - Advanced collision handling


See also: - Fundamental Concepts - API Reference - Scene - API Reference - Entity - API Reference - Actor

\ No newline at end of file +

Next Steps

Now that you understand scenes and entities, learn about: - Basic Rendering - Draw sprites, text, and primitives - Input and Control - Handle user input - Physics and Collisions - Advanced collision handling


See also: - Fundamental Concepts - API Reference - Scene - API Reference - Entity - API Reference - Actor

\ No newline at end of file diff --git a/site/manual/game_development/user_interface/index.html b/site/manual/game_development/user_interface/index.html index ea2db43..fad4376 100644 --- a/site/manual/game_development/user_interface/index.html +++ b/site/manual/game_development/user_interface/index.html @@ -1,4 +1,4 @@ - User Interface - PixelRoot32 Documentation

User Interface

PixelRoot32 provides a complete UI system for creating menus, HUDs, and interface elements. This guide covers all UI components and layout systems.

UI Elements

All UI elements inherit from UIElement, which itself inherits from Entity. This means UI elements can be added to scenes just like any other entity.

UILabel

Display text on screen:

#include <graphics/ui/UILabel.h>
+ User Interface - PixelRoot32 Documentation      

User Interface

PixelRoot32 provides a complete UI system for creating menus, HUDs, and interface elements. This guide covers all UI components and layout systems.

UI Elements

All UI elements inherit from UIElement, which itself inherits from Entity. This means UI elements can be added to scenes just like any other entity.

UILabel

Display text on screen:

#include <graphics/ui/UILabel.h>
 
 // Create a label
 pixelroot32::graphics::ui::UILabel* scoreLabel = new pixelroot32::graphics::ui::UILabel(
@@ -214,179 +214,203 @@
 
 // Or set asymmetric padding
 container->setPadding(5, 15, 10, 10); // left, right, top, bottom
-
+```cpp
 // Add child element
 container->setChild(button);
 
 addEntity(container);
-

Layouts handle D-pad navigation automatically:

Vertical Navigation

verticalLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN);
-
-// Layout automatically:
-// - Highlights selected button
-// - Scrolls to keep selected button visible
-// - Handles wrapping (optional)
-

Horizontal Navigation

horizontalLayout->setNavigationButtons(Buttons::LEFT, Buttons::RIGHT);
-

Grid Navigation

gridLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN, Buttons::LEFT, Buttons::RIGHT);
-
-// Layout automatically:
-// - Handles 4-direction navigation
-// - Wraps around edges
-// - Updates selection
-

Manual Selection

// Set selected element programmatically
-layout->setSelectedIndex(2);
-
-// Get selected element
-int selected = layout->getSelectedIndex();
-UIElement* element = layout->getSelectedElement();
-

Complete Example: Main Menu

#include <core/Scene.h>
-#include <graphics/ui/UIVerticalLayout.h>
-#include <graphics/ui/UIButton.h>
-#include <graphics/ui/UILabel.h>
-#include <graphics/ui/UIPanel.h>
-
-class MainMenuScene : public pixelroot32::core::Scene {
-private:
-    pixelroot32::graphics::ui::UIVerticalLayout* menuLayout;
-    pixelroot32::graphics::ui::UIPanel* menuPanel;
-
-public:
-    void init() override {
-        // Create panel
-        menuPanel = new pixelroot32::graphics::ui::UIPanel(40, 40, 160, 160);
-        menuPanel->setBackgroundColor(pixelroot32::graphics::Color::Black);
-        menuPanel->setBorderColor(pixelroot32::graphics::Color::White);
-        menuPanel->setBorderWidth(2);
-        menuPanel->setRenderLayer(2);
-        addEntity(menuPanel);
-
-        // Create layout inside panel
-        menuLayout = new pixelroot32::graphics::ui::UIVerticalLayout(0, 0, 160, 160);
-        menuLayout->setPadding(10);
-        menuLayout->setSpacing(8);
-        menuLayout->setNavigationButtons(0, 1);
-        menuLayout->setButtonStyle(
-            pixelroot32::graphics::Color::White,
-            pixelroot32::graphics::Color::Cyan,
-            pixelroot32::graphics::Color::White,
-            pixelroot32::graphics::Color::Black
-        );
-
-        // Add title
-        pixelroot32::graphics::ui::UILabel* title = new pixelroot32::graphics::ui::UILabel(
-            "GAME MENU", 0, 0, pixelroot32::graphics::Color::Yellow, 2
-        );
-        menuLayout->addElement(title);
-
-        // Add menu buttons
-        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(
-            "Start Game", 0, 0, 0, 140, 25, []() { startGame(); }
-        ));
-
-        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(
-            "Options", 1, 0, 0, 140, 25, []() { showOptions(); }
-        ));
-
-        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(
-            "Quit", 2, 0, 0, 140, 25, []() { quitGame(); }
-        ));
-
-        menuPanel->setChild(menuLayout);
-    }
-
-    void update(unsigned long deltaTime) override {
-        // Handle input for layout navigation
-        auto& input = engine.getInputManager();
-        menuLayout->handleInput(input);
-
-        Scene::update(deltaTime);
-    }
-
-    void draw(pixelroot32::graphics::Renderer& renderer) override {
-        Scene::draw(renderer);
-    }
-};
-

Complete Example: HUD

class GameHUD : public pixelroot32::core::Entity {
-private:
-    pixelroot32::graphics::ui::UIAnchorLayout* hud;
-    pixelroot32::graphics::ui::UILabel* scoreLabel;
-    pixelroot32::graphics::ui::UILabel* livesLabel;
-    pixelroot32::graphics::ui::UILabel* healthLabel;
-
-public:
-    GameHUD()
-        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::UI_ELEMENT) {
-        setRenderLayer(2); // UI layer
-
-        // Create HUD layout
-        hud = new pixelroot32::graphics::ui::UIAnchorLayout(0, 0, 240, 240);
-        hud->setScreenSize(240, 240);
-
-        // Create labels
-        scoreLabel = new pixelroot32::graphics::ui::UILabel(
-            "Score: 0", 0, 0, pixelroot32::graphics::Color::White, 1
-        );
+

Fixed Position UI (HUDs)

By default, UI elements behave like world objects: if you move the Camera2D, the UI elements will scroll with the world. For elements that should stay fixed on screen (like a HUD, health bar, or pause menu), you can use the fixedPosition property.

When setFixedPosition(true) is called on an element: 1. It ignores any Camera2D offsets (xOffset/yOffset). 2. It remains at its logical screen coordinates regardless of camera movement. 3. If the element is a layout (like UIAnchorLayout), all its children will also become fixed on screen.

Example: Fixed HUD

// Create an anchor layout for HUD
+pixelroot32::graphics::ui::UIAnchorLayout* hud = new pixelroot32::graphics::ui::UIAnchorLayout(0, 0, 240, 240);
+hud->setScreenSize(240, 240);
+
+// IMPORTANT: Make the HUD stay fixed on screen
+hud->setFixedPosition(true);
+
+// Add health label at TOP_LEFT
+UILabel* healthLabel = new UILabel("HP: 100", 0, 0, Color::Red, 1);
+hud->addElement(healthLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);
+
+// Add score label at TOP_RIGHT
+UILabel* scoreLabel = new UILabel("Score: 0", 0, 0, Color::White, 1);
+hud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);
+
+addEntity(hud);
+

Layouts handle D-pad navigation automatically:

Vertical Navigation

verticalLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN);
+
+// Layout automatically:
+// - Highlights selected button
+// - Scrolls to keep selected button visible
+// - Handles wrapping (optional)
+

Horizontal Navigation

horizontalLayout->setNavigationButtons(Buttons::LEFT, Buttons::RIGHT);
+

Grid Navigation

gridLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN, Buttons::LEFT, Buttons::RIGHT);
+
+// Layout automatically:
+// - Handles 4-direction navigation
+// - Wraps around edges
+// - Updates selection
+

Manual Selection

// Set selected element programmatically
+layout->setSelectedIndex(2);
+
+// Get selected element
+int selected = layout->getSelectedIndex();
+UIElement* element = layout->getSelectedElement();
+

Complete Example: Main Menu

#include <core/Scene.h>
+#include <graphics/ui/UIVerticalLayout.h>
+#include <graphics/ui/UIButton.h>
+#include <graphics/ui/UILabel.h>
+#include <graphics/ui/UIPanel.h>
+
+class MainMenuScene : public pixelroot32::core::Scene {
+private:
+    pixelroot32::graphics::ui::UIVerticalLayout* menuLayout;
+    pixelroot32::graphics::ui::UIPanel* menuPanel;
+
+public:
+    void init() override {
+        // Create panel
+        menuPanel = new pixelroot32::graphics::ui::UIPanel(40, 40, 160, 160);
+        menuPanel->setBackgroundColor(pixelroot32::graphics::Color::Black);
+        menuPanel->setBorderColor(pixelroot32::graphics::Color::White);
+        menuPanel->setBorderWidth(2);
+        menuPanel->setRenderLayer(2);
+        addEntity(menuPanel);
 
-        livesLabel = new pixelroot32::graphics::ui::UILabel(
-            "Lives: 3", 0, 0, pixelroot32::graphics::Color::White, 1
-        );
-
-        healthLabel = new pixelroot32::graphics::ui::UILabel(
-            "Health: 100%", 0, 0, pixelroot32::graphics::Color::Green, 1
-        );
-
-        // Position labels
-        hud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);
-        hud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);
-        hud->addElement(healthLabel, pixelroot32::graphics::ui::Anchor::BOTTOM_CENTER);
-    }
-
-    void update(unsigned long deltaTime) override {
-        // Update HUD text (example)
-        char buffer[32];
-        snprintf(buffer, sizeof(buffer), "Score: %d", currentScore);
-        scoreLabel->setText(buffer);
-    }
-
-    void draw(pixelroot32::graphics::Renderer& renderer) override {
-        // HUD draws itself through its layout
-    }
-
-    // Add HUD to scene
-    void addToScene(Scene* scene) {
-        scene->addEntity(hud);
-    }
-};
-

Best Practices

Organization

  • Use render layer 2: Keep all UI on the top layer
  • Group related elements: Use panels to group menu items
  • Separate HUD from menus: Use different layouts for different UI types
  • Reuse layouts: Create layout factories for common patterns

Performance

  • Layouts use viewport culling: Only visible elements are rendered
  • Minimize text updates: Updating text has overhead
  • Use appropriate layouts: Choose the right layout for your needs
  • Limit element count: Too many elements can impact performance
  • Set navigation buttons: Configure D-pad navigation for layouts
  • Handle input in update(): Check for button presses to trigger actions
  • Provide visual feedback: Selected buttons should be clearly visible
  • Test navigation flow: Ensure navigation feels responsive

Common Patterns

class MenuSystem {
-    UIVerticalLayout* currentMenu;
-
-public:
-    void showMainMenu() {
-        currentMenu = createMainMenu();
-        scene->addEntity(currentMenu);
-    }
-
-    void showPauseMenu() {
-        currentMenu = createPauseMenu();
-        scene->addEntity(currentMenu);
-    }
-
-    void hideMenu() {
-        if (currentMenu) {
-            scene->removeEntity(currentMenu);
-            currentMenu = nullptr;
-        }
-    }
-};
-

Dynamic UI Updates

void updateHUD(int score, int lives, int health) {
-    char buffer[32];
+        // Create layout inside panel
+        menuLayout = new pixelroot32::graphics::ui::UIVerticalLayout(0, 0, 160, 160);
+        menuLayout->setPadding(10);
+        menuLayout->setSpacing(8);
+        menuLayout->setNavigationButtons(0, 1);
+        menuLayout->setButtonStyle(
+            pixelroot32::graphics::Color::White,
+            pixelroot32::graphics::Color::Cyan,
+            pixelroot32::graphics::Color::White,
+            pixelroot32::graphics::Color::Black
+        );
+
+        // Add title
+        pixelroot32::graphics::ui::UILabel* title = new pixelroot32::graphics::ui::UILabel(
+            "GAME MENU", 0, 0, pixelroot32::graphics::Color::Yellow, 2
+        );
+        menuLayout->addElement(title);
+
+        // Add menu buttons
+        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(
+            "Start Game", 0, 0, 0, 140, 25, []() { startGame(); }
+        ));
+
+        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(
+            "Options", 1, 0, 0, 140, 25, []() { showOptions(); }
+        ));
+
+        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(
+            "Quit", 2, 0, 0, 140, 25, []() { quitGame(); }
+        ));
+
+        menuPanel->setChild(menuLayout);
+    }
+
+    void update(unsigned long deltaTime) override {
+        // Handle input for layout navigation
+        auto& input = engine.getInputManager();
+        menuLayout->handleInput(input);
+
+        Scene::update(deltaTime);
+    }
+
+    void draw(pixelroot32::graphics::Renderer& renderer) override {
+        Scene::draw(renderer);
+    }
+};
+

Complete Example: HUD

class GameHUD : public pixelroot32::core::Entity {
+private:
+    pixelroot32::graphics::ui::UIAnchorLayout* hud;
+    pixelroot32::graphics::ui::UILabel* scoreLabel;
+    pixelroot32::graphics::ui::UILabel* livesLabel;
+    pixelroot32::graphics::ui::UILabel* healthLabel;
+
+public:
+    GameHUD()
+        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::UI_ELEMENT) {
+        setRenderLayer(2); // UI layer
+
+        // Create HUD layout
+        hud = new pixelroot32::graphics::ui::UIAnchorLayout(0, 0, 240, 240);
+        hud->setScreenSize(240, 240);
+
+        // Create labels
+        scoreLabel = new pixelroot32::graphics::ui::UILabel(
+            "Score: 0", 0, 0, pixelroot32::graphics::Color::White, 1
+        );
+
+        livesLabel = new pixelroot32::graphics::ui::UILabel(
+            "Lives: 3", 0, 0, pixelroot32::graphics::Color::White, 1
+        );
+
+        healthLabel = new pixelroot32::graphics::ui::UILabel(
+            "Health: 100%", 0, 0, pixelroot32::graphics::Color::Green, 1
+        );
+
+        // Position labels
+        hud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);
+        hud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);
+        hud->addElement(healthLabel, pixelroot32::graphics::ui::Anchor::BOTTOM_CENTER);
+    }
+
+    void update(unsigned long deltaTime) override {
+        // Update HUD text (example)
+        char buffer[32];
+        snprintf(buffer, sizeof(buffer), "Score: %d", currentScore);
+        scoreLabel->setText(buffer);
+    }
+
+    void draw(pixelroot32::graphics::Renderer& renderer) override {
+        // HUD draws itself through its layout
+    }
+
+    // Add HUD to scene
+    void addToScene(Scene* scene) {
+        scene->addEntity(hud);
+    }
+};
+

Best Practices

Organization

  • Use render layer 2: Keep all UI on the top layer
  • Group related elements: Use panels to group menu items
  • Separate HUD from menus: Use different layouts for different UI types
  • Reuse layouts: Create layout factories for common patterns

Performance

  • Layouts use viewport culling: Only visible elements are rendered
  • Minimize text updates: Updating text has overhead
  • Use appropriate layouts: Choose the right layout for your needs
  • Limit element count: Too many elements can impact performance

Fixed Position UI (HUDs & Overlays)

By default, UI elements placed in a scene will move with the Camera2D just like any other entity. To create a HUD or a menu that stays fixed on the screen regardless of camera movement, use the fixedPosition flag on your layouts:

// Create a HUD layout
+pixelroot32::graphics::ui::UIVerticalLayout* hud = new pixelroot32::graphics::ui::UIVerticalLayout(10, 10, 100, 50);
 
-    snprintf(buffer, sizeof(buffer), "Score: %d", score);
-    scoreLabel->setText(buffer);
+// Enable fixed positioning
+hud->setFixedPosition(true); // <--- This layout will now ignore Camera2D scrolling
 
-    snprintf(buffer, sizeof(buffer), "Lives: %d", lives);
-    livesLabel->setText(buffer);
-
-    snprintf(buffer, sizeof(buffer), "Health: %d%%", health);
-    healthLabel->setText(buffer);
-}
-

Next Steps

Now that you understand the UI system, you've completed the core game development topics. Continue with: - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels - Performance Tuning - Improve performance


See also: - API Reference - UIElement - API Reference - UIButton - API Reference - UI Layouts - Manual - UI Overview

\ No newline at end of file +// Add to scene +addEntity(hud); +

When setFixedPosition(true) is called: 1. The layout and all its children will ignore the global camera offset. 2. The coordinates (x, y) of the layout become relative to the screen, not the world. 3. This is the recommended way to implement HUDs, pause menus, and screen-space overlays.

  • Set navigation buttons: Configure D-pad navigation for layouts
  • Handle input in update(): Check for button presses to trigger actions
  • Provide visual feedback: Selected buttons should be clearly visible
  • Test navigation flow: Ensure navigation feels responsive

Common Patterns

class MenuSystem {
+    UIVerticalLayout* currentMenu;
+
+public:
+    void showMainMenu() {
+        currentMenu = createMainMenu();
+        scene->addEntity(currentMenu);
+    }
+
+    void showPauseMenu() {
+        currentMenu = createPauseMenu();
+        scene->addEntity(currentMenu);
+    }
+
+    void hideMenu() {
+        if (currentMenu) {
+            scene->removeEntity(currentMenu);
+            currentMenu = nullptr;
+        }
+    }
+};
+

Dynamic UI Updates

void updateHUD(int score, int lives, int health) {
+    char buffer[32];
+
+    snprintf(buffer, sizeof(buffer), "Score: %d", score);
+    scoreLabel->setText(buffer);
+
+    snprintf(buffer, sizeof(buffer), "Lives: %d", lives);
+    livesLabel->setText(buffer);
+
+    snprintf(buffer, sizeof(buffer), "Health: %d%%", health);
+    healthLabel->setText(buffer);
+}
+

Next Steps

Now that you understand the UI system, you've completed the core game development topics. Continue with: - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels - Performance Tuning - Improve performance


See also: - API Reference - UIElement - API Reference - UIButton - API Reference - UI Layouts - Manual - UI Overview

\ No newline at end of file diff --git a/site/manual/optimization/extensibility/index.html b/site/manual/optimization/extensibility/index.html index d0fe630..e1afb27 100644 --- a/site/manual/optimization/extensibility/index.html +++ b/site/manual/optimization/extensibility/index.html @@ -348,4 +348,4 @@ } } }; -

Troubleshooting

Driver Not Working

  • Verify all interface methods are implemented
  • Check initialization order
  • Test with simple drawing first
  • Verify hardware connections

Audio Backend Issues

  • Check sample rate matches hardware
  • Verify audio generation logic
  • Test with simple tones first
  • Check channel management

Extension Conflicts

  • Ensure namespace isolation
  • Avoid modifying engine code directly
  • Use composition over modification
  • Test with engine updates

Next Steps

Now that you understand extensibility, you've completed the optimization section. Continue with: - API Reference - Complete API documentation - Examples - Code examples - Resources - Tools and troubleshooting


See also: - API Reference - DrawSurface - API Reference - AudioBackend - Manual - Platforms and Drivers

\ No newline at end of file +

Troubleshooting

Driver Not Working

  • Verify all interface methods are implemented
  • Check initialization order
  • Test with simple drawing first
  • Verify hardware connections

Audio Backend Issues

  • Check sample rate matches hardware
  • Verify audio generation logic
  • Test with simple tones first
  • Check channel management

Extension Conflicts

  • Ensure namespace isolation
  • Avoid modifying engine code directly
  • Use composition over modification
  • Test with engine updates

Next Steps

Now that you understand extensibility, you've completed the optimization section. Continue with: - API Reference - Complete API documentation - Examples - Code examples - Resources - Tools and troubleshooting


See also: - API Reference - DrawSurface - API Reference - AudioBackend - Manual - Platforms and Drivers

\ No newline at end of file diff --git a/site/manual/optimization/memory_management/index.html b/site/manual/optimization/memory_management/index.html index 705db99..98b6a26 100644 --- a/site/manual/optimization/memory_management/index.html +++ b/site/manual/optimization/memory_management/index.html @@ -294,4 +294,4 @@ int size() const { return count; } pixelroot32::core::Entity* operator[](int index) { return entities[index]; } }; -

Troubleshooting

Out of Memory Errors

  • Reduce pool sizes
  • Use fewer entities
  • Store more data in flash
  • Avoid dynamic allocation
  • Check for memory leaks

Entity Limit Reached

  • MAX_ENTITIES = 32 is a hard limit
  • Use object pooling to reuse entities
  • Deactivate entities instead of removing
  • Combine multiple entities into one

Memory Fragmentation

  • Use object pooling
  • Pre-allocate all resources
  • Avoid frequent new/delete
  • Consider Scene Arena (experimental)

Next Steps

Now that you understand memory management, learn about: - Performance Optimization - Improve game performance - Platforms and Drivers - Understand platform specifics - Extensibility - Extend the engine


See also: - API Reference - Scene - Manual - Scenes and Entities

\ No newline at end of file +

Troubleshooting

Out of Memory Errors

  • Reduce pool sizes
  • Use fewer entities
  • Store more data in flash
  • Avoid dynamic allocation
  • Check for memory leaks

Entity Limit Reached

  • MAX_ENTITIES = 32 is a hard limit
  • Use object pooling to reuse entities
  • Deactivate entities instead of removing
  • Combine multiple entities into one

Memory Fragmentation

  • Use object pooling
  • Pre-allocate all resources
  • Avoid frequent new/delete
  • Consider Scene Arena (experimental)

Next Steps

Now that you understand memory management, learn about: - Performance Optimization - Improve game performance - Platforms and Drivers - Understand platform specifics - Extensibility - Extend the engine


See also: - API Reference - Scene - Manual - Scenes and Entities

\ No newline at end of file diff --git a/site/manual/optimization/performance_tuning/index.html b/site/manual/optimization/performance_tuning/index.html index 609e3e4..50e9ec7 100644 --- a/site/manual/optimization/performance_tuning/index.html +++ b/site/manual/optimization/performance_tuning/index.html @@ -64,4 +64,4 @@ } } }; -

Troubleshooting

Low FPS

  • Profile to find bottlenecks
  • Reduce entity count
  • Optimize rendering (culling, batching)
  • Simplify collision detection
  • Reduce update frequency

Frame Drops

  • Check for expensive operations in update()
  • Avoid dynamic allocation
  • Cache calculations
  • Reduce draw calls

Stuttering

  • Ensure frame-rate independence (use deltaTime)
  • Avoid blocking operations
  • Pre-load resources
  • Use object pooling

Next Steps

Now that you understand performance optimization, learn about: - Memory Management - Manage memory efficiently - Platforms and Drivers - Platform-specific optimizations - Extensibility - Extend the engine


See also: - Manual - Basic Rendering - Manual - Physics and Collisions

\ No newline at end of file +

Troubleshooting

Low FPS

  • Profile to find bottlenecks
  • Reduce entity count
  • Optimize rendering (culling, batching)
  • Simplify collision detection
  • Reduce update frequency

Frame Drops

  • Check for expensive operations in update()
  • Avoid dynamic allocation
  • Cache calculations
  • Reduce draw calls

Stuttering

  • Ensure frame-rate independence (use deltaTime)
  • Avoid blocking operations
  • Pre-load resources
  • Use object pooling

Next Steps

Now that you understand performance optimization, learn about: - Memory Management - Manage memory efficiently - Platforms and Drivers - Platform-specific optimizations - Extensibility - Extend the engine


See also: - Manual - Basic Rendering - Manual - Physics and Collisions

\ No newline at end of file diff --git a/site/manual/optimization/platforms_and_drivers/index.html b/site/manual/optimization/platforms_and_drivers/index.html index 63c8f39..ec73418 100644 --- a/site/manual/optimization/platforms_and_drivers/index.html +++ b/site/manual/optimization/platforms_and_drivers/index.html @@ -171,4 +171,4 @@ engine.run(); return 0; } -

Platform-Specific Considerations

ESP32

Memory: - Limited RAM (~320KB) - Use object pooling - Store data in flash - Avoid dynamic allocation

Performance: - Target 30-60 FPS - Optimize rendering - Reduce entity count - Profile on hardware

Hardware: - GPIO pin configuration - SPI display setup - Audio hardware connections - Power considerations

Native

Development: - Fast iteration - Easy debugging - Unlimited resources - Visual debugging tools

Testing: - Test logic without hardware - Rapid prototyping - CI/CD integration - Cross-platform testing

Troubleshooting

ESP32 Display Issues

  • Check wiring connections
  • Verify pin numbers
  • Lower SPI frequency
  • Check display type matches
  • Verify power supply

ESP32 Audio Issues

  • Check DAC/I2S pin configuration
  • Verify sample rate
  • Check hardware connections
  • Lower volume if distorted
  • Test with different sample rates

Native Build Issues

  • Verify SDL2 installation
  • Check include/library paths
  • Ensure SDL2 version compatibility
  • Check linker flags

Next Steps

Now that you understand platforms and drivers, learn about: - Extensibility - Create custom drivers - Memory Management - ESP32 memory constraints - Performance Optimization - Platform-specific optimization


See also: - API Reference - DrawSurface - API Reference - AudioBackend - Getting Started - Your First Project

\ No newline at end of file +

Platform-Specific Considerations

ESP32

Memory: - Limited RAM (~320KB) - Use object pooling - Store data in flash - Avoid dynamic allocation

Performance: - Target 30-60 FPS - Optimize rendering - Reduce entity count - Profile on hardware

Hardware: - GPIO pin configuration - SPI display setup - Audio hardware connections - Power considerations

Native

Development: - Fast iteration - Easy debugging - Unlimited resources - Visual debugging tools

Testing: - Test logic without hardware - Rapid prototyping - CI/CD integration - Cross-platform testing

Troubleshooting

ESP32 Display Issues

  • Check wiring connections
  • Verify pin numbers
  • Lower SPI frequency
  • Check display type matches
  • Verify power supply

ESP32 Audio Issues

  • Check DAC/I2S pin configuration
  • Verify sample rate
  • Check hardware connections
  • Lower volume if distorted
  • Test with different sample rates

Native Build Issues

  • Verify SDL2 installation
  • Check include/library paths
  • Ensure SDL2 version compatibility
  • Check linker flags

Next Steps

Now that you understand platforms and drivers, learn about: - Extensibility - Create custom drivers - Memory Management - ESP32 memory constraints - Performance Optimization - Platform-specific optimization


See also: - API Reference - DrawSurface - API Reference - AudioBackend - Getting Started - Your First Project

\ No newline at end of file diff --git a/site/reference/api_overview/index.html b/site/reference/api_overview/index.html index 2cde716..0e2ae3e 100644 --- a/site/reference/api_overview/index.html +++ b/site/reference/api_overview/index.html @@ -1,7 +1,7 @@ - API Overview - PixelRoot32 Documentation

API Reference Overview

This document provides a complete technical reference for all PixelRoot32 APIs, organized by module. Each class includes descriptions, constructors, methods, properties, and usage examples.

Organization

The API is organized into the following modules:

  • Core: Engine, Scene, Entity, Actor, PhysicsActor, SceneManager
  • Graphics: Renderer, Camera2D, Color, Font, Sprite, TileMap, DrawSurface
  • Audio: AudioEngine, MusicPlayer, AudioTypes, AudioConfig, AudioBackend
  • Input: InputManager, InputConfig
  • Physics: CollisionSystem, CollisionTypes
  • UI: UIElement, UIButton, UILabel, UILayouts
  • Particles: ParticleEmitter, ParticleConfig, ParticlePresets

Quick Navigation

Core Module

Graphics Module

Audio Module

Physics Module

UI Module

API Documentation Format

Each API reference page follows this structure:

Class Name

Brief description of the class and its purpose.

Namespace

namespace pixelroot32::module {
+ API Overview - PixelRoot32 Documentation      

API Reference Overview

This document provides a complete technical reference for all PixelRoot32 APIs, organized by module. Each class includes descriptions, constructors, methods, properties, and usage examples.

Organization

The API is organized into the following modules:

  • Core: Engine, Scene, Entity, Actor, PhysicsActor, SceneManager
  • Graphics: Renderer, Camera2D, Color, Font, Sprite, TileMap, DrawSurface
  • Audio: AudioEngine, MusicPlayer, AudioTypes, AudioConfig, AudioBackend
  • Input: InputManager, InputConfig
  • Physics: CollisionSystem, CollisionTypes
  • UI: UIElement, UIButton, UILabel, UILayouts
  • Particles: ParticleEmitter, ParticleConfig, ParticlePresets

Quick Navigation

Core Module

Graphics Module

Audio Module

Physics Module

UI Module

API Documentation Format

Each API reference page follows this structure:

Class Name

Brief description of the class and its purpose.

Namespace

namespace pixelroot32::module {
     class ClassName {
         // ...
     };
 }
 

Constructors

List of all constructors with parameters.

Public Methods

Method Description Parameters Returns
methodName() Description param: type return type

Properties

Property Type Description
property type Description

Usage Example

// Example code showing typical usage
-

Performance Notes

Any performance considerations or limitations.

See Also

Links to related APIs and documentation.

Finding APIs

By Functionality

By Module

Navigate to the specific module folder: - api_reference/core/ - Core engine classes - api_reference/graphics/ - Rendering and graphics - api_reference/audio/ - Audio system - api_reference/physics/ - Physics and collisions - api_reference/ui/ - User interface

Complete API List

Core

Graphics

Audio

Physics

UI


Note: This is an overview. For detailed API documentation, see the individual reference pages linked above.

\ No newline at end of file +

Performance Notes

Any performance considerations or limitations.

See Also

Links to related APIs and documentation.

Finding APIs

By Functionality

By Module

Navigate to the specific module folder: - api_reference/core/ - Core engine classes - api_reference/graphics/ - Rendering and graphics - api_reference/audio/ - Audio system - api_reference/physics/ - Physics and collisions - api_reference/ui/ - User interface

Complete API List

Core

Graphics

Audio

Physics

UI


Note: This is an overview. For detailed API documentation, see the individual reference pages linked above.

\ No newline at end of file diff --git a/site/reference/code_examples/index.html b/site/reference/code_examples/index.html index dd51a5a..1dc93b3 100644 --- a/site/reference/code_examples/index.html +++ b/site/reference/code_examples/index.html @@ -605,4 +605,4 @@ bool isActive() const { return active; } float getProgress() const { return static_cast<float>(elapsed) / duration; } }; -

See Also

\ No newline at end of file +

See Also

\ No newline at end of file diff --git a/site/reference/game_examples_guide/index.html b/site/reference/game_examples_guide/index.html index 45e7fad..9f04ef8 100644 --- a/site/reference/game_examples_guide/index.html +++ b/site/reference/game_examples_guide/index.html @@ -171,4 +171,4 @@ // 4. Draw UI/HUD drawHUD(renderer); } -

Learning Path

Beginner Examples

  1. Pong: Basic physics and collisions
  2. TicTacToe: Turn-based logic
  3. Snake: Entity pooling and grid

Intermediate Examples

  1. CameraDemo: Camera and parallax
  2. SpritesDemo: 2bpp and 4bpp formats
  3. BrickBreaker: Physics, particles and audio

Advanced Examples

  1. Space Invaders: Full game (1bpp sprites, collisions, audio)
  2. Metroidvania: Platformer with multi-layer 4bpp tilemap, tile-based collision and ESP32 optimizations (no scroll/camera)

Code Study Recommendations

For Learning Physics

  • Study Pong/BallActor.cpp - PhysicsActor usage
  • Study CameraDemo/PlayerCube.cpp - Platformer physics

For Learning Collisions

  • Study SpaceInvaders - Complex collision layers
  • Study Pong - Simple collision response

For Learning Memory Management

  • Study Snake/SnakeScene.cpp - Entity pooling
  • Study SpaceInvaders - Projectile pooling

For Learning Audio

  • Study SpaceInvaders - Music and sound effects
  • Study Pong - Simple audio integration

For Learning UI

  • Study TicTacToe - Button-based UI
  • Study menu scenes - Layout usage

Extending Examples

Adding Features

  • Pong: Add power-ups, multiple balls
  • Snake: Add obstacles, multiple food types
  • Space Invaders: Add boss battles, power-ups

Creating Variations

  • Pong: Make it vertical, add walls
  • Snake: Change to hexagonal grid
  • TicTacToe: Make it 4x4 or 5x5

Best Practices from Examples

  1. Pre-allocate Resources: All examples pre-allocate entities
  2. Use Object Pooling: For frequently created/destroyed entities
  3. Organize by Layers: Clear collision layer organization
  4. Separate Concerns: Game logic separate from rendering
  5. State Management: Clear game state handling

See Also


Note: All example code is available in the src/examples/ directory of the PixelRoot32 Game Samples project.

\ No newline at end of file +

Learning Path

Beginner Examples

  1. Pong: Basic physics and collisions
  2. TicTacToe: Turn-based logic
  3. Snake: Entity pooling and grid

Intermediate Examples

  1. CameraDemo: Camera and parallax
  2. SpritesDemo: 2bpp and 4bpp formats
  3. BrickBreaker: Physics, particles and audio

Advanced Examples

  1. Space Invaders: Full game (1bpp sprites, collisions, audio)
  2. Metroidvania: Platformer with multi-layer 4bpp tilemap, tile-based collision and ESP32 optimizations (no scroll/camera)

Code Study Recommendations

For Learning Physics

  • Study Pong/BallActor.cpp - PhysicsActor usage
  • Study CameraDemo/PlayerCube.cpp - Platformer physics

For Learning Collisions

  • Study SpaceInvaders - Complex collision layers
  • Study Pong - Simple collision response

For Learning Memory Management

  • Study Snake/SnakeScene.cpp - Entity pooling
  • Study SpaceInvaders - Projectile pooling

For Learning Audio

  • Study SpaceInvaders - Music and sound effects
  • Study Pong - Simple audio integration

For Learning UI

  • Study TicTacToe - Button-based UI
  • Study menu scenes - Layout usage

Extending Examples

Adding Features

  • Pong: Add power-ups, multiple balls
  • Snake: Add obstacles, multiple food types
  • Space Invaders: Add boss battles, power-ups

Creating Variations

  • Pong: Make it vertical, add walls
  • Snake: Change to hexagonal grid
  • TicTacToe: Make it 4x4 or 5x5

Best Practices from Examples

  1. Pre-allocate Resources: All examples pre-allocate entities
  2. Use Object Pooling: For frequently created/destroyed entities
  3. Organize by Layers: Clear collision layer organization
  4. Separate Concerns: Game logic separate from rendering
  5. State Management: Clear game state handling

See Also


Note: All example code is available in the src/examples/ directory of the PixelRoot32 Game Samples project.

\ No newline at end of file diff --git a/site/resources/available_tools/index.html b/site/resources/available_tools/index.html index bf46cf9..26e5614 100644 --- a/site/resources/available_tools/index.html +++ b/site/resources/available_tools/index.html @@ -61,4 +61,4 @@ #!/bin/bash pr32-sprite-compiler assets/sprites/*.png --output-dir src/sprites/ # Continue with build... -

Best Practices

  • Organize assets: Keep source images separate from generated code
  • Version control: Commit generated headers, not source images (or both)
  • Naming conventions: Use consistent naming for sprites
  • Batch processing: Process multiple sprites at once when possible

See Also


Note: Tool availability may vary. Check the PixelRoot32 repository for the latest tool information.

\ No newline at end of file +

Best Practices

  • Organize assets: Keep source images separate from generated code
  • Version control: Commit generated headers, not source images (or both)
  • Naming conventions: Use consistent naming for sprites
  • Batch processing: Process multiple sprites at once when possible

See Also


Note: Tool availability may vary. Check the PixelRoot32 repository for the latest tool information.

\ No newline at end of file diff --git a/site/resources/faq/index.html b/site/resources/faq/index.html index eaf71d2..c31e1fe 100644 --- a/site/resources/faq/index.html +++ b/site/resources/faq/index.html @@ -11,4 +11,4 @@ Serial.print("Free heap: "); Serial.println(ESP.getFreeHeap()); #endif -

Hardware

Which ESP32 board should I use?

Any ESP32 board works. Common choices: - ESP32-WROOM-32 - ESP32-WROVER (more RAM) - ESP32-DevKit

Which display should I use?

Popular choices: - ST7789: 240x240, good quality - ST7735: 128x128, smaller/cheaper - ILI9341: 240x320, larger

See Platforms and Drivers.

How many buttons do I need?

Minimum: 4 (UP, DOWN, LEFT, RIGHT) Recommended: 6 (add A and B buttons) More buttons can be added if needed.

Can I use analog joysticks?

Not directly supported. You can read analog pins manually and convert to digital input, but the engine expects digital buttons.

Troubleshooting

My display is blank. What's wrong?

  1. Check wiring connections
  2. Verify pin numbers in platformio.ini
  3. Lower SPI frequency
  4. Check display type matches hardware
  5. Verify power supply

See Troubleshooting.

Buttons don't work. Why?

  1. Check button wiring
  2. Verify pin numbers in InputConfig
  3. Check pull-up/pull-down resistors
  4. Ensure InputManager is being updated
  5. Test with isButtonDown() vs isButtonPressed()

Audio is distorted. How do I fix it?

  1. Lower volume levels
  2. Reduce sample rate (try 11025 Hz)
  3. Check for too many simultaneous sounds
  4. Verify hardware connections
  5. Check power supply

Game crashes randomly. What's happening?

Common causes: - Out of memory - Too many entities - Infinite loops - Stack overflow - Watchdog timeout

See Troubleshooting for debugging techniques.

Advanced

Can I extend the engine?

Yes, PixelRoot32 is designed to be extensible. You can: - Create custom display drivers - Create custom audio backends - Extend existing systems

See Extensibility.

Can I use 3D graphics?

No, PixelRoot32 is 2D-only. It's designed for sprite-based 2D games.

Can I add networking?

Not currently supported. The engine focuses on single-player games.

Can I save game data?

Not currently supported. A save system is planned for future versions.

Can I use multiple scenes at once?

Yes, use SceneManager to push/pop scenes. This is useful for menus and pause screens.

Getting Help

Where can I get help?

  • Documentation: This documentation site
  • Examples: Study example games in the samples project
  • Discord: Community Discord server
  • GitHub: Open an issue for bugs

How do I report a bug?

Create a detailed bug report with: - Platform (ESP32 or Native) - Hardware details - Minimal reproduction code - Error messages - Expected vs actual behavior

Can I contribute?

Yes! PixelRoot32 is open source. Check the main repository for contribution guidelines.

See Also


Can't find your question? Check the Troubleshooting guide or ask on the Discord server.

\ No newline at end of file +

Hardware

Which ESP32 board should I use?

Any ESP32 board works. Common choices: - ESP32-WROOM-32 - ESP32-WROVER (more RAM) - ESP32-DevKit

Which display should I use?

Popular choices: - ST7789: 240x240, good quality - ST7735: 128x128, smaller/cheaper - ILI9341: 240x320, larger

See Platforms and Drivers.

How many buttons do I need?

Minimum: 4 (UP, DOWN, LEFT, RIGHT) Recommended: 6 (add A and B buttons) More buttons can be added if needed.

Can I use analog joysticks?

Not directly supported. You can read analog pins manually and convert to digital input, but the engine expects digital buttons.

Troubleshooting

My display is blank. What's wrong?

  1. Check wiring connections
  2. Verify pin numbers in platformio.ini
  3. Lower SPI frequency
  4. Check display type matches hardware
  5. Verify power supply

See Troubleshooting.

Buttons don't work. Why?

  1. Check button wiring
  2. Verify pin numbers in InputConfig
  3. Check pull-up/pull-down resistors
  4. Ensure InputManager is being updated
  5. Test with isButtonDown() vs isButtonPressed()

Audio is distorted. How do I fix it?

  1. Lower volume levels
  2. Reduce sample rate (try 11025 Hz)
  3. Check for too many simultaneous sounds
  4. Verify hardware connections
  5. Check power supply

Game crashes randomly. What's happening?

Common causes: - Out of memory - Too many entities - Infinite loops - Stack overflow - Watchdog timeout

See Troubleshooting for debugging techniques.

Advanced

Can I extend the engine?

Yes, PixelRoot32 is designed to be extensible. You can: - Create custom display drivers - Create custom audio backends - Extend existing systems

See Extensibility.

Can I use 3D graphics?

No, PixelRoot32 is 2D-only. It's designed for sprite-based 2D games.

Can I add networking?

Not currently supported. The engine focuses on single-player games.

Can I save game data?

Not currently supported. A save system is planned for future versions.

Can I use multiple scenes at once?

Yes, use SceneManager to push/pop scenes. This is useful for menus and pause screens.

Getting Help

Where can I get help?

  • Documentation: This documentation site
  • Examples: Study example games in the samples project
  • Discord: Community Discord server
  • GitHub: Open an issue for bugs

How do I report a bug?

Create a detailed bug report with: - Platform (ESP32 or Native) - Hardware details - Minimal reproduction code - Error messages - Expected vs actual behavior

Can I contribute?

Yes! PixelRoot32 is open source. Check the main repository for contribution guidelines.

See Also


Can't find your question? Check the Troubleshooting guide or ask on the Discord server.

\ No newline at end of file diff --git a/site/resources/limitations_and_considerations/index.html b/site/resources/limitations_and_considerations/index.html index 19ef915..fa43ec1 100644 --- a/site/resources/limitations_and_considerations/index.html +++ b/site/resources/limitations_and_considerations/index.html @@ -1 +1 @@ - Limitations and Considerations - PixelRoot32 Documentation

Limitations and Considerations

This document honestly documents what PixelRoot32 can and cannot do, helping you make informed decisions about using the engine.

Hardware Limitations (ESP32)

Memory Constraints

RAM: - Available: ~320KB total (varies by ESP32 model) - Heap: Limited and fragmented over time - Stack: ~8KB, avoid large stack allocations - Impact: Limits entity count, sprite data, and dynamic allocation

Flash: - Available: 4MB+ (varies by model) - Usage: Program code, sprite data, assets - Impact: Large games may approach limits

Recommendations: - Use object pooling - Store data in flash (const/constexpr) - Avoid dynamic allocation in game loop - Keep entity count low

CPU Limitations

Performance: - Clock Speed: 240MHz (typically) - Single-threaded: One core handles everything - Target FPS: 30-60 FPS (depends on complexity) - Frame Budget: ~16-33ms per frame at 60 FPS

Impact: - Complex games may struggle - Many entities reduce performance - Expensive calculations hurt FPS

Recommendations: - Optimize rendering - Reduce entity count - Cache calculations - Profile on hardware

Display Limitations

Supported Displays: - TFT displays via SPI (ST7735, ST7789, ILI9341, etc.) - Limited to SPI displays - Resolution typically 128x128 to 320x240

Constraints: - SPI communication speed limits - Display initialization complexity - Power consumption

Audio Limitations

Hardware: - Internal DAC: Lower quality, simple setup - I2S: Higher quality, requires external DAC - Sample rates: 11025 Hz (DAC) or 22050 Hz (I2S)

Constraints: - 4 channels total (2 Pulse, 1 Triangle, 1 Noise) - Music uses one channel - Limited simultaneous sounds - Quality limited by hardware

Software Limitations

Entity System

MAX_ENTITIES = 32 per scene - Hard limit, cannot be changed easily - Applies to all entities (actors, UI, particles, etc.) - Must manage entity count carefully

Workarounds: - Use object pooling - Reuse entities - Disable entities instead of removing - Combine multiple entities into one

No RTTI (Runtime Type Information)

Impact: - Cannot use dynamic_cast in most code - Type checking must be done manually - Limits polymorphism patterns

Alternatives: - Use virtual functions - Manual type checking - Tag-based systems

No Exceptions in Critical Code

Impact: - Cannot use try/catch in game loop - Error handling must be explicit - Crashes instead of exceptions

Best Practices: - Validate inputs - Check return values - Use assertions for debugging - Handle errors explicitly

No Dynamic Allocation in Game Loop

Impact: - Cannot use new/delete during gameplay - Must pre-allocate resources - Limits flexibility

Solutions: - Object pooling - Pre-allocation in init() - Static buffers - Fixed-size arrays

No Advanced Features

Not Supported: - 3D graphics - Shaders - Advanced physics (joints, constraints) - Networking - File system (ESP32) - Advanced audio effects

Focus: - 2D sprite-based games - Simple physics - Retro-style games - Embedded-friendly features

Experimental Features

2bpp Sprites

Status: Experimental - Requires PIXELROOT32_ENABLE_2BPP_SPRITES flag - May have bugs or limitations - Not fully tested

Use with caution: - Test thoroughly - May change in future versions - Report issues if found

4bpp Sprites

Status: Experimental - Requires PIXELROOT32_ENABLE_4BPP_SPRITES flag - More experimental than 2bpp - Higher memory usage

Use with caution: - Test extensively - Monitor memory usage - May be unstable

Scene Arena

Status: Experimental - Requires PIXELROOT32_ENABLE_SCENE_ARENA flag - Alternative memory management - May have bugs

Recommendations: - Use object pooling instead (more stable) - Test thoroughly if using - May be removed or changed

Unsupported Features (Current)

Planned but Not Available

  • u8g2 Driver: Alternative display driver (planned)
  • Music Compiler: Tool to convert music files (planned)
  • Tilemap Compiler: Tool to create tilemaps (planned)
  • Save System: Persistent storage system (planned)
  • Spatial Partitioning: Advanced collision optimization (planned)

Not Planned

  • 3D Graphics: 2D-only engine
  • Networking: No network support
  • File System: No file I/O on ESP32
  • Advanced Audio: NES-like audio only
  • Scripting: No Lua/JavaScript support

Best Practices for ESP32

Memory Management

  • Pre-allocate: All resources in init()
  • Object pooling: Reuse entities
  • Flash storage: Use const/constexpr for data
  • Avoid strings: Use static buffers
  • Monitor usage: Check heap regularly

Performance

  • Limit entities: Stay well below MAX_ENTITIES
  • Optimize rendering: Use culling, batching
  • Cache calculations: Avoid repeated work
  • Profile on hardware: PC performance ≠ ESP32

Development

  • Test on hardware: Don't rely only on Native
  • Start simple: Add complexity gradually
  • Monitor memory: Watch for leaks
  • Optimize incrementally: Profile and optimize

What PixelRoot32 IS Good For

Retro-style 2D gamesArcade gamesPuzzle gamesPlatformersShootersEducational projectsPrototypingEmbedded game development

What PixelRoot32 is NOT Good For

3D gamesComplex physics simulationsLarge open worldsGames requiring many entitiesGames with complex graphicsNetwork multiplayerGames requiring file I/O

Making Informed Decisions

Before Starting a Project

  1. Assess requirements: Does PixelRoot32 fit?
  2. Check limitations: Can you work within constraints?
  3. Plan architecture: Design around limitations
  4. Test early: Verify on hardware early

If Limitations Are a Problem

Consider alternatives: - Full game engines (Unity, Godot) for complex games - Custom solutions for specific needs - Different hardware for more resources

Or work within limits: - Simplify game design - Optimize aggressively - Use creative solutions

Version Compatibility

Current Version

  • Engine Version: 0.2.0-dev
  • API Stability: May change
  • Breaking Changes: Possible in future versions

Recommendations: - Pin exact version in platformio.ini - Don't use ^ or fuzzy versioning - Test after engine updates - Review changelog

Honest Assessment

PixelRoot32 is designed for: - Simple to medium complexity games - Retro/arcade style - ESP32 hardware constraints - Rapid development

It is not designed for: - AAA game complexity - Modern graphics - Large-scale games - Unlimited resources

See Also


Remember: Understanding limitations helps you build better games within PixelRoot32's capabilities.

\ No newline at end of file + Limitations and Considerations - PixelRoot32 Documentation

Limitations and Considerations

This document honestly documents what PixelRoot32 can and cannot do, helping you make informed decisions about using the engine.

Hardware Limitations (ESP32)

Memory Constraints

RAM: - Available: ~320KB total (varies by ESP32 model) - Heap: Limited and fragmented over time - Stack: ~8KB, avoid large stack allocations - Impact: Limits entity count, sprite data, and dynamic allocation

Flash: - Available: 4MB+ (varies by model) - Usage: Program code, sprite data, assets - Impact: Large games may approach limits

Recommendations: - Use object pooling - Store data in flash (const/constexpr) - Avoid dynamic allocation in game loop - Keep entity count low

CPU Limitations

Performance: - Clock Speed: 240MHz (typically) - Single-threaded: One core handles everything - Target FPS: 30-60 FPS (depends on complexity) - Frame Budget: ~16-33ms per frame at 60 FPS

Impact: - Complex games may struggle - Many entities reduce performance - Expensive calculations hurt FPS

Recommendations: - Optimize rendering - Reduce entity count - Cache calculations - Profile on hardware

Display Limitations

Supported Displays: - TFT displays via SPI (ST7735, ST7789, ILI9341, etc.) - Limited to SPI displays - Resolution typically 128x128 to 320x240

Constraints: - SPI communication speed limits - Display initialization complexity - Power consumption

Audio Limitations

Hardware: - Internal DAC: Lower quality, simple setup - I2S: Higher quality, requires external DAC - Sample rates: 11025 Hz (DAC) or 22050 Hz (I2S)

Constraints: - 4 channels total (2 Pulse, 1 Triangle, 1 Noise) - Music uses one channel - Limited simultaneous sounds - Quality limited by hardware

Software Limitations

Entity System

MAX_ENTITIES = 32 per scene - Hard limit, cannot be changed easily - Applies to all entities (actors, UI, particles, etc.) - Must manage entity count carefully

Workarounds: - Use object pooling - Reuse entities - Disable entities instead of removing - Combine multiple entities into one

No RTTI (Runtime Type Information)

Impact: - Cannot use dynamic_cast in most code - Type checking must be done manually - Limits polymorphism patterns

Alternatives: - Use virtual functions - Manual type checking - Tag-based systems

No Exceptions in Critical Code

Impact: - Cannot use try/catch in game loop - Error handling must be explicit - Crashes instead of exceptions

Best Practices: - Validate inputs - Check return values - Use assertions for debugging - Handle errors explicitly

No Dynamic Allocation in Game Loop

Impact: - Cannot use new/delete during gameplay - Must pre-allocate resources - Limits flexibility

Solutions: - Object pooling - Pre-allocation in init() - Static buffers - Fixed-size arrays

No Advanced Features

Not Supported: - 3D graphics - Shaders - Advanced physics (joints, constraints) - Networking - File system (ESP32) - Advanced audio effects

Focus: - 2D sprite-based games - Simple physics - Retro-style games - Embedded-friendly features

Experimental Features

2bpp Sprites

Status: Experimental - Requires PIXELROOT32_ENABLE_2BPP_SPRITES flag - May have bugs or limitations - Not fully tested

Use with caution: - Test thoroughly - May change in future versions - Report issues if found

4bpp Sprites

Status: Experimental - Requires PIXELROOT32_ENABLE_4BPP_SPRITES flag - More experimental than 2bpp - Higher memory usage

Use with caution: - Test extensively - Monitor memory usage - May be unstable

Scene Arena

Status: Experimental - Requires PIXELROOT32_ENABLE_SCENE_ARENA flag - Alternative memory management - May have bugs

Recommendations: - Use object pooling instead (more stable) - Test thoroughly if using - May be removed or changed

Unsupported Features (Current)

Planned but Not Available

  • u8g2 Driver: Alternative display driver (planned)
  • Music Compiler: Tool to convert music files (planned)
  • Tilemap Compiler: Tool to create tilemaps (planned)
  • Save System: Persistent storage system (planned)
  • Spatial Partitioning: Advanced collision optimization (planned)

Not Planned

  • 3D Graphics: 2D-only engine
  • Networking: No network support
  • File System: No file I/O on ESP32
  • Advanced Audio: NES-like audio only
  • Scripting: No Lua/JavaScript support

Best Practices for ESP32

Memory Management

  • Pre-allocate: All resources in init()
  • Object pooling: Reuse entities
  • Flash storage: Use const/constexpr for data
  • Avoid strings: Use static buffers
  • Monitor usage: Check heap regularly

Performance

  • Limit entities: Stay well below MAX_ENTITIES
  • Optimize rendering: Use culling, batching
  • Cache calculations: Avoid repeated work
  • Profile on hardware: PC performance ≠ ESP32

Development

  • Test on hardware: Don't rely only on Native
  • Start simple: Add complexity gradually
  • Monitor memory: Watch for leaks
  • Optimize incrementally: Profile and optimize

What PixelRoot32 IS Good For

Retro-style 2D gamesArcade gamesPuzzle gamesPlatformersShootersEducational projectsPrototypingEmbedded game development

What PixelRoot32 is NOT Good For

3D gamesComplex physics simulationsLarge open worldsGames requiring many entitiesGames with complex graphicsNetwork multiplayerGames requiring file I/O

Making Informed Decisions

Before Starting a Project

  1. Assess requirements: Does PixelRoot32 fit?
  2. Check limitations: Can you work within constraints?
  3. Plan architecture: Design around limitations
  4. Test early: Verify on hardware early

If Limitations Are a Problem

Consider alternatives: - Full game engines (Unity, Godot) for complex games - Custom solutions for specific needs - Different hardware for more resources

Or work within limits: - Simplify game design - Optimize aggressively - Use creative solutions

Version Compatibility

Current Version

  • Engine Version: 0.2.0-dev
  • API Stability: May change
  • Breaking Changes: Possible in future versions

Recommendations: - Pin exact version in platformio.ini - Don't use ^ or fuzzy versioning - Test after engine updates - Review changelog

Honest Assessment

PixelRoot32 is designed for: - Simple to medium complexity games - Retro/arcade style - ESP32 hardware constraints - Rapid development

It is not designed for: - AAA game complexity - Modern graphics - Large-scale games - Unlimited resources

See Also


Remember: Understanding limitations helps you build better games within PixelRoot32's capabilities.

\ No newline at end of file diff --git a/site/resources/troubleshooting/index.html b/site/resources/troubleshooting/index.html index 4de5d9b..b3778ab 100644 --- a/site/resources/troubleshooting/index.html +++ b/site/resources/troubleshooting/index.html @@ -71,4 +71,4 @@ // Usage DEBUG_LOG("Entity created"); DEBUG_LOG("Collision detected"); -

Getting Help

If you can't resolve an issue:

  1. Check documentation: Review relevant guides
  2. Search examples: Look at example games
  3. Review code: Check engine source code
  4. Community: Ask on Discord or GitHub
  5. Report issue: Create detailed bug report

Bug Report Template

When reporting issues, include:

  • Platform: ESP32 or Native
  • Hardware: Display type, ESP32 model
  • Code: Minimal reproduction code
  • Error messages: Full error output
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Steps to reproduce: How to trigger the issue

See Also


Note: Many issues are configuration-related. Double-check your setup before assuming a bug.

\ No newline at end of file +

Getting Help

If you can't resolve an issue:

  1. Check documentation: Review relevant guides
  2. Search examples: Look at example games
  3. Review code: Check engine source code
  4. Community: Ask on Discord or GitHub
  5. Report issue: Create detailed bug report

Bug Report Template

When reporting issues, include:

  • Platform: ESP32 or Native
  • Hardware: Display type, ESP32 model
  • Code: Minimal reproduction code
  • Error messages: Full error output
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Steps to reproduce: How to trigger the issue

See Also


Note: Many issues are configuration-related. Double-check your setup before assuming a bug.

\ No newline at end of file diff --git a/site/search/search_index.json b/site/search/search_index.json index 8add885..637e307 100644 --- a/site/search/search_index.json +++ b/site/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"PixelRoot32 Documentation","text":"

PixelRoot32 is a lightweight 2D game engine designed for ESP32 and native desktop targets. This site provides official, versioned documentation with clear guides, conceptual explanations, API references, and complete examples to help you build games efficiently.

"},{"location":"#quick-links","title":"Quick Links","text":"
  • What is PixelRoot32? - Start here to understand the engine
  • Your First Project - Get up and running quickly
  • Fundamental Concepts - Learn the core concepts
  • Manual - Complete user guide
  • API Reference - Complete API documentation
  • Examples - Complete game examples
  • Tools - Available tools
  • FAQ - FAQ and troubleshooting
"},{"location":"#getting-started","title":"Getting Started","text":"

New to PixelRoot32? Follow this learning path:

  1. What is PixelRoot32? - Understand what the engine is and what it can do
  2. Why PixelRoot32? - Learn the advantages and use cases
  3. Fundamental Concepts - Learn the core architecture concepts
  4. Your First Project - Create and run your first project
"},{"location":"#about-this-documentation","title":"About This Documentation","text":"
  • Professional technical English across all pages
  • Search-enabled, mobile-friendly UI
  • Versioned with mike (stable/dev/experimental)
  • Cross-linked concepts, API, and examples
  • Progressive learning path from basics to advanced topics
"},{"location":"api_reference/audio/audio_config/","title":"AudioConfig","text":"

Configuration for the Audio subsystem.

"},{"location":"api_reference/audio/audio_config/#description","title":"Description","text":"

AudioConfig is a simple struct that holds configuration settings for the audio system, including the audio backend and sample rate. It is passed to AudioEngine during construction.

"},{"location":"api_reference/audio/audio_config/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    struct AudioConfig {\n        // ...\n    };\n}\n
"},{"location":"api_reference/audio/audio_config/#structure","title":"Structure","text":""},{"location":"api_reference/audio/audio_config/#audiobackend-backend","title":"AudioBackend* backend","text":"

Pointer to the platform-specific audio backend implementation.

Type: AudioBackend*

Access: Read-write

Default: nullptr

Notes: - Must be set to a valid backend instance - Backend is platform-specific: - ESP32: ESP32_DAC_AudioBackend or ESP32_I2S_AudioBackend - Native: SDL2_AudioBackend - Backend manages the actual audio hardware/API

Example:

#ifdef PLATFORM_ESP32\n    pixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\n    audioConfig.backend = &dacBackend;\n#elif PLATFORM_NATIVE\n    pixelroot32::drivers::native::SDL2_AudioBackend sdlBackend;\n    audioConfig.backend = &sdlBackend;\n#endif\n

"},{"location":"api_reference/audio/audio_config/#int-samplerate","title":"int sampleRate","text":"

Desired sample rate in Hz.

Type: int

Access: Read-write

Default: 22050

Notes: - Common values: 11025, 22050, 44100 - Lower rates use less CPU and memory (better for ESP32) - Higher rates provide better quality - Must match backend capabilities

Example:

audioConfig.sampleRate = 11025;  // Lower quality, less CPU (ESP32)\naudioConfig.sampleRate = 22050;  // Balanced (default)\naudioConfig.sampleRate = 44100; // Higher quality (Native)\n

"},{"location":"api_reference/audio/audio_config/#constructors","title":"Constructors","text":""},{"location":"api_reference/audio/audio_config/#audioconfigaudiobackend-backend-nullptr-int-samplerate-22050","title":"AudioConfig(AudioBackend* backend = nullptr, int sampleRate = 22050)","text":"

Default constructor.

Parameters: - backend (AudioBackend*, optional): Pointer to the audio backend implementation. Default: nullptr - sampleRate (int, optional): Desired sample rate in Hz. Default: 22050

Example:

// Default construction\npixelroot32::audio::AudioConfig audioConfig;\n\n// With backend\npixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\npixelroot32::audio::AudioConfig audioConfig(&dacBackend, 11025);\n

"},{"location":"api_reference/audio/audio_config/#usage-example","title":"Usage Example","text":""},{"location":"api_reference/audio/audio_config/#esp32-with-dac-backend","title":"ESP32 with DAC Backend","text":"
#ifdef PLATFORM_ESP32\n#include \"drivers/esp32/ESP32_DAC_AudioBackend.h\"\n\npixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &dacBackend;\naudioConfig.sampleRate = 11025;  // Lower rate for ESP32\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n#endif\n
"},{"location":"api_reference/audio/audio_config/#esp32-with-i2s-backend","title":"ESP32 with I2S Backend","text":"
#ifdef PLATFORM_ESP32\n#include \"drivers/esp32/ESP32_I2S_AudioBackend.h\"\n\npixelroot32::drivers::esp32::ESP32_I2S_AudioBackend i2sBackend;\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &i2sBackend;\naudioConfig.sampleRate = 22050;  // Higher quality with I2S\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n#endif\n
"},{"location":"api_reference/audio/audio_config/#native-with-sdl2-backend","title":"Native with SDL2 Backend","text":"
#ifdef PLATFORM_NATIVE\n#include \"drivers/native/SDL2_AudioBackend.h\"\n\npixelroot32::drivers::native::SDL2_AudioBackend sdlBackend;\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &sdlBackend;\naudioConfig.sampleRate = 44100;  // High quality for PC\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n#endif\n
"},{"location":"api_reference/audio/audio_config/#complete-engine-setup","title":"Complete Engine Setup","text":"
#include \"core/Engine.h\"\n#include \"graphics/DisplayConfig.h\"\n#include \"input/InputConfig.h\"\n#include \"audio/AudioConfig.h\"\n\nvoid setup() {\n    // Display config\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    displayConfig.width = 128;\n    displayConfig.height = 128;\n\n    // Input config\n    pixelroot32::input::InputConfig inputConfig;\n    // ... configure input\n\n    // Audio config\n    #ifdef PLATFORM_ESP32\n        pixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\n        pixelroot32::audio::AudioConfig audioConfig(&dacBackend, 11025);\n    #elif PLATFORM_NATIVE\n        pixelroot32::drivers::native::SDL2_AudioBackend sdlBackend;\n        pixelroot32::audio::AudioConfig audioConfig(&sdlBackend, 44100);\n    #endif\n\n    // Create engine with all configs\n    pixelroot32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/audio/audio_config/#platform-specific-considerations","title":"Platform-Specific Considerations","text":""},{"location":"api_reference/audio/audio_config/#esp32-dac-backend","title":"ESP32 DAC Backend","text":"
  • Sample rate: 11025 Hz recommended (lower CPU usage)
  • Quality: Lower quality, but simple setup
  • Pin: Uses GPIO 25 or 26
  • Hardware: Requires simple amplifier circuit
"},{"location":"api_reference/audio/audio_config/#esp32-i2s-backend","title":"ESP32 I2S Backend","text":"
  • Sample rate: 22050 Hz recommended
  • Quality: Higher quality than DAC
  • Pins: Requires I2S pins (BCLK, LRCK, DOUT)
  • Hardware: Requires external I2S DAC
"},{"location":"api_reference/audio/audio_config/#native-sdl2-backend","title":"Native SDL2 Backend","text":"
  • Sample rate: 44100 Hz typical
  • Quality: High quality
  • Setup: Requires SDL2 library installed
  • Platforms: Windows, Linux, macOS
"},{"location":"api_reference/audio/audio_config/#performance-considerations","title":"Performance Considerations","text":"
  • Sample rate: Lower rates use less CPU and memory
  • Backend choice: DAC is simpler but lower quality than I2S
  • Buffer size: Configured in backend, affects latency vs stability
"},{"location":"api_reference/audio/audio_config/#see-also","title":"See Also","text":"
  • AudioEngine - Audio playback engine
  • Manual - Audio
  • Manual - Platforms and Drivers
  • API Overview
"},{"location":"api_reference/audio/audio_engine/","title":"AudioEngine","text":"

Core class for the NES-like audio subsystem.

"},{"location":"api_reference/audio/audio_engine/#description","title":"Description","text":"

AudioEngine manages the audio channels (Pulse, Triangle, Noise), mixes their output, and provides the audio stream to the backend. It implements a NES-like audio system with 4 fixed channels: 2 Pulse channels, 1 Triangle channel, and 1 Noise channel.

The engine is event-driven: you trigger sound effects via playEvent(), and the engine automatically manages channel allocation and playback.

"},{"location":"api_reference/audio/audio_engine/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    class AudioEngine {\n        // ...\n    };\n}\n
"},{"location":"api_reference/audio/audio_engine/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages audio engine instance)
"},{"location":"api_reference/audio/audio_engine/#constructors","title":"Constructors","text":""},{"location":"api_reference/audio/audio_engine/#audioengineconst-audioconfig-config","title":"AudioEngine(const AudioConfig& config)","text":"

Constructs the AudioEngine with the given configuration.

Parameters: - config (const AudioConfig&): Configuration struct containing the backend and parameters (sample rate, etc.)

Example:

#include \"audio/AudioEngine.h\"\n#include \"audio/AudioConfig.h\"\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &audioBackend;  // Platform-specific backend\naudioConfig.sampleRate = 22050;       // 22.05 kHz for retro feel\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n

"},{"location":"api_reference/audio/audio_engine/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/audio/audio_engine/#void-init","title":"void init()","text":"

Initializes the audio subsystem and the backend.

Returns: - void

Notes: - Must be called after construction and before use - Initializes the platform-specific audio backend - Safe to call multiple times (idempotent) - Typically called automatically by Engine::init()

Example:

AudioEngine audioEngine(audioConfig);\naudioEngine.init();  // Initialize before use\n

"},{"location":"api_reference/audio/audio_engine/#void-updateunsigned-long-deltatime","title":"void update(unsigned long deltaTime)","text":"

Updates the audio state based on game time.

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Returns: - void

Notes: - Should be called from the main game loop (typically via Engine::update()) - Updates channel lifetimes and durations - Automatically stops channels when their duration expires - Must be called every frame for proper audio timing

Example:

void update(unsigned long deltaTime) override {\n    // Update audio (called automatically by Engine)\n    engine.getAudioEngine().update(deltaTime);\n\n    // Your game logic...\n}\n

"},{"location":"api_reference/audio/audio_engine/#void-generatesamplesint16_t-stream-int-length","title":"void generateSamples(int16_t* stream, int length)","text":"

Fills the provided buffer with mixed audio samples.

Parameters: - stream (int16_t*): Pointer to the buffer to fill - length (int): Number of samples to generate

Returns: - void

Notes: - This method is typically called by the AudioBackend from an audio callback or task - Not usually called directly by game code - Generates 16-bit signed integer PCM samples - Mixes all active channels into a mono stream

Advanced Usage:

// Typically not called directly, but if implementing custom backend:\nint16_t buffer[512];\naudioEngine.generateSamples(buffer, 512);\n

"},{"location":"api_reference/audio/audio_engine/#void-playeventconst-audioevent-event","title":"void playEvent(const AudioEvent& event)","text":"

Triggers a one-shot sound effect.

Parameters: - event (const AudioEvent&): The audio event to play

Returns: - void

Notes: - Automatically finds an available channel of the correct type - If no channel is available, the event may be dropped (no error) - Events are fire-and-forget (no need to track playback) - Use for sound effects, not background music

Example:

// Play a jump sound\npixelroot32::audio::AudioEvent jumpSound{};\njumpSound.type = pixelroot32::audio::WaveType::PULSE;\njumpSound.frequency = 800.0f;\njumpSound.duration = 0.1f;\njumpSound.volume = 0.7f;\njumpSound.duty = 0.5f;\n\nauto& audio = engine.getAudioEngine();\naudio.playEvent(jumpSound);\n\n// Play an explosion sound\npixelroot32::audio::AudioEvent explosion{};\nexplosion.type = pixelroot32::audio::WaveType::NOISE;\nexplosion.frequency = 1000.0f;\nexplosion.duration = 0.3f;\nexplosion.volume = 0.9f;\n\naudio.playEvent(explosion);\n

"},{"location":"api_reference/audio/audio_engine/#void-setmastervolumefloat-volume","title":"void setMasterVolume(float volume)","text":"

Sets the master volume for all audio output.

Parameters: - volume (float): Volume level (0.0 = silent, 1.0 = full volume)

Returns: - void

Notes: - Affects all channels and events - Clamped to [0.0, 1.0] range - Use for volume control menus or mute functionality

Example:

auto& audio = engine.getAudioEngine();\naudio.setMasterVolume(0.5f);  // 50% volume\naudio.setMasterVolume(0.0f);  // Mute\naudio.setMasterVolume(1.0f);  // Full volume\n

"},{"location":"api_reference/audio/audio_engine/#float-getmastervolume-const","title":"float getMasterVolume() const","text":"

Gets the current master volume.

Returns: - float: Current master volume (0.0 to 1.0)

Example:

float currentVolume = audioEngine.getMasterVolume();\n

"},{"location":"api_reference/audio/audio_engine/#audio-channels","title":"Audio Channels","text":"

The engine manages 4 fixed channels:

  1. Channel 0: Pulse wave
  2. Channel 1: Pulse wave
  3. Channel 2: Triangle wave
  4. Channel 3: Noise wave

Notes: - Channels are automatically allocated when playing events - If all channels of a type are busy, new events may be dropped - Background music typically uses one channel (via MusicPlayer)

"},{"location":"api_reference/audio/audio_engine/#usage-example","title":"Usage Example","text":"
#include \"audio/AudioEngine.h\"\n#include \"audio/AudioConfig.h\"\n\nclass MyScene : public pixelroot32::core::Scene {\nprivate:\n    void playJumpSound() {\n        auto& audio = engine.getAudioEngine();\n\n        pixelroot32::audio::AudioEvent sound{};\n        sound.type = pixelroot32::audio::WaveType::PULSE;\n        sound.frequency = 800.0f;\n        sound.duration = 0.1f;\n        sound.volume = 0.7f;\n        sound.duty = 0.5f;\n\n        audio.playEvent(sound);\n    }\n\n    void playHitSound() {\n        auto& audio = engine.getAudioEngine();\n\n        pixelroot32::audio::AudioEvent sound{};\n        sound.type = pixelroot32::audio::WaveType::NOISE;\n        sound.frequency = 500.0f;\n        sound.duration = 0.05f;\n        sound.volume = 0.5f;\n\n        audio.playEvent(sound);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Audio is updated automatically by Engine\n        // Just play events when needed\n        if (playerJumped) {\n            playJumpSound();\n            playerJumped = false;\n        }\n    }\n};\n
"},{"location":"api_reference/audio/audio_engine/#performance-considerations","title":"Performance Considerations","text":"
  • Channel limit: Only 4 channels total; plan sound effects accordingly
  • Event dropping: If all channels are busy, new events are silently dropped
  • Update frequency: update() must be called every frame for proper timing
  • Sample generation: generateSamples() is called by backend at audio rate (not game rate)
"},{"location":"api_reference/audio/audio_engine/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Sample rate: Lower sample rates (11025 Hz) use less CPU and memory
  • Backend choice: DAC backend is simpler but lower quality than I2S
  • Buffer size: Larger buffers reduce underruns but increase latency
  • Channel management: Limit simultaneous sounds to avoid channel conflicts
"},{"location":"api_reference/audio/audio_engine/#see-also","title":"See Also","text":"
  • AudioConfig - Audio configuration
  • AudioTypes - Audio data structures
  • MusicPlayer - Background music playback
  • Manual - Audio
  • API Overview
"},{"location":"api_reference/audio/audio_types/","title":"Audio Types","text":"

Data structures and types for the audio system.

"},{"location":"api_reference/audio/audio_types/#description","title":"Description","text":"

This document describes the data structures used by the audio system, including wave types, audio events, and channel state.

"},{"location":"api_reference/audio/audio_types/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    // Types and structures\n}\n
"},{"location":"api_reference/audio/audio_types/#wavetype-enum","title":"WaveType Enum","text":"

Defines the types of waveforms available.

Values: - WaveType::PULSE: Pulse wave (square wave with variable duty cycle) - WaveType::TRIANGLE: Triangle wave (smooth, melodic) - WaveType::NOISE: Noise wave (random, percussive)

Example:

pixelroot32::audio::WaveType wave = pixelroot32::audio::WaveType::PULSE;\n

"},{"location":"api_reference/audio/audio_types/#audioevent-structure","title":"AudioEvent Structure","text":"

A fire-and-forget sound event triggered by the game.

Members: - WaveType type: Type of waveform to use - float frequency: Frequency in Hz - float duration: Duration in seconds - float volume: Volume level (0.0 to 1.0) - float duty: Duty cycle for pulse wave (0.0 to 1.0, pulse only)

Example:

pixelroot32::audio::AudioEvent jumpSound{};\njumpSound.type = pixelroot32::audio::WaveType::PULSE;\njumpSound.frequency = 800.0f;\njumpSound.duration = 0.1f;\njumpSound.volume = 0.7f;\njumpSound.duty = 0.5f;\n\nauto& audio = engine.getAudioEngine();\naudio.playEvent(jumpSound);\n

"},{"location":"api_reference/audio/audio_types/#common-sound-effects","title":"Common Sound Effects","text":"

Jump Sound:

pixelroot32::audio::AudioEvent jump{};\njump.type = pixelroot32::audio::WaveType::PULSE;\njump.frequency = 800.0f;\njump.duration = 0.1f;\njump.volume = 0.7f;\njump.duty = 0.5f;\n

Hit Sound:

pixelroot32::audio::AudioEvent hit{};\nhit.type = pixelroot32::audio::WaveType::NOISE;\nhit.frequency = 500.0f;\nhit.duration = 0.05f;\nhit.volume = 0.5f;\n

Collect Sound:

pixelroot32::audio::AudioEvent collect{};\ncollect.type = pixelroot32::audio::WaveType::TRIANGLE;\ncollect.frequency = 1000.0f;\ncollect.duration = 0.15f;\ncollect.volume = 0.6f;\n

Explosion:

pixelroot32::audio::AudioEvent explosion{};\nexplosion.type = pixelroot32::audio::WaveType::NOISE;\nexplosion.frequency = 200.0f;\nexplosion.duration = 0.3f;\nexplosion.volume = 0.9f;\n

"},{"location":"api_reference/audio/audio_types/#audiochannel-structure","title":"AudioChannel Structure","text":"

Represents the internal state of a single audio channel.

Members: - bool enabled: Whether the channel is active - WaveType type: Type of waveform - float frequency: Current frequency in Hz - float phase: Current phase (0.0 to 1.0) - float phaseIncrement: Pre-calculated phase increment - float volume: Current volume (0.0 to 1.0) - float targetVolume: Target volume for envelopes - float dutyCycle: Duty cycle for pulse wave (0.0 to 1.0) - uint16_t noiseRegister: LFSR state for noise generation - unsigned long durationMs: Total duration in milliseconds - unsigned long remainingMs: Remaining duration in milliseconds

Methods: - void reset(): Resets the channel to inactive state

Notes: - Internal structure, typically not accessed directly - Managed automatically by AudioEngine - 4 channels total: 2 Pulse, 1 Triangle, 1 Noise

"},{"location":"api_reference/audio/audio_types/#frequency-reference","title":"Frequency Reference","text":"

Common frequencies for musical notes (A4 = 440 Hz):

  • C4: 261.63 Hz
  • D4: 293.66 Hz
  • E4: 329.63 Hz
  • F4: 349.23 Hz
  • G4: 392.00 Hz
  • A4: 440.00 Hz
  • B4: 493.88 Hz
  • C5: 523.25 Hz

Example:

// Play a C note\npixelroot32::audio::AudioEvent note{};\nnote.type = pixelroot32::audio::WaveType::PULSE;\nnote.frequency = 261.63f;  // C4\nnote.duration = 0.5f;\nnote.volume = 0.8f;\nnote.duty = 0.5f;\n

"},{"location":"api_reference/audio/audio_types/#duty-cycle-pulse-wave","title":"Duty Cycle (Pulse Wave)","text":"

Duty cycle controls the shape of the pulse wave:

  • 0.125 (12.5%): Thin pulse (NES-like)
  • 0.25 (25%): Narrow pulse
  • 0.5 (50%): Square wave (most common)
  • 0.75 (75%): Wide pulse

Example:

// Thin pulse (NES style)\nevent.duty = 0.125f;\n\n// Square wave (standard)\nevent.duty = 0.5f;\n

"},{"location":"api_reference/audio/audio_types/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/audio/audio_types/#creating-sound-effect-library","title":"Creating Sound Effect Library","text":"
namespace SoundEffects {\n    // Jump sound\n    inline pixelroot32::audio::AudioEvent jump() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 800.0f;\n        evt.duration = 0.1f;\n        evt.volume = 0.7f;\n        evt.duty = 0.5f;\n        return evt;\n    }\n\n    // Hit sound\n    inline pixelroot32::audio::AudioEvent hit() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::NOISE;\n        evt.frequency = 500.0f;\n        evt.duration = 0.05f;\n        evt.volume = 0.5f;\n        return evt;\n    }\n\n    // Collect sound\n    inline pixelroot32::audio::AudioEvent collect() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::TRIANGLE;\n        evt.frequency = 1000.0f;\n        evt.duration = 0.15f;\n        evt.volume = 0.6f;\n        return evt;\n    }\n}\n\n// Usage\nauto& audio = engine.getAudioEngine();\naudio.playEvent(SoundEffects::jump());\naudio.playEvent(SoundEffects::hit());\n
"},{"location":"api_reference/audio/audio_types/#frequency-sweep-effect","title":"Frequency Sweep Effect","text":"
void playSweepSound() {\n    auto& audio = engine.getAudioEngine();\n\n    // Create multiple events for sweep effect\n    for (int i = 0; i < 5; i++) {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 400.0f + (i * 200.0f);  // Sweep from 400 to 1200 Hz\n        evt.duration = 0.05f;\n        evt.volume = 0.6f;\n        evt.duty = 0.5f;\n\n        audio.playEvent(evt);\n        delay(50);  // Small delay between events\n    }\n}\n
"},{"location":"api_reference/audio/audio_types/#performance-considerations","title":"Performance Considerations","text":"
  • Event creation: Creating events is fast (just struct initialization)
  • Channel allocation: Events are queued and played when channels are available
  • Frequency range: Keep frequencies in reasonable range (100-5000 Hz) for best results
  • Duration: Shorter durations free channels faster
"},{"location":"api_reference/audio/audio_types/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Events are small structs, safe to create frequently
  • CPU: Audio generation is efficient but limit simultaneous sounds
  • Quality: Lower sample rates reduce CPU usage
"},{"location":"api_reference/audio/audio_types/#see-also","title":"See Also","text":"
  • AudioEngine - Audio playback engine
  • AudioConfig - Audio configuration
  • Manual - Audio
  • API Overview
"},{"location":"api_reference/audio/music_player/","title":"MusicPlayer","text":"

Lightweight sequencer built on top of AudioEngine to play background melodies as tracks.

"},{"location":"api_reference/audio/music_player/#description","title":"Description","text":"

MusicPlayer is a simple sequencer that plays MusicTrack structures. It advances notes based on game time, converts MusicNote entries to AudioEvent calls, and manages playback state (play, stop, pause, resume).

The player uses one audio channel (typically a Pulse channel) for music, leaving other channels available for sound effects.

"},{"location":"api_reference/audio/music_player/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    class MusicPlayer {\n        // ...\n    };\n}\n
"},{"location":"api_reference/audio/music_player/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages music player instance)
"},{"location":"api_reference/audio/music_player/#constructors","title":"Constructors","text":""},{"location":"api_reference/audio/music_player/#musicplayeraudioengine-engine","title":"MusicPlayer(AudioEngine& engine)","text":"

Constructs the MusicPlayer.

Parameters: - engine (AudioEngine&): Reference to the AudioEngine used to play sounds

Notes: - Typically created and managed by Engine - Access via engine.getMusicPlayer()

Example:

auto& audio = engine.getAudioEngine();\npixelroot32::audio::MusicPlayer musicPlayer(audio);\n

"},{"location":"api_reference/audio/music_player/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/audio/music_player/#void-playconst-musictrack-track","title":"void play(const MusicTrack& track)","text":"

Starts playing a track.

Parameters: - track (const MusicTrack&): The track to play

Returns: - void

Notes: - Stops any currently playing track - Starts from the beginning of the track - If track has loop = true, will loop automatically - Uses one audio channel (typically Pulse)

Example:

static const MusicNote MELODY[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),\n};\n\nstatic const MusicTrack GAME_MUSIC = {\n    MELODY,\n    sizeof(MELODY) / sizeof(MusicNote),\n    true,  // loop\n    WaveType::PULSE,\n    0.5f   // volume\n};\n\nvoid init() override {\n    auto& music = engine.getMusicPlayer();\n    music.play(GAME_MUSIC);\n}\n

"},{"location":"api_reference/audio/music_player/#void-stop","title":"void stop()","text":"

Stops playback and silences the channel.

Returns: - void

Notes: - Immediately stops the current note - Resets playback to the beginning - Channel is freed for other use

Example:

void onGameOver() {\n    auto& music = engine.getMusicPlayer();\n    music.stop();\n}\n

"},{"location":"api_reference/audio/music_player/#void-pause","title":"void pause()","text":"

Pauses playback.

Returns: - void

Notes: - Current note continues until it ends, then playback pauses - Playback state is preserved (can resume from where it paused) - Use for pause menus

Example:

void onPause() {\n    auto& music = engine.getMusicPlayer();\n    music.pause();\n}\n

"},{"location":"api_reference/audio/music_player/#void-resume","title":"void resume()","text":"

Resumes playback.

Returns: - void

Notes: - Only works if playback was paused - Resumes from where it was paused - Use to unpause after pause menu

Example:

void onResume() {\n    auto& music = engine.getMusicPlayer();\n    music.resume();\n}\n

"},{"location":"api_reference/audio/music_player/#void-updateunsigned-long-deltatime","title":"void update(unsigned long deltaTime)","text":"

Updates the player state. Should be called every frame.

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Returns: - void

Notes: - Must be called every frame for proper timing - Advances note playback based on elapsed time - Automatically plays next notes in sequence - Typically called automatically by Engine

Example:

// Called automatically by Engine, but can be called manually:\nvoid update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);\n\n    // Music player is updated automatically by Engine\n    // No need to call manually\n}\n

"},{"location":"api_reference/audio/music_player/#bool-isplaying-const","title":"bool isPlaying() const","text":"

Checks if a track is currently playing.

Returns: - bool: true if playing, false otherwise

Notes: - Returns false if stopped or paused - Use to check playback state before operations

Example:

auto& music = engine.getMusicPlayer();\nif (music.isPlaying()) {\n    // Music is active\n} else {\n    // Music is stopped or paused\n}\n

"},{"location":"api_reference/audio/music_player/#void-settempofactorfloat-factor","title":"void setTempoFactor(float factor)","text":"

Sets the global tempo scaling factor.

Parameters: - factor (float): Tempo multiplier - 1.0f: Normal speed - 2.0f: Double speed - 0.5f: Half speed

Returns: - void

Notes: - Affects all note durations - Useful for speed-up effects or slow-motion - Applied to all tracks

Example:

auto& music = engine.getMusicPlayer();\nmusic.setTempoFactor(1.5f);  // 50% faster\nmusic.setTempoFactor(0.5f);   // 50% slower\nmusic.setTempoFactor(1.0f);   // Normal speed\n

"},{"location":"api_reference/audio/music_player/#float-gettempofactor-const","title":"float getTempoFactor() const","text":"

Gets the current tempo scaling factor.

Returns: - float: Current factor (default 1.0f)

Example:

float currentTempo = musicPlayer.getTempoFactor();\n

"},{"location":"api_reference/audio/music_player/#musictrack-structure","title":"MusicTrack Structure","text":"

A MusicTrack contains:

  • notes (const MusicNote*): Array of music notes
  • noteCount (size_t): Number of notes in the array
  • loop (bool): Whether to loop the track
  • waveType (WaveType): Wave type to use (typically PULSE)
  • volume (float): Volume level (0.0 to 1.0)
"},{"location":"api_reference/audio/music_player/#musicnote-structure","title":"MusicNote Structure","text":"

A MusicNote contains:

  • instrument (InstrumentPreset): Instrument preset to use
  • note (Note): Musical note (C, D, E, etc.)
  • duration (float): Duration in seconds

Use helper functions: - makeNote(instrument, note, duration): Create a note - makeRest(duration): Create a rest (silence)

"},{"location":"api_reference/audio/music_player/#usage-example","title":"Usage Example","text":"
#include \"audio/MusicPlayer.h\"\n#include \"audio/AudioMusicTypes.h\"\n\nusing namespace pixelroot32::audio;\n\n// Define a simple melody\nstatic const MusicNote MAIN_THEME[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.25f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.25f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.1f),\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.5f),\n    makeRest(0.2f),\n};\n\nstatic const MusicTrack MAIN_THEME_TRACK = {\n    MAIN_THEME,\n    sizeof(MAIN_THEME) / sizeof(MusicNote),\n    true,           // loop\n    WaveType::PULSE,\n    0.6f            // volume\n};\n\nclass GameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Start background music\n        auto& music = engine.getMusicPlayer();\n        music.play(MAIN_THEME_TRACK);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Music updates automatically\n    }\n\n    void onPauseMenu() {\n        auto& music = engine.getMusicPlayer();\n        music.pause();\n    }\n\n    void onResumeGame() {\n        auto& music = engine.getMusicPlayer();\n        music.resume();\n    }\n\n    void onGameOver() {\n        auto& music = engine.getMusicPlayer();\n        music.stop();\n    }\n};\n
"},{"location":"api_reference/audio/music_player/#performance-considerations","title":"Performance Considerations","text":"
  • One channel: Music uses one channel, leaving others for sound effects
  • Update frequency: update() must be called every frame
  • Track size: Larger tracks use more memory (store in flash)
  • Tempo factor: Changing tempo is fast (just a multiplier)
"},{"location":"api_reference/audio/music_player/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store tracks in flash (const/constexpr) to save RAM
  • CPU: Music playback is lightweight (simple sequencing)
  • Channel conflict: Music and sound effects share channels; plan accordingly
"},{"location":"api_reference/audio/music_player/#see-also","title":"See Also","text":"
  • AudioEngine - Audio playback engine
  • AudioTypes - Audio data structures
  • AudioMusicTypes - Music data structures
  • Manual - Audio
  • API Overview
"},{"location":"api_reference/core/actor/","title":"Actor","text":"

An Entity capable of physical interaction and collision.

"},{"location":"api_reference/core/actor/#description","title":"Description","text":"

Actor extends Entity with collision layers and masks. Actors are used for dynamic game objects like players, enemies, projectiles, and obstacles that need to interact with each other through collision detection.

Actors participate in the collision system and can detect collisions with other actors based on their collision layers and masks.

"},{"location":"api_reference/core/actor/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Actor : public Entity {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/actor/#inheritance","title":"Inheritance","text":"
  • Inherits from: Entity
  • Inherited by: PhysicsActor and your custom actor classes
"},{"location":"api_reference/core/actor/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/actor/#actorfloat-x-float-y-int-w-int-h","title":"Actor(float x, float y, int w, int h)","text":"

Creates a new actor with specified position and size.

Parameters: - x (float): Initial X position in world space - y (float): Initial Y position in world space - w (int): Actor width in pixels - h (int): Actor height in pixels

Notes: - Actor type is automatically set to EntityType::ACTOR - Collision layer and mask default to DefaultLayers::kNone - Must set collision layer and mask for collision detection to work

Example:

class PlayerActor : public pixelroot32::core::Actor {\npublic:\n    PlayerActor(float x, float y) \n        : Actor(x, y, 16, 16) {\n        // Set collision layer and mask\n        layer = pixelroot32::physics::DefaultLayers::kPlayer;\n        mask = pixelroot32::physics::DefaultLayers::kEnemy | \n               pixelroot32::physics::DefaultLayers::kObstacle;\n    }\n\n    void update(unsigned long deltaTime) override {\n        Actor::update(deltaTime);\n        // Player logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawSprite(playerSprite, \n                           static_cast<int>(x), \n                           static_cast<int>(y), \n                           Color::White);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        // Handle collision\n    }\n};\n

"},{"location":"api_reference/core/actor/#public-properties","title":"Public Properties","text":""},{"location":"api_reference/core/actor/#collisionlayer-layer","title":"CollisionLayer layer","text":"

The collision layer this actor belongs to.

Type: pixelroot32::physics::CollisionLayer (uint16_t)

Access: Read-write

Default: DefaultLayers::kNone

Notes: - Defines which layer this actor is on - Use bit flags to assign multiple layers (e.g., kPlayer | kProjectile) - Only actors with matching layers in their mask will collide

Example:

actor->layer = pixelroot32::physics::DefaultLayers::kPlayer;\n

"},{"location":"api_reference/core/actor/#collisionlayer-mask","title":"CollisionLayer mask","text":"

The collision layers this actor interacts with.

Type: pixelroot32::physics::CollisionLayer (uint16_t)

Access: Read-write

Default: DefaultLayers::kNone

Notes: - Defines which layers this actor can collide with - Use bit flags to check multiple layers (e.g., kEnemy | kObstacle) - Collision only occurs if the other actor's layer matches bits in this mask

Example:

// Actor collides with enemies and obstacles\nactor->mask = pixelroot32::physics::DefaultLayers::kEnemy | \n              pixelroot32::physics::DefaultLayers::kObstacle;\n

"},{"location":"api_reference/core/actor/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/actor/#void-setcollisionlayercollisionlayer-l","title":"void setCollisionLayer(CollisionLayer l)","text":"

Sets the collision layer for this actor.

Parameters: - l (pixelroot32::physics::CollisionLayer): The layer to set

Returns: - void

Notes: - Equivalent to setting layer directly - Use bit flags for multiple layers

Example:

actor->setCollisionLayer(pixelroot32::physics::DefaultLayers::kPlayer);\n

"},{"location":"api_reference/core/actor/#void-setcollisionmaskcollisionlayer-m","title":"void setCollisionMask(CollisionLayer m)","text":"

Sets the collision mask for this actor.

Parameters: - m (pixelroot32::physics::CollisionLayer): The mask to set

Returns: - void

Notes: - Equivalent to setting mask directly - Use bit flags for multiple layers

Example:

actor->setCollisionMask(pixelroot32::physics::DefaultLayers::kEnemy | \n                        pixelroot32::physics::DefaultLayers::kObstacle);\n

"},{"location":"api_reference/core/actor/#bool-isinlayeruint16_t-targetlayer-const","title":"bool isInLayer(uint16_t targetLayer) const","text":"

Checks if the Actor belongs to a specific collision layer.

Parameters: - targetLayer (uint16_t): The bit(s) to check (e.g., DefaultLayers::kPlayer)

Returns: - bool: true if the bit is set in the actor's layer

Notes: - Uses bitwise AND operation - Useful for checking if an actor is on a specific layer

Example:

if (actor->isInLayer(pixelroot32::physics::DefaultLayers::kPlayer)) {\n    // This is a player actor\n}\n

"},{"location":"api_reference/core/actor/#virtual-rect-gethitbox-0","title":"virtual Rect getHitBox() = 0","text":"

Gets the hitbox for collision detection. Must be implemented by derived classes.

Returns: - Rect: A rectangle representing the collision bounds

Notes: - Called by the collision system to check collisions - Should return the actual collision bounds (may differ from visual size) - Use AABB (Axis-Aligned Bounding Box) for efficiency

Example:

Rect getHitBox() override {\n    // Return collision bounds (may be smaller than visual)\n    return {x + 2, y + 2, width - 4, height - 4};\n}\n

"},{"location":"api_reference/core/actor/#virtual-void-oncollisionactor-other-0","title":"virtual void onCollision(Actor* other) = 0","text":"

Callback invoked when a collision occurs. Must be implemented by derived classes.

Parameters: - other (Actor*): The actor that this actor collided with

Notes: - Called automatically by the collision system when a collision is detected - Both actors' onCollision() methods are called - Use to handle collision responses (damage, bouncing, etc.)

Example:

void onCollision(Actor* other) override {\n    // Check what we collided with\n    if (other->isInLayer(pixelroot32::physics::DefaultLayers::kEnemy)) {\n        // Take damage\n        health--;\n        if (health <= 0) {\n            isEnabled = false;\n        }\n    } else if (other->isInLayer(pixelroot32::physics::DefaultLayers::kCollectible)) {\n        // Collect item\n        score += 10;\n        other->isEnabled = false;  // Remove collectible\n    }\n}\n

"},{"location":"api_reference/core/actor/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the actor logic. Default implementation does nothing.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Override to implement actor-specific update logic - Called automatically by Scene if isEnabled is true - Use deltaTime for frame-rate independent movement

Example:

void update(unsigned long deltaTime) override {\n    Actor::update(deltaTime);  // Call base implementation\n\n    // Move actor\n    float speed = 100.0f;  // pixels per second\n    x += (speed * deltaTime) / 1000.0f;\n}\n

"},{"location":"api_reference/core/actor/#collision-layers","title":"Collision Layers","text":"

Collision layers use bit flags to organize actors into groups. Common layers:

  • DefaultLayers::kNone (0): No layer
  • DefaultLayers::kPlayer (1 << 0): Player actors
  • DefaultLayers::kEnemy (1 << 1): Enemy actors
  • DefaultLayers::kObstacle (1 << 2): Obstacles/walls
  • DefaultLayers::kProjectile (1 << 3): Projectiles
  • DefaultLayers::kCollectible (1 << 4): Collectible items

Example:

// Player collides with enemies and obstacles\nplayer->layer = DefaultLayers::kPlayer;\nplayer->mask = DefaultLayers::kEnemy | DefaultLayers::kObstacle;\n\n// Enemy collides with player and obstacles\nenemy->layer = DefaultLayers::kEnemy;\nenemy->mask = DefaultLayers::kPlayer | DefaultLayers::kObstacle;\n\n// Projectile collides with enemies\nprojectile->layer = DefaultLayers::kProjectile;\nprojectile->mask = DefaultLayers::kEnemy;\n

"},{"location":"api_reference/core/actor/#usage-example","title":"Usage Example","text":"
#include \"core/Actor.h\"\n#include \"physics/CollisionTypes.h\"\n\nclass EnemyActor : public pixelroot32::core::Actor {\nprivate:\n    const pixelroot32::graphics::Sprite* sprite;\n    int health = 3;\n\npublic:\n    EnemyActor(float x, float y) \n        : Actor(x, y, 16, 16),\n          sprite(&enemySprite) {\n        // Set collision layer and mask\n        layer = pixelroot32::physics::DefaultLayers::kEnemy;\n        mask = pixelroot32::physics::DefaultLayers::kPlayer | \n               pixelroot32::physics::DefaultLayers::kProjectile;\n    }\n\n    void update(unsigned long deltaTime) override {\n        Actor::update(deltaTime);\n\n        // Move towards player\n        float speed = 50.0f;\n        // ... movement logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawSprite(*sprite, \n                           static_cast<int>(x), \n                           static_cast<int>(y), \n                           Color::Red);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        if (other->isInLayer(pixelroot32::physics::DefaultLayers::kProjectile)) {\n            // Hit by projectile\n            health--;\n            if (health <= 0) {\n                isEnabled = false;  // Remove enemy\n            }\n        }\n    }\n};\n
"},{"location":"api_reference/core/actor/#performance-considerations","title":"Performance Considerations","text":"
  • Collision layers: Use layers efficiently to reduce collision checks
  • Hitbox size: Keep hitboxes simple (AABB) for best performance
  • Collision callbacks: Keep onCollision() fast; avoid expensive operations
  • Layer organization: Group actors by layer to minimize checks
"},{"location":"api_reference/core/actor/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Collision checks: Collision system automatically optimizes using layers
  • Memory: Each actor consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse actors instead of creating/destroying frequently
"},{"location":"api_reference/core/actor/#see-also","title":"See Also","text":"
  • Entity - Base entity class
  • PhysicsActor - Entity with physics
  • CollisionSystem - Collision detection
  • CollisionTypes - Collision layer definitions
  • Manual - Scenes and Entities
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/core/engine/","title":"Engine","text":"

The main engine class that manages the game loop and core subsystems.

"},{"location":"api_reference/core/engine/#description","title":"Description","text":"

Engine acts as the central hub of the PixelRoot32 game engine. It initializes and manages the Renderer, InputManager, AudioEngine, and SceneManager. It runs the main game loop, handling timing (delta time), updating the current scene, and rendering frames.

The engine provides a unified interface for both ESP32 and Native (SDL2) platforms, abstracting platform-specific details while maintaining consistent behavior.

"},{"location":"api_reference/core/engine/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Engine {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/engine/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Application entry point (main.cpp)
"},{"location":"api_reference/core/engine/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/engine/#engineconst-displayconfig-displayconfig-const-inputconfig-inputconfig-const-audioconfig-audioconfig","title":"Engine(const DisplayConfig& displayConfig, const InputConfig& inputConfig, const AudioConfig& audioConfig)","text":"

Creates a new engine instance with custom display, input, and audio configurations.

Parameters: - displayConfig (const pixelroot32::graphics::DisplayConfig&): Configuration settings for the display (width, height, rotation, etc.) - inputConfig (const pixelroot32::input::InputConfig&): Configuration settings for the input system (pins, buttons) - audioConfig (const pixelroot32::audio::AudioConfig&): Configuration settings for the audio system (backend, sample rate, buffer size)

Example:

#include \"core/Engine.h\"\n#include \"graphics/DisplayConfig.h\"\n#include \"input/InputConfig.h\"\n#include \"audio/AudioConfig.h\"\n\npixelroot32::graphics::DisplayConfig displayConfig;\ndisplayConfig.logicalWidth = 128;\ndisplayConfig.logicalHeight = 128;\n\npixelroot32::input::InputConfig inputConfig;\n// Configure input pins...\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = pixelroot32::audio::AudioConfig::Backend::ESP32_DAC;\naudioConfig.sampleRate = 11025;\n\npixelroot32::core::Engine engine(displayConfig, inputConfig, audioConfig);\nengine.init();\nengine.run();\n

"},{"location":"api_reference/core/engine/#engineconst-displayconfig-displayconfig-const-inputconfig-inputconfig","title":"Engine(const DisplayConfig& displayConfig, const InputConfig& inputConfig)","text":"

Creates a new engine instance with custom display and input configurations, using default audio settings.

Parameters: - displayConfig (const pixelroot32::graphics::DisplayConfig&): Configuration settings for the display - inputConfig (const pixelroot32::input::InputConfig&): Configuration settings for the input system

Example:

pixelroot32::core::Engine engine(displayConfig, inputConfig);\nengine.init();\nengine.run();\n

"},{"location":"api_reference/core/engine/#engineconst-displayconfig-displayconfig","title":"Engine(const DisplayConfig& displayConfig)","text":"

Creates a new engine instance with custom display configuration and default input/audio settings.

Parameters: - displayConfig (const pixelroot32::graphics::DisplayConfig&): Configuration settings for the display

Example:

pixelroot32::core::Engine engine(displayConfig);\nengine.init();\nengine.run();\n

"},{"location":"api_reference/core/engine/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/engine/#void-init","title":"void init()","text":"

Initializes the engine subsystems. This method must be called before run().

Returns: - void

Notes: - Initializes the Renderer, InputManager, and sets up the initial state - Must be called after construction and before run() - Safe to call multiple times (idempotent)

Example:

Engine engine(displayConfig);\nengine.init();  // Initialize subsystems\nengine.setScene(myScene);\nengine.run();   // Start game loop\n

"},{"location":"api_reference/core/engine/#void-run","title":"void run()","text":"

Starts the main game loop. This method contains the infinite loop that calls update() and draw() repeatedly until the application exits.

Returns: - void

Notes: - This method blocks until the application exits - Handles frame timing and delta time calculation automatically - Calls update() and draw() once per frame - Do not call this method multiple times

Example:

Engine engine(displayConfig);\nengine.init();\nengine.setScene(myScene);\nengine.run();  // Blocks here, runs game loop\n

"},{"location":"api_reference/core/engine/#unsigned-long-getdeltatime-const","title":"unsigned long getDeltaTime() const","text":"

Gets the time elapsed since the last frame.

Returns: - unsigned long: The delta time in milliseconds

Performance Notes: - Very fast (inline accessor) - Safe to call every frame - Use this value to make movement frame-rate independent

Example:

void update(unsigned long deltaTime) override {\n    auto& engine = getEngine();\n    unsigned long dt = engine.getDeltaTime();\n\n    // Move at constant speed regardless of FPS\n    float speed = 100.0f;  // pixels per second\n    x += (speed * dt) / 1000.0f;\n}\n

"},{"location":"api_reference/core/engine/#void-setscenescene-newscene","title":"void setScene(Scene* newScene)","text":"

Sets the current active scene to be updated and rendered.

Parameters: - newScene (Scene*): Pointer to the new Scene to become active. Can be nullptr to clear the current scene.

Notes: - The previous scene is replaced (not pushed onto a stack) - Use SceneManager for push/pop operations if needed - The scene's init() method will be called automatically - Safe to call during the game loop

Example:

class MainMenuScene : public pixelroot32::core::Scene {\n    // ...\n};\n\nclass GameScene : public pixelroot32::core::Scene {\n    // ...\n};\n\nMainMenuScene menuScene;\nGameScene gameScene;\n\nEngine engine(displayConfig);\nengine.init();\nengine.setScene(&menuScene);  // Start with menu\nengine.run();\n

"},{"location":"api_reference/core/engine/#scene-getcurrentscene-const","title":"Scene* getCurrentScene() const","text":"

Retrieves the currently active scene.

Returns: - Scene*: Pointer to the current Scene, or nullptr if none is set

Example:

auto* currentScene = engine.getCurrentScene();\nif (currentScene) {\n    // Scene is active\n}\n

"},{"location":"api_reference/core/engine/#void-setrendererrenderer-newrenderer","title":"void setRenderer(Renderer& newRenderer)","text":"

Replaces the current renderer instance.

Parameters: - newRenderer (pixelroot32::graphics::Renderer&): Reference to the new Renderer to use

Notes: - Advanced usage: typically not needed unless implementing custom renderer - The renderer must be properly initialized before use - Use with caution: may break existing rendering code

"},{"location":"api_reference/core/engine/#renderer-getrenderer","title":"Renderer& getRenderer()","text":"

Provides access to the Renderer subsystem.

Returns: - pixelroot32::graphics::Renderer&: Reference to the current Renderer

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    auto& engineRenderer = engine.getRenderer();\n    engineRenderer.drawSprite(mySprite, 100, 100, Color::White);\n}\n

"},{"location":"api_reference/core/engine/#inputmanager-getinputmanager","title":"InputManager& getInputManager()","text":"

Provides access to the InputManager subsystem.

Returns: - pixelroot32::input::InputManager&: Reference to the InputManager

Example:

void update(unsigned long deltaTime) override {\n    auto& input = engine.getInputManager();\n    if (input.isButtonPressed(Buttons::A)) {\n        // Handle button press\n    }\n}\n

"},{"location":"api_reference/core/engine/#audioengine-getaudioengine","title":"AudioEngine& getAudioEngine()","text":"

Provides access to the AudioEngine subsystem.

Returns: - pixelroot32::audio::AudioEngine&: Reference to the AudioEngine

Example:

void playSound() {\n    auto& audio = engine.getAudioEngine();\n    pixelroot32::audio::AudioEvent sound{};\n    sound.type = pixelroot32::audio::WaveType::PULSE;\n    sound.frequency = 800.0f;\n    sound.duration = 0.1f;\n    audio.playEvent(sound);\n}\n

"},{"location":"api_reference/core/engine/#musicplayer-getmusicplayer","title":"MusicPlayer& getMusicPlayer()","text":"

Provides access to the MusicPlayer subsystem.

Returns: - pixelroot32::audio::MusicPlayer&: Reference to the MusicPlayer

Example:

void playMusic() {\n    auto& music = engine.getMusicPlayer();\n    music.playTrack(myMusicTrack);\n}\n

"},{"location":"api_reference/core/engine/#optional-debug-statistics-overlay","title":"Optional: Debug Statistics Overlay","text":"

When the engine is built with the preprocessor define PIXELROOT32_ENABLE_DEBUG_OVERLAY, an on-screen technical overlay is drawn each frame.

Metrics Included:

  • FPS: Frames per second (Green).
  • RAM: Used heap memory in KB (Cyan).
  • CPU: Estimated processor load percentage (Yellow).

Behavior:

  • The overlay is drawn in the top-right area of the screen.
  • It is rendered after the scene, making it fixed and independent of the camera.

Performance:

  • Metric values are recalculated and formatted only every 16 frames (DEBUG_UPDATE_INTERVAL).
  • Cached strings are drawn every frame to minimize per-frame cost (division and snprintf).

How to enable:

In platformio.ini, add to your environment's build_flags:

build_flags =\n    -D PIXELROOT32_ENABLE_DEBUG_OVERLAY\n

Alternatively, you can enable it in EngineConfig.h. The implementation uses the private method drawDebugOverlay(Renderer& r), which is only compiled when the define is set.

See also: Performance Tuning - Profiling and Platforms and Drivers - Build flags.

"},{"location":"api_reference/core/engine/#usage-example","title":"Usage Example","text":"
#include \"core/Engine.h\"\n#include \"graphics/DisplayConfig.h\"\n#include \"MyScene.h\"\n\nvoid setup() {\n    // Configure display\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    displayConfig.logicalWidth = 128;\n    displayConfig.logicalHeight = 128;\n    displayConfig.rotation = 0;\n\n    // Create engine\n    pixelroot32::core::Engine engine(displayConfig);\n\n    // Initialize\n    engine.init();\n\n    // Create and set scene\n    MyScene myScene;\n    engine.setScene(&myScene);\n\n    // Run game loop\n    engine.run();\n}\n
"},{"location":"api_reference/core/engine/#performance-considerations","title":"Performance Considerations","text":"
  • Initialization: init() should be called once at startup, not in the game loop
  • Scene switching: Switching scenes is fast but avoid doing it every frame
  • Subsystem access: Getters are inline and very fast; safe to call every frame
  • Delta time: Use getDeltaTime() for frame-rate independent movement
"},{"location":"api_reference/core/engine/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Ensure init() completes before run() to avoid initialization issues
  • Monitor memory usage when switching scenes frequently
  • Use getDeltaTime() for consistent gameplay across different frame rates
"},{"location":"api_reference/core/engine/#see-also","title":"See Also","text":"
  • Scene - Scene management
  • Renderer - Rendering system
  • InputManager - Input handling
  • AudioEngine - Audio system
  • Getting Started - Fundamental Concepts
  • Manual - Scenes and Entities
  • API Overview
"},{"location":"api_reference/core/entity/","title":"Entity","text":"

Abstract base class for all game objects.

"},{"location":"api_reference/core/entity/#description","title":"Description","text":"

Entity is the fundamental building block of the scene. Entities have a position, size, and lifecycle methods (update, draw). All game objects inherit from Entity, including actors, UI elements, and custom game objects.

Entities are managed by Scene and are automatically updated and drawn each frame when enabled and visible.

"},{"location":"api_reference/core/entity/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Entity {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/entity/#inheritance","title":"Inheritance","text":"
  • Base class: None (abstract base class)
  • Inherited by: Actor, UI elements, and your custom entity classes
"},{"location":"api_reference/core/entity/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/entity/#entityfloat-x-float-y-int-w-int-h-entitytype-t","title":"Entity(float x, float y, int w, int h, EntityType t)","text":"

Creates a new entity with specified position, size, and type.

Parameters: - x (float): Initial X position in world space - y (float): Initial Y position in world space - w (int): Width in pixels - h (int): Height in pixels - t (EntityType): The type of entity (GENERIC, ACTOR, UI_ELEMENT)

Example:

class MyEntity : public pixelroot32::core::Entity {\npublic:\n    MyEntity(float x, float y) \n        : Entity(x, y, 16, 16, EntityType::GENERIC) {}\n\n    void update(unsigned long deltaTime) override {\n        // Update logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw logic\n    }\n};\n

"},{"location":"api_reference/core/entity/#public-properties","title":"Public Properties","text":""},{"location":"api_reference/core/entity/#float-x-y","title":"float x, y","text":"

Position of the entity in world space.

Type: float

Access: Read-write

Notes: - Position is in world coordinates, not screen coordinates - Can be modified directly or through helper methods - Use for entity positioning and movement

Example:

entity->x = 100.0f;\nentity->y = 50.0f;\n

"},{"location":"api_reference/core/entity/#int-width-height","title":"int width, height","text":"

Dimensions of the entity in pixels.

Type: int

Access: Read-write

Notes: - Used for collision detection, rendering bounds, and layout - Should match the visual size of the entity - Can be modified at runtime if needed

Example:

entity->width = 32;\nentity->height = 32;\n

"},{"location":"api_reference/core/entity/#entitytype-type","title":"EntityType type","text":"

The specific type of this entity.

Type: EntityType enum

Access: Read-only (set in constructor)

Values: - EntityType::GENERIC: Generic entity - EntityType::ACTOR: Actor entity (with collision) - EntityType::UI_ELEMENT: UI element

Notes: - Used for type-safe casting and logic differentiation - Set once in constructor, typically not changed

"},{"location":"api_reference/core/entity/#bool-isvisible","title":"bool isVisible","text":"

If false, the entity's draw() method will not be called.

Type: bool

Access: Read-write

Default: true

Notes: - Use to hide entities without removing them from the scene - More efficient than removing and re-adding entities - Useful for object pooling

Example:

entity->isVisible = false;  // Hide entity\nentity->setVisible(true);   // Show entity\n

"},{"location":"api_reference/core/entity/#bool-isenabled","title":"bool isEnabled","text":"

If false, the entity's update() method will not be called.

Type: bool

Access: Read-write

Default: true

Notes: - Use to disable entity logic without removing it - Entity still exists but doesn't update - Useful for paused entities or object pooling

Example:

entity->isEnabled = false;  // Disable updates\nentity->setEnabled(true);   // Enable updates\n

"},{"location":"api_reference/core/entity/#unsigned-char-renderlayer","title":"unsigned char renderLayer","text":"

The render layer this entity is drawn on.

Type: unsigned char

Access: Read-write

Default: 1

Notes: - Layers are drawn in ascending order (0 = background, 1 = gameplay, 2 = UI) - Entities on the same layer are drawn in add order - Use to control draw order without changing entity order

Example:

entity->renderLayer = 0;  // Background layer\nentity->setRenderLayer(2); // UI layer\n

"},{"location":"api_reference/core/entity/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/entity/#virtual-void-setvisiblebool-v","title":"virtual void setVisible(bool v)","text":"

Sets the visibility of the entity.

Parameters: - v (bool): true to show, false to hide

Returns: - void

Notes: - Equivalent to setting isVisible directly - Can be overridden for custom visibility logic

Example:

entity->setVisible(false);  // Hide\nentity->setVisible(true);   // Show\n

"},{"location":"api_reference/core/entity/#virtual-void-setenabledbool-e","title":"virtual void setEnabled(bool e)","text":"

Sets the enabled state of the entity.

Parameters: - e (bool): true to enable, false to disable

Returns: - void

Notes: - Equivalent to setting isEnabled directly - Can be overridden for custom enable logic

Example:

entity->setEnabled(false);  // Disable updates\nentity->setEnabled(true);   // Enable updates\n

"},{"location":"api_reference/core/entity/#unsigned-char-getrenderlayer-const","title":"unsigned char getRenderLayer() const","text":"

Gets the current render layer.

Returns: - unsigned char: The render layer (0-255)

Example:

unsigned char layer = entity->getRenderLayer();\n

"},{"location":"api_reference/core/entity/#virtual-void-setrenderlayerunsigned-char-layer","title":"virtual void setRenderLayer(unsigned char layer)","text":"

Sets the render layer for this entity.

Parameters: - layer (unsigned char): The render layer (0 = background, 1 = gameplay, 2 = UI)

Returns: - void

Example:

entity->setRenderLayer(0);  // Background\n

"},{"location":"api_reference/core/entity/#virtual-void-updateunsigned-long-deltatime-0","title":"virtual void update(unsigned long deltaTime) = 0","text":"

Updates the entity's logic. Must be implemented by derived classes.

Parameters: - deltaTime (unsigned long): Time elapsed since the last frame in milliseconds

Returns: - void

Notes: - Called automatically by Scene every frame if isEnabled is true - Use deltaTime for frame-rate independent movement - Override to implement entity-specific update logic

Example:

void update(unsigned long deltaTime) override {\n    // Move entity\n    float speed = 50.0f;  // pixels per second\n    x += (speed * deltaTime) / 1000.0f;\n\n    // Wrap around screen\n    if (x > 128) {\n        x = 0;\n    }\n}\n

"},{"location":"api_reference/core/entity/#virtual-void-drawrenderer-renderer-0","title":"virtual void draw(Renderer& renderer) = 0","text":"

Renders the entity. Must be implemented by derived classes.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer to use for drawing

Returns: - void

Notes: - Called automatically by Scene every frame if isVisible is true - Entities are drawn in render layer order, then in add order - Override to implement entity-specific drawing logic

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Draw sprite at entity position\n    renderer.drawSprite(mySprite, static_cast<int>(x), static_cast<int>(y), Color::White);\n}\n

"},{"location":"api_reference/core/entity/#entitytype-enum","title":"EntityType Enum","text":"

Categorizes entities for type-safe casting and logic differentiation.

Values: - EntityType::GENERIC: Generic entity (default) - EntityType::ACTOR: Actor entity (with collision support) - EntityType::UI_ELEMENT: UI element

Example:

if (entity->type == EntityType::ACTOR) {\n    Actor* actor = static_cast<Actor*>(entity);\n    // Use actor-specific methods\n}\n

"},{"location":"api_reference/core/entity/#rect-structure","title":"Rect Structure","text":"

Represents a 2D rectangle, typically used for hitboxes or bounds.

Members: - float x, y: Top-left corner coordinates - int width, height: Dimensions of the rectangle

Methods: - bool intersects(const Rect& other): Checks if this rectangle intersects with another

Example:

pixelroot32::core::Rect rect1{10.0f, 20.0f, 50, 50};\npixelroot32::core::Rect rect2{30.0f, 40.0f, 50, 50};\n\nif (rect1.intersects(rect2)) {\n    // Rectangles overlap\n}\n

"},{"location":"api_reference/core/entity/#usage-example","title":"Usage Example","text":"
#include \"core/Entity.h\"\n\nclass Collectible : public pixelroot32::core::Entity {\nprivate:\n    const pixelroot32::graphics::Sprite* sprite;\n\npublic:\n    Collectible(float x, float y) \n        : Entity(x, y, 8, 8, EntityType::GENERIC),\n          sprite(&collectibleSprite) {}\n\n    void update(unsigned long deltaTime) override {\n        // Rotate or animate\n        rotation += deltaTime * 0.001f;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        if (isVisible) {\n            renderer.drawSprite(*sprite, \n                               static_cast<int>(x), \n                               static_cast<int>(y), \n                               Color::Yellow);\n        }\n    }\n\nprivate:\n    float rotation = 0.0f;\n};\n
"},{"location":"api_reference/core/entity/#performance-considerations","title":"Performance Considerations","text":"
  • Visibility: Use isVisible = false instead of removing entities when hiding
  • Enable state: Use isEnabled = false to pause entity logic
  • Render layers: Organize entities by layer to minimize layer switches
  • Direct access: Direct property access is fast (no function call overhead)
"},{"location":"api_reference/core/entity/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Each entity consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse entities instead of creating/destroying frequently
  • Update frequency: Disable entities that don't need to update every frame
"},{"location":"api_reference/core/entity/#see-also","title":"See Also","text":"
  • Scene - Scene management
  • Actor - Entity with collision support
  • PhysicsActor - Entity with physics
  • Manual - Scenes and Entities
  • API Overview
"},{"location":"api_reference/core/input_config/","title":"InputConfig","text":"

Configuration structure for the InputManager.

"},{"location":"api_reference/core/input_config/#description","title":"Description","text":"

InputConfig defines the mapping between logical inputs and physical pins (ESP32) or keyboard keys (Native/SDL2). It uses variadic arguments to allow flexible configuration of any number of inputs.

The configuration is platform-specific: ESP32 uses GPIO pin numbers, while Native uses SDL keyboard scancodes.

"},{"location":"api_reference/core/input_config/#namespace","title":"Namespace","text":"
namespace pixelroot32::input {\n    struct InputConfig {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/input_config/#structure","title":"Structure","text":""},{"location":"api_reference/core/input_config/#int-count","title":"int count","text":"

Total number of configured inputs.

Type: int

Access: Read-write

Default: 0

Notes: - Must match the number of arguments provided to constructor - Determines the size of the internal button array

"},{"location":"api_reference/core/input_config/#int-inputpins-esp32-only","title":"int* inputPins (ESP32 only)","text":"

Array of GPIO pin numbers for ESP32.

Type: int*

Access: Read-write

Default: nullptr

Notes: - Only available on ESP32 platform - Array size equals count - Pin numbers correspond to ESP32 GPIO pins - Use nullptr if count is 0

Example:

// ESP32: 6 buttons on pins 0, 2, 4, 5, 18, 19\npixelroot32::input::InputConfig config(6, 0, 2, 4, 5, 18, 19);\n// config.inputPins[0] = 0  (Up)\n// config.inputPins[1] = 2  (Down)\n// config.inputPins[2] = 4  (Left)\n// config.inputPins[3] = 5  (Right)\n// config.inputPins[4] = 18 (Button A)\n// config.inputPins[5] = 19 (Button B)\n

"},{"location":"api_reference/core/input_config/#uint8_t-buttonnames-native-only","title":"uint8_t* buttonNames (Native only)","text":"

Array of button mappings (scancodes) for Native.

Type: uint8_t*

Access: Read-write

Default: nullptr

Notes: - Only available on Native platform - Array size equals count - Values are SDL keyboard scancodes - Use nullptr if count is 0

Example:

// Native: Map to keyboard keys\n#include <SDL2/SDL.h>\n\npixelroot32::input::InputConfig config(6,\n    SDL_SCANCODE_UP,    // Index 0\n    SDL_SCANCODE_DOWN,  // Index 1\n    SDL_SCANCODE_LEFT,  // Index 2\n    SDL_SCANCODE_RIGHT, // Index 3\n    SDL_SCANCODE_X,     // Index 4 (Button A)\n    SDL_SCANCODE_Z      // Index 5 (Button B)\n);\n

"},{"location":"api_reference/core/input_config/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/input_config/#inputconfigint-count","title":"InputConfig(int count, ...)","text":"

Constructs a new InputConfig with variadic arguments.

Parameters: - count (int): Number of inputs to configure - ... (variadic): Variable arguments list of pins (ESP32) or scancodes (Native)

Notes: - If count <= 0, configuration is empty (nullptr arrays) - Allocates arrays dynamically based on count - Arguments must match count in number - Platform-specific: ESP32 expects int (GPIO pins), Native expects int (SDL scancodes)

ESP32 Example:

// Configure 4 directional buttons\npixelroot32::input::InputConfig config(4, 0, 2, 4, 5);\n// Pin 0 = Up, Pin 2 = Down, Pin 4 = Left, Pin 5 = Right\n\n// Configure 6 buttons (4 directions + 2 action buttons)\npixelroot32::input::InputConfig config(6, 0, 2, 4, 5, 18, 19);\n

Native Example:

#include <SDL2/SDL.h>\n\n// Configure 4 directional buttons\npixelroot32::input::InputConfig config(4,\n    SDL_SCANCODE_UP,\n    SDL_SCANCODE_DOWN,\n    SDL_SCANCODE_LEFT,\n    SDL_SCANCODE_RIGHT\n);\n\n// Configure 6 buttons (4 directions + 2 action buttons)\npixelroot32::input::InputConfig config(6,\n    SDL_SCANCODE_UP,\n    SDL_SCANCODE_DOWN,\n    SDL_SCANCODE_LEFT,\n    SDL_SCANCODE_RIGHT,\n    SDL_SCANCODE_X,  // Button A\n    SDL_SCANCODE_Z   // Button B\n);\n

"},{"location":"api_reference/core/input_config/#usage-example","title":"Usage Example","text":""},{"location":"api_reference/core/input_config/#esp32-configuration","title":"ESP32 Configuration","text":"
#include \"input/InputConfig.h\"\n#include \"input/InputManager.h\"\n#include \"core/Engine.h\"\n\nvoid setup() {\n    // Configure input: 6 buttons\n    // Pins: Up=0, Down=2, Left=4, Right=5, A=18, B=19\n    pixelroot32::input::InputConfig inputConfig(6, 0, 2, 4, 5, 18, 19);\n\n    // Create input manager\n    pixelroot32::input::InputManager inputManager(inputConfig);\n    inputManager.init();\n\n    // Or use with Engine\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    pixelroot32::core::Engine engine(displayConfig, inputConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/core/input_config/#native-configuration","title":"Native Configuration","text":"
#include \"input/InputConfig.h\"\n#include <SDL2/SDL.h>\n\nvoid setup() {\n    // Configure input: 6 buttons mapped to keyboard\n    pixelroot32::input::InputConfig inputConfig(6,\n        SDL_SCANCODE_UP,    // Index 0: Up\n        SDL_SCANCODE_DOWN,  // Index 1: Down\n        SDL_SCANCODE_LEFT,  // Index 2: Left\n        SDL_SCANCODE_RIGHT, // Index 3: Right\n        SDL_SCANCODE_X,     // Index 4: Button A\n        SDL_SCANCODE_Z      // Index 5: Button B\n    );\n\n    // Use with Engine\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    pixelroot32::core::Engine engine(displayConfig, inputConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/core/input_config/#platform-agnostic-configuration","title":"Platform-Agnostic Configuration","text":"
#ifdef PLATFORM_ESP32\n    // ESP32: Use GPIO pins\n    pixelroot32::input::InputConfig inputConfig(6, 0, 2, 4, 5, 18, 19);\n#elif PLATFORM_NATIVE\n    // Native: Use SDL scancodes\n    #include <SDL2/SDL.h>\n    pixelroot32::input::InputConfig inputConfig(6,\n        SDL_SCANCODE_UP,\n        SDL_SCANCODE_DOWN,\n        SDL_SCANCODE_LEFT,\n        SDL_SCANCODE_RIGHT,\n        SDL_SCANCODE_X,\n        SDL_SCANCODE_Z\n    );\n#endif\n
"},{"location":"api_reference/core/input_config/#button-index-mapping","title":"Button Index Mapping","text":"

Button indices are determined by the order in the constructor:

Typical Convention: - Index 0: Up / Primary action - Index 1: Down / Secondary action - Index 2: Left - Index 3: Right - Index 4+: Additional buttons

Example:

// 4-button D-pad\nInputConfig config(4, UP_PIN, DOWN_PIN, LEFT_PIN, RIGHT_PIN);\n// Index 0 = Up, Index 1 = Down, Index 2 = Left, Index 3 = Right\n\n// 6-button setup (D-pad + 2 action buttons)\nInputConfig config(6, UP_PIN, DOWN_PIN, LEFT_PIN, RIGHT_PIN, A_PIN, B_PIN);\n// Index 0-3 = D-pad, Index 4 = A, Index 5 = B\n

"},{"location":"api_reference/core/input_config/#esp32-pin-considerations","title":"ESP32 Pin Considerations","text":"
  • GPIO pins: Use any available GPIO pin
  • Pull-up/pull-down: Configure resistors appropriately
  • Input mode: Pins are automatically configured as inputs
  • Restrictions: Some pins have special functions (check ESP32 datasheet)

Common Pin Choices: - GPIO 0, 2, 4, 5: Safe for buttons (watch for boot mode pins) - GPIO 18, 19: Good for additional buttons - Avoid: GPIO 6-11 (flash), GPIO 34-39 (input only, no pull-up)

"},{"location":"api_reference/core/input_config/#native-sdl-scancode-reference","title":"Native SDL Scancode Reference","text":"

Common SDL scancodes:

  • SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT: Arrow keys
  • SDL_SCANCODE_W, SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_D: WASD
  • SDL_SCANCODE_X, SDL_SCANCODE_Z: Common action buttons
  • SDL_SCANCODE_SPACE: Spacebar
  • SDL_SCANCODE_RETURN: Enter key

Example:

// WASD + Space + Enter\npixelroot32::input::InputConfig config(6,\n    SDL_SCANCODE_W,        // Up\n    SDL_SCANCODE_S,        // Down\n    SDL_SCANCODE_A,        // Left\n    SDL_SCANCODE_D,         // Right\n    SDL_SCANCODE_SPACE,    // Jump\n    SDL_SCANCODE_RETURN    // Action\n);\n

"},{"location":"api_reference/core/input_config/#performance-considerations","title":"Performance Considerations","text":"
  • Memory: Arrays are allocated dynamically (small overhead)
  • Configuration: Done once at startup, no runtime cost
  • Access: Button indices are fast (array access)
"},{"location":"api_reference/core/input_config/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Pin configuration: Ensure pins are not used by other peripherals
  • Debouncing: Hardware debouncing recommended for reliable input
  • Power: Buttons should use pull-up resistors to avoid floating pins
"},{"location":"api_reference/core/input_config/#see-also","title":"See Also","text":"
  • InputManager - Input handling
  • Engine - Engine that uses InputConfig
  • Manual - Input and Control
  • API Overview
"},{"location":"api_reference/core/input_manager/","title":"InputManager","text":"

Handles input from physical buttons or keyboard (on PC).

"},{"location":"api_reference/core/input_manager/#description","title":"Description","text":"

The InputManager polls configured pins (ESP32) or keyboard state (Native), handles debouncing, and tracks button states (Pressed, Released, Down, Clicked). It provides a unified input interface for both platforms.

The manager supports edge detection (just pressed/released) and continuous state (held down), making it suitable for both gameplay and UI navigation.

"},{"location":"api_reference/core/input_manager/#namespace","title":"Namespace","text":"
namespace pixelroot32::input {\n    class InputManager {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/input_manager/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages input manager instance)
"},{"location":"api_reference/core/input_manager/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/input_manager/#inputmanagerconst-inputconfig-config","title":"InputManager(const InputConfig& config)","text":"

Constructs the InputManager with a specific configuration.

Parameters: - config (const InputConfig&): The input configuration (pins, button count)

Example:

#include \"input/InputManager.h\"\n#include \"input/InputConfig.h\"\n\n// ESP32: Configure GPIO pins\npixelroot32::input::InputConfig inputConfig(6, 0, 2, 4, 5, 18, 19);\npixelroot32::input::InputManager inputManager(inputConfig);\ninputManager.init();\n\n// Native: Configure keyboard keys\n// (Configuration handled differently on Native)\n

"},{"location":"api_reference/core/input_manager/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/input_manager/#void-init","title":"void init()","text":"

Initializes the input pins.

Returns: - void

Notes: - Must be called after construction and before use - Configures GPIO pins (ESP32) or keyboard state (Native) - Safe to call multiple times (idempotent) - Typically called automatically by Engine::init()

Example:

InputManager inputManager(inputConfig);\ninputManager.init();  // Initialize before use\n

"},{"location":"api_reference/core/input_manager/#void-updateunsigned-long-dt","title":"void update(unsigned long dt)","text":"

Updates input state by polling hardware pins (ESP32) or keyboard state (Native).

Parameters: - dt (unsigned long): Delta time in milliseconds

Returns: - void

Notes: - Must be called every frame for proper input detection - Handles debouncing automatically - Updates button states and edge detection - Typically called automatically by Engine::update()

ESP32 Example:

void update(unsigned long deltaTime) override {\n    // Input is updated automatically by Engine\n    // Access input via engine.getInputManager()\n}\n

Native Example:

// On Native, update is called with keyboard state:\nvoid update(unsigned long dt, const uint8_t* keyboardState);\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttonpresseduint8_t-buttonindex-const","title":"bool isButtonPressed(uint8_t buttonIndex) const","text":"

Checks if a button was just pressed this frame.

Parameters: - buttonIndex (uint8_t): Index of the button to check (0-based)

Returns: - bool: true if the button transitioned from UP to DOWN this frame

Notes: - Returns true only on the frame the button was pressed - Useful for one-time actions (jump, shoot, menu select) - Resets automatically on next frame

Example:

auto& input = engine.getInputManager();\n\nif (input.isButtonPressed(0)) {  // Button A (index 0)\n    // Jump (only once per press)\n    player->jump();\n}\n\nif (input.isButtonPressed(1)) {  // Button B (index 1)\n    // Shoot (only once per press)\n    player->shoot();\n}\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttonreleaseduint8_t-buttonindex-const","title":"bool isButtonReleased(uint8_t buttonIndex) const","text":"

Checks if a button was just released this frame.

Parameters: - buttonIndex (uint8_t): Index of the button to check

Returns: - bool: true if the button transitioned from DOWN to UP this frame

Notes: - Returns true only on the frame the button was released - Useful for detecting button release events - Less commonly used than isButtonPressed()

Example:

auto& input = engine.getInputManager();\n\nif (input.isButtonReleased(0)) {\n    // Button A was just released\n    player->stopCharging();\n}\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttonclickeduint8_t-buttonindex-const","title":"bool isButtonClicked(uint8_t buttonIndex) const","text":"

Checks if a button was clicked (pressed and released).

Parameters: - buttonIndex (uint8_t): Index of the button to check

Returns: - bool: true if the button was clicked (pressed then released)

Notes: - Returns true when button is released after being pressed - Useful for UI buttons and menu selection - Detects complete press-release cycle

Example:

auto& input = engine.getInputManager();\n\nif (input.isButtonClicked(0)) {  // Button A clicked\n    // Select menu item\n    menu->select();\n}\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttondownuint8_t-buttonindex-const","title":"bool isButtonDown(uint8_t buttonIndex) const","text":"

Checks if a button is currently held down.

Parameters: - buttonIndex (uint8_t): Index of the button to check

Returns: - bool: true if the button is currently in the DOWN state

Notes: - Returns true for as long as the button is held - Useful for continuous actions (movement, charging) - Use with deltaTime for frame-rate independent movement

Example:

auto& input = engine.getInputManager();\n\nfloat speed = 100.0f;  // pixels per second\nfloat vx = 0.0f, vy = 0.0f;\n\nif (input.isButtonDown(2)) {  // Left button\n    vx = -speed;\n}\nif (input.isButtonDown(3)) {  // Right button\n    vx = speed;\n}\nif (input.isButtonDown(0)) {  // Up button\n    vy = -speed;\n}\nif (input.isButtonDown(1)) {  // Down button\n    vy = speed;\n}\n\n// Apply movement (frame-rate independent)\nx += (vx * deltaTime) / 1000.0f;\ny += (vy * deltaTime) / 1000.0f;\n

"},{"location":"api_reference/core/input_manager/#button-indices","title":"Button Indices","text":"

Button indices are defined by the order in InputConfig:

Typical Mapping: - 0: Up / Button A - 1: Down / Button B - 2: Left - 3: Right - 4: Additional button 1 - 5: Additional button 2

Example:

// Configure 6 buttons: Up, Down, Left, Right, A, B\npixelroot32::input::InputConfig inputConfig(6, \n    GPIO_UP,    // Index 0\n    GPIO_DOWN,  // Index 1\n    GPIO_LEFT,  // Index 2\n    GPIO_RIGHT, // Index 3\n    GPIO_A,     // Index 4\n    GPIO_B      // Index 5\n);\n\n// Use indices\nif (input.isButtonDown(2)) {  // Left\n    moveLeft();\n}\nif (input.isButtonPressed(4)) {  // A button\n    jump();\n}\n

"},{"location":"api_reference/core/input_manager/#usage-example","title":"Usage Example","text":"
#include \"input/InputManager.h\"\n#include \"core/Engine.h\"\n\nclass PlayerController {\nprivate:\n    pixelroot32::core::Engine& engine;\n\npublic:\n    PlayerController(pixelroot32::core::Engine& eng) : engine(eng) {}\n\n    void update(unsigned long deltaTime) {\n        auto& input = engine.getInputManager();\n\n        // Movement (continuous)\n        float speed = 150.0f;  // pixels per second\n        float vx = 0.0f, vy = 0.0f;\n\n        if (input.isButtonDown(3)) {  // Right\n            vx = speed;\n        }\n        if (input.isButtonDown(2)) {  // Left\n            vx = -speed;\n        }\n        if (input.isButtonDown(0)) {  // Up\n            vy = -speed;\n        }\n        if (input.isButtonDown(1)) {  // Down\n            vy = speed;\n        }\n\n        // Apply movement\n        playerX += (vx * deltaTime) / 1000.0f;\n        playerY += (vy * deltaTime) / 1000.0f;\n\n        // Actions (one-time)\n        if (input.isButtonPressed(4)) {  // A button\n            player->jump();\n        }\n\n        if (input.isButtonPressed(5)) {  // B button\n            player->shoot();\n        }\n    }\n};\n
"},{"location":"api_reference/core/input_manager/#input-state-comparison","title":"Input State Comparison","text":"Method Returns true when Use Case isButtonPressed() Button just pressed this frame One-time actions (jump, shoot) isButtonReleased() Button just released this frame Release events (stop charging) isButtonClicked() Button pressed then released UI buttons, menu selection isButtonDown() Button currently held Continuous actions (movement)"},{"location":"api_reference/core/input_manager/#performance-considerations","title":"Performance Considerations","text":"
  • Update frequency: update() must be called every frame
  • Debouncing: Handled automatically, no performance impact
  • State queries: All query methods are fast (inline accessors)
  • Memory: Button state arrays are small and efficient
"},{"location":"api_reference/core/input_manager/#esp32-considerations","title":"ESP32 Considerations","text":"
  • GPIO pins: Configure pins in InputConfig
  • Pull-up/pull-down: Ensure proper resistor configuration
  • Debouncing: Hardware debouncing recommended for noisy buttons
  • Pin limits: Some ESP32 pins have restrictions (check datasheet)
"},{"location":"api_reference/core/input_manager/#native-considerations","title":"Native Considerations","text":"
  • Keyboard mapping: Uses SDL scancodes
  • Key detection: Automatically handles keyboard state
  • Multiple keys: Can detect multiple keys simultaneously
"},{"location":"api_reference/core/input_manager/#see-also","title":"See Also","text":"
  • InputConfig - Input configuration
  • Engine - Engine that manages InputManager
  • Manual - Input and Control
  • API Overview
"},{"location":"api_reference/core/physics_actor/","title":"PhysicsActor","text":"

An actor with basic 2D physics properties.

"},{"location":"api_reference/core/physics_actor/#description","title":"Description","text":"

PhysicsActor extends the base Actor class by adding velocity, acceleration, friction, restitution (bounciness), and world boundary collision resolution. It is designed for objects that need to move and bounce within a defined area, such as balls, projectiles, or platformer characters.

PhysicsActor automatically handles: - Velocity-based movement - Friction application - World boundary collision and bouncing - Collision callbacks

"},{"location":"api_reference/core/physics_actor/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class PhysicsActor : public Actor {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/physics_actor/#inheritance","title":"Inheritance","text":"
  • Inherits from: Actor
  • Inherited by: Your custom physics-enabled actor classes
"},{"location":"api_reference/core/physics_actor/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/physics_actor/#physicsactorfloat-x-float-y-float-w-float-h","title":"PhysicsActor(float x, float y, float w, float h)","text":"

Creates a physics-enabled actor with specified position and size.

Parameters: - x (float): Initial X position in world space - y (float): Initial Y position in world space - w (float): Actor width in pixels - h (float): Actor height in pixels

Notes: - Velocity starts at (0, 0) - Restitution defaults to 1.0 (perfect bounce) - Friction defaults to 0.0 (no friction) - No world limits by default

Example:

class BallActor : public pixelroot32::core::PhysicsActor {\npublic:\n    BallActor(float x, float y) \n        : PhysicsActor(x, y, 8.0f, 8.0f) {\n        // Set physics properties\n        setRestitution(0.8f);  // 80% bounce\n        setFriction(0.1f);     // Small friction\n        setWorldSize(128, 128); // World bounds\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledCircle(static_cast<int>(x + width/2), \n                                 static_cast<int>(y + height/2), \n                                 width/2, \n                                 Color::White);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        // Bounce off other actors\n    }\n\n    void onWorldCollision() override {\n        // Play bounce sound\n    }\n};\n

"},{"location":"api_reference/core/physics_actor/#protected-properties","title":"Protected Properties","text":""},{"location":"api_reference/core/physics_actor/#float-vx-vy","title":"float vx, vy","text":"

Horizontal and vertical velocity components.

Type: float

Access: Protected (use setVelocity() to modify)

Default: 0.0f

Notes: - Velocity is in pixels per second - Automatically applied during update() - Modified by friction and world collisions

"},{"location":"api_reference/core/physics_actor/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/physics_actor/#void-setvelocityfloat-x-float-y","title":"void setVelocity(float x, float y)","text":"

Sets the linear velocity of the actor.

Parameters: - x (float): Horizontal velocity in pixels per second - y (float): Vertical velocity in pixels per second

Returns: - void

Notes: - Velocity is applied every frame during update() - Use for initial velocity or impulse-based movement - Can be called every frame for continuous control

Example:

// Set initial velocity\nphysicsActor->setVelocity(100.0f, -200.0f);  // Move right and up\n\n// Continuous control (e.g., player movement)\nvoid update(unsigned long deltaTime) override {\n    PhysicsActor::update(deltaTime);\n\n    float speed = 150.0f;\n    float vx = 0.0f, vy = 0.0f;\n\n    if (input.isButtonDown(Buttons::LEFT)) vx = -speed;\n    if (input.isButtonDown(Buttons::RIGHT)) vx = speed;\n    if (input.isButtonDown(Buttons::UP)) vy = -speed;\n    if (input.isButtonDown(Buttons::DOWN)) vy = speed;\n\n    setVelocity(vx, vy);\n}\n

"},{"location":"api_reference/core/physics_actor/#void-setrestitutionfloat-r","title":"void setRestitution(float r)","text":"

Sets the restitution (bounciness) of the actor.

Parameters: - r (float): Restitution value (0.0 to 1.0+) - 0.0: No bounce (stops on impact) - 1.0: Perfect bounce (no energy loss) - > 1.0: Energy gain (unrealistic but possible)

Returns: - void

Notes: - Applied when actor collides with world boundaries - Higher values = more bouncy - Typical values: 0.5-0.9 for realistic bouncing

Example:

ball->setRestitution(0.8f);  // 80% bounce\n

"},{"location":"api_reference/core/physics_actor/#void-setfrictionfloat-f","title":"void setFriction(float f)","text":"

Sets the friction coefficient.

Parameters: - f (float): Friction value - 0.0: No friction (object continues moving) - > 0.0: Friction applied to velocity each frame

Returns: - void

Notes: - Applied every frame to reduce velocity - Higher values = more friction (slower movement) - Typical values: 0.05-0.2 for smooth deceleration

Example:

player->setFriction(0.1f);  // Light friction\n

"},{"location":"api_reference/core/physics_actor/#void-setlimitslimitrect-limits","title":"void setLimits(LimitRect limits)","text":"

Sets custom movement limits for the actor.

Parameters: - limits (LimitRect): A rectangle defining the allowed area

Returns: - void

Notes: - Overrides world size limits - Use -1 for any boundary to disable that limit - Actor will bounce off these boundaries

Example:

pixelroot32::core::LimitRect limits;\nlimits.left = 0;\nlimits.top = 0;\nlimits.right = 128;\nlimits.bottom = 128;\nphysicsActor->setLimits(limits);\n

"},{"location":"api_reference/core/physics_actor/#void-setworldsizeint-width-int-height","title":"void setWorldSize(int width, int height)","text":"

Defines the world size for boundary checking.

Parameters: - width (int): Width of the world in pixels - height (int): Height of the world in pixels

Returns: - void

Notes: - Used as default limits if no custom LimitRect is provided - Actor will bounce off world boundaries - Set to display size for screen boundaries

Example:

physicsActor->setWorldSize(128, 128);  // Match display size\n

"},{"location":"api_reference/core/physics_actor/#worldcollisioninfo-getworldcollisioninfo-const","title":"WorldCollisionInfo getWorldCollisionInfo() const","text":"

Gets information about collisions with the world boundaries.

Returns: - WorldCollisionInfo: A struct containing collision flags (left, right, top, bottom)

Notes: - Updated every frame during update() - Use to detect which boundary was hit - Useful for sound effects or special behaviors

Example:

void update(unsigned long deltaTime) override {\n    PhysicsActor::update(deltaTime);\n\n    auto collision = getWorldCollisionInfo();\n    if (collision.left || collision.right) {\n        // Hit side wall\n        playSound(wallHitSound);\n    }\n    if (collision.top || collision.bottom) {\n        // Hit top or bottom\n        playSound(ceilingHitSound);\n    }\n}\n

"},{"location":"api_reference/core/physics_actor/#virtual-void-oncollisionactor-other-override","title":"virtual void onCollision(Actor* other) override","text":"

Callback triggered when this actor collides with another actor.

Parameters: - other (Actor*): Pointer to the actor involved in the collision

Returns: - void

Notes: - Called automatically by the collision system - Override to implement custom collision responses - Default implementation does nothing

Example:

void onCollision(Actor* other) override {\n    if (other->isInLayer(DefaultLayers::kEnemy)) {\n        // Bounce off enemy\n        vx = -vx * 0.5f;\n        vy = -vy * 0.5f;\n    }\n}\n

"},{"location":"api_reference/core/physics_actor/#virtual-void-onworldcollision","title":"virtual void onWorldCollision()","text":"

Callback triggered when this actor collides with world boundaries.

Returns: - void

Notes: - Called automatically when a world boundary collision occurs - Override to implement custom behavior (sound effects, particles, etc.) - Default implementation does nothing

Example:

void onWorldCollision() override {\n    // Play bounce sound\n    auto& audio = engine.getAudioEngine();\n    pixelroot32::audio::AudioEvent sound{};\n    sound.type = pixelroot32::audio::WaveType::NOISE;\n    sound.frequency = 500.0f;\n    sound.duration = 0.05f;\n    audio.playEvent(sound);\n\n    // Spawn particles\n    spawnBounceParticles();\n}\n

"},{"location":"api_reference/core/physics_actor/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the actor state. Applies physics integration and checks for world boundary collisions.

Parameters: - deltaTime (unsigned long): Time elapsed since the last frame in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Applies velocity to position - Applies friction to velocity - Resolves world boundary collisions - Override to add custom update logic, but call PhysicsActor::update(deltaTime) first

Example:

void update(unsigned long deltaTime) override {\n    // Apply physics\n    PhysicsActor::update(deltaTime);\n\n    // Custom logic\n    if (shouldApplyGravity) {\n        vy += gravity * (deltaTime / 1000.0f);\n    }\n}\n

"},{"location":"api_reference/core/physics_actor/#limitrect-structure","title":"LimitRect Structure","text":"

Bounding rectangle for world-collision resolution.

Members: - int left: Left boundary (-1 means no limit) - int top: Top boundary (-1 means no limit) - int right: Right boundary (-1 means no limit) - int bottom: Bottom boundary (-1 means no limit)

Methods: - int width() const: Calculates width (right - left) - int height() const: Calculates height (bottom - top)

Example:

pixelroot32::core::LimitRect limits(10, 10, 118, 118);  // 10px margin\nphysicsActor->setLimits(limits);\n

"},{"location":"api_reference/core/physics_actor/#worldcollisioninfo-structure","title":"WorldCollisionInfo Structure","text":"

Information about world collisions in the current frame.

Members: - bool left: True if collided with the left boundary - bool right: True if collided with the right boundary - bool top: True if collided with the top boundary - bool bottom: True if collided with the bottom boundary

Example:

auto collision = physicsActor->getWorldCollisionInfo();\nif (collision.bottom) {\n    // On ground\n    canJump = true;\n}\n

"},{"location":"api_reference/core/physics_actor/#usage-example","title":"Usage Example","text":"
#include \"core/PhysicsActor.h\"\n\nclass BouncingBall : public pixelroot32::core::PhysicsActor {\npublic:\n    BouncingBall(float x, float y) \n        : PhysicsActor(x, y, 8.0f, 8.0f) {\n        // Set physics properties\n        setRestitution(0.9f);  // Very bouncy\n        setFriction(0.05f);    // Light friction\n        setWorldSize(128, 128);\n\n        // Set initial velocity\n        setVelocity(100.0f, -150.0f);\n\n        // Set collision layer\n        layer = pixelroot32::physics::DefaultLayers::kProjectile;\n        mask = pixelroot32::physics::DefaultLayers::kObstacle;\n    }\n\n    void update(unsigned long deltaTime) override {\n        PhysicsActor::update(deltaTime);\n\n        // Apply gravity\n        vy += 200.0f * (deltaTime / 1000.0f);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledCircle(static_cast<int>(x + width/2), \n                                 static_cast<int>(y + height/2), \n                                 width/2, \n                                 Color::White);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        // Bounce off obstacles\n        vx = -vx * 0.8f;\n        vy = -vy * 0.8f;\n    }\n\n    void onWorldCollision() override {\n        // Play bounce sound\n        playBounceSound();\n    }\n};\n
"},{"location":"api_reference/core/physics_actor/#performance-considerations","title":"Performance Considerations","text":"
  • Physics integration: Very efficient (simple velocity integration)
  • World bounds: Boundary checks are fast (AABB)
  • Friction: Applied every frame; keep friction values reasonable
  • Collision callbacks: Keep onCollision() and onWorldCollision() fast
"},{"location":"api_reference/core/physics_actor/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Floating point: Uses float math; acceptable for ESP32 but integer math would be faster
  • Frame rate: Physics is frame-rate independent (uses deltaTime)
  • Memory: Each PhysicsActor consumes more memory than Actor (velocity, limits, etc.)
"},{"location":"api_reference/core/physics_actor/#see-also","title":"See Also","text":"
  • Actor - Base actor class
  • CollisionSystem - Collision detection
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/core/scene/","title":"Scene","text":"

Represents a game level or screen containing entities.

"},{"location":"api_reference/core/scene/#description","title":"Description","text":"

A Scene manages a collection of Entities and a CollisionSystem. It is responsible for updating and drawing all entities it contains. Scenes provide lifecycle hooks (init(), update(), draw()) to manage gameplay segments.

Scenes are the primary organizational unit in PixelRoot32, similar to levels or screens in other game engines. Each scene can contain up to MAX_ENTITIES (default 32; overridable via compiler flags) entities, and drawing uses up to MAX_LAYERS (default 3; overridable) render layers.

"},{"location":"api_reference/core/scene/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Scene {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/scene/#inheritance","title":"Inheritance","text":"
  • Base class: None (abstract base class)
  • Inherited by: Your custom scene classes (e.g., MainMenuScene, GameScene)
"},{"location":"api_reference/core/scene/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/scene/#scene_1","title":"Scene()","text":"

Creates an empty scene ready to be populated with entities.

Notes: - The scene starts with no entities - init() should be called when the scene becomes active - The collision system is automatically initialized

Example:

class MyScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Initialize scene resources\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);  // Update entities and collisions\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        Scene::draw(renderer);  // Draw all entities\n    }\n};\n

"},{"location":"api_reference/core/scene/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/scene/#virtual-void-init","title":"virtual void init()","text":"

Initializes the scene. Called when entering the scene.

Returns: - void

Notes: - Called automatically when the scene is set via Engine::setScene() - Override this method to initialize scene-specific resources - Safe to call multiple times (idempotent) - Add entities here or in the constructor

Example:

class GameScene : public pixelroot32::core::Scene {\nprivate:\n    PlayerActor* player;\n    std::array<EnemyActor*, 10> enemies;\n\npublic:\n    void init() override {\n        // Create player\n        player = new PlayerActor();\n        addEntity(player);\n\n        // Create enemies\n        for (int i = 0; i < 10; i++) {\n            enemies[i] = new EnemyActor();\n            addEntity(enemies[i]);\n        }\n    }\n};\n

"},{"location":"api_reference/core/scene/#virtual-void-updateunsigned-long-deltatime","title":"virtual void update(unsigned long deltaTime)","text":"

Updates all entities in the scene and handles collisions.

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Notes: - Called automatically by the engine every frame - Updates all entities in the scene - Processes collisions between actors - Override to add custom update logic, but call Scene::update(deltaTime) to maintain entity updates

Example:

void update(unsigned long deltaTime) override {\n    // Custom update logic\n    gameTimer += deltaTime;\n\n    // Update entities and collisions\n    Scene::update(deltaTime);\n\n    // Additional logic after entity updates\n    if (gameTimer > 60000) {\n        // Game over after 60 seconds\n    }\n}\n

"},{"location":"api_reference/core/scene/#virtual-void-drawrenderer-renderer","title":"virtual void draw(Renderer& renderer)","text":"

Draws all visible entities in the scene.

Parameters: - renderer (pixelroot32::graphics::Renderer&): The renderer to use for drawing

Notes: - Called automatically by the engine every frame after update() - Draws all visible entities in the scene - Override to add custom drawing logic, but call Scene::draw(renderer) to maintain entity rendering - Entities are drawn in the order they were added

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Draw background\n    renderer.drawTileMap(backgroundTileMap, 0, 0, Color::White);\n\n    // Draw all entities\n    Scene::draw(renderer);\n\n    // Draw UI overlay\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n}\n

"},{"location":"api_reference/core/scene/#void-addentityentity-entity","title":"void addEntity(Entity* entity)","text":"

Adds an entity to the scene.

Parameters: - entity (Entity*): Pointer to the Entity to add. Must not be nullptr.

Notes: - Entities are added to an internal queue - Maximum of MAX_ENTITIES (default 32; overridable) entities per scene - If the limit is reached, the entity may not be added (check return value if available) - Entities are updated and drawn in the order they were added - The entity's lifetime is managed by the scene (do not delete manually while in scene)

Example:

void init() override {\n    // Create and add player\n    PlayerActor* player = new PlayerActor();\n    player->setPosition(64, 64);\n    addEntity(player);\n\n    // Create and add enemy\n    EnemyActor* enemy = new EnemyActor();\n    enemy->setPosition(100, 100);\n    addEntity(enemy);\n}\n

"},{"location":"api_reference/core/scene/#void-removeentityentity-entity","title":"void removeEntity(Entity* entity)","text":"

Removes an entity from the scene.

Parameters: - entity (Entity*): Pointer to the Entity to remove

Notes: - The entity is removed from the update and draw queues - The entity is not deleted automatically (you must manage its lifetime) - Safe to call even if the entity is not in the scene - Consider using object pooling instead of frequent add/remove

Example:

void onEnemyDestroyed(EnemyActor* enemy) {\n    removeEntity(enemy);\n    // Return to pool or delete\n    enemyPool.returnToPool(enemy);\n}\n

"},{"location":"api_reference/core/scene/#void-clearentities","title":"void clearEntities()","text":"

Removes all entities from the scene.

Notes: - All entities are removed from the update and draw queues - Entities are not deleted automatically (you must manage their lifetimes) - Useful for scene cleanup or reset - Consider using object pooling to reuse entities

Example:

void reset() {\n    clearEntities();\n    // Return all entities to pool\n    for (auto* entity : entityPool) {\n        entityPool.returnToPool(entity);\n    }\n}\n

"},{"location":"api_reference/core/scene/#protected-members","title":"Protected Members","text":""},{"location":"api_reference/core/scene/#arduinoqueue-entities","title":"ArduinoQueue entities

Queue of entities in the scene. Accessible to derived classes for custom entity management.

Type: ArduinoQueue<Entity*>

Notes: - Maximum capacity: MAX_ENTITIES (default 32; overridable) - Direct access allows custom iteration or filtering - Use with caution: modifying while iterating may cause issues

","text":""},{"location":"api_reference/core/scene/#collisionsystem-collisionsystem","title":"CollisionSystem collisionSystem

System to handle collisions between actors. Accessible to derived classes for custom collision handling.

Type: pixelroot32::physics::CollisionSystem

Notes: - Automatically processes collisions between actors - Uses collision layers and masks for filtering - Can be accessed for custom collision queries

","text":""},{"location":"api_reference/core/scene/#overriding-scene-limits-max_layers-max_entities","title":"Overriding scene limits (MAX_LAYERS / MAX_ENTITIES)","text":"

The engine defines default limits in core/Scene.h: MAX_LAYERS (default 3) and MAX_ENTITIES (default 32). These are guarded with #ifndef, so you can override them from your project without modifying the engine.

ESP32 platform limitation

The default of 3 for MAX_LAYERS is due to ESP32 platform constraints (memory and draw-loop cost). On native/PC you can safely use a higher value; on ESP32, increasing it may affect performance or memory.

"},{"location":"api_reference/core/scene/#option-a-compiler-flags-recommended","title":"Option A: Compiler flags (recommended)

In your project (e.g. in platformio.ini), add the defines to build_flags for the environment you use:

build_flags =\n    -DMAX_LAYERS=5\n    -DMAX_ENTITIES=64\n

The compiler defines MAX_LAYERS and MAX_ENTITIES before processing any .cpp file. Because Scene.h uses #ifndef MAX_LAYERS / #ifndef MAX_ENTITIES, it will not redefine them and your values will be used.

Effect: - MAX_LAYERS: Number of render layers drawn in Scene::draw() (layer 0 = background, 1+ = sprite context). Increasing this allows more distinct draw layers (e.g. background, platforms, gameplay, foreground, UI). - MAX_ENTITIES: On Arduino, the capacity of the scene entity queue when constructed with this value. On native (mock queue), the value is ignored (unbounded).

See also: Platforms and Drivers - Scene limits.

","text":""},{"location":"api_reference/core/scene/#usage-example","title":"Usage Example","text":"
#include \"core/Scene.h\"\n#include \"core/Actor.h\"\n\nclass MyGameScene : public pixelroot32::core::Scene {\nprivate:\n    PlayerActor* player;\n\npublic:\n    void init() override {\n        // Create player\n        player = new PlayerActor();\n        player->setPosition(64, 64);\n        addEntity(player);\n\n        // Create some enemies\n        for (int i = 0; i < 5; i++) {\n            EnemyActor* enemy = new EnemyActor();\n            enemy->setPosition(10 + i * 20, 10);\n            addEntity(enemy);\n        }\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Custom game logic\n        if (player->isDead()) {\n            // Handle game over\n        }\n\n        // Update entities and collisions\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background\n        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n\n        // Draw all entities\n        Scene::draw(renderer);\n\n        // Draw HUD\n        char scoreText[32];\n        snprintf(scoreText, sizeof(scoreText), \"Score: %d\", score);\n        renderer.drawText(scoreText, 10, 10, Color::White, 1);\n    }\n};\n
"},{"location":"api_reference/core/scene/#performance-considerations","title":"Performance Considerations","text":"
  • Entity limit: MAX_ENTITIES (default 32) can be overridden via compiler flags; plan accordingly
  • Add/Remove: Frequent add/remove operations can be expensive; use object pooling
  • Update order: Entities are updated in add order; consider order for dependencies
  • Collision checks: CollisionSystem automatically handles actor collisions efficiently
"},{"location":"api_reference/core/scene/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Each entity consumes memory; stay well below the limit
  • Object pooling: Essential for ESP32 to avoid memory fragmentation
  • Scene switching: Clearing and recreating scenes can fragment memory; reuse scenes when possible
"},{"location":"api_reference/core/scene/#see-also","title":"See Also","text":"
  • Entity - Base entity class
  • Actor - Entity with collision support
  • PhysicsActor - Entity with physics
  • CollisionSystem - Collision detection
  • Manual - Scenes and Entities
  • API Overview
"},{"location":"api_reference/graphics/camera2d/","title":"Camera2D","text":"

2D camera for scrolling and viewport control.

"},{"location":"api_reference/graphics/camera2d/#description","title":"Description","text":"

Camera2D controls viewport position and enables scrolling by shifting the renderer's display offset. It supports following targets, boundary constraints, and can be used for parallax effects.

The camera uses a dead-zone system: it only moves when the target is outside a central zone, creating smooth following behavior.

"},{"location":"api_reference/graphics/camera2d/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    class Camera2D {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/camera2d/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Scenes (for scrolling and camera control)
"},{"location":"api_reference/graphics/camera2d/#constructors","title":"Constructors","text":""},{"location":"api_reference/graphics/camera2d/#camera2dint-viewportwidth-int-viewportheight","title":"Camera2D(int viewportWidth, int viewportHeight)","text":"

Creates a new camera with specified viewport dimensions.

Parameters: - viewportWidth (int): Width of the viewport in pixels - viewportHeight (int): Height of the viewport in pixels

Notes: - Viewport size should match display size - Camera position starts at (0, 0) - No boundaries set by default (camera can move anywhere)

Example:

#include \"graphics/Camera2D.h\"\n\n// Create camera matching display size\npixelroot32::graphics::Camera2D camera(128, 128);\n\n// Or get from renderer\nint width = renderer.getWidth();\nint height = renderer.getHeight();\npixelroot32::graphics::Camera2D camera(width, height);\n

"},{"location":"api_reference/graphics/camera2d/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/graphics/camera2d/#void-setpositionfloat-x-float-y","title":"void setPosition(float x, float y)","text":"

Sets the camera position directly.

Parameters: - x (float): X position in world space - y (float): Y position in world space

Returns: - void

Notes: - Position is clamped to boundaries if set - Use for direct camera control or cutscenes - Overrides any following behavior

Example:

camera.setPosition(100.0f, 200.0f);\n

"},{"location":"api_reference/graphics/camera2d/#void-setboundsfloat-minx-float-maxx","title":"void setBounds(float minX, float maxX)","text":"

Sets horizontal boundaries for the camera.

Parameters: - minX (float): Minimum X position - maxX (float): Maximum X position

Returns: - void

Notes: - Camera position is clamped to these bounds - Use to prevent camera from going outside level bounds - Set both horizontal and vertical bounds for full constraint

Example:

// Level is 512 pixels wide, camera viewport is 128\n// Prevent camera from showing outside level\ncamera.setBounds(0.0f, 512.0f - 128.0f);\n

"},{"location":"api_reference/graphics/camera2d/#void-setverticalboundsfloat-miny-float-maxy","title":"void setVerticalBounds(float minY, float maxY)","text":"

Sets vertical boundaries for the camera.

Parameters: - minY (float): Minimum Y position - maxY (float): Maximum Y position

Returns: - void

Notes: - Camera position is clamped to these bounds - Use to prevent camera from going outside level bounds vertically

Example:

// Level is 512 pixels tall, camera viewport is 128\ncamera.setVerticalBounds(0.0f, 512.0f - 128.0f);\n

"},{"location":"api_reference/graphics/camera2d/#void-followtargetfloat-targetx","title":"void followTarget(float targetX)","text":"

Makes the camera follow a target horizontally only.

Parameters: - targetX (float): X position of the target to follow

Returns: - void

Notes: - Camera follows target with dead-zone behavior - Only horizontal movement; vertical position unchanged - Useful for side-scrolling games

Example:

void update(unsigned long deltaTime) override {\n    // Update player position\n    player->update(deltaTime);\n\n    // Camera follows player horizontally\n    camera.followTarget(player->x);\n    camera.apply(renderer);\n}\n

"},{"location":"api_reference/graphics/camera2d/#void-followtargetfloat-targetx-float-targety","title":"void followTarget(float targetX, float targetY)","text":"

Makes the camera follow a target in both axes.

Parameters: - targetX (float): X position of the target to follow - targetY (float): Y position of the target to follow

Returns: - void

Notes: - Camera follows target with dead-zone behavior - Both horizontal and vertical following - Useful for top-down or platformer games

Example:

void update(unsigned long deltaTime) override {\n    player->update(deltaTime);\n\n    // Camera follows player in both axes\n    camera.followTarget(player->x, player->y);\n    camera.apply(renderer);\n}\n

"},{"location":"api_reference/graphics/camera2d/#float-getx-const","title":"float getX() const","text":"

Gets the current X position of the camera.

Returns: - float: Current X position in world space

Example:

float cameraX = camera.getX();\n

"},{"location":"api_reference/graphics/camera2d/#float-gety-const","title":"float getY() const","text":"

Gets the current Y position of the camera.

Returns: - float: Current Y position in world space

Example:

float cameraY = camera.getY();\n

"},{"location":"api_reference/graphics/camera2d/#void-applyrenderer-renderer-const","title":"void apply(Renderer& renderer) const","text":"

Applies the camera's offset to the renderer.

Parameters: - renderer (Renderer&): The renderer to apply the camera offset to

Returns: - void

Notes: - Sets the renderer's display offset based on camera position - Should be called before drawing world elements - Negative offset is applied (camera moves right = world moves left)

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera offset\n    camera.apply(renderer);\n\n    // Draw world (offset applied automatically)\n    renderer.drawTileMap(levelMap, 0, 0, Color::White);\n    renderer.drawSprite(playerSprite, playerX, playerY, Color::White);\n\n    // UI elements (not affected by camera)\n    renderer.setDisplayOffset(0, 0);  // Reset for UI\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n}\n

"},{"location":"api_reference/graphics/camera2d/#dead-zone-following","title":"Dead-Zone Following","text":"

The camera uses a dead-zone system for smooth following:

  • Dead zone: Central area where camera doesn't move
  • Following: Camera moves only when target leaves dead zone
  • Smooth: Creates natural, non-jarring camera movement

Example:

// Camera follows player with dead zone\nvoid update(unsigned long deltaTime) override {\n    player->update(deltaTime);\n\n    // Camera follows (dead zone handled internally)\n    camera.followTarget(player->x, player->y);\n}\n

"},{"location":"api_reference/graphics/camera2d/#usage-example","title":"Usage Example","text":"
#include \"graphics/Camera2D.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n    TileMap levelMap;\n\npublic:\n    void init() override {\n        // Create camera matching display size\n        auto& renderer = engine.getRenderer();\n        camera = pixelroot32::graphics::Camera2D(\n            renderer.getWidth(), \n            renderer.getHeight()\n        );\n\n        // Set level boundaries\n        // Level is 512x512, viewport is 128x128\n        camera.setBounds(0.0f, 512.0f - 128.0f);\n        camera.setVerticalBounds(0.0f, 512.0f - 128.0f);\n\n        // Create player\n        player = new PlayerActor(64, 64);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Camera follows player\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw world (camera offset applied)\n        renderer.drawTileMap(levelMap, 0, 0, Color::White);\n\n        // Draw entities (Scene::draw handles this)\n        Scene::draw(renderer);\n\n        // Reset offset for UI\n        renderer.setDisplayOffset(0, 0);\n        renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n    }\n};\n
"},{"location":"api_reference/graphics/camera2d/#parallax-scrolling","title":"Parallax Scrolling","text":"

Use multiple cameras or manual offset for parallax:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Background layer (slow parallax)\n    float bgOffsetX = camera.getX() * 0.5f;  // 50% speed\n    renderer.setDisplayOffset(-bgOffsetX, 0);\n    renderer.drawTileMap(backgroundMap, 0, 0, Color::White);\n\n    // Midground layer (normal speed)\n    camera.apply(renderer);\n    renderer.drawTileMap(midgroundMap, 0, 0, Color::White);\n\n    // Foreground (entities, normal speed)\n    Scene::draw(renderer);\n\n    // UI (no offset)\n    renderer.setDisplayOffset(0, 0);\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n}\n
"},{"location":"api_reference/graphics/camera2d/#performance-considerations","title":"Performance Considerations","text":"
  • Apply frequency: apply() is fast; safe to call every frame
  • Boundary checks: Boundary clamping is efficient
  • Following: Dead-zone calculations are lightweight
"},{"location":"api_reference/graphics/camera2d/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Float math: Uses floating point; acceptable but integer math would be faster
  • Memory: Camera is small (few floats); minimal memory usage
"},{"location":"api_reference/graphics/camera2d/#see-also","title":"See Also","text":"
  • Renderer - Rendering system
  • Manual - Cameras and Scrolling
  • API Overview
"},{"location":"api_reference/graphics/color/","title":"Color","text":"

Color constants and palette management system.

"},{"location":"api_reference/graphics/color/#description","title":"Description","text":"

The Color enum provides color constants that map to palette indices. The engine supports both legacy mode (single global palette) and dual palette mode (separate palettes for backgrounds and sprites).

Colors are resolved to 16-bit RGB565 values based on the active palette(s).

"},{"location":"api_reference/graphics/color/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    enum class Color : uint8_t {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/color/#color-enum-values","title":"Color Enum Values","text":""},{"location":"api_reference/graphics/color/#standard-colors-pr32-palette-indices","title":"Standard Colors (PR32 Palette Indices)","text":"
  • Color::Black (0)
  • Color::White (1)
  • Color::Navy (2)
  • Color::Blue (3)
  • Color::Cyan (4)
  • Color::DarkGreen (5)
  • Color::Green (6)
  • Color::LightGreen (7)
  • Color::Yellow (8)
  • Color::Orange (9)
  • Color::LightRed (10)
  • Color::Red (11)
  • Color::DarkRed (12)
  • Color::Purple (13)
  • Color::Magenta (14)
  • Color::Gray (15)
"},{"location":"api_reference/graphics/color/#color-aliases","title":"Color Aliases","text":"

For compatibility, several aliases map to the closest available color:

  • Color::DarkBlue \u2192 Navy
  • Color::LightBlue \u2192 Blue
  • Color::Teal \u2192 Cyan
  • Color::Olive \u2192 DarkGreen
  • Color::Gold \u2192 Yellow
  • Color::Brown \u2192 DarkRed
  • Color::Pink \u2192 Magenta
  • Color::LightPurple \u2192 Magenta
  • Color::Maroon \u2192 DarkRed
  • Color::MidGray \u2192 Gray
  • Color::LightGray \u2192 Gray
  • Color::DarkGray \u2192 Gray
  • Color::Silver \u2192 Gray
"},{"location":"api_reference/graphics/color/#special-colors","title":"Special Colors","text":"
  • Color::Transparent (255): Not a real color; must be handled by renderer (results in no-op)
  • Color::DebugRed \u2192 Red
  • Color::DebugGreen \u2192 Green
  • Color::DebugBlue \u2192 Blue
"},{"location":"api_reference/graphics/color/#palettetype-enum","title":"PaletteType Enum","text":"

Built-in palette types:

  • PaletteType::NES: NES color palette
  • PaletteType::GB: Game Boy (4 shades of green)
  • PaletteType::GBC: Game Boy Color palette
  • PaletteType::PICO8: PICO-8 palette
  • PaletteType::PR32: PixelRoot32 default palette
"},{"location":"api_reference/graphics/color/#palettecontext-enum","title":"PaletteContext Enum","text":"

Context for palette selection in dual palette mode:

  • PaletteContext::Background: For backgrounds, tilemaps, and background primitives
  • PaletteContext::Sprite: For sprites, characters, and gameplay elements
"},{"location":"api_reference/graphics/color/#palette-functions","title":"Palette Functions","text":""},{"location":"api_reference/graphics/color/#void-setpalettepalettetype-palette","title":"void setPalette(PaletteType palette)","text":"

Selects the active color palette (legacy mode). Sets both background and sprite palettes to the same value.

Parameters: - palette (PaletteType): The palette to use

Notes: - Does not enable dual palette mode - All rendering uses the same palette - Use for simple games with single palette

Example:

pixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n

"},{"location":"api_reference/graphics/color/#void-setcustompaletteconst-uint16_t-palette","title":"void setCustomPalette(const uint16_t* palette)","text":"

Sets a custom color palette (legacy mode). Sets both background and sprite palettes to the same value.

Parameters: - palette (const uint16_t*): Pointer to an array of 16 uint16_t RGB565 color values

Notes: - Array must remain valid (use static/global storage) - Engine does not copy the palette - Does not enable dual palette mode

Example:

static const uint16_t MY_PALETTE[16] = {\n    0x0000,  // Black\n    0xFFFF,  // White\n    0x001F,  // Blue\n    // ... 13 more colors\n};\n\npixelroot32::graphics::setCustomPalette(MY_PALETTE);\n

"},{"location":"api_reference/graphics/color/#void-enabledualpalettemodebool-enable","title":"void enableDualPaletteMode(bool enable)","text":"

Enables or disables dual palette mode.

Parameters: - enable (bool): true to enable dual palette mode, false for legacy mode

Notes: - When enabled: backgrounds and sprites use separate palettes - When disabled: single palette for all rendering (legacy mode)

Example:

pixelroot32::graphics::enableDualPaletteMode(true);\n

"},{"location":"api_reference/graphics/color/#void-setbackgroundpalettepalettetype-palette","title":"void setBackgroundPalette(PaletteType palette)","text":"

Sets the background palette (for backgrounds, tilemaps, etc.).

Parameters: - palette (PaletteType): The palette type to use for backgrounds

Notes: - Only used in dual palette mode - Affects tilemaps, background primitives, etc.

Example:

pixelroot32::graphics::enableDualPaletteMode(true);\npixelroot32::graphics::setBackgroundPalette(pixelroot32::graphics::PaletteType::NES);\n

"},{"location":"api_reference/graphics/color/#void-setspritepalettepalettetype-palette","title":"void setSpritePalette(PaletteType palette)","text":"

Sets the sprite palette (for sprites, characters, etc.).

Parameters: - palette (PaletteType): The palette type to use for sprites

Notes: - Only used in dual palette mode - Affects sprites, characters, gameplay elements

Example:

pixelroot32::graphics::setSpritePalette(pixelroot32::graphics::PaletteType::GB);\n

"},{"location":"api_reference/graphics/color/#void-setdualpalettepalettetype-bgpalette-palettetype-spritepalette","title":"void setDualPalette(PaletteType bgPalette, PaletteType spritePalette)","text":"

Sets both background and sprite palettes at once. Automatically enables dual palette mode.

Parameters: - bgPalette (PaletteType): The palette type to use for backgrounds - spritePalette (PaletteType): The palette type to use for sprites

Example:

pixelroot32::graphics::setDualPalette(\n    pixelroot32::graphics::PaletteType::NES,  // Background\n    pixelroot32::graphics::PaletteType::GB     // Sprites\n);\n

"},{"location":"api_reference/graphics/color/#void-setbackgroundcustompaletteconst-uint16_t-palette","title":"void setBackgroundCustomPalette(const uint16_t* palette)","text":"

Sets a custom background palette.

Parameters: - palette (const uint16_t*): Pointer to an array of 16 uint16_t RGB565 color values

Notes: - Array must remain valid (use static/global storage) - Only used in dual palette mode

Example:

static const uint16_t BG_PALETTE[16] = { /* ... */ };\npixelroot32::graphics::enableDualPaletteMode(true);\npixelroot32::graphics::setBackgroundCustomPalette(BG_PALETTE);\n

"},{"location":"api_reference/graphics/color/#void-setspritecustompaletteconst-uint16_t-palette","title":"void setSpriteCustomPalette(const uint16_t* palette)","text":"

Sets a custom sprite palette.

Parameters: - palette (const uint16_t*): Pointer to an array of 16 uint16_t RGB565 color values

Notes: - Array must remain valid (use static/global storage) - Only used in dual palette mode

Example:

static const uint16_t SPRITE_PALETTE[16] = { /* ... */ };\npixelroot32::graphics::setSpriteCustomPalette(SPRITE_PALETTE);\n

"},{"location":"api_reference/graphics/color/#void-setdualcustompaletteconst-uint16_t-bgpalette-const-uint16_t-spritepal","title":"void setDualCustomPalette(const uint16_t bgPalette, const uint16_t spritePal)","text":"

Sets both background and sprite custom palettes at once. Automatically enables dual palette mode.

Parameters: - bgPalette (const uint16_t): Pointer to background palette array (16 RGB565 values) - spritePal (const uint16_t): Pointer to sprite palette array (16 RGB565 values)

Example:

static const uint16_t BG_PAL[16] = { /* ... */ };\nstatic const uint16_t SPRITE_PAL[16] = { /* ... */ };\npixelroot32::graphics::setDualCustomPalette(BG_PAL, SPRITE_PAL);\n

"},{"location":"api_reference/graphics/color/#uint16_t-resolvecolorcolor-color","title":"uint16_t resolveColor(Color color)","text":"

Resolves a Color enum to its corresponding 16-bit color value (legacy mode).

Parameters: - color (Color): The Color enum value

Returns: - uint16_t: The 16-bit RGB565 color value

Notes: - Uses the current active palette (single palette mode) - Color::Transparent must not be resolved (handled by renderer) - Typically called internally by renderer

Example:

uint16_t rgb565 = pixelroot32::graphics::resolveColor(pixelroot32::graphics::Color::Red);\n

"},{"location":"api_reference/graphics/color/#uint16_t-resolvecolorcolor-color-palettecontext-context","title":"uint16_t resolveColor(Color color, PaletteContext context)","text":"

Resolves a Color enum with context (dual palette mode).

Parameters: - color (Color): The Color enum value - context (PaletteContext): The palette context (Background or Sprite)

Returns: - uint16_t: The 16-bit RGB565 color value

Notes: - Uses the appropriate palette based on context - In legacy mode, context is ignored - Color::Transparent must not be resolved

Example:

uint16_t bgColor = pixelroot32::graphics::resolveColor(\n    pixelroot32::graphics::Color::Blue,\n    pixelroot32::graphics::PaletteContext::Background\n);\n

"},{"location":"api_reference/graphics/color/#rgb565-format","title":"RGB565 Format","text":"

Colors are stored as 16-bit RGB565 values:

  • Bits 15-11: Red (5 bits, 0-31)
  • Bits 10-5: Green (6 bits, 0-63)
  • Bits 4-0: Blue (5 bits, 0-31)

Conversion Example:

// Convert RGB to RGB565\nuint16_t rgb565 = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\n

"},{"location":"api_reference/graphics/color/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/graphics/color/#legacy-mode-single-palette","title":"Legacy Mode (Single Palette)","text":"
// Set single palette for all rendering\npixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n\n// Use colors\nrenderer.drawSprite(sprite, 100, 100, pixelroot32::graphics::Color::Red);\nrenderer.drawFilledRectangle(10, 10, 50, 50, pixelroot32::graphics::Color::Blue);\n
"},{"location":"api_reference/graphics/color/#dual-palette-mode","title":"Dual Palette Mode","text":"
// Enable dual palette mode\npixelroot32::graphics::enableDualPaletteMode(true);\n\n// Set different palettes for backgrounds and sprites\npixelroot32::graphics::setBackgroundPalette(pixelroot32::graphics::PaletteType::NES);\npixelroot32::graphics::setSpritePalette(pixelroot32::graphics::PaletteType::GB);\n\n// Or use convenience function\npixelroot32::graphics::setDualPalette(\n    pixelroot32::graphics::PaletteType::NES,\n    pixelroot32::graphics::PaletteType::GB\n);\n
"},{"location":"api_reference/graphics/color/#custom-palettes","title":"Custom Palettes","text":"
// Define custom palette (RGB565 values)\nstatic const uint16_t CUSTOM_PALETTE[16] = {\n    0x0000,  // 0: Black\n    0xFFFF,  // 1: White\n    0x001F,  // 2: Blue\n    0x07E0,  // 3: Green\n    0xF800,  // 4: Red\n    // ... 11 more colors\n};\n\n// Use in legacy mode\npixelroot32::graphics::setCustomPalette(CUSTOM_PALETTE);\n\n// Or use in dual palette mode\npixelroot32::graphics::enableDualPaletteMode(true);\npixelroot32::graphics::setBackgroundCustomPalette(CUSTOM_PALETTE);\npixelroot32::graphics::setSpriteCustomPalette(CUSTOM_PALETTE);\n
"},{"location":"api_reference/graphics/color/#performance-considerations","title":"Performance Considerations","text":"
  • Color resolution: Fast lookup operation
  • Palette switching: Changing palettes is fast (just pointer assignment)
  • Memory: Palettes are stored in flash (const arrays) for best performance
  • Dual mode: Slightly more overhead than legacy mode, but minimal
"},{"location":"api_reference/graphics/color/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Flash storage: Store custom palettes in flash (const/constexpr)
  • Memory: Palettes are small (16 uint16_t = 32 bytes)
  • Palette switching: Avoid switching palettes every frame
"},{"location":"api_reference/graphics/color/#see-also","title":"See Also","text":"
  • Renderer - Rendering system
  • Manual - Color Palettes
  • API Overview
"},{"location":"api_reference/graphics/display_config/","title":"DisplayConfig","text":"

Configuration settings for initializing the display.

"},{"location":"api_reference/graphics/display_config/#description","title":"Description","text":"

DisplayConfig holds display parameters used by the renderer and camera to draw correctly on the target device. It defines the display type, dimensions, rotation, and creates the appropriate DrawSurface implementation for the platform.

"},{"location":"api_reference/graphics/display_config/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    struct DisplayConfig {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/display_config/#displaytype-enum","title":"DisplayType Enum","text":"

Supported display types:

  • DisplayType::ST7789: 240x240 TFT display
  • DisplayType::ST7735: 128x128 TFT display
  • DisplayType::NONE: For SDL2 native (no driver needed)
"},{"location":"api_reference/graphics/display_config/#structure","title":"Structure","text":""},{"location":"api_reference/graphics/display_config/#displaytype-type","title":"DisplayType type","text":"

The type of display.

Type: DisplayType enum

Access: Read-write

Notes: - Determines which driver to use (ESP32) - NONE for Native/SDL2 platform

"},{"location":"api_reference/graphics/display_config/#int-rotation","title":"int rotation","text":"

Display rotation in degrees.

Type: int

Access: Read-write

Default: 0

Notes: - Common values: 0, 90, 180, 270 - Rotation is applied during initialization - Some displays may not support all rotations

"},{"location":"api_reference/graphics/display_config/#uint16_t-physicalwidth","title":"uint16_t physicalWidth","text":"

Physical hardware width of the display.

Type: uint16_t

Access: Read-write

Notes: - Defines the actual resolution of the display hardware.

"},{"location":"api_reference/graphics/display_config/#uint16_t-physicalheight","title":"uint16_t physicalHeight","text":"

Physical hardware height of the display.

Type: uint16_t

Access: Read-write

Notes: - Defines the actual resolution of the display hardware.

"},{"location":"api_reference/graphics/display_config/#uint16_t-logicalwidth","title":"uint16_t logicalWidth","text":"

Logical rendering width. This is the resolution the game \"sees\" and draws to.

Type: uint16_t

Access: Read-write

Notes: - If smaller than physicalWidth, the image will be scaled up. - Used for clipping, camera, and UI calculations. - Recommended values for ESP32: 160, 128, 96 (for 240 physical).

"},{"location":"api_reference/graphics/display_config/#uint16_t-logicalheight","title":"uint16_t logicalHeight","text":"

Logical rendering height. This is the resolution the game \"sees\" and draws to.

Type: uint16_t

Access: Read-write

Notes: - If smaller than physicalHeight, the image will be scaled up. - Used for clipping, camera, and UI calculations.

"},{"location":"api_reference/graphics/display_config/#uint16_t-width-deprecated","title":"uint16_t width() (Deprecated)","text":"

Alias for logicalWidth. Maintained for backward compatibility.

"},{"location":"api_reference/graphics/display_config/#uint16_t-height-deprecated","title":"uint16_t height() (Deprecated)","text":"

Alias for logicalHeight. Maintained for backward compatibility.

"},{"location":"api_reference/graphics/display_config/#int-xoffset","title":"int xOffset","text":"

X offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

"},{"location":"api_reference/graphics/display_config/#int-yoffset","title":"int yOffset","text":"

Y offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

"},{"location":"api_reference/graphics/display_config/#drawsurface-getdrawsurface-const","title":"DrawSurface& getDrawSurface() const","text":"

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed - Provides access to low-level display driver - Platform-specific implementation

"},{"location":"api_reference/graphics/display_config/#resolution-helpers","title":"Resolution Helpers","text":""},{"location":"api_reference/graphics/display_config/#bool-needsscaling-const","title":"bool needsScaling() const","text":"

Checks if the logical resolution differs from the physical resolution.

Returns: - bool: true if scaling is active.

"},{"location":"api_reference/graphics/display_config/#float-getscalex-const","title":"float getScaleX() const","text":"

Gets the horizontal scaling factor (physicalWidth / logicalWidth).

"},{"location":"api_reference/graphics/display_config/#float-getscaley-const","title":"float getScaleY() const","text":"

Gets the vertical scaling factor (physicalHeight / logicalHeight).

"},{"location":"api_reference/graphics/display_config/#constructors","title":"Constructors","text":""},{"location":"api_reference/graphics/display_config/#displayconfigdisplaytype-type-const-int-rot-uint16_t-physw-uint16_t-physh-uint16_t-logw-uint16_t-logh-const-int-xoff-0-const-int-yoff-0","title":"DisplayConfig(DisplayType type, const int rot, uint16_t physW, uint16_t physH, uint16_t logW, uint16_t logH, const int xOff = 0, const int yOff = 0)","text":"

Extended constructor that allows defining separate physical and logical resolutions.

Parameters: - type (DisplayType): The display type. - rot (int): Rotation (0-3 or degrees depending on implementation). - physW (uint16_t): Physical hardware width. - physH (uint16_t): Physical hardware height. - logW (uint16_t): Logical rendering width (0 = same as physical). - logH (uint16_t): Logical rendering height (0 = same as physical). - xOff (int, optional): X alignment offset. - yOff (int, optional): Y alignment offset.

Example:

// 128x128 game logic scaled to 240x240 display\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7789,\n    0,    // rotation\n    240, 240, // physical\n    128, 128  // logical\n);\n

"},{"location":"api_reference/graphics/display_config/#displayconfigdisplaytype-type-const-int-rot-0-uint16_t-w-240-uint16_t-h-240-const-int-xoffset-0-const-int-yoffset-0","title":"DisplayConfig(DisplayType type, const int rot = 0, uint16_t w = 240, uint16_t h = 240, const int xOffset = 0, const int yOffset = 0)","text":"

Legacy constructor for backward compatibility. Sets both logical and physical resolutions to the same values.

Notes: - Automatically creates the appropriate DrawSurface for the platform - ESP32: Creates TFT_eSPI_Drawer based on display type - Native: Creates SDL2_Drawer

Example:

// ST7789 display, 240x240, no rotation\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7789\n);\n\n// ST7735 display, 128x128, rotated 90 degrees\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7735,\n    90,   // rotation\n    128,  // physical width\n    128,  // physical height\n    128,  // logical width\n    128   // logical height\n);\n\n// Native/SDL2 (no specific display type)\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::NONE,\n    0,    // rotation\n    128, 128, // physical\n    128, 128  // logical\n);\n

"},{"location":"api_reference/graphics/display_config/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/graphics/display_config/#esp32-with-st7789","title":"ESP32 with ST7789","text":"
#ifdef PLATFORM_ESP32\n#include \"graphics/DisplayConfig.h\"\n\nvoid setup() {\n    // Configure ST7789 display (240x240 physical, 128x128 logical)\n    pixelroot32::graphics::DisplayConfig displayConfig(\n        pixelroot32::graphics::DisplayType::ST7789,\n        0,    // rotation\n        240, 240, // physical\n        128, 128  // logical\n    );\n\n    // Use with Engine\n    pixelroot32::core::Engine engine(displayConfig);\n    engine.init();\n    engine.run();\n}\n#endif\n
"},{"location":"api_reference/graphics/display_config/#esp32-with-st7735","title":"ESP32 with ST7735","text":"
#ifdef PLATFORM_ESP32\n    // Configure ST7735 display (128x128)\n    pixelroot32::graphics::DisplayConfig displayConfig(\n        pixelroot32::graphics::DisplayType::ST7735,\n        0,    // rotation\n        128, 128 // physical & logical\n    );\n#endif\n
"},{"location":"api_reference/graphics/display_config/#nativesdl2","title":"Native/SDL2","text":"
#ifdef PLATFORM_NATIVE\n    // Native display (SDL2 window)\n    pixelroot32::graphics::DisplayConfig displayConfig(\n        pixelroot32::graphics::DisplayType::NONE,\n        0,    // rotation\n        240, 240 // logical & physical\n    );\n#endif\n
"},{"location":"api_reference/graphics/display_config/#platform-agnostic-setup","title":"Platform-Agnostic Setup","text":"
#include \"graphics/DisplayConfig.h\"\n#include \"core/Engine.h\"\n\nvoid setup() {\n    pixelroot32::graphics::DisplayConfig displayConfig;\n\n    #ifdef PLATFORM_ESP32\n        displayConfig.type = pixelroot32::graphics::DisplayType::ST7789;\n        displayConfig.physicalWidth = 240;\n        displayConfig.physicalHeight = 240;\n        displayConfig.logicalWidth = 160; // 160x160 logic\n        displayConfig.logicalHeight = 160;\n    #elif PLATFORM_NATIVE\n        displayConfig.type = pixelroot32::graphics::DisplayType::NONE;\n        displayConfig.logicalWidth = 128;\n        displayConfig.logicalHeight = 128;\n    #endif\n\n    displayConfig.rotation = 0;\n\n    pixelroot32::core::Engine engine(displayConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/graphics/display_config/#display-type-details","title":"Display Type Details","text":""},{"location":"api_reference/graphics/display_config/#st7789","title":"ST7789","text":"
  • Resolution: Typically 240x240 or 240x320
  • Interface: SPI
  • Driver: TFT_eSPI
  • Common sizes: 240x240, 240x320
"},{"location":"api_reference/graphics/display_config/#st7735","title":"ST7735","text":"
  • Resolution: Typically 128x128 or 128x160
  • Interface: SPI
  • Driver: TFT_eSPI
  • Common sizes: 128x128, 128x160
"},{"location":"api_reference/graphics/display_config/#none-native","title":"NONE (Native)","text":"
  • Platform: Native/SDL2
  • Driver: SDL2_Drawer
  • Resolution: Configurable (any size)
  • Window: Creates SDL2 window
"},{"location":"api_reference/graphics/display_config/#rotation","title":"Rotation","text":"

Display rotation values:

  • 0: Normal orientation
  • 90: Rotated 90 degrees clockwise
  • 180: Rotated 180 degrees
  • 270: Rotated 90 degrees counter-clockwise

Notes: - Rotation affects coordinate system - Some displays may not support all rotations - Test rotation on your specific hardware

"},{"location":"api_reference/graphics/display_config/#performance-considerations","title":"Performance Considerations","text":"
  • Initialization: Display initialization happens once at startup
  • Driver selection: Automatic based on platform and type
  • Memory: DisplayConfig is small (few fields)
"},{"location":"api_reference/graphics/display_config/#esp32-considerations","title":"ESP32 Considerations","text":""},{"location":"api_reference/graphics/display_config/#tft_espi-configuration","title":"TFT_eSPI Configuration","text":"

DisplayConfig uses TFT_eSPI driver. Additional configuration may be needed in platformio.ini:

build_flags =\n    -DUSER_SETUP_LOADED=1\n    -DST7789_DRIVER=1\n    -DTFT_WIDTH=240\n    -DTFT_HEIGHT=240\n    # ... pin configuration\n
"},{"location":"api_reference/graphics/display_config/#pin-configuration","title":"Pin Configuration","text":"

GPIO pins must be configured separately (not in DisplayConfig):

  • MOSI: Data pin
  • SCLK: Clock pin
  • DC: Data/Command pin
  • RST: Reset pin
  • CS: Chip select pin (optional)
"},{"location":"api_reference/graphics/display_config/#see-also","title":"See Also","text":"
  • Renderer - Rendering system
  • Camera2D - Camera that uses display dimensions
  • Manual - Platforms and Drivers
  • API Overview
"},{"location":"api_reference/graphics/font/","title":"Font","text":"

Descriptor for a bitmap font using 1bpp sprites.

"},{"location":"api_reference/graphics/font/#description","title":"Description","text":"

A Font contains an array of Sprite structures, one for each character in the font's character set. Each glyph is rendered as a 1bpp sprite, allowing consistent rendering across platforms.

The font uses fixed-width glyphs for simplicity and performance. All glyphs share the same width and height, with spacing between characters controlled by the spacing field.

"},{"location":"api_reference/graphics/font/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    struct Font {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/font/#structure","title":"Structure","text":""},{"location":"api_reference/graphics/font/#const-sprite-glyphs","title":"const Sprite* glyphs","text":"

Array of sprites, one per character (indexed by character code - firstChar).

Type: const Sprite*

Access: Read-only

Notes: - Array must contain sprites for all characters from firstChar to lastChar - Each sprite represents one character glyph - Should be stored in flash (const/constexpr) for best performance

Example:

static const Sprite FONT_GLYPHS[] = {\n    spaceGlyph,    // Index 0 = ' ' (firstChar = 32)\n    exclamationGlyph, // Index 1 = '!'\n    // ... more glyphs\n};\n\nstatic const Font myFont = {\n    FONT_GLYPHS,\n    32,  // firstChar\n    126, // lastChar\n    5,   // glyphWidth\n    7,   // glyphHeight\n    1,   // spacing\n    8    // lineHeight\n};\n

"},{"location":"api_reference/graphics/font/#uint8_t-firstchar","title":"uint8_t firstChar","text":"

First character code in the font.

Type: uint8_t

Access: Read-only

Default: Typically 32 (space character)

Notes: - ASCII code of the first character - Common: 32 (space ' ') for ASCII fonts - Glyphs array starts at index 0 for this character

Example:

firstChar = 32;  // Starts at space character\n

"},{"location":"api_reference/graphics/font/#uint8_t-lastchar","title":"uint8_t lastChar","text":"

Last character code in the font.

Type: uint8_t

Access: Read-only

Default: Typically 126 (tilde '~')

Notes: - ASCII code of the last character - Common: 126 (tilde '~') for full ASCII fonts - Glyphs array must contain (lastChar - firstChar + 1) sprites

Example:

lastChar = 126;  // Ends at tilde character\n// Font contains characters 32-126 (95 characters)\n

"},{"location":"api_reference/graphics/font/#uint8_t-glyphwidth","title":"uint8_t glyphWidth","text":"

Fixed width of each glyph in pixels.

Type: uint8_t

Access: Read-only

Notes: - All glyphs must have the same width - Typical values: 5, 6, 8 pixels - Smaller = more characters per line, less readable

Example:

glyphWidth = 5;  // 5 pixels wide (like FONT_5X7)\n

"},{"location":"api_reference/graphics/font/#uint8_t-glyphheight","title":"uint8_t glyphHeight","text":"

Fixed height of each glyph in pixels.

Type: uint8_t

Access: Read-only

Notes: - All glyphs must have the same height - Typical values: 7, 8, 10 pixels - Smaller = more lines, less readable

Example:

glyphHeight = 7;  // 7 pixels tall (like FONT_5X7)\n

"},{"location":"api_reference/graphics/font/#uint8_t-spacing","title":"uint8_t spacing","text":"

Horizontal spacing between characters in pixels.

Type: uint8_t

Access: Read-only

Default: Typically 1

Notes: - Space added between characters - 0 = no spacing (characters touch) - 1 = 1 pixel gap (common) - Higher values = more readable but wider text

Example:

spacing = 1;  // 1 pixel between characters\n

"},{"location":"api_reference/graphics/font/#uint8_t-lineheight","title":"uint8_t lineHeight","text":"

Total line height including vertical spacing.

Type: uint8_t

Access: Read-only

Notes: - Should be glyphHeight + verticalSpacing - Used for line breaks and multi-line text - Typical: glyphHeight + 1 or glyphHeight + 2

Example:

lineHeight = 8;  // 7 pixel glyph + 1 pixel spacing\n

"},{"location":"api_reference/graphics/font/#built-in-fonts","title":"Built-in Fonts","text":""},{"location":"api_reference/graphics/font/#font_5x7","title":"FONT_5X7","text":"

Standard 5x7 pixel font (built-in).

Properties: - Width: 5 pixels - Height: 7 pixels - Characters: Typically ASCII 32-126 - Spacing: 1 pixel - Line height: 8 pixels

Usage:

#include \"graphics/Font.h\"\n\nrenderer.drawText(\"Hello\", 10, 10, Color::White, 1, &FONT_5X7);\n

"},{"location":"api_reference/graphics/font/#creating-custom-fonts","title":"Creating Custom Fonts","text":""},{"location":"api_reference/graphics/font/#step-1-create-glyph-sprites","title":"Step 1: Create Glyph Sprites","text":"
// Space character (ASCII 32)\nstatic const uint16_t SPACE_GLYPH[] = {\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000\n};\n\n// 'A' character (ASCII 65)\nstatic const uint16_t A_GLYPH[] = {\n    0b00100,\n    0b01010,\n    0b10001,\n    0b11111,\n    0b10001,\n    0b10001,\n    0b00000\n};\n\n// ... more glyphs\n
"},{"location":"api_reference/graphics/font/#step-2-create-glyph-array","title":"Step 2: Create Glyph Array","text":"
static const Sprite FONT_GLYPHS[] = {\n    {SPACE_GLYPH, 5, 7},  // Index 0 = ' ' (32)\n    // ... more glyphs\n    {A_GLYPH, 5, 7},      // Index 33 = 'A' (65)\n    // ... more glyphs\n};\n
"},{"location":"api_reference/graphics/font/#step-3-create-font-structure","title":"Step 3: Create Font Structure","text":"
static const Font MY_FONT = {\n    FONT_GLYPHS,  // glyphs array\n    32,           // firstChar (space)\n    126,          // lastChar (tilde)\n    5,            // glyphWidth\n    7,            // glyphHeight\n    1,            // spacing\n    8             // lineHeight\n};\n
"},{"location":"api_reference/graphics/font/#step-4-use-font","title":"Step 4: Use Font","text":"
renderer.drawText(\"Hello\", 10, 10, Color::White, 1, &MY_FONT);\n
"},{"location":"api_reference/graphics/font/#usage-example","title":"Usage Example","text":"
#include \"graphics/Font.h\"\n#include \"graphics/Renderer.h\"\n\n// Using built-in font\nvoid draw(Renderer& renderer) override {\n    // Default font\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n\n    // Explicit font\n    renderer.drawText(\"Score: 100\", 10, 30, Color::White, 1, &FONT_5X7);\n\n    // Centered text with font\n    renderer.drawTextCentered(\"Game Over\", 64, Color::Yellow, 2, &FONT_5X7);\n}\n\n// Custom font example\nstatic const uint16_t CUSTOM_GLYPHS[][7] = {\n    // Space, A, B, C, etc.\n};\n\nstatic const Sprite CUSTOM_SPRITES[] = {\n    {CUSTOM_GLYPHS[0], 6, 8},  // Space\n    {CUSTOM_GLYPHS[1], 6, 8},  // A\n    // ... more\n};\n\nstatic const Font CUSTOM_FONT = {\n    CUSTOM_SPRITES,\n    32,   // firstChar\n    90,   // lastChar (A-Z only)\n    6,    // width\n    8,    // height\n    1,    // spacing\n    9     // lineHeight\n};\n\nvoid draw(Renderer& renderer) override {\n    renderer.drawText(\"CUSTOM\", 10, 10, Color::White, 1, &CUSTOM_FONT);\n}\n
"},{"location":"api_reference/graphics/font/#text-sizing","title":"Text Sizing","text":"

Calculate text dimensions:

int getTextWidth(const Font* font, const char* text) {\n    if (!font || !text) return 0;\n\n    int width = 0;\n    for (int i = 0; text[i] != '\\0'; i++) {\n        if (text[i] >= font->firstChar && text[i] <= font->lastChar) {\n            width += font->glyphWidth + font->spacing;\n        }\n    }\n    return width - font->spacing;  // Remove last spacing\n}\n\nint getTextHeight(const Font* font) {\n    return font ? font->lineHeight : 8;\n}\n
"},{"location":"api_reference/graphics/font/#performance-considerations","title":"Performance Considerations","text":"
  • Font storage: Store fonts in flash (const/constexpr) for best performance
  • Glyph lookup: Fast array access (character code - firstChar)
  • Fixed width: Fixed-width fonts are faster than variable-width
  • Font switching: Changing fonts is fast (just pointer assignment)
"},{"location":"api_reference/graphics/font/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store font data in flash, not RAM
  • Font size: Larger fonts use more flash memory
  • Character range: Limit character range to save memory if not needed
"},{"location":"api_reference/graphics/font/#see-also","title":"See Also","text":"
  • Renderer - Rendering system that uses fonts
  • Sprite - Sprite structure used for glyphs
  • Manual - Basic Rendering
  • API Overview
"},{"location":"api_reference/graphics/renderer/","title":"Renderer","text":"

High-level graphics rendering system for drawing shapes, text, sprites, and tilemaps.

"},{"location":"api_reference/graphics/renderer/#description","title":"Description","text":"

The Renderer class provides a unified API for drawing shapes, text, and images. It abstracts the underlying hardware implementation (DrawSurface) and manages display configuration, including rotation and resolution scaling.

All drawing operations are performed in logical screen space. If the logical resolution differs from the physical resolution, the renderer will automatically scale the output to fit the display using a high-performance nearest-neighbor algorithm.

The renderer uses integer-only math for optimal performance on ESP32 and supports multiple sprite formats (1bpp, 2bpp, 4bpp) and multi-layer sprites.

"},{"location":"api_reference/graphics/renderer/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    class Renderer {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/renderer/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages renderer instance)
"},{"location":"api_reference/graphics/renderer/#constructors","title":"Constructors","text":""},{"location":"api_reference/graphics/renderer/#rendererconst-displayconfig-config","title":"Renderer(const DisplayConfig& config)","text":"

Constructs the Renderer with a specific display configuration.

Parameters: - config (const DisplayConfig&): The display configuration settings (width, height, rotation, etc.)

Example:

#include \"graphics/Renderer.h\"\n#include \"graphics/DisplayConfig.h\"\n\n// 128x128 game logic scaled to 240x240 display\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7789,\n    0,      // rotation\n    240, 240, // physical resolution\n    128, 128  // logical resolution (rendering space)\n);\n\npixelroot32::graphics::Renderer renderer(config);\nrenderer.init();\n

"},{"location":"api_reference/graphics/renderer/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/graphics/renderer/#void-init","title":"void init()","text":"

Initializes the renderer and the underlying draw surface.

Returns: - void

Notes: - Must be called after construction and before any drawing operations - Initializes the platform-specific DrawSurface implementation - Safe to call multiple times (idempotent)

Example:

Renderer renderer(displayConfig);\nrenderer.init();  // Initialize before use\n

"},{"location":"api_reference/graphics/renderer/#void-beginframe","title":"void beginFrame()","text":"

Prepares the buffer for a new frame (clears screen).

Returns: - void

Notes: - Should be called once at the start of each frame - Clears the display buffer - Typically called automatically by Engine, but can be called manually

Example:

void draw(Renderer& renderer) override {\n    renderer.beginFrame();\n    // Draw everything...\n    renderer.endFrame();\n}\n

"},{"location":"api_reference/graphics/renderer/#void-endframe","title":"void endFrame()","text":"

Finalizes the frame and sends the buffer to the display.

Returns: - void

Notes: - Should be called once at the end of each frame - Sends the completed frame buffer to the display - Typically called automatically by Engine, but can be called manually

"},{"location":"api_reference/graphics/renderer/#drawsurface-getdrawsurface","title":"DrawSurface& getDrawSurface()","text":"

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed unless implementing custom drawing - Provides low-level access to the display driver

"},{"location":"api_reference/graphics/renderer/#void-drawtextconst-char-text-int16_t-x-int16_t-y-color-color-uint8_t-size","title":"void drawText(const char* text, int16_t x, int16_t y, Color color, uint8_t size)","text":"

Draws a string of text using the default font and scaling.

Parameters: - text (const char*): The text to draw (null-terminated string) - x (int16_t): X coordinate (top-left corner of text) - y (int16_t): Y coordinate (top-left corner of text) - color (Color): Text color - size (uint8_t): Text size multiplier (1 = 5x7 pixels, 2 = 10x14 pixels, etc.)

Performance Notes: - Efficient for small amounts of text - Uses integer-only scaling (no floats)

Example:

renderer.drawText(\"Hello World\", 10, 10, Color::White, 1);\nrenderer.drawText(\"Score: 100\", 10, 30, Color::Yellow, 2);\n

"},{"location":"api_reference/graphics/renderer/#void-drawtextconst-char-text-int16_t-x-int16_t-y-color-color-uint8_t-size-const-font-font","title":"void drawText(const char text, int16_t x, int16_t y, Color color, uint8_t size, const Font font)","text":"

Draws a string of text using a specific font and scaling.

Parameters: - text (const char): The text to draw - x (int16_t): X coordinate - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size multiplier - font (const Font): Pointer to the font to use. If nullptr, uses the default font

Example:

const Font* customFont = &FONT_5X7;\nrenderer.drawText(\"Custom Font\", 10, 10, Color::White, 1, customFont);\n

"},{"location":"api_reference/graphics/renderer/#void-drawtextcenteredconst-char-text-int16_t-y-color-color-uint8_t-size","title":"void drawTextCentered(const char* text, int16_t y, Color color, uint8_t size)","text":"

Draws text centered horizontally at a given Y coordinate using the default font.

Parameters: - text (const char*): The text to draw - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size

Example:

renderer.drawTextCentered(\"Game Over\", 64, Color::White, 2);\n

"},{"location":"api_reference/graphics/renderer/#void-drawtextcenteredconst-char-text-int16_t-y-color-color-uint8_t-size-const-font-font","title":"void drawTextCentered(const char text, int16_t y, Color color, uint8_t size, const Font font)","text":"

Draws text centered horizontally at a given Y coordinate using a specific font.

Parameters: - text (const char): The text to draw - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size - font (const Font): Pointer to the font to use. If nullptr, uses the default font

"},{"location":"api_reference/graphics/renderer/#void-drawfilledcircleint-x-int-y-int-radius-color-color","title":"void drawFilledCircle(int x, int y, int radius, Color color)","text":"

Draws a filled circle.

Parameters: - x (int): Center X coordinate - y (int): Center Y coordinate - radius (int): Radius of the circle in pixels - color (Color): Fill color

Example:

renderer.drawFilledCircle(64, 64, 20, Color::Red);\n

"},{"location":"api_reference/graphics/renderer/#void-drawcircleint-x-int-y-int-radius-color-color","title":"void drawCircle(int x, int y, int radius, Color color)","text":"

Draws a circle outline.

Parameters: - x (int): Center X coordinate - y (int): Center Y coordinate - radius (int): Radius of the circle in pixels - color (Color): Outline color

Example:

renderer.drawCircle(64, 64, 20, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-drawrectangleint-x-int-y-int-width-int-height-color-color","title":"void drawRectangle(int x, int y, int width, int height, Color color)","text":"

Draws a rectangle outline.

Parameters: - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - width (int): Width of the rectangle in pixels - height (int): Height of the rectangle in pixels - color (Color): Outline color

Example:

renderer.drawRectangle(10, 10, 100, 50, Color::Blue);\n

"},{"location":"api_reference/graphics/renderer/#void-drawfilledrectangleint-x-int-y-int-width-int-height-color-color","title":"void drawFilledRectangle(int x, int y, int width, int height, Color color)","text":"

Draws a filled rectangle.

Parameters: - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - width (int): Width of the rectangle in pixels - height (int): Height of the rectangle in pixels - color (Color): Fill color

Example:

renderer.drawFilledRectangle(10, 10, 100, 50, Color::Green);\n

"},{"location":"api_reference/graphics/renderer/#void-drawlineint-x1-int-y1-int-x2-int-y2-color-color","title":"void drawLine(int x1, int y1, int x2, int y2, Color color)","text":"

Draws a line between two points.

Parameters: - x1 (int): Start X coordinate - y1 (int): Start Y coordinate - x2 (int): End X coordinate - y2 (int): End Y coordinate - color (Color): Line color

Example:

renderer.drawLine(0, 0, 128, 128, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-drawpixelint-x-int-y-color-color","title":"void drawPixel(int x, int y, Color color)","text":"

Draws a single pixel.

Parameters: - x (int): X coordinate - y (int): Y coordinate - color (Color): Pixel color

Performance Notes: - Very fast, but avoid calling thousands of times per frame - Use for special effects or debugging

Example:

renderer.drawPixel(64, 64, Color::Red);\n

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite-sprite-int-x-int-y-color-color-bool-flipx-false","title":"void drawSprite(const Sprite& sprite, int x, int y, Color color, bool flipX = false)","text":"

Draws a 1bpp monochrome sprite using the Sprite descriptor.

Parameters: - sprite (const Sprite&): Sprite descriptor (data, width, height) - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space - color (Color): Color used for \"on\" pixels - flipX (bool, optional): If true, sprite is mirrored horizontally. Default: false

Performance Notes: - Very efficient for 1bpp sprites (integer-only operations) - Sprite data should be stored in flash (const/constexpr) for best performance

Example:

renderer.drawSprite(playerSprite, 100, 100, Color::White);\nrenderer.drawSprite(playerSprite, 120, 100, Color::White, true);  // Flipped\n

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite-sprite-int-x-int-y-float-scalex-float-scaley-color-color-bool-flipx-false","title":"void drawSprite(const Sprite& sprite, int x, int y, float scaleX, float scaleY, Color color, bool flipX = false)","text":"

Draws a scaled 1bpp monochrome sprite using nearest-neighbor scaling.

Parameters: - sprite (const Sprite&): Sprite descriptor - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - scaleX (float): Horizontal scaling factor (e.g., 2.0 for double width) - scaleY (float): Vertical scaling factor - color (Color): Color used for \"on\" pixels - flipX (bool, optional): If true, sprite is mirrored horizontally before scaling. Default: false

Performance Notes: - Slower than non-scaled version due to scaling calculations - The destination size is calculated as ceil(width * scaleX) x ceil(height * scaleY)

Example:

renderer.drawSprite(playerSprite, 100, 100, 2.0f, 2.0f, Color::White);  // 2x size\n

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite2bpp-sprite-int-x-int-y-bool-flipx-false","title":"void drawSprite(const Sprite2bpp& sprite, int x, int y, bool flipX = false)","text":"

Draws a 2bpp sprite. Available when PIXELROOT32_ENABLE_2BPP_SPRITES is defined.

Parameters: - sprite (const Sprite2bpp&): 2bpp sprite descriptor - x (int): X coordinate - y (int): Y coordinate - flipX (bool, optional): Horizontal flip. Default: false

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite4bpp-sprite-int-x-int-y-bool-flipx-false","title":"void drawSprite(const Sprite4bpp& sprite, int x, int y, bool flipX = false)","text":"

Draws a 4bpp sprite. Available when PIXELROOT32_ENABLE_4BPP_SPRITES is defined.

Parameters: - sprite (const Sprite4bpp&): 4bpp sprite descriptor - x (int): X coordinate - y (int): Y coordinate - flipX (bool, optional): Horizontal flip. Default: false

"},{"location":"api_reference/graphics/renderer/#void-drawmultispriteconst-multisprite-sprite-int-x-int-y","title":"void drawMultiSprite(const MultiSprite& sprite, int x, int y)","text":"

Draws a multi-layer sprite composed of several 1bpp layers.

Parameters: - sprite (const MultiSprite&): Multi-layer sprite descriptor - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space

Performance Notes: - Each layer is rendered separately, so more layers = more draw calls - Still efficient as each layer uses 1bpp format - Use for multi-color sprites without higher bit-depths

Example:

static const SpriteLayer layers[] = {\n    { outlineData, Color::Black },\n    { fillData, Color::Red },\n    { highlightData, Color::Yellow }\n};\n\nstatic const MultiSprite playerMultiSprite = {\n    8,      // width\n    8,      // height\n    layers, // layers array\n    3       // layer count\n};\n\nrenderer.drawMultiSprite(playerMultiSprite, 100, 100);\n

"},{"location":"api_reference/graphics/renderer/#void-drawmultispriteconst-multisprite-sprite-int-x-int-y-float-scalex-float-scaley","title":"void drawMultiSprite(const MultiSprite& sprite, int x, int y, float scaleX, float scaleY)","text":"

Draws a scaled multi-layer sprite.

Parameters: - sprite (const MultiSprite&): Multi-layer sprite descriptor - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - scaleX (float): Horizontal scaling factor - scaleY (float): Vertical scaling factor

"},{"location":"api_reference/graphics/renderer/#void-drawtilemapconst-tilemap-map-int-originx-int-originy-color-color","title":"void drawTileMap(const TileMap& map, int originX, int originY, Color color)","text":"

Draws a 1bpp tilemap.

Parameters: - map (const TileMap&): Tilemap descriptor (indices, 1bpp tiles, dimensions) - originX (int): X coordinate of the top-left corner - originY (int): Y coordinate of the top-left corner - color (Color): Color used for all tiles in the map

"},{"location":"api_reference/graphics/renderer/#void-drawtilemapconst-tilemap2bpp-map-int-originx-int-originy","title":"void drawTileMap(const TileMap2bpp& map, int originX, int originY)","text":"

Draws a 2bpp tilemap. Available when PIXELROOT32_ENABLE_2BPP_SPRITES is defined.

Parameters: - map (const TileMap2bpp&): Tilemap descriptor (indices, 2bpp tiles, dimensions) - originX (int): X coordinate - originY (int): Y coordinate

"},{"location":"api_reference/graphics/renderer/#void-drawtilemapconst-tilemap4bpp-map-int-originx-int-originy","title":"void drawTileMap(const TileMap4bpp& map, int originX, int originY)","text":"

Draws a 4bpp tilemap. Available when PIXELROOT32_ENABLE_4BPP_SPRITES is defined.

Parameters: - map (const TileMap4bpp&): Tilemap descriptor (indices, 4bpp tiles, dimensions) - originX (int): X coordinate - originY (int): Y coordinate

Performance Notes: - Very efficient for rendering large backgrounds - Only visible tiles are drawn (viewport culling) - Use tilemaps instead of individual sprites for backgrounds

Example:

static const uint8_t levelIndices[] = {\n    0, 1, 2, 3,\n    4, 5, 6, 7,\n    // ... more rows\n};\n\nstatic const TileMap levelMap = {\n    levelIndices,\n    16,        // width in tiles\n    16,        // height in tiles\n    tileSprites, // tile sprite array\n    8,         // tile width\n    8,         // tile height\n    16         // tile count\n};\n\nrenderer.drawTileMap(levelMap, 0, 0, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#int-getlogicalwidth-const","title":"int getLogicalWidth() const","text":"

Gets the logical rendering width.

Returns: - int: The width of the logical screen space.

"},{"location":"api_reference/graphics/renderer/#int-getlogicalheight-const","title":"int getLogicalHeight() const","text":"

Gets the logical rendering height.

Returns: - int: The height of the logical screen space.

Note: These methods replace the deprecated getWidth() and getHeight().

"},{"location":"api_reference/graphics/renderer/#void-setdisplayoffsetint-x-int-y","title":"void setDisplayOffset(int x, int y)","text":"

Sets a global offset for all drawing operations. Useful for camera/parallax effects.

Parameters: - x (int): X offset in pixels - y (int): Y offset in pixels

Notes: - All subsequent drawing operations are offset by this amount - Useful for camera scrolling and parallax effects - Reset to (0, 0) to disable offset

Example:

// Camera scrolling\ncamera.setPosition(playerX - 64, playerY - 64);\nrenderer.setDisplayOffset(-camera.getX(), -camera.getY());\nrenderer.drawTileMap(background, 0, 0, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-setdisplaysizeint-w-int-h","title":"void setDisplaySize(int w, int h)","text":"

Sets the logical display size.

Parameters: - w (int): Width in pixels - h (int): Height in pixels

Notes: - Typically set via DisplayConfig during construction - Use this to change display size at runtime if needed

"},{"location":"api_reference/graphics/renderer/#int-getwidth-const","title":"int getWidth() const","text":"

Gets the display width.

Returns: - int: Display width in pixels

"},{"location":"api_reference/graphics/renderer/#int-getheight-const","title":"int getHeight() const","text":"

Gets the display height.

Returns: - int: Display height in pixels

"},{"location":"api_reference/graphics/renderer/#int-getxoffset-const","title":"int getXOffset() const","text":"

Gets the current X display offset.

Returns: - int: X offset in pixels

"},{"location":"api_reference/graphics/renderer/#int-getyoffset-const","title":"int getYOffset() const","text":"

Gets the current Y display offset.

Returns: - int: Y offset in pixels

"},{"location":"api_reference/graphics/renderer/#void-setcontrastuint8_t-level","title":"void setContrast(uint8_t level)","text":"

Sets the display contrast (brightness).

Parameters: - level (uint8_t): Contrast level (0-255)

Notes: - Platform-specific: may not be supported on all displays - Higher values = brighter display

"},{"location":"api_reference/graphics/renderer/#void-setfontconst-uint8_t-font","title":"void setFont(const uint8_t* font)","text":"

Sets the font for text rendering.

Parameters: - font (const uint8_t*): Pointer to the font data

Notes: - Sets the default font for drawText() calls without font parameter - Use font constants like FONT_5X7 from Font.h

"},{"location":"api_reference/graphics/renderer/#usage-example","title":"Usage Example","text":"
#include \"graphics/Renderer.h\"\n#include \"graphics/DisplayConfig.h\"\n\nvoid draw(Renderer& renderer) override {\n    renderer.beginFrame();\n\n    // Draw background\n    renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n\n    // Draw sprites\n    renderer.drawSprite(playerSprite, playerX, playerY, Color::White);\n    renderer.drawSprite(enemySprite, enemyX, enemyY, Color::Red);\n\n    // Draw UI\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n    renderer.drawTextCentered(\"Game Over\", 64, Color::Yellow, 2);\n\n    renderer.endFrame();\n}\n
"},{"location":"api_reference/graphics/renderer/#performance-considerations","title":"Performance Considerations","text":"
  • Integer-only math: All operations use integer arithmetic for ESP32 efficiency
  • Sprite storage: Store sprite data in flash (const/constexpr) for best performance
  • Batch operations: Group similar draw calls together
  • Tilemaps: Dibuja un mapa de tiles completo. Implementa viewport culling autom\u00e1tico y cach\u00e9 de paleta para m\u00e1ximo rendimiento.
  • Sprites 2bpp/4bpp: Optimizado para ESP32 (IRAM + acceso de 16 bits).
"},{"location":"api_reference/graphics/renderer/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Sprite data should be in flash, not RAM
  • Frame rate: Limit draw calls per frame for consistent FPS
  • Display offset: Use for scrolling instead of redrawing everything
"},{"location":"api_reference/graphics/renderer/#see-also","title":"See Also","text":"
  • Sprite - Sprite structure
  • MultiSprite - Multi-layer sprites
  • TileMap - Tilemap structure
  • Color - Color constants
  • DisplayConfig - Display configuration
  • Camera2D - Camera for scrolling
  • Manual - Basic Rendering
  • Manual - Sprites and Animation
  • API Overview
"},{"location":"api_reference/graphics/sprite/","title":"Sprite","text":"

Low-level bitmap descriptor and multi-layer composition for retro rendering.

"},{"location":"api_reference/graphics/sprite/#description","title":"Description","text":"

Sprites are the fundamental graphics primitive in PixelRoot32. The engine supports multiple sprite formats:

  • 1bpp (Standard): Monochrome sprites, most memory-efficient
  • 2bpp (Experimental): 4 colors per sprite
  • 4bpp (Experimental): 16 colors per sprite
  • MultiSprite: Multi-layer 1bpp sprites for multi-color effects
"},{"location":"api_reference/graphics/sprite/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    struct Sprite {\n        // ...\n    };\n\n    struct MultiSprite {\n        // ...\n    };\n\n    struct SpriteLayer {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/sprite/#sprite-structure-1bpp","title":"Sprite Structure (1bpp)","text":"

Compact sprite descriptor for monochrome bitmapped sprites.

"},{"location":"api_reference/graphics/sprite/#members","title":"Members","text":"
  • const uint16_t* data: Pointer to packed row data (size = height)
  • uint8_t width: Sprite width in pixels (\u2264 16)
  • uint8_t height: Sprite height in pixels
"},{"location":"api_reference/graphics/sprite/#data-format","title":"Data Format","text":"

Sprites are stored as an array of 16-bit rows. Each row packs horizontal pixels into bits:

  • Bit 0: Leftmost pixel of the row
  • Bit (width - 1): Rightmost pixel of the row
  • Bit value 1: Pixel on (colored)
  • Bit value 0: Pixel off (transparent/background)

Only the lowest width bits of each row are used.

"},{"location":"api_reference/graphics/sprite/#example","title":"Example","text":"
// 8x8 sprite (smiley face)\nstatic const uint16_t SMILEY_DATA[] = {\n    0b00111100,  // Row 0:  \u2588\u2588\u2588\u2588\n    0b01111110,  // Row 1:  \u2588\u2588\u2588\u2588\u2588\u2588\n    0b11011011,  // Row 2:  \u2588\u2588 \u2588\u2588 \u2588\u2588\n    0b11111111,  // Row 3:  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\n    0b11011011,  // Row 4:  \u2588\u2588 \u2588\u2588 \u2588\u2588\n    0b01100110,  // Row 5:  \u2588\u2588  \u2588\u2588\n    0b01111110,  // Row 6:  \u2588\u2588\u2588\u2588\u2588\u2588\n    0b00111100   // Row 7:  \u2588\u2588\u2588\u2588\n};\n\nstatic const Sprite SMILEY_SPRITE = {\n    SMILEY_DATA,\n    8,  // width\n    8   // height\n};\n
"},{"location":"api_reference/graphics/sprite/#spritelayer-structure","title":"SpriteLayer Structure","text":"

Single monochrome layer used by layered sprites.

"},{"location":"api_reference/graphics/sprite/#members_1","title":"Members","text":"
  • const uint16_t* data: Pointer to packed row data for this layer
  • Color color: Color used for \"on\" pixels in this layer
"},{"location":"api_reference/graphics/sprite/#notes","title":"Notes","text":"
  • Each layer uses the same width/height as its owning MultiSprite
  • Layers can have different colors
  • Layers are drawn in array order
"},{"location":"api_reference/graphics/sprite/#multisprite-structure","title":"MultiSprite Structure","text":"

Multi-layer, multi-color sprite built from 1bpp layers.

"},{"location":"api_reference/graphics/sprite/#members_2","title":"Members","text":"
  • uint8_t width: Sprite width in pixels (\u2264 16)
  • uint8_t height: Sprite height in pixels
  • const SpriteLayer* layers: Pointer to array of layers
  • uint8_t layerCount: Number of layers in the array
"},{"location":"api_reference/graphics/sprite/#notes_1","title":"Notes","text":"
  • Combines several 1bpp layers with different colors
  • Layers are drawn in array order
  • Enables multi-color sprites without higher bit-depths
  • More layers = more draw calls (but still efficient)
"},{"location":"api_reference/graphics/sprite/#example_1","title":"Example","text":"
// Outline layer\nstatic const uint16_t OUTLINE_DATA[] = {\n    0b11111111,\n    0b10000001,\n    0b10000001,\n    0b11111111\n};\n\n// Fill layer\nstatic const uint16_t FILL_DATA[] = {\n    0b00000000,\n    0b01111110,\n    0b01111110,\n    0b00000000\n};\n\nstatic const SpriteLayer LAYERS[] = {\n    {OUTLINE_DATA, Color::Black},  // Layer 0: Black outline\n    {FILL_DATA, Color::Red}       // Layer 1: Red fill\n};\n\nstatic const MultiSprite PLAYER_MULTISPRITE = {\n    8,      // width\n    8,      // height\n    LAYERS, // layers array\n    2       // layer count\n};\n
"},{"location":"api_reference/graphics/sprite/#sprite2bpp-structure-experimental","title":"Sprite2bpp Structure (Experimental)","text":"

2-bit per pixel sprite (4 colors).

Requires: PIXELROOT32_ENABLE_2BPP_SPRITES build flag

"},{"location":"api_reference/graphics/sprite/#members_3","title":"Members","text":"
  • const uint16_t* data: Datos empaquetados (4 p\u00edxeles por cada 8 bits, alineados a 16 bits)
  • const Color* palette: Local palette (4 colors)
  • uint8_t width: Sprite width
  • uint8_t height: Sprite height
  • uint8_t paletteSize: Number of colors (typically 4)
"},{"location":"api_reference/graphics/sprite/#notes_2","title":"Notes","text":"
  • Experimental feature
  • Uses more memory than 1bpp
  • Each pixel can be one of 4 colors from local palette
"},{"location":"api_reference/graphics/sprite/#sprite4bpp-structure-experimental","title":"Sprite4bpp Structure (Experimental)","text":"

4-bit per pixel sprite (16 colors).

Requires: PIXELROOT32_ENABLE_4BPP_SPRITES build flag

"},{"location":"api_reference/graphics/sprite/#members_4","title":"Members","text":"
  • const uint16_t* data: Datos empaquetados (2 p\u00edxeles por cada 8 bits, alineados a 16 bits)
  • const Color* palette: Local palette (16 colors)
  • uint8_t width: Sprite width
  • uint8_t height: Sprite height
  • uint8_t paletteSize: Number of colors (typically 16)
"},{"location":"api_reference/graphics/sprite/#notes_3","title":"Notes","text":"
  • Experimental feature
  • Uses more memory than 1bpp/2bpp
  • Each pixel can be one of 16 colors from local palette
"},{"location":"api_reference/graphics/sprite/#sprite-animation","title":"Sprite Animation","text":""},{"location":"api_reference/graphics/sprite/#spriteanimationframe-structure","title":"SpriteAnimationFrame Structure","text":"

Frame that can reference either a Sprite or a MultiSprite.

Members: - const Sprite* sprite: Optional pointer to a simple 1bpp sprite frame - const MultiSprite* multiSprite: Optional pointer to a layered sprite frame

Notes: - Exactly one pointer should be non-null for a valid frame - Allows same animation system for both sprite types

"},{"location":"api_reference/graphics/sprite/#spriteanimation-structure","title":"SpriteAnimation Structure","text":"

Lightweight, step-based sprite animation controller.

Members: - const SpriteAnimationFrame* frames: Pointer to immutable frame table - uint8_t frameCount: Number of frames in the table - uint8_t current: Current frame index [0, frameCount)

Methods: - void reset(): Reset to first frame - void step(): Advance to next frame (wrapping) - const SpriteAnimationFrame& getCurrentFrame() const: Get current frame - const Sprite* getCurrentSprite() const: Get current simple sprite - const MultiSprite* getCurrentMultiSprite() const: Get current multi-sprite

Example:

static const SpriteAnimationFrame WALK_FRAMES[] = {\n    {&walkFrame1, nullptr},\n    {&walkFrame2, nullptr},\n    {&walkFrame3, nullptr},\n    {&walkFrame2, nullptr}  // Loop back\n};\n\nstatic SpriteAnimation walkAnimation = {\n    WALK_FRAMES,\n    4,    // frameCount\n    0     // current\n};\n\n// In update\nwalkAnimation.step();\nconst Sprite* currentSprite = walkAnimation.getCurrentSprite();\n

"},{"location":"api_reference/graphics/sprite/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/graphics/sprite/#creating-1bpp-sprites","title":"Creating 1bpp Sprites","text":"
// 8x8 player sprite\nstatic const uint16_t PLAYER_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11011011,\n    0b11111111,\n    0b01111110,\n    0b00111100,\n    0b00011000\n};\n\nstatic const Sprite PLAYER_SPRITE = {\n    PLAYER_DATA,\n    8,  // width\n    8   // height\n};\n\n// Use in rendering\nrenderer.drawSprite(PLAYER_SPRITE, 100, 100, Color::White);\n
"},{"location":"api_reference/graphics/sprite/#creating-multisprite","title":"Creating MultiSprite","text":"
// Outline layer\nstatic const uint16_t OUTLINE[] = {\n    0b11111111,\n    0b10000001,\n    0b10000001,\n    0b11111111\n};\n\n// Fill layer\nstatic const uint16_t FILL[] = {\n    0b00000000,\n    0b01111110,\n    0b01111110,\n    0b00000000\n};\n\nstatic const SpriteLayer LAYERS[] = {\n    {OUTLINE, Color::Black},\n    {FILL, Color::Red}\n};\n\nstatic const MultiSprite ENEMY_SPRITE = {\n    8,      // width\n    8,      // height\n    LAYERS, // layers\n    2       // layer count\n};\n\n// Use in rendering\nrenderer.drawMultiSprite(ENEMY_SPRITE, 100, 100);\n
"},{"location":"api_reference/graphics/sprite/#sprite-animation_1","title":"Sprite Animation","text":"
class AnimatedActor : public pixelroot32::core::Actor {\nprivate:\n    SpriteAnimation animation;\n    unsigned long animTimer = 0;\n    unsigned long animInterval = 200;  // 200ms per frame\n\npublic:\n    void update(unsigned long deltaTime) override {\n        Actor::update(deltaTime);\n\n        animTimer += deltaTime;\n        if (animTimer >= animInterval) {\n            animTimer -= animInterval;\n            animation.step();\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        const Sprite* frame = animation.getCurrentSprite();\n        if (frame) {\n            renderer.drawSprite(*frame, \n                               static_cast<int>(x), \n                               static_cast<int>(y), \n                               Color::White);\n        }\n    }\n};\n
"},{"location":"api_reference/graphics/sprite/#sprite-flipping","title":"Sprite Flipping","text":"

Sprites can be flipped horizontally:

// Draw normal\nrenderer.drawSprite(sprite, 100, 100, Color::White, false);\n\n// Draw flipped\nrenderer.drawSprite(sprite, 100, 100, Color::White, true);\n
"},{"location":"api_reference/graphics/sprite/#performance-considerations","title":"Performance Considerations","text":"
  • 1bpp sprites: Most efficient (integer-only operations)
  • MultiSprite: Each layer is a separate draw call (still efficient)
  • 2bpp/4bpp: Experimental, uses more memory and CPU
  • Storage: Store sprite data in flash (const/constexpr) for best performance
  • Size limit: Sprites are limited to 16 pixels wide for 1bpp format
"},{"location":"api_reference/graphics/sprite/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store sprite data in flash, not RAM
  • Sprite size: Smaller sprites = faster drawing
  • Format choice: Use 1bpp when possible for best performance
  • MultiSprite: More layers = more draw calls (but acceptable)
"},{"location":"api_reference/graphics/sprite/#see-also","title":"See Also","text":"
  • Renderer - Rendering system that draws sprites
  • Color - Color constants for sprites
  • Manual - Sprites and Animation
  • API Overview
"},{"location":"api_reference/graphics/tilemap/","title":"TileMap","text":"

Generic structure for tile-based background rendering.

"},{"location":"api_reference/graphics/tilemap/#description","title":"Description","text":"

TileMapGeneric<T> is a template structure for rendering tile-based backgrounds efficiently. It supports multiple bit-depths (1bpp, 2bpp, 4bpp) by using the appropriate sprite type for tiles.

Tilemaps are ideal for large backgrounds, levels, and static environments. They support viewport culling (only visible tiles are drawn) for optimal performance.

"},{"location":"api_reference/graphics/tilemap/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    template<typename T>\n    struct TileMapGeneric {\n        // ...\n    };\n\n    using TileMap = TileMapGeneric<Sprite>;\n    using TileMap2bpp = TileMapGeneric<Sprite2bpp>;\n    using TileMap4bpp = TileMapGeneric<Sprite4bpp>;\n}\n
"},{"location":"api_reference/graphics/tilemap/#template-parameters","title":"Template Parameters","text":""},{"location":"api_reference/graphics/tilemap/#t","title":"T","text":"

The sprite type used for tiles.

Supported types: - Sprite (1bpp) - Sprite2bpp (2bpp) - Sprite4bpp (4bpp)

"},{"location":"api_reference/graphics/tilemap/#structure","title":"Structure","text":""},{"location":"api_reference/graphics/tilemap/#uint8_t-indices","title":"uint8_t* indices","text":"

Array of tile indices mapping to tile sprites.

Type: uint8_t*

Access: Read-write

Notes: - Array size = width * height - Each value is an index into the tiles array - 0 = first tile, 1 = second tile, etc. - Should be stored in flash (const) for best performance

Example:

// 16x16 tilemap (256 tiles)\nstatic const uint8_t LEVEL_INDICES[] = {\n    0, 0, 0, 0, 1, 1, 1, 1, // Row 0\n    0, 2, 2, 2, 2, 2, 2, 0, // Row 1\n    // ... more rows\n};\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-width","title":"uint8_t width","text":"

Width of the tilemap in tiles.

Type: uint8_t

Access: Read-write

Example:

width = 16;  // 16 tiles wide\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-height","title":"uint8_t height","text":"

Height of the tilemap in tiles.

Type: uint8_t

Access: Read-write

Example:

height = 16;  // 16 tiles tall\n

"},{"location":"api_reference/graphics/tilemap/#const-t-tiles","title":"const T* tiles","text":"

Array of tile sprites of type T.

Type: const T*

Access: Read-only

Notes: - Array of sprite pointers, one per unique tile - Indices reference this array - All tiles should be the same size - Should be stored in flash (const) for best performance

Example (1bpp):

static const Sprite TILE_SPRITES[] = {\n    EMPTY_TILE,   // Index 0\n    WALL_TILE,    // Index 1\n    FLOOR_TILE,   // Index 2\n    // ... more tiles\n};\n

Example (2bpp):

static const Sprite2bpp TILE_SPRITES_2BPP[] = {\n    TILE_GRASS,   // Index 0\n    TILE_DIRT,    // Index 1\n    // ... more tiles\n};\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-tilewidth","title":"uint8_t tileWidth","text":"

Width of each tile in pixels.

Type: uint8_t

Access: Read-write

Notes: - All tiles must have the same width - Common values: 8, 16 pixels - Should match sprite width

Example:

tileWidth = 8;  // 8x8 tiles\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-tileheight","title":"uint8_t tileHeight","text":"

Height of each tile in pixels.

Type: uint8_t

Access: Read-write

Notes: - All tiles must have the same height - Common values: 8, 16 pixels - Should match sprite height

Example:

tileHeight = 8;  // 8x8 tiles\n

"},{"location":"api_reference/graphics/tilemap/#uint16_t-tilecount","title":"uint16_t tileCount","text":"

Number of unique tiles in the tiles array.

Type: uint16_t

Access: Read-write

Notes: - Must match the size of the tiles array - Indices must be < tileCount

Example:

tileCount = 16;  // 16 unique tiles\n

"},{"location":"api_reference/graphics/tilemap/#creating-tilemaps","title":"Creating Tilemaps","text":""},{"location":"api_reference/graphics/tilemap/#step-1-create-tile-sprites","title":"Step 1: Create Tile Sprites","text":"
// Empty tile (index 0)\nstatic const uint16_t EMPTY_DATA[] = {\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000\n};\n\n// Wall tile (index 1)\nstatic const uint16_t WALL_DATA[] = {\n    0b11111111,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b11111111\n};\n\n// Floor tile (index 2)\nstatic const uint16_t FLOOR_DATA[] = {\n    0b00000000,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b00000000\n};\n\nstatic const Sprite TILE_SPRITES[] = {\n    {EMPTY_DATA, 8, 8},  // Index 0\n    {WALL_DATA, 8, 8},   // Index 1\n    {FLOOR_DATA, 8, 8}   // Index 2\n};\n
"},{"location":"api_reference/graphics/tilemap/#step-2-create-index-array","title":"Step 2: Create Index Array","text":"
// 16x16 level (256 tiles)\n// 0 = empty, 1 = wall, 2 = floor\nstatic const uint8_t LEVEL_INDICES[] = {\n    // Row 0: Top wall\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n    // Row 1: Walls on sides\n    1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,\n    // Row 2\n    1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,\n    // ... more rows\n    // Row 15: Bottom wall\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n};\n
"},{"location":"api_reference/graphics/tilemap/#step-3-create-tilemap-structure","title":"Step 3: Create TileMap Structure","text":"
static const TileMap LEVEL_MAP = {\n    const_cast<uint8_t*>(LEVEL_INDICES),  // indices (non-const for struct)\n    16,        // width in tiles\n    16,        // height in tiles\n    TILE_SPRITES, // tile sprites array\n    8,         // tile width\n    8,         // tile height\n    3          // tile count\n};\n
"},{"location":"api_reference/graphics/tilemap/#rendering-tilemaps","title":"Rendering Tilemaps","text":"

Use Renderer::drawTileMap():

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Draw tilemap at origin (0, 0)\n    renderer.drawTileMap(LEVEL_MAP, 0, 0, Color::White);\n\n    // With camera offset\n    camera.apply(renderer);\n    renderer.drawTileMap(LEVEL_MAP, 0, 0, Color::White);\n}\n
"},{"location":"api_reference/graphics/tilemap/#viewport-culling","title":"Viewport Culling","text":"

Tilemaps automatically cull tiles outside the viewport:

  • Only visible tiles are drawn
  • Very efficient for large levels
  • Works with camera scrolling

Example:

// Large level (256x256 tiles)\n// Only tiles visible on screen are drawn\ncamera.apply(renderer);\nrenderer.drawTileMap(LARGE_LEVEL_MAP, 0, 0, Color::White);\n

"},{"location":"api_reference/graphics/tilemap/#collision-detection-with-tilemaps","title":"Collision Detection with Tilemaps","text":"

Check tile at world position:

bool isSolidTile(int worldX, int worldY, const TileMap& map) {\n    int tileX = worldX / map.tileWidth;\n    int tileY = worldY / map.tileHeight;\n\n    if (tileX < 0 || tileX >= map.width || \n        tileY < 0 || tileY >= map.height) {\n        return true;  // Outside map = solid\n    }\n\n    int index = tileY * map.width + tileX;\n    uint8_t tileIndex = map.indices[index];\n\n    // Check if tile is solid (e.g., wall = index 1)\n    return (tileIndex == 1);\n}\n
"},{"location":"api_reference/graphics/tilemap/#usage-example","title":"Usage Example","text":"
#include \"graphics/TileMap.h\"\n#include \"graphics/Renderer.h\"\n\nclass LevelScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::TileMap levelMap;\n    pixelroot32::graphics::Camera2D camera;\n\npublic:\n    void init() override {\n        // Level map is already defined (see above)\n        // Create camera\n        auto& renderer = engine.getRenderer();\n        camera = pixelroot32::graphics::Camera2D(\n            renderer.getWidth(),\n            renderer.getHeight()\n        );\n\n        // Set level boundaries\n        int levelWidth = levelMap.width * levelMap.tileWidth;\n        int levelHeight = levelMap.height * levelMap.tileHeight;\n        camera.setBounds(0.0f, levelWidth - renderer.getWidth());\n        camera.setVerticalBounds(0.0f, levelHeight - renderer.getHeight());\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Camera follows player\n        if (player) {\n            camera.followTarget(player->x, player->y);\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw tilemap (viewport culling automatic)\n        renderer.drawTileMap(levelMap, 0, 0, Color::White);\n\n        // Draw entities\n        Scene::draw(renderer);\n\n        // Reset for UI\n        renderer.setDisplayOffset(0, 0);\n    }\n\n    bool checkTileCollision(float x, float y) {\n        int tileX = static_cast<int>(x) / levelMap.tileWidth;\n        int tileY = static_cast<int>(y) / levelMap.tileHeight;\n\n        if (tileX < 0 || tileX >= levelMap.width || \n            tileY < 0 || tileY >= levelMap.height) {\n            return true;  // Outside = solid\n        }\n\n        int index = tileY * levelMap.width + tileX;\n        uint8_t tile = levelMap.indices[index];\n        return (tile == 1);  // Wall tile\n    }\n};\n
"},{"location":"api_reference/graphics/tilemap/#performance-considerations","title":"Performance Considerations","text":"
  • Viewport culling: Only visible tiles are drawn (automatic)
  • Tile reuse: Reuse tile sprites across the map
  • Index storage: Compact uint8_t indices (1 byte per tile)
  • Memory: Store indices and tiles in flash (const) for best performance
  • Tile size: Smaller tiles = more tiles to draw, but more detail
"},{"location":"api_reference/graphics/tilemap/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store tilemap data in flash, not RAM
  • Map size: Large maps use more flash memory
  • Tile count: Limit unique tiles to save memory
  • Culling: Viewport culling is essential for large levels
"},{"location":"api_reference/graphics/tilemap/#see-also","title":"See Also","text":"
  • Renderer - Rendering system that draws tilemaps
  • Sprite - Sprite structure used for tiles
  • Camera2D - Camera for scrolling tilemaps
  • Manual - Tilemaps
  • API Overview
"},{"location":"api_reference/physics/collision_system/","title":"CollisionSystem","text":"

Manages collision detection between entities.

"},{"location":"api_reference/physics/collision_system/#description","title":"Description","text":"

CollisionSystem iterates through registered entities, checks if they are Actors, and performs AABB (Axis-Aligned Bounding Box) collision checks based on their collision layers and masks.

The system automatically filters collisions using layers and masks, avoiding unnecessary checks. When a collision is detected, it triggers the onCollision() callback on both actors.

"},{"location":"api_reference/physics/collision_system/#namespace","title":"Namespace","text":"
namespace pixelroot32::physics {\n    class CollisionSystem {\n        // ...\n    };\n}\n
"},{"location":"api_reference/physics/collision_system/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Scene (manages collision system instance)
"},{"location":"api_reference/physics/collision_system/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/physics/collision_system/#void-addentityentity-e","title":"void addEntity(Entity* e)","text":"

Adds an entity to the collision system.

Parameters: - e (pixelroot32::core::Entity*): Pointer to the entity to add

Returns: - void

Notes: - Only Actor entities participate in collisions - Entities are automatically added when added to Scene - Typically not called directly (handled by Scene)

Example:

// Typically handled automatically by Scene\nscene->addEntity(actor);  // Automatically added to collision system\n

"},{"location":"api_reference/physics/collision_system/#void-removeentityentity-e","title":"void removeEntity(Entity* e)","text":"

Removes an entity from the collision system.

Parameters: - e (pixelroot32::core::Entity*): Pointer to the entity to remove

Returns: - void

Notes: - Entities are automatically removed when removed from Scene - Typically not called directly

Example:

// Typically handled automatically by Scene\nscene->removeEntity(actor);  // Automatically removed from collision system\n

"},{"location":"api_reference/physics/collision_system/#void-update","title":"void update()","text":"

Performs collision detection for all registered entities.

Returns: - void

Notes: - Called automatically by Scene::update() - Iterates through all pairs of entities - Only checks collisions between Actors with matching layers/masks - Triggers onCollision() callbacks when collisions are detected - Uses AABB (Axis-Aligned Bounding Box) collision detection

Example:

// Called automatically by Scene, but can be called manually:\nvoid update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);  // Calls collisionSystem.update()\n\n    // Or manually:\n    collisionSystem.update();\n}\n

"},{"location":"api_reference/physics/collision_system/#how-it-works","title":"How It Works","text":"
  1. Entity Registration: Entities added to Scene are automatically registered
  2. Layer Filtering: Only actors with matching layers/masks are checked
  3. AABB Check: Uses Rect::intersects() for collision detection
  4. Callback: Calls onCollision() on both actors when collision detected
"},{"location":"api_reference/physics/collision_system/#collision-detection-algorithm","title":"Collision Detection Algorithm","text":"
for each actor1 in entities:\n    if actor1 is not an Actor: continue\n    for each actor2 in entities:\n        if actor2 is not an Actor: continue\n        if actor1 == actor2: continue\n\n        // Check layers/masks\n        if (actor1->layer & actor2->mask) == 0: continue\n        if (actor2->layer & actor1->mask) == 0: continue\n\n        // Check AABB intersection\n        Rect box1 = actor1->getHitBox();\n        Rect box2 = actor2->getHitBox();\n\n        if (box1.intersects(box2)) {\n            actor1->onCollision(actor2);\n            actor2->onCollision(actor1);\n        }\n
"},{"location":"api_reference/physics/collision_system/#usage-example","title":"Usage Example","text":"
#include \"physics/CollisionSystem.h\"\n#include \"core/Actor.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Create actors with collision layers\n        PlayerActor* player = new PlayerActor(64, 64);\n        player->layer = pixelroot32::physics::DefaultLayers::kPlayer;\n        player->mask = pixelroot32::physics::DefaultLayers::kEnemy | \n                       pixelroot32::physics::DefaultLayers::kObstacle;\n        addEntity(player);\n\n        EnemyActor* enemy = new EnemyActor(100, 100);\n        enemy->layer = pixelroot32::physics::DefaultLayers::kEnemy;\n        enemy->mask = pixelroot32::physics::DefaultLayers::kPlayer;\n        addEntity(enemy);\n\n        // Collision system is managed by Scene\n        // Collisions are checked automatically in Scene::update()\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Collision detection happens here automatically\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"api_reference/physics/collision_system/#performance-considerations","title":"Performance Considerations","text":"
  • Layer filtering: Very efficient; avoids most collision checks
  • AABB checks: Fast (simple rectangle intersection)
  • Pair checking: O(n\u00b2) complexity, but n is limited (MAX_ENTITIES = 32)
  • Update frequency: Called every frame; keep hitboxes simple
"},{"location":"api_reference/physics/collision_system/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Entity limit: MAX_ENTITIES = 32 limits collision pairs
  • Layer efficiency: Use layers effectively to minimize checks
  • Hitbox simplicity: Keep hitboxes as simple AABB for best performance
"},{"location":"api_reference/physics/collision_system/#see-also","title":"See Also","text":"
  • Actor - Actors that participate in collisions
  • CollisionTypes - Collision primitives and layers
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/physics/collision_types/","title":"Collision Types","text":"

Basic geometric types and collision layer definitions.

"},{"location":"api_reference/physics/collision_types/#description","title":"Description","text":"

This document describes the collision primitives (Rect, Circle, Segment) and collision layer system used by the collision detection system.

"},{"location":"api_reference/physics/collision_types/#namespace","title":"Namespace","text":"
namespace pixelroot32::physics {\n    // Types and functions\n}\n
"},{"location":"api_reference/physics/collision_types/#collisionlayer-type","title":"CollisionLayer Type","text":"

Collision layer type (bit flags).

Type: uint16_t (typedef)

Notes: - Uses bit flags for layer assignment - Actors can be on multiple layers (bitwise OR) - Masks define which layers an actor can collide with

"},{"location":"api_reference/physics/collision_types/#defaultlayers-namespace","title":"DefaultLayers Namespace","text":"

Predefined collision layers.

"},{"location":"api_reference/physics/collision_types/#knone","title":"kNone","text":"

No layer (0).

Value: 0

Usage:

actor->layer = pixelroot32::physics::DefaultLayers::kNone;\n

"},{"location":"api_reference/physics/collision_types/#kall","title":"kAll","text":"

All layers (0xFFFF).

Value: 0xFFFF

Usage:

actor->mask = pixelroot32::physics::DefaultLayers::kAll;  // Collide with everything\n

"},{"location":"api_reference/physics/collision_types/#custom-layers","title":"Custom Layers","text":"

Define custom layers using bit flags:

namespace MyLayers {\n    const pixelroot32::physics::CollisionLayer kPlayer = 1 << 0;      // Bit 0\n    const pixelroot32::physics::CollisionLayer kEnemy = 1 << 1;       // Bit 1\n    const pixelroot32::physics::CollisionLayer kObstacle = 1 << 2;    // Bit 2\n    const pixelroot32::physics::CollisionLayer kProjectile = 1 << 3;  // Bit 3\n    const pixelroot32::physics::CollisionLayer kCollectible = 1 << 4;  // Bit 4\n}\n\n// Usage\nactor->layer = MyLayers::kPlayer;\nactor->mask = MyLayers::kEnemy | MyLayers::kObstacle;\n
"},{"location":"api_reference/physics/collision_types/#circle-structure","title":"Circle Structure","text":"

Represents a circle for collision detection.

Members: - float x: Center X coordinate - float y: Center Y coordinate - float radius: Radius of the circle

Example:

pixelroot32::physics::Circle circle;\ncircle.x = 100.0f;\ncircle.y = 100.0f;\ncircle.radius = 10.0f;\n

"},{"location":"api_reference/physics/collision_types/#segment-structure","title":"Segment Structure","text":"

Represents a line segment for collision detection.

Members: - float x1, y1: Start point coordinates - float x2, y2: End point coordinates

Example:

pixelroot32::physics::Segment segment;\nsegment.x1 = 0.0f;\nsegment.y1 = 0.0f;\nsegment.x2 = 100.0f;\nsegment.y2 = 100.0f;\n

"},{"location":"api_reference/physics/collision_types/#intersection-functions","title":"Intersection Functions","text":""},{"location":"api_reference/physics/collision_types/#bool-intersectsconst-circle-a-const-circle-b","title":"bool intersects(const Circle& a, const Circle& b)","text":"

Checks if two circles intersect.

Parameters: - a (const Circle&): First circle - b (const Circle&): Second circle

Returns: - bool: true if circles intersect

Example:

pixelroot32::physics::Circle circle1{100.0f, 100.0f, 10.0f};\npixelroot32::physics::Circle circle2{110.0f, 100.0f, 10.0f};\n\nif (pixelroot32::physics::intersects(circle1, circle2)) {\n    // Circles overlap\n}\n

"},{"location":"api_reference/physics/collision_types/#bool-intersectsconst-circle-c-const-rect-r","title":"bool intersects(const Circle& c, const Rect& r)","text":"

Checks if a circle and rectangle intersect.

Parameters: - c (const Circle&): Circle - r (const Rect&): Rectangle

Returns: - bool: true if circle and rectangle intersect

Example:

pixelroot32::physics::Circle circle{100.0f, 100.0f, 10.0f};\npixelroot32::core::Rect rect{95.0f, 95.0f, 20, 20};\n\nif (pixelroot32::physics::intersects(circle, rect)) {\n    // Circle overlaps rectangle\n}\n

"},{"location":"api_reference/physics/collision_types/#bool-intersectsconst-segment-s-const-rect-r","title":"bool intersects(const Segment& s, const Rect& r)","text":"

Checks if a line segment and rectangle intersect.

Parameters: - s (const Segment&): Line segment - r (const Rect&): Rectangle

Returns: - bool: true if segment and rectangle intersect

Example:

pixelroot32::physics::Segment segment{0.0f, 0.0f, 100.0f, 100.0f};\npixelroot32::core::Rect rect{50.0f, 50.0f, 20, 20};\n\nif (pixelroot32::physics::intersects(segment, rect)) {\n    // Segment intersects rectangle\n}\n

"},{"location":"api_reference/physics/collision_types/#bool-sweepcirclevsrectconst-circle-start-const-circle-end-const-rect-target-float-thit","title":"bool sweepCircleVsRect(const Circle& start, const Circle& end, const Rect& target, float& tHit)","text":"

Performs a sweep test: checks if a moving circle collides with a rectangle.

Parameters: - start (const Circle&): Circle at start position - end (const Circle&): Circle at end position - target (const Rect&): Target rectangle - tHit (float&): Output parameter for collision time (0.0 to 1.0)

Returns: - bool: true if collision occurs during sweep

Notes: - Useful for fast-moving projectiles - tHit indicates when collision occurs (0.0 = start, 1.0 = end) - More expensive than simple AABB check

Example:

// Projectile moving from (0, 0) to (100, 100)\npixelroot32::physics::Circle start{0.0f, 0.0f, 5.0f};\npixelroot32::physics::Circle end{100.0f, 100.0f, 5.0f};\npixelroot32::core::Rect wall{50.0f, 50.0f, 20, 20};\n\nfloat tHit = 0.0f;\nif (pixelroot32::physics::sweepCircleVsRect(start, end, wall, tHit)) {\n    // Collision at time tHit\n    float hitX = 0.0f + (100.0f - 0.0f) * tHit;\n    float hitY = 0.0f + (100.0f - 0.0f) * tHit;\n}\n

"},{"location":"api_reference/physics/collision_types/#rect-structure-from-coreentityh","title":"Rect Structure (from core/Entity.h)","text":"

Represents a 2D rectangle for collision detection.

Members: - float x, y: Top-left corner coordinates - int width, height: Dimensions

Methods: - bool intersects(const Rect& other) const: Checks if rectangles overlap

Example:

pixelroot32::core::Rect rect1{10.0f, 20.0f, 50, 50};\npixelroot32::core::Rect rect2{30.0f, 40.0f, 50, 50};\n\nif (rect1.intersects(rect2)) {\n    // Rectangles overlap\n}\n

"},{"location":"api_reference/physics/collision_types/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/physics/collision_types/#layer-based-collision","title":"Layer-Based Collision","text":"
// Define layers\nnamespace GameLayers {\n    const pixelroot32::physics::CollisionLayer kPlayer = 1 << 0;\n    const pixelroot32::physics::CollisionLayer kEnemy = 1 << 1;\n    const pixelroot32::physics::CollisionLayer kObstacle = 1 << 2;\n    const pixelroot32::physics::CollisionLayer kProjectile = 1 << 3;\n}\n\n// Player collides with enemies and obstacles\nplayer->layer = GameLayers::kPlayer;\nplayer->mask = GameLayers::kEnemy | GameLayers::kObstacle;\n\n// Enemy collides with player and obstacles\nenemy->layer = GameLayers::kEnemy;\nenemy->mask = GameLayers::kPlayer | GameLayers::kObstacle;\n\n// Projectile collides with enemies only\nprojectile->layer = GameLayers::kProjectile;\nprojectile->mask = GameLayers::kEnemy;\n
"},{"location":"api_reference/physics/collision_types/#circle-vs-circle-collision","title":"Circle vs Circle Collision","text":"
bool checkCollision(const Circle& a, const Circle& b) {\n    return pixelroot32::physics::intersects(a, b);\n}\n
"},{"location":"api_reference/physics/collision_types/#sweep-test-for-fast-projectiles","title":"Sweep Test for Fast Projectiles","text":"
class ProjectileActor : public pixelroot32::core::Actor {\nprivate:\n    float startX, startY;\n    float endX, endY;\n    float radius = 2.0f;\n\npublic:\n    bool checkWallCollision(const Rect& wall) {\n        pixelroot32::physics::Circle start{startX, startY, radius};\n        pixelroot32::physics::Circle end{endX, endY, radius};\n\n        float tHit = 0.0f;\n        if (pixelroot32::physics::sweepCircleVsRect(start, end, wall, tHit)) {\n            // Collision detected at time tHit\n            return true;\n        }\n        return false;\n    }\n};\n
"},{"location":"api_reference/physics/collision_types/#performance-considerations","title":"Performance Considerations","text":"
  • AABB checks: Very fast (simple rectangle intersection)
  • Circle checks: Slightly slower (distance calculation)
  • Sweep tests: More expensive (use only for fast-moving objects)
  • Layer filtering: Essential for performance with many actors
"},{"location":"api_reference/physics/collision_types/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Float math: Uses floating point; acceptable but integer math would be faster
  • Sweep tests: Use sparingly (more CPU intensive)
  • Layer efficiency: Use layers effectively to minimize checks
"},{"location":"api_reference/physics/collision_types/#see-also","title":"See Also","text":"
  • CollisionSystem - Collision detection system
  • Actor - Actors that use collision layers
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/ui/ui_button/","title":"UIButton","text":"

A clickable button UI element.

"},{"location":"api_reference/ui/ui_button/#description","title":"Description","text":"

UIButton is a clickable button that supports both physical (keyboard/gamepad) and touch input. It can trigger a callback function when pressed and integrates with UI layouts for automatic navigation.

Buttons support selection state (for D-pad navigation), custom styling, and text alignment.

"},{"location":"api_reference/ui/ui_button/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIButton : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_button/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom button classes (if needed)
"},{"location":"api_reference/ui/ui_button/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_button/#uibuttonstring-t-uint8_t-index-float-x-float-y-float-w-float-h-function-callback-textalignment-textalign-center-int-fontsize-2","title":"UIButton(string t, uint8_t index, float x, float y, float w, float h, function callback, TextAlignment textAlign = CENTER, int fontSize = 2)

Constructs a new UIButton.

Parameters: - t (std::string): Button label text - index (uint8_t): Navigation index (for D-pad navigation in layouts) - x (float): X position - y (float): Y position - w (float): Width - h (float): Height - callback (std::function): Function to call when clicked/pressed - textAlign (TextAlignment, optional): Text alignment. Default: CENTER - fontSize (int, optional): Text size multiplier. Default: 2

Example:

#include \"graphics/ui/UIButton.h\"\n\nvoid onStartButtonClicked() {\n    // Start game\n    engine.setScene(&gameScene);\n}\n\nvoid onQuitButtonClicked() {\n    // Quit game\n    engine.stop();\n}\n\n// Create buttons\npixelroot32::graphics::ui::UIButton* startButton = new pixelroot32::graphics::ui::UIButton(\n    \"Start\",\n    0,  // index\n    64.0f, 64.0f,  // position\n    100.0f, 30.0f, // size\n    onStartButtonClicked,\n    pixelroot32::graphics::ui::TextAlignment::CENTER,\n    2\n);\n\npixelroot32::graphics::ui::UIButton* quitButton = new pixelroot32::graphics::ui::UIButton(\n    \"Quit\",\n    1,  // index\n    64.0f, 100.0f,\n    100.0f, 30.0f,\n    onQuitButtonClicked\n);\n

","text":""},{"location":"api_reference/ui/ui_button/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_button/#void-setstylecolor-textcol-color-bgcol-bool-drawbg","title":"void setStyle(Color textCol, Color bgCol, bool drawBg)

Configures the button's visual style.

Parameters: - textCol (Color): Color of the text - bgCol (Color): Color of the background - drawBg (bool): Whether to draw the background rectangle

Returns: - void

Example:

button->setStyle(\n    pixelroot32::graphics::Color::White,  // Text color\n    pixelroot32::graphics::Color::Blue,   // Background color\n    true                                   // Draw background\n);\n

","text":""},{"location":"api_reference/ui/ui_button/#void-setselectedbool-selected","title":"void setSelected(bool selected)

Sets the selection state (e.g., focused via D-pad).

Parameters: - selected (bool): true if selected

Returns: - void

Notes: - Used by layouts for D-pad navigation - Selected buttons typically have different visual style - Can be set manually or automatically by layouts

Example:

button->setSelected(true);  // Highlight button\n

","text":""},{"location":"api_reference/ui/ui_button/#bool-getselected-const","title":"bool getSelected() const

Checks if the button is currently selected.

Returns: - bool: true if selected

Example:

if (button->getSelected()) {\n    // Button is focused\n}\n

","text":""},{"location":"api_reference/ui/ui_button/#bool-isfocusable-const-override","title":"bool isFocusable() const override

Returns true (Buttons are always focusable).

Returns: - bool: Always true

","text":""},{"location":"api_reference/ui/ui_button/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)

Handles input events. Checks for touch events within bounds or confirmation buttons if selected.

Parameters: - input (const pixelroot32::input::InputManager&): The input manager instance

Returns: - void

Notes: - Should be called every frame in update() - Checks if button is selected and action button is pressed - Triggers callback if conditions are met

Example:

void update(unsigned long deltaTime) override {\n    UIElement::update(deltaTime);\n\n    auto& input = engine.getInputManager();\n    button->handleInput(input);\n}\n

","text":""},{"location":"api_reference/ui/ui_button/#void-press","title":"void press()

Manually triggers the button's action.

Returns: - void

Notes: - Calls the button's callback function - Useful for programmatic button presses

Example:

button->press();  // Trigger button action\n

","text":""},{"location":"api_reference/ui/ui_button/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override

Updates the button state.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Handles input and updates button state - Override to add custom update logic

Example:

void update(unsigned long deltaTime) override {\n    UIButton::update(deltaTime);\n\n    // Custom update logic\n    if (shouldPulse) {\n        // Animate button\n    }\n}\n

","text":""},{"location":"api_reference/ui/ui_button/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override

Renders the button.

Parameters: - renderer (pixelroot32::graphics::Renderer&): The renderer to use

Returns: - void

Notes: - Called automatically by Scene if isVisible is true - Draws background (if enabled) and text - Selected state may change appearance

Example:

// Drawing is handled automatically\n// Override only for custom rendering\n

","text":""},{"location":"api_reference/ui/ui_button/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIButton.h\"\n#include \"core/Scene.h\"\n\nclass MainMenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIButton* startButton;\n    pixelroot32::graphics::ui::UIButton* quitButton;\n\npublic:\n    void init() override {\n        // Start button\n        startButton = new pixelroot32::graphics::ui::UIButton(\n            \"Start Game\",\n            0,  // index\n            64.0f, 50.0f,  // position (centered)\n            120.0f, 30.0f, // size\n            [this]() {\n                // Lambda callback\n                engine.setScene(&gameScene);\n            },\n            pixelroot32::graphics::ui::TextAlignment::CENTER,\n            2\n        );\n        startButton->setStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Blue,\n            true\n        );\n        addEntity(startButton);\n\n        // Quit button\n        quitButton = new pixelroot32::graphics::ui::UIButton(\n            \"Quit\",\n            1,  // index\n            64.0f, 90.0f,\n            120.0f, 30.0f,\n            [this]() {\n                // Quit game\n                engine.stop();\n            }\n        );\n        quitButton->setStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Red,\n            true\n        );\n        addEntity(quitButton);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Buttons handle input automatically\n        // Layouts handle navigation automatically\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background\n        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n\n        // Draw UI elements (buttons)\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"api_reference/ui/ui_button/#button-navigation","title":"Button Navigation","text":"

Buttons can be navigated with D-pad when in layouts:

// Buttons in a vertical layout\npixelroot32::graphics::ui::UIVerticalLayout* layout = new UIVerticalLayout(64.0f, 50.0f);\nlayout->addChild(startButton);  // Index 0\nlayout->addChild(quitButton);   // Index 1\n\n// D-pad navigation is automatic\n// UP/DOWN moves selection\n// Action button (A) triggers selected button\n
"},{"location":"api_reference/ui/ui_button/#performance-considerations","title":"Performance Considerations","text":"
  • Input handling: handleInput() is fast; safe to call every frame
  • Rendering: Simple rectangle and text; very efficient
  • Memory: Each button consumes memory (stay within MAX_ENTITIES)
"},{"location":"api_reference/ui/ui_button/#esp32-considerations","title":"ESP32 Considerations","text":"
  • String storage: Button labels use std::string; consider memory usage
  • Callback functions: Use function pointers or lambdas (both efficient)
"},{"location":"api_reference/ui/ui_button/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UILabel - Text label
  • UILayouts - Layout containers
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_checkbox/","title":"UICheckBox","text":"

A clickable checkbox UI element.

"},{"location":"api_reference/ui/ui_checkbox/#description","title":"Description","text":"

UICheckBox is a clickable checkbox that can be toggled between checked and unchecked states. It supports both physical (keyboard/gamepad) and touch input. It can trigger a callback function when its state changes and integrates with UI layouts for automatic navigation.

"},{"location":"api_reference/ui/ui_checkbox/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UICheckBox : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_checkbox/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
"},{"location":"api_reference/ui/ui_checkbox/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_checkbox/#uicheckboxstring-label-uint8_t-index-float-x-float-y-float-w-float-h-bool-checked-false-function-callback-nullptr-int-fontsize-2","title":"UICheckBox(string label, uint8_t index, float x, float y, float w, float h, bool checked = false, function callback = nullptr, int fontSize = 2)

Constructs a new UICheckBox.

Parameters: - label (std::string): Checkbox label text - index (uint8_t): Navigation index (for D-pad navigation in layouts) - x (float): X position - y (float): Y position - w (float): Width - h (float): Height - checked (bool, optional): Initial checked state. Default: false - callback (std::function, optional): Function to call when the state changes. Default: nullptr - fontSize (int, optional): Text size multiplier. Default: 2

Example:

#include \"graphics/ui/UICheckBox.h\"\n\nvoid onCheckChanged(bool checked) {\n    if (checked) {\n        // Sound enabled\n    } else {\n        // Sound disabled\n    }\n}\n\n// Create checkbox\npixelroot32::graphics::ui::UICheckBox* soundCheckbox = new pixelroot32::graphics::ui::UICheckBox(\n    \"Enable Sound\",\n    0,  // index\n    64.0f, 64.0f,  // position\n    120.0f, 20.0f, // size\n    true,          // initial state\n    onCheckChanged,\n    1              // font size\n);\n

","text":""},{"location":"api_reference/ui/ui_checkbox/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_checkbox/#void-setstylecolor-textcol-color-bgcol-bool-drawbg-false","title":"void setStyle(Color textCol, Color bgCol, bool drawBg = false)

Configures the checkbox's visual style.

Parameters: - textCol (Color): Color of the text - bgCol (Color): Color of the background - drawBg (bool, optional): Whether to draw the background rectangle. Default: false

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#void-setcheckedbool-checked","title":"void setChecked(bool checked)

Sets the checked state.

Parameters: - checked (bool): True if checked

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#bool-ischecked-const","title":"bool isChecked() const

Checks if the checkbox is currently checked.

Returns: - bool: true if checked

","text":""},{"location":"api_reference/ui/ui_checkbox/#void-toggle","title":"void toggle()

Toggles the checkbox state and triggers the callback.

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#void-setselectedbool-selected","title":"void setSelected(bool selected)

Sets the selection state (e.g., focused via D-pad).

Parameters: - selected (bool): True if selected

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#bool-getselected-const","title":"bool getSelected() const

Checks if the checkbox is currently selected.

Returns: - bool: true if selected

","text":""},{"location":"api_reference/ui/ui_checkbox/#callbacks","title":"Callbacks","text":""},{"location":"api_reference/ui/ui_checkbox/#oncheckchanged","title":"onCheckChanged

The onCheckChanged callback is a std::function<void(bool)> that is triggered whenever the checkbox state changes via setChecked() or toggle().

checkbox->onCheckChanged = [](bool isChecked) {\n    Serial.println(isChecked ? \"Checked!\" : \"Unchecked!\");\n};\n
","text":""},{"location":"api_reference/ui/ui_checkbox/#navigation-layouts","title":"Navigation & Layouts","text":"

UICheckBox is designed to work seamlessly with UILayout containers (like UIVerticalLayout).

  • Focusable: Returns true for isFocusable(), allowing it to receive focus in a layout.
  • Input Handling: When selected (focused), it listens for the button index provided in the constructor (typically the 'A' button) to toggle its state.
  • Visual Feedback: When selected, it displays a selection indicator (usually a > character) if no background is drawn, or highlights its text/border.
"},{"location":"api_reference/ui/ui_element/","title":"UIElement","text":"

Base class for all user interface elements.

"},{"location":"api_reference/ui/ui_element/#description","title":"Description","text":"

UIElement is the base class for all UI components (buttons, labels, panels, etc.). It inherits from Entity to integrate with the scene graph and automatically sets the entity type to UI_ELEMENT and render layer to 2 (UI layer).

"},{"location":"api_reference/ui/ui_element/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    enum class UIElementType {\n        GENERIC,\n        BUTTON,\n        LABEL,\n        CHECKBOX,\n        LAYOUT\n    };\n\n    class UIElement : public pixelroot32::core::Entity {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_element/#inheritance","title":"Inheritance","text":"
  • Inherits from: pixelroot32::core::Entity
  • Inherited by: UIButton, UICheckBox, UILabel, UIPanel, and all UI layouts
"},{"location":"api_reference/ui/ui_element/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_element/#uielementfloat-x-float-y-float-w-float-h-uielementtype-type-uielementtypegeneric","title":"UIElement(float x, float y, float w, float h, UIElementType type = UIElementType::GENERIC)","text":"

Constructs a new UIElement.

Parameters: - x (float): X position - y (float): Y position - w (float): Width - h (float): Height - type (UIElementType): The type of the element (default: GENERIC)

Notes: - Entity type is automatically set to UI_ELEMENT - Render layer is automatically set to 2 (UI layer) - Position and size can be modified after construction

Example:

class MyUIElement : public pixelroot32::graphics::ui::UIElement {\npublic:\n    MyUIElement(float x, float y) \n        : UIElement(x, y, 100.0f, 50.0f) {}\n\n    void update(unsigned long deltaTime) override {\n        // UI logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // UI rendering\n    }\n};\n

"},{"location":"api_reference/ui/ui_element/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_element/#uielementtype-gettype-const","title":"UIElementType getType() const","text":"

Returns the type of the UI element.

Returns: - UIElementType: The type enum value (GENERIC, BUTTON, LABEL, CHECKBOX, or LAYOUT)

"},{"location":"api_reference/ui/ui_element/#virtual-bool-isfocusable-const","title":"virtual bool isFocusable() const","text":"

Checks if the element is focusable/selectable. Useful for navigation logic.

Returns: - bool: true if focusable, false otherwise (default: false)

"},{"location":"api_reference/ui/ui_element/#void-setpositionfloat-newx-float-newy","title":"void setPosition(float newX, float newY)","text":"

Sets the position of the element.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Updates element position immediately - Use for manual positioning or animations

Example:

uiElement->setPosition(100.0f, 50.0f);\n

"},{"location":"api_reference/ui/ui_element/#virtual-void-getpreferredsizefloat-preferredwidth-float-preferredheight-const","title":"virtual void getPreferredSize(float& preferredWidth, float& preferredHeight) const","text":"

Gets the preferred size of the element. Used by layouts to determine how much space the element needs.

Parameters: - preferredWidth (float&): Output parameter for preferred width (or -1 if flexible) - preferredHeight (float&): Output parameter for preferred height (or -1 if flexible)

Returns: - void

Notes: - Default implementation returns current width/height - Override in derived classes for custom sizing logic - Layouts use this to arrange elements

Example:

void getPreferredSize(float& w, float& h) const override {\n    // Custom sizing logic\n    w = static_cast<float>(width);\n    h = static_cast<float>(height);\n}\n

"},{"location":"api_reference/ui/ui_element/#inherited-from-entity","title":"Inherited from Entity","text":"

UIElement inherits all properties and methods from Entity:

  • float x, y: Position
  • int width, height: Dimensions
  • bool isVisible: Visibility state
  • bool isEnabled: Enabled state
  • unsigned char renderLayer: Render layer (automatically set to 2)
  • void setVisible(bool v): Set visibility
  • void setEnabled(bool e): Set enabled state
  • virtual void update(unsigned long deltaTime): Update logic
  • virtual void draw(Renderer& renderer): Drawing logic
"},{"location":"api_reference/ui/ui_element/#textalignment-enum","title":"TextAlignment Enum","text":"

Text alignment options for UI elements.

Values: - TextAlignment::LEFT: Left-aligned text - TextAlignment::CENTER: Center-aligned text - TextAlignment::RIGHT: Right-aligned text

"},{"location":"api_reference/ui/ui_element/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIElement.h\"\n\nclass CustomUIElement : public pixelroot32::graphics::ui::UIElement {\nprivate:\n    pixelroot32::graphics::Color bgColor;\n\npublic:\n    CustomUIElement(float x, float y, float w, float h) \n        : UIElement(x, y, w, h),\n          bgColor(pixelroot32::graphics::Color::Blue) {}\n\n    void update(unsigned long deltaTime) override {\n        // Update logic (if needed)\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        if (isVisible) {\n            // Draw background\n            renderer.drawFilledRectangle(\n                static_cast<int>(x),\n                static_cast<int>(y),\n                width,\n                height,\n                bgColor\n            );\n\n            // Draw border\n            renderer.drawRectangle(\n                static_cast<int>(x),\n                static_cast<int>(y),\n                width,\n                height,\n                pixelroot32::graphics::Color::White\n            );\n        }\n    }\n\n    void getPreferredSize(float& w, float& h) const override {\n        w = static_cast<float>(width);\n        h = static_cast<float>(height);\n    }\n};\n
"},{"location":"api_reference/ui/ui_element/#performance-considerations","title":"Performance Considerations","text":"
  • Render layer: UI elements are on layer 2, drawn after gameplay
  • Visibility: Use isVisible = false to hide elements efficiently
  • Layout integration: Layouts automatically manage element positioning
"},{"location":"api_reference/ui/ui_element/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Each UI element consumes memory (stay within MAX_ENTITIES)
  • Object pooling: Reuse UI elements when possible
  • Update frequency: Disable UI elements that don't need to update
"},{"location":"api_reference/ui/ui_element/#see-also","title":"See Also","text":"
  • Entity - Base entity class
  • UIButton - Clickable button
  • UILabel - Text label
  • UILayout - Layout containers
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_label/","title":"UILabel","text":"

A simple text label UI element.

"},{"location":"api_reference/ui/ui_label/#description","title":"Description","text":"

UILabel displays a string of text on the screen. It auto-calculates its bounds based on text length and font size, making it easy to create dynamic text displays.

Labels are useful for displaying scores, status messages, menu text, and other UI information.

"},{"location":"api_reference/ui/ui_label/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UILabel : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_label/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom label classes (if needed)
"},{"location":"api_reference/ui/ui_label/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_label/#uilabelstring-t-float-x-float-y-color-col-uint8_t-sz","title":"UILabel(string t, float x, float y, Color col, uint8_t sz)","text":"

Constructs a new UILabel.

Parameters: - t (std::string): Initial text - x (float): X position - y (float): Y position - col (Color): Text color - sz (uint8_t): Text size multiplier

Example:

#include \"graphics/ui/UILabel.h\"\n\n// Create label\npixelroot32::graphics::ui::UILabel* scoreLabel = new pixelroot32::graphics::ui::UILabel(\n    \"Score: 0\",\n    10.0f, 10.0f,  // position\n    pixelroot32::graphics::Color::White,\n    1  // size\n);\n\n// Add to scene\nscene->addEntity(scoreLabel);\n

"},{"location":"api_reference/ui/ui_label/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_label/#void-settextconst-string-t","title":"void setText(const string& t)","text":"

Updates the label's text. Recalculates dimensions immediately using the active font metrics to ensure precise layout.

Parameters: - t (const std::string&): New text

Returns: - void

Notes: - Automatically recalculates width and height using FontManager::textWidth - Use for dynamic text (scores, timers, etc.) - Text is stored as std::string (consider memory on ESP32)

Example:

// Update score label\nchar scoreText[32];\nsnprintf(scoreText, sizeof(scoreText), \"Score: %d\", score);\nscoreLabel->setText(scoreText);\n

"},{"location":"api_reference/ui/ui_label/#void-setvisiblebool-v","title":"void setVisible(bool v)","text":"

Sets visibility.

Parameters: - v (bool): true to show, false to hide

Returns: - void

Notes: - Inherited from Entity - Hides label without removing from scene

Example:

label->setVisible(false);  // Hide\nlabel->setVisible(true);   // Show\n

"},{"location":"api_reference/ui/ui_label/#void-centerxint-screenwidth","title":"void centerX(int screenWidth)","text":"

Centers the label horizontally within a given width (typically the screen width). Recalculates dimensions before positioning to ensure perfect centering.

Parameters: - screenWidth (int): The width to center within (e.g., engine.getRenderer().getWidth())

Returns: - void

Example:

label->centerX(128); // Center on a 128px screen\n

"},{"location":"api_reference/ui/ui_label/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the label state.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Default implementation does nothing - Override to add custom update logic (animations, etc.)

Example:

void update(unsigned long deltaTime) override {\n    UILabel::update(deltaTime);\n\n    // Custom logic (e.g., update text based on game state)\n    if (scoreChanged) {\n        updateScoreText();\n    }\n}\n

"},{"location":"api_reference/ui/ui_label/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Renders the label.

Parameters: - renderer (pixelroot32::graphics::Renderer&): The renderer to use

Returns: - void

Notes: - Called automatically by Scene if isVisible is true - Draws text at label position - Uses default font

Example:

// Drawing is handled automatically\n// Override only for custom rendering\n

"},{"location":"api_reference/ui/ui_label/#auto-sizing","title":"Auto-Sizing","text":"

Labels automatically calculate their size based on text:

  • Width: text.length() * (6 * size) pixels
  • Height: 8 * size pixels

Example:

// Label with text \"Hello\" (5 characters), size 1\n// Width: 5 * 6 * 1 = 30 pixels\n// Height: 8 * 1 = 8 pixels\n\nUILabel label(\"Hello\", 10, 10, Color::White, 1);\n// label.width = 30, label.height = 8\n

"},{"location":"api_reference/ui/ui_label/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UILabel.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n    int score = 0;\n    int lives = 3;\n\npublic:\n    void init() override {\n        // Score label\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\",\n            10.0f, 10.0f,\n            pixelroot32::graphics::Color::White,\n            1\n        );\n        addEntity(scoreLabel);\n\n        // Lives label\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\",\n            10.0f, 25.0f,\n            pixelroot32::graphics::Color::Yellow,\n            1\n        );\n        addEntity(livesLabel);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Update labels\n        char text[32];\n        snprintf(text, sizeof(text), \"Score: %d\", score);\n        scoreLabel->setText(text);\n\n        snprintf(text, sizeof(text), \"Lives: %d\", lives);\n        livesLabel->setText(text);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw game\n        Scene::draw(renderer);\n\n        // Labels are drawn automatically by Scene::draw()\n    }\n};\n
"},{"location":"api_reference/ui/ui_label/#centered-labels","title":"Centered Labels","text":"
// Create centered title\npixelroot32::graphics::ui::UILabel* title = new pixelroot32::graphics::ui::UILabel(\n    \"Game Title\",\n    0, 20.0f,  // X will be adjusted\n    pixelroot32::graphics::Color::Yellow,\n    2  // Large text\n);\ntitle->centerX(128);  // Center on screen\naddEntity(title);\n
"},{"location":"api_reference/ui/ui_label/#performance-considerations","title":"Performance Considerations","text":"
  • Text updates: setText() recalculates size; avoid calling every frame if text doesn't change
  • String storage: Uses std::string; consider memory on ESP32
  • Rendering: Simple text drawing; very efficient
  • Static text: For static text, create once and don't update
"},{"location":"api_reference/ui/ui_label/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: std::string uses heap memory; use static buffers when possible
  • Text updates: Limit frequency of text updates
  • String length: Keep text short to save memory
"},{"location":"api_reference/ui/ui_label/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UIButton - Clickable button
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layout/","title":"UILayout","text":"

Base class for UI layout containers.

"},{"location":"api_reference/ui/ui_layout/#description","title":"Description","text":"

UILayout is the base class for all layout containers. Layouts organize UI elements automatically, handling positioning, spacing, and optional scrolling. Layouts are themselves UI elements that can be added to scenes.

"},{"location":"api_reference/ui/ui_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UILayout : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: UIVerticalLayout, UIHorizontalLayout, UIGridLayout, UIAnchorLayout
"},{"location":"api_reference/ui/ui_layout/#scrollbehavior-enum","title":"ScrollBehavior Enum","text":"

Defines how scrolling behaves in layouts.

Values: - ScrollBehavior::NONE: No scrolling allowed - ScrollBehavior::SCROLL: Scroll freely within bounds - ScrollBehavior::CLAMP: Scroll but clamp to content bounds

"},{"location":"api_reference/ui/ui_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layout/#virtual-void-addelementuielement-element-0","title":"virtual void addElement(UIElement* element) = 0","text":"

Adds a UI element to the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to add

"},{"location":"api_reference/ui/ui_layout/#virtual-void-removeelementuielement-element-0","title":"virtual void removeElement(UIElement* element) = 0","text":"

Removes a UI element from the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to remove

"},{"location":"api_reference/ui/ui_layout/#virtual-void-updatelayout-0","title":"virtual void updateLayout() = 0","text":"

Recalculates positions of all elements in the layout. Must be implemented by derived classes.

Returns: - void

Notes: - Should be called automatically when elements are added/removed

"},{"location":"api_reference/ui/ui_layout/#virtual-void-handleinputconst-inputmanager-input-0","title":"virtual void handleInput(const InputManager& input) = 0","text":"

Handles input for layout navigation (scroll, selection, etc.). Must be implemented by derived classes.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

"},{"location":"api_reference/ui/ui_layout/#void-setpaddingfloat-p","title":"void setPadding(float p)","text":"

Sets the padding (internal spacing) of the layout.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Layout is automatically recalculated

"},{"location":"api_reference/ui/ui_layout/#float-getpadding-const","title":"float getPadding() const","text":"

Gets the current padding.

Returns: - float: Padding value in pixels

"},{"location":"api_reference/ui/ui_layout/#void-setspacingfloat-s","title":"void setSpacing(float s)","text":"

Sets the spacing between elements.

Parameters: - s (float): Spacing value in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Default: 4.0 pixels

"},{"location":"api_reference/ui/ui_layout/#float-getspacing-const","title":"float getSpacing() const","text":"

Gets the current spacing.

Returns: - float: Spacing value in pixels

"},{"location":"api_reference/ui/ui_layout/#size_t-getelementcount-const","title":"size_t getElementCount() const","text":"

Gets the number of elements in the layout.

Returns: - size_t: Element count

"},{"location":"api_reference/ui/ui_layout/#uielement-getelementsize_t-index-const","title":"UIElement* getElement(size_t index) const","text":"

Gets the element at a specific index.

Parameters: - index (size_t): Element index

Returns: - UIElement*: Pointer to the element, or nullptr if index is invalid

"},{"location":"api_reference/ui/ui_layout/#void-clearelements","title":"void clearElements()","text":"

Clears all elements from the layout.

Returns: - void

Notes: - Elements are not deleted (you must manage their lifetimes) - Layout is automatically recalculated

"},{"location":"api_reference/ui/ui_layout/#protected-members","title":"Protected Members","text":"
  • std::vector<UIElement*> elements: List of child elements
  • float padding: Internal padding
  • float spacing: Spacing between elements (default: 4.0)
  • float scrollOffset: Current scroll offset
  • bool enableScroll: Whether scrolling is enabled
  • ScrollBehavior scrollBehavior: Scroll behavior mode
"},{"location":"api_reference/ui/ui_layout/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UIVerticalLayout - Vertical layout
  • UIHorizontalLayout - Horizontal layout
  • UIGridLayout - Grid layout
  • UIAnchorLayout - Anchor layout
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/","title":"UIAnchorLayout","text":"

Layout that positions elements at fixed anchor points on the screen.

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#description","title":"Description","text":"

UIAnchorLayout positions UI elements at fixed anchor points (corners, center, edges) without reflow. Very efficient for HUDs, debug UI, and fixed-position elements. Positions are calculated once or when screen size changes.

This layout is ideal for HUD elements like score, lives, health bars, and other fixed-position UI.

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIAnchorLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom anchor layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#anchor-enum","title":"Anchor Enum","text":"

Defines anchor points for positioning UI elements.

Values: - Anchor::TOP_LEFT: Top-left corner - Anchor::TOP_RIGHT: Top-right corner - Anchor::BOTTOM_LEFT: Bottom-left corner - Anchor::BOTTOM_RIGHT: Bottom-right corner - Anchor::CENTER: Center of screen - Anchor::TOP_CENTER: Top center - Anchor::BOTTOM_CENTER: Bottom center - Anchor::LEFT_CENTER: Left center - Anchor::RIGHT_CENTER: Right center

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/anchor_layout/#uianchorlayoutfloat-x-float-y-float-w-float-h","title":"UIAnchorLayout(float x, float y, float w, float h)","text":"

Constructs a new UIAnchorLayout.

Parameters: - x (float): X position of the layout container (usually 0) - y (float): Y position of the layout container (usually 0) - w (float): Width of the layout container (usually screen width) - h (float): Height of the layout container (usually screen height)

Example:

#include \"graphics/ui/UIAnchorLayout.h\"\n\n// Create full-screen anchor layout for HUD\nauto& renderer = engine.getRenderer();\npixelroot32::graphics::ui::UIAnchorLayout* hud = \n    new pixelroot32::graphics::ui::UIAnchorLayout(\n        0.0f, 0.0f,\n        static_cast<float>(renderer.getWidth()),\n        static_cast<float>(renderer.getHeight())\n    );\nhud->setScreenSize(\n    static_cast<float>(renderer.getWidth()),\n    static_cast<float>(renderer.getHeight())\n);\n

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-addelementuielement-element-anchor-anchor","title":"void addElement(UIElement* element, Anchor anchor)","text":"

Adds a UI element with a specific anchor point.

Parameters: - element (UIElement*): Pointer to the element to add - anchor (Anchor): Anchor point for positioning

Returns: - void

Example:

// Score label at top-right\nhud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\n// Lives label at top-left\nhud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout (defaults to TOP_LEFT anchor).

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements based on anchors.

Returns: - void

Notes: - Called automatically when screen size changes - Can be called manually if needed

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input (no-op for anchor layout, elements handle their own input).

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Anchor layout doesn't handle navigation - Elements handle their own input

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout and child elements.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws all elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-setscreensizefloat-screenwidth-float-screenheight","title":"void setScreenSize(float screenWidth, float screenHeight)","text":"

Sets the screen size for anchor calculations.

Parameters: - screenWidth (float): Screen width in pixels - screenHeight (float): Screen height in pixels

Returns: - void

Notes: - Used to calculate anchor positions - Should match actual display size - Layout is automatically recalculated

Example:

auto& renderer = engine.getRenderer();\nhud->setScreenSize(\n    static_cast<float>(renderer.getWidth()),\n    static_cast<float>(renderer.getHeight())\n);\n

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#float-getscreenwidth-const","title":"float getScreenWidth() const","text":"

Gets the screen width.

Returns: - float: Screen width in pixels

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#float-getscreenheight-const","title":"float getScreenHeight() const","text":"

Gets the screen height.

Returns: - float: Screen height in pixels

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIAnchorLayout.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIAnchorLayout* hud;\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n\npublic:\n    void init() override {\n        auto& renderer = engine.getRenderer();\n\n        // Create HUD layout\n        hud = new pixelroot32::graphics::ui::UIAnchorLayout(\n            0.0f, 0.0f,\n            static_cast<float>(renderer.getWidth()),\n            static_cast<float>(renderer.getHeight())\n        );\n        hud->setScreenSize(\n            static_cast<float>(renderer.getWidth()),\n            static_cast<float>(renderer.getHeight())\n        );\n\n        // Score label (top-right)\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\",\n            0, 0,\n            Color::White,\n            1\n        );\n        hud->addElement(scoreLabel, \n                        pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\n        // Lives label (top-left)\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\",\n            0, 0,\n            Color::Yellow,\n            1\n        );\n        hud->addElement(livesLabel, \n                        pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n\n        addEntity(hud);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Update labels\n        char text[32];\n        snprintf(text, sizeof(text), \"Score: %d\", score);\n        scoreLabel->setText(text);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw game\n        Scene::draw(renderer);\n\n        // HUD is drawn automatically (on layer 2)\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#anchor-positioning","title":"Anchor Positioning","text":"

Elements are positioned based on their anchor:

  • TOP_LEFT: Element's top-left at screen top-left
  • TOP_RIGHT: Element's top-right at screen top-right
  • BOTTOM_LEFT: Element's bottom-left at screen bottom-left
  • BOTTOM_RIGHT: Element's bottom-right at screen bottom-right
  • CENTER: Element centered on screen
  • TOP_CENTER: Element centered horizontally, top-aligned
  • BOTTOM_CENTER: Element centered horizontally, bottom-aligned
  • LEFT_CENTER: Element centered vertically, left-aligned
  • RIGHT_CENTER: Element centered vertically, right-aligned
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#performance-considerations","title":"Performance Considerations","text":"
  • No reflow: Very efficient (positions calculated once)
  • Fixed positions: Ideal for HUD elements
  • Viewport independent: Elements stay in fixed screen positions
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Very efficient (no complex calculations)
  • Update frequency: Positions only recalculate when screen size changes
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class
  • UILabel - Labels for HUD
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/grid_layout/","title":"UIGridLayout","text":"

Grid layout container for organizing elements in a matrix.

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#description","title":"Description","text":"

UIGridLayout organizes UI elements in a fixed grid of rows and columns. It supports navigation in 4 directions (UP/DOWN/LEFT/RIGHT) and automatic positioning based on grid coordinates.

This layout is ideal for inventories, level selection screens, galleries, and any grid-based UI arrangement.

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIGridLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/grid_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom grid layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/grid_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/grid_layout/#uigridlayoutfloat-x-float-y-float-w-float-h","title":"UIGridLayout(float x, float y, float w, float h)","text":"

Constructs a new UIGridLayout.

Parameters: - x (float): X position of the layout container - y (float): Y position of the layout container - w (float): Width of the layout container - h (float): Height of the layout container

Example:

#include \"graphics/ui/UIGridLayout.h\"\n\n// Create 4x4 grid for inventory\npixelroot32::graphics::ui::UIGridLayout* inventory = \n    new pixelroot32::graphics::ui::UIGridLayout(\n        10.0f, 10.0f,  // position\n        108.0f, 108.0f // size\n    );\ninventory->setColumns(4);\n

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout.

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

Notes: - Elements are arranged in grid order (left to right, top to bottom) - Layout is automatically recalculated - Cell size is calculated based on columns and layout size

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements.

Returns: - void

Notes: - Recalculates cell dimensions - Recalculates row count - Repositions all elements

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input for navigation and selection.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Handles UP/DOWN/LEFT/RIGHT navigation - Manages selection state - Wraps around grid edges (if configured)

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout and child elements.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the layout and its visible elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setcolumnsuint8_t-cols","title":"void setColumns(uint8_t cols)","text":"

Sets the number of columns in the grid.

Parameters: - cols (uint8_t): Number of columns (must be > 0)

Returns: - void

Notes: - Layout is automatically recalculated - Row count is calculated based on element count and columns

Example:

inventory->setColumns(4);  // 4 columns\n

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#uint8_t-getcolumns-const","title":"uint8_t getColumns() const","text":"

Gets the number of columns.

Returns: - uint8_t: Number of columns

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#uint8_t-getrows-const","title":"uint8_t getRows() const","text":"

Gets the number of rows (calculated).

Returns: - uint8_t: Number of rows

Notes: - Calculated as ceil(elementCount / columns)

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#int-getselectedindex-const","title":"int getSelectedIndex() const","text":"

Gets the currently selected element index.

Returns: - int: Selected index, or -1 if none selected

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setselectedindexint-index","title":"void setSelectedIndex(int index)","text":"

Sets the selected element index.

Parameters: - index (int): Index to select (-1 to deselect)

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#uielement-getselectedelement-const","title":"UIElement* getSelectedElement() const","text":"

Gets the selected element.

Returns: - UIElement*: Pointer to selected element, or nullptr if none selected

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setnavigationbuttonsuint8_t-upbutton-uint8_t-downbutton-uint8_t-leftbutton-uint8_t-rightbutton","title":"void setNavigationButtons(uint8_t upButton, uint8_t downButton, uint8_t leftButton, uint8_t rightButton)","text":"

Sets the navigation button indices.

Parameters: - upButton (uint8_t): Button index for UP navigation - downButton (uint8_t): Button index for DOWN navigation - leftButton (uint8_t): Button index for LEFT navigation - rightButton (uint8_t): Button index for RIGHT navigation

Returns: - void

Notes: - Default: UP=0, DOWN=1, LEFT=2, RIGHT=3 - Change if your input mapping differs

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setbuttonstylecolor-selectedtextcol-color-selectedbgcol-color-unselectedtextcol-color-unselectedbgcol","title":"void setButtonStyle(Color selectedTextCol, Color selectedBgCol, Color unselectedTextCol, Color unselectedBgCol)","text":"

Sets the style colors for selected and unselected buttons.

Parameters: - selectedTextCol (Color): Text color when selected - selectedBgCol (Color): Background color when selected - unselectedTextCol (Color): Text color when not selected - unselectedBgCol (Color): Background color when not selected

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIGridLayout.h\"\n\nclass InventoryScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIGridLayout* inventory;\n\npublic:\n    void init() override {\n        // Create 4x4 inventory grid\n        inventory = new pixelroot32::graphics::ui::UIGridLayout(\n            10.0f, 10.0f,\n            108.0f, 108.0f\n        );\n        inventory->setColumns(4);\n        inventory->setSpacing(2.0f);\n        inventory->setPadding(4.0f);\n\n        // Add inventory slots\n        for (int i = 0; i < 16; i++) {\n            auto* slot = createInventorySlot(i);\n            inventory->addElement(slot);\n        }\n\n        addEntity(inventory);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/grid_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class (abstract)
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/","title":"UIHorizontalLayout","text":"

Horizontal layout container with scroll support.

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#description","title":"Description","text":"

UIHorizontalLayout organizes UI elements horizontally, one next to another. It supports scrolling when content exceeds the visible viewport and handles keyboard/D-pad navigation automatically.

This layout is ideal for toolbars, tab bars, horizontal menus, and any horizontal arrangement of UI elements.

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIHorizontalLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom horizontal layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#uihorizontallayoutfloat-x-float-y-float-w-float-h","title":"UIHorizontalLayout(float x, float y, float w, float h)","text":"

Constructs a new UIHorizontalLayout.

Parameters: - x (float): X position of the layout container - y (float): Y position of the layout container - w (float): Width of the layout container (viewport width) - h (float): Height of the layout container

Example:

#include \"graphics/ui/UIHorizontalLayout.h\"\n\n// Create horizontal layout for toolbar\npixelroot32::graphics::ui::UIHorizontalLayout* toolbar = \n    new pixelroot32::graphics::ui::UIHorizontalLayout(\n        0.0f, 0.0f,   // position (top of screen)\n        128.0f, 20.0f // size\n    );\n

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout.

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

Notes: - Elements are arranged horizontally, left to right - Layout is automatically recalculated - Elements are positioned based on spacing and padding

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements.

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input for navigation and scrolling.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Handles LEFT/RIGHT navigation - Manages selection state - Handles scrolling if enabled

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout (handles smooth scrolling).

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the layout and its visible elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setscrollenabledbool-enable","title":"void setScrollEnabled(bool enable)","text":"

Enables or disables scrolling.

Parameters: - enable (bool): true to enable scrolling

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setviewportwidthfloat-w","title":"void setViewportWidth(float w)","text":"

Sets the viewport width (visible area).

Parameters: - w (float): Viewport width in pixels

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#float-getscrolloffset-const","title":"float getScrollOffset() const","text":"

Gets the current scroll offset.

Returns: - float: Scroll offset in pixels

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setscrolloffsetfloat-offset","title":"void setScrollOffset(float offset)","text":"

Sets the scroll offset directly.

Parameters: - offset (float): Scroll offset in pixels

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#float-getcontentwidth-const","title":"float getContentWidth() const","text":"

Gets the total content width.

Returns: - float: Content width in pixels

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#int-getselectedindex-const","title":"int getSelectedIndex() const","text":"

Gets the currently selected element index.

Returns: - int: Selected index, or -1 if none selected

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setselectedindexint-index","title":"void setSelectedIndex(int index)","text":"

Sets the selected element index.

Parameters: - index (int): Index to select (-1 to deselect)

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#uielement-getselectedelement-const","title":"UIElement* getSelectedElement() const","text":"

Gets the selected element.

Returns: - UIElement*: Pointer to selected element, or nullptr if none selected

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setscrollspeedfloat-speed","title":"void setScrollSpeed(float speed)","text":"

Sets the scroll speed for smooth scrolling.

Parameters: - speed (float): Pixels per millisecond

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setnavigationbuttonsuint8_t-leftbutton-uint8_t-rightbutton","title":"void setNavigationButtons(uint8_t leftButton, uint8_t rightButton)","text":"

Sets the navigation button indices.

Parameters: - leftButton (uint8_t): Button index for LEFT navigation - rightButton (uint8_t): Button index for RIGHT navigation

Returns: - void

Notes: - Default: LEFT = 2, RIGHT = 3 - Change if your input mapping differs

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setbuttonstylecolor-selectedtextcol-color-selectedbgcol-color-unselectedtextcol-color-unselectedbgcol","title":"void setButtonStyle(Color selectedTextCol, Color selectedBgCol, Color unselectedTextCol, Color unselectedBgCol)","text":"

Sets the style colors for selected and unselected buttons.

Parameters: - selectedTextCol (Color): Text color when selected - selectedBgCol (Color): Background color when selected - unselectedTextCol (Color): Text color when not selected - unselectedBgCol (Color): Background color when not selected

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIHorizontalLayout.h\"\n\nclass ToolbarScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIHorizontalLayout* toolbar;\n\npublic:\n    void init() override {\n        // Create horizontal toolbar\n        toolbar = new pixelroot32::graphics::ui::UIHorizontalLayout(\n            0.0f, 0.0f,    // Top of screen\n            128.0f, 20.0f  // Full width, 20px tall\n        );\n        toolbar->setSpacing(4.0f);\n        toolbar->setPadding(2.0f);\n\n        // Add toolbar buttons\n        toolbar->addElement(newButton(\"File\", ...));\n        toolbar->addElement(newButton(\"Edit\", ...));\n        toolbar->addElement(newButton(\"View\", ...));\n\n        addEntity(toolbar);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class (abstract)
  • UIVerticalLayout - Vertical layout
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/padding_container/","title":"UIPaddingContainer","text":"

Container that wraps a single UI element and applies padding.

"},{"location":"api_reference/ui/ui_layouts/padding_container/#description","title":"Description","text":"

UIPaddingContainer adds padding/margin around a single child element without organizing multiple elements. Useful for adding spacing to individual elements or nesting layouts with custom padding.

This container is simpler than UIPanel (no background/border) and focuses only on spacing.

"},{"location":"api_reference/ui/ui_layouts/padding_container/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIPaddingContainer : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/padding_container/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom padding containers (if needed)
"},{"location":"api_reference/ui/ui_layouts/padding_container/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/padding_container/#uipaddingcontainerfloat-x-float-y-float-w-float-h","title":"UIPaddingContainer(float x, float y, float w, float h)","text":"

Constructs a new UIPaddingContainer.

Parameters: - x (float): X position of the container - y (float): Y position of the container - w (float): Width of the container - h (float): Height of the container

Example:

#include \"graphics/ui/UIPaddingContainer.h\"\n\n// Create padding container\npixelroot32::graphics::ui::UIPaddingContainer* padded = \n    new pixelroot32::graphics::ui::UIPaddingContainer(\n        10.0f, 10.0f,\n        108.0f, 108.0f\n    );\npadded->setPadding(8.0f);  // 8px padding on all sides\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setchilduielement-element","title":"void setChild(UIElement* element)","text":"

Sets the child element.

Parameters: - element (UIElement*): Pointer to the UI element to wrap

Returns: - void

Notes: - Child element is positioned with padding applied - Can wrap any UI element (button, label, layout, etc.)

Example:

padded->setChild(button);\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#uielement-getchild-const","title":"UIElement* getChild() const","text":"

Gets the child element.

Returns: - UIElement*: Pointer to the child element, or nullptr if none set

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setpaddingfloat-p","title":"void setPadding(float p)","text":"

Sets uniform padding on all sides.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Applies same padding to all sides - Child position is automatically updated

Example:

padded->setPadding(10.0f);  // 10px padding all around\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setpaddingfloat-left-float-right-float-top-float-bottom","title":"void setPadding(float left, float right, float top, float bottom)","text":"

Sets asymmetric padding.

Parameters: - left (float): Left padding in pixels - right (float): Right padding in pixels - top (float): Top padding in pixels - bottom (float): Bottom padding in pixels

Returns: - void

Example:

padded->setPadding(10.0f, 5.0f, 8.0f, 12.0f);  // Different padding per side\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingleft-const","title":"float getPaddingLeft() const","text":"

Gets the left padding.

Returns: - float: Left padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingright-const","title":"float getPaddingRight() const","text":"

Gets the right padding.

Returns: - float: Right padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingtop-const","title":"float getPaddingTop() const","text":"

Gets the top padding.

Returns: - float: Top padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingbottom-const","title":"float getPaddingBottom() const","text":"

Gets the bottom padding.

Returns: - float: Bottom padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setpositionfloat-newx-float-newy","title":"void setPosition(float newX, float newY)","text":"

Sets the position of the container. Also updates the child element's position.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Child element position is updated automatically with padding applied

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the container and child element.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Updates child element if set - Called automatically by Scene

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the child element.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

Notes: - Only draws child element (no background/border) - Child is drawn at padded position

"},{"location":"api_reference/ui/ui_layouts/padding_container/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIPaddingContainer.h\"\n\nclass MenuScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Create button\n        auto* button = new UIButton(\"Start\", 0, 0, 0, 100.0f, 30.0f, \n                                    [this]() { startGame(); });\n\n        // Wrap button with padding\n        auto* paddedButton = new pixelroot32::graphics::ui::UIPaddingContainer(\n            64.0f, 50.0f,  // position\n            120.0f, 50.0f  // size (button + padding)\n        );\n        paddedButton->setPadding(10.0f);  // 10px padding\n        paddedButton->setChild(button);\n\n        addEntity(paddedButton);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/padding_container/#nesting-with-layouts","title":"Nesting with Layouts","text":"
// Create layout\nauto* layout = new UIVerticalLayout(10, 10, 108, 108);\n\n// Wrap layout with padding\nauto* paddedLayout = new UIPaddingContainer(0, 0, 128, 128);\npaddedLayout->setPadding(10.0f, 10.0f, 20.0f, 20.0f);  // Asymmetric\npaddedLayout->setChild(layout);\n
"},{"location":"api_reference/ui/ui_layouts/padding_container/#performance-considerations","title":"Performance Considerations","text":"
  • Rendering: Very efficient (just draws child)
  • Position calculation: Fast (simple addition)
  • Memory: Minimal overhead
"},{"location":"api_reference/ui/ui_layouts/padding_container/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Very lightweight
  • Update frequency: Position only recalculates when padding/position changes
"},{"location":"api_reference/ui/ui_layouts/padding_container/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UIPanel - Panel with background and border
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/panel/","title":"UIPanel","text":"

Visual container that draws a background and border around a child element.

"},{"location":"api_reference/ui/ui_layouts/panel/#description","title":"Description","text":"

UIPanel provides a retro-style window/panel appearance with a background color and border. Typically contains a UILayout or other UI elements. Useful for dialogs, menus, and information panels.

The panel wraps a single child element and draws a background rectangle and border around it.

"},{"location":"api_reference/ui/ui_layouts/panel/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIPanel : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/panel/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom panel classes (if needed)
"},{"location":"api_reference/ui/ui_layouts/panel/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/panel/#uipanelfloat-x-float-y-float-w-float-h","title":"UIPanel(float x, float y, float w, float h)","text":"

Constructs a new UIPanel.

Parameters: - x (float): X position of the panel - y (float): Y position of the panel - w (float): Width of the panel - h (float): Height of the panel

Example:

#include \"graphics/ui/UIPanel.h\"\n\n// Create dialog panel\npixelroot32::graphics::ui::UIPanel* dialog = \n    new pixelroot32::graphics::ui::UIPanel(\n        20.0f, 30.0f,  // position\n        88.0f, 68.0f   // size\n    );\n

"},{"location":"api_reference/ui/ui_layouts/panel/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/panel/#void-setchilduielement-element","title":"void setChild(UIElement* element)","text":"

Sets the child element.

Parameters: - element (UIElement*): Pointer to the UI element to wrap (typically a UILayout)

Returns: - void

Notes: - Child element is positioned inside the panel (with padding) - Typically a layout (VerticalLayout, etc.)

Example:

// Create panel\nauto* panel = new UIPanel(20, 30, 88, 68);\n\n// Create layout for panel content\nauto* layout = new UIVerticalLayout(0, 0, 80, 60);\nlayout->addElement(button1);\nlayout->addElement(button2);\n\n// Set layout as panel child\npanel->setChild(layout);\n

"},{"location":"api_reference/ui/ui_layouts/panel/#uielement-getchild-const","title":"UIElement* getChild() const","text":"

Gets the child element.

Returns: - UIElement*: Pointer to the child element, or nullptr if none set

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setbackgroundcolorcolor-color","title":"void setBackgroundColor(Color color)","text":"

Sets the background color.

Parameters: - color (Color): Background color

Returns: - void

Example:

panel->setBackgroundColor(Color::Blue);\n

"},{"location":"api_reference/ui/ui_layouts/panel/#color-getbackgroundcolor-const","title":"Color getBackgroundColor() const","text":"

Gets the background color.

Returns: - Color: Background color

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setbordercolorcolor-color","title":"void setBorderColor(Color color)","text":"

Sets the border color.

Parameters: - color (Color): Border color

Returns: - void

Example:

panel->setBorderColor(Color::White);\n

"},{"location":"api_reference/ui/ui_layouts/panel/#color-getbordercolor-const","title":"Color getBorderColor() const","text":"

Gets the border color.

Returns: - Color: Border color

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setborderwidthuint8_t-width","title":"void setBorderWidth(uint8_t width)","text":"

Sets the border width.

Parameters: - width (uint8_t): Border width in pixels

Returns: - void

Notes: - Default: 1 pixel - Higher values = thicker border

Example:

panel->setBorderWidth(2);  // 2 pixel border\n

"},{"location":"api_reference/ui/ui_layouts/panel/#uint8_t-getborderwidth-const","title":"uint8_t getBorderWidth() const","text":"

Gets the border width.

Returns: - uint8_t: Border width in pixels

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setpositionfloat-newx-float-newy","title":"void setPosition(float newX, float newY)","text":"

Sets the position of the panel. Also updates the child element's position.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Child element position is updated automatically

"},{"location":"api_reference/ui/ui_layouts/panel/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the panel and child element.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Updates child element if set - Called automatically by Scene

"},{"location":"api_reference/ui/ui_layouts/panel/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the panel (background, border) and child element.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

Notes: - Draws background rectangle - Draws border rectangle - Draws child element if set

"},{"location":"api_reference/ui/ui_layouts/panel/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIPanel.h\"\n#include \"graphics/ui/UIVerticalLayout.h\"\n\nclass DialogScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIPanel* dialog;\n\npublic:\n    void init() override {\n        // Create dialog panel\n        dialog = new pixelroot32::graphics::ui::UIPanel(\n            20.0f, 30.0f,  // position\n            88.0f, 68.0f   // size\n        );\n        dialog->setBackgroundColor(Color::Navy);\n        dialog->setBorderColor(Color::White);\n        dialog->setBorderWidth(2);\n\n        // Create layout for dialog content\n        auto* layout = new pixelroot32::graphics::ui::UIVerticalLayout(\n            4.0f, 4.0f,  // Position inside panel\n            80.0f, 60.0f // Size inside panel\n        );\n        layout->setSpacing(8.0f);\n\n        // Add buttons\n        auto* okButton = new UIButton(\"OK\", 0, 0, 0, 70.0f, 20.0f, \n                                     [this]() { closeDialog(); });\n        auto* cancelButton = new UIButton(\"Cancel\", 1, 0, 0, 70.0f, 20.0f,\n                                         [this]() { closeDialog(); });\n\n        layout->addElement(okButton);\n        layout->addElement(cancelButton);\n\n        // Set layout as panel child\n        dialog->setChild(layout);\n\n        addEntity(dialog);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/panel/#performance-considerations","title":"Performance Considerations","text":"
  • Rendering: Simple rectangles; very efficient
  • Child updates: Child element updates are fast
  • Memory: Small overhead (just colors and border width)
"},{"location":"api_reference/ui/ui_layouts/panel/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Panel is lightweight
  • Rendering: Two rectangles (background + border); minimal overhead
"},{"location":"api_reference/ui/ui_layouts/panel/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UILayouts - Layout containers to use inside panels
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/","title":"UIVerticalLayout","text":"

Vertical layout container with scroll support.

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#description","title":"Description","text":"

UIVerticalLayout organizes UI elements vertically, one below another. It supports scrolling when content exceeds the visible viewport and handles keyboard/D-pad navigation automatically.

This layout is ideal for menus, lists, and any vertical arrangement of UI elements.

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIVerticalLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom vertical layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/vertical_layout/#uiverticallayoutfloat-x-float-y-float-w-float-h","title":"UIVerticalLayout(float x, float y, float w, float h)","text":"

Constructs a new UIVerticalLayout.

Parameters: - x (float): X position of the layout container - y (float): Y position of the layout container - w (float): Width of the layout container - h (float): Height of the layout container (viewport height)

Example:

#include \"graphics/ui/UIVerticalLayout.h\"\n\n// Create vertical layout for menu\npixelroot32::graphics::ui::UIVerticalLayout* menuLayout = \n    new pixelroot32::graphics::ui::UIVerticalLayout(\n        20.0f, 20.0f,  // position\n        88.0f, 88.0f   // size (viewport)\n    );\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout.

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

Notes: - Elements are arranged vertically, one below another - Layout is automatically recalculated - Elements are positioned based on spacing and padding

Example:

menuLayout->addElement(startButton);\nmenuLayout->addElement(quitButton);\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

Notes: - Layout is automatically recalculated - Element is not deleted (you must manage its lifetime)

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements.

Returns: - void

Notes: - Called automatically when elements are added/removed - Can be called manually if needed - Recalculates all element positions and content height

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input for navigation and scrolling.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Handles UP/DOWN navigation - Manages selection state - Handles scrolling if enabled - Should be called every frame in update()

Example:

void update(unsigned long deltaTime) override {\n    UIVerticalLayout::update(deltaTime);\n\n    auto& input = engine.getInputManager();\n    menuLayout->handleInput(input);\n}\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout (handles smooth scrolling).

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Updates smooth scrolling animation - Updates child elements

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the layout and its visible elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

Notes: - Called automatically by Scene if isVisible is true - Only draws visible elements (viewport culling) - Draws elements in order

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setscrollenabledbool-enable","title":"void setScrollEnabled(bool enable)","text":"

Enables or disables scrolling.

Parameters: - enable (bool): true to enable scrolling

Returns: - void

Notes: - When disabled, scroll offset is reset to 0 - Scrolling is useful when content exceeds viewport height

Example:

menuLayout->setScrollEnabled(true);  // Enable scrolling\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-enablescrollbool-enable","title":"void enableScroll(bool enable)","text":"

Alias for setScrollEnabled().

Parameters: - enable (bool): true to enable scrolling

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setviewportheightfloat-h","title":"void setViewportHeight(float h)","text":"

Sets the viewport height (visible area).

Parameters: - h (float): Viewport height in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Use to adjust visible area

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#float-getscrolloffset-const","title":"float getScrollOffset() const","text":"

Gets the current scroll offset.

Returns: - float: Scroll offset in pixels

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setscrolloffsetfloat-offset","title":"void setScrollOffset(float offset)","text":"

Sets the scroll offset directly.

Parameters: - offset (float): Scroll offset in pixels

Returns: - void

Notes: - Offset is clamped to valid range automatically - Use for programmatic scrolling

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#float-getcontentheight-const","title":"float getContentHeight() const","text":"

Gets the total content height.

Returns: - float: Content height in pixels

Notes: - Includes all elements plus spacing and padding - Useful for scroll calculations

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#int-getselectedindex-const","title":"int getSelectedIndex() const","text":"

Gets the currently selected element index.

Returns: - int: Selected index, or -1 if none selected

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setselectedindexint-index","title":"void setSelectedIndex(int index)","text":"

Sets the selected element index.

Parameters: - index (int): Index to select (-1 to deselect)

Returns: - void

Notes: - Selected element is highlighted - Selection is scrolled into view if needed

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#uielement-getselectedelement-const","title":"UIElement* getSelectedElement() const","text":"

Gets the selected element.

Returns: - UIElement*: Pointer to selected element, or nullptr if none selected

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setscrollspeedfloat-speed","title":"void setScrollSpeed(float speed)","text":"

Sets the scroll speed for smooth scrolling.

Parameters: - speed (float): Pixels per millisecond

Returns: - void

Notes: - Default: 0.5 pixels per millisecond - Higher values = faster scrolling

Example:

menuLayout->setScrollSpeed(1.0f);  // Faster scrolling\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setnavigationbuttonsuint8_t-upbutton-uint8_t-downbutton","title":"void setNavigationButtons(uint8_t upButton, uint8_t downButton)","text":"

Sets the navigation button indices.

Parameters: - upButton (uint8_t): Button index for UP navigation - downButton (uint8_t): Button index for DOWN navigation

Returns: - void

Notes: - Default: UP = 0, DOWN = 1 - Change if your input mapping differs

Example:

menuLayout->setNavigationButtons(0, 1);  // UP=0, DOWN=1\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setbuttonstylecolor-selectedtextcol-color-selectedbgcol-color-unselectedtextcol-color-unselectedbgcol","title":"void setButtonStyle(Color selectedTextCol, Color selectedBgCol, Color unselectedTextCol, Color unselectedBgCol)","text":"

Sets the style colors for selected and unselected buttons.

Parameters: - selectedTextCol (Color): Text color when selected - selectedBgCol (Color): Background color when selected - unselectedTextCol (Color): Text color when not selected - unselectedBgCol (Color): Background color when not selected

Returns: - void

Example:

menuLayout->setButtonStyle(\n    Color::Yellow,  // Selected text\n    Color::Blue,    // Selected background\n    Color::White,   // Unselected text\n    Color::Black    // Unselected background\n);\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIVerticalLayout.h\"\n#include \"graphics/ui/UIButton.h\"\n\nclass MainMenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIVerticalLayout* menuLayout;\n\npublic:\n    void init() override {\n        // Create menu layout\n        menuLayout = new pixelroot32::graphics::ui::UIVerticalLayout(\n            20.0f, 20.0f,  // position\n            88.0f, 88.0f   // size\n        );\n        menuLayout->setScrollEnabled(true);\n        menuLayout->setSpacing(8.0f);\n        menuLayout->setPadding(4.0f);\n\n        // Create buttons\n        auto* startButton = new pixelroot32::graphics::ui::UIButton(\n            \"Start\",\n            0, 64.0f, 50.0f, 100.0f, 30.0f,\n            [this]() { engine.setScene(&gameScene); }\n        );\n\n        auto* quitButton = new pixelroot32::graphics::ui::UIButton(\n            \"Quit\",\n            1, 64.0f, 50.0f, 100.0f, 30.0f,\n            [this]() { engine.stop(); }\n        );\n\n        // Add buttons to layout\n        menuLayout->addElement(startButton);\n        menuLayout->addElement(quitButton);\n\n        // Add layout to scene\n        addEntity(menuLayout);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Layout handles input automatically\n        auto& input = engine.getInputManager();\n        menuLayout->handleInput(input);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n        Scene::draw(renderer);  // Draws layout and buttons\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#navigation","title":"Navigation","text":"

The layout handles D-pad navigation automatically:

  • UP button: Moves selection up
  • DOWN button: Moves selection down
  • Action button: Triggers selected button's callback
  • Scrolling: Automatically scrolls to keep selected element visible
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#performance-considerations","title":"Performance Considerations","text":"
  • Viewport culling: Only visible elements are drawn
  • Layout recalculation: Fast (simple positioning)
  • Scrolling: Smooth scrolling is efficient
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Element count: Stay within MAX_ENTITIES limit
  • Scrolling: Smooth scrolling uses minimal CPU
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class (abstract)
  • UIButton - Buttons for menus
  • Manual - User Interface
  • API Overview
"},{"location":"getting_started/fundamental_concepts/","title":"Fundamental Concepts","text":"

Before you start programming, it's important to understand the basic concepts that form PixelRoot32's architecture. This section explains how the engine works at a conceptual level, without going into code details.

"},{"location":"getting_started/fundamental_concepts/#engine-architecture","title":"Engine Architecture","text":""},{"location":"getting_started/fundamental_concepts/#engine-the-heart-of-the-engine","title":"Engine: The Heart of the Engine","text":"

The Engine is the main class that orchestrates the entire system. Think of it as the conductor that coordinates all subsystems:

  • Renderer: Handles drawing everything on screen
  • InputManager: Reads and processes user input (buttons, keyboard)
  • AudioEngine: Generates and plays sounds and music
  • SceneManager: Manages game scenes (menus, levels, etc.)

The Engine runs the main game loop: an infinite cycle that updates game logic and draws each frame on screen. It also calculates delta time (time elapsed between frames) so the game runs at the same speed regardless of framerate.

"},{"location":"getting_started/fundamental_concepts/#scene-organizing-your-game","title":"Scene: Organizing Your Game","text":"

A Scene represents a screen or level in your game. For example: - A scene for the main menu - A scene for each game level - A scene for the game over screen - A scene for the pause menu

Each scene contains and manages a set of entities (characters, enemies, objects, etc.). The scene is responsible for: - Initializing its entities when loaded - Updating the logic of all its entities each frame - Drawing all its visible entities each frame - Managing collisions between entities that can collide

The Engine can only have one active scene at a time, but you can easily switch between scenes (for example, go from menu to game, or from game to pause menu).

"},{"location":"getting_started/fundamental_concepts/#entity-the-fundamental-building-blocks","title":"Entity: The Fundamental Building Blocks","text":"

An Entity is any object in your game that has: - Position (x, y) in the world - Size (width and height) - Visibility (can be visible or not) - Active state (can be enabled or disabled) - Render layer (in what order it's drawn)

Entities are the foundation of everything in your game: the player, enemies, projectiles, objects, UI elements\u2014everything is an entity or inherits from Entity.

Each entity has two main methods: - update(): Called each frame to update the entity's logic (movement, animation, etc.) - draw(): Called each frame to draw the entity on screen

"},{"location":"getting_started/fundamental_concepts/#actor-entities-that-can-collide","title":"Actor: Entities That Can Collide","text":"

An Actor is a special entity that can participate in the collision system. In addition to everything an Entity has, an Actor has: - Collision layer: Which group it belongs to (e.g., \"player\", \"enemy\", \"projectile\") - Collision mask: Which other groups it can collide with - Hitbox: The shape used to detect collisions (usually a rectangle)

For example, a player might be on the \"player\" layer and have a mask that allows it to collide with \"enemies\" and \"obstacles\", but not with \"other players\".

When two actors collide, the system calls their onCollision() method so they can react (e.g., player loses health, enemy is destroyed, etc.).

"},{"location":"getting_started/fundamental_concepts/#physicsactor-entities-with-physics","title":"PhysicsActor: Entities with Physics","text":"

A PhysicsActor is an Actor that also has physical properties: - Velocity (vx, vy): Moves automatically according to its velocity - Gravity: Can fall automatically - Friction: Gradually loses velocity - Restitution: Bounces when it collides (like a ball)

The PhysicsActor updates automatically each frame, applying physics and moving the entity. It can also detect collisions with world boundaries (the walls of the play area).

"},{"location":"getting_started/fundamental_concepts/#entity-hierarchy","title":"Entity Hierarchy","text":"

The relationship between these classes is hierarchical:

Entity (base)\n  \u2514\u2500\u2500 Actor (can collide)\n       \u2514\u2500\u2500 PhysicsActor (has physics)\n

This means: - Every Actor is also an Entity - Every PhysicsActor is also an Actor and an Entity - You can use Entity for simple objects that don't need collisions - You can use Actor for objects that need to detect collisions - You can use PhysicsActor for objects that need automatic physics

"},{"location":"getting_started/fundamental_concepts/#rendering-system","title":"Rendering System","text":""},{"location":"getting_started/fundamental_concepts/#render-layers","title":"Render Layers","text":"

To control the order in which things are drawn, PixelRoot32 uses render layers:

  • Layer 0 (Background): Backgrounds, tilemaps, background elements
  • Layer 1 (Gameplay): Characters, enemies, projectiles, game objects
  • Layer 2 (UI): Menus, HUD, text, interface elements

Layers are drawn in order: first 0, then 1, and finally 2. This ensures the background is always behind, gameplay in the middle, and UI always visible in front.

Each entity has a renderLayer property that indicates which layer it should be drawn on. You can change this property to move entities between layers.

"},{"location":"getting_started/fundamental_concepts/#resolution-scaling","title":"Resolution Scaling","text":"

PixelRoot32 supports Independent Resolution Scaling. This means your game logic can run at a different resolution (the logical resolution) than the physical screen (physical resolution).

  • Logical Resolution: The resolution you program for (e.g., 128x128). All coordinates and sizes in your code refer to this space.
  • Physical Resolution: The actual number of pixels on your display (e.g., 240x240).

The engine automatically handles the scaling using an optimized hardware-accelerated process, allowing you to create low-resolution retro games that look crisp on modern high-resolution micro-displays.

"},{"location":"getting_started/fundamental_concepts/#rendering-pipeline","title":"Rendering Pipeline","text":"

The rendering process works like this:

  1. beginFrame(): The screen is cleared (painted black or background color)
  2. Draw entities: All visible entities are traversed, organized by layer
  3. endFrame(): The complete frame is sent to the display

The Renderer abstracts hardware details, so the same code works on both ESP32 (TFT_eSPI) and PC (SDL2).

"},{"location":"getting_started/fundamental_concepts/#coordinates-and-space","title":"Coordinates and Space","text":"

PixelRoot32 uses a standard coordinate system: - Origin (0, 0): Top-left corner - X-axis: Increases to the right - Y-axis: Increases downward

Coordinates are in pixels. If your display is 240x240, coordinates range from (0, 0) to (239, 239).

"},{"location":"getting_started/fundamental_concepts/#lifecycle","title":"Lifecycle","text":""},{"location":"getting_started/fundamental_concepts/#initialization","title":"Initialization","text":"

When your game starts:

  1. Configuration: Configuration objects are created (DisplayConfig, InputConfig, AudioConfig)
  2. Engine: The Engine is created with these configurations
  3. init(): engine.init() is called to initialize all subsystems
  4. Scene: The initial scene is created and configured
  5. setScene(): The scene is assigned to the Engine
"},{"location":"getting_started/fundamental_concepts/#game-loop","title":"Game Loop","text":"

Once initialized, the Engine enters the game loop:

While the game is running:\n  1. Calculate deltaTime (time since last frame)\n  2. Update InputManager (read buttons/keyboard)\n  3. Update AudioEngine (advance sounds and music)\n  4. Update current scene (update all entities)\n  5. Detect collisions in the scene\n  6. Draw the scene (draw all visible entities)\n  7. Repeat\n

This cycle runs continuously, typically at 30-60 FPS on ESP32, or faster on PC.

"},{"location":"getting_started/fundamental_concepts/#update","title":"Update","text":"

Each frame, all enabled entities receive a call to their update(deltaTime) method. This is where: - Entities move - Animations update - Game logic is processed - User input is read - Sound effects are played

The deltaTime is passed in milliseconds and represents how much time has passed since the last frame. This allows movement to be framerate-independent.

"},{"location":"getting_started/fundamental_concepts/#rendering-draw","title":"Rendering (Draw)","text":"

After updating, all visible entities receive a call to their draw(renderer) method. This is where: - Sprites are drawn - Text is drawn - Primitives are drawn (rectangles, circles, etc.)

The renderer is passed as a parameter so entities can draw themselves.

"},{"location":"getting_started/fundamental_concepts/#cleanup","title":"Cleanup","text":"

When you change scenes or end the game: - Entities from the previous scene can be cleaned up - Resources are freed - The new scene is initialized

"},{"location":"getting_started/fundamental_concepts/#conceptual-summary","title":"Conceptual Summary","text":"

To summarize, PixelRoot32 works like this:

  1. Engine coordinates everything and runs the game loop
  2. Scene organizes your game into screens/levels
  3. Entity is any object in your game
  4. Actor is an entity that can collide
  5. PhysicsActor is an actor with automatic physics
  6. Renderer draws everything on screen using layers
  7. Each frame updates logic and then draws

All of this works automatically once you configure the Engine and create your scenes and entities. You don't need to worry about game loop details; you just need to implement update() and draw() in your entities.

"},{"location":"getting_started/fundamental_concepts/#next-step","title":"Next Step","text":"

Now that you understand the fundamental concepts, you're ready to create your first project and see these concepts in action with real code.

See also: - What is PixelRoot32? - Why PixelRoot32? - Your First Project - Manual - Scenes and Entities

"},{"location":"getting_started/installation/","title":"Installation","text":"

This guide covers installing the PixelRoot32 documentation environment and preparing your development setup for ESP32 and Native (PC) targets.

"},{"location":"getting_started/installation/#requirements","title":"Requirements","text":"
  • Python 3.11 or newer
  • Git (recommended for source management)
  • VS Code (or your preferred IDE)
  • For ESP32 targets: PlatformIO (VS Code extension) with ESP32 toolchain
  • For Native targets: a C++ build toolchain (CMake or your OS-native toolchain)
"},{"location":"getting_started/installation/#install-documentation-tooling","title":"Install Documentation Tooling","text":"

To build and preview this documentation locally:

pip install mkdocs mkdocs-material mkdocs-minify-plugin mkdocs-git-revision-date-localized-plugin mike\nmkdocs serve\n

Open http://127.0.0.1:8000 in your browser to preview.

"},{"location":"getting_started/installation/#esp32-setup-recommended","title":"ESP32 Setup (Recommended)","text":"
  1. Install VS Code
  2. Install PlatformIO IDE extension
  3. Install ESP32 platform/toolchain via PlatformIO
  4. Clone the engine repository:
  5. https://github.com/Gperez88/PixelRoot32-Game-Engine
  6. Open the engine or example project in VS Code (PlatformIO)
  7. Build and upload to your ESP32 board

Tip: Use boards based on ESP32-WROOM/WROVER for best compatibility. Ensure a reliable USB cable and correct serial port selection.

"},{"location":"getting_started/installation/#native-pc-setup","title":"Native (PC) Setup","text":"
  1. Install a C++ toolchain (e.g., MSVC or MinGW on Windows)
  2. Install CMake (if the engine provides CMake build files)
  3. Clone the engine repository:
  4. https://github.com/Gperez88/PixelRoot32-Game-Engine
  5. Configure and build the native runtime:
  6. Follow the engine\u2019s native build instructions (Development \u2192 Compiling)
"},{"location":"getting_started/installation/#verify-your-environment","title":"Verify Your Environment","text":"
  • ESP32: Build and flash a minimal sample; confirm serial output and display if applicable
  • Native: Run the executable; confirm window output and input handling
"},{"location":"getting_started/installation/#troubleshooting","title":"Troubleshooting","text":"
  • If PlatformIO cannot find the ESP32 platform, update PlatformIO and retry
  • If native builds fail, verify compiler versions and CMake generator settings
  • Use Community \u2192 Troubleshooting for common issues and fixes
"},{"location":"getting_started/installation/#next-steps","title":"Next Steps","text":"
  • First Project
  • Concepts
"},{"location":"getting_started/what_is_pixelroot32/","title":"What is PixelRoot32?","text":"

PixelRoot32 is a lightweight, modular 2D game engine written in C++ designed specifically for ESP32 microcontrollers, with a native simulation layer for PC (SDL2) that allows you to develop and debug quickly on your desktop before deploying to hardware.

"},{"location":"getting_started/what_is_pixelroot32/#simple-definition","title":"Simple Definition","text":"

PixelRoot32 is a game engine that lets you create retro-style 8-bit/16-bit video games directly on an ESP32 board, with the ability to develop and test on your PC before transferring code to hardware.

"},{"location":"getting_started/what_is_pixelroot32/#key-features","title":"Key Features","text":""},{"location":"getting_started/what_is_pixelroot32/#scene-based-architecture","title":"\ud83c\udfae Scene-Based Architecture","text":"
  • Scene system inspired by Godot Engine
  • Intuitive management of levels, menus, and screens
  • Simple transitions between scenes
"},{"location":"getting_started/what_is_pixelroot32/#optimized-rendering","title":"\ud83c\udfa8 Optimized Rendering","text":"
  • 1bpp (monochrome) sprites as the standard format
  • Support for multi-layer sprites (MultiSprite)
  • Experimental 2bpp and 4bpp formats for higher fidelity
  • Retro color palette system (NES, GameBoy, PICO-8, etc.)
  • Compact tilemaps for backgrounds and levels
  • 2D camera with dead-zone for smooth scrolling
  • Render layer system (background, gameplay, UI)
"},{"location":"getting_started/what_is_pixelroot32/#nes-like-audio","title":"\ud83d\udd0a NES-like Audio","text":"
  • 4 audio channels (2 Pulse, 1 Triangle, 1 Noise)
  • Integrated sound effects system
  • Music player for background melodies
  • Backends for ESP32 (internal DAC or external I2S) and SDL2
"},{"location":"getting_started/what_is_pixelroot32/#physics-and-collisions","title":"\ud83c\udfaf Physics and Collisions","text":"
  • AABB (Axis-Aligned Bounding Box) collision system
  • PhysicsActor with gravity, friction, and restitution
  • Collision layers and masks for fine control
  • World boundary collision detection
"},{"location":"getting_started/what_is_pixelroot32/#user-interface","title":"\ud83d\udda5\ufe0f User Interface","text":"
  • Basic elements: Labels, Buttons, Panels
  • Automatic layouts: Vertical, Horizontal, Grid, Anchor
  • Integrated D-pad navigation
  • Scroll and viewport culling for long lists
"},{"location":"getting_started/what_is_pixelroot32/#optimized-for-esp32","title":"\u26a1 Optimized for ESP32","text":"
  • Efficient memory management
  • Integrated object pooling
  • No dynamic allocations in the game loop
  • Performance optimized for limited hardware
"},{"location":"getting_started/what_is_pixelroot32/#typical-use-cases","title":"Typical Use Cases","text":"

PixelRoot32 is ideal for creating:

  • Arcade Games: Space Invaders, Pong, Breakout
  • Platformers: Horizontal scrolling games with simple physics
  • Puzzles: Tetris, Snake, logic games
  • Simple RPGs: Basic role-playing games with tilemaps
  • Shooters: Vertical or horizontal shooting games
  • Rapid Prototypes: Quick development of game ideas
"},{"location":"getting_started/what_is_pixelroot32/#supported-platforms","title":"Supported Platforms","text":""},{"location":"getting_started/what_is_pixelroot32/#esp32","title":"ESP32","text":"
  • Display: TFT_eSPI (ST7735, ILI9341, ST7789, etc.)
  • Audio: Internal DAC (GPIO 25/26) or external I2S (MAX98357A, PCM5102)
  • Input: Digital buttons, D-pad
  • Hardware: Any ESP32 board (ESP32-WROOM, ESP32-WROVER, etc.)
"},{"location":"getting_started/what_is_pixelroot32/#desktopnative-pc","title":"Desktop/Native (PC)","text":"
  • Display: SDL2 (Windows, Linux, macOS)
  • Audio: SDL2 Audio
  • Input: Keyboard, mouse
  • Usage: Development, debugging, testing

Note: Support for u8g2 (OLEDs) is planned for the future.

"},{"location":"getting_started/what_is_pixelroot32/#project-status","title":"Project Status","text":"

Current Version: v0.2.0-dev

PixelRoot32 is under active development. APIs may change and some subsystems are still experimental. Occasional changes or breaking changes are expected, especially on less-tested configurations.

"},{"location":"getting_started/what_is_pixelroot32/#stable-features","title":"Stable Features","text":"
  • Scene and entity system
  • Basic rendering (1bpp sprites)
  • NES-like audio system
  • Basic physics and collisions
  • Basic UI system
  • ESP32 and Native support
"},{"location":"getting_started/what_is_pixelroot32/#experimental-features","title":"Experimental Features","text":"
  • 2bpp and 4bpp sprites (require compilation flags)
  • Scene Arena (advanced memory management)
"},{"location":"getting_started/what_is_pixelroot32/#planned-features","title":"Planned Features","text":"
  • Support for u8g2 (OLEDs)
  • Music compiler
  • Tilemap compiler
  • Save/load system
  • Spatial partitioning for collisions
"},{"location":"getting_started/what_is_pixelroot32/#quick-comparison","title":"Quick Comparison","text":""},{"location":"getting_started/what_is_pixelroot32/#when-to-use-pixelroot32","title":"When to use PixelRoot32?","text":"

\u2705 Use PixelRoot32 if: - You want to create retro games on ESP32 - You need a lightweight and efficient engine - You prefer a simple and clear architecture - You want to develop on PC and deploy to ESP32 - You like 8-bit/16-bit style games

\u274c Don't use PixelRoot32 if: - You need 3D graphics - You require advanced shaders - You need complex physics (advanced physics engines) - You want to create modern AAA games - You need support for multiple mobile platforms

"},{"location":"getting_started/what_is_pixelroot32/#next-step","title":"Next Step","text":"

Now that you understand what PixelRoot32 is, discover why you should use it or go directly to your first project.

See also: - Fundamental Concepts - Installation - API Reference

"},{"location":"getting_started/why_pixelroot32/","title":"Why PixelRoot32?","text":"

PixelRoot32 is specifically designed to solve the unique challenges of creating video games on embedded hardware like the ESP32, while maintaining the simplicity and productivity of modern development.

"},{"location":"getting_started/why_pixelroot32/#main-advantages","title":"Main Advantages","text":""},{"location":"getting_started/why_pixelroot32/#optimized-for-esp32","title":"\ud83c\udfaf Optimized for ESP32","text":"

Memory Efficient - 1bpp sprite system that minimizes RAM and Flash usage - Integrated object pooling to avoid memory fragmentation - Compact tilemaps that reuse sprites - No dynamic allocations in the game loop

Performance Optimized - Rendering optimized for ESP32 limitations - Efficient render layer system - Viewport culling to reduce draw calls - Rendering pipeline designed for limited hardware

Real Hardware - Direct support for common TFT displays (ST7735, ILI9341, ST7789) - Integrated audio (internal DAC or external I2S) - Simple pin and hardware configuration

"},{"location":"getting_started/why_pixelroot32/#cross-platform-development","title":"\ud83d\udda5\ufe0f Cross-Platform Development","text":"

Develop on PC, Deploy to ESP32 - Same code works on PC (SDL2) and ESP32 - Fast debugging on desktop - Testing without hardware needed - Rapid development iteration

Visual Consistency - Native bitmap font system (pixel-perfect) - Same rendering on PC and ESP32 - Consistent color palettes - No surprises when transferring to hardware

"},{"location":"getting_started/why_pixelroot32/#retro-palette-system","title":"\ud83c\udfa8 Retro Palette System","text":"

Authentic Style - Predefined palettes: NES, GameBoy, GameBoy Color, PICO-8 - Dual palette mode for visual contrasts - Custom palettes for unique styles - Automatic color resolution (RGB565)

Easy to Use - Change palette with one line of code - Consistent visualization across all sprites - No need to manually convert assets

"},{"location":"getting_started/why_pixelroot32/#integrated-audio","title":"\ud83d\udd0a Integrated Audio","text":"

Complete NES-like System - 4 audio channels (2 Pulse, 1 Triangle, 1 Noise) - Simple sound effects to create - Integrated music system - Backends for different hardware configurations

No External Dependencies - Software-generated audio - No heavy audio libraries required - Full control over sound - Deterministic and predictable

"},{"location":"getting_started/why_pixelroot32/#simple-and-clear-architecture","title":"\ud83c\udfd7\ufe0f Simple and Clear Architecture","text":"

Easy to Understand - Intuitive scene system (inspired by Godot) - Clear hierarchy: Entity \u2192 Actor \u2192 PhysicsActor - Consistent and predictable APIs - Clean and well-organized code

Quick to Learn - Familiar concepts for game developers - Clear documentation and complete examples - Smooth learning curve - Active community and support

"},{"location":"getting_started/why_pixelroot32/#complete-features","title":"\ud83c\udfae Complete Features","text":"

Everything Needed for Games - Rendering (sprites, tilemaps, primitives) - Audio (effects and music) - Physics (gravity, collisions, basic physics) - UI (layouts, buttons, navigation) - Input (buttons, keyboard) - Camera (scroll, parallax)

No Bloat - Only the essentials, nothing more - No heavy dependencies - Small and maintainable codebase - Easy to understand and modify

"},{"location":"getting_started/why_pixelroot32/#tools-and-ecosystem","title":"\ud83d\udee0\ufe0f Tools and Ecosystem","text":"

Available Tools - Sprite Compiler to convert PNG to sprites - Complete game examples - Templates and starter code - Extensive documentation

Community and Support - Active and developing project - Open source (MIT License) - Feedback and contributions welcome - Examples available

"},{"location":"getting_started/why_pixelroot32/#comparison-with-alternatives","title":"Comparison with Alternatives","text":""},{"location":"getting_started/why_pixelroot32/#vs-full-engines-unity-godot-etc","title":"vs. Full Engines (Unity, Godot, etc.)","text":"

PixelRoot32 Advantages: - \u2705 Much lighter (fits in ESP32) - \u2705 No unnecessary overhead - \u2705 Full control over code - \u2705 Specifically optimized for limited hardware

Disadvantages: - \u274c Fewer advanced features - \u274c No visual editor - \u274c Fewer resources and community

"},{"location":"getting_started/why_pixelroot32/#vs-writing-everything-from-scratch","title":"vs. Writing Everything from Scratch","text":"

PixelRoot32 Advantages: - \u2705 Rendering system already implemented - \u2705 Integrated and working audio - \u2705 Physics and collisions ready - \u2705 Complete UI system - \u2705 Saves months of development

Disadvantages: - \u274c Less control over internal implementation - \u274c You must learn the engine API

"},{"location":"getting_started/why_pixelroot32/#vs-other-esp32-engines","title":"vs. Other ESP32 Engines","text":"

PixelRoot32 Advantages: - \u2705 More modern and clear architecture - \u2705 Better documentation - \u2705 Unique palette system - \u2705 Integrated NES-like audio - \u2705 Real cross-platform development

"},{"location":"getting_started/why_pixelroot32/#ideal-use-cases","title":"Ideal Use Cases","text":"

PixelRoot32 is perfect for:

  1. Educational Projects
  2. Learn game development
  3. Understand engine architecture
  4. Student projects

  5. Rapid Prototypes

  6. Quickly validate game ideas
  7. Create demos and proof-of-concepts
  8. Test mechanics

  9. Retro Games

  10. 8-bit/16-bit style games
  11. Arcade games
  12. Games with retro aesthetics

  13. Hardware Projects

  14. Games on small displays
  15. DIY portable consoles
  16. Maker/retro projects

  17. C++ Learning

  18. Clean and well-structured code
  19. Good programming practices
  20. Real and functional examples
"},{"location":"getting_started/why_pixelroot32/#limitations-to-consider","title":"Limitations to Consider","text":"

To be honest, PixelRoot32 has limitations:

  • Limited Hardware: Designed for ESP32, not powerful PCs
  • Simple Graphics: No 3D, no advanced shaders
  • Basic Physics: Not a complete physics engine
  • Restricted Memory: MAX_ENTITIES = 32 per scene
  • In Development: Some features are experimental

If you need advanced features or powerful hardware, consider other engines. But for retro games on ESP32, PixelRoot32 is an excellent choice.

"},{"location":"getting_started/why_pixelroot32/#conclusion","title":"Conclusion","text":"

PixelRoot32 combines:

  • \u2705 Simplicity of use
  • \u2705 Efficiency for limited hardware
  • \u2705 Completeness of essential features
  • \u2705 Clarity of architecture
  • \u2705 Productivity in development

If you want to create retro games on ESP32 without the complexity of large engines, PixelRoot32 is the right choice.

"},{"location":"getting_started/why_pixelroot32/#next-step","title":"Next Step","text":"

Now that you understand why PixelRoot32 is a good option, learn the fundamental concepts or start directly with your first project.

See also: - What is PixelRoot32? - Fundamental Concepts - Your First Project

"},{"location":"getting_started/your_first_project/","title":"Your First Project","text":"

This guide will walk you through creating and running your first PixelRoot32 project step by step. By the end, you'll have a working project that displays a simple scene on both ESP32 and PC.

"},{"location":"getting_started/your_first_project/#prerequisites","title":"Prerequisites","text":""},{"location":"getting_started/your_first_project/#required-software","title":"Required Software","text":"
  • PlatformIO: Install the PlatformIO IDE extension in VS Code
  • Open VS Code
  • Go to Extensions (Ctrl+Shift+X)
  • Search for \"PlatformIO IDE\"
  • Install and restart VS Code

  • Python 3.8+: Required for PlatformIO (usually installed automatically)

"},{"location":"getting_started/your_first_project/#for-esp32-development","title":"For ESP32 Development","text":"
  • ESP32 Board: Any ESP32 development board (ESP32-WROOM, ESP32-WROVER, etc.)
  • USB Cable: To connect and program your ESP32
  • TFT Display: Compatible display (ST7735, ST7789, ILI9341, etc.)
  • Buttons: 5-6 digital buttons for input (optional for first project)
  • Audio Hardware (optional): Speaker + amplifier (PAM8302A) or I2S DAC (MAX98357A)
"},{"location":"getting_started/your_first_project/#for-native-pc-development","title":"For Native (PC) Development","text":"
  • SDL2: Development libraries
  • Windows (MSYS2): pacman -S mingw-w64-x86_64-SDL2
  • Linux: sudo apt-get install libsdl2-dev
  • macOS: brew install sdl2
"},{"location":"getting_started/your_first_project/#step-1-create-a-new-platformio-project","title":"Step 1: Create a New PlatformIO Project","text":"
  1. Open VS Code with PlatformIO installed

  2. Create New Project:

  3. Click on the PlatformIO icon in the sidebar
  4. Click \"New Project\"
  5. Name: my-first-pixelroot32-game
  6. Board: Select \"ESP32 Dev Module\" (or your specific board)
  7. Framework: Arduino
  8. Location: Choose your workspace folder
  9. Click \"Finish\"

  10. Project Structure: Your project should now have this structure:

    my-first-pixelroot32-game/\n\u251c\u2500\u2500 .pio/\n\u251c\u2500\u2500 include/\n\u251c\u2500\u2500 lib/\n\u251c\u2500\u2500 src/\n\u2502   \u2514\u2500\u2500 main.cpp\n\u251c\u2500\u2500 test/\n\u2514\u2500\u2500 platformio.ini\n

"},{"location":"getting_started/your_first_project/#step-2-install-pixelroot32-engine","title":"Step 2: Install PixelRoot32 Engine","text":""},{"location":"getting_started/your_first_project/#option-a-via-platformio-library-manager-recommended","title":"Option A: Via PlatformIO Library Manager (Recommended)","text":"
  1. Open platformio.ini

  2. Add the library dependency:

[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = arduino\nlib_deps = \n    gperez88/PixelRoot32-Game-Engine@0.2.0-dev\n

\u26a0\ufe0f IMPORTANT: Use the exact version 0.2.0-dev. Do NOT use ^ or fuzzy versioning.

  1. Save the file. PlatformIO will automatically download the library.
"},{"location":"getting_started/your_first_project/#option-b-git-submodule","title":"Option B: Git Submodule","text":"
  1. Open terminal in your project root

  2. Add as submodule:

    git submodule add https://github.com/Gperez88/PixelRoot32-Game-Engine.git lib/PixelRoot32-Game-Engine\n

  3. Update platformio.ini:

    lib_extra_dirs = lib\n

"},{"location":"getting_started/your_first_project/#step-3-configure-hardware-esp32","title":"Step 3: Configure Hardware (ESP32)","text":""},{"location":"getting_started/your_first_project/#configure-tft_espi-display","title":"Configure TFT_eSPI Display","text":"

Edit platformio.ini and add build flags for your display. Here are two common configurations:

For ST7789 (240x240):

[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = arduino\nlib_deps = \n    gperez88/PixelRoot32-Game-Engine@0.2.0-dev\n    bodmer/TFT_eSPI@^2.5.43\n\nbuild_flags = \n    -D ST7789_DRIVER\n    -D TFT_WIDTH=240\n    -D TFT_HEIGHT=240\n    -D TFT_MOSI=23\n    -D TFT_SCLK=18\n    -D TFT_DC=2\n    -D TFT_RST=4\n    -D TFT_CS=-1\n    -D LOAD_GLCD\n    -D LOAD_FONT2\n    -D LOAD_FONT4\n    -D LOAD_FONT6\n    -D LOAD_FONT7\n    -D LOAD_FONT8\n    -D LOAD_GFXFF\n    -D SMOOTH_FONT\n    -D SPI_FREQUENCY=40000000\n    -D SPI_READ_FREQUENCY=20000000\n

For ST7735 (128x128):

build_flags = \n    -D ST7735_DRIVER\n    -D ST7735_GREENTAB3\n    -D TFT_WIDTH=128\n    -D TFT_HEIGHT=128\n    -D TFT_MOSI=23\n    -D TFT_SCLK=18\n    -D TFT_DC=2\n    -D TFT_RST=4\n    -D TFT_CS=-1\n    -D LOAD_GLCD\n    -D LOAD_FONT2\n    -D LOAD_FONT4\n    -D LOAD_FONT6\n    -D LOAD_FONT7\n    -D LOAD_FONT8\n    -D LOAD_GFXFF\n    -D SMOOTH_FONT\n    -D SPI_FREQUENCY=27000000\n    -D SPI_READ_FREQUENCY=20000000\n

Note: Adjust the pin numbers (TFT_MOSI, TFT_SCLK, TFT_DC, TFT_RST) to match your hardware wiring.

"},{"location":"getting_started/your_first_project/#configure-input-optional-for-first-project","title":"Configure Input (Optional for First Project)","text":"

If you have buttons connected, note the GPIO pins. For now, we'll create a project that works without input.

"},{"location":"getting_started/your_first_project/#configure-audio-optional-for-first-project","title":"Configure Audio (Optional for First Project)","text":"

Audio is optional for the first project. We'll add it later.

"},{"location":"getting_started/your_first_project/#step-4-create-your-first-scene","title":"Step 4: Create Your First Scene","text":"

Create a new file src/MyFirstScene.h:

#pragma once\n#include <core/Scene.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass MyFirstScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Called when the scene is initialized\n        // Set up your scene here\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Called every frame\n        // Update game logic here\n        Scene::update(deltaTime); // Don't forget to call parent update!\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Called every frame to draw\n        // Draw your scene here\n\n        // Example: Draw a simple rectangle\n        renderer.drawFilledRectangle(50, 50, 100, 100, pixelroot32::graphics::Color::Blue);\n\n        // Example: Draw text\n        renderer.drawText(\"Hello PixelRoot32!\", 20, 20, pixelroot32::graphics::Color::White, 2);\n\n        // Don't forget to call parent draw to draw all entities!\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"getting_started/your_first_project/#step-5-create-main-file-esp32","title":"Step 5: Create Main File (ESP32)","text":"

Replace the contents of src/main.cpp with:

#include <Arduino.h>\n#include <core/Engine.h>\n#include <drivers/esp32/TFT_eSPI_Drawer.h>\n#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n#include \"MyFirstScene.h\"\n\nnamespace pr32 = pixelroot32;\n\n// Audio configuration (optional - can be omitted for first project)\nconst int DAC_PIN = 25; // GPIO 25 or 26\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\n// Display configuration\n// 128x128 game logic scaled to 240x240 display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::ST7789, \n    0,      // rotation\n    240, 240, // physical resolution (hardware)\n    128, 128  // logical resolution (rendering space)\n);\n\n// Input configuration (6 buttons: UP, DOWN, LEFT, RIGHT, A, B)\n// For now, we'll use dummy pins - you can change these later\npr32::input::InputConfig inputConfig(\n    6,      // button count\n    32,     // UP pin\n    27,     // DOWN pin\n    33,     // LEFT pin\n    14,     // RIGHT pin\n    13,     // A button pin\n    12      // B button pin\n);\n\n// Audio configuration\npr32::audio::AudioConfig audioConfig(&audioBackend, audioBackend.getSampleRate());\n\n// Create the engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\n// Create your scene\nMyFirstScene myScene;\n\nvoid setup() {\n    Serial.begin(115200);\n\n    // Initialize the engine\n    engine.init();\n\n    // Initialize and set the scene\n    myScene.init();\n    engine.setScene(&myScene);\n\n    Serial.println(\"PixelRoot32 initialized!\");\n}\n\nvoid loop() {\n    // Run the game loop\n    engine.run();\n}\n
"},{"location":"getting_started/your_first_project/#step-6-create-native-version-optional","title":"Step 6: Create Native Version (Optional)","text":"

If you want to test on PC first, create src/main_native.cpp:

#define SDL_MAIN_HANDLED\n#include <SDL2/SDL.h>\n#include <core/Engine.h>\n#include <drivers/native/SDL2_Drawer.h>\n#include <drivers/native/SDL2_AudioBackend.h>\n#include \"MyFirstScene.h\"\n\nnamespace pr32 = pixelroot32;\n\n// Audio configuration\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\n\n// Display configuration (NONE defaults to SDL2 on Native)\n// 128x128 game logic scaled to 240x240 display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::NONE,\n    0,      // rotation\n    240, 240, // physical resolution\n    128, 128  // logical resolution\n);\n\n// Input configuration (SDL scancodes)\npr32::input::InputConfig inputConfig(\n    6,                      // button count\n    SDL_SCANCODE_UP,        // UP\n    SDL_SCANCODE_DOWN,      // DOWN\n    SDL_SCANCODE_LEFT,      // LEFT\n    SDL_SCANCODE_RIGHT,     // RIGHT\n    SDL_SCANCODE_SPACE,     // A button\n    SDL_SCANCODE_RETURN     // B button\n);\n\n// Audio configuration\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n\n// Create the engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\n// Create your scene\nMyFirstScene myScene;\n\nint main(int argc, char* argv[]) {\n    (void)argc;\n    (void)argv;\n\n    // Initialize the engine\n    engine.init();\n\n    // Initialize and set the scene\n    myScene.init();\n    engine.setScene(&myScene);\n\n    // Run the game loop\n    engine.run();\n\n    return 0;\n}\n
"},{"location":"getting_started/your_first_project/#configure-native-build","title":"Configure Native Build","text":"

Add to platformio.ini:

[env:native]\nplatform = native\nbuild_src_filter = \n    +<*>\n    -<main.cpp>\nlib_extra_dirs = lib\nbuild_flags = \n    -D PLATFORM_NATIVE\n    -Isrc\n    -Ilib/PixelRoot32-Game-Engine/include\n    -IC:/msys64/mingw64/include/SDL2    # Windows MSYS2 path - adjust for your system\n    -LC:/msys64/mingw64/lib             # Windows MSYS2 path - adjust for your system\n    -O2\n    -Wall\n    -Wextra\n    -std=c++17\n    -lSDL2\n    -mconsole\n

Note: Adjust the SDL2 include and library paths for your system.

"},{"location":"getting_started/your_first_project/#step-7-build-and-run","title":"Step 7: Build and Run","text":""},{"location":"getting_started/your_first_project/#for-esp32","title":"For ESP32","text":"
  1. Connect your ESP32 via USB
  2. Select the environment: Click on the PlatformIO icon \u2192 Select env:esp32dev
  3. Build: Click the checkmark icon (\u2713) or press Ctrl+Alt+B
  4. Upload: Click the arrow icon (\u2192) or press Ctrl+Alt+U
  5. Monitor: Click the plug icon to open serial monitor

You should see \"PixelRoot32 initialized!\" in the serial monitor and your display should show a blue rectangle and text.

"},{"location":"getting_started/your_first_project/#for-native-pc","title":"For Native (PC)","text":"
  1. Select the environment: Click on the PlatformIO icon \u2192 Select env:native
  2. Build and Run: Click the play icon (\u25b6) or press Ctrl+Alt+R

A window should open showing your scene with a blue rectangle and \"Hello PixelRoot32!\" text.

"},{"location":"getting_started/your_first_project/#step-8-verify-it-works","title":"Step 8: Verify It Works","text":"

If everything is set up correctly, you should see:

  • ESP32: Display shows a blue rectangle at (50, 50) and white text \"Hello PixelRoot32!\" at (20, 20)
  • Native: Window shows the same content

If you see this, congratulations! Your first PixelRoot32 project is working.

"},{"location":"getting_started/your_first_project/#troubleshooting","title":"Troubleshooting","text":""},{"location":"getting_started/your_first_project/#esp32-issues","title":"ESP32 Issues","text":"

Display is blank: - Check wiring connections - Verify pin numbers in platformio.ini match your hardware - Check SPI frequency (try lowering it) - Verify display type (ST7789 vs ST7735)

Compilation errors: - Ensure library version is exactly 0.2.0-dev - Check that TFT_eSPI is installed - Verify all include paths are correct

Upload fails: - Check USB cable connection - Try different USB port - Press BOOT button on ESP32 during upload - Check COM port in PlatformIO

"},{"location":"getting_started/your_first_project/#native-issues","title":"Native Issues","text":"

SDL2 not found: - Verify SDL2 is installed - Check include/library paths in platformio.ini - On Windows, ensure MSYS2 paths are correct

Window doesn't open: - Check console for error messages - Verify SDL2 is properly linked - Try running from terminal to see errors

"},{"location":"getting_started/your_first_project/#next-steps","title":"Next Steps","text":"

Now that you have a working project, you can:

  1. Learn about Scenes and Entities: See how to create game objects
  2. Add Input: Make your scene respond to buttons
  3. Add Sprites: Draw custom graphics
  4. Add Audio: Play sounds and music

Continue with the Development Guide to learn more.

See also: - Fundamental Concepts - Installation - Manual - Scenes and Entities - API Reference

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/","title":"Cameras and Scrolling","text":"

Camera2D allows you to create worlds larger than the screen by scrolling the view. This guide covers camera setup, following targets, boundaries, and parallax effects.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera2d-basics","title":"Camera2D Basics","text":"

A Camera2D defines what portion of your game world is visible on screen.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#creating-a-camera","title":"Creating a Camera","text":"
#include <graphics/Camera2D.h>\n\n// Create camera with viewport size\npixelroot32::graphics::Camera2D camera(240, 240); // Screen width, height\n\n// Set camera position\ncamera.setPosition(0, 0);\n\n// Apply camera to renderer (in draw method)\ncamera.apply(renderer);\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#how-it-works","title":"How It Works","text":"

The camera translates world coordinates to screen coordinates: - Objects at world position (100, 50) with camera at (0, 0) appear at screen (100, 50) - Objects at world position (100, 50) with camera at (50, 0) appear at screen (50, 50) - The camera effectively \"moves\" the world relative to the screen

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#following-a-target","title":"Following a Target","text":"

The most common use is following a player or other target.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#basic-follow","title":"Basic Follow","text":"
class GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        // Create camera\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n\n        // Create player\n        player = new PlayerActor(500, 300); // World position\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Make camera follow player\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera before drawing\n        camera.apply(renderer);\n\n        // Now all drawing uses camera coordinates\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#dead-zone-smooth-following","title":"Dead Zone (Smooth Following)","text":"

For smoother following, you can implement a dead zone where the camera doesn't move until the target leaves the zone:

void update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);\n\n    // Get screen center\n    int screenCenterX = engine.getRenderer().getWidth() / 2;\n    int screenCenterY = engine.getRenderer().getHeight() / 2;\n\n    // Calculate player position relative to screen center\n    float playerScreenX = player->x - camera.getX();\n    float playerScreenY = player->y - camera.getY();\n\n    // Dead zone size\n    const int DEAD_ZONE_X = 40;\n    const int DEAD_ZONE_Y = 40;\n\n    // Move camera if player leaves dead zone\n    if (playerScreenX < screenCenterX - DEAD_ZONE_X) {\n        camera.setPosition(player->x - (screenCenterX - DEAD_ZONE_X), camera.getY());\n    } else if (playerScreenX > screenCenterX + DEAD_ZONE_X) {\n        camera.setPosition(player->x - (screenCenterX + DEAD_ZONE_X), camera.getY());\n    }\n\n    if (playerScreenY < screenCenterY - DEAD_ZONE_Y) {\n        camera.setPosition(camera.getX(), player->y - (screenCenterY - DEAD_ZONE_Y));\n    } else if (playerScreenY > screenCenterY + DEAD_ZONE_Y) {\n        camera.setPosition(camera.getX(), player->y - (screenCenterY + DEAD_ZONE_Y));\n    }\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-boundaries","title":"Camera Boundaries","text":"

Limit camera movement to keep it within your level bounds.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#setting-boundaries","title":"Setting Boundaries","text":"
void init() override {\n    // Create camera\n    camera = pixelroot32::graphics::Camera2D(240, 240);\n\n    // Set horizontal boundaries (level is 2000 pixels wide)\n    camera.setBounds(0, 2000 - 240); // minX, maxX\n\n    // Set vertical boundaries (level is 1000 pixels tall)\n    camera.setVerticalBounds(0, 1000 - 240); // minY, maxY\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#example-side-scroller-with-boundaries","title":"Example: Side-Scroller with Boundaries","text":"
class SideScrollerScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n    static const int LEVEL_WIDTH = 2000;\n    static const int LEVEL_HEIGHT = 240;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n\n        // Set boundaries (camera can't go outside level)\n        camera.setBounds(0, LEVEL_WIDTH - screenWidth);\n        camera.setVerticalBounds(0, LEVEL_HEIGHT - screenHeight);\n\n        // Create player at start\n        player = new PlayerActor(100, 100);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Follow player horizontally\n        camera.followTarget(player->x, camera.getY());\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#parallax-scrolling","title":"Parallax Scrolling","text":"

Parallax creates depth by moving background layers at different speeds.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#basic-parallax","title":"Basic Parallax","text":"
class ParallaxBackground : public pixelroot32::core::Entity {\nprivate:\n    float parallaxSpeed; // 0.0 to 1.0 (1.0 = normal, 0.5 = half speed)\n    float baseX;\n\npublic:\n    ParallaxBackground(float speed)\n        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::GENERIC),\n          parallaxSpeed(speed), baseX(0) {\n        setRenderLayer(0);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Get camera position\n        auto& camera = getCamera(); // You'll need to pass camera reference\n\n        // Calculate parallax offset\n        baseX = camera.getX() * parallaxSpeed;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background with parallax offset\n        renderer.drawTileMap(backgroundTileMap, \n            static_cast<int>(baseX), 0, \n            pixelroot32::graphics::Color::White);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#multiple-parallax-layers","title":"Multiple Parallax Layers","text":"
class ParallaxScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n\n    // Parallax layers (farther = slower)\n    ParallaxLayer* farBackground;    // Speed: 0.2\n    ParallaxLayer* midBackground;      // Speed: 0.5\n    ParallaxLayer* nearBackground;     // Speed: 0.8\n    PlayerActor* player;               // Speed: 1.0 (normal)\n\npublic:\n    void init() override {\n        camera = pixelroot32::graphics::Camera2D(240, 240);\n\n        // Create parallax layers\n        farBackground = new ParallaxLayer(0.2f);  // Moves slowest\n        midBackground = new ParallaxLayer(0.5f);\n        nearBackground = new ParallaxLayer(0.8f);\n\n        addEntity(farBackground);\n        addEntity(midBackground);\n        addEntity(nearBackground);\n\n        player = new PlayerActor(100, 100);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Update parallax layers with camera position\n        farBackground->updateParallax(camera.getX());\n        midBackground->updateParallax(camera.getX());\n        nearBackground->updateParallax(camera.getX());\n\n        // Follow player\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#using-setdisplayoffset-for-parallax","title":"Using setDisplayOffset for Parallax","text":"

For simpler parallax, you can use setDisplayOffset():

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera\n    camera.apply(renderer);\n\n    // Draw far background with offset (moves slower)\n    renderer.setDisplayOffset(\n        static_cast<int>(camera.getX() * 0.3f), \n        0\n    );\n    renderer.drawTileMap(farBackground, 0, 0, Color::White);\n\n    // Draw mid background\n    renderer.setDisplayOffset(\n        static_cast<int>(camera.getX() * 0.6f), \n        0\n    );\n    renderer.drawTileMap(midBackground, 0, 0, Color::White);\n\n    // Reset offset for normal drawing\n    renderer.setDisplayOffset(0, 0);\n\n    // Draw game objects (normal speed)\n    Scene::draw(renderer);\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#complete-example-platformer-with-camera","title":"Complete Example: Platformer with Camera","text":"
class PlatformerScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n    static const int LEVEL_WIDTH = 3000;\n    static const int LEVEL_HEIGHT = 800;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        // Create camera\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n\n        // Set boundaries\n        camera.setBounds(0, LEVEL_WIDTH - screenWidth);\n        camera.setVerticalBounds(0, LEVEL_HEIGHT - screenHeight);\n\n        // Create player\n        player = new PlayerActor(100, 400);\n        addEntity(player);\n\n        // Create platforms, enemies, etc.\n        // ...\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Follow player with dead zone\n        int screenCenterX = engine.getRenderer().getWidth() / 2;\n        int screenCenterY = engine.getRenderer().getHeight() / 2;\n\n        float playerScreenX = player->x - camera.getX();\n        float playerScreenY = player->y - camera.getY();\n\n        const int DEAD_ZONE = 60;\n\n        // Horizontal follow\n        if (playerScreenX < screenCenterX - DEAD_ZONE) {\n            camera.setPosition(player->x - (screenCenterX - DEAD_ZONE), camera.getY());\n        } else if (playerScreenX > screenCenterX + DEAD_ZONE) {\n            camera.setPosition(player->x - (screenCenterX + DEAD_ZONE), camera.getY());\n        }\n\n        // Vertical follow (only when falling or jumping high)\n        if (playerScreenY < screenCenterY - DEAD_ZONE || \n            playerScreenY > screenCenterY + DEAD_ZONE) {\n            camera.setPosition(camera.getX(), player->y - screenCenterY);\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw background (parallax)\n        renderer.setDisplayOffset(\n            static_cast<int>(camera.getX() * 0.3f), \n            0\n        );\n        renderer.drawTileMap(backgroundTileMap, 0, 0, Color::DarkGray);\n        renderer.setDisplayOffset(0, 0);\n\n        // Draw game objects\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-movement","title":"Camera Movement","text":"
  • Use dead zones: Prevents jittery camera movement
  • Smooth transitions: Consider lerping camera position for smoother movement
  • Set boundaries: Always limit camera to level bounds
  • Test on hardware: Camera performance may differ on ESP32
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#parallax","title":"Parallax","text":"
  • Layer speeds: Farther layers move slower (0.2-0.5), closer move faster (0.7-0.9)
  • Limit layers: Too many parallax layers can impact performance
  • Use tilemaps: Parallax works best with tilemaps
  • Test visually: Ensure parallax effect is noticeable but not distracting
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#performance","title":"Performance","text":"
  • Apply once: Call camera.apply() once per frame, at start of draw()
  • Cull off-screen: Don't draw entities outside camera view
  • Limit parallax layers: 2-3 layers is usually enough
  • Optimize tilemaps: Use efficient tilemap rendering
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-helper-class","title":"Camera Helper Class","text":"
class CameraController {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    float targetX, targetY;\n    float smoothSpeed = 0.1f;\n\npublic:\n    void followTarget(float x, float y) {\n        targetX = x;\n        targetY = y;\n    }\n\n    void update(unsigned long deltaTime) {\n        // Smooth camera movement\n        float currentX = camera.getX();\n        float currentY = camera.getY();\n\n        float newX = currentX + (targetX - currentX) * smoothSpeed;\n        float newY = currentY + (targetY - currentY) * smoothSpeed;\n\n        camera.setPosition(newX, newY);\n    }\n\n    void apply(pixelroot32::graphics::Renderer& renderer) {\n        camera.apply(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#viewport-culling","title":"Viewport Culling","text":"

Only draw entities within camera view:

bool isVisible(float x, float y, int width, int height) {\n    float cameraX = camera.getX();\n    float cameraY = camera.getY();\n    int screenWidth = engine.getRenderer().getWidth();\n    int screenHeight = engine.getRenderer().getHeight();\n\n    return !(x + width < cameraX || \n             x > cameraX + screenWidth ||\n             y + height < cameraY || \n             y > cameraY + screenHeight);\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-not-moving","title":"Camera Not Moving","text":"
  • Verify camera.apply() is called in draw()
  • Check followTarget() or setPosition() is called in update()
  • Ensure camera is created with correct viewport size
  • Check boundaries aren't preventing movement
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#objects-not-visible","title":"Objects Not Visible","text":"
  • Verify objects are within camera view
  • Check world coordinates vs screen coordinates
  • Ensure camera is applied before drawing
  • Verify render layers are correct
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#parallax-not-working","title":"Parallax Not Working","text":"
  • Check setDisplayOffset() is used correctly
  • Verify parallax speed values (0.0 to 1.0)
  • Ensure offset is reset after parallax layers
  • Test with different speed values
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#next-steps","title":"Next Steps","text":"

Now that you understand cameras and scrolling, learn about: - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects - Performance Optimization - Optimize your game

See also: - API Reference - Camera2D - Manual - Basic Rendering - Manual - Tilemaps

"},{"location":"manual/advanced_graphics/color_palettes/","title":"Color Palettes","text":"

PixelRoot32 uses a palette-based color system that allows you to easily change the visual style of your game. This guide covers built-in palettes, dual palette mode, and custom palettes.

"},{"location":"manual/advanced_graphics/color_palettes/#built-in-palettes","title":"Built-in Palettes","text":"

PixelRoot32 includes several predefined palettes inspired by classic gaming systems:

"},{"location":"manual/advanced_graphics/color_palettes/#available-palettes","title":"Available Palettes","text":"
#include <graphics/PaletteDefs.h>\n\nnamespace pixelroot32::graphics {\n\nenum class PaletteType {\n    PR32,    // PixelRoot32 default palette\n    NES,     // Nintendo Entertainment System\n    GB,      // GameBoy (4 shades of green)\n    GBC,     // GameBoy Color\n    PICO8    // PICO-8 palette\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#using-built-in-palettes","title":"Using Built-in Palettes","text":"
#include <graphics/PaletteDefs.h>\n\n// Set palette globally (legacy mode)\npixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n\n// All sprites will now use NES colors\nrenderer.drawSprite(MY_SPRITE, 100, 100, pixelroot32::graphics::Color::White);\n
"},{"location":"manual/advanced_graphics/color_palettes/#palette-characteristics","title":"Palette Characteristics","text":"

PR32 (Default) - Modern, balanced colors - Good contrast - Suitable for most games

NES - Classic 8-bit console colors - Limited color range - Nostalgic feel

GB (GameBoy) - 4 shades of green - Monochrome aesthetic - Classic handheld look

GBC (GameBoy Color) - Expanded color range - More vibrant than GB - Classic portable console

PICO8 - PICO-8 fantasy console palette - 16 carefully chosen colors - Popular for retro games

"},{"location":"manual/advanced_graphics/color_palettes/#legacy-mode-single-global-palette","title":"Legacy Mode (Single Global Palette)","text":"

In legacy mode, one palette is used for all sprites:

void MyScene::init() override {\n    // Set global palette\n    pixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n\n    // All sprites use NES colors\n    // This is the simplest mode\n}\n

When to use: - Simple games - Consistent visual style - Maximum compatibility

"},{"location":"manual/advanced_graphics/color_palettes/#dual-palette-mode","title":"Dual Palette Mode","text":"

Dual palette mode allows different palettes for background elements and sprites, creating visual contrast.

"},{"location":"manual/advanced_graphics/color_palettes/#enabling-dual-palette-mode","title":"Enabling Dual Palette Mode","text":"
#include <graphics/PaletteDefs.h>\n\nvoid MyScene::init() override {\n    // Enable dual palette mode\n    pixelroot32::graphics::enableDualPaletteMode();\n\n    // Set background palette\n    pixelroot32::graphics::setBackgroundPalette(\n        pixelroot32::graphics::PaletteType::GB\n    );\n\n    // Set sprite palette\n    pixelroot32::graphics::setSpritePalette(\n        pixelroot32::graphics::PaletteType::NES\n    );\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#how-it-works","title":"How It Works","text":"
  • Background palette: Used for tilemaps, primitives, and background sprites
  • Sprite palette: Used for game objects, characters, and foreground sprites
  • Automatic context: The renderer automatically selects the correct palette based on what you're drawing
"},{"location":"manual/advanced_graphics/color_palettes/#example-contrasting-styles","title":"Example: Contrasting Styles","text":"
void MyScene::init() override {\n    pixelroot32::graphics::enableDualPaletteMode();\n\n    // Dark, muted background (GameBoy green)\n    pixelroot32::graphics::setBackgroundPalette(\n        pixelroot32::graphics::PaletteType::GB\n    );\n\n    // Bright, colorful sprites (NES)\n    pixelroot32::graphics::setSpritePalette(\n        pixelroot32::graphics::PaletteType::NES\n    );\n\n    // Background uses GB palette\n    renderer.drawTileMap(backgroundTileMap, 0, 0, \n        pixelroot32::graphics::Color::White);\n\n    // Sprites use NES palette\n    renderer.drawSprite(playerSprite, 100, 100, \n        pixelroot32::graphics::Color::White);\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#when-to-use-dual-palette-mode","title":"When to Use Dual Palette Mode","text":"
  • Visual contrast: Make sprites stand out from background
  • Artistic style: Different palettes for different layers
  • Retro aesthetics: Classic console color separation
  • Performance: No performance impact, just visual variety
"},{"location":"manual/advanced_graphics/color_palettes/#custom-palettes","title":"Custom Palettes","text":"

Create your own color palettes for unique visual styles.

"},{"location":"manual/advanced_graphics/color_palettes/#creating-a-custom-palette","title":"Creating a Custom Palette","text":"
#include <graphics/PaletteDefs.h>\n#include <graphics/Color.h>\n\n// Define custom colors (RGB565 format)\nstatic const pixelroot32::graphics::Color CUSTOM_PALETTE[] = {\n    pixelroot32::graphics::Color::Black,      // 0: Transparent/background\n    pixelroot32::graphics::Color::DarkBlue,   // 1\n    pixelroot32::graphics::Color::Blue,       // 2\n    pixelroot32::graphics::Color::LightBlue, // 3\n    pixelroot32::graphics::Color::Cyan,      // 4\n    pixelroot32::graphics::Color::White,      // 5\n    // ... more colors\n};\n\n// Set custom palette\npixelroot32::graphics::setCustomPalette(\n    CUSTOM_PALETTE,\n    sizeof(CUSTOM_PALETTE) / sizeof(pixelroot32::graphics::Color)\n);\n
"},{"location":"manual/advanced_graphics/color_palettes/#rgb565-color-format","title":"RGB565 Color Format","text":"

Colors in PixelRoot32 use RGB565 format (16-bit):

// RGB565: 5 bits red, 6 bits green, 5 bits blue\n// Format: RRRRR GGGGGG BBBBB\n\n// Create custom RGB565 color\nuint16_t myColor = (31 << 11) | (63 << 5) | 31; // White\nuint16_t myColor = (0 << 11) | (0 << 5) | 0;    // Black\nuint16_t myColor = (31 << 11) | (0 << 5) | 0;   // Red\n\n// Or use Color constants\npixelroot32::graphics::Color::Red\npixelroot32::graphics::Color::Green\npixelroot32::graphics::Color::Blue\n
"},{"location":"manual/advanced_graphics/color_palettes/#helper-function-for-custom-colors","title":"Helper Function for Custom Colors","text":"
// Create RGB565 color from RGB values (0-255)\nuint16_t rgb565(uint8_t r, uint8_t g, uint8_t b) {\n    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\n}\n\n// Usage\nstatic const pixelroot32::graphics::Color MY_PALETTE[] = {\n    rgb565(0, 0, 0),        // Black\n    rgb565(255, 0, 0),      // Red\n    rgb565(0, 255, 0),      // Green\n    rgb565(0, 0, 255),      // Blue\n    rgb565(255, 255, 255),  // White\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#complete-custom-palette-example","title":"Complete Custom Palette Example","text":"
class CustomPaletteScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Define custom palette (ocean theme)\n        static const pixelroot32::graphics::Color OCEAN_PALETTE[] = {\n            pixelroot32::graphics::Color::Black,      // 0: Deep ocean\n            pixelroot32::graphics::Color::Navy,        // 1: Dark blue\n            pixelroot32::graphics::Color::Blue,       // 2: Medium blue\n            pixelroot32::graphics::Color::Cyan,       // 3: Light blue\n            pixelroot32::graphics::Color::LightBlue, // 4: Surface\n            pixelroot32::graphics::Color::White,      // 5: Foam\n        };\n\n        // Set custom palette\n        pixelroot32::graphics::setCustomPalette(\n            OCEAN_PALETTE,\n            sizeof(OCEAN_PALETTE) / sizeof(pixelroot32::graphics::Color)\n        );\n\n        // Now all sprites use the ocean palette\n    }\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#color-constants","title":"Color Constants","text":"

PixelRoot32 provides predefined color constants:

namespace pixelroot32::graphics {\n    Color::Black\n    Color::White\n    Color::Red\n    Color::Green\n    Color::Blue\n    Color::Yellow\n    Color::Cyan\n    Color::Magenta\n    Color::DarkGray\n    Color::LightGray\n    Color::Navy\n    Color::DarkGreen\n    Color::DarkRed\n    Color::Brown\n    Color::Purple\n    Color::Orange\n    Color::Pink\n    Color::Gold\n    Color::LightBlue\n    Color::LightGreen\n    Color::LightRed\n    Color::Transparent\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/color_palettes/#palette-selection","title":"Palette Selection","text":"
  • Match game style: Choose palette that fits your game's theme
  • Test on hardware: Colors may look different on ESP32 display
  • Consider contrast: Ensure sprites are visible against background
  • Consistency: Stick with one palette per scene (or use dual mode)
"},{"location":"manual/advanced_graphics/color_palettes/#dual-palette-mode_1","title":"Dual Palette Mode","text":"
  • Use sparingly: Not all games need dual palettes
  • Test combinations: Some palette combinations work better than others
  • Clear separation: Use for clear visual distinction between layers
  • Performance: No performance cost, use freely
"},{"location":"manual/advanced_graphics/color_palettes/#custom-palettes_1","title":"Custom Palettes","text":"
  • Limit colors: Keep palette size reasonable (8-16 colors)
  • Plan ahead: Design palette before creating sprites
  • Test thoroughly: Verify colors work well together
  • Document: Comment your palette choices
"},{"location":"manual/advanced_graphics/color_palettes/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/color_palettes/#palette-switching","title":"Palette Switching","text":"
class GameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Set initial palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::NES\n        );\n    }\n\n    void changeToNightMode() {\n        // Switch to darker palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::GB\n        );\n    }\n\n    void changeToDayMode() {\n        // Switch to brighter palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::PICO8\n        );\n    }\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#theme-based-palettes","title":"Theme-Based Palettes","text":"
namespace GamePalettes {\n    // Forest theme\n    static const pixelroot32::graphics::Color FOREST[] = {\n        Color::Black,\n        Color::DarkGreen,\n        Color::Green,\n        Color::LightGreen,\n        Color::Brown,\n        Color::Yellow\n    };\n\n    // Desert theme\n    static const pixelroot32::graphics::Color DESERT[] = {\n        Color::Black,\n        Color::Brown,\n        Color::Yellow,\n        Color::Gold,\n        Color::Orange,\n        Color::White\n    };\n\n    // Ocean theme\n    static const pixelroot32::graphics::Color OCEAN[] = {\n        Color::Black,\n        Color::Navy,\n        Color::Blue,\n        Color::Cyan,\n        Color::LightBlue,\n        Color::White\n    };\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/color_palettes/#colors-not-changing","title":"Colors Not Changing","text":"
  • Verify setPalette() is called before drawing
  • Check palette is set in init(), not update()
  • Ensure dual palette mode is enabled if using separate palettes
  • Verify Color constants are from correct namespace
"},{"location":"manual/advanced_graphics/color_palettes/#colors-look-wrong-on-hardware","title":"Colors Look Wrong on Hardware","text":"
  • ESP32 displays may render colors differently
  • Test on actual hardware, not just PC
  • Adjust palette colors if needed
  • Consider display calibration
"},{"location":"manual/advanced_graphics/color_palettes/#dual-palette-not-working","title":"Dual Palette Not Working","text":"
  • Ensure enableDualPaletteMode() is called first
  • Verify both palettes are set
  • Check that you're drawing in correct context
  • Review renderer documentation
"},{"location":"manual/advanced_graphics/color_palettes/#next-steps","title":"Next Steps","text":"

Now that you understand palettes, learn about: - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects

See also: - API Reference - PaletteDefs - API Reference - Color - Manual - Basic Rendering

"},{"location":"manual/advanced_graphics/particles_and_effects/","title":"Particles and Effects","text":"

The particle system allows you to create visual effects like fire, explosions, smoke, and sparks. This guide covers ParticleEmitter, ParticleConfig, and the included presets.

"},{"location":"manual/advanced_graphics/particles_and_effects/#particleemitter-basics","title":"ParticleEmitter Basics","text":"

A ParticleEmitter is an Entity that manages a pool of particles to create visual effects.

"},{"location":"manual/advanced_graphics/particles_and_effects/#creating-a-particle-emitter","title":"Creating a Particle Emitter","text":"
#include <graphics/particles/ParticleEmitter.h>\n#include <graphics/particles/ParticleConfig.h>\n\n// Create particle configuration\npixelroot32::graphics::particles::ParticleConfig config;\nconfig.startColor = pixelroot32::graphics::Color::Red;\nconfig.endColor = pixelroot32::graphics::Color::Yellow;\nconfig.lifetime = 1.0f; // 1 second\nconfig.speed = 50.0f;\nconfig.gravity = -100.0f; // Upward (negative = up)\n\n// Create emitter\npixelroot32::graphics::particles::ParticleEmitter* emitter = \n    new pixelroot32::graphics::particles::ParticleEmitter(100, 100, config);\n\n// Add to scene\naddEntity(emitter);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#emitting-particles","title":"Emitting Particles","text":"
// Emit a burst of particles\nemitter->burst(100, 100, 10); // x, y, particle count\n\n// Particles will automatically update and draw\n// No additional code needed!\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#particleconfig","title":"ParticleConfig","text":"

ParticleConfig defines how particles behave:

#include <graphics/particles/ParticleConfig.h>\n\npixelroot32::graphics::particles::ParticleConfig config;\n\n// Colors\nconfig.startColor = pixelroot32::graphics::Color::Red;   // Color at spawn\nconfig.endColor = pixelroot32::graphics::Color::Yellow;  // Color at death\n\n// Lifetime\nconfig.lifetime = 0.5f; // Duration in seconds\n\n// Velocity\nconfig.speed = 100.0f;           // Base speed\nconfig.speedVariation = 20.0f;   // Random variation\nconfig.direction = 90.0f;        // Direction in degrees (0 = right, 90 = up)\nconfig.directionVariation = 45.0f; // Random direction spread\n\n// Physics\nconfig.gravity = 200.0f;  // Gravity force (positive = down)\nconfig.friction = 0.95f;   // Friction (0.0 to 1.0, 1.0 = no friction)\n\n// Size\nconfig.startSize = 2;     // Size at spawn (pixels)\nconfig.endSize = 1;       // Size at death\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#complete-config-example","title":"Complete Config Example","text":"
pixelroot32::graphics::particles::ParticleConfig fireConfig;\n\n// Fire colors (red to yellow)\nfireConfig.startColor = pixelroot32::graphics::Color::Red;\nfireConfig.endColor = pixelroot32::graphics::Color::Yellow;\n\n// Short lifetime\nfireConfig.lifetime = 0.3f;\n\n// Upward movement with variation\nfireConfig.speed = 80.0f;\nfireConfig.speedVariation = 30.0f;\nfireConfig.direction = 90.0f; // Up\nfireConfig.directionVariation = 30.0f; // Spread\n\n// Upward gravity (negative)\nfireConfig.gravity = -50.0f;\n\n// Slight friction\nfireConfig.friction = 0.98f;\n\n// Size\nfireConfig.startSize = 3;\nfireConfig.endSize = 1;\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#built-in-presets","title":"Built-in Presets","text":"

PixelRoot32 includes several particle presets for common effects:

"},{"location":"manual/advanced_graphics/particles_and_effects/#fire","title":"Fire","text":"
#include <graphics/particles/ParticlePresets.h>\n\n// Create fire emitter\npixelroot32::graphics::particles::ParticleEmitter* fire = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Fire()\n    );\n\n// Emit continuous fire\nvoid update(unsigned long deltaTime) override {\n    fire->burst(100, 100, 2); // Emit 2 particles per frame\n    Scene::update(deltaTime);\n}\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#explosion","title":"Explosion","text":"
// Create explosion emitter\npixelroot32::graphics::particles::ParticleEmitter* explosion = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Explosion()\n    );\n\n// Emit explosion burst\nexplosion->burst(100, 100, 20); // 20 particles at once\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#sparks","title":"Sparks","text":"
// Create sparks emitter\npixelroot32::graphics::particles::ParticleEmitter* sparks = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Sparks()\n    );\n\n// Emit sparks\nsparks->burst(100, 100, 10);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#smoke","title":"Smoke","text":"
// Create smoke emitter\npixelroot32::graphics::particles::ParticleEmitter* smoke = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Smoke()\n    );\n\n// Emit smoke\nsmoke->burst(100, 100, 3);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#dust","title":"Dust","text":"
// Create dust emitter\npixelroot32::graphics::particles::ParticleEmitter* dust = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Dust()\n    );\n\n// Emit dust\ndust->burst(100, 100, 5);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#complete-example-explosion-effect","title":"Complete Example: Explosion Effect","text":"
#include <core/Scene.h>\n#include <graphics/particles/ParticleEmitter.h>\n#include <graphics/particles/ParticlePresets.h>\n\nclass ExplosionEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* explosion;\n    bool active = false;\n\npublic:\n    ExplosionEffect()\n        : Entity(0, 0, 1, 1, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n\n        // Create explosion emitter\n        explosion = new pixelroot32::graphics::particles::ParticleEmitter(\n            0, 0,\n            pixelroot32::graphics::particles::ParticlePresets::Explosion()\n        );\n    }\n\n    void trigger(float x, float y) {\n        active = true;\n        this->x = x;\n        this->y = y;\n\n        // Emit explosion burst\n        explosion->burst(x, y, 25);\n    }\n\n    void update(unsigned long deltaTime) override {\n        explosion->update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        explosion->draw(renderer);\n    }\n};\n\n// Usage in scene\nvoid MyScene::init() override {\n    explosionEffect = new ExplosionEffect();\n    addEntity(explosionEffect);\n}\n\nvoid MyScene::update(unsigned long deltaTime) override {\n    auto& input = engine.getInputManager();\n\n    // Trigger explosion on button press\n    if (input.isButtonPressed(4)) { // Button A\n        explosionEffect->trigger(player->x, player->y);\n    }\n\n    Scene::update(deltaTime);\n}\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#continuous-effects","title":"Continuous Effects","text":"

For continuous effects like fire or smoke:

class FireEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* fire;\n    unsigned long emitTimer = 0;\n    const unsigned long EMIT_INTERVAL_MS = 50; // Emit every 50ms\n\npublic:\n    FireEffect(float x, float y)\n        : Entity(x, y, 1, 1, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n\n        fire = new pixelroot32::graphics::particles::ParticleEmitter(\n            x, y,\n            pixelroot32::graphics::particles::ParticlePresets::Fire()\n        );\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Emit particles continuously\n        emitTimer += deltaTime;\n        if (emitTimer >= EMIT_INTERVAL_MS) {\n            emitTimer -= EMIT_INTERVAL_MS;\n            fire->burst(x, y, 2); // 2 particles per interval\n        }\n\n        fire->update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        fire->draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#custom-particle-effects","title":"Custom Particle Effects","text":"

Create your own particle effects by customizing ParticleConfig:

"},{"location":"manual/advanced_graphics/particles_and_effects/#magic-spell-effect","title":"Magic Spell Effect","text":"
pixelroot32::graphics::particles::ParticleConfig magicConfig;\n\n// Magical colors (purple to cyan)\nmagicConfig.startColor = pixelroot32::graphics::Color::Purple;\nmagicConfig.endColor = pixelroot32::graphics::Color::Cyan;\n\n// Medium lifetime\nmagicConfig.lifetime = 0.8f;\n\n// Outward spread\nmagicConfig.speed = 60.0f;\nmagicConfig.speedVariation = 20.0f;\nmagicConfig.direction = 0.0f; // Right\nmagicConfig.directionVariation = 360.0f; // Full circle\n\n// Slight upward float\nmagicConfig.gravity = -30.0f;\n\n// Low friction (floaty)\nmagicConfig.friction = 0.92f;\n\n// Size\nmagicConfig.startSize = 2;\nmagicConfig.endSize = 1;\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#rain-effect","title":"Rain Effect","text":"
pixelroot32::graphics::particles::ParticleConfig rainConfig;\n\n// Rain color (light blue)\nrainConfig.startColor = pixelroot32::graphics::Color::LightBlue;\nrainConfig.endColor = pixelroot32::graphics::Color::LightBlue;\n\n// Long lifetime\nrainConfig.lifetime = 2.0f;\n\n// Downward movement\nrainConfig.speed = 150.0f;\nrainConfig.speedVariation = 20.0f;\nrainConfig.direction = 270.0f; // Down\nrainConfig.directionVariation = 5.0f; // Slight angle variation\n\n// Downward gravity\nrainConfig.gravity = 200.0f;\n\n// No friction\nrainConfig.friction = 1.0f;\n\n// Small size\nrainConfig.startSize = 1;\nrainConfig.endSize = 1;\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/particles_and_effects/#performance","title":"Performance","text":"
  • Limit particle count: Each emitter has MAX_PARTICLES_PER_EMITTER (50)
  • Reuse emitters: Don't create new emitters every frame
  • Disable when not visible: Set isVisible = false when off-screen
  • Limit active emitters: Too many emitters can impact performance
"},{"location":"manual/advanced_graphics/particles_and_effects/#visual-design","title":"Visual Design","text":"
  • Match game style: Particle effects should fit your game's aesthetic
  • Use appropriate colors: Match particle colors to game palette
  • Test on hardware: ESP32 may render particles differently
  • Keep it simple: Simple effects often look better than complex ones
"},{"location":"manual/advanced_graphics/particles_and_effects/#timing","title":"Timing","text":"
  • Burst timing: Space out bursts for better visual effect
  • Continuous effects: Use timers to control emission rate
  • Lifetime: Adjust lifetime to match effect duration
  • Cleanup: Particles automatically clean up when lifetime expires
"},{"location":"manual/advanced_graphics/particles_and_effects/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/particles_and_effects/#one-shot-effect","title":"One-Shot Effect","text":"
class OneShotEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* emitter;\n    bool hasEmitted = false;\n\npublic:\n    void trigger(float x, float y) {\n        if (!hasEmitted) {\n            emitter->burst(x, y, 20);\n            hasEmitted = true;\n        }\n    }\n\n    void reset() {\n        hasEmitted = false;\n    }\n};\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#attached-effect","title":"Attached Effect","text":"
class AttachedParticleEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* emitter;\n    pixelroot32::core::Actor* target;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        // Update emitter position to follow target\n        emitter->x = target->x;\n        emitter->y = target->y;\n\n        // Emit particles\n        emitter->burst(target->x, target->y, 1);\n\n        emitter->update(deltaTime);\n    }\n};\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/particles_and_effects/#particles-not-appearing","title":"Particles Not Appearing","text":"
  • Verify emitter is added to scene
  • Check particle config is valid
  • Ensure burst() is being called
  • Verify emitter position is on-screen
"},{"location":"manual/advanced_graphics/particles_and_effects/#performance-issues","title":"Performance Issues","text":"
  • Reduce particle count per burst
  • Limit number of active emitters
  • Use simpler particle configs
  • Disable emitters when not visible
"},{"location":"manual/advanced_graphics/particles_and_effects/#particles-not-moving","title":"Particles Not Moving","text":"
  • Check gravity value (positive = down, negative = up)
  • Verify speed is not 0
  • Check friction isn't too high (1.0 = no movement)
  • Ensure direction is correct (degrees: 0=right, 90=up, 180=left, 270=down)
"},{"location":"manual/advanced_graphics/particles_and_effects/#next-steps","title":"Next Steps","text":"

Now that you understand particles, you've completed the advanced graphics section. Continue with: - Performance Optimization - Optimize your game - Memory Management - Manage memory efficiently - API Reference - Complete API documentation

See also: - API Reference - ParticleEmitter - API Reference - ParticleConfig - API Reference - ParticlePresets - Manual - Basic Rendering

"},{"location":"manual/advanced_graphics/resolution_scaling/","title":"Resolution Scaling","text":"

PixelRoot32 features a powerful Independent Resolution Scaling system. This allows the engine to render internally at a lower resolution (Logical Resolution) and then scale the final image to the display's actual hardware resolution (Physical Resolution).

"},{"location":"manual/advanced_graphics/resolution_scaling/#why-use-resolution-scaling","title":"Why use Resolution Scaling?","text":"

On microcontrollers like the ESP32, memory and processing power are limited. Rendering at a full 240x240 resolution consumes significant RAM and CPU cycles for every pixel drawn.

By using a lower logical resolution (e.g., 128x128): 1. Memory Savings: A 128x128 8bpp buffer uses ~16KB, while 240x240 uses ~57KB (72% reduction). 2. Performance Boost: Fewer pixels to process means more complex scenes and higher FPS. 3. Retro Aesthetic: Nearest-neighbor scaling preserves the pixel-art look perfectly.

"},{"location":"manual/advanced_graphics/resolution_scaling/#logical-vs-physical-resolution","title":"Logical vs Physical Resolution","text":"
  • Logical Resolution: The virtual canvas where your game logic, sprites, and UI are drawn.
  • Physical Resolution: The actual pixel dimensions of your hardware display.
flowchart LR\n    subgraph Logical [Logical Resolution 128x128]\n        A[Game Logic] --> B[Renderer API]\n        B --> C[Internal Framebuffer]\n    end\n\n    subgraph Scaling [Hardware Scaling]\n        C --> D[Nearest Neighbor Scaler]\n    end\n\n    subgraph Physical [Physical Display 240x240]\n        D --> E[SPI/DMA Transfer]\n        E --> F[LCD Hardware]\n    end
"},{"location":"manual/advanced_graphics/resolution_scaling/#configuration","title":"Configuration","text":""},{"location":"manual/advanced_graphics/resolution_scaling/#using-presets","title":"Using Presets","text":"

The easiest way to configure scaling is using the ResolutionPresets helper.

#include <graphics/ResolutionPresets.h>\n\n// Create a config for 128x128 logical resolution scaled to 240x240 physical\nauto config = pr32::graphics::ResolutionPresets::create(\n    pr32::graphics::RES_128x128,\n    pr32::graphics::ST7789\n);\n
"},{"location":"manual/advanced_graphics/resolution_scaling/#manual-configuration","title":"Manual Configuration","text":"

You can also specify custom dimensions in the DisplayConfig constructor.

pr32::graphics::DisplayConfig config(\n    pr32::graphics::ST7789, // Driver\n    0,                      // Rotation\n    240, 240,               // Physical Width, Physical Height\n    160, 160                // Logical Width, Logical Height\n);\n
"},{"location":"manual/advanced_graphics/resolution_scaling/#performance-impact","title":"Performance Impact","text":"

The following table shows estimated savings on an ESP32 for a standard 240x240 display:

Logical Resolution Memory (8bpp) RAM Savings FPS Gain (est.) 240x240 (Full) 57.6 KB 0% Baseline 160x160 25.6 KB ~55% +30% 128x128 16.4 KB ~72% +60% 96x96 9.2 KB ~84% +100%"},{"location":"manual/advanced_graphics/resolution_scaling/#implementation-details","title":"Implementation Details","text":""},{"location":"manual/advanced_graphics/resolution_scaling/#nearest-neighbor-scaling","title":"Nearest Neighbor Scaling","text":"

The engine uses a Nearest Neighbor algorithm optimized for ESP32. It avoids floating-point math by using pre-calculated Lookup Tables (LUTs).

"},{"location":"manual/advanced_graphics/resolution_scaling/#on-the-fly-scaling","title":"On-the-fly Scaling","text":"

To save even more RAM, the engine does not maintain a physical-sized buffer. Instead, it scales the image line-by-line during the SPI DMA transfer. This means the only large buffer in memory is the small logical one.

"},{"location":"manual/advanced_graphics/resolution_scaling/#profiling","title":"Profiling","text":"

You can measure the performance of the scaling system by enabling the Debug Statistics Overlay. This provides real-time data on FPS, CPU load, and RAM usage directly on the screen.

See Engine - Debug Overlay for instructions on how to enable it.

Alternatively, you can enable low-level profiling in EngineConfig.h:

#define PIXELROOT32_ENABLE_PROFILING\n

This will output the time taken for scaling and transfer to the Serial monitor: [PROFILING] Scaled Transfer: 12450 us (80 FPS max)

"},{"location":"manual/advanced_graphics/resolution_scaling/#best-practices","title":"Best Practices","text":"
  1. Aspect Ratio: Keep the logical aspect ratio the same as the physical one to avoid stretching.
  2. Integer Multiples: For the sharpest results, try to use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen).
  3. UI Positioning: Use UIAnchorLayout to ensure your UI elements stay correctly positioned regardless of the logical resolution chosen.
"},{"location":"manual/advanced_graphics/sprites_and_animation/","title":"Sprites and Animation","text":"

This guide covers advanced sprite techniques and animation in PixelRoot32, including different sprite formats, creating animations, and best practices.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-formats","title":"Sprite Formats","text":"

PixelRoot32 supports multiple sprite formats, each optimized for different use cases.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#1bpp-standard-monochrome","title":"1bpp (Standard, Monochrome)","text":"

The standard format uses 1 bit per pixel (monochrome). This is the most memory-efficient format:

#include <graphics/Renderer.h>\n\n// Define sprite data (8x8 example)\nstatic const uint16_t PLAYER_SPRITE_DATA[] = {\n    0b00111100,  // Row 0\n    0b01111110,  // Row 1\n    0b11111111,  // Row 2\n    0b11111111,  // Row 3\n    0b11111111,  // Row 4\n    0b01111110,  // Row 5\n    0b00111100,  // Row 6\n    0b00000000   // Row 7\n};\n\n// Create sprite descriptor\nstatic const pixelroot32::graphics::Sprite PLAYER_SPRITE = {\n    PLAYER_SPRITE_DATA,\n    8,  // width\n    8   // height\n};\n\n// Draw sprite\nrenderer.drawSprite(PLAYER_SPRITE, 100, 100, pixelroot32::graphics::Color::White);\n

Characteristics: - Most memory-efficient - 1 bit per pixel - Maximum width: 16 pixels - Color applied at draw time - Best for: Simple graphics, retro style

"},{"location":"manual/advanced_graphics/sprites_and_animation/#2bpp-experimental-4-colors","title":"2bpp (Experimental, 4 Colors)","text":"

2 bits per pixel allows 4 colors per sprite:

#ifdef PIXELROOT32_ENABLE_2BPP_SPRITES\n#include <graphics/Renderer.h>\n\n// Define 2bpp sprite data\nstatic const uint8_t COLORFUL_SPRITE_DATA[] = {\n    // Each byte represents 4 pixels (2 bits each)\n    // Format: [pixel3][pixel2][pixel1][pixel0]\n    0x00, 0x11, 0x22, 0x33,  // Row 0\n    0x11, 0x22, 0x33, 0x00,  // Row 1\n    // ... more rows\n};\n\n// Define palette (4 colors)\nstatic const pixelroot32::graphics::Color SPRITE_PALETTE[] = {\n    pixelroot32::graphics::Color::Transparent,\n    pixelroot32::graphics::Color::Red,\n    pixelroot32::graphics::Color::Green,\n    pixelroot32::graphics::Color::Blue\n};\n\n// Create 2bpp sprite\nstatic const pixelroot32::graphics::Sprite2bpp COLORFUL_SPRITE = {\n    COLORFUL_SPRITE_DATA,\n    SPRITE_PALETTE,\n    16,  // width\n    8,   // height\n    4    // palette size\n};\n\n// Draw 2bpp sprite\nrenderer.drawSprite(COLORFUL_SPRITE, 100, 100, false);\n#endif\n

Characteristics: - 2 bits per pixel (4 colors) - Requires custom palette - More memory than 1bpp - Best for: More colorful sprites without full color

"},{"location":"manual/advanced_graphics/sprites_and_animation/#4bpp-experimental-16-colors","title":"4bpp (Experimental, 16 Colors)","text":"

4 bits per pixel allows 16 colors per sprite:

#ifdef PIXELROOT32_ENABLE_4BPP_SPRITES\n#include <graphics/Renderer.h>\n\n// Define 4bpp sprite data\nstatic const uint8_t RICH_SPRITE_DATA[] = {\n    // Each byte represents 2 pixels (4 bits each)\n    // Format: [pixel1][pixel0]\n    0x01, 0x23, 0x45, 0x67,  // Row 0\n    // ... more rows\n};\n\n// Define palette (16 colors)\nstatic const pixelroot32::graphics::Color RICH_PALETTE[] = {\n    pixelroot32::graphics::Color::Transparent,\n    pixelroot32::graphics::Color::Black,\n    pixelroot32::graphics::Color::DarkGray,\n    // ... 13 more colors\n};\n\n// Create 4bpp sprite\nstatic const pixelroot32::graphics::Sprite4bpp RICH_SPRITE = {\n    RICH_SPRITE_DATA,\n    RICH_PALETTE,\n    16,  // width\n    16,  // height\n    16   // palette size\n};\n\n// Draw 4bpp sprite\nrenderer.drawSprite(RICH_SPRITE, 100, 100, false);\n#endif\n

Characteristics: - 4 bits per pixel (16 colors) - Requires custom palette - Most memory-intensive - Best for: Detailed sprites with many colors

"},{"location":"manual/advanced_graphics/sprites_and_animation/#multisprite-multi-layer","title":"MultiSprite (Multi-Layer)","text":"

MultiSprite combines multiple 1bpp layers to create multi-color sprites:

#include <graphics/Renderer.h>\n\n// Define layers (each is 1bpp)\nstatic const uint16_t BASE_LAYER_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b01111110,\n    0b00111100,\n    0b00000000\n};\n\nstatic const uint16_t HIGHLIGHT_LAYER_DATA[] = {\n    0b00000000,\n    0b00011000,\n    0b00111100,\n    0b00111100,\n    0b00111100,\n    0b00011000,\n    0b00000000,\n    0b00000000\n};\n\n// Create layers\nstatic const pixelroot32::graphics::SpriteLayer LAYERS[] = {\n    { BASE_LAYER_DATA, pixelroot32::graphics::Color::Blue },      // Base layer\n    { HIGHLIGHT_LAYER_DATA, pixelroot32::graphics::Color::Cyan }  // Highlight layer\n};\n\n// Create MultiSprite\nstatic const pixelroot32::graphics::MultiSprite PLAYER_MULTI = {\n    8,      // width\n    8,      // height\n    LAYERS, // layers array\n    2       // layer count\n};\n\n// Draw MultiSprite\nrenderer.drawSprite(PLAYER_MULTI, 100, 100, false);\n

Characteristics: - Combines multiple 1bpp layers - Each layer can have different color - Layers drawn in order (first = bottom) - Best for: Complex sprites with highlights, outlines, etc.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#creating-sprites","title":"Creating Sprites","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#manual-creation-1bpp","title":"Manual Creation (1bpp)","text":"

For simple sprites, you can create them manually:

// 8x8 sprite: Simple circle\nstatic const uint16_t CIRCLE_SPRITE_DATA[] = {\n    0b00111100,  //   ####\n    0b01111110,  //  ######\n    0b11111111,  // ########\n    0b11111111,  // ########\n    0b11111111,  // ########\n    0b11111111,  // ########\n    0b01111110,  //  ######\n    0b00111100   //   ####\n};\n\nstatic const pixelroot32::graphics::Sprite CIRCLE_SPRITE = {\n    CIRCLE_SPRITE_DATA,\n    8,\n    8\n};\n

Tips: - Use binary notation for clarity - Comment each row to visualize - Keep sprites small (8x8, 16x16) - Reuse sprites when possible

"},{"location":"manual/advanced_graphics/sprites_and_animation/#using-sprite-compiler","title":"Using Sprite Compiler","text":"

For complex sprites, use the Sprite Compiler tool (if available) to convert PNG images to sprite data.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-animation","title":"Sprite Animation","text":"

PixelRoot32 uses a step-based animation system that's lightweight and efficient.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#spriteanimation-structure","title":"SpriteAnimation Structure","text":"
#include <graphics/Renderer.h>\n\n// Define animation frames\nstatic const uint16_t FRAME1_DATA[] = { /* ... */ };\nstatic const uint16_t FRAME2_DATA[] = { /* ... */ };\nstatic const uint16_t FRAME3_DATA[] = { /* ... */ };\n\nstatic const pixelroot32::graphics::Sprite FRAME1 = { FRAME1_DATA, 8, 8 };\nstatic const pixelroot32::graphics::Sprite FRAME2 = { FRAME2_DATA, 8, 8 };\nstatic const pixelroot32::graphics::Sprite FRAME3 = { FRAME3_DATA, 8, 8 };\n\n// Create animation frames\nstatic const pixelroot32::graphics::SpriteAnimationFrame ANIMATION_FRAMES[] = {\n    { &FRAME1, nullptr },  // Frame 1 (no mask)\n    { &FRAME2, nullptr },  // Frame 2\n    { &FRAME3, nullptr }   // Frame 3\n};\n\n// Create animation\npixelroot32::graphics::SpriteAnimation walkAnimation;\nwalkAnimation.frames = ANIMATION_FRAMES;\nwalkAnimation.frameCount = 3;\nwalkAnimation.current = 0;\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#using-animations-in-actors","title":"Using Animations in Actors","text":"
#include <core/Actor.h>\n#include <graphics/Renderer.h>\n\nclass AnimatedPlayer : public pixelroot32::core::Actor {\nprivate:\n    pixelroot32::graphics::SpriteAnimation walkAnimation;\n    unsigned long animationTimer = 0;\n    const unsigned long FRAME_DURATION_MS = 100; // 100ms per frame\n\npublic:\n    AnimatedPlayer(float x, float y)\n        : Actor(x, y, 8, 8) {\n        setRenderLayer(1);\n\n        // Initialize animation\n        walkAnimation.frames = WALK_ANIMATION_FRAMES;\n        walkAnimation.frameCount = 3;\n        walkAnimation.current = 0;\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update animation\n        animationTimer += deltaTime;\n        if (animationTimer >= FRAME_DURATION_MS) {\n            animationTimer -= FRAME_DURATION_MS;\n            walkAnimation.step(); // Advance to next frame\n        }\n\n        // Movement logic...\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Get current frame\n        const pixelroot32::graphics::Sprite* currentFrame = \n            walkAnimation.frames[walkAnimation.current].sprite;\n\n        // Draw current frame\n        renderer.drawSprite(\n            *currentFrame,\n            static_cast<int>(x),\n            static_cast<int>(y),\n            pixelroot32::graphics::Color::White,\n            false // flipX\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collision\n    }\n};\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#animation-control","title":"Animation Control","text":"
// Reset animation to first frame\nwalkAnimation.reset();\n\n// Step to next frame (loops automatically)\nwalkAnimation.step();\n\n// Get current frame\nconst pixelroot32::graphics::Sprite* frame = \n    walkAnimation.frames[walkAnimation.current].sprite;\n\n// Check if animation is at specific frame\nif (walkAnimation.current == 0) {\n    // At first frame\n}\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#multiple-animations","title":"Multiple Animations","text":"

For actors with multiple animations (idle, walk, jump):

class PlayerActor : public pixelroot32::core::Actor {\nprivate:\n    enum class AnimationState {\n        IDLE,\n        WALK,\n        JUMP\n    };\n\n    AnimationState currentState = AnimationState::IDLE;\n    pixelroot32::graphics::SpriteAnimation idleAnim;\n    pixelroot32::graphics::SpriteAnimation walkAnim;\n    pixelroot32::graphics::SpriteAnimation jumpAnim;\n\n    pixelroot32::graphics::SpriteAnimation* getCurrentAnimation() {\n        switch (currentState) {\n            case AnimationState::IDLE: return &idleAnim;\n            case AnimationState::WALK: return &walkAnim;\n            case AnimationState::JUMP: return &jumpAnim;\n        }\n        return &idleAnim;\n    }\n\npublic:\n    void update(unsigned long deltaTime) override {\n        // Update current animation\n        auto* anim = getCurrentAnimation();\n        animationTimer += deltaTime;\n        if (animationTimer >= FRAME_DURATION_MS) {\n            animationTimer -= FRAME_DURATION_MS;\n            anim->step();\n        }\n\n        // Change animation state based on game logic\n        if (isMoving) {\n            if (currentState != AnimationState::WALK) {\n                currentState = AnimationState::WALK;\n                walkAnim.reset();\n            }\n        } else if (isJumping) {\n            if (currentState != AnimationState::JUMP) {\n                currentState = AnimationState::JUMP;\n                jumpAnim.reset();\n            }\n        } else {\n            if (currentState != AnimationState::IDLE) {\n                currentState = AnimationState::IDLE;\n                idleAnim.reset();\n            }\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        auto* anim = getCurrentAnimation();\n        const auto* frame = anim->frames[anim->current].sprite;\n        renderer.drawSprite(*frame, static_cast<int>(x), static_cast<int>(y), \n            pixelroot32::graphics::Color::White);\n    }\n};\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-flipping","title":"Sprite Flipping","text":"

Flip sprites horizontally for facing direction:

bool facingRight = true;\n\nvoid draw(pixelroot32::graphics::Renderer& renderer) override {\n    renderer.drawSprite(\n        PLAYER_SPRITE,\n        static_cast<int>(x),\n        static_cast<int>(y),\n        pixelroot32::graphics::Color::White,\n        !facingRight // Flip if facing left\n    );\n}\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#memory-optimization","title":"Memory Optimization","text":"
  • Reuse sprites: Define sprites once, use many times
  • Use 1bpp when possible: Most memory-efficient
  • Store in flash: Use static const to keep in flash memory
  • Limit sprite count: Too many unique sprites can exhaust memory
"},{"location":"manual/advanced_graphics/sprites_and_animation/#performance","title":"Performance","text":"
  • Pre-calculate animations: Set up animations in init(), not update()
  • Limit active animations: Only animate visible entities
  • Use appropriate formats: Don't use 4bpp if 1bpp works
  • Batch similar sprites: Draw similar sprites together
"},{"location":"manual/advanced_graphics/sprites_and_animation/#organization","title":"Organization","text":"
  • Group related sprites: Keep sprite data together
  • Use meaningful names: Name sprites clearly
  • Document complex sprites: Comment sprite bit patterns
  • Create sprite libraries: Reusable sprite collections
"},{"location":"manual/advanced_graphics/sprites_and_animation/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-sheet-pattern","title":"Sprite Sheet Pattern","text":"

Organize multiple sprites in arrays:

namespace PlayerSprites {\n    static const uint16_t IDLE_FRAME1[] = { /* ... */ };\n    static const uint16_t IDLE_FRAME2[] = { /* ... */ };\n    static const uint16_t WALK_FRAME1[] = { /* ... */ };\n    static const uint16_t WALK_FRAME2[] = { /* ... */ };\n\n    static const pixelroot32::graphics::Sprite IDLE[] = {\n        { IDLE_FRAME1, 8, 8 },\n        { IDLE_FRAME2, 8, 8 }\n    };\n\n    static const pixelroot32::graphics::Sprite WALK[] = {\n        { WALK_FRAME1, 8, 8 },\n        { WALK_FRAME2, 8, 8 }\n    };\n}\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#animation-helper","title":"Animation Helper","text":"

Create a helper class for animation management:

class AnimationController {\nprivate:\n    pixelroot32::graphics::SpriteAnimation* currentAnim;\n    unsigned long timer = 0;\n    unsigned long frameDuration;\n\npublic:\n    void setAnimation(pixelroot32::graphics::SpriteAnimation* anim) {\n        if (currentAnim != anim) {\n            currentAnim = anim;\n            currentAnim->reset();\n            timer = 0;\n        }\n    }\n\n    void update(unsigned long deltaTime) {\n        if (currentAnim) {\n            timer += deltaTime;\n            if (timer >= frameDuration) {\n                timer -= frameDuration;\n                currentAnim->step();\n            }\n        }\n    }\n\n    const pixelroot32::graphics::Sprite* getCurrentFrame() {\n        if (currentAnim && currentAnim->frameCount > 0) {\n            return currentAnim->frames[currentAnim->current].sprite;\n        }\n        return nullptr;\n    }\n};\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#sprites-not-displaying","title":"Sprites Not Displaying","text":"
  • Check sprite data is valid
  • Verify width/height match data
  • Ensure sprite is within screen bounds
  • Check render layer is correct
"},{"location":"manual/advanced_graphics/sprites_and_animation/#animation-not-playing","title":"Animation Not Playing","text":"
  • Verify animation frames are set
  • Check step() is being called
  • Ensure timer logic is correct
  • Verify frame count matches array size
"},{"location":"manual/advanced_graphics/sprites_and_animation/#memory-issues","title":"Memory Issues","text":"
  • Reduce sprite count
  • Use 1bpp instead of 2bpp/4bpp
  • Reuse sprites more
  • Check available flash memory
"},{"location":"manual/advanced_graphics/sprites_and_animation/#next-steps","title":"Next Steps","text":"

Now that you understand sprites and animation, learn about: - Color Palettes - Use different color schemes - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles

See also: - API Reference - Sprite - API Reference - SpriteAnimation - Manual - Basic Rendering

"},{"location":"manual/advanced_graphics/tilemaps/","title":"Tilemaps","text":"

Tilemaps allow you to build levels efficiently by reusing small tile sprites. This guide covers creating tilemaps, rendering them, and using them with scrolling cameras.

"},{"location":"manual/advanced_graphics/tilemaps/#what-are-tilemaps","title":"What are Tilemaps?","text":"

A tilemap is a 2D grid where each cell references a tile sprite. Instead of placing individual sprites, you define which tile appears at each grid position.

Advantages: - Memory efficient: Reuse tile sprites many times - Easy level design: Edit level data, not code - Fast rendering: Optimized tilemap drawing - Large levels: Create levels bigger than screen - Multiple Bit-Depths: Support for 1bpp, 2bpp, and 4bpp tilemaps for higher graphical fidelity

"},{"location":"manual/advanced_graphics/tilemaps/#creating-a-tilemap","title":"Creating a Tilemap","text":""},{"location":"manual/advanced_graphics/tilemaps/#1-define-tiles","title":"1. Define Tiles","text":"

First, create the tile sprites you'll reuse. You can use standard 1bpp sprites or multi-bpp sprites (2bpp/4bpp) if enabled.

"},{"location":"manual/advanced_graphics/tilemaps/#1bpp-tiles-example","title":"1bpp Tiles Example","text":"
#include <graphics/Renderer.h>\n\n// Ground tile (solid)\nstatic const uint16_t TILE_GROUND_BITS[] = {\n    0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,\n    0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF\n};\n\n// Create tile sprites (8x8 tiles)\nstatic const pixelroot32::graphics::Sprite TILES[] = {\n    { TILE_EMPTY_BITS, 8, 8 },  // Index 0: Empty\n    { TILE_GROUND_BITS, 8, 8 }  // Index 1: Ground\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#2bpp-tiles-example-multi-color","title":"2bpp Tiles Example (Multi-color)","text":"
#include <graphics/Renderer.h>\n\n// 2bpp grass tile\nstatic const uint8_t TILE_GRASS_DATA[] = {\n    0b01010101, 0b01010101, // Packed 2bpp data\n    // ...\n};\n\nstatic const Color GRASS_PALETTE[] = {\n    Color::Transparent, Color::DarkGreen, Color::Green, Color::LightGreen\n};\n\nstatic const pixelroot32::graphics::Sprite2bpp TILES_2BPP[] = {\n    { TILE_GRASS_DATA, GRASS_PALETTE, 8, 8, 4 }\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#2-create-tile-index-array","title":"2. Create Tile Index Array","text":"

Define which tile appears at each position:

// Tilemap dimensions (30 tiles wide, 20 tiles tall)\nstatic const int TILEMAP_WIDTH = 30;\nstatic const int TILEMAP_HEIGHT = 20;\n\n// Array of tile indices (each byte is a tile index)\nstatic uint8_t TILEMAP_INDICES[TILEMAP_WIDTH * TILEMAP_HEIGHT];\n\n// Initialize to empty\nvoid initTilemap() {\n    for (int i = 0; i < TILEMAP_WIDTH * TILEMAP_HEIGHT; i++) {\n        TILEMAP_INDICES[i] = 0; // Empty\n    }\n\n    // Draw ground at bottom\n    int groundRow = TILEMAP_HEIGHT - 1;\n    for (int x = 0; x < TILEMAP_WIDTH; x++) {\n        TILEMAP_INDICES[groundRow * TILEMAP_WIDTH + x] = 1; // Ground tile\n    }\n\n    // Add some walls\n    TILEMAP_INDICES[5 * TILEMAP_WIDTH + 10] = 2; // Wall at (10, 5)\n    TILEMAP_INDICES[5 * TILEMAP_WIDTH + 11] = 2;\n    TILEMAP_INDICES[5 * TILEMAP_WIDTH + 12] = 2;\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#3-create-tilemap-structure","title":"3. Create TileMap Structure","text":"
#include <graphics/Renderer.h>\n\nstatic pixelroot32::graphics::TileMap myTileMap = {\n    TILEMAP_INDICES,                    // indices array\n    TILEMAP_WIDTH,                      // width (in tiles)\n    TILEMAP_HEIGHT,                     // height (in tiles)\n    TILES,                              // tiles array\n    8,                                  // tile width (pixels)\n    8,                                  // tile height (pixels)\n    sizeof(TILES) / sizeof(pixelroot32::graphics::Sprite) // tile count\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#rendering-tilemaps","title":"Rendering Tilemaps","text":""},{"location":"manual/advanced_graphics/tilemaps/#basic-rendering","title":"Basic Rendering","text":"
void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // 1bpp Tilemap (requires a color)\n    renderer.drawTileMap(\n        myTileMap,\n        0, 0,\n        pixelroot32::graphics::Color::White\n    );\n\n    // 2bpp/4bpp Tilemap (colors are in the sprite palettes)\n    renderer.drawTileMap(myTileMap2bpp, 0, 100);\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#with-camerascrolling","title":"With Camera/Scrolling","text":"
void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera first\n    camera.apply(renderer);\n\n    // Draw tilemap (camera offset is automatically applied)\n    renderer.drawTileMap(\n        myTileMap,\n        0,                              // World position (0, 0)\n        0,\n        pixelroot32::graphics::Color::White\n    );\n\n    // Draw game objects\n    Scene::draw(renderer);\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#complete-example-platformer-level","title":"Complete Example: Platformer Level","text":"
#include <core/Scene.h>\n#include <graphics/Renderer.h>\n#include <graphics/Camera2D.h>\n\nclass PlatformerLevel : public pixelroot32::core::Scene {\nprivate:\n    static const int TILE_SIZE = 8;\n    static const int TILEMAP_WIDTH = 100;  // 800 pixels wide\n    static const int TILEMAP_HEIGHT = 30;   // 240 pixels tall\n\n    // Tile definitions\n    static const uint16_t TILE_EMPTY_BITS[] = {\n        0x0000, 0x0000, 0x0000, 0x0000,\n        0x0000, 0x0000, 0x0000, 0x0000\n    };\n\n    static const uint16_t TILE_GROUND_BITS[] = {\n        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,\n        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF\n    };\n\n    static const uint16_t TILE_GRASS_BITS[] = {\n        0x0000, 0x0000, 0x0000, 0x0000,\n        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF\n    };\n\n    static const pixelroot32::graphics::Sprite TILES[] = {\n        { TILE_EMPTY_BITS, TILE_SIZE, TILE_SIZE },  // 0: Empty\n        { TILE_GROUND_BITS, TILE_SIZE, TILE_SIZE }, // 1: Ground\n        { TILE_GRASS_BITS, TILE_SIZE, TILE_SIZE }   // 2: Grass top\n    };\n\n    static uint8_t LEVEL_INDICES[TILEMAP_WIDTH * TILEMAP_HEIGHT];\n\n    pixelroot32::graphics::TileMap levelTileMap;\n    pixelroot32::graphics::Camera2D camera;\n\npublic:\n    PlatformerLevel() \n        : camera(240, 240) {\n        // Initialize tilemap structure\n        levelTileMap = {\n            LEVEL_INDICES,\n            TILEMAP_WIDTH,\n            TILEMAP_HEIGHT,\n            TILES,\n            TILE_SIZE,\n            TILE_SIZE,\n            sizeof(TILES) / sizeof(pixelroot32::graphics::Sprite)\n        };\n    }\n\n    void init() override {\n        // Initialize all tiles to empty\n        for (int i = 0; i < TILEMAP_WIDTH * TILEMAP_HEIGHT; i++) {\n            LEVEL_INDICES[i] = 0;\n        }\n\n        // Create ground level\n        int groundY = TILEMAP_HEIGHT - 1;\n        for (int x = 0; x < TILEMAP_WIDTH; x++) {\n            LEVEL_INDICES[groundY * TILEMAP_WIDTH + x] = 1; // Ground\n        }\n\n        // Add grass on top of ground\n        int grassY = groundY - 1;\n        for (int x = 0; x < TILEMAP_WIDTH; x++) {\n            LEVEL_INDICES[grassY * TILEMAP_WIDTH + x] = 2; // Grass\n        }\n\n        // Add platforms\n        // Platform 1: x=10 to x=15, y=20\n        for (int x = 10; x < 16; x++) {\n            LEVEL_INDICES[20 * TILEMAP_WIDTH + x] = 1; // Ground tile\n        }\n\n        // Platform 2: x=30 to x=35, y=15\n        for (int x = 30; x < 36; x++) {\n            LEVEL_INDICES[15 * TILEMAP_WIDTH + x] = 1;\n        }\n\n        // Set camera boundaries\n        camera.setBounds(0, TILEMAP_WIDTH * TILE_SIZE - 240);\n        camera.setVerticalBounds(0, TILEMAP_HEIGHT * TILE_SIZE - 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Follow player (example)\n        // camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw tilemap\n        renderer.drawTileMap(\n            levelTileMap,\n            0, 0,\n            pixelroot32::graphics::Color::White\n        );\n\n        // Draw game objects\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#tilemap-with-scroll","title":"Tilemap with Scroll","text":"

For scrolling levels, combine tilemaps with cameras:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera (handles scrolling)\n    camera.apply(renderer);\n\n    // Draw tilemap (automatically scrolled by camera)\n    renderer.drawTileMap(\n        levelTileMap,\n        0, 0,\n        pixelroot32::graphics::Color::White\n    );\n\n    // Draw entities (also scrolled)\n    Scene::draw(renderer);\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#optimizing-tilemap-rendering","title":"Optimizing Tilemap Rendering","text":""},{"location":"manual/advanced_graphics/tilemaps/#viewport-culling","title":"Viewport Culling","text":"

Only draw visible tiles:

void drawTileMapOptimized(\n    pixelroot32::graphics::Renderer& renderer,\n    const pixelroot32::graphics::TileMap& tileMap,\n    int offsetX, int offsetY,\n    pixelroot32::graphics::Color color\n) {\n    int screenWidth = renderer.getWidth();\n    int screenHeight = renderer.getHeight();\n\n    // Calculate which tiles are visible\n    int startTileX = (offsetX < 0) ? (-offsetX / tileMap.tileWidth) : 0;\n    int startTileY = (offsetY < 0) ? (-offsetY / tileMap.tileHeight) : 0;\n    int endTileX = startTileX + (screenWidth / tileMap.tileWidth) + 1;\n    int endTileY = startTileY + (screenHeight / tileMap.tileHeight) + 1;\n\n    // Clamp to tilemap bounds\n    if (startTileX < 0) startTileX = 0;\n    if (startTileY < 0) startTileY = 0;\n    if (endTileX > tileMap.width) endTileX = tileMap.width;\n    if (endTileY > tileMap.height) endTileY = tileMap.height;\n\n    // Draw only visible tiles\n    for (int ty = startTileY; ty < endTileY; ty++) {\n        for (int tx = startTileX; tx < endTileX; tx++) {\n            uint8_t tileIndex = tileMap.indices[ty * tileMap.width + tx];\n            if (tileIndex < tileMap.tileCount) {\n                int x = tx * tileMap.tileWidth + offsetX;\n                int y = ty * tileMap.tileHeight + offsetY;\n                renderer.drawSprite(\n                    tileMap.tiles[tileIndex],\n                    x, y,\n                    color,\n                    false\n                );\n            }\n        }\n    }\n}\n

Note: The built-in drawTileMap() already performs viewport culling, so you typically don't need to implement this yourself.

"},{"location":"manual/advanced_graphics/tilemaps/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/tilemaps/#tile-design","title":"Tile Design","text":"
  • Keep tiles small: 8x8 or 16x16 pixels work best
  • Reuse tiles: Design tiles that can be used in multiple ways
  • Consistent style: All tiles should match visually
  • Limit tile count: Too many unique tiles uses more memory
"},{"location":"manual/advanced_graphics/tilemaps/#level-design","title":"Level Design","text":"
  • Use indices efficiently: 0 = empty, 1+ = different tiles
  • Plan layout: Design level on paper/grid first
  • Test on hardware: Large tilemaps may impact performance
  • Optimize data: Use compact level data format
"},{"location":"manual/advanced_graphics/tilemaps/#performance","title":"Performance","text":"
  • Limit tilemap size: Very large tilemaps can be slow
  • Use appropriate tile size: Smaller tiles = more tiles to draw
  • Combine with culling: Only draw visible area
  • Test scrolling: Ensure smooth scrolling performance
"},{"location":"manual/advanced_graphics/tilemaps/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/tilemaps/#level-data-in-code","title":"Level Data in Code","text":"
// Define level as 2D array (easier to read)\nstatic const uint8_t LEVEL_DATA[][TILEMAP_WIDTH] = {\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, // Ground\n};\n\n// Copy to tilemap indices\nvoid loadLevel() {\n    for (int y = 0; y < TILEMAP_HEIGHT; y++) {\n        for (int x = 0; x < TILEMAP_WIDTH; x++) {\n            TILEMAP_INDICES[y * TILEMAP_WIDTH + x] = LEVEL_DATA[y][x];\n        }\n    }\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#collision-detection-with-tilemaps","title":"Collision Detection with Tilemaps","text":"
bool isTileSolid(int tileX, int tileY) {\n    if (tileX < 0 || tileX >= TILEMAP_WIDTH ||\n        tileY < 0 || tileY >= TILEMAP_HEIGHT) {\n        return true; // Out of bounds = solid\n    }\n\n    uint8_t tileIndex = TILEMAP_INDICES[tileY * TILEMAP_WIDTH + tileX];\n    return tileIndex != 0; // 0 = empty, others = solid\n}\n\nbool checkCollision(float x, float y, int width, int height) {\n    // Convert world position to tile coordinates\n    int tileX1 = static_cast<int>(x) / TILE_SIZE;\n    int tileY1 = static_cast<int>(y) / TILE_SIZE;\n    int tileX2 = static_cast<int>(x + width) / TILE_SIZE;\n    int tileY2 = static_cast<int>(y + height) / TILE_SIZE;\n\n    // Check all tiles actor overlaps\n    for (int ty = tileY1; ty <= tileY2; ty++) {\n        for (int tx = tileX1; tx <= tileX2; tx++) {\n            if (isTileSolid(tx, ty)) {\n                return true; // Collision!\n            }\n        }\n    }\n\n    return false; // No collision\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/tilemaps/#tiles-not-appearing","title":"Tiles Not Appearing","text":"
  • Verify tile indices are correct (0 = first tile, 1 = second, etc.)
  • Check tilemap dimensions match indices array size
  • Ensure tiles array has enough entries
  • Verify tile size matches sprite size
"},{"location":"manual/advanced_graphics/tilemaps/#performance-issues","title":"Performance Issues","text":"
  • Reduce tilemap size
  • Use smaller tiles
  • Limit number of unique tiles
  • Test viewport culling
"},{"location":"manual/advanced_graphics/tilemaps/#scrolling-problems","title":"Scrolling Problems","text":"
  • Ensure camera is applied before drawing tilemap
  • Check tilemap position matches camera offset
  • Verify tilemap boundaries are correct
  • Test with simple tilemap first
"},{"location":"manual/advanced_graphics/tilemaps/#next-steps","title":"Next Steps","text":"

Now that you understand tilemaps, learn about: - Particles and Effects - Add visual effects - Cameras and Scrolling - Combine with scrolling - Performance Optimization - Optimize rendering

See also: - API Reference - TileMap - API Reference - Renderer - Manual - Cameras and Scrolling

"},{"location":"manual/game_development/audio/","title":"Audio","text":"

PixelRoot32 includes a complete NES-like audio system with 4 channels for sound effects and background music. This guide shows you how to add sound and music to your games.

"},{"location":"manual/game_development/audio/#audio-configuration","title":"Audio Configuration","text":"

Before using audio, you need to configure an AudioBackend. This is done when creating the Engine:

"},{"location":"manual/game_development/audio/#esp32-internal-dac","title":"ESP32: Internal DAC","text":"
#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nconst int DAC_PIN = 25; // GPIO 25 or 26\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\npr32::audio::AudioConfig audioConfig(&audioBackend, audioBackend.getSampleRate());\n
"},{"location":"manual/game_development/audio/#esp32-external-i2s-dac","title":"ESP32: External I2S DAC","text":"
#include <drivers/esp32/ESP32_I2S_AudioBackend.h>\n\nconst int I2S_BCLK = 26;  // Bit clock\nconst int I2S_LRCK = 25;  // Left/Right clock\nconst int I2S_DOUT = 22;  // Data out\n\npr32::drivers::esp32::ESP32_I2S_AudioBackend audioBackend(\n    I2S_BCLK, I2S_LRCK, I2S_DOUT, 22050\n);\n\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n
"},{"location":"manual/game_development/audio/#native-pc-sdl2","title":"Native (PC): SDL2","text":"
#include <drivers/native/SDL2_AudioBackend.h>\n\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\n\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n
"},{"location":"manual/game_development/audio/#sound-effects","title":"Sound Effects","text":"

Sound effects are created using AudioEvent structures and played through the AudioEngine.

"},{"location":"manual/game_development/audio/#audioevent-structure","title":"AudioEvent Structure","text":"
#include <audio/AudioTypes.h>\n\npr32::audio::AudioEvent soundEffect{};\nsoundEffect.type = pr32::audio::WaveType::PULSE;  // Waveform type\nsoundEffect.frequency = 1500.0f;                  // Frequency in Hz\nsoundEffect.duration = 0.12f;                      // Duration in seconds\nsoundEffect.volume = 0.8f;                         // Volume (0.0 to 1.0)\nsoundEffect.duty = 0.5f;                           // Duty cycle (for PULSE only)\n
"},{"location":"manual/game_development/audio/#wave-types","title":"Wave Types","text":"

PixelRoot32 supports three wave types:

  • PULSE: Square wave with variable duty cycle
  • Duty cycles: 0.125 (thin), 0.25 (classic NES), 0.5 (symmetric), 0.75 (fat)
  • Good for: Beeps, jumps, UI sounds, leads

  • TRIANGLE: Triangle wave (fixed volume/duty)

  • Softer, smoother sound
  • Good for: Bass lines, pads, background tones

  • NOISE: Pseudo-random noise

  • Harsh, chaotic sound
  • Good for: Explosions, hits, impacts, drums
"},{"location":"manual/game_development/audio/#playing-sound-effects","title":"Playing Sound Effects","text":"
// Get the audio engine\nauto& audio = engine.getAudioEngine();\n\n// Create and play a sound\npr32::audio::AudioEvent jumpSound{};\njumpSound.type = pr32::audio::WaveType::PULSE;\njumpSound.frequency = 800.0f;\njumpSound.duration = 0.1f;\njumpSound.volume = 0.7f;\njumpSound.duty = 0.25f;\n\naudio.playEvent(jumpSound);\n
"},{"location":"manual/game_development/audio/#common-sound-effects","title":"Common Sound Effects","text":"

Here are some example sound effects you can use:

namespace SoundEffects {\n    // Jump sound\n    inline pr32::audio::AudioEvent jump() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::PULSE;\n        evt.frequency = 600.0f;\n        evt.duration = 0.1f;\n        evt.volume = 0.7f;\n        evt.duty = 0.25f;\n        return evt;\n    }\n\n    // Coin/collect sound\n    inline pr32::audio::AudioEvent coin() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::PULSE;\n        evt.frequency = 1500.0f;\n        evt.duration = 0.12f;\n        evt.volume = 0.8f;\n        evt.duty = 0.5f;\n        return evt;\n    }\n\n    // Explosion\n    inline pr32::audio::AudioEvent explosion() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::NOISE;\n        evt.frequency = 200.0f;\n        evt.duration = 0.3f;\n        evt.volume = 0.9f;\n        return evt;\n    }\n\n    // Hit/damage\n    inline pr32::audio::AudioEvent hit() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::NOISE;\n        evt.frequency = 300.0f;\n        evt.duration = 0.15f;\n        evt.volume = 0.6f;\n        return evt;\n    }\n}\n\n// Usage\naudio.playEvent(SoundEffects::jump());\n
"},{"location":"manual/game_development/audio/#background-music","title":"Background Music","text":"

Background music uses the MusicPlayer system, which sequences notes over time.

"},{"location":"manual/game_development/audio/#music-notes","title":"Music Notes","text":"

Music is built from MusicNote structures:

#include <audio/AudioMusicTypes.h>\n\nusing namespace pr32::audio;\n\nMusicNote note{};\nnote.note = Note::C;        // Musical note (C, D, E, F, G, A, B, or Rest)\nnote.octave = 4;            // Octave (0-8)\nnote.duration = 0.2f;       // Duration in seconds\nnote.volume = 0.7f;         // Volume (0.0 to 1.0)\n
"},{"location":"manual/game_development/audio/#instrument-presets","title":"Instrument Presets","text":"

For convenience, use predefined instrument presets:

using namespace pr32::audio;\n\n// Available presets:\n// - INSTR_PULSE_LEAD: Main lead pulse (octave 4)\n// - INSTR_PULSE_BASS: Bass pulse (octave 3)\n// - INSTR_PULSE_CHIP_HIGH: High-pitched chiptune (octave 5)\n// - INSTR_TRIANGLE_PAD: Soft triangle pad (octave 4)\n
"},{"location":"manual/game_development/audio/#creating-a-melody","title":"Creating a Melody","text":"
#include <audio/AudioMusicTypes.h>\n\nusing namespace pr32::audio;\n\n// Define melody notes\nstatic const MusicNote MELODY_NOTES[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),  // Rest (silence)\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),\n};\n\n// Create music track\nstatic const MusicTrack GAME_MUSIC = {\n    MELODY_NOTES,                              // notes array\n    sizeof(MELODY_NOTES) / sizeof(MusicNote),  // note count\n    true,                                       // loop\n    WaveType::PULSE,                           // channel type\n    0.5f                                       // duty cycle\n};\n
"},{"location":"manual/game_development/audio/#playing-music","title":"Playing Music","text":"
// Get the music player\nauto& music = engine.getMusicPlayer();\n\n// Play a track\nmusic.play(GAME_MUSIC);\n\n// Control playback\nmusic.stop();   // Stop playback\nmusic.pause();  // Pause (time doesn't advance)\nmusic.resume(); // Resume after pause\n\n// Check status\nif (music.isPlaying()) {\n    // Music is currently playing\n}\n
"},{"location":"manual/game_development/audio/#music-in-scene","title":"Music in Scene","text":"

Typically, you start music in your scene's init():

void MyGameScene::init() override {\n    // Start background music\n    engine.getMusicPlayer().play(GAME_MUSIC);\n\n    // ... rest of initialization\n}\n
"},{"location":"manual/game_development/audio/#master-volume","title":"Master Volume","text":"

Control overall volume without changing individual sounds:

auto& audio = engine.getAudioEngine();\n\n// Set master volume (0.0 to 1.0)\naudio.setMasterVolume(0.5f); // 50% volume\n\n// Get current volume\nfloat currentVolume = audio.getMasterVolume();\n
"},{"location":"manual/game_development/audio/#complete-example","title":"Complete Example","text":"

Here's a complete example combining sound effects and music:

#include <core/Scene.h>\n#include <audio/AudioTypes.h>\n#include <audio/AudioMusicTypes.h>\n\nusing namespace pr32::audio;\n\n// Background music\nstatic const MusicNote GAME_MELODY[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),\n};\n\nstatic const MusicTrack BACKGROUND_MUSIC = {\n    GAME_MELODY,\n    sizeof(GAME_MELODY) / sizeof(MusicNote),\n    true,  // loop\n    WaveType::PULSE,\n    0.5f\n};\n\nclass AudioExampleScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Start background music\n        engine.getMusicPlayer().play(BACKGROUND_MUSIC);\n\n        // Set master volume\n        engine.getAudioEngine().setMasterVolume(0.8f);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        auto& audio = engine.getAudioEngine();\n\n        // Play sound effect on button press\n        if (input.isButtonPressed(4)) { // Button A\n            AudioEvent jumpSound{};\n            jumpSound.type = WaveType::PULSE;\n            jumpSound.frequency = 800.0f;\n            jumpSound.duration = 0.1f;\n            jumpSound.volume = 0.7f;\n            jumpSound.duty = 0.25f;\n\n            audio.playEvent(jumpSound);\n        }\n\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/audio/#designing-nes-like-sounds","title":"Designing NES-like Sounds","text":""},{"location":"manual/game_development/audio/#frequency-guidelines","title":"Frequency Guidelines","text":"
  • Low frequencies (200-400 Hz): Bass, impacts, explosions
  • Mid frequencies (400-1000 Hz): Main sounds, jumps, UI
  • High frequencies (1000-2000 Hz): Beeps, coins, pickups
  • Very high (2000+ Hz): Sharp sounds, alerts
"},{"location":"manual/game_development/audio/#duration-guidelines","title":"Duration Guidelines","text":"
  • Short (0.05-0.1s): UI clicks, small effects
  • Medium (0.1-0.2s): Jumps, hits, pickups
  • Long (0.2-0.5s): Explosions, power-ups, transitions
"},{"location":"manual/game_development/audio/#duty-cycle-pulse-only","title":"Duty Cycle (PULSE only)","text":"
  • 0.125: Thin, sharp, piercing
  • 0.25: Classic NES lead sound
  • 0.5: Symmetric, full, fat
  • 0.75: Very fat, bass-like
"},{"location":"manual/game_development/audio/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/audio/#sound-design","title":"Sound Design","text":"
  • Keep sounds short: Long sounds can overlap and cause issues
  • Use appropriate volumes: 0.6-0.8 is usually good for effects
  • Vary frequencies: Don't use the same frequency for everything
  • Test on hardware: ESP32 audio may sound different than PC
"},{"location":"manual/game_development/audio/#music","title":"Music","text":"
  • Use one channel for music: Leave other channels for SFX
  • Keep melodies simple: Complex melodies can be hard to follow
  • Loop seamlessly: End your melody where it can loop naturally
  • Consider tempo: Faster games need faster music
"},{"location":"manual/game_development/audio/#performance","title":"Performance","text":"
  • Limit simultaneous sounds: Only 4 channels total
  • Music uses one channel: Plan your SFX accordingly
  • Don't spam sounds: Too many sounds can cause audio glitches
  • Use master volume: Easier than adjusting individual sounds
"},{"location":"manual/game_development/audio/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/audio/#sound-effect-helper-function","title":"Sound Effect Helper Function","text":"
void playJumpSound() {\n    auto& audio = engine.getAudioEngine();\n    AudioEvent evt{};\n    evt.type = WaveType::PULSE;\n    evt.frequency = 600.0f;\n    evt.duration = 0.1f;\n    evt.volume = 0.7f;\n    evt.duty = 0.25f;\n    audio.playEvent(evt);\n}\n
"},{"location":"manual/game_development/audio/#music-state-management","title":"Music State Management","text":"
class GameScene : public Scene {\n    bool musicStarted = false;\n\n    void init() override {\n        // Don't start music here if scene can be re-initialized\n    }\n\n    void update(unsigned long deltaTime) override {\n        if (!musicStarted) {\n            engine.getMusicPlayer().play(GAME_MUSIC);\n            musicStarted = true;\n        }\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"manual/game_development/audio/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/game_development/audio/#no-sound","title":"No Sound","text":"
  • Check audio backend is configured correctly
  • Verify sample rate matches backend
  • Check master volume is not 0
  • Ensure audio is initialized (engine.init())
"},{"location":"manual/game_development/audio/#distorted-sound","title":"Distorted Sound","text":"
  • Lower volume levels
  • Reduce sample rate (ESP32 DAC works better at 11025 Hz)
  • Check for too many simultaneous sounds
  • Verify hardware connections (ESP32)
"},{"location":"manual/game_development/audio/#music-not-playing","title":"Music Not Playing","text":"
  • Check music.isPlaying() status
  • Ensure track is properly defined
  • Verify MusicPlayer is updated (happens automatically)
  • Check that music channel is not being used by SFX
"},{"location":"manual/game_development/audio/#next-steps","title":"Next Steps","text":"

Now that you can add audio, learn about: - NES Audio Reference - Advanced audio techniques - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs

See also: - API Reference - AudioEngine - API Reference - MusicPlayer - API Reference - Audio Types - Manual - Audio Overview

"},{"location":"manual/game_development/basic_rendering/","title":"Basic Rendering","text":"

Rendering is how you draw everything on screen. This guide covers the fundamental drawing operations in PixelRoot32: primitives, sprites, and text.

"},{"location":"manual/game_development/basic_rendering/#accessing-the-renderer","title":"Accessing the Renderer","text":"

You can access the renderer in two ways:

"},{"location":"manual/game_development/basic_rendering/#from-the-engine","title":"From the Engine","text":"
auto& renderer = engine.getRenderer();\n
"},{"location":"manual/game_development/basic_rendering/#from-a-scene","title":"From a Scene","text":"
void MyScene::draw(pixelroot32::graphics::Renderer& renderer) override {\n    // renderer is passed as parameter\n    // Drawing covers the entire logical screen (e.g., 128x128)\n    renderer.drawFilledRectangle(0, 0, renderer.getLogicalWidth(), renderer.getLogicalHeight(), Color::Black);\n}\n
"},{"location":"manual/game_development/basic_rendering/#drawing-primitives","title":"Drawing Primitives","text":""},{"location":"manual/game_development/basic_rendering/#pixels","title":"Pixels","text":"

Draw a single pixel:

renderer.drawPixel(100, 100, pixelroot32::graphics::Color::White);\n
"},{"location":"manual/game_development/basic_rendering/#lines","title":"Lines","text":"

Draw a line between two points:

renderer.drawLine(10, 10, 200, 200, pixelroot32::graphics::Color::Red);\n
"},{"location":"manual/game_development/basic_rendering/#rectangles","title":"Rectangles","text":"

Draw a rectangle outline:

renderer.drawRectangle(50, 50, 100, 80, pixelroot32::graphics::Color::Blue);\n

Draw a filled rectangle:

renderer.drawFilledRectangle(50, 50, 100, 80, pixelroot32::graphics::Color::Blue);\n
"},{"location":"manual/game_development/basic_rendering/#circles","title":"Circles","text":"

Draw a circle outline:

renderer.drawCircle(120, 120, 30, pixelroot32::graphics::Color::Green);\n

Draw a filled circle:

renderer.drawFilledCircle(120, 120, 30, pixelroot32::graphics::Color::Green);\n
"},{"location":"manual/game_development/basic_rendering/#simple-sprites-1bpp","title":"Simple Sprites (1bpp)","text":"

Sprites are the primary way to draw game graphics. The standard format is 1bpp (1 bit per pixel), which is memory-efficient and perfect for retro-style graphics.

"},{"location":"manual/game_development/basic_rendering/#creating-a-sprite-manually","title":"Creating a Sprite Manually","text":"

A 1bpp sprite is defined as an array of uint16_t, where each value represents one row:

#include <graphics/Renderer.h>\n\n// Example: 8x8 sprite (8 rows, each row is a uint16_t)\n// Bit 0 = leftmost pixel, bit 7 = rightmost pixel\nstatic const uint16_t MY_SPRITE_DATA[] = {\n    0b00111100,  // Row 0:   ..####..\n    0b01111110,  // Row 1:  .######.\n    0b11111111,  // Row 2:  ########\n    0b11111111,  // Row 3:  ########\n    0b11111111,  // Row 4:  ########\n    0b01111110,  // Row 5:  .######.\n    0b00111100,  // Row 6:   ..####..\n    0b00000000   // Row 7:  ........\n};\n\n// Create sprite descriptor\nstatic const pixelroot32::graphics::Sprite MY_SPRITE = {\n    MY_SPRITE_DATA,  // data pointer\n    8,                // width\n    8                 // height\n};\n
"},{"location":"manual/game_development/basic_rendering/#drawing-a-sprite","title":"Drawing a Sprite","text":"
renderer.drawSprite(\n    MY_SPRITE,                                    // sprite\n    100,                                          // x position\n    100,                                          // y position\n    pixelroot32::graphics::Color::White,         // color\n    false                                         // flipX (optional, default false)\n);\n
"},{"location":"manual/game_development/basic_rendering/#sprite-bit-convention","title":"Sprite Bit Convention","text":"
  • Each uint16_t represents one row
  • Bit 0 (rightmost bit) = leftmost pixel
  • Bit (width - 1) = rightmost pixel
  • 0 = transparent/off, 1 = on (colored)

Example: For an 8-pixel wide sprite:

Row value: 0b00111100\nPixels:    ..####..\n           ^      ^\n         bit 7  bit 0 (leftmost)\n

"},{"location":"manual/game_development/basic_rendering/#flipping-sprites","title":"Flipping Sprites","text":"

You can flip a sprite horizontally:

renderer.drawSprite(MY_SPRITE, 100, 100, Color::White, true); // flipped\n
"},{"location":"manual/game_development/basic_rendering/#text-rendering","title":"Text Rendering","text":"

PixelRoot32 uses a native bitmap font system for pixel-perfect text rendering.

"},{"location":"manual/game_development/basic_rendering/#drawing-text","title":"Drawing Text","text":"
renderer.drawText(\n    \"Hello World!\",                           // text string\n    10,                                       // x position\n    20,                                       // y position\n    pixelroot32::graphics::Color::White,     // color\n    1                                         // size multiplier (1=normal, 2=double, etc.)\n);\n
"},{"location":"manual/game_development/basic_rendering/#centered-text","title":"Centered Text","text":"
renderer.drawTextCentered(\n    \"Game Over\",                              // text\n    120,                                      // y position (centered horizontally)\n    pixelroot32::graphics::Color::Red,       // color\n    2                                         // size\n);\n
"},{"location":"manual/game_development/basic_rendering/#text-size","title":"Text Size","text":"

The size parameter multiplies the font size: - 1 = normal size (5x7 pixels per character with default font) - 2 = double size (10x14 pixels) - 3 = triple size (15x21 pixels) - etc.

"},{"location":"manual/game_development/basic_rendering/#supported-characters","title":"Supported Characters","text":"

The default font (FONT_5X7) supports ASCII characters 32-126: - Letters: A-Z, a-z - Numbers: 0-9 - Symbols: !@#$%^&*()_+-=[]{}|;:'\",.<>?/ etc.

"},{"location":"manual/game_development/basic_rendering/#render-layers","title":"Render Layers","text":"

Entities are drawn in order based on their renderLayer property:

  • Layer 0 (Background): Drawn first (behind everything)
  • Layer 1 (Gameplay): Drawn second (main game objects)
  • Layer 2 (UI): Drawn last (on top of everything)

Set the render layer when creating an entity:

myEntity->setRenderLayer(0); // Background\nmyEntity->setRenderLayer(1); // Gameplay (default)\nmyEntity->setRenderLayer(2); // UI\n
"},{"location":"manual/game_development/basic_rendering/#complete-example","title":"Complete Example","text":"

Here's a complete example that draws various primitives and a sprite:

#include <core/Scene.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\n// Simple sprite data (8x8 circle)\nstatic const uint16_t CIRCLE_SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b01111110,\n    0b00111100\n};\n\nstatic const pixelroot32::graphics::Sprite CIRCLE_SPRITE = {\n    CIRCLE_SPRITE_DATA,\n    8,\n    8\n};\n\nclass RenderingExampleScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Set palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::NES\n        );\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background (layer 0)\n        renderer.drawFilledRectangle(0, 0, 240, 240, \n            pixelroot32::graphics::Color::Navy);\n\n        // Draw primitives (layer 1)\n        renderer.drawRectangle(10, 10, 100, 80, \n            pixelroot32::graphics::Color::White);\n        renderer.drawFilledCircle(120, 120, 30, \n            pixelroot32::graphics::Color::Red);\n        renderer.drawLine(0, 0, 240, 240, \n            pixelroot32::graphics::Color::Yellow);\n\n        // Draw sprite\n        renderer.drawSprite(CIRCLE_SPRITE, 50, 50, \n            pixelroot32::graphics::Color::Cyan);\n\n        // Draw text (layer 2 - UI)\n        renderer.drawText(\"Score: 100\", 10, 10, \n            pixelroot32::graphics::Color::White, 1);\n        renderer.drawTextCentered(\"Rendering Demo\", 200, \n            pixelroot32::graphics::Color::Yellow, 2);\n\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/basic_rendering/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/basic_rendering/#performance","title":"Performance","text":"
  • Minimize draw calls: Batch similar operations when possible
  • Use render layers efficiently: Don't mix layers unnecessarily
  • Avoid drawing off-screen: Check bounds before drawing
  • Reuse sprites: Define sprites once, use many times
"},{"location":"manual/game_development/basic_rendering/#organization","title":"Organization","text":"
  • Define sprites as static const: Keep them in flash memory
  • Use meaningful names: Name your sprites clearly
  • Group related sprites: Organize sprite data logically
  • Document complex sprites: Comment sprite bit patterns if needed
"},{"location":"manual/game_development/basic_rendering/#text","title":"Text","text":"
  • Avoid frequent text updates: Text rendering has overhead
  • Use appropriate sizes: Larger text uses more memory
  • Cache text dimensions: Use FontManager::textWidth() if needed
  • Keep text simple: Complex formatting is not supported
"},{"location":"manual/game_development/basic_rendering/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/basic_rendering/#drawing-a-background","title":"Drawing a Background","text":"
void drawBackground(Renderer& renderer) {\n    // Solid color background\n    renderer.drawFilledRectangle(0, 0, 240, 240, Color::Black);\n\n    // Or use a tilemap (see Advanced Graphics section)\n}\n
"},{"location":"manual/game_development/basic_rendering/#drawing-a-hud","title":"Drawing a HUD","text":"
void drawHUD(Renderer& renderer, int score, int lives) {\n    char buffer[32];\n    snprintf(buffer, sizeof(buffer), \"Score: %d\", score);\n    renderer.drawText(buffer, 10, 10, Color::White, 1);\n\n    snprintf(buffer, sizeof(buffer), \"Lives: %d\", lives);\n    renderer.drawText(buffer, 10, 20, Color::White, 1);\n}\n
"},{"location":"manual/game_development/basic_rendering/#drawing-multiple-sprites","title":"Drawing Multiple Sprites","text":"
void drawSpriteArray(Renderer& renderer, const Sprite& sprite, \n                     int count, int startX, int startY, int spacing) {\n    for (int i = 0; i < count; i++) {\n        int x = startX + (i * (sprite.width + spacing));\n        renderer.drawSprite(sprite, x, startY, Color::White);\n    }\n}\n
"},{"location":"manual/game_development/basic_rendering/#next-steps","title":"Next Steps","text":"

Now that you can draw basic graphics, learn about: - Sprites and Animation - Advanced sprite techniques - Input and Control - Make your game interactive - Palettes - Use different color schemes

See also: - API Reference - Renderer - API Reference - Sprite - Render Layers

"},{"location":"manual/game_development/input_and_control/","title":"Input and Control","text":"

Handling user input is essential for any interactive game. This guide covers how to read and process input from buttons (ESP32) or keyboard (Native) in PixelRoot32.

"},{"location":"manual/game_development/input_and_control/#input-configuration","title":"Input Configuration","text":"

Before you can read input, you need to configure the InputManager. This is done when creating the Engine:

"},{"location":"manual/game_development/input_and_control/#esp32-configuration","title":"ESP32 Configuration","text":"
#include <input/InputConfig.h>\n\n// InputConfig(buttonCount, UP, DOWN, LEFT, RIGHT, A, B)\npr32::input::InputConfig inputConfig(\n    6,      // Total number of buttons\n    32,     // UP button GPIO pin\n    27,     // DOWN button GPIO pin\n    33,     // LEFT button GPIO pin\n    14,     // RIGHT button GPIO pin\n    13,     // A button GPIO pin\n    12      // B button GPIO pin\n);\n
"},{"location":"manual/game_development/input_and_control/#native-pc-configuration","title":"Native (PC) Configuration","text":"
#include <SDL2/SDL.h>\n#include <input/InputConfig.h>\n\n// InputConfig(buttonCount, UP, DOWN, LEFT, RIGHT, A, B)\npr32::input::InputConfig inputConfig(\n    6,                      // Total number of buttons\n    SDL_SCANCODE_UP,        // UP key\n    SDL_SCANCODE_DOWN,      // DOWN key\n    SDL_SCANCODE_LEFT,      // LEFT key\n    SDL_SCANCODE_RIGHT,     // RIGHT key\n    SDL_SCANCODE_SPACE,     // A button (Space)\n    SDL_SCANCODE_RETURN     // B button (Enter)\n);\n
"},{"location":"manual/game_development/input_and_control/#reading-input","title":"Reading Input","text":"

Access the InputManager through the Engine:

auto& input = engine.getInputManager();\n
"},{"location":"manual/game_development/input_and_control/#input-states","title":"Input States","text":"

The InputManager provides four different ways to check button state:

"},{"location":"manual/game_development/input_and_control/#1-isbuttonpressed","title":"1. isButtonPressed()","text":"

Returns true only on the frame when the button was just pressed:

if (input.isButtonPressed(4)) { // Button A (index 4)\n    // This code runs only once when button is first pressed\n    jump();\n}\n

Use for: Actions that should trigger once per press (jump, shoot, select menu item).

"},{"location":"manual/game_development/input_and_control/#2-isbuttonreleased","title":"2. isButtonReleased()","text":"

Returns true only on the frame when the button was just released:

if (input.isButtonReleased(4)) {\n    // This code runs only once when button is released\n    stopCharging();\n}\n

Use for: Actions that trigger on release (charge attacks, menu confirmation).

"},{"location":"manual/game_development/input_and_control/#3-isbuttondown","title":"3. isButtonDown()","text":"

Returns true while the button is currently held down:

if (input.isButtonDown(2)) { // LEFT button (index 2)\n    // This code runs every frame while button is held\n    playerX -= speed * (deltaTime * 0.001f);\n}\n

Use for: Continuous actions (movement, holding, charging).

"},{"location":"manual/game_development/input_and_control/#4-isbuttonclicked","title":"4. isButtonClicked()","text":"

Returns true when the button was pressed and then released:

if (input.isButtonClicked(4)) {\n    // This code runs once per click (press + release cycle)\n    toggleMenu();\n}\n

Use for: Toggle actions, menu selections, click interactions.

"},{"location":"manual/game_development/input_and_control/#button-indices","title":"Button Indices","text":"

The button indices correspond to the order in InputConfig:

  • Index 0: UP
  • Index 1: DOWN
  • Index 2: LEFT
  • Index 3: RIGHT
  • Index 4: A button
  • Index 5: B button

For convenience, you can define constants:

namespace Buttons {\n    constexpr uint8_t UP = 0;\n    constexpr uint8_t DOWN = 1;\n    constexpr uint8_t LEFT = 2;\n    constexpr uint8_t RIGHT = 3;\n    constexpr uint8_t A = 4;\n    constexpr uint8_t B = 5;\n}\n\n// Usage\nif (input.isButtonPressed(Buttons::A)) {\n    // ...\n}\n
"},{"location":"manual/game_development/input_and_control/#character-control-example","title":"Character Control Example","text":"

Here's a complete example of character movement:

#include <core/Actor.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass PlayerActor : public pixelroot32::core::Actor {\npublic:\n    float speed = 100.0f; // pixels per second\n\n    PlayerActor(float x, float y)\n        : Actor(x, y, 16, 16) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f; // Convert to seconds\n\n        // Horizontal movement\n        if (input.isButtonDown(Buttons::LEFT)) {\n            x -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::RIGHT)) {\n            x += speed * dt;\n        }\n\n        // Vertical movement\n        if (input.isButtonDown(Buttons::UP)) {\n            y -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::DOWN)) {\n            y += speed * dt;\n        }\n\n        // Keep player on screen\n        if (x < 0) x = 0;\n        if (x > 224) x = 224;\n        if (y < 0) y = 0;\n        if (y > 224) y = 224;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width,\n            height,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collisions\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#jumping-example","title":"Jumping Example","text":"

For platformer-style jumping:

class PlatformerPlayer : public pixelroot32::core::PhysicsActor {\npublic:\n    bool canJump = true;\n    float jumpForce = 200.0f;\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        // Horizontal movement\n        float moveSpeed = 80.0f;\n        if (input.isButtonDown(Buttons::LEFT)) {\n            setVelocity(-moveSpeed, vy);\n        } else if (input.isButtonDown(Buttons::RIGHT)) {\n            setVelocity(moveSpeed, vy);\n        } else {\n            setVelocity(0, vy);\n        }\n\n        // Jump (only on press, and only if on ground)\n        if (input.isButtonPressed(Buttons::A) && canJump) {\n            setVelocity(vx, -jumpForce);\n            canJump = false;\n        }\n\n        // Check if on ground (for jump reset)\n        auto collisionInfo = getWorldCollisionInfo();\n        if (collisionInfo.bottom) {\n            canJump = true;\n        }\n\n        PhysicsActor::update(deltaTime);\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#shooting-example","title":"Shooting Example","text":"

For shooting projectiles:

class ShooterActor : public pixelroot32::core::Actor {\nprivate:\n    bool fireInputReady = true;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n\n        // Shooting (with cooldown)\n        if (input.isButtonPressed(Buttons::A) && fireInputReady) {\n            shoot();\n            fireInputReady = false;\n        }\n\n        // Reset fire input when button is released\n        if (input.isButtonReleased(Buttons::A)) {\n            fireInputReady = true;\n        }\n    }\n\n    void shoot() {\n        // Create projectile\n        // ...\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#menu-navigation-example","title":"Menu Navigation Example","text":"

For menu navigation:

class MenuScene : public pixelroot32::core::Scene {\nprivate:\n    int selectedIndex = 0;\n    static const int MENU_ITEMS = 3;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n\n        // Navigate menu\n        if (input.isButtonPressed(Buttons::UP)) {\n            selectedIndex--;\n            if (selectedIndex < 0) selectedIndex = MENU_ITEMS - 1;\n        }\n\n        if (input.isButtonPressed(Buttons::DOWN)) {\n            selectedIndex++;\n            if (selectedIndex >= MENU_ITEMS) selectedIndex = 0;\n        }\n\n        // Select menu item\n        if (input.isButtonPressed(Buttons::A)) {\n            selectMenuItem(selectedIndex);\n        }\n\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/input_and_control/#frame-rate-independence","title":"Frame-Rate Independence","text":"

Always multiply movement by delta time:

// \u2705 GOOD: Framerate-independent\nx += speed * (deltaTime * 0.001f);\n\n// \u274c BAD: Framerate-dependent\nx += speed;\n
"},{"location":"manual/game_development/input_and_control/#input-debouncing","title":"Input Debouncing","text":"

For actions that should only trigger once:

// Use isButtonPressed() instead of isButtonDown()\nif (input.isButtonPressed(Buttons::A)) {\n    // Triggers once per press\n}\n
"},{"location":"manual/game_development/input_and_control/#input-buffering","title":"Input Buffering","text":"

For responsive controls, you can buffer input:

class InputBuffer {\n    uint8_t bufferedInput = 0;\n\npublic:\n    void update(const InputManager& input) {\n        if (input.isButtonPressed(Buttons::A)) {\n            bufferedInput = Buttons::A;\n        }\n    }\n\n    bool hasBufferedInput() const { return bufferedInput != 0; }\n    uint8_t consumeInput() {\n        uint8_t result = bufferedInput;\n        bufferedInput = 0;\n        return result;\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#multiple-input-methods","title":"Multiple Input Methods","text":"

Support both button presses and held buttons:

// Allow both tap and hold for rapid fire\nif (input.isButtonPressed(Buttons::A) || \n    (input.isButtonDown(Buttons::A) && rapidFireTimer <= 0)) {\n    shoot();\n    rapidFireTimer = RAPID_FIRE_DELAY;\n}\n
"},{"location":"manual/game_development/input_and_control/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/input_and_control/#directional-input","title":"Directional Input","text":"
float getHorizontalInput() {\n    auto& input = engine.getInputManager();\n    float dir = 0.0f;\n    if (input.isButtonDown(Buttons::LEFT)) dir -= 1.0f;\n    if (input.isButtonDown(Buttons::RIGHT)) dir += 1.0f;\n    return dir;\n}\n\nfloat getVerticalInput() {\n    auto& input = engine.getInputManager();\n    float dir = 0.0f;\n    if (input.isButtonDown(Buttons::UP)) dir -= 1.0f;\n    if (input.isButtonDown(Buttons::DOWN)) dir += 1.0f;\n    return dir;\n}\n
"},{"location":"manual/game_development/input_and_control/#input-state-machine","title":"Input State Machine","text":"

For complex input handling:

enum class InputState {\n    IDLE,\n    PRESSED,\n    HELD,\n    RELEASED\n};\n\nInputState getButtonState(const InputManager& input, uint8_t button) {\n    if (input.isButtonPressed(button)) return InputState::PRESSED;\n    if (input.isButtonDown(button)) return InputState::HELD;\n    if (input.isButtonReleased(button)) return InputState::RELEASED;\n    return InputState::IDLE;\n}\n
"},{"location":"manual/game_development/input_and_control/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/game_development/input_and_control/#button-not-responding","title":"Button Not Responding","text":"
  • Check button indices match your InputConfig
  • Verify GPIO pins (ESP32) or scancodes (Native) are correct
  • Ensure InputManager is being updated (happens automatically in Engine)
"},{"location":"manual/game_development/input_and_control/#input-feels-laggy","title":"Input Feels Laggy","text":"
  • Ensure you're using deltaTime for movement
  • Check that input is read in update(), not draw()
  • Verify framerate is stable
"},{"location":"manual/game_development/input_and_control/#multiple-triggers","title":"Multiple Triggers","text":"
  • Use isButtonPressed() instead of isButtonDown() for one-time actions
  • Implement input buffering or cooldown timers
"},{"location":"manual/game_development/input_and_control/#next-steps","title":"Next Steps","text":"

Now that you can handle input, learn about: - Audio - Add sound effects and music - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs

See also: - API Reference - InputManager - API Reference - InputConfig - Manual - Input Overview

"},{"location":"manual/game_development/physics_and_collisions/","title":"Physics and Collisions","text":"

PixelRoot32 provides a physics system for moving objects and collision detection. This guide covers PhysicsActor for automatic physics and the collision system for detecting interactions between objects.

"},{"location":"manual/game_development/physics_and_collisions/#physicsactor","title":"PhysicsActor","text":"

A PhysicsActor is an Actor that automatically handles physics: velocity, gravity, friction, and world boundary collisions.

"},{"location":"manual/game_development/physics_and_collisions/#creating-a-physicsactor","title":"Creating a PhysicsActor","text":"
#include <core/PhysicsActor.h>\n\nclass Ball : public pixelroot32::core::PhysicsActor {\npublic:\n    Ball(float x, float y, float radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRenderLayer(1);\n\n        // Set physics properties\n        setRestitution(0.8f);  // Bounciness (0.8 = 80% bounce)\n        setFriction(0.1f);     // Friction (0.1 = slight friction)\n\n        // Set world boundaries\n        setWorldSize(240, 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Apply gravity\n        // (PhysicsActor handles this automatically, but you can add custom forces)\n\n        // Call parent update to apply physics\n        PhysicsActor::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        int radius = width / 2;\n        renderer.drawFilledCircle(\n            static_cast<int>(x + radius),\n            static_cast<int>(y + radius),\n            radius,\n            pixelroot32::graphics::Color::White\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collision with other actors\n    }\n\n    void onWorldCollision() override {\n        // Called when hitting world boundaries\n        // You can play a sound effect here, for example\n    }\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#physics-properties","title":"Physics Properties","text":""},{"location":"manual/game_development/physics_and_collisions/#velocity","title":"Velocity","text":"

Set the velocity directly:

ball->setVelocity(100.0f, -50.0f); // Move right at 100 px/s, up at 50 px/s\n

Or modify existing velocity:

float vx = ball->vx; // Access velocity components (protected, use getter if needed)\nball->setVelocity(vx + 10.0f, ball->vy); // Accelerate horizontally\n
"},{"location":"manual/game_development/physics_and_collisions/#restitution-bounciness","title":"Restitution (Bounciness)","text":"

Controls how much energy is conserved in collisions:

ball->setRestitution(1.0f);  // Perfect bounce (no energy loss)\nball->setRestitution(0.5f);  // 50% energy loss\nball->setRestitution(0.0f);  // No bounce (stops on impact)\n
"},{"location":"manual/game_development/physics_and_collisions/#friction","title":"Friction","text":"

Applies gradual velocity reduction:

ball->setFriction(0.0f);  // No friction (slides forever)\nball->setFriction(0.5f);  // Moderate friction\nball->setFriction(1.0f);  // High friction (stops quickly)\n
"},{"location":"manual/game_development/physics_and_collisions/#world-boundaries","title":"World Boundaries","text":"

Set the playable area:

// Set world size (used as default boundaries)\nball->setWorldSize(240, 240);\n\n// Or set custom boundaries\npixelroot32::core::LimitRect limits(10, 10, 230, 230); // Left, Top, Right, Bottom\nball->setLimits(limits);\n
"},{"location":"manual/game_development/physics_and_collisions/#world-collision-detection","title":"World Collision Detection","text":"

Check if the actor hit world boundaries:

void update(unsigned long deltaTime) override {\n    PhysicsActor::update(deltaTime);\n\n    auto collisionInfo = getWorldCollisionInfo();\n\n    if (collisionInfo.left || collisionInfo.right) {\n        // Hit side walls\n    }\n\n    if (collisionInfo.top || collisionInfo.bottom) {\n        // Hit top/bottom walls\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#collision-system","title":"Collision System","text":"

The collision system detects when Actors overlap and triggers callbacks.

"},{"location":"manual/game_development/physics_and_collisions/#collision-layers","title":"Collision Layers","text":"

Use bit flags to organize actors into groups:

// Define layers (typically in GameLayers.h)\nnamespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;    // Bit 0\n    constexpr uint16_t ENEMY = 0x0002;     // Bit 1\n    constexpr uint16_t PROJECTILE = 0x0004; // Bit 2\n    constexpr uint16_t WALL = 0x0008;      // Bit 3\n    constexpr uint16_t PICKUP = 0x0010;    // Bit 4\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#setting-up-collisions","title":"Setting Up Collisions","text":"

Configure each actor's collision layer and mask:

class PlayerActor : public pixelroot32::core::Actor {\npublic:\n    PlayerActor(float x, float y)\n        : Actor(x, y, 16, 16) {\n        // This actor belongs to the PLAYER layer\n        setCollisionLayer(Layers::PLAYER);\n\n        // This actor can collide with ENEMY, WALL, and PICKUP\n        setCollisionMask(Layers::ENEMY | Layers::WALL | Layers::PICKUP);\n    }\n\n    // ... rest of implementation\n};\n\nclass EnemyActor : public pixelroot32::core::Actor {\npublic:\n    EnemyActor(float x, float y)\n        : Actor(x, y, 16, 16) {\n        // This actor belongs to the ENEMY layer\n        setCollisionLayer(Layers::ENEMY);\n\n        // This actor can collide with PLAYER and PROJECTILE\n        setCollisionMask(Layers::PLAYER | Layers::PROJECTILE);\n    }\n\n    // ... rest of implementation\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#collision-detection","title":"Collision Detection","text":"

Collisions are automatically detected by the Scene's CollisionSystem. You handle collisions in onCollision():

void PlayerActor::onCollision(pixelroot32::core::Actor* other) override {\n    // Check what we collided with\n    if (other->isInLayer(Layers::ENEMY)) {\n        // Hit an enemy - take damage\n        takeDamage();\n    } else if (other->isInLayer(Layers::PICKUP)) {\n        // Hit a pickup - collect it\n        collectPickup(other);\n    } else if (other->isInLayer(Layers::WALL)) {\n        // Hit a wall - stop movement\n        stopMovement();\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#hitbox","title":"Hitbox","text":"

Define the collision shape:

pixelroot32::core::Rect getHitBox() override {\n    // Simple AABB (Axis-Aligned Bounding Box)\n    return {x, y, width, height};\n\n    // Or use a smaller hitbox for more forgiving collisions\n    // return {x + 2, y + 2, width - 4, height - 4};\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#complete-example-bouncing-ball","title":"Complete Example: Bouncing Ball","text":"
#include <core/PhysicsActor.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass BouncingBall : public pixelroot32::core::PhysicsActor {\npublic:\n    BouncingBall(float x, float y, float radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRenderLayer(1);\n\n        // Physics setup\n        setRestitution(0.9f);  // Very bouncy\n        setFriction(0.05f);    // Low friction\n        setWorldSize(240, 240); // World boundaries\n\n        // Initial velocity\n        setVelocity(50.0f, -30.0f);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Apply gravity\n        float gravity = 200.0f; // pixels per second squared\n        float dt = deltaTime * 0.001f;\n        setVelocity(vx, vy + gravity * dt);\n\n        // Update physics\n        PhysicsActor::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        int radius = width / 2;\n        renderer.drawFilledCircle(\n            static_cast<int>(x + radius),\n            static_cast<int>(y + radius),\n            radius,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Bounce off other objects\n        // (PhysicsActor handles world boundaries automatically)\n    }\n\n    void onWorldCollision() override {\n        // Play bounce sound when hitting walls\n        // (Implementation depends on your audio setup)\n    }\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#complete-example-platformer-player","title":"Complete Example: Platformer Player","text":"
class PlatformerPlayer : public pixelroot32::core::PhysicsActor {\nprivate:\n    bool onGround = false;\n    float jumpForce = 250.0f;\n    float moveSpeed = 100.0f;\n\npublic:\n    PlatformerPlayer(float x, float y)\n        : PhysicsActor(x, y, 16, 16) {\n        setRenderLayer(1);\n        setFriction(0.3f);  // Ground friction\n        setWorldSize(240, 240);\n\n        // Collision setup\n        setCollisionLayer(Layers::PLAYER);\n        setCollisionMask(Layers::ENEMY | Layers::PLATFORM);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        // Horizontal movement\n        float moveDir = 0.0f;\n        if (input.isButtonDown(Buttons::LEFT)) moveDir -= 1.0f;\n        if (input.isButtonDown(Buttons::RIGHT)) moveDir += 1.0f;\n\n        setVelocity(moveDir * moveSpeed, vy);\n\n        // Apply gravity\n        float gravity = 300.0f;\n        setVelocity(vx, vy + gravity * dt);\n\n        // Jump\n        if (input.isButtonPressed(Buttons::A) && onGround) {\n            setVelocity(vx, -jumpForce);\n            onGround = false;\n        }\n\n        // Update physics\n        PhysicsActor::update(deltaTime);\n\n        // Check if on ground\n        auto collisionInfo = getWorldCollisionInfo();\n        onGround = collisionInfo.bottom;\n\n        // Also check collision with platforms\n        // (This would be handled in onCollision)\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        if (other->isInLayer(Layers::PLATFORM)) {\n            // Land on platform\n            auto platformRect = other->getHitBox();\n            if (y + height <= platformRect.y + 5) { // Within 5 pixels of top\n                y = platformRect.y - height;\n                vy = 0;\n                onGround = true;\n            }\n        } else if (other->isInLayer(Layers::ENEMY)) {\n            // Hit enemy\n            takeDamage();\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width,\n            height,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#sweep-tests","title":"Sweep Tests","text":"

For fast-moving projectiles, use sweep tests to detect collisions between positions:

#include <physics/CollisionPrimitives.h>\n\nbool checkProjectileHit(PhysicsActor* projectile, Actor* target) {\n    // Get previous and current positions\n    float prevX = projectile->x - (projectile->vx * deltaTime * 0.001f);\n    float prevY = projectile->y - (projectile->vy * deltaTime * 0.001f);\n\n    // Create circles for sweep test\n    pixelroot32::physics::Circle startCircle;\n    startCircle.x = prevX + projectile->width / 2;\n    startCircle.y = prevY + projectile->height / 2;\n    startCircle.radius = projectile->width / 2;\n\n    pixelroot32::physics::Circle endCircle;\n    endCircle.x = projectile->x + projectile->width / 2;\n    endCircle.y = projectile->y + projectile->height / 2;\n    endCircle.radius = projectile->width / 2;\n\n    // Get target rectangle\n    auto targetRect = target->getHitBox();\n\n    // Perform sweep test\n    float tHit;\n    if (pixelroot32::physics::sweepCircleVsRect(\n        startCircle, endCircle, targetRect, tHit)) {\n        // Collision detected at time tHit (0.0 = at start, 1.0 = at end)\n        return true;\n    }\n\n    return false;\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/physics_and_collisions/#collision-layers_1","title":"Collision Layers","text":"
  • Plan your layers: Design the layer system before coding
  • Use bit flags: Makes combining layers easy with | operator
  • Keep it simple: Don't create too many layers
  • Document layers: Create a GameLayers.h file with all definitions
"},{"location":"manual/game_development/physics_and_collisions/#physics","title":"Physics","text":"
  • Use appropriate values: Test gravity, speed, and forces
  • Frame-rate independence: Always use deltaTime
  • Limit world size: Keep boundaries reasonable
  • Test on hardware: Physics may behave differently on ESP32 vs PC
"},{"location":"manual/game_development/physics_and_collisions/#performance","title":"Performance","text":"
  • Limit active actors: Fewer actors = faster collision checks
  • Use layers efficiently: Reduce unnecessary collision pairs
  • Simple hitboxes: AABB is fast, complex shapes are slow
  • Sweep tests sparingly: Only for fast-moving objects
"},{"location":"manual/game_development/physics_and_collisions/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/physics_and_collisions/#collision-layer-helper","title":"Collision Layer Helper","text":"
namespace CollisionLayers {\n    constexpr uint16_t PLAYER = 0x0001;\n    constexpr uint16_t ENEMY = 0x0002;\n    constexpr uint16_t PROJECTILE = 0x0004;\n    constexpr uint16_t WALL = 0x0008;\n    constexpr uint16_t PICKUP = 0x0010;\n\n    // Helper to check if actor is in specific layer\n    bool isPlayer(Actor* actor) {\n        return actor->isInLayer(PLAYER);\n    }\n\n    bool isEnemy(Actor* actor) {\n        return actor->isInLayer(ENEMY);\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#platform-collision","title":"Platform Collision","text":"
void PlatformerPlayer::onCollision(Actor* other) override {\n    if (other->isInLayer(Layers::PLATFORM)) {\n        auto platform = other->getHitBox();\n\n        // Check if landing on top of platform\n        float playerBottom = y + height;\n        float platformTop = platform.y;\n\n        if (playerBottom <= platformTop + 5 && vy > 0) {\n            // Land on platform\n            y = platformTop - height;\n            vy = 0;\n            onGround = true;\n        }\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/game_development/physics_and_collisions/#collisions-not-detected","title":"Collisions Not Detected","text":"
  • Verify collision layers and masks overlap
  • Check that actors are added to the scene
  • Ensure Scene::update() is called
  • Verify hitboxes are correct
"},{"location":"manual/game_development/physics_and_collisions/#physics-too-fastslow","title":"Physics Too Fast/Slow","text":"
  • Adjust values based on deltaTime
  • Check gravity and velocity values
  • Test on actual hardware (ESP32 may run slower)
"},{"location":"manual/game_development/physics_and_collisions/#objects-passing-through","title":"Objects Passing Through","text":"
  • Use sweep tests for fast objects
  • Increase collision detection frequency
  • Check hitbox sizes match visual size
"},{"location":"manual/game_development/physics_and_collisions/#next-steps","title":"Next Steps","text":"

Now that you understand physics and collisions, learn about: - User Interface - Create menus and HUDs - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels

See also: - API Reference - PhysicsActor - API Reference - CollisionSystem - Manual - Physics Overview - Manual - Collision Detection

"},{"location":"manual/game_development/scenes_and_entities/","title":"Scenes and Entities","text":"

Scenes and entities are the foundation of every PixelRoot32 game. This guide teaches you how to organize your game using scenes and create interactive game objects with entities.

"},{"location":"manual/game_development/scenes_and_entities/#creating-a-scene","title":"Creating a Scene","text":"

A Scene represents a screen or level in your game. To create a scene, inherit from pixelroot32::core::Scene and implement the three main methods:

#include <core/Scene.h>\n#include <graphics/Renderer.h>\n\nclass MyGameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Called once when the scene is initialized\n        // Set up your scene here: create entities, load resources, etc.\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Called every frame\n        // Update game logic here\n\n        // IMPORTANT: Always call parent update to update all entities\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Called every frame to draw\n        // Draw your scene here\n\n        // IMPORTANT: Always call parent draw to draw all entities\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#scene-lifecycle","title":"Scene Lifecycle","text":"
  1. init(): Called once when the scene is set as active
  2. Create and initialize entities
  3. Set up game state
  4. Load resources
  5. Configure palettes, audio, etc.

  6. update(deltaTime): Called every frame

  7. Process input
  8. Update game logic
  9. Handle collisions
  10. Must call Scene::update(deltaTime) to update all entities

  11. draw(renderer): Called every frame

  12. Draw background elements
  13. Draw UI elements
  14. Must call Scene::draw(renderer) to draw all entities
"},{"location":"manual/game_development/scenes_and_entities/#basic-entities","title":"Basic Entities","text":"

An Entity is any object in your game. To create an entity, inherit from pixelroot32::core::Entity:

#include <core/Entity.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass SimpleEntity : public pixelroot32::core::Entity {\npublic:\n    SimpleEntity(float x, float y)\n        : Entity(x, y, 16, 16, pixelroot32::core::EntityType::GENERIC) {\n        // Set render layer (0=background, 1=gameplay, 2=UI)\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update entity logic\n        // For example, move the entity\n        this->x += 1.0f * (deltaTime * 0.001f); // Move right at 1 pixel per second\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw the entity\n        renderer.drawFilledRectangle(\n            static_cast<int>(x), \n            static_cast<int>(y), \n            width, \n            height, \n            pixelroot32::graphics::Color::Red\n        );\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#entity-properties","title":"Entity Properties","text":"

Every entity has these properties:

  • x, y: Position in world space (float)
  • width, height: Dimensions (int)
  • isVisible: If false, draw() is not called
  • isEnabled: If false, update() is not called
  • renderLayer: Which layer to draw on (0, 1, or 2)
"},{"location":"manual/game_development/scenes_and_entities/#adding-entities-to-a-scene","title":"Adding Entities to a Scene","text":"

Add entities to your scene in init():

void MyGameScene::init() override {\n    // Create entities\n    SimpleEntity* entity1 = new SimpleEntity(50, 50);\n    SimpleEntity* entity2 = new SimpleEntity(100, 100);\n\n    // Add them to the scene\n    addEntity(entity1);\n    addEntity(entity2);\n}\n

The scene automatically manages these entities: - Calls update() on all enabled entities each frame - Calls draw() on all visible entities each frame - Handles cleanup when the scene is destroyed

"},{"location":"manual/game_development/scenes_and_entities/#actors-entities-with-collisions","title":"Actors: Entities with Collisions","text":"

An Actor is an entity that can participate in collision detection. Inherit from pixelroot32::core::Actor:

#include <core/Actor.h>\n#include <physics/CollisionTypes.h>\n\nclass MyActor : public pixelroot32::core::Actor {\npublic:\n    MyActor(float x, float y, int w, int h)\n        : Actor(x, y, w, h) {\n        // Set collision layer (what group this actor belongs to)\n        setCollisionLayer(0x0001); // Example: layer 1\n\n        // Set collision mask (what groups this actor can collide with)\n        setCollisionMask(0x0002); // Example: can collide with layer 2\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update actor logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw the actor\n    }\n\n    // REQUIRED: Define the hitbox for collision detection\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    // REQUIRED: Handle collisions\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // React to collision\n        // For example: take damage, destroy self, etc.\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#collision-layers-and-masks","title":"Collision Layers and Masks","text":"

Collision layers use bit flags to organize actors into groups:

// Define your layers (typically in a GameLayers.h file)\nnamespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;  // Bit 0\n    constexpr uint16_t ENEMY = 0x0002;  // Bit 1\n    constexpr uint16_t PROJECTILE = 0x0004; // Bit 2\n    constexpr uint16_t WALL = 0x0008;   // Bit 3\n}\n\n// Set up a player actor\nplayer->setCollisionLayer(Layers::PLAYER);\nplayer->setCollisionMask(Layers::ENEMY | Layers::WALL); // Can collide with enemies and walls\n\n// Set up an enemy actor\nenemy->setCollisionLayer(Layers::ENEMY);\nenemy->setCollisionMask(Layers::PLAYER | Layers::PROJECTILE); // Can collide with player and projectiles\n

The collision system only checks collisions between actors whose layers and masks overlap. This is much more efficient than checking every pair.

"},{"location":"manual/game_development/scenes_and_entities/#scene-management","title":"Scene Management","text":""},{"location":"manual/game_development/scenes_and_entities/#setting-the-active-scene","title":"Setting the Active Scene","text":"

From your main code, set the active scene:

MyGameScene gameScene;\n\nvoid setup() {\n    engine.init();\n    gameScene.init();\n    engine.setScene(&gameScene); // Set as active scene\n}\n
"},{"location":"manual/game_development/scenes_and_entities/#switching-scenes","title":"Switching Scenes","text":"

To switch to a different scene:

MenuScene menuScene;\nGameScene gameScene;\n\nvoid switchToGame() {\n    gameScene.init();\n    engine.setScene(&gameScene); // Replaces current scene\n}\n
"},{"location":"manual/game_development/scenes_and_entities/#scene-stack-pushpop","title":"Scene Stack (Push/Pop)","text":"

For menus and pause screens, use the scene stack:

// Push a pause menu (game scene stays in background)\nvoid pauseGame() {\n    pauseMenu.init();\n    engine.getCurrentScene()->getSceneManager().pushScene(&pauseMenu);\n}\n\n// Pop the pause menu (resume game)\nvoid resumeGame() {\n    engine.getCurrentScene()->getSceneManager().popScene();\n}\n

Note: Scene stack management is handled internally by the Engine's SceneManager. You typically access it through engine.getCurrentScene().

"},{"location":"manual/game_development/scenes_and_entities/#complete-example","title":"Complete Example","text":"

Here's a complete example of a scene with multiple entities:

#include <core/Scene.h>\n#include <core/Entity.h>\n#include <core/Actor.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\n// A simple moving entity\nclass MovingBox : public pixelroot32::core::Entity {\npublic:\n    MovingBox(float x, float y) \n        : Entity(x, y, 20, 20, pixelroot32::core::EntityType::GENERIC),\n          speedX(50.0f), speedY(30.0f) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        float dt = deltaTime * 0.001f; // Convert to seconds\n\n        x += speedX * dt;\n        y += speedY * dt;\n\n        // Bounce off screen edges\n        if (x < 0 || x > 220) speedX = -speedX;\n        if (y < 0 || y > 220) speedY = -speedY;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x), \n            static_cast<int>(y), \n            width, \n            height, \n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\nprivate:\n    float speedX, speedY;\n};\n\n// A simple actor that can collide\nclass CollidableBox : public pixelroot32::core::Actor {\npublic:\n    CollidableBox(float x, float y)\n        : Actor(x, y, 30, 30) {\n        setRenderLayer(1);\n        setCollisionLayer(0x0001);\n        setCollisionMask(0x0001);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Static actor, no movement\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x), \n            static_cast<int>(y), \n            width, \n            height, \n            pixelroot32::graphics::Color::Yellow\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Change color when collided\n        // (In a real game, you'd handle collision logic here)\n    }\n};\n\n// The scene\nclass ExampleScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Create and add entities\n        addEntity(new MovingBox(50, 50));\n        addEntity(new MovingBox(150, 100));\n        addEntity(new CollidableBox(100, 100));\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime); // Update all entities\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background\n        renderer.drawFilledRectangle(0, 0, 240, 240, \n            pixelroot32::graphics::Color::Black);\n\n        Scene::draw(renderer); // Draw all entities\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/scenes_and_entities/#entity-management","title":"Entity Management","text":"
  • Pre-allocate entities: Create entities in init(), not in update()
  • Reuse entities: Instead of creating/destroying, enable/disable entities
  • Limit entity count: MAX_ENTITIES = 32 per scene
  • Use object pooling: For frequently created/destroyed entities (projectiles, particles)
"},{"location":"manual/game_development/scenes_and_entities/#scene-organization","title":"Scene Organization","text":"
  • One scene per screen: Menu, game, game over, etc.
  • Keep scenes focused: Each scene should have a single responsibility
  • Initialize in init(): Don't do heavy work in the constructor
  • Clean up properly: Remove entities when switching scenes
"},{"location":"manual/game_development/scenes_and_entities/#collision-layers","title":"Collision Layers","text":"
  • Plan your layers: Design your layer system before coding
  • Use bit flags: Makes layer combinations easy
  • Keep it simple: Don't over-complicate with too many layers
  • Document your layers: Create a GameLayers.h file
"},{"location":"manual/game_development/scenes_and_entities/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/scenes_and_entities/#entity-pool-pattern","title":"Entity Pool Pattern","text":"

For entities that are frequently created and destroyed (like projectiles):

class ProjectilePool {\n    static const int POOL_SIZE = 10;\n    ProjectileActor pool[POOL_SIZE];\n\npublic:\n    ProjectileActor* getAvailable() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!pool[i].isActive) {\n                pool[i].isActive = true;\n                return &pool[i];\n            }\n        }\n        return nullptr; // Pool exhausted\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#entity-factory-pattern","title":"Entity Factory Pattern","text":"

Create entities through factory functions:

Entity* createEnemy(EnemyType type, float x, float y) {\n    switch (type) {\n        case EnemyType::BASIC:\n            return new BasicEnemy(x, y);\n        case EnemyType::FAST:\n            return new FastEnemy(x, y);\n        // ...\n    }\n}\n
"},{"location":"manual/game_development/scenes_and_entities/#next-steps","title":"Next Steps","text":"

Now that you understand scenes and entities, learn about: - Basic Rendering - Draw sprites, text, and primitives - Input and Control - Handle user input - Physics and Collisions - Advanced collision handling

See also: - Fundamental Concepts - API Reference - Scene - API Reference - Entity - API Reference - Actor

"},{"location":"manual/game_development/user_interface/","title":"User Interface","text":"

PixelRoot32 provides a complete UI system for creating menus, HUDs, and interface elements. This guide covers all UI components and layout systems.

"},{"location":"manual/game_development/user_interface/#ui-elements","title":"UI Elements","text":"

All UI elements inherit from UIElement, which itself inherits from Entity. This means UI elements can be added to scenes just like any other entity.

"},{"location":"manual/game_development/user_interface/#uilabel","title":"UILabel","text":"

Display text on screen:

#include <graphics/ui/UILabel.h>\n\n// Create a label\npixelroot32::graphics::ui::UILabel* scoreLabel = new pixelroot32::graphics::ui::UILabel(\n    \"Score: 0\",                    // text\n    10,                            // x position\n    10,                            // y position\n    pixelroot32::graphics::Color::White,  // color\n    1                              // size multiplier\n);\n\n// Add to scene\naddEntity(scoreLabel);\n\n// Update text dynamically\nscoreLabel->setText(\"Score: 100\");\n\n// Center horizontally\nscoreLabel->centerX(240); // Screen width\n
"},{"location":"manual/game_development/user_interface/#uibutton","title":"UIButton","text":"

Create clickable buttons:

#include <graphics/ui/UIButton.h>\n\n// Create a button\npixelroot32::graphics::ui::UIButton* startButton = new pixelroot32::graphics::ui::UIButton(\n    \"Start Game\",                  // text\n    4,                             // navigation index\n    50,                            // x position\n    100,                           // y position\n    140,                           // width\n    30,                            // height\n    []() {                         // callback function\n        // Button clicked - start game\n        startGame();\n    }\n);\n\n// Configure style\nstartButton->setStyle(\n    pixelroot32::graphics::Color::White,   // text color\n    pixelroot32::graphics::Color::Blue,    // background color\n    true                                    // draw background\n);\n\n// Add to scene\naddEntity(startButton);\n
"},{"location":"manual/game_development/user_interface/#uicheckbox","title":"UICheckBox","text":"

Create interactive checkboxes:

#include <graphics/ui/UICheckBox.h>\n\n// Create a checkbox\npixelroot32::graphics::ui::UICheckBox* soundCheckbox = new pixelroot32::graphics::ui::UICheckBox(\n    \"Enable Sound\",                // text\n    4,                             // navigation index\n    50,                            // x position\n    140,                           // y position\n    140,                           // width\n    20,                            // height\n    true,                          // initial checked state\n    [](bool checked) {             // callback function\n        // Checkbox state changed\n        setSoundEnabled(checked);\n    },\n    1                              // font size\n);\n\n// Configure style\nsoundCheckbox->setStyle(\n    pixelroot32::graphics::Color::White,   // text color\n    pixelroot32::graphics::Color::Blue,    // background color\n    false                                  // draw background\n);\n\n// Add to scene\naddEntity(soundCheckbox);\n
"},{"location":"manual/game_development/user_interface/#uipanel","title":"UIPanel","text":"

Create visual containers with background and border:

#include <graphics/ui/UIPanel.h>\n\n// Create a panel\npixelroot32::graphics::ui::UIPanel* dialog = new pixelroot32::graphics::ui::UIPanel(\n    50,   // x\n    50,   // y\n    140,  // width\n    140   // height\n);\n\n// Configure appearance\ndialog->setBackgroundColor(pixelroot32::graphics::Color::Black);\ndialog->setBorderColor(pixelroot32::graphics::Color::White);\ndialog->setBorderWidth(2);\n\n// Add content (typically a layout)\ndialog->setChild(menuLayout);\n\n// Add to scene\naddEntity(dialog);\n
"},{"location":"manual/game_development/user_interface/#layouts","title":"Layouts","text":"

Layouts automatically organize UI elements, eliminating the need for manual position calculations.

"},{"location":"manual/game_development/user_interface/#uiverticallayout","title":"UIVerticalLayout","text":"

Organize elements vertically with automatic scrolling:

#include <graphics/ui/UIVerticalLayout.h>\n\n// Create vertical layout\npixelroot32::graphics::ui::UIVerticalLayout* menu = new pixelroot32::graphics::ui::UIVerticalLayout(\n    10,   // x\n    60,   // y\n    220,  // width\n    160   // height (viewport)\n);\n\n// Configure layout\nmenu->setPadding(5);        // Internal padding\nmenu->setSpacing(6);        // Space between elements\nmenu->setScrollEnabled(true); // Enable scrolling\n\n// Set navigation buttons\nmenu->setNavigationButtons(0, 1); // UP=0, DOWN=1\n\n// Set button styles\nmenu->setButtonStyle(\n    pixelroot32::graphics::Color::White,  // selected text\n    pixelroot32::graphics::Color::Cyan,    // selected background\n    pixelroot32::graphics::Color::White,  // unselected text\n    pixelroot32::graphics::Color::Black   // unselected background\n);\n\n// Add buttons (no manual positioning needed!)\nfor (int i = 0; i < 10; i++) {\n    UIButton* btn = new UIButton(\n        \"Option \" + std::to_string(i),\n        i,\n        0, 0,  // Position ignored - layout handles it\n        200, 20,\n        [i]() { handleOption(i); }\n    );\n    menu->addElement(btn);\n}\n\n// Add layout to scene\nmenu->setRenderLayer(2); // UI layer\naddEntity(menu);\n
"},{"location":"manual/game_development/user_interface/#uihorizontallayout","title":"UIHorizontalLayout","text":"

Organize elements horizontally:

#include <graphics/ui/UIHorizontalLayout.h>\n\n// Create horizontal layout (menu bar)\npixelroot32::graphics::ui::UIHorizontalLayout* menuBar = new pixelroot32::graphics::ui::UIHorizontalLayout(\n    0,    // x\n    0,    // y\n    240,  // width\n    30    // height\n);\n\nmenuBar->setPadding(5);\nmenuBar->setSpacing(4);\nmenuBar->setScrollEnabled(true);\nmenuBar->setNavigationButtons(2, 3); // LEFT=2, RIGHT=3\n\n// Add menu items\nmenuBar->addElement(new UIButton(\"File\", 0, 0, 0, 60, 20, []() {}));\nmenuBar->addElement(new UIButton(\"Edit\", 1, 0, 0, 60, 20, []() {}));\nmenuBar->addElement(new UIButton(\"View\", 2, 0, 0, 60, 20, []() {}));\n\naddEntity(menuBar);\n
"},{"location":"manual/game_development/user_interface/#uigridlayout","title":"UIGridLayout","text":"

Organize elements in a grid (matrix):

#include <graphics/ui/UIGridLayout.h>\n\n// Create grid layout (inventory)\npixelroot32::graphics::ui::UIGridLayout* inventory = new pixelroot32::graphics::ui::UIGridLayout(\n    10,   // x\n    60,   // y\n    220,  // width\n    160   // height\n);\n\ninventory->setColumns(4);  // 4 columns\ninventory->setPadding(5);\ninventory->setSpacing(4);\ninventory->setNavigationButtons(0, 1, 2, 3); // UP, DOWN, LEFT, RIGHT\n\n// Add items (automatically arranged in grid)\nfor (int i = 0; i < 16; i++) {\n    UIButton* item = new UIButton(\n        \"Item \" + std::to_string(i),\n        i,\n        0, 0,  // Position ignored\n        50, 50,\n        [i]() { useItem(i); }\n    );\n    inventory->addElement(item);\n}\n\naddEntity(inventory);\n
"},{"location":"manual/game_development/user_interface/#uianchorlayout","title":"UIAnchorLayout","text":"

Position elements at fixed screen positions (perfect for HUDs):

#include <graphics/ui/UIAnchorLayout.h>\n\n// Create anchor layout for HUD\npixelroot32::graphics::ui::UIAnchorLayout* hud = new pixelroot32::graphics::ui::UIAnchorLayout(\n    0,    // x\n    0,    // y\n    240,  // screen width\n    240   // screen height\n);\n\nhud->setScreenSize(240, 240);\n\n// Add HUD elements at different anchor points\nUILabel* scoreLabel = new UILabel(\"Score: 0\", 0, 0, Color::White, 1);\nUILabel* livesLabel = new UILabel(\"Lives: 3\", 0, 0, Color::White, 1);\n\nhud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\nhud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\naddEntity(hud);\n

Available Anchors: - TOP_LEFT, TOP_RIGHT, TOP_CENTER - BOTTOM_LEFT, BOTTOM_RIGHT, BOTTOM_CENTER - LEFT_CENTER, RIGHT_CENTER - CENTER

"},{"location":"manual/game_development/user_interface/#uipaddingcontainer","title":"UIPaddingContainer","text":"

Add padding around a single element:

#include <graphics/ui/UIPaddingContainer.h>\n\n// Create padding container\npixelroot32::graphics::ui::UIPaddingContainer* container = new pixelroot32::graphics::ui::UIPaddingContainer(\n    10,   // x\n    10,   // y\n    200,  // width\n    100   // height\n);\n\n// Set uniform padding\ncontainer->setPadding(10);\n\n// Or set asymmetric padding\ncontainer->setPadding(5, 15, 10, 10); // left, right, top, bottom\n\n// Add child element\ncontainer->setChild(button);\n\naddEntity(container);\n
"},{"location":"manual/game_development/user_interface/#navigation","title":"Navigation","text":"

Layouts handle D-pad navigation automatically:

"},{"location":"manual/game_development/user_interface/#vertical-navigation","title":"Vertical Navigation","text":"
verticalLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN);\n\n// Layout automatically:\n// - Highlights selected button\n// - Scrolls to keep selected button visible\n// - Handles wrapping (optional)\n
"},{"location":"manual/game_development/user_interface/#horizontal-navigation","title":"Horizontal Navigation","text":"
horizontalLayout->setNavigationButtons(Buttons::LEFT, Buttons::RIGHT);\n
"},{"location":"manual/game_development/user_interface/#grid-navigation","title":"Grid Navigation","text":"
gridLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN, Buttons::LEFT, Buttons::RIGHT);\n\n// Layout automatically:\n// - Handles 4-direction navigation\n// - Wraps around edges\n// - Updates selection\n
"},{"location":"manual/game_development/user_interface/#manual-selection","title":"Manual Selection","text":"
// Set selected element programmatically\nlayout->setSelectedIndex(2);\n\n// Get selected element\nint selected = layout->getSelectedIndex();\nUIElement* element = layout->getSelectedElement();\n
"},{"location":"manual/game_development/user_interface/#complete-example-main-menu","title":"Complete Example: Main Menu","text":"
#include <core/Scene.h>\n#include <graphics/ui/UIVerticalLayout.h>\n#include <graphics/ui/UIButton.h>\n#include <graphics/ui/UILabel.h>\n#include <graphics/ui/UIPanel.h>\n\nclass MainMenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIVerticalLayout* menuLayout;\n    pixelroot32::graphics::ui::UIPanel* menuPanel;\n\npublic:\n    void init() override {\n        // Create panel\n        menuPanel = new pixelroot32::graphics::ui::UIPanel(40, 40, 160, 160);\n        menuPanel->setBackgroundColor(pixelroot32::graphics::Color::Black);\n        menuPanel->setBorderColor(pixelroot32::graphics::Color::White);\n        menuPanel->setBorderWidth(2);\n        menuPanel->setRenderLayer(2);\n        addEntity(menuPanel);\n\n        // Create layout inside panel\n        menuLayout = new pixelroot32::graphics::ui::UIVerticalLayout(0, 0, 160, 160);\n        menuLayout->setPadding(10);\n        menuLayout->setSpacing(8);\n        menuLayout->setNavigationButtons(0, 1);\n        menuLayout->setButtonStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Cyan,\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Black\n        );\n\n        // Add title\n        pixelroot32::graphics::ui::UILabel* title = new pixelroot32::graphics::ui::UILabel(\n            \"GAME MENU\", 0, 0, pixelroot32::graphics::Color::Yellow, 2\n        );\n        menuLayout->addElement(title);\n\n        // Add menu buttons\n        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Start Game\", 0, 0, 0, 140, 25, []() { startGame(); }\n        ));\n\n        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Options\", 1, 0, 0, 140, 25, []() { showOptions(); }\n        ));\n\n        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Quit\", 2, 0, 0, 140, 25, []() { quitGame(); }\n        ));\n\n        menuPanel->setChild(menuLayout);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Handle input for layout navigation\n        auto& input = engine.getInputManager();\n        menuLayout->handleInput(input);\n\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/user_interface/#complete-example-hud","title":"Complete Example: HUD","text":"
class GameHUD : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::ui::UIAnchorLayout* hud;\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n    pixelroot32::graphics::ui::UILabel* healthLabel;\n\npublic:\n    GameHUD()\n        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::UI_ELEMENT) {\n        setRenderLayer(2); // UI layer\n\n        // Create HUD layout\n        hud = new pixelroot32::graphics::ui::UIAnchorLayout(0, 0, 240, 240);\n        hud->setScreenSize(240, 240);\n\n        // Create labels\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\", 0, 0, pixelroot32::graphics::Color::White, 1\n        );\n\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\", 0, 0, pixelroot32::graphics::Color::White, 1\n        );\n\n        healthLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Health: 100%\", 0, 0, pixelroot32::graphics::Color::Green, 1\n        );\n\n        // Position labels\n        hud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n        hud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n        hud->addElement(healthLabel, pixelroot32::graphics::ui::Anchor::BOTTOM_CENTER);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update HUD text (example)\n        char buffer[32];\n        snprintf(buffer, sizeof(buffer), \"Score: %d\", currentScore);\n        scoreLabel->setText(buffer);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // HUD draws itself through its layout\n    }\n\n    // Add HUD to scene\n    void addToScene(Scene* scene) {\n        scene->addEntity(hud);\n    }\n};\n
"},{"location":"manual/game_development/user_interface/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/user_interface/#organization","title":"Organization","text":"
  • Use render layer 2: Keep all UI on the top layer
  • Group related elements: Use panels to group menu items
  • Separate HUD from menus: Use different layouts for different UI types
  • Reuse layouts: Create layout factories for common patterns
"},{"location":"manual/game_development/user_interface/#performance","title":"Performance","text":"
  • Layouts use viewport culling: Only visible elements are rendered
  • Minimize text updates: Updating text has overhead
  • Use appropriate layouts: Choose the right layout for your needs
  • Limit element count: Too many elements can impact performance
"},{"location":"manual/game_development/user_interface/#navigation_1","title":"Navigation","text":"
  • Set navigation buttons: Configure D-pad navigation for layouts
  • Handle input in update(): Check for button presses to trigger actions
  • Provide visual feedback: Selected buttons should be clearly visible
  • Test navigation flow: Ensure navigation feels responsive
"},{"location":"manual/game_development/user_interface/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/user_interface/#menu-system","title":"Menu System","text":"
class MenuSystem {\n    UIVerticalLayout* currentMenu;\n\npublic:\n    void showMainMenu() {\n        currentMenu = createMainMenu();\n        scene->addEntity(currentMenu);\n    }\n\n    void showPauseMenu() {\n        currentMenu = createPauseMenu();\n        scene->addEntity(currentMenu);\n    }\n\n    void hideMenu() {\n        if (currentMenu) {\n            scene->removeEntity(currentMenu);\n            currentMenu = nullptr;\n        }\n    }\n};\n
"},{"location":"manual/game_development/user_interface/#dynamic-ui-updates","title":"Dynamic UI Updates","text":"
void updateHUD(int score, int lives, int health) {\n    char buffer[32];\n\n    snprintf(buffer, sizeof(buffer), \"Score: %d\", score);\n    scoreLabel->setText(buffer);\n\n    snprintf(buffer, sizeof(buffer), \"Lives: %d\", lives);\n    livesLabel->setText(buffer);\n\n    snprintf(buffer, sizeof(buffer), \"Health: %d%%\", health);\n    healthLabel->setText(buffer);\n}\n
"},{"location":"manual/game_development/user_interface/#next-steps","title":"Next Steps","text":"

Now that you understand the UI system, you've completed the core game development topics. Continue with: - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels - Performance Tuning - Improve performance

See also: - API Reference - UIElement - API Reference - UIButton - API Reference - UI Layouts - Manual - UI Overview

"},{"location":"manual/optimization/extensibility/","title":"Extensibility","text":"

PixelRoot32 is designed to be extensible. This guide covers how to create custom drivers, audio backends, and extend existing systems.

"},{"location":"manual/optimization/extensibility/#creating-custom-display-drivers","title":"Creating Custom Display Drivers","text":"

To support a new display, implement the DrawSurface interface.

"},{"location":"manual/optimization/extensibility/#drawsurface-interface","title":"DrawSurface Interface","text":"
#include <graphics/DrawSurface.h>\n\nclass MyCustomDrawer : public pixelroot32::graphics::DrawSurface {\npublic:\n    // Required methods\n    void init() override;\n    void setRotation(uint8_t rotation) override;\n    void clearBuffer() override;\n    void sendBuffer() override;\n\n    // Drawing primitives\n    void drawPixel(int x, int y, uint16_t color) override;\n    void drawLine(int x1, int y1, int x2, int y2, uint16_t color) override;\n    void drawRectangle(int x, int y, int width, int height, uint16_t color) override;\n    void drawFilledRectangle(int x, int y, int width, int height, uint16_t color) override;\n    void drawCircle(int x, int y, int radius, uint16_t color) override;\n    void drawFilledCircle(int x, int y, int radius, uint16_t color) override;\n    void drawBitmap(int x, int y, int width, int height, const uint8_t* bitmap, uint16_t color) override;\n\n    // Text (deprecated, but must implement)\n    void drawText(const char* text, int16_t x, int16_t y, uint16_t color, uint8_t size) override;\n    void drawTextCentered(const char* text, int16_t y, uint16_t color, uint8_t size) override;\n\n    // State management\n    void setTextColor(uint16_t color) override;\n    void setTextSize(uint8_t size) override;\n    void setCursor(int16_t x, int16_t y) override;\n    void setContrast(uint8_t level) override;\n    void setDisplaySize(int w, int h) override;\n\n    // Utilities\n    uint16_t color565(uint8_t r, uint8_t g, uint8_t b) override;\n    bool processEvents() override;\n    void present() override;\n};\n
"},{"location":"manual/optimization/extensibility/#example-simple-custom-drawer","title":"Example: Simple Custom Drawer","text":"
#include <graphics/DrawSurface.h>\n\nclass SimpleDrawer : public pixelroot32::graphics::DrawSurface {\nprivate:\n    uint16_t* framebuffer;\n    int width, height;\n\npublic:\n    SimpleDrawer(int w, int h) : width(w), height(h) {\n        framebuffer = new uint16_t[w * h];\n    }\n\n    ~SimpleDrawer() {\n        delete[] framebuffer;\n    }\n\n    void init() override {\n        // Initialize your display hardware\n        // Clear framebuffer\n        clearBuffer();\n    }\n\n    void clearBuffer() override {\n        for (int i = 0; i < width * height; i++) {\n            framebuffer[i] = 0x0000; // Black\n        }\n    }\n\n    void sendBuffer() override {\n        // Send framebuffer to display\n        // Implementation depends on your hardware\n    }\n\n    void drawPixel(int x, int y, uint16_t color) override {\n        if (x >= 0 && x < width && y >= 0 && y < height) {\n            framebuffer[y * width + x] = color;\n        }\n    }\n\n    void drawFilledRectangle(int x, int y, int w, int h, uint16_t color) override {\n        for (int py = y; py < y + h; py++) {\n            for (int px = x; px < x + w; px++) {\n                drawPixel(px, py, color);\n            }\n        }\n    }\n\n    // Implement other required methods...\n    // (See TFT_eSPI_Drawer or SDL2_Drawer for reference implementations)\n};\n
"},{"location":"manual/optimization/extensibility/#integrating-custom-driver","title":"Integrating Custom Driver","text":"
// Create custom drawer\nSimpleDrawer* customDrawer = new SimpleDrawer(240, 240);\n\n// Create renderer with custom drawer\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::NONE, // Use NONE for custom\n    0, 240, 240\n);\n\n// You'll need to modify Engine to accept custom DrawSurface\n// Or create a custom Engine wrapper\n
"},{"location":"manual/optimization/extensibility/#creating-custom-audio-backends","title":"Creating Custom Audio Backends","text":"

Implement the AudioBackend interface for custom audio hardware.

"},{"location":"manual/optimization/extensibility/#audiobackend-interface","title":"AudioBackend Interface","text":"
#include <audio/AudioBackend.h>\n\nclass MyCustomAudioBackend : public pixelroot32::audio::AudioBackend {\npublic:\n    // Required methods\n    void init() override;\n    void start() override;\n    void stop() override;\n    uint32_t getSampleRate() const override;\n\n    // Audio generation\n    int16_t generateSample() override;\n\n    // Channel management\n    void setChannelWave(int channel, pixelroot32::audio::WaveType type, float frequency, float duty) override;\n    void setChannelVolume(int channel, float volume) override;\n    void stopChannel(int channel) override;\n};\n
"},{"location":"manual/optimization/extensibility/#example-custom-audio-backend","title":"Example: Custom Audio Backend","text":"
#include <audio/AudioBackend.h>\n\nclass CustomAudioBackend : public pixelroot32::audio::AudioBackend {\nprivate:\n    uint32_t sampleRate;\n    float phase[4] = {0, 0, 0, 0}; // 4 channels\n    float frequency[4] = {0, 0, 0, 0};\n    float volume[4] = {0, 0, 0, 0};\n    pixelroot32::audio::WaveType waveType[4];\n\npublic:\n    CustomAudioBackend(uint32_t rate) : sampleRate(rate) {\n        for (int i = 0; i < 4; i++) {\n            waveType[i] = pixelroot32::audio::WaveType::PULSE;\n            volume[i] = 0.0f;\n        }\n    }\n\n    void init() override {\n        // Initialize your audio hardware\n    }\n\n    void start() override {\n        // Start audio output\n    }\n\n    void stop() override {\n        // Stop audio output\n    }\n\n    uint32_t getSampleRate() const override {\n        return sampleRate;\n    }\n\n    int16_t generateSample() override {\n        float sample = 0.0f;\n\n        for (int ch = 0; ch < 4; ch++) {\n            if (frequency[ch] > 0 && volume[ch] > 0) {\n                float phaseIncrement = frequency[ch] / sampleRate;\n                phase[ch] += phaseIncrement;\n                if (phase[ch] >= 1.0f) phase[ch] -= 1.0f;\n\n                float channelSample = 0.0f;\n                switch (waveType[ch]) {\n                    case pixelroot32::audio::WaveType::PULSE:\n                        channelSample = (phase[ch] < 0.5f) ? 1.0f : -1.0f;\n                        break;\n                    case pixelroot32::audio::WaveType::TRIANGLE:\n                        channelSample = (phase[ch] < 0.5f) ? \n                            (phase[ch] * 4.0f - 1.0f) : \n                            (3.0f - phase[ch] * 4.0f);\n                        break;\n                    // ... other wave types\n                }\n\n                sample += channelSample * volume[ch];\n            }\n        }\n\n        // Clamp and convert to int16_t\n        if (sample > 1.0f) sample = 1.0f;\n        if (sample < -1.0f) sample = -1.0f;\n        return static_cast<int16_t>(sample * 32767.0f);\n    }\n\n    void setChannelWave(int ch, pixelroot32::audio::WaveType type, \n                       float freq, float duty) override {\n        if (ch >= 0 && ch < 4) {\n            waveType[ch] = type;\n            frequency[ch] = freq;\n        }\n    }\n\n    void setChannelVolume(int ch, float vol) override {\n        if (ch >= 0 && ch < 4) {\n            volume[ch] = vol;\n        }\n    }\n\n    void stopChannel(int ch) override {\n        if (ch >= 0 && ch < 4) {\n            frequency[ch] = 0.0f;\n            volume[ch] = 0.0f;\n        }\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#extending-existing-systems","title":"Extending Existing Systems","text":""},{"location":"manual/optimization/extensibility/#custom-entity-types","title":"Custom Entity Types","text":"

Create specialized entity types:

class PowerUpActor : public pixelroot32::core::Actor {\nprivate:\n    PowerUpType type;\n    float lifetime = 5.0f; // 5 seconds\n\npublic:\n    PowerUpActor(float x, float y, PowerUpType t)\n        : Actor(x, y, 8, 8), type(t) {\n        setRenderLayer(1);\n        setCollisionLayer(Layers::POWERUP);\n        setCollisionMask(Layers::PLAYER);\n    }\n\n    void update(unsigned long deltaTime) override {\n        lifetime -= deltaTime * 0.001f;\n        if (lifetime <= 0) {\n            isEnabled = false;\n            isVisible = false;\n        }\n\n        // Animate (bob up and down)\n        y += sin(millis() * 0.005f) * 0.5f;\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        if (other->isInLayer(Layers::PLAYER)) {\n            applyPowerUp(other);\n            isEnabled = false;\n            isVisible = false;\n        }\n    }\n\nprivate:\n    void applyPowerUp(pixelroot32::core::Actor* player) {\n        switch (type) {\n            case PowerUpType::SPEED:\n                // Increase player speed\n                break;\n            case PowerUpType::HEALTH:\n                // Restore health\n                break;\n            // ...\n        }\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#custom-ui-layouts","title":"Custom UI Layouts","text":"

Create new layout types:

#include <graphics/ui/UILayout.h>\n\nclass UICircularLayout : public pixelroot32::graphics::ui::UILayout {\nprivate:\n    float radius;\n    float startAngle;\n\npublic:\n    UICircularLayout(float x, float y, float w, float h, float r)\n        : UILayout(x, y, w, h), radius(r), startAngle(0.0f) {\n    }\n\n    void updateLayout() override {\n        int count = elements.size();\n        float angleStep = 360.0f / count;\n\n        for (size_t i = 0; i < elements.size(); i++) {\n            float angle = startAngle + (i * angleStep);\n            float rad = angle * M_PI / 180.0f;\n\n            float elementX = x + (radius * cos(rad)) - (elements[i]->width / 2);\n            float elementY = y + (radius * sin(rad)) - (elements[i]->height / 2);\n\n            elements[i]->x = elementX;\n            elements[i]->y = elementY;\n        }\n    }\n\n    void handleInput(const pixelroot32::input::InputManager& input) override {\n        // Implement circular navigation\n        // ...\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#custom-collision-primitives","title":"Custom Collision Primitives","text":"

Extend collision system with new shapes:

// Add to your game code (not engine modification)\nstruct Triangle {\n    float x1, y1, x2, y2, x3, y3;\n};\n\nbool intersects(const Triangle& tri, const pixelroot32::core::Rect& rect) {\n    // Implement triangle-rectangle intersection\n    // ...\n    return false;\n}\n\nbool intersects(const Triangle& tri1, const Triangle& tri2) {\n    // Implement triangle-triangle intersection\n    // ...\n    return false;\n}\n
"},{"location":"manual/optimization/extensibility/#best-practices","title":"Best Practices","text":""},{"location":"manual/optimization/extensibility/#maintain-compatibility","title":"Maintain Compatibility","text":"
  • Don't break existing APIs: Extend, don't modify
  • Use inheritance: Inherit from base classes
  • Follow patterns: Match existing code patterns
  • Document extensions: Comment your custom code
"},{"location":"manual/optimization/extensibility/#testing","title":"Testing","text":"
  • Test on both platforms: ESP32 and Native
  • Test edge cases: Boundary conditions, null pointers
  • Performance testing: Ensure extensions don't hurt performance
  • Memory testing: Check for leaks with custom code
"},{"location":"manual/optimization/extensibility/#documentation","title":"Documentation","text":"
  • Comment your code: Explain why, not just what
  • Provide examples: Show how to use your extensions
  • Document limitations: State what doesn't work
  • Version compatibility: Note which engine version
"},{"location":"manual/optimization/extensibility/#common-extension-patterns","title":"Common Extension Patterns","text":""},{"location":"manual/optimization/extensibility/#factory-pattern","title":"Factory Pattern","text":"
class EntityFactory {\npublic:\n    static pixelroot32::core::Entity* createEnemy(EnemyType type, float x, float y) {\n        switch (type) {\n            case EnemyType::BASIC:\n                return new BasicEnemy(x, y);\n            case EnemyType::FAST:\n                return new FastEnemy(x, y);\n            case EnemyType::TANK:\n                return new TankEnemy(x, y);\n            default:\n                return nullptr;\n        }\n    }\n\n    static pixelroot32::core::Entity* createPowerUp(PowerUpType type, float x, float y) {\n        return new PowerUpActor(x, y, type);\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#strategy-pattern","title":"Strategy Pattern","text":"
class MovementStrategy {\npublic:\n    virtual void update(pixelroot32::core::Actor* actor, unsigned long deltaTime) = 0;\n};\n\nclass LinearMovement : public MovementStrategy {\npublic:\n    void update(pixelroot32::core::Actor* actor, unsigned long deltaTime) override {\n        actor->x += speed * (deltaTime * 0.001f);\n    }\n};\n\nclass CircularMovement : public MovementStrategy {\npublic:\n    void update(pixelroot32::core::Actor* actor, unsigned long deltaTime) override {\n        float angle = millis() * 0.001f;\n        actor->x = centerX + radius * cos(angle);\n        actor->y = centerY + radius * sin(angle);\n    }\n};\n\nclass SmartEnemy : public pixelroot32::core::Actor {\nprivate:\n    MovementStrategy* movement;\n\npublic:\n    void setMovement(MovementStrategy* strat) {\n        movement = strat;\n    }\n\n    void update(unsigned long deltaTime) override {\n        if (movement) {\n            movement->update(this, deltaTime);\n        }\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/extensibility/#driver-not-working","title":"Driver Not Working","text":"
  • Verify all interface methods are implemented
  • Check initialization order
  • Test with simple drawing first
  • Verify hardware connections
"},{"location":"manual/optimization/extensibility/#audio-backend-issues","title":"Audio Backend Issues","text":"
  • Check sample rate matches hardware
  • Verify audio generation logic
  • Test with simple tones first
  • Check channel management
"},{"location":"manual/optimization/extensibility/#extension-conflicts","title":"Extension Conflicts","text":"
  • Ensure namespace isolation
  • Avoid modifying engine code directly
  • Use composition over modification
  • Test with engine updates
"},{"location":"manual/optimization/extensibility/#next-steps","title":"Next Steps","text":"

Now that you understand extensibility, you've completed the optimization section. Continue with: - API Reference - Complete API documentation - Examples - Code examples - Resources - Tools and troubleshooting

See also: - API Reference - DrawSurface - API Reference - AudioBackend - Manual - Platforms and Drivers

"},{"location":"manual/optimization/memory_management/","title":"Memory Management","text":"

ESP32 has limited memory, so efficient memory management is crucial for PixelRoot32 games. This guide covers memory constraints, object pooling, and best practices.

"},{"location":"manual/optimization/memory_management/#esp32-memory-constraints","title":"ESP32 Memory Constraints","text":""},{"location":"manual/optimization/memory_management/#available-memory","title":"Available Memory","text":"

ESP32 typically has: - RAM: ~320KB total (varies by model) - Flash: 4MB+ (for program storage) - Heap: Limited and fragmented over time

"},{"location":"manual/optimization/memory_management/#real-world-limits","title":"Real-World Limits","text":"
  • MAX_ENTITIES: 32 per scene (hard limit)
  • Sprite data: Stored in flash (const/constexpr)
  • Dynamic allocation: Should be avoided in game loop
  • Stack: Limited (~8KB), avoid large stack allocations
"},{"location":"manual/optimization/memory_management/#object-pooling","title":"Object Pooling","text":"

Object pooling reuses objects instead of creating/destroying them, avoiding memory fragmentation.

"},{"location":"manual/optimization/memory_management/#basic-pool-pattern","title":"Basic Pool Pattern","text":"
class ProjectilePool {\nprivate:\n    static const int POOL_SIZE = 10;\n    ProjectileActor pool[POOL_SIZE];\n    bool inUse[POOL_SIZE];\n\npublic:\n    ProjectilePool() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            inUse[i] = false;\n        }\n    }\n\n    ProjectileActor* getAvailable() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!inUse[i]) {\n                inUse[i] = true;\n                return &pool[i];\n            }\n        }\n        return nullptr; // Pool exhausted\n    }\n\n    void release(ProjectileActor* projectile) {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (&pool[i] == projectile) {\n                inUse[i] = false;\n                projectile->isEnabled = false;\n                projectile->isVisible = false;\n                break;\n            }\n        }\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#using-object-pools","title":"Using Object Pools","text":"
class GameScene : public pixelroot32::core::Scene {\nprivate:\n    ProjectilePool projectilePool;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Fire projectile\n        if (input.isButtonPressed(Buttons::A)) {\n            ProjectileActor* proj = projectilePool.getAvailable();\n            if (proj) {\n                proj->x = player->x;\n                proj->y = player->y;\n                proj->isEnabled = true;\n                proj->isVisible = true;\n                // ... initialize projectile\n            }\n        }\n\n        // Clean up projectiles that hit target\n        for (auto* entity : entities) {\n            if (auto* proj = dynamic_cast<ProjectileActor*>(entity)) {\n                if (proj->hitTarget) {\n                    projectilePool.release(proj);\n                }\n            }\n        }\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#complete-example-entity-pool","title":"Complete Example: Entity Pool","text":"
template<typename T, int POOL_SIZE>\nclass EntityPool {\nprivate:\n    T pool[POOL_SIZE];\n    bool inUse[POOL_SIZE];\n    int activeCount = 0;\n\npublic:\n    EntityPool() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            inUse[i] = false;\n        }\n    }\n\n    T* acquire() {\n        if (activeCount >= POOL_SIZE) {\n            return nullptr; // Pool full\n        }\n\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!inUse[i]) {\n                inUse[i] = true;\n                activeCount++;\n                return &pool[i];\n            }\n        }\n        return nullptr;\n    }\n\n    void release(T* obj) {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (&pool[i] == obj) {\n                inUse[i] = false;\n                activeCount--;\n                obj->isEnabled = false;\n                obj->isVisible = false;\n                break;\n            }\n        }\n    }\n\n    int getActiveCount() const { return activeCount; }\n    int getAvailableCount() const { return POOL_SIZE - activeCount; }\n};\n\n// Usage\nEntityPool<EnemyActor, 8> enemyPool;\nEntityPool<ParticleEmitter, 5> particlePool;\n
"},{"location":"manual/optimization/memory_management/#scene-arena-experimental","title":"Scene Arena (Experimental)","text":"

Scene Arena provides a memory arena for scene-specific allocations, reducing fragmentation.

"},{"location":"manual/optimization/memory_management/#what-is-scene-arena","title":"What is Scene Arena?","text":"

Scene Arena is a contiguous memory block pre-allocated for a scene. All scene entities are allocated from this arena instead of the heap.

"},{"location":"manual/optimization/memory_management/#when-to-use","title":"When to Use","text":"
  • Large scenes: Scenes with many entities
  • Frequent allocation: Scenes that create/destroy entities often
  • Memory fragmentation: When heap fragmentation is a problem
  • Performance: When you need predictable allocation performance
"},{"location":"manual/optimization/memory_management/#configuration","title":"Configuration","text":"
#ifdef PIXELROOT32_ENABLE_SCENE_ARENA\n#include <core/Scene.h>\n\n// Define arena buffer (typically in scene header)\nstatic unsigned char MY_SCENE_ARENA_BUFFER[8192]; // 8KB arena\n\nclass MyScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Initialize arena\n        arena.init(MY_SCENE_ARENA_BUFFER, sizeof(MY_SCENE_ARENA_BUFFER));\n\n        // Now entities allocated with arena will use this memory\n        // (Requires custom allocation functions)\n    }\n};\n#endif\n
"},{"location":"manual/optimization/memory_management/#limitations","title":"Limitations","text":"
  • Experimental: May have bugs or limitations
  • Fixed size: Arena size must be determined at compile time
  • No reallocation: Can't resize arena at runtime
  • Manual management: Requires careful memory management

Note: Scene Arena is an experimental feature. Use object pooling for most cases.

"},{"location":"manual/optimization/memory_management/#best-practices","title":"Best Practices","text":""},{"location":"manual/optimization/memory_management/#avoid-dynamic-allocation-in-game-loop","title":"Avoid Dynamic Allocation in Game Loop","text":"
// \u274c BAD: Allocates every frame\nvoid update(unsigned long deltaTime) override {\n    if (shouldSpawnEnemy) {\n        EnemyActor* enemy = new EnemyActor(x, y);\n        addEntity(enemy);\n    }\n}\n\n// \u2705 GOOD: Use pool\nvoid update(unsigned long deltaTime) override {\n    if (shouldSpawnEnemy) {\n        EnemyActor* enemy = enemyPool.getAvailable();\n        if (enemy) {\n            enemy->reset(x, y);\n            enemy->isEnabled = true;\n        }\n    }\n}\n
"},{"location":"manual/optimization/memory_management/#pre-allocate-resources","title":"Pre-allocate Resources","text":"
class GameScene : public pixelroot32::core::Scene {\nprivate:\n    // Pre-allocated pools\n    ProjectilePool projectiles;\n    EnemyPool enemies;\n    ParticlePool particles;\n\npublic:\n    void init() override {\n        // All pools created in constructor\n        // No allocation in init() or update()\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#reuse-objects","title":"Reuse Objects","text":"
class EnemyActor : public pixelroot32::core::Actor {\npublic:\n    void reset(float x, float y) {\n        this->x = x;\n        this->y = y;\n        this->isEnabled = true;\n        this->isVisible = true;\n        this->health = maxHealth;\n        // Reset all state\n    }\n\n    void deactivate() {\n        isEnabled = false;\n        isVisible = false;\n    }\n};\n\n// Usage\nEnemyActor* enemy = enemyPool.getAvailable();\nif (enemy) {\n    enemy->reset(spawnX, spawnY);\n    addEntity(enemy);\n}\n
"},{"location":"manual/optimization/memory_management/#avoid-strings-and-dynamic-memory","title":"Avoid Strings and Dynamic Memory","text":"
// \u274c BAD: String allocation\nvoid draw(Renderer& renderer) override {\n    std::string scoreText = \"Score: \" + std::to_string(score);\n    renderer.drawText(scoreText.c_str(), 10, 10, Color::White, 1);\n}\n\n// \u2705 GOOD: Static buffer\nvoid draw(Renderer& renderer) override {\n    char scoreBuffer[32];\n    snprintf(scoreBuffer, sizeof(scoreBuffer), \"Score: %d\", score);\n    renderer.drawText(scoreBuffer, 10, 10, Color::White, 1);\n}\n
"},{"location":"manual/optimization/memory_management/#store-data-in-flash","title":"Store Data in Flash","text":"
// \u2705 GOOD: Stored in flash (const/constexpr)\nstatic const uint16_t SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    // ...\n};\n\n// \u274c BAD: Stored in RAM\nuint16_t spriteData[] = {\n    0b00111100,\n    0b01111110,\n    // ...\n};\n
"},{"location":"manual/optimization/memory_management/#memory-monitoring","title":"Memory Monitoring","text":""},{"location":"manual/optimization/memory_management/#check-available-memory","title":"Check Available Memory","text":"
#ifdef PLATFORM_ESP32\n#include <Arduino.h>\n\nvoid checkMemory() {\n    Serial.print(\"Free heap: \");\n    Serial.println(ESP.getFreeHeap());\n    Serial.print(\"Largest free block: \");\n    Serial.println(ESP.getMaxAllocHeap());\n}\n#endif\n
"},{"location":"manual/optimization/memory_management/#monitor-entity-count","title":"Monitor Entity Count","text":"
void update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);\n\n    // Check entity count\n    int entityCount = getEntityCount();\n    if (entityCount >= MAX_ENTITIES) {\n        Serial.println(\"WARNING: Entity limit reached!\");\n    }\n}\n
"},{"location":"manual/optimization/memory_management/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/optimization/memory_management/#entity-lifecycle-management","title":"Entity Lifecycle Management","text":"
class ManagedEntity {\nprivate:\n    bool isActive = false;\n\npublic:\n    void activate(float x, float y) {\n        this->x = x;\n        this->y = y;\n        isActive = true;\n        isEnabled = true;\n        isVisible = true;\n    }\n\n    void deactivate() {\n        isActive = false;\n        isEnabled = false;\n        isVisible = false;\n    }\n\n    bool getIsActive() const { return isActive; }\n};\n\n// Pool manages lifecycle\nclass EntityManager {\nprivate:\n    EntityPool<ManagedEntity, 20> pool;\n\npublic:\n    ManagedEntity* spawn(float x, float y) {\n        auto* entity = pool.acquire();\n        if (entity) {\n            entity->activate(x, y);\n        }\n        return entity;\n    }\n\n    void despawn(ManagedEntity* entity) {\n        if (entity) {\n            entity->deactivate();\n            pool.release(entity);\n        }\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#memory-efficient-collections","title":"Memory-Efficient Collections","text":"
// Fixed-size array instead of vector\nclass EntityArray {\nprivate:\n    static const int MAX_SIZE = 32;\n    pixelroot32::core::Entity* entities[MAX_SIZE];\n    int count = 0;\n\npublic:\n    bool add(pixelroot32::core::Entity* entity) {\n        if (count >= MAX_SIZE) return false;\n        entities[count++] = entity;\n        return true;\n    }\n\n    void remove(pixelroot32::core::Entity* entity) {\n        for (int i = 0; i < count; i++) {\n            if (entities[i] == entity) {\n                entities[i] = entities[--count];\n                break;\n            }\n        }\n    }\n\n    int size() const { return count; }\n    pixelroot32::core::Entity* operator[](int index) { return entities[index]; }\n};\n
"},{"location":"manual/optimization/memory_management/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/memory_management/#out-of-memory-errors","title":"Out of Memory Errors","text":"
  • Reduce pool sizes
  • Use fewer entities
  • Store more data in flash
  • Avoid dynamic allocation
  • Check for memory leaks
"},{"location":"manual/optimization/memory_management/#entity-limit-reached","title":"Entity Limit Reached","text":"
  • MAX_ENTITIES = 32 is a hard limit
  • Use object pooling to reuse entities
  • Deactivate entities instead of removing
  • Combine multiple entities into one
"},{"location":"manual/optimization/memory_management/#memory-fragmentation","title":"Memory Fragmentation","text":"
  • Use object pooling
  • Pre-allocate all resources
  • Avoid frequent new/delete
  • Consider Scene Arena (experimental)
"},{"location":"manual/optimization/memory_management/#next-steps","title":"Next Steps","text":"

Now that you understand memory management, learn about: - Performance Optimization - Improve game performance - Platforms and Drivers - Understand platform specifics - Extensibility - Extend the engine

See also: - API Reference - Scene - Manual - Scenes and Entities

"},{"location":"manual/optimization/performance_tuning/","title":"Performance Optimization","text":"

This guide covers techniques to improve game performance on ESP32, including rendering optimization, logic optimization, and profiling.

"},{"location":"manual/optimization/performance_tuning/#esp32-performance-characteristics","title":"ESP32 Performance Characteristics","text":""},{"location":"manual/optimization/performance_tuning/#cpu-limitations","title":"CPU Limitations","text":"
  • Dual-core: 240MHz (typically)
  • Single-threaded game loop: One core handles everything
  • Target FPS: 30-60 FPS (depends on game complexity)
  • Frame budget: ~16-33ms per frame at 60 FPS
"},{"location":"manual/optimization/performance_tuning/#common-bottlenecks","title":"Common Bottlenecks","text":"
  1. Rendering: Too many draw calls
  2. Collision detection: Too many collision checks
  3. Memory allocation: Dynamic allocation in game loop
  4. Complex calculations: Expensive math operations
  5. String operations: String concatenation/formatting
"},{"location":"manual/optimization/performance_tuning/#tecnicas-de-optimizacion","title":"T\u00e9cnicas de Optimizaci\u00f3n","text":"

El motor utiliza varias t\u00e9cnicas para maximizar los FPS, especialmente en hardware limitado como el ESP32.

"},{"location":"manual/optimization/performance_tuning/#1-independent-resolution-scaling-escalado-de-resolucion","title":"1. Independent Resolution Scaling (Escalado de Resoluci\u00f3n)","text":"

Esta es probablemente la optimizaci\u00f3n m\u00e1s impactante para el ESP32. Permite renderizar el juego a una resoluci\u00f3n l\u00f3gica menor (ej: 128x128) y reescalarla autom\u00e1ticamente a la resoluci\u00f3n f\u00edsica de la pantalla (ej: 240x240).

  • Reducci\u00f3n de Memoria: Un buffer de 128x128 (8bpp) consume solo 16KB, comparado con los 57KB de uno de 240x240.
  • Aumento de FPS: Al haber menos p\u00edxeles que procesar por cada primitiva o sprite, el rendimiento puede duplicarse.
  • Implementaci\u00f3n: Se realiza mediante Hardware-accelerated Nearest Neighbor durante la transferencia DMA.

Consulta la gu\u00eda completa de Resolution Scaling para aprender a configurarlo.

"},{"location":"manual/optimization/performance_tuning/#2-viewport-culling-recorte-de-camara","title":"2. Viewport Culling (Recorte de C\u00e1mara)","text":"

No proceses objetos que est\u00e1n fuera de la pantalla. El motor lo hace autom\u00e1ticamente en drawTileMap, pero debes implementarlo en tu l\u00f3gica de actualizaci\u00f3n:

bool isOnScreen(float x, float y, int width, int height, \n                const Camera2D& camera) {\n    float cameraX = camera.getX();\n    float cameraY = camera.getY();\n    int screenWidth = engine.getRenderer().getLogicalWidth();\n    int screenHeight = engine.getRenderer().getLogicalHeight();\n\n    return !(x + width < cameraX || \n             x > cameraX + screenWidth ||\n             y + height < cameraY || \n             y > cameraY + screenHeight);\n}\n
"},{"location":"manual/optimization/performance_tuning/#2-optimizacion-de-memoria-y-cpu-esp32","title":"2. Optimizaci\u00f3n de Memoria y CPU (ESP32)","text":"

Para la plataforma ESP32, se han implementado optimizaciones de bajo nivel cr\u00edticas:

  • IRAM_ATTR: Las funciones cr\u00edticas de renderizado (drawSprite, drawTileMap, etc.) est\u00e1n marcadas para ejecutarse desde la RAM interna (IRAM), eliminando la latencia de lectura de la Flash SPI.
  • DMA (Direct Memory Access): El volcado del buffer a la pantalla TFT se realiza mediante DMA, lo que permite que la CPU comience a procesar el siguiente frame mientras el hardware transfiere los datos.
  • Acceso a Datos de 16 bits: Los sprites de 2bpp y 4bpp utilizan punteros uint16_t* para garantizar accesos alineados a memoria, lo cual es significativamente m\u00e1s r\u00e1pido en la arquitectura Xtensa del ESP32.
"},{"location":"manual/optimization/performance_tuning/#3-optimizacion-de-tilemaps","title":"3. Optimizaci\u00f3n de TileMaps","text":"

El renderizado de mapas de tiles es una de las operaciones m\u00e1s costosas. PixelRoot32 utiliza:

  • Cach\u00e9 de Paleta: Durante el dibujado de un tilemap, se genera una tabla de b\u00fasqueda (LUT) temporal para evitar c\u00e1lculos de color redundantes por cada p\u00edxel.
  • Dibujado por Columnas: Optimizado para minimizar los saltos de memoria en el framebuffer.
"},{"location":"manual/optimization/performance_tuning/#4-colisiones-eficientes","title":"4. Colisiones Eficientes","text":"

Usa colisiones basadas en tiles siempre que sea posible. Acceder a un array de tiles es O(1), mientras que iterar sobre una lista de entidades es O(n).

// Ejemplo de colisi\u00f3n r\u00e1pida con el mapa\nint tileX = x / 8;\nint tileY = y / 8;\nif (levelMap.data[tileY * levelMap.width + tileX] != 0) {\n    // Colisi\u00f3n detectada\n}\n
"},{"location":"manual/optimization/performance_tuning/#recomendaciones-generales","title":"Recomendaciones Generales","text":"
  • Sprites Indexados: Prefiere Sprite2bpp (4 colores) o Sprite4bpp (16 colores) sobre Sprite (1bpp) si necesitas color, ya que est\u00e1n altamente optimizados.
  • Evitar std::string en el Loop: Las concatenaciones de strings generan fragmentaci\u00f3n de memoria. Usa buffers est\u00e1ticos o char[] para textos din\u00e1micos.
  • Perfilado: Activa el overlay de estad\u00edsticas de depuraci\u00f3n compilando con PIXELROOT32_ENABLE_DEBUG_OVERLAY (ver Engine - Debug Overlay) para monitorear FPS, RAM y carga de CPU en tiempo real.
"},{"location":"manual/optimization/performance_tuning/#common-optimization-patterns","title":"Common Optimization Patterns","text":""},{"location":"manual/optimization/performance_tuning/#update-frequency-reduction","title":"Update Frequency Reduction","text":"
class LowFrequencyUpdater {\nprivate:\n    unsigned long timer = 0;\n    unsigned long interval = 100; // Update every 100ms\n\npublic:\n    void update(unsigned long deltaTime) {\n        timer += deltaTime;\n        if (timer >= interval) {\n            timer -= interval;\n            // Do expensive update\n            expensiveUpdate();\n        }\n    }\n};\n
"},{"location":"manual/optimization/performance_tuning/#spatial-partitioning-simple","title":"Spatial Partitioning (Simple)","text":"
// Divide screen into zones\nclass SpatialGrid {\nprivate:\n    static const int GRID_SIZE = 4;\n    static const int CELL_WIDTH = 60;\n    static const int CELL_HEIGHT = 60;\n\n    std::vector<Actor*> grid[GRID_SIZE][GRID_SIZE];\n\npublic:\n    void add(Actor* actor) {\n        int cellX = static_cast<int>(actor->x) / CELL_WIDTH;\n        int cellY = static_cast<int>(actor->y) / CELL_HEIGHT;\n        if (cellX >= 0 && cellX < GRID_SIZE && \n            cellY >= 0 && cellY < GRID_SIZE) {\n            grid[cellY][cellX].push_back(actor);\n        }\n    }\n\n    void checkCollisions() {\n        // Only check collisions within same cell\n        for (int y = 0; y < GRID_SIZE; y++) {\n            for (int x = 0; x < GRID_SIZE; x++) {\n                auto& cell = grid[y][x];\n                for (size_t i = 0; i < cell.size(); i++) {\n                    for (size_t j = i + 1; j < cell.size(); j++) {\n                        checkCollision(cell[i], cell[j]);\n                    }\n                }\n            }\n        }\n    }\n};\n
"},{"location":"manual/optimization/performance_tuning/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/performance_tuning/#low-fps","title":"Low FPS","text":"
  • Profile to find bottlenecks
  • Reduce entity count
  • Optimize rendering (culling, batching)
  • Simplify collision detection
  • Reduce update frequency
"},{"location":"manual/optimization/performance_tuning/#frame-drops","title":"Frame Drops","text":"
  • Check for expensive operations in update()
  • Avoid dynamic allocation
  • Cache calculations
  • Reduce draw calls
"},{"location":"manual/optimization/performance_tuning/#stuttering","title":"Stuttering","text":"
  • Ensure frame-rate independence (use deltaTime)
  • Avoid blocking operations
  • Pre-load resources
  • Use object pooling
"},{"location":"manual/optimization/performance_tuning/#next-steps","title":"Next Steps","text":"

Now that you understand performance optimization, learn about: - Memory Management - Manage memory efficiently - Platforms and Drivers - Platform-specific optimizations - Extensibility - Extend the engine

See also: - Manual - Basic Rendering - Manual - Physics and Collisions

"},{"location":"manual/optimization/platforms_and_drivers/","title":"Platforms and Drivers","text":"

PixelRoot32 supports multiple platforms through driver abstraction. This guide covers supported platforms, display drivers, audio backends, and build configuration.

"},{"location":"manual/optimization/platforms_and_drivers/#supported-platforms","title":"Supported Platforms","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32","title":"ESP32","text":"

Primary platform for PixelRoot32 games.

Characteristics: - TFT_eSPI display driver - Internal DAC or I2S audio - GPIO button input - Limited RAM/Flash - Real hardware constraints

Use for: - Final game deployment - Hardware testing - Production builds

"},{"location":"manual/optimization/platforms_and_drivers/#nativedesktop-sdl2","title":"Native/Desktop (SDL2)","text":"

Development platform for rapid iteration.

Characteristics: - SDL2 display driver - SDL2 audio backend - Keyboard input - Unlimited resources (for testing) - Fast development cycle

Use for: - Development and debugging - Testing without hardware - Rapid prototyping - CI/CD testing

"},{"location":"manual/optimization/platforms_and_drivers/#display-drivers","title":"Display Drivers","text":""},{"location":"manual/optimization/platforms_and_drivers/#tft_espi-esp32","title":"TFT_eSPI (ESP32)","text":"

TFT_eSPI is the display driver for ESP32, supporting many TFT displays.

"},{"location":"manual/optimization/platforms_and_drivers/#optimizaciones-esp32","title":"Optimizaciones ESP32","text":"

Para maximizar el rendimiento en ESP32, PixelRoot32 utiliza:

  • DMA (Direct Memory Access): Las transferencias al display se realizan en segundo plano, permitiendo que la CPU prepare el siguiente frame mientras se env\u00eda el actual.
  • Independent Resolution Scaling: El driver soporta resoluciones l\u00f3gicas menores que las f\u00edsicas, realizando el escalado Nearest-Neighbor on-the-fly durante la transferencia DMA para ahorrar RAM y ganar FPS.
  • Doble Buffer con IRAM: El motor utiliza un buffer de pantalla (Sprite de TFT_eSPI) optimizado para transferencias r\u00e1pidas.
  • Alineaci\u00f3n de 16 bits: Los datos de sprites 2bpp/4bpp est\u00e1n alineados a palabras de 16 bits para aprovechar la arquitectura Xtensa.
  • IRAM_ATTR: Las funciones cr\u00edticas de renderizado est\u00e1n marcadas para residir en la RAM de instrucciones, evitando cuellos de botella por acceso a la Flash.
"},{"location":"manual/optimization/platforms_and_drivers/#configuracion-dma","title":"Configuraci\u00f3n DMA","text":"

El DMA se activa autom\u00e1ticamente si el hardware lo soporta. Aseg\u00farate de configurar la frecuencia SPI adecuada para tu display (usualmente 40MHz u 80MHz).

[env:esp32dev]\nbuild_flags = \n    -D ST7789_DRIVER          # Display type\n    -D TFT_WIDTH=240          # Display width\n    -D TFT_HEIGHT=240         # Display height\n    -D TFT_MOSI=23            # SPI MOSI pin\n    -D TFT_SCLK=18            # SPI clock pin\n    -D TFT_DC=2               # Data/Command pin\n    -D TFT_RST=4              # Reset pin\n    -D TFT_CS=-1              # Chip select (-1 if not used)\n    -D SPI_FREQUENCY=40000000 # SPI frequency\n
"},{"location":"manual/optimization/platforms_and_drivers/#supported-displays","title":"Supported Displays","text":"
  • ST7735: 128x128, 128x160
  • ST7789: 240x240, 240x320
  • ILI9341: 240x320
  • And more: See TFT_eSPI documentation
"},{"location":"manual/optimization/platforms_and_drivers/#usage","title":"Usage","text":"
#include <drivers/esp32/TFT_eSPI_Drawer.h>\n\n// Display configuration\n// 128x128 logic scaled to 240x240 hardware\npixelroot32::graphics::DisplayConfig displayConfig(\n    pixelroot32::graphics::DisplayType::ST7789,\n    0,      // rotation\n    240, 240, // physical width, height\n    128, 128  // logical width, height\n);\n\n// TFT_eSPI_Drawer is created automatically by Engine\n// No manual driver creation needed\n
"},{"location":"manual/optimization/platforms_and_drivers/#sdl2_drawer-native","title":"SDL2_Drawer (Native)","text":"

SDL2_Drawer provides display output for PC/desktop development.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration","title":"Configuration","text":"
#include <drivers/native/SDL2_Drawer.h>\n\n// Display configuration (NONE defaults to SDL2)\npixelroot32::graphics::DisplayConfig displayConfig(\n    pixelroot32::graphics::DisplayType::NONE,\n    0,      // rotation\n    240,    // width\n    240     // height\n);\n\n// SDL2_Drawer is created automatically\n
"},{"location":"manual/optimization/platforms_and_drivers/#sdl2-installation","title":"SDL2 Installation","text":"

Windows (MSYS2):

pacman -S mingw-w64-x86_64-SDL2\n

Linux:

sudo apt-get install libsdl2-dev\n

macOS:

brew install sdl2\n

"},{"location":"manual/optimization/platforms_and_drivers/#audio-backends","title":"Audio Backends","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32_dac_audiobackend","title":"ESP32_DAC_AudioBackend","text":"

Uses ESP32's internal DAC for audio output.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration_1","title":"Configuration","text":"
#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nconst int DAC_PIN = 25; // GPIO 25 or 26\npixelroot32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(\n    DAC_PIN,    // DAC pin (25 or 26)\n    11025       // Sample rate (Hz)\n);\n\npixelroot32::audio::AudioConfig audioConfig(\n    &audioBackend, \n    audioBackend.getSampleRate()\n);\n

Characteristics: - Simple setup (just one pin) - Lower quality than I2S - Good for basic audio - Sample rate: 11025 Hz recommended

"},{"location":"manual/optimization/platforms_and_drivers/#esp32_i2s_audiobackend","title":"ESP32_I2S_AudioBackend","text":"

Uses ESP32's I2S peripheral for higher quality audio.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration_2","title":"Configuration","text":"
#include <drivers/esp32/ESP32_I2S_AudioBackend.h>\n\nconst int I2S_BCLK = 26;  // Bit clock pin\nconst int I2S_LRCK = 25;  // Left/Right clock pin\nconst int I2S_DOUT = 22;  // Data out pin\n\npixelroot32::drivers::esp32::ESP32_I2S_AudioBackend audioBackend(\n    I2S_BCLK,\n    I2S_LRCK,\n    I2S_DOUT,\n    22050  // Sample rate (Hz)\n);\n\npixelroot32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n

Characteristics: - Higher quality than DAC - Requires external I2S DAC (e.g., MAX98357A) - Better for music - Sample rate: 22050 Hz recommended

"},{"location":"manual/optimization/platforms_and_drivers/#sdl2_audiobackend-native","title":"SDL2_AudioBackend (Native)","text":"

SDL2 audio for PC development.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration_3","title":"Configuration","text":"
#include <drivers/native/SDL2_AudioBackend.h>\n\npixelroot32::drivers::native::SDL2_AudioBackend audioBackend(\n    22050,  // Sample rate\n    1024    // Buffer size\n);\n\npixelroot32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n
"},{"location":"manual/optimization/platforms_and_drivers/#build-flags","title":"Build Flags","text":""},{"location":"manual/optimization/platforms_and_drivers/#experimental-features","title":"Experimental Features","text":"

Enable experimental features with build flags:

[env:esp32dev]\nbuild_flags = \n    -D PIXELROOT32_ENABLE_2BPP_SPRITES    # Enable 2bpp sprite format\n    - D PIXELROOT32_ENABLE_4BPP_SPRITES   # Enable 4bpp sprite format\n    - D PIXELROOT32_ENABLE_SCENE_ARENA    # Enable Scene Arena (experimental)\n    - D PIXELROOT32_ENABLE_DEBUG_OVERLAY  # On-screen debug statistics (FPS, RAM, CPU load; throttled update)\n
"},{"location":"manual/optimization/platforms_and_drivers/#debug-statistics-overlay-pixelroot32_enable_debug_overlay","title":"Debug Statistics Overlay (PIXELROOT32_ENABLE_DEBUG_OVERLAY)","text":"

When defined, the engine draws a technical overlay (FPS, RAM, CPU load) in the top-right area of the screen each frame. Values are updated every 16 frames to maintain performance. No code changes are required. See API Reference - Engine - Optional: Debug Overlay for details.

"},{"location":"manual/optimization/platforms_and_drivers/#scene-limits-max_layers-max_entities","title":"Scene limits (MAX_LAYERS / MAX_ENTITIES)","text":"

You can override the default scene limits from your project without modifying the engine. The default of 3 for MAX_LAYERS is due to ESP32 platform constraints (memory and draw-loop cost); on native/PC you can use a higher value.

Option A: Compiler flags (recommended) \u2014 in platformio.ini, add to build_flags for your environment:

build_flags =\n    -DMAX_LAYERS=5\n    -DMAX_ENTITIES=64\n

The compiler defines these before any .cpp is processed. Because Scene.h uses #ifndef MAX_LAYERS / #ifndef MAX_ENTITIES, your values are used (more render layers drawn in Scene::draw, and on Arduino the entity queue capacity when built with MAX_ENTITIES).

See API Reference - Scene - Overriding scene limits for details.

"},{"location":"manual/optimization/platforms_and_drivers/#platform-detection","title":"Platform Detection","text":"
#ifdef PLATFORM_ESP32\n    // ESP32-specific code\n    Serial.println(\"Running on ESP32\");\n#endif\n\n#ifdef PLATFORM_NATIVE\n    // Native/PC-specific code\n    printf(\"Running on PC\\n\");\n#endif\n
"},{"location":"manual/optimization/platforms_and_drivers/#optimization-flags","title":"Optimization Flags","text":"
[env:esp32dev]\nbuild_flags = \n    -O2              # Optimization level\n    -ffunction-sections\n    -fdata-sections\n    -Wl,--gc-sections\n
"},{"location":"manual/optimization/platforms_and_drivers/#complete-platform-setup-examples","title":"Complete Platform Setup Examples","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32-complete-setup","title":"ESP32 Complete Setup","text":"
#include <Arduino.h>\n#include <core/Engine.h>\n#include <drivers/esp32/TFT_eSPI_Drawer.h>\n#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\n// Audio\nconst int DAC_PIN = 25;\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\n// Display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::ST7789,\n    0, 240, 240\n);\n\n// Input\npr32::input::InputConfig inputConfig(\n    6, 32, 27, 33, 14, 13, 12  // 6 buttons, pins\n);\n\n// Audio config\npr32::audio::AudioConfig audioConfig(&audioBackend, 11025);\n\n// Engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nvoid setup() {\n    Serial.begin(115200);\n    engine.init();\n    // ... scene setup\n}\n\nvoid loop() {\n    engine.run();\n}\n
"},{"location":"manual/optimization/platforms_and_drivers/#native-complete-setup","title":"Native Complete Setup","text":"
#define SDL_MAIN_HANDLED\n#include <SDL2/SDL.h>\n#include <core/Engine.h>\n#include <drivers/native/SDL2_Drawer.h>\n#include <drivers/native/SDL2_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\n// Audio\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\n\n// Display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::NONE,\n    0, 240, 240\n);\n\n// Input (SDL scancodes)\npr32::input::InputConfig inputConfig(\n    6,\n    SDL_SCANCODE_UP,\n    SDL_SCANCODE_DOWN,\n    SDL_SCANCODE_LEFT,\n    SDL_SCANCODE_RIGHT,\n    SDL_SCANCODE_SPACE,\n    SDL_SCANCODE_RETURN\n);\n\n// Audio config\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n\n// Engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nint main(int argc, char* argv[]) {\n    engine.init();\n    // ... scene setup\n    engine.run();\n    return 0;\n}\n
"},{"location":"manual/optimization/platforms_and_drivers/#platform-specific-considerations","title":"Platform-Specific Considerations","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32_1","title":"ESP32","text":"

Memory: - Limited RAM (~320KB) - Use object pooling - Store data in flash - Avoid dynamic allocation

Performance: - Target 30-60 FPS - Optimize rendering - Reduce entity count - Profile on hardware

Hardware: - GPIO pin configuration - SPI display setup - Audio hardware connections - Power considerations

"},{"location":"manual/optimization/platforms_and_drivers/#native","title":"Native","text":"

Development: - Fast iteration - Easy debugging - Unlimited resources - Visual debugging tools

Testing: - Test logic without hardware - Rapid prototyping - CI/CD integration - Cross-platform testing

"},{"location":"manual/optimization/platforms_and_drivers/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32-display-issues","title":"ESP32 Display Issues","text":"
  • Check wiring connections
  • Verify pin numbers
  • Lower SPI frequency
  • Check display type matches
  • Verify power supply
"},{"location":"manual/optimization/platforms_and_drivers/#esp32-audio-issues","title":"ESP32 Audio Issues","text":"
  • Check DAC/I2S pin configuration
  • Verify sample rate
  • Check hardware connections
  • Lower volume if distorted
  • Test with different sample rates
"},{"location":"manual/optimization/platforms_and_drivers/#native-build-issues","title":"Native Build Issues","text":"
  • Verify SDL2 installation
  • Check include/library paths
  • Ensure SDL2 version compatibility
  • Check linker flags
"},{"location":"manual/optimization/platforms_and_drivers/#next-steps","title":"Next Steps","text":"

Now that you understand platforms and drivers, learn about: - Extensibility - Create custom drivers - Memory Management - ESP32 memory constraints - Performance Optimization - Platform-specific optimization

See also: - API Reference - DrawSurface - API Reference - AudioBackend - Getting Started - Your First Project

"},{"location":"reference/api_overview/","title":"API Reference Overview","text":"

This document provides a complete technical reference for all PixelRoot32 APIs, organized by module. Each class includes descriptions, constructors, methods, properties, and usage examples.

"},{"location":"reference/api_overview/#organization","title":"Organization","text":"

The API is organized into the following modules:

  • Core: Engine, Scene, Entity, Actor, PhysicsActor, SceneManager
  • Graphics: Renderer, Camera2D, Color, Font, Sprite, TileMap, DrawSurface
  • Audio: AudioEngine, MusicPlayer, AudioTypes, AudioConfig, AudioBackend
  • Input: InputManager, InputConfig
  • Physics: CollisionSystem, CollisionTypes
  • UI: UIElement, UIButton, UILabel, UILayouts
  • Particles: ParticleEmitter, ParticleConfig, ParticlePresets
"},{"location":"reference/api_overview/#quick-navigation","title":"Quick Navigation","text":""},{"location":"reference/api_overview/#core-module","title":"Core Module","text":"
  • Engine - Main engine class, game loop management
  • Scene - Scene/level management
  • Entity - Base game object class
  • Actor - Entity with collision support
  • PhysicsActor - Actor with automatic physics
  • InputManager - Input handling
  • InputConfig - Input configuration
"},{"location":"reference/api_overview/#graphics-module","title":"Graphics Module","text":"
  • Renderer - High-level rendering API
  • Camera2D - 2D camera for scrolling
  • Color - Color constants and utilities
  • Font - Bitmap font system
  • Sprite - Sprite structures and formats
  • TileMap - Tilemap structure
  • DisplayConfig - Display configuration
"},{"location":"reference/api_overview/#audio-module","title":"Audio Module","text":"
  • AudioEngine - Sound effects playback
  • MusicPlayer - Background music playback
  • AudioTypes - Audio data structures
  • AudioConfig - Audio configuration
"},{"location":"reference/api_overview/#physics-module","title":"Physics Module","text":"
  • CollisionSystem - Collision detection
  • CollisionTypes - Collision primitives
"},{"location":"reference/api_overview/#ui-module","title":"UI Module","text":"
  • UIElement - Base UI element class
  • UIButton - Clickable button
  • UILabel - Text label
  • UILayouts - Layout containers
"},{"location":"reference/api_overview/#api-documentation-format","title":"API Documentation Format","text":"

Each API reference page follows this structure:

"},{"location":"reference/api_overview/#class-name","title":"Class Name","text":"

Brief description of the class and its purpose.

"},{"location":"reference/api_overview/#namespace","title":"Namespace","text":"
namespace pixelroot32::module {\n    class ClassName {\n        // ...\n    };\n}\n
"},{"location":"reference/api_overview/#constructors","title":"Constructors","text":"

List of all constructors with parameters.

"},{"location":"reference/api_overview/#public-methods","title":"Public Methods","text":"Method Description Parameters Returns methodName() Description param: type return type"},{"location":"reference/api_overview/#properties","title":"Properties","text":"Property Type Description property type Description"},{"location":"reference/api_overview/#usage-example","title":"Usage Example","text":"
// Example code showing typical usage\n
"},{"location":"reference/api_overview/#performance-notes","title":"Performance Notes","text":"

Any performance considerations or limitations.

"},{"location":"reference/api_overview/#see-also","title":"See Also","text":"

Links to related APIs and documentation.

"},{"location":"reference/api_overview/#finding-apis","title":"Finding APIs","text":""},{"location":"reference/api_overview/#by-functionality","title":"By Functionality","text":"
  • Game Loop: See Engine
  • Rendering: See Renderer
  • Input: See InputManager
  • Audio: See AudioEngine and MusicPlayer
  • Physics: See PhysicsActor and CollisionSystem
  • UI: See UIElement and layouts
"},{"location":"reference/api_overview/#by-module","title":"By Module","text":"

Navigate to the specific module folder: - api_reference/core/ - Core engine classes - api_reference/graphics/ - Rendering and graphics - api_reference/audio/ - Audio system - api_reference/physics/ - Physics and collisions - api_reference/ui/ - User interface

"},{"location":"reference/api_overview/#complete-api-list","title":"Complete API List","text":""},{"location":"reference/api_overview/#core","title":"Core","text":"
  • Engine
  • Scene
  • Entity
  • Actor
  • PhysicsActor
  • InputManager
  • InputConfig
"},{"location":"reference/api_overview/#graphics","title":"Graphics","text":"
  • Renderer
  • Camera2D
  • Color
  • Font
  • Sprite
  • TileMap
  • DisplayConfig
"},{"location":"reference/api_overview/#audio","title":"Audio","text":"
  • AudioEngine
  • MusicPlayer
  • AudioTypes
  • AudioConfig
"},{"location":"reference/api_overview/#physics","title":"Physics","text":"
  • CollisionSystem
  • CollisionTypes
"},{"location":"reference/api_overview/#ui","title":"UI","text":"
  • UIElement
  • UIButton
  • UILabel
  • UIVerticalLayout
  • UIHorizontalLayout
  • UIGridLayout
  • UIAnchorLayout
  • UIPanel
  • UIPaddingContainer
"},{"location":"reference/api_overview/#related-documentation","title":"Related Documentation","text":"
  • Manual - Game Development - How to use the APIs
  • Manual - Advanced Graphics - Advanced techniques
  • Code Examples - Reusable code snippets
  • Game Examples Guide - Learn from complete games

Note: This is an overview. For detailed API documentation, see the individual reference pages linked above.

"},{"location":"reference/code_examples/","title":"Code Examples","text":"

A library of reusable code snippets for common PixelRoot32 tasks. All examples are complete and functional.

"},{"location":"reference/code_examples/#initialization","title":"Initialization","text":""},{"location":"reference/code_examples/#basic-engine-setup-esp32","title":"Basic Engine Setup (ESP32)","text":"
#include <Arduino.h>\n#include <core/Engine.h>\n#include <drivers/esp32/TFT_eSPI_Drawer.h>\n#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\n// Audio\nconst int DAC_PIN = 25;\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\n// Display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::ST7789,\n    0, 240, 240\n);\n\n// Input\npr32::input::InputConfig inputConfig(6, 32, 27, 33, 14, 13, 12);\n\n// Audio config\npr32::audio::AudioConfig audioConfig(&audioBackend, 11025);\n\n// Engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nvoid setup() {\n    Serial.begin(115200);\n    engine.init();\n    // ... scene setup\n}\n\nvoid loop() {\n    engine.run();\n}\n
"},{"location":"reference/code_examples/#basic-engine-setup-native","title":"Basic Engine Setup (Native)","text":"
#define SDL_MAIN_HANDLED\n#include <SDL2/SDL.h>\n#include <core/Engine.h>\n#include <drivers/native/SDL2_Drawer.h>\n#include <drivers/native/SDL2_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::NONE, 0, 240, 240\n);\npr32::input::InputConfig inputConfig(\n    6, SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, \n    SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT,\n    SDL_SCANCODE_SPACE, SDL_SCANCODE_RETURN\n);\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nint main(int argc, char* argv[]) {\n    engine.init();\n    // ... scene setup\n    engine.run();\n    return 0;\n}\n
"},{"location":"reference/code_examples/#entity-movement","title":"Entity Movement","text":""},{"location":"reference/code_examples/#simple-movement","title":"Simple Movement","text":"
class MovingEntity : public pixelroot32::core::Entity {\nprivate:\n    float speedX = 50.0f;\n    float speedY = 30.0f;\n\npublic:\n    MovingEntity(float x, float y)\n        : Entity(x, y, 16, 16, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        float dt = deltaTime * 0.001f;\n        x += speedX * dt;\n        y += speedY * dt;\n\n        // Bounce off edges\n        if (x < 0 || x > 224) speedX = -speedX;\n        if (y < 0 || y > 224) speedY = -speedY;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width, height,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n};\n
"},{"location":"reference/code_examples/#input-based-movement","title":"Input-Based Movement","text":"
class PlayerEntity : public pixelroot32::core::Actor {\nprivate:\n    float speed = 100.0f;\n\npublic:\n    PlayerEntity(float x, float y)\n        : Actor(x, y, 16, 16) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        if (input.isButtonDown(Buttons::LEFT)) {\n            x -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::RIGHT)) {\n            x += speed * dt;\n        }\n        if (input.isButtonDown(Buttons::UP)) {\n            y -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::DOWN)) {\n            y += speed * dt;\n        }\n\n        // Keep on screen\n        if (x < 0) x = 0;\n        if (x > 224) x = 224;\n        if (y < 0) y = 0;\n        if (y > 224) y = 224;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width, height,\n            pixelroot32::graphics::Color::White\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collision\n    }\n};\n
"},{"location":"reference/code_examples/#collisions","title":"Collisions","text":""},{"location":"reference/code_examples/#basic-collision-detection","title":"Basic Collision Detection","text":"
class CollidableEntity : public pixelroot32::core::Actor {\npublic:\n    CollidableEntity(float x, float y)\n        : Actor(x, y, 16, 16) {\n        setRenderLayer(1);\n        setCollisionLayer(Layers::PLAYER);\n        setCollisionMask(Layers::ENEMY | Layers::WALL);\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        if (other->isInLayer(Layers::ENEMY)) {\n            // Hit enemy\n            takeDamage();\n        } else if (other->isInLayer(Layers::WALL)) {\n            // Hit wall\n            stopMovement();\n        }\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"reference/code_examples/#collision-layers-setup","title":"Collision Layers Setup","text":"
// Define in GameLayers.h\nnamespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;\n    constexpr uint16_t ENEMY = 0x0002;\n    constexpr uint16_t PROJECTILE = 0x0004;\n    constexpr uint16_t WALL = 0x0008;\n    constexpr uint16_t PICKUP = 0x0010;\n}\n\n// Usage\nplayer->setCollisionLayer(Layers::PLAYER);\nplayer->setCollisionMask(Layers::ENEMY | Layers::WALL);\n\nenemy->setCollisionLayer(Layers::ENEMY);\nenemy->setCollisionMask(Layers::PLAYER | Layers::PROJECTILE);\n
"},{"location":"reference/code_examples/#sound-effects","title":"Sound Effects","text":""},{"location":"reference/code_examples/#common-sound-effects","title":"Common Sound Effects","text":"
namespace SoundEffects {\n    inline pixelroot32::audio::AudioEvent jump() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 600.0f;\n        evt.duration = 0.1f;\n        evt.volume = 0.7f;\n        evt.duty = 0.25f;\n        return evt;\n    }\n\n    inline pixelroot32::audio::AudioEvent coin() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 1500.0f;\n        evt.duration = 0.12f;\n        evt.volume = 0.8f;\n        evt.duty = 0.5f;\n        return evt;\n    }\n\n    inline pixelroot32::audio::AudioEvent explosion() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::NOISE;\n        evt.frequency = 200.0f;\n        evt.duration = 0.3f;\n        evt.volume = 0.9f;\n        return evt;\n    }\n}\n\n// Usage\nengine.getAudioEngine().playEvent(SoundEffects::jump());\n
"},{"location":"reference/code_examples/#playing-sound-on-event","title":"Playing Sound on Event","text":"
class PlayerActor : public pixelroot32::core::Actor {\npublic:\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n\n        if (input.isButtonPressed(Buttons::A)) {\n            // Play jump sound\n            pixelroot32::audio::AudioEvent jumpSound{};\n            jumpSound.type = pixelroot32::audio::WaveType::PULSE;\n            jumpSound.frequency = 800.0f;\n            jumpSound.duration = 0.1f;\n            jumpSound.volume = 0.7f;\n            jumpSound.duty = 0.25f;\n\n            engine.getAudioEngine().playEvent(jumpSound);\n\n            // Jump logic\n            jump();\n        }\n    }\n};\n
"},{"location":"reference/code_examples/#ui-components","title":"UI Components","text":""},{"location":"reference/code_examples/#simple-menu","title":"Simple Menu","text":"
class MenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIVerticalLayout* menu;\n\npublic:\n    void init() override {\n        menu = new pixelroot32::graphics::ui::UIVerticalLayout(40, 60, 160, 160);\n        menu->setPadding(10);\n        menu->setSpacing(8);\n        menu->setNavigationButtons(0, 1);\n        menu->setButtonStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Cyan,\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Black\n        );\n\n        menu->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Start\", 0, 0, 0, 140, 25, []() { startGame(); }\n        ));\n\n        menu->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Options\", 1, 0, 0, 140, 25, []() { showOptions(); }\n        ));\n\n        addEntity(menu);\n    }\n\n    void update(unsigned long deltaTime) override {\n        menu->handleInput(engine.getInputManager());\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"reference/code_examples/#hud-with-labels","title":"HUD with Labels","text":"
class GameHUD : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n\npublic:\n    GameHUD()\n        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::UI_ELEMENT) {\n        setRenderLayer(2);\n\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\", 10, 10,\n            pixelroot32::graphics::Color::White, 1\n        );\n\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\", 10, 20,\n            pixelroot32::graphics::Color::White, 1\n        );\n    }\n\n    void updateHUD(int score, int lives) {\n        char buffer[32];\n        snprintf(buffer, sizeof(buffer), \"Score: %d\", score);\n        scoreLabel->setText(buffer);\n\n        snprintf(buffer, sizeof(buffer), \"Lives: %d\", lives);\n        livesLabel->setText(buffer);\n    }\n};\n
"},{"location":"reference/code_examples/#physics","title":"Physics","text":""},{"location":"reference/code_examples/#bouncing-ball","title":"Bouncing Ball","text":"
class BouncingBall : public pixelroot32::core::PhysicsActor {\npublic:\n    BouncingBall(float x, float y, float radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRenderLayer(1);\n        setRestitution(0.9f);\n        setFriction(0.05f);\n        setWorldSize(240, 240);\n        setVelocity(50.0f, -30.0f);\n    }\n\n    void update(unsigned long deltaTime) override {\n        float gravity = 200.0f;\n        float dt = deltaTime * 0.001f;\n        setVelocity(vx, vy + gravity * dt);\n        PhysicsActor::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        int radius = width / 2;\n        renderer.drawFilledCircle(\n            static_cast<int>(x + radius),\n            static_cast<int>(y + radius),\n            radius,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"reference/code_examples/#platformer-player","title":"Platformer Player","text":"
class PlatformerPlayer : public pixelroot32::core::PhysicsActor {\nprivate:\n    bool canJump = true;\n    float jumpForce = 250.0f;\n    float moveSpeed = 100.0f;\n\npublic:\n    PlatformerPlayer(float x, float y)\n        : PhysicsActor(x, y, 16, 16) {\n        setRenderLayer(1);\n        setFriction(0.3f);\n        setWorldSize(240, 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        // Horizontal movement\n        float moveDir = 0.0f;\n        if (input.isButtonDown(Buttons::LEFT)) moveDir -= 1.0f;\n        if (input.isButtonDown(Buttons::RIGHT)) moveDir += 1.0f;\n        setVelocity(moveDir * moveSpeed, vy);\n\n        // Gravity\n        float gravity = 300.0f;\n        setVelocity(vx, vy + gravity * dt);\n\n        // Jump\n        if (input.isButtonPressed(Buttons::A) && canJump) {\n            setVelocity(vx, -jumpForce);\n            canJump = false;\n        }\n\n        PhysicsActor::update(deltaTime);\n\n        // Check if on ground\n        auto collisionInfo = getWorldCollisionInfo();\n        if (collisionInfo.bottom) {\n            canJump = true;\n        }\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"reference/code_examples/#sprites-and-animation","title":"Sprites and Animation","text":""},{"location":"reference/code_examples/#simple-sprite","title":"Simple Sprite","text":"
// Define sprite data\nstatic const uint16_t PLAYER_SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b01111110,\n    0b00111100,\n    0b00000000\n};\n\nstatic const pixelroot32::graphics::Sprite PLAYER_SPRITE = {\n    PLAYER_SPRITE_DATA, 8, 8\n};\n\n// Draw sprite\nrenderer.drawSprite(PLAYER_SPRITE, 100, 100, \n    pixelroot32::graphics::Color::White);\n
"},{"location":"reference/code_examples/#sprite-animation","title":"Sprite Animation","text":"
class AnimatedActor : public pixelroot32::core::Actor {\nprivate:\n    pixelroot32::graphics::SpriteAnimation animation;\n    unsigned long timer = 0;\n    const unsigned long FRAME_DURATION_MS = 100;\n\npublic:\n    AnimatedActor(float x, float y)\n        : Actor(x, y, 8, 8) {\n        setRenderLayer(1);\n        animation.frames = WALK_ANIMATION_FRAMES;\n        animation.frameCount = 3;\n        animation.current = 0;\n    }\n\n    void update(unsigned long deltaTime) override {\n        timer += deltaTime;\n        if (timer >= FRAME_DURATION_MS) {\n            timer -= FRAME_DURATION_MS;\n            animation.step();\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        const auto* frame = animation.frames[animation.current].sprite;\n        renderer.drawSprite(*frame, static_cast<int>(x), static_cast<int>(y),\n            pixelroot32::graphics::Color::White);\n    }\n};\n
"},{"location":"reference/code_examples/#camera-and-scrolling","title":"Camera and Scrolling","text":""},{"location":"reference/code_examples/#basic-camera-follow","title":"Basic Camera Follow","text":"
class ScrollingScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n        camera.setBounds(0, 2000 - screenWidth);\n\n        player = new PlayerActor(100, 100);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"reference/code_examples/#tilemaps","title":"Tilemaps","text":""},{"location":"reference/code_examples/#simple-tilemap","title":"Simple Tilemap","text":"
// Define tiles\nstatic const uint16_t TILE_EMPTY_BITS[] = { /* ... */ };\nstatic const uint16_t TILE_GROUND_BITS[] = { /* ... */ };\n\nstatic const pixelroot32::graphics::Sprite TILES[] = {\n    { TILE_EMPTY_BITS, 8, 8 },\n    { TILE_GROUND_BITS, 8, 8 }\n};\n\n// Create tilemap\nstatic uint8_t TILEMAP_INDICES[30 * 20];\nstatic pixelroot32::graphics::TileMap levelTileMap = {\n    TILEMAP_INDICES, 30, 20, TILES, 8, 8, 2\n};\n\n// Initialize\nvoid initTilemap() {\n    for (int i = 0; i < 30 * 20; i++) {\n        TILEMAP_INDICES[i] = 0;\n    }\n    // Set ground row\n    for (int x = 0; x < 30; x++) {\n        TILEMAP_INDICES[19 * 30 + x] = 1; // Ground tile\n    }\n}\n\n// Draw\nrenderer.drawTileMap(levelTileMap, 0, 0, \n    pixelroot32::graphics::Color::White);\n
"},{"location":"reference/code_examples/#particles","title":"Particles","text":""},{"location":"reference/code_examples/#explosion-effect","title":"Explosion Effect","text":"
#include <graphics/particles/ParticleEmitter.h>\n#include <graphics/particles/ParticlePresets.h>\n\nclass ExplosionEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* emitter;\n\npublic:\n    ExplosionEffect()\n        : Entity(0, 0, 1, 1, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n        emitter = new pixelroot32::graphics::particles::ParticleEmitter(\n            0, 0,\n            pixelroot32::graphics::particles::ParticlePresets::Explosion()\n        );\n    }\n\n    void trigger(float x, float y) {\n        this->x = x;\n        this->y = y;\n        emitter->burst(x, y, 25);\n    }\n\n    void update(unsigned long deltaTime) override {\n        emitter->update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        emitter->draw(renderer);\n    }\n};\n
"},{"location":"reference/code_examples/#object-pooling","title":"Object Pooling","text":""},{"location":"reference/code_examples/#entity-pool","title":"Entity Pool","text":"
template<typename T, int POOL_SIZE>\nclass EntityPool {\nprivate:\n    T pool[POOL_SIZE];\n    bool inUse[POOL_SIZE];\n    int activeCount = 0;\n\npublic:\n    EntityPool() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            inUse[i] = false;\n        }\n    }\n\n    T* acquire() {\n        if (activeCount >= POOL_SIZE) return nullptr;\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!inUse[i]) {\n                inUse[i] = true;\n                activeCount++;\n                return &pool[i];\n            }\n        }\n        return nullptr;\n    }\n\n    void release(T* obj) {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (&pool[i] == obj) {\n                inUse[i] = false;\n                activeCount--;\n                obj->isEnabled = false;\n                obj->isVisible = false;\n                break;\n            }\n        }\n    }\n};\n
"},{"location":"reference/code_examples/#common-patterns","title":"Common Patterns","text":""},{"location":"reference/code_examples/#state-machine","title":"State Machine","text":"
enum class GameState {\n    MENU,\n    PLAYING,\n    PAUSED,\n    GAME_OVER\n};\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    GameState currentState = GameState::MENU;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        switch (currentState) {\n            case GameState::MENU:\n                updateMenu();\n                break;\n            case GameState::PLAYING:\n                updateGame();\n                break;\n            case GameState::PAUSED:\n                updatePause();\n                break;\n            case GameState::GAME_OVER:\n                updateGameOver();\n                break;\n        }\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"reference/code_examples/#timer-pattern","title":"Timer Pattern","text":"
class Timer {\nprivate:\n    unsigned long duration;\n    unsigned long elapsed = 0;\n    bool active = false;\n\npublic:\n    Timer(unsigned long ms) : duration(ms) {}\n\n    void start() {\n        active = true;\n        elapsed = 0;\n    }\n\n    void update(unsigned long deltaTime) {\n        if (active) {\n            elapsed += deltaTime;\n            if (elapsed >= duration) {\n                active = false;\n            }\n        }\n    }\n\n    bool isFinished() const { return !active && elapsed >= duration; }\n    bool isActive() const { return active; }\n    float getProgress() const { return static_cast<float>(elapsed) / duration; }\n};\n
"},{"location":"reference/code_examples/#see-also","title":"See Also","text":"
  • API Reference Overview - Complete API documentation
  • Game Examples Guide - Learn from complete games
  • Manual - Game Development - Detailed guides
"},{"location":"reference/game_examples_guide/","title":"Game Examples Guide","text":"

This guide analyzes the complete game examples included with PixelRoot32, explaining their architecture, patterns, and lessons learned.

"},{"location":"reference/game_examples_guide/#available-examples","title":"Available Examples","text":"

PixelRoot32 (in the PixelRoot32 Game Samples project) includes these games and demos:

  • Metroidvania: 2D platformer with multi-layer 4bpp tilemap and tile-based collision (requires PIXELROOT32_ENABLE_4BPP_SPRITES; no scroll/camera)
  • Space Invaders: Full shooter with enemies, projectiles, bunkers and audio
  • Pong: Classic with physics and collisions
  • BrickBreaker: Breakout-style with particles and advanced audio
  • Snake: Grid-based game with entity pooling
  • TicTacToe: Turn-based with simple AI
  • CameraDemo: Platformer with camera and parallax
  • SpritesDemo: 2bpp and 4bpp sprites
  • TileMapDemo: 4bpp tilemaps (with viewport culling)
"},{"location":"reference/game_examples_guide/#space-invaders","title":"Space Invaders","text":"

Location: src/examples/SpaceInvaders/

"},{"location":"reference/game_examples_guide/#architecture","title":"Architecture","text":"

Space Invaders demonstrates a complete game with multiple systems:

  • Scene Management: SpaceInvadersScene manages game state
  • Actor Hierarchy: PlayerActor, AlienActor, ProjectileActor, BunkerActor
  • Collision System: Uses collision layers for player, enemies, projectiles
  • Audio Integration: Sound effects for shooting, explosions, music
  • Background: Starfield (code-generated star pattern) or tilemap
"},{"location":"reference/game_examples_guide/#key-systems","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#collision-layers","title":"Collision Layers","text":"
namespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;\n    constexpr uint16_t ALIEN = 0x0002;\n    constexpr uint16_t PROJECTILE = 0x0004;\n    constexpr uint16_t BUNKER = 0x0008;\n}\n\n// Player can collide with aliens and bunkers\nplayer->setCollisionLayer(Layers::PLAYER);\nplayer->setCollisionMask(Layers::ALIEN | Layers::BUNKER);\n\n// Projectiles can hit aliens and bunkers\nprojectile->setCollisionLayer(Layers::PROJECTILE);\nprojectile->setCollisionMask(Layers::ALIEN | Layers::BUNKER);\n
"},{"location":"reference/game_examples_guide/#entity-management","title":"Entity Management","text":"
  • Uses object pooling for projectiles
  • Manages alien formation with grid layout
  • Handles game state (playing, game over)
"},{"location":"reference/game_examples_guide/#audio-integration","title":"Audio Integration","text":"
  • Background music using MusicPlayer
  • Sound effects for various events
  • Audio events triggered on collisions
"},{"location":"reference/game_examples_guide/#patterns-used","title":"Patterns Used","text":"
  • Object Pooling: Projectiles are pooled and reused
  • State Machine: Game states (playing, game over, victory)
  • Grid Layout: Alien formation uses grid-based positioning
  • Event-Driven Audio: Sounds triggered by game events
"},{"location":"reference/game_examples_guide/#lessons-learned","title":"Lessons Learned","text":"
  • Collision layers are essential for complex games
  • Object pooling improves performance
  • Starfield or tilemap backgrounds are efficient
  • Audio enhances game feel significantly
"},{"location":"reference/game_examples_guide/#metroidvania","title":"Metroidvania","text":"

Location: src/examples/Games/Metroidvania/

Assets: Sprites and tilesets for this example come from the Tiny Metroidvania 8x8 pack by Kenmi (kenmi-art.itch.io).

"},{"location":"reference/game_examples_guide/#architecture_1","title":"Architecture","text":"

Metroidvania is a 2D platformer example with multi-layer tilemap and optimizations aimed at ESP32. It does not use scroll or camera; the level is drawn with a fixed origin (0,0).

  • Scene: MetroidvaniaScene with a single PlayerActor and several tilemap layers (background, platforms, details, stairs).
  • PlayerActor: Horizontal and vertical movement, stairs, tile-based collision (no rectangle lists).
  • Tilemap: 4bpp (TileMap4bpp), with viewport culling and palette cache in the engine. Level 40\u00d730 tiles (320\u00d7240 px).
  • No camera: The view does not follow the player; for scroll you would use Camera2D and apply offset in the renderer (as in CameraDemo).
"},{"location":"reference/game_examples_guide/#engine-features-used","title":"Engine features used","text":"
  • Tile-based collision: Direct tile checks around the player (getTileAt), instead of iterating over platformRects.
  • 4bpp sprites: Player with animations (idle, run, jump) from generated headers (e.g. Sprite Compiler).
  • Rendering optimizations: Viewport culling in drawTileMap, optimized 4bpp drawSprite, layers culled by viewport.
  • Optional: Scene arena, DMA, IRAM_ATTR on critical paths (per example optimization plan).
"},{"location":"reference/game_examples_guide/#patterns-used_1","title":"Patterns used","text":"
  • Tile-based collision: Single O(1) access per tile instead of O(N) rectangles.
  • Stair detection: Single result reused for collision and state change.
  • Simplified hitbox: Fewer vertical check points (head and feet).
"},{"location":"reference/game_examples_guide/#lessons-learned_1","title":"Lessons learned","text":"
  • Tile-based collision scales better than rectangle lists on large levels.
  • Viewport and 4bpp optimizations improve FPS on ESP32.
  • Metroidvania serves as a reference for platformers with tilemap and camera.
"},{"location":"reference/game_examples_guide/#pong","title":"Pong","text":"

Location: src/examples/Pong/

"},{"location":"reference/game_examples_guide/#architecture_2","title":"Architecture","text":"

Pong demonstrates physics and collision handling:

  • PhysicsActor: Ball uses PhysicsActor for automatic physics
  • Collision Callbacks: Paddles and ball handle collisions
  • Score System: Simple score tracking and display
  • Game State: Reset and game over handling
"},{"location":"reference/game_examples_guide/#key-systems_1","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#physics-setup","title":"Physics Setup","text":"
class BallActor : public pixelroot32::core::PhysicsActor {\npublic:\n    BallActor(float x, float y, float speed, int radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRestitution(0.8f);  // Bouncy\n        setFriction(0.1f);     // Low friction\n        setWorldSize(240, 240);\n    }\n};\n
"},{"location":"reference/game_examples_guide/#collision-response","title":"Collision Response","text":"
void BallActor::onCollision(pixelroot32::core::Actor* other) {\n    // Adjust ball position\n    // Modify velocity based on impact point\n    // Play bounce sound\n}\n
"},{"location":"reference/game_examples_guide/#patterns-used_2","title":"Patterns Used","text":"
  • Physics Integration: Uses PhysicsActor for automatic movement
  • Collision Response: Custom collision handling
  • Score Management: Simple state tracking
  • Audio Feedback: Sound on collision
"},{"location":"reference/game_examples_guide/#lessons-learned_2","title":"Lessons Learned","text":"
  • PhysicsActor simplifies physics-based games
  • Collision callbacks allow custom response logic
  • Simple games can be very effective
"},{"location":"reference/game_examples_guide/#snake","title":"Snake","text":"

Location: src/examples/Snake/

"},{"location":"reference/game_examples_guide/#architecture_3","title":"Architecture","text":"

Snake demonstrates entity pooling and grid-based movement:

  • Entity Pooling: Snake segments are pooled
  • Grid Movement: Movement constrained to grid
  • Game Logic: Food spawning, collision detection
  • State Management: Game over, reset functionality
"},{"location":"reference/game_examples_guide/#key-systems_2","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#entity-pooling","title":"Entity Pooling","text":"
class SnakeScene {\nprivate:\n    std::vector<SnakeSegmentActor*> segmentPool;\n    std::vector<SnakeSegmentActor*> snakeSegments;\n\n    void resetGame() {\n        // Reuse pooled segments\n        for (int i = 0; i < initialLength; ++i) {\n            SnakeSegmentActor* segment = segmentPool[i];\n            segment->resetAlive();\n            snakeSegments.push_back(segment);\n            addEntity(segment);\n        }\n    }\n};\n
"},{"location":"reference/game_examples_guide/#grid-based-movement","title":"Grid-Based Movement","text":"
class SnakeSegmentActor : public pixelroot32::core::Actor {\nprivate:\n    int cellX, cellY;  // Grid position\n\npublic:\n    void setCellPosition(int x, int y) {\n        cellX = x;\n        cellY = y;\n        // Convert to world position\n        this->x = cellX * CELL_SIZE;\n        this->y = cellY * CELL_SIZE;\n    }\n};\n
"},{"location":"reference/game_examples_guide/#patterns-used_3","title":"Patterns Used","text":"
  • Object Pooling: Segments are pre-allocated and reused
  • Grid System: Discrete grid-based movement
  • Linked List: Snake segments form a linked structure
  • Food Spawning: Random food placement with collision checking
"},{"location":"reference/game_examples_guide/#lessons-learned_3","title":"Lessons Learned","text":"
  • Entity pooling is essential for dynamic entities
  • Grid-based movement simplifies collision detection
  • Pre-allocation avoids memory fragmentation
"},{"location":"reference/game_examples_guide/#tictactoe","title":"TicTacToe","text":"

Location: src/examples/TicTacToe/

"},{"location":"reference/game_examples_guide/#architecture_4","title":"Architecture","text":"

TicTacToe demonstrates turn-based logic and simple AI:

  • Turn Management: Player vs AI turns
  • Game Board: 3x3 grid representation
  • Win Detection: Check for winning conditions
  • Simple AI: Random move selection
"},{"location":"reference/game_examples_guide/#key-systems_3","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#board-representation","title":"Board Representation","text":"
class TicTacToeScene {\nprivate:\n    int board[3][3];  // 0=empty, 1=X, 2=O\n    bool playerTurn = true;\n\n    bool makeMove(int row, int col, int player) {\n        if (board[row][col] == 0) {\n            board[row][col] = player;\n            return true;\n        }\n        return false;\n    }\n};\n
"},{"location":"reference/game_examples_guide/#win-detection","title":"Win Detection","text":"
int checkWinner() {\n    // Check rows\n    for (int i = 0; i < 3; i++) {\n        if (board[i][0] == board[i][1] && board[i][1] == board[i][2]) {\n            return board[i][0];\n        }\n    }\n    // Check columns, diagonals...\n    return 0; // No winner\n}\n
"},{"location":"reference/game_examples_guide/#patterns-used_4","title":"Patterns Used","text":"
  • State Machine: Turn-based state management
  • Grid Logic: 2D array for board representation
  • Simple AI: Random valid move selection
  • UI Integration: Buttons for player input
"},{"location":"reference/game_examples_guide/#lessons-learned_4","title":"Lessons Learned","text":"
  • Turn-based games are straightforward to implement
  • Simple AI can be effective for basic games
  • Grid-based logic is easy to reason about
"},{"location":"reference/game_examples_guide/#camerademo","title":"CameraDemo","text":"

Location: src/examples/CameraDemo/

"},{"location":"reference/game_examples_guide/#architecture_5","title":"Architecture","text":"

CameraDemo demonstrates scrolling and parallax:

  • Camera2D: Camera following player
  • Tilemap: Level built with tilemap
  • Parallax: Multiple background layers
  • Platformer Physics: Player with jumping and gravity
"},{"location":"reference/game_examples_guide/#key-systems_4","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#camera-setup","title":"Camera Setup","text":"
class CameraDemoScene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    float levelWidth;\n\npublic:\n    void init() override {\n        camera = pixelroot32::graphics::Camera2D(240, 240);\n        camera.setBounds(0, levelWidth - 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        renderer.drawTileMap(levelTileMap, 0, 0, Color::White);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"reference/game_examples_guide/#platformer-physics","title":"Platformer Physics","text":"
class PlayerCube : public pixelroot32::core::PhysicsActor {\npublic:\n    void update(unsigned long deltaTime) override {\n        // Input handling\n        // Gravity application\n        // Jump logic\n        // Platform collision\n        PhysicsActor::update(deltaTime);\n    }\n};\n
"},{"location":"reference/game_examples_guide/#patterns-used_5","title":"Patterns Used","text":"
  • Camera Following: Dead-zone camera following
  • Tilemap Rendering: Efficient level rendering
  • Parallax Scrolling: Multiple background layers
  • Platform Collision: Custom collision with platforms
"},{"location":"reference/game_examples_guide/#lessons-learned_5","title":"Lessons Learned","text":"
  • Camera system enables large levels
  • Tilemaps are efficient for level data
  • Parallax adds depth to 2D games
  • Platform collision requires custom logic
"},{"location":"reference/game_examples_guide/#spritesdemo","title":"SpritesDemo","text":"

Location: src/examples/SpritesDemo/

"},{"location":"reference/game_examples_guide/#architecture_6","title":"Architecture","text":"

SpritesDemo showcases advanced sprite formats:

  • 2bpp Sprites: 4-color sprite format
  • 4bpp Sprites: 16-color sprite format (if enabled)
  • Animation: Sprite animation examples
  • Format Comparison: Side-by-side format display
"},{"location":"reference/game_examples_guide/#key-systems_5","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#2bpp-sprite-usage","title":"2bpp Sprite Usage","text":"
#ifdef PIXELROOT32_ENABLE_2BPP_SPRITES\nstatic const pixelroot32::graphics::Sprite2bpp SPRITE_2BPP = {\n    SPRITE_DATA,\n    SPRITE_PALETTE,\n    16, 32, 4\n};\n\nrenderer.drawSprite(SPRITE_2BPP, x, y, false);\n#endif\n
"},{"location":"reference/game_examples_guide/#animation-display","title":"Animation Display","text":"
class SpritesDemoActor : public pixelroot32::core::Entity {\nprivate:\n    unsigned long timer = 0;\n    uint8_t currentFrame = 0;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        timer += deltaTime;\n        if (timer >= 150) {\n            timer -= 150;\n            currentFrame = (currentFrame + 1) % 9;\n        }\n    }\n};\n
"},{"location":"reference/game_examples_guide/#patterns-used_6","title":"Patterns Used","text":"
  • Format Comparison: Shows different sprite formats
  • Animation Loop: Frame-based animation
  • Conditional Compilation: Uses build flags
"},{"location":"reference/game_examples_guide/#lessons-learned_6","title":"Lessons Learned","text":"
  • Advanced formats provide more color options
  • Animation is straightforward with frame arrays
  • Build flags enable/disable experimental features
"},{"location":"reference/game_examples_guide/#common-patterns-across-examples","title":"Common Patterns Across Examples","text":""},{"location":"reference/game_examples_guide/#screen-resolution","title":"Screen Resolution","text":"

All examples are configured for a 240x240 screen resolution.

"},{"location":"reference/game_examples_guide/#scene-initialization","title":"Scene Initialization","text":"

All examples follow this pattern:

void init() override {\n    // 1. Set palette\n    pixelroot32::graphics::setPalette(PaletteType::NES);\n\n    // 2. Create background entity\n    addEntity(new BackgroundEntity());\n\n    // 3. Create game entities\n    player = new PlayerActor(...);\n    addEntity(player);\n\n    // 4. Initialize game state\n    resetGame();\n}\n
"},{"location":"reference/game_examples_guide/#update-pattern","title":"Update Pattern","text":"
void update(unsigned long deltaTime) override {\n    // 1. Process input\n    handleInput();\n\n    // 2. Update game logic\n    updateGameLogic();\n\n    // 3. Call parent update (updates all entities)\n    Scene::update(deltaTime);\n\n    // 4. Post-update logic\n    checkGameState();\n}\n
"},{"location":"reference/game_examples_guide/#draw-pattern","title":"Draw Pattern","text":"
void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // 1. Apply camera (if used)\n    camera.apply(renderer);\n\n    // 2. Draw background/tilemap\n    renderer.drawTileMap(background, 0, 0, Color::White);\n\n    // 3. Call parent draw (draws all entities)\n    Scene::draw(renderer);\n\n    // 4. Draw UI/HUD\n    drawHUD(renderer);\n}\n
"},{"location":"reference/game_examples_guide/#learning-path","title":"Learning Path","text":""},{"location":"reference/game_examples_guide/#beginner-examples","title":"Beginner Examples","text":"
  1. Pong: Basic physics and collisions
  2. TicTacToe: Turn-based logic
  3. Snake: Entity pooling and grid
"},{"location":"reference/game_examples_guide/#intermediate-examples","title":"Intermediate Examples","text":"
  1. CameraDemo: Camera and parallax
  2. SpritesDemo: 2bpp and 4bpp formats
  3. BrickBreaker: Physics, particles and audio
"},{"location":"reference/game_examples_guide/#advanced-examples","title":"Advanced Examples","text":"
  1. Space Invaders: Full game (1bpp sprites, collisions, audio)
  2. Metroidvania: Platformer with multi-layer 4bpp tilemap, tile-based collision and ESP32 optimizations (no scroll/camera)
"},{"location":"reference/game_examples_guide/#code-study-recommendations","title":"Code Study Recommendations","text":""},{"location":"reference/game_examples_guide/#for-learning-physics","title":"For Learning Physics","text":"
  • Study Pong/BallActor.cpp - PhysicsActor usage
  • Study CameraDemo/PlayerCube.cpp - Platformer physics
"},{"location":"reference/game_examples_guide/#for-learning-collisions","title":"For Learning Collisions","text":"
  • Study SpaceInvaders - Complex collision layers
  • Study Pong - Simple collision response
"},{"location":"reference/game_examples_guide/#for-learning-memory-management","title":"For Learning Memory Management","text":"
  • Study Snake/SnakeScene.cpp - Entity pooling
  • Study SpaceInvaders - Projectile pooling
"},{"location":"reference/game_examples_guide/#for-learning-audio","title":"For Learning Audio","text":"
  • Study SpaceInvaders - Music and sound effects
  • Study Pong - Simple audio integration
"},{"location":"reference/game_examples_guide/#for-learning-ui","title":"For Learning UI","text":"
  • Study TicTacToe - Button-based UI
  • Study menu scenes - Layout usage
"},{"location":"reference/game_examples_guide/#extending-examples","title":"Extending Examples","text":""},{"location":"reference/game_examples_guide/#adding-features","title":"Adding Features","text":"
  • Pong: Add power-ups, multiple balls
  • Snake: Add obstacles, multiple food types
  • Space Invaders: Add boss battles, power-ups
"},{"location":"reference/game_examples_guide/#creating-variations","title":"Creating Variations","text":"
  • Pong: Make it vertical, add walls
  • Snake: Change to hexagonal grid
  • TicTacToe: Make it 4x4 or 5x5
"},{"location":"reference/game_examples_guide/#best-practices-from-examples","title":"Best Practices from Examples","text":"
  1. Pre-allocate Resources: All examples pre-allocate entities
  2. Use Object Pooling: For frequently created/destroyed entities
  3. Organize by Layers: Clear collision layer organization
  4. Separate Concerns: Game logic separate from rendering
  5. State Management: Clear game state handling
"},{"location":"reference/game_examples_guide/#see-also","title":"See Also","text":"
  • Code Examples - Reusable code snippets
  • API Reference Overview - Complete API documentation
  • Manual - Game Development - Detailed guides

Note: All example code is available in the src/examples/ directory of the PixelRoot32 Game Samples project.

"},{"location":"resources/available_tools/","title":"Available Tools","text":"

This guide documents tools available to facilitate PixelRoot32 game development.

"},{"location":"resources/available_tools/#sprite-compiler-pr32-sprite-compiler","title":"Sprite Compiler (pr32-sprite-compiler)","text":"

The Sprite Compiler converts PNG images to PixelRoot32 sprite data formats, making it easy to create sprites from image files.

Read more in the Sprite Compiler Guide

From Source:

git clone https://github.com/Gperez88/pr32-sprite-compiler.git\ncd pr32-sprite-compiler\nnpm install\nnpm link  # Optional: install globally\n

As NPM Package:

npm install -g pr32-sprite-compiler\n
"},{"location":"resources/available_tools/#basic-usage","title":"Basic Usage","text":"

Command Line:

pr32-sprite-compiler input.png output.h\n

With Options:

pr32-sprite-compiler input.png output.h --format 1bpp --name MY_SPRITE\n
"},{"location":"resources/available_tools/#supported-formats","title":"Supported Formats","text":"
  • 1bpp (default): Monochrome, most memory-efficient
  • 2bpp: 4 colors per sprite (requires PIXELROOT32_ENABLE_2BPP_SPRITES)
  • 4bpp: 16 colors per sprite (requires PIXELROOT32_ENABLE_4BPP_SPRITES)
"},{"location":"resources/available_tools/#output-format","title":"Output Format","text":"

The compiler generates C++ header files with sprite data:

// output.h\n#ifndef SPRITE_DATA_H\n#define SPRITE_DATA_H\n\n#include <stdint.h>\n\nstatic const uint16_t MY_SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    // ... more rows\n};\n\nstatic const pixelroot32::graphics::Sprite MY_SPRITE = {\n    MY_SPRITE_DATA,\n    8,  // width\n    8   // height\n};\n\n#endif\n
"},{"location":"resources/available_tools/#advanced-options","title":"Advanced Options","text":"

Batch Processing:

pr32-sprite-compiler --batch sprites/*.png --output-dir sprites/out/\n

Custom Palette:

pr32-sprite-compiler input.png output.h --palette custom_palette.json\n

Sprite Sheet:

pr32-sprite-compiler sheet.png output.h --sheet 8x8 --count 16\n
"},{"location":"resources/available_tools/#gui-version","title":"GUI Version","text":"

If available, a GUI version provides visual feedback:

  • Drag and drop images
  • Preview sprite data
  • Adjust settings visually
  • Export to header files
"},{"location":"resources/available_tools/#step-by-step-example","title":"Step-by-Step Example","text":"
  1. Create or find a PNG image (8x8, 16x16, etc.)

  2. Run the compiler:

pr32-sprite-compiler player.png player_sprite.h --name PLAYER_SPRITE\n
  1. Include in your project:
#include \"player_sprite.h\"\n\nvoid draw() {\n    renderer.drawSprite(PLAYER_SPRITE, 100, 100, Color::White);\n}\n
"},{"location":"resources/available_tools/#troubleshooting","title":"Troubleshooting","text":"

Image too large:

  • Sprites must be \u2264 16 pixels wide for 1bpp
  • Reduce image size or split into multiple sprites

Colors not converting correctly:

  • Ensure image uses indexed colors
  • Use black/white for 1bpp
  • Use 4 colors for 2bpp, 16 for 4bpp

Output file not found:

  • Check write permissions
  • Verify output path exists
"},{"location":"resources/available_tools/#future-tools","title":"Future Tools","text":""},{"location":"resources/available_tools/#music-compiler-planned","title":"Music Compiler (Planned)","text":"

A tool to convert music files or MIDI to PixelRoot32 MusicTrack format.

Planned Features:

  • MIDI to MusicTrack conversion
  • Visual music editor
  • Instrument preset management
  • Export to C++ header files
"},{"location":"resources/available_tools/#tilemap-compiler-planned","title":"Tilemap Compiler (Planned)","text":"

A tool to create tilemaps from image files or tile editors.

Planned Features:

  • Image to tilemap conversion
  • Tile editor integration
  • Export to C++ arrays
  • Collision data generation
"},{"location":"resources/available_tools/#other-planned-tools","title":"Other Planned Tools","text":"
  • Save System Generator: Generate save/load code
  • Asset Packer: Bundle assets for distribution
  • Performance Profiler: Analyze game performance
"},{"location":"resources/available_tools/#using-tools-in-development","title":"Using Tools in Development","text":""},{"location":"resources/available_tools/#workflow-integration","title":"Workflow Integration","text":"

Typical Workflow:

  1. Create/edit sprites in image editor
  2. Compile sprites to C++ headers
  3. Include headers in project
  4. Use sprites in code

Automation:

# Build script example\n#!/bin/bash\npr32-sprite-compiler assets/sprites/*.png --output-dir src/sprites/\n# Continue with build...\n
"},{"location":"resources/available_tools/#best-practices","title":"Best Practices","text":"
  • Organize assets: Keep source images separate from generated code
  • Version control: Commit generated headers, not source images (or both)
  • Naming conventions: Use consistent naming for sprites
  • Batch processing: Process multiple sprites at once when possible
"},{"location":"resources/available_tools/#see-also","title":"See Also","text":"
  • Sprite Compiler Documentation - Detailed sprite compiler guide
  • Manual - Sprites and Animation - Using sprites in games
  • Troubleshooting - Common tool issues

Note: Tool availability may vary. Check the PixelRoot32 repository for the latest tool information.

"},{"location":"resources/faq/","title":"Frequently Asked Questions","text":"

Common questions about PixelRoot32, organized by category.

"},{"location":"resources/faq/#general","title":"General","text":""},{"location":"resources/faq/#what-is-pixelroot32","title":"What is PixelRoot32?","text":"

PixelRoot32 is a lightweight, modular 2D game engine designed for ESP32 microcontrollers. It provides a complete game development framework with rendering, audio, physics, input, and UI systems, optimized for limited hardware resources.

"},{"location":"resources/faq/#what-platforms-does-it-support","title":"What platforms does it support?","text":"
  • ESP32: Primary platform (TFT displays, GPIO buttons, DAC/I2S audio)
  • Native/Desktop: Development platform (SDL2, keyboard, SDL2 audio)
"},{"location":"resources/faq/#what-kind-of-games-can-i-make","title":"What kind of games can I make?","text":"

PixelRoot32 is ideal for: - Retro/arcade-style games - 2D platformers - Shooters - Puzzle games - Simple RPGs - Educational games

See Limitations and Considerations for what's not suitable.

"},{"location":"resources/faq/#is-it-free-to-use","title":"Is it free to use?","text":"

Yes, PixelRoot32 is open source and licensed under the MIT License. You can use it freely for personal and commercial projects.

"},{"location":"resources/faq/#where-can-i-find-the-source-code","title":"Where can I find the source code?","text":"
  • Engine: https://github.com/Gperez88/PixelRoot32-Game-Engine
  • Samples: https://github.com/Gperez88/PixelRoot32-Game-Samples
  • Documentation: https://github.com/PixelRoot32-Game-Engine/PixelRoot32-Docs
"},{"location":"resources/faq/#installation-and-configuration","title":"Installation and Configuration","text":""},{"location":"resources/faq/#how-do-i-install-pixelroot32","title":"How do I install PixelRoot32?","text":"

See Your First Project for detailed installation instructions.

Quick answer: 1. Install PlatformIO in VS Code 2. Create new ESP32 project 3. Add library dependency: gperez88/PixelRoot32-Game-Engine@0.2.0-dev 4. Configure hardware in platformio.ini

"},{"location":"resources/faq/#what-version-should-i-use","title":"What version should I use?","text":"

Use the exact version 0.2.0-dev. Do NOT use ^ or fuzzy versioning, as the API may change.

"},{"location":"resources/faq/#how-do-i-configure-my-display","title":"How do I configure my display?","text":"

Configure TFT_eSPI via build flags in platformio.ini. See Your First Project for examples.

"},{"location":"resources/faq/#how-do-i-set-up-audio","title":"How do I set up audio?","text":"

Choose an audio backend: - ESP32_DAC: Simple, one pin (GPIO 25 or 26) - ESP32_I2S: Higher quality, requires external DAC - SDL2_AudioBackend: For Native/PC development

See Audio for details.

"},{"location":"resources/faq/#development","title":"Development","text":""},{"location":"resources/faq/#how-do-i-create-a-scene","title":"How do I create a scene?","text":"

Inherit from pixelroot32::core::Scene and implement init(), update(), and draw(). See Scenes and Entities.

"},{"location":"resources/faq/#how-do-i-add-entities-to-a-scene","title":"How do I add entities to a scene?","text":"

Create entities and call addEntity() in init(). The scene manages them automatically.

"},{"location":"resources/faq/#whats-the-difference-between-entity-actor-and-physicsactor","title":"What's the difference between Entity, Actor, and PhysicsActor?","text":"
  • Entity: Base class, can be drawn and updated
  • Actor: Entity with collision detection
  • PhysicsActor: Actor with automatic physics (velocity, gravity, friction)

See Scenes and Entities for details.

"},{"location":"resources/faq/#how-do-i-handle-input","title":"How do I handle input?","text":"

Access InputManager through the engine:

auto& input = engine.getInputManager();\nif (input.isButtonPressed(Buttons::A)) {\n    // Handle input\n}\n

See Input and Control.

"},{"location":"resources/faq/#how-do-i-play-sounds","title":"How do I play sounds?","text":"

Create an AudioEvent and play it:

pixelroot32::audio::AudioEvent sound{};\nsound.type = pixelroot32::audio::WaveType::PULSE;\nsound.frequency = 800.0f;\nsound.duration = 0.1f;\nengine.getAudioEngine().playEvent(sound);\n

See Audio.

"},{"location":"resources/faq/#how-do-i-create-sprites","title":"How do I create sprites?","text":"

Define sprite data manually or use the Sprite Compiler tool. See Sprites and Animation.

"},{"location":"resources/faq/#can-i-use-images-instead-of-manual-sprite-data","title":"Can I use images instead of manual sprite data?","text":"

Yes, use the Sprite Compiler tool to convert PNG images to sprite data. See Available Tools.

"},{"location":"resources/faq/#performance","title":"Performance","text":""},{"location":"resources/faq/#why-is-my-game-running-slowly","title":"Why is my game running slowly?","text":"

Common causes: - Too many entities (MAX_ENTITIES = 32) - Too many draw calls - Expensive calculations in update() - Memory issues

See Performance Tuning for solutions.

"},{"location":"resources/faq/#what-fps-should-i-target","title":"What FPS should I target?","text":"

30-60 FPS is typical. Lower complexity games can achieve 60 FPS, more complex games may need to target 30 FPS.

"},{"location":"resources/faq/#how-do-i-optimize-my-game","title":"How do I optimize my game?","text":"
  • Use object pooling
  • Implement viewport culling
  • Reduce entity count
  • Cache calculations
  • Use tilemaps for backgrounds

See Performance Tuning.

"},{"location":"resources/faq/#memory","title":"Memory","text":""},{"location":"resources/faq/#why-do-i-get-out-of-memory-errors","title":"Why do I get \"out of memory\" errors?","text":"

ESP32 has limited RAM (~320KB). Solutions: - Use object pooling - Store data in flash (const/constexpr) - Reduce entity count - Avoid dynamic allocation

See Memory Management.

"},{"location":"resources/faq/#what-is-max_entities","title":"What is MAX_ENTITIES?","text":"

MAX_ENTITIES = 32 is a hard limit per scene. This includes all entities: actors, UI elements, particles, etc.

Solutions: - Use object pooling to reuse entities - Disable entities instead of removing - Combine multiple entities into one

"},{"location":"resources/faq/#how-do-i-check-available-memory","title":"How do I check available memory?","text":"
#ifdef PLATFORM_ESP32\nSerial.print(\"Free heap: \");\nSerial.println(ESP.getFreeHeap());\n#endif\n
"},{"location":"resources/faq/#hardware","title":"Hardware","text":""},{"location":"resources/faq/#which-esp32-board-should-i-use","title":"Which ESP32 board should I use?","text":"

Any ESP32 board works. Common choices: - ESP32-WROOM-32 - ESP32-WROVER (more RAM) - ESP32-DevKit

"},{"location":"resources/faq/#which-display-should-i-use","title":"Which display should I use?","text":"

Popular choices: - ST7789: 240x240, good quality - ST7735: 128x128, smaller/cheaper - ILI9341: 240x320, larger

See Platforms and Drivers.

"},{"location":"resources/faq/#how-many-buttons-do-i-need","title":"How many buttons do I need?","text":"

Minimum: 4 (UP, DOWN, LEFT, RIGHT) Recommended: 6 (add A and B buttons) More buttons can be added if needed.

"},{"location":"resources/faq/#can-i-use-analog-joysticks","title":"Can I use analog joysticks?","text":"

Not directly supported. You can read analog pins manually and convert to digital input, but the engine expects digital buttons.

"},{"location":"resources/faq/#troubleshooting","title":"Troubleshooting","text":""},{"location":"resources/faq/#my-display-is-blank-whats-wrong","title":"My display is blank. What's wrong?","text":"
  1. Check wiring connections
  2. Verify pin numbers in platformio.ini
  3. Lower SPI frequency
  4. Check display type matches hardware
  5. Verify power supply

See Troubleshooting.

"},{"location":"resources/faq/#buttons-dont-work-why","title":"Buttons don't work. Why?","text":"
  1. Check button wiring
  2. Verify pin numbers in InputConfig
  3. Check pull-up/pull-down resistors
  4. Ensure InputManager is being updated
  5. Test with isButtonDown() vs isButtonPressed()
"},{"location":"resources/faq/#audio-is-distorted-how-do-i-fix-it","title":"Audio is distorted. How do I fix it?","text":"
  1. Lower volume levels
  2. Reduce sample rate (try 11025 Hz)
  3. Check for too many simultaneous sounds
  4. Verify hardware connections
  5. Check power supply
"},{"location":"resources/faq/#game-crashes-randomly-whats-happening","title":"Game crashes randomly. What's happening?","text":"

Common causes: - Out of memory - Too many entities - Infinite loops - Stack overflow - Watchdog timeout

See Troubleshooting for debugging techniques.

"},{"location":"resources/faq/#advanced","title":"Advanced","text":""},{"location":"resources/faq/#can-i-extend-the-engine","title":"Can I extend the engine?","text":"

Yes, PixelRoot32 is designed to be extensible. You can: - Create custom display drivers - Create custom audio backends - Extend existing systems

See Extensibility.

"},{"location":"resources/faq/#can-i-use-3d-graphics","title":"Can I use 3D graphics?","text":"

No, PixelRoot32 is 2D-only. It's designed for sprite-based 2D games.

"},{"location":"resources/faq/#can-i-add-networking","title":"Can I add networking?","text":"

Not currently supported. The engine focuses on single-player games.

"},{"location":"resources/faq/#can-i-save-game-data","title":"Can I save game data?","text":"

Not currently supported. A save system is planned for future versions.

"},{"location":"resources/faq/#can-i-use-multiple-scenes-at-once","title":"Can I use multiple scenes at once?","text":"

Yes, use SceneManager to push/pop scenes. This is useful for menus and pause screens.

"},{"location":"resources/faq/#getting-help","title":"Getting Help","text":""},{"location":"resources/faq/#where-can-i-get-help","title":"Where can I get help?","text":"
  • Documentation: This documentation site
  • Examples: Study example games in the samples project
  • Discord: Community Discord server
  • GitHub: Open an issue for bugs
"},{"location":"resources/faq/#how-do-i-report-a-bug","title":"How do I report a bug?","text":"

Create a detailed bug report with: - Platform (ESP32 or Native) - Hardware details - Minimal reproduction code - Error messages - Expected vs actual behavior

"},{"location":"resources/faq/#can-i-contribute","title":"Can I contribute?","text":"

Yes! PixelRoot32 is open source. Check the main repository for contribution guidelines.

"},{"location":"resources/faq/#see-also","title":"See Also","text":"
  • Troubleshooting - Detailed problem solving
  • Limitations and Considerations - What the engine can/can't do
  • Getting Started - Start here if you're new
  • Manual - Complete development guides

Can't find your question? Check the Troubleshooting guide or ask on the Discord server.

"},{"location":"resources/limitations_and_considerations/","title":"Limitations and Considerations","text":"

This document honestly documents what PixelRoot32 can and cannot do, helping you make informed decisions about using the engine.

"},{"location":"resources/limitations_and_considerations/#hardware-limitations-esp32","title":"Hardware Limitations (ESP32)","text":""},{"location":"resources/limitations_and_considerations/#memory-constraints","title":"Memory Constraints","text":"

RAM: - Available: ~320KB total (varies by ESP32 model) - Heap: Limited and fragmented over time - Stack: ~8KB, avoid large stack allocations - Impact: Limits entity count, sprite data, and dynamic allocation

Flash: - Available: 4MB+ (varies by model) - Usage: Program code, sprite data, assets - Impact: Large games may approach limits

Recommendations: - Use object pooling - Store data in flash (const/constexpr) - Avoid dynamic allocation in game loop - Keep entity count low

"},{"location":"resources/limitations_and_considerations/#cpu-limitations","title":"CPU Limitations","text":"

Performance: - Clock Speed: 240MHz (typically) - Single-threaded: One core handles everything - Target FPS: 30-60 FPS (depends on complexity) - Frame Budget: ~16-33ms per frame at 60 FPS

Impact: - Complex games may struggle - Many entities reduce performance - Expensive calculations hurt FPS

Recommendations: - Optimize rendering - Reduce entity count - Cache calculations - Profile on hardware

"},{"location":"resources/limitations_and_considerations/#display-limitations","title":"Display Limitations","text":"

Supported Displays: - TFT displays via SPI (ST7735, ST7789, ILI9341, etc.) - Limited to SPI displays - Resolution typically 128x128 to 320x240

Constraints: - SPI communication speed limits - Display initialization complexity - Power consumption

"},{"location":"resources/limitations_and_considerations/#audio-limitations","title":"Audio Limitations","text":"

Hardware: - Internal DAC: Lower quality, simple setup - I2S: Higher quality, requires external DAC - Sample rates: 11025 Hz (DAC) or 22050 Hz (I2S)

Constraints: - 4 channels total (2 Pulse, 1 Triangle, 1 Noise) - Music uses one channel - Limited simultaneous sounds - Quality limited by hardware

"},{"location":"resources/limitations_and_considerations/#software-limitations","title":"Software Limitations","text":""},{"location":"resources/limitations_and_considerations/#entity-system","title":"Entity System","text":"

MAX_ENTITIES = 32 per scene - Hard limit, cannot be changed easily - Applies to all entities (actors, UI, particles, etc.) - Must manage entity count carefully

Workarounds: - Use object pooling - Reuse entities - Disable entities instead of removing - Combine multiple entities into one

"},{"location":"resources/limitations_and_considerations/#no-rtti-runtime-type-information","title":"No RTTI (Runtime Type Information)","text":"

Impact: - Cannot use dynamic_cast in most code - Type checking must be done manually - Limits polymorphism patterns

Alternatives: - Use virtual functions - Manual type checking - Tag-based systems

"},{"location":"resources/limitations_and_considerations/#no-exceptions-in-critical-code","title":"No Exceptions in Critical Code","text":"

Impact: - Cannot use try/catch in game loop - Error handling must be explicit - Crashes instead of exceptions

Best Practices: - Validate inputs - Check return values - Use assertions for debugging - Handle errors explicitly

"},{"location":"resources/limitations_and_considerations/#no-dynamic-allocation-in-game-loop","title":"No Dynamic Allocation in Game Loop","text":"

Impact: - Cannot use new/delete during gameplay - Must pre-allocate resources - Limits flexibility

Solutions: - Object pooling - Pre-allocation in init() - Static buffers - Fixed-size arrays

"},{"location":"resources/limitations_and_considerations/#no-advanced-features","title":"No Advanced Features","text":"

Not Supported: - 3D graphics - Shaders - Advanced physics (joints, constraints) - Networking - File system (ESP32) - Advanced audio effects

Focus: - 2D sprite-based games - Simple physics - Retro-style games - Embedded-friendly features

"},{"location":"resources/limitations_and_considerations/#experimental-features","title":"Experimental Features","text":""},{"location":"resources/limitations_and_considerations/#2bpp-sprites","title":"2bpp Sprites","text":"

Status: Experimental - Requires PIXELROOT32_ENABLE_2BPP_SPRITES flag - May have bugs or limitations - Not fully tested

Use with caution: - Test thoroughly - May change in future versions - Report issues if found

"},{"location":"resources/limitations_and_considerations/#4bpp-sprites","title":"4bpp Sprites","text":"

Status: Experimental - Requires PIXELROOT32_ENABLE_4BPP_SPRITES flag - More experimental than 2bpp - Higher memory usage

Use with caution: - Test extensively - Monitor memory usage - May be unstable

"},{"location":"resources/limitations_and_considerations/#scene-arena","title":"Scene Arena","text":"

Status: Experimental - Requires PIXELROOT32_ENABLE_SCENE_ARENA flag - Alternative memory management - May have bugs

Recommendations: - Use object pooling instead (more stable) - Test thoroughly if using - May be removed or changed

"},{"location":"resources/limitations_and_considerations/#unsupported-features-current","title":"Unsupported Features (Current)","text":""},{"location":"resources/limitations_and_considerations/#planned-but-not-available","title":"Planned but Not Available","text":"
  • u8g2 Driver: Alternative display driver (planned)
  • Music Compiler: Tool to convert music files (planned)
  • Tilemap Compiler: Tool to create tilemaps (planned)
  • Save System: Persistent storage system (planned)
  • Spatial Partitioning: Advanced collision optimization (planned)
"},{"location":"resources/limitations_and_considerations/#not-planned","title":"Not Planned","text":"
  • 3D Graphics: 2D-only engine
  • Networking: No network support
  • File System: No file I/O on ESP32
  • Advanced Audio: NES-like audio only
  • Scripting: No Lua/JavaScript support
"},{"location":"resources/limitations_and_considerations/#best-practices-for-esp32","title":"Best Practices for ESP32","text":""},{"location":"resources/limitations_and_considerations/#memory-management","title":"Memory Management","text":"
  • Pre-allocate: All resources in init()
  • Object pooling: Reuse entities
  • Flash storage: Use const/constexpr for data
  • Avoid strings: Use static buffers
  • Monitor usage: Check heap regularly
"},{"location":"resources/limitations_and_considerations/#performance","title":"Performance","text":"
  • Limit entities: Stay well below MAX_ENTITIES
  • Optimize rendering: Use culling, batching
  • Cache calculations: Avoid repeated work
  • Profile on hardware: PC performance \u2260 ESP32
"},{"location":"resources/limitations_and_considerations/#development","title":"Development","text":"
  • Test on hardware: Don't rely only on Native
  • Start simple: Add complexity gradually
  • Monitor memory: Watch for leaks
  • Optimize incrementally: Profile and optimize
"},{"location":"resources/limitations_and_considerations/#what-pixelroot32-is-good-for","title":"What PixelRoot32 IS Good For","text":"

\u2705 Retro-style 2D games \u2705 Arcade games \u2705 Puzzle games \u2705 Platformers \u2705 Shooters \u2705 Educational projects \u2705 Prototyping \u2705 Embedded game development

"},{"location":"resources/limitations_and_considerations/#what-pixelroot32-is-not-good-for","title":"What PixelRoot32 is NOT Good For","text":"

\u274c 3D games \u274c Complex physics simulations \u274c Large open worlds \u274c Games requiring many entities \u274c Games with complex graphics \u274c Network multiplayer \u274c Games requiring file I/O

"},{"location":"resources/limitations_and_considerations/#making-informed-decisions","title":"Making Informed Decisions","text":""},{"location":"resources/limitations_and_considerations/#before-starting-a-project","title":"Before Starting a Project","text":"
  1. Assess requirements: Does PixelRoot32 fit?
  2. Check limitations: Can you work within constraints?
  3. Plan architecture: Design around limitations
  4. Test early: Verify on hardware early
"},{"location":"resources/limitations_and_considerations/#if-limitations-are-a-problem","title":"If Limitations Are a Problem","text":"

Consider alternatives: - Full game engines (Unity, Godot) for complex games - Custom solutions for specific needs - Different hardware for more resources

Or work within limits: - Simplify game design - Optimize aggressively - Use creative solutions

"},{"location":"resources/limitations_and_considerations/#version-compatibility","title":"Version Compatibility","text":""},{"location":"resources/limitations_and_considerations/#current-version","title":"Current Version","text":"
  • Engine Version: 0.2.0-dev
  • API Stability: May change
  • Breaking Changes: Possible in future versions

Recommendations: - Pin exact version in platformio.ini - Don't use ^ or fuzzy versioning - Test after engine updates - Review changelog

"},{"location":"resources/limitations_and_considerations/#honest-assessment","title":"Honest Assessment","text":"

PixelRoot32 is designed for: - Simple to medium complexity games - Retro/arcade style - ESP32 hardware constraints - Rapid development

It is not designed for: - AAA game complexity - Modern graphics - Large-scale games - Unlimited resources

"},{"location":"resources/limitations_and_considerations/#see-also","title":"See Also","text":"
  • Memory Management - Working with memory limits
  • Performance Tuning - Optimizing performance
  • Troubleshooting - Solving problems
  • FAQ - Common questions

Remember: Understanding limitations helps you build better games within PixelRoot32's capabilities.

"},{"location":"resources/troubleshooting/","title":"Troubleshooting","text":"

This guide helps you diagnose and fix common issues when developing with PixelRoot32.

"},{"location":"resources/troubleshooting/#compilation-problems","title":"Compilation Problems","text":""},{"location":"resources/troubleshooting/#common-compilation-errors","title":"Common Compilation Errors","text":"

Error: Library not found

Solution: Ensure PixelRoot32-Game-Engine is properly installed\n- Check platformio.ini has correct lib_deps\n- Verify library version matches (use exact version, not ^)\n- Try: pio lib install\n

Error: Include file not found

Solution: Check include paths\n- Verify lib_extra_dirs in platformio.ini\n- Check that library is in lib/ directory\n- Ensure correct namespace (pixelroot32::)\n

Error: Undefined reference

Solution: Link missing libraries\n- Check all required libraries are listed\n- Verify TFT_eSPI is installed for ESP32\n- Check SDL2 is installed for Native builds\n

Error: Build flags not recognized

Solution: Verify build flag syntax\n- Use -D FLAG_NAME (not --define)\n- Check flag names are correct\n- Ensure flags are in correct environment section\n

"},{"location":"resources/troubleshooting/#configuration-issues","title":"Configuration Issues","text":"

Wrong display type: - Verify DisplayType matches your hardware - Check TFT_eSPI build flags match display - Test with different display types

Incorrect pin configuration: - Verify GPIO pins match your wiring - Check pin numbers in platformio.ini - Ensure pins aren't used by other peripherals

"},{"location":"resources/troubleshooting/#hardware-problems-esp32","title":"Hardware Problems (ESP32)","text":""},{"location":"resources/troubleshooting/#display-not-working","title":"Display Not Working","text":"

Symptoms: - Blank screen - Garbled display - No output

Solutions: 1. Check wiring: - Verify SPI connections (MOSI, SCLK, DC, RST) - Check power supply (3.3V or 5V as required) - Ensure ground connections

  1. Verify configuration:
  2. Check display type matches hardware
  3. Verify pin numbers in platformio.ini
  4. Test with known working configuration

  5. SPI frequency:

  6. Lower SPI frequency (try 20MHz instead of 40MHz)
  7. Some displays need slower speeds
  8. Check display datasheet for max frequency

  9. Display initialization:

  10. Try different rotation values
  11. Check display width/height settings
  12. Verify TFT_eSPI driver is correct
"},{"location":"resources/troubleshooting/#resolution-scaling-issues","title":"Resolution Scaling Issues","text":"

Symptoms: - Image is not scaled to full screen - Visual artifacts (jittery pixels) - Frame rate drops when scaling is enabled

Solutions: 1. Verify DisplayConfig: - Ensure physicalWidth and physicalHeight match your hardware resolution (e.g., 240x240). - Check that logicalWidth and logicalHeight are set correctly (e.g., 128x128). - Use displayConfig.needsScaling() to check if the engine thinks scaling is required.

  1. Check Scaling Performance:
  2. Enabling scaling is generally faster than native high resolution, but still has some overhead.
  3. Use the Debug Statistics Overlay to check CPU load.
  4. Ensure you are using integer-only coordinates for drawing.

  5. Visual Quality:

  6. The engine uses nearest-neighbor scaling. Some aspect ratios might look \"blocky\" or have uneven pixel sizes.
  7. For best results, use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen).
"},{"location":"resources/troubleshooting/#buttons-not-responding","title":"Buttons Not Responding","text":"

Symptoms: - No input detected - Buttons don't trigger actions - Input feels laggy

Solutions: 1. Check wiring: - Verify button connections to GPIO pins - Check pull-up/pull-down resistors - Test buttons with multimeter

  1. Verify pin configuration:
  2. Check InputConfig pin numbers
  3. Ensure pins match hardware
  4. Verify pins aren't used elsewhere

  5. Input debouncing:

  6. Add hardware debouncing (capacitor)
  7. Check InputManager is being updated
  8. Verify input is read in update(), not draw()

  9. Button logic:

  10. Test with isButtonDown() vs isButtonPressed()
  11. Check button indices match configuration
  12. Verify input is accessed correctly
"},{"location":"resources/troubleshooting/#audio-not-working","title":"Audio Not Working","text":"

Symptoms: - No sound output - Distorted audio - Audio glitches

Solutions: 1. DAC Configuration: - Verify DAC pin (25 or 26 for ESP32) - Check sample rate (11025 Hz recommended) - Ensure audio backend is initialized

  1. I2S Configuration:
  2. Verify I2S pin connections (BCLK, LRCK, DOUT)
  3. Check external DAC is powered
  4. Verify I2S DAC is compatible

  5. Audio quality:

  6. Lower sample rate if distorted
  7. Reduce volume levels
  8. Check for too many simultaneous sounds
  9. Verify audio buffer size

  10. Hardware:

  11. Check speaker connections
  12. Verify amplifier is powered
  13. Test with different audio hardware
  14. Check audio cable connections
"},{"location":"resources/troubleshooting/#power-issues","title":"Power Issues","text":"

Symptoms: - ESP32 resets randomly - Display flickers - Unstable operation

Solutions: 1. Power supply: - Use adequate power supply (500mA+ recommended) - Check voltage is stable (3.3V) - Add decoupling capacitors

  1. Current draw:
  2. Display draws significant current
  3. Audio amplifier adds load
  4. Reduce brightness if possible

  5. Wiring:

  6. Use thick wires for power
  7. Keep power wires short
  8. Add capacitors near ESP32
"},{"location":"resources/troubleshooting/#performance-problems","title":"Performance Problems","text":""},{"location":"resources/troubleshooting/#low-fps","title":"Low FPS","text":"

Symptoms: - Game runs slowly - Laggy movement - Stuttering

Solutions: 1. Reduce entity count: - Limit active entities (MAX_ENTITIES = 32) - Disable off-screen entities - Use object pooling

  1. Optimize rendering:
  2. Use viewport culling
  3. Reduce draw calls
  4. Use tilemaps instead of individual sprites
  5. Limit sprite count

  6. Simplify logic:

  7. Cache expensive calculations
  8. Reduce collision checks
  9. Lower update frequency for non-critical entities

  10. Check hardware:

  11. Verify ESP32 is running at full speed (240MHz)
  12. Check for thermal throttling
  13. Ensure adequate power supply
"},{"location":"resources/troubleshooting/#frame-drops","title":"Frame Drops","text":"

Symptoms: - Occasional stuttering - Inconsistent frame times - Periodic freezes

Solutions: 1. Identify bottlenecks: - Profile frame time - Check for expensive operations - Look for blocking code

  1. Optimize update loop:
  2. Avoid dynamic allocation
  3. Cache calculations
  4. Reduce string operations

  5. Memory issues:

  6. Check for memory leaks
  7. Reduce memory usage
  8. Use object pooling
"},{"location":"resources/troubleshooting/#freezescrashes","title":"Freezes/Crashes","text":"

Symptoms: - Game stops responding - ESP32 resets - Watchdog resets

Solutions: 1. Memory issues: - Check available heap memory - Reduce entity count - Avoid dynamic allocation - Use object pooling

  1. Infinite loops:
  2. Check for infinite loops in update()
  3. Verify collision detection doesn't loop
  4. Check animation logic

  5. Stack overflow:

  6. Avoid large stack allocations
  7. Reduce recursion depth
  8. Move large data to heap (carefully)

  9. Watchdog:

  10. Ensure update() completes quickly
  11. Add yield() calls if needed
  12. Check for blocking operations
"},{"location":"resources/troubleshooting/#memory-problems","title":"Memory Problems","text":""},{"location":"resources/troubleshooting/#out-of-memory","title":"Out of Memory","text":"

Symptoms: - Compilation fails - Runtime crashes - \"Allocation failed\" errors

Solutions: 1. Reduce memory usage: - Use 1bpp sprites instead of 2bpp/4bpp - Store data in flash (const/constexpr) - Reduce entity count - Use object pooling

  1. Optimize data:
  2. Reuse sprites
  3. Compress tilemap data
  4. Remove unused code/data

  5. Memory management:

  6. Avoid dynamic allocation in game loop
  7. Pre-allocate all resources
  8. Use static buffers
"},{"location":"resources/troubleshooting/#memory-fragmentation","title":"Memory Fragmentation","text":"

Symptoms: - Gradual performance degradation - Allocation failures over time - Crashes after running for a while

Solutions: 1. Use object pooling: - Pre-allocate entities - Reuse objects instead of creating/destroying - Avoid frequent new/delete

  1. Pre-allocate resources:
  2. Allocate everything in init()
  3. Use fixed-size arrays
  4. Avoid dynamic containers
"},{"location":"resources/troubleshooting/#native-build-problems","title":"Native Build Problems","text":""},{"location":"resources/troubleshooting/#sdl2-not-found","title":"SDL2 Not Found","text":"

Symptoms: - Compilation fails - Linker errors - Missing SDL2 symbols

Solutions: 1. Install SDL2: - Windows (MSYS2): pacman -S mingw-w64-x86_64-SDL2 - Linux: sudo apt-get install libsdl2-dev - macOS: brew install sdl2

  1. Check paths:
  2. Verify include paths in platformio.ini
  3. Check library paths
  4. Ensure SDL2 version is compatible

  5. Linker flags:

  6. Verify -lSDL2 is in build flags
  7. Check library search paths
  8. Ensure SDL2 DLL is accessible (Windows)
"},{"location":"resources/troubleshooting/#window-not-opening","title":"Window Not Opening","text":"

Symptoms: - Program runs but no window - Console shows errors - Immediate exit

Solutions: 1. Check SDL2 initialization: - Verify SDL2 is properly initialized - Check for SDL2 error messages - Ensure display config is correct

  1. Graphics drivers:
  2. Update graphics drivers
  3. Check SDL2 video backend
  4. Test with simple SDL2 program

  5. Console output:

  6. Run from terminal to see errors
  7. Check for error messages
  8. Verify SDL2 is working
"},{"location":"resources/troubleshooting/#debugging-techniques","title":"Debugging Techniques","text":""},{"location":"resources/troubleshooting/#serial-debugging-esp32","title":"Serial Debugging (ESP32)","text":"
void setup() {\n    Serial.begin(115200);\n    // ... initialization\n\n    Serial.println(\"Engine initialized\");\n}\n\nvoid update(unsigned long deltaTime) override {\n    // Debug output\n    if (frameCount % 60 == 0) {\n        Serial.print(\"FPS: \");\n        Serial.println(1000.0f / deltaTime);\n    }\n    frameCount++;\n}\n
"},{"location":"resources/troubleshooting/#memory-monitoring","title":"Memory Monitoring","text":"
#ifdef PLATFORM_ESP32\n#include <Arduino.h>\n\nvoid checkMemory() {\n    Serial.print(\"Free heap: \");\n    Serial.println(ESP.getFreeHeap());\n    Serial.print(\"Largest block: \");\n    Serial.println(ESP.getMaxAllocHeap());\n}\n#endif\n
"},{"location":"resources/troubleshooting/#performance-profiling","title":"Performance Profiling","text":"
class Profiler {\nprivate:\n    unsigned long updateTime = 0;\n    unsigned long drawTime = 0;\n\npublic:\n    void startUpdate() {\n        updateTime = micros();\n    }\n\n    void endUpdate() {\n        updateTime = micros() - updateTime;\n    }\n\n    void log() {\n        Serial.print(\"Update: \");\n        Serial.print(updateTime);\n        Serial.print(\"us, Draw: \");\n        Serial.println(drawTime);\n    }\n};\n
"},{"location":"resources/troubleshooting/#visual-debugging","title":"Visual Debugging","text":"
  • Draw hitboxes: Visualize collision boxes
  • Show FPS: Display frame rate on screen
  • Entity count: Show active entity count
  • Memory usage: Display memory statistics
"},{"location":"resources/troubleshooting/#common-patterns-for-debugging","title":"Common Patterns for Debugging","text":""},{"location":"resources/troubleshooting/#isolate-the-problem","title":"Isolate the Problem","text":"
  1. Minimal reproduction: Create smallest code that shows issue
  2. Disable features: Turn off systems one by one
  3. Test incrementally: Add features back one at a time
"},{"location":"resources/troubleshooting/#check-the-basics","title":"Check the Basics","text":"
  1. Verify initialization: Ensure engine.init() is called
  2. Check scene setup: Verify scene is set and initialized
  3. Test on both platforms: Compare ESP32 vs Native behavior
  4. Review recent changes: What changed before the issue?
"},{"location":"resources/troubleshooting/#use-logging","title":"Use Logging","text":"
#define DEBUG_MODE\n\n#ifdef DEBUG_MODE\n    #define DEBUG_LOG(x) Serial.println(x)\n#else\n    #define DEBUG_LOG(x)\n#endif\n\n// Usage\nDEBUG_LOG(\"Entity created\");\nDEBUG_LOG(\"Collision detected\");\n
"},{"location":"resources/troubleshooting/#getting-help","title":"Getting Help","text":"

If you can't resolve an issue:

  1. Check documentation: Review relevant guides
  2. Search examples: Look at example games
  3. Review code: Check engine source code
  4. Community: Ask on Discord or GitHub
  5. Report issue: Create detailed bug report
"},{"location":"resources/troubleshooting/#bug-report-template","title":"Bug Report Template","text":"

When reporting issues, include:

  • Platform: ESP32 or Native
  • Hardware: Display type, ESP32 model
  • Code: Minimal reproduction code
  • Error messages: Full error output
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Steps to reproduce: How to trigger the issue
"},{"location":"resources/troubleshooting/#see-also","title":"See Also","text":"
  • Limitations and Considerations - Known limitations
  • Performance Tuning - Performance optimization
  • Memory Management - Memory optimization
  • FAQ - Frequently asked questions

Note: Many issues are configuration-related. Double-check your setup before assuming a bug.

"},{"location":"tools/sprite_compiler/advanced_features/","title":"Sprite Compiler Advanced Features","text":"

Advanced features and options for the PixelRoot32 Sprite Compiler to optimize sprite conversion and handle complex scenarios.

"},{"location":"tools/sprite_compiler/advanced_features/#automatic-palette-detection","title":"Automatic Palette Detection","text":"

The Sprite Compiler automatically detects if your sprite uses one of the engine's built-in palettes. This simplifies your workflow and ensures color consistency.

"},{"location":"tools/sprite_compiler/advanced_features/#predefined-engine-palettes","title":"Predefined Engine Palettes","text":"

The engine includes 5 optimized palettes: - PR32 (Default PixelRoot32 palette) - NES (Nintendo style) - GB (GameBoy style) - GBC (GameBoy Color style) - PICO8 (Fantasy console style)

"},{"location":"tools/sprite_compiler/advanced_features/#how-it-works","title":"How it works","text":"
  1. Detection: When you compile an image, the tool compares all unique colors found in the sprite with the colors in the 5 engine palettes.
  2. Match: If all colors in your sprite belong to one of these palettes, the compiler:
  3. Omits generating a color array in the header.
  4. Assumes you will use the engine's built-in palette definitions at runtime.
  5. Custom Palette: If your sprite uses colors not found in the engine palettes, it automatically generates a {PREFIX}_PALETTE_MAPPING[16] array in the header file.
"},{"location":"tools/sprite_compiler/advanced_features/#naming-with-prefixes","title":"Naming with Prefixes","text":"

You can organize your generated code by using the --prefix parameter (or the Prefix field in the GUI).

"},{"location":"tools/sprite_compiler/advanced_features/#using-prefixes","title":"Using Prefixes","text":"

By default, sprites are named SPRITE_N_.... Using a prefix allows you to create more descriptive names and avoid naming collisions.

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --prefix PLAYER_JUM\n

Generated names will follow this pattern: - PLAYER_JUM_SPRITE_0_LAYER_0 - PLAYER_JUM_SPRITE_0_2BPP - PLAYER_JUM_SPRITE_0_4BPP - PLAYER_JUM_PALETTE_MAPPING (if a custom palette is used)

"},{"location":"tools/sprite_compiler/advanced_features/#export-modes","title":"Export Modes","text":""},{"location":"tools/sprite_compiler/advanced_features/#layered-1bpp","title":"Layered (1bpp)","text":"

Best for standard PixelRoot32 rendering. It extracts each color into its own bitmask (1bpp). The engine then renders these layers sequentially.

"},{"location":"tools/sprite_compiler/advanced_features/#packed-2bpp-4bpp","title":"Packed (2bpp / 4bpp)","text":"

Generates a single packed array where each pixel uses multiple bits. - 2bpp: 4 colors max (Index 0 is always transparent). - 4bpp: 16 colors max (Index 0 is always transparent).

These modes are more efficient for sprites with many colors as they require only a single draw call.

"},{"location":"tools/sprite_compiler/installation/","title":"Sprite Compiler Installation","text":"

This guide walks you through installing the PixelRoot32 Sprite Compiler on your system.

"},{"location":"tools/sprite_compiler/installation/#prerequisites","title":"Prerequisites","text":""},{"location":"tools/sprite_compiler/installation/#required-software","title":"Required Software","text":"
  • Python: Version 3.8 or higher
  • pip: Usually included with Python
"},{"location":"tools/sprite_compiler/installation/#verify-prerequisites","title":"Verify Prerequisites","text":"

Check if Python is installed:

python --version\n# Should show 3.8.0 or higher\n

Check if pip is installed:

pip --version\n# Should show version number\n

If not installed, download from python.org

"},{"location":"tools/sprite_compiler/installation/#installation-methods","title":"Installation Methods","text":""},{"location":"tools/sprite_compiler/installation/#method-1-from-source-recommended","title":"Method 1: From Source (Recommended)","text":""},{"location":"tools/sprite_compiler/installation/#step-1-clone-repository","title":"Step 1: Clone Repository","text":"
git clone https://github.com/Gperez88/PixelRoot32-Sprite-Compiler.git\ncd PixelRoot32-Sprite-Compiler\n
"},{"location":"tools/sprite_compiler/installation/#step-2-install-dependencies","title":"Step 2: Install Dependencies","text":"
pip install -r requirements.txt\n
"},{"location":"tools/sprite_compiler/installation/#step-3-verify-installation","title":"Step 3: Verify Installation","text":"
python main.py --help\n
"},{"location":"tools/sprite_compiler/installation/#method-2-standalone-executable-windows","title":"Method 2: Standalone Executable (Windows)","text":"

If you are on Windows, you can download the latest standalone .exe from the Releases section of the repository. This does not require Python or any dependencies to be installed.

"},{"location":"tools/sprite_compiler/installation/#platform-specific-instructions","title":"Platform-Specific Instructions","text":""},{"location":"tools/sprite_compiler/installation/#windows","title":"Windows","text":""},{"location":"tools/sprite_compiler/installation/#using-npm-recommended","title":"Using npm (Recommended)","text":"
  1. Install Node.js from nodejs.org
  2. Download the Windows installer
  3. Run the installer
  4. Restart your terminal/command prompt

  5. Open Command Prompt or PowerShell

  6. Install globally:

    npm install -g pr32-sprite-compiler\n

  7. Verify:

    pr32-sprite-compiler --version\n

"},{"location":"tools/sprite_compiler/installation/#troubleshooting-windows-issues","title":"Troubleshooting Windows Issues","text":"

\"pr32-sprite-compiler is not recognized\": - Ensure Node.js is in your PATH - Restart terminal after installation - Try using full path: C:\\Users\\YourName\\AppData\\Roaming\\npm\\pr32-sprite-compiler.cmd

Permission errors: - Run terminal as Administrator - Or install locally: npm install pr32-sprite-compiler (without -g)

"},{"location":"tools/sprite_compiler/installation/#linux","title":"Linux","text":""},{"location":"tools/sprite_compiler/installation/#using-npm","title":"Using npm","text":"
  1. Install Node.js (if not already installed):

Ubuntu/Debian:

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -\nsudo apt-get install -y nodejs\n

Fedora/RHEL:

sudo dnf install nodejs npm\n

  1. Install Sprite Compiler:

    sudo npm install -g pr32-sprite-compiler\n

  2. Verify:

    pr32-sprite-compiler --version\n

"},{"location":"tools/sprite_compiler/installation/#troubleshooting-linux-issues","title":"Troubleshooting Linux Issues","text":"

Permission denied: - Use sudo for global installation - Or install locally without -g flag

Command not found: - Check npm global bin path: npm config get prefix - Add to PATH if needed: export PATH=$PATH:$(npm config get prefix)/bin

"},{"location":"tools/sprite_compiler/installation/#macos","title":"macOS","text":""},{"location":"tools/sprite_compiler/installation/#using-npm_1","title":"Using npm","text":"
  1. Install Node.js:
  2. Download from nodejs.org
  3. Or use Homebrew: brew install node

  4. Install Sprite Compiler:

    npm install -g pr32-sprite-compiler\n

  5. Verify:

    pr32-sprite-compiler --version\n

"},{"location":"tools/sprite_compiler/installation/#using-homebrew-alternative","title":"Using Homebrew (Alternative)","text":"

If available as a Homebrew formula:

brew install pr32-sprite-compiler\n

"},{"location":"tools/sprite_compiler/installation/#gui-version-installation","title":"GUI Version Installation","text":"

If a GUI version is available:

"},{"location":"tools/sprite_compiler/installation/#windows_1","title":"Windows","text":"

Download the installer from the releases page and run it.

"},{"location":"tools/sprite_compiler/installation/#linux_1","title":"Linux","text":"
# Download AppImage or .deb package\n# Make executable and run\nchmod +x pr32-sprite-compiler-gui.AppImage\n./pr32-sprite-compiler-gui.AppImage\n
"},{"location":"tools/sprite_compiler/installation/#macos_1","title":"macOS","text":"

Download the .dmg file from releases and install.

"},{"location":"tools/sprite_compiler/installation/#verification","title":"Verification","text":"

After installation, verify everything works:

"},{"location":"tools/sprite_compiler/installation/#test-basic-functionality","title":"Test Basic Functionality","text":"
  1. Create a test image:
  2. Create an 8x8 pixel PNG image (black and white)
  3. Save as test.png

  4. Run compiler:

    pr32-sprite-compiler test.png test_output.h\n

  5. Check output:

  6. File test_output.h should be created
  7. Should contain sprite data arrays
"},{"location":"tools/sprite_compiler/installation/#check-version","title":"Check Version","text":"
pr32-sprite-compiler --version\n
"},{"location":"tools/sprite_compiler/installation/#check-help","title":"Check Help","text":"
pr32-sprite-compiler --help\n
"},{"location":"tools/sprite_compiler/installation/#updating","title":"Updating","text":""},{"location":"tools/sprite_compiler/installation/#update-via-npm","title":"Update via npm","text":"
npm update -g pr32-sprite-compiler\n
"},{"location":"tools/sprite_compiler/installation/#update-from-source","title":"Update from Source","text":"
cd pr32-sprite-compiler\ngit pull\nnpm install\n
"},{"location":"tools/sprite_compiler/installation/#uninstallation","title":"Uninstallation","text":""},{"location":"tools/sprite_compiler/installation/#remove-global-installation","title":"Remove Global Installation","text":"
npm uninstall -g pr32-sprite-compiler\n
"},{"location":"tools/sprite_compiler/installation/#remove-local-installation","title":"Remove Local Installation","text":"
npm uninstall pr32-sprite-compiler\n
"},{"location":"tools/sprite_compiler/installation/#troubleshooting","title":"Troubleshooting","text":""},{"location":"tools/sprite_compiler/installation/#common-issues","title":"Common Issues","text":"

\"Command not found\" after installation: - Restart your terminal - Check npm global bin path: npm config get prefix - Verify PATH includes npm bin directory

Permission errors: - On Linux/macOS: Use sudo for global install - Or install locally without -g flag - On Windows: Run terminal as Administrator

Module not found errors: - Reinstall: npm install -g pr32-sprite-compiler - Clear npm cache: npm cache clean --force

Version conflicts: - Check Node.js version: node --version - Update Node.js if version is too old - Use nvm (Node Version Manager) to manage versions

"},{"location":"tools/sprite_compiler/installation/#getting-help","title":"Getting Help","text":"
  • Check the Usage Guide for usage examples
  • Review Troubleshooting for common issues
  • Open an issue on GitHub if problems persist
"},{"location":"tools/sprite_compiler/installation/#next-steps","title":"Next Steps","text":"

Once installed, proceed to: - Usage Guide - Learn how to use the compiler - Advanced Features - Explore advanced options

"},{"location":"tools/sprite_compiler/installation/#see-also","title":"See Also","text":"
  • Overview - What the Sprite Compiler does
  • Available Tools - All PixelRoot32 tools
"},{"location":"tools/sprite_compiler/overview/","title":"Sprite Compiler Overview","text":"

The Sprite Compiler is a tool that converts PNG images into PixelRoot32 sprite data formats. It provides both a graphical interface (GUI) and a command-line interface (CLI) to automate the process of creating sprite arrays from image files.

"},{"location":"tools/sprite_compiler/overview/#what-it-does","title":"What It Does","text":"

The Sprite Compiler takes bitmap images (PNG) and converts them into C header files containing:

  • Sprite data arrays: Optimized uint16_t arrays for various formats.
  • Layered support: Generates multiple 1bpp layers for complex sprites.
  • Packed formats: Supports 2bpp and 4bpp packed formats.
  • Sprite sheets: Handles grid-based sprite sheets with auto-detection.
"},{"location":"tools/sprite_compiler/overview/#key-features","title":"Key Features","text":""},{"location":"tools/sprite_compiler/overview/#format-support","title":"\u2705 Format Support","text":"
  • Layered (1bpp): Standard format, generates one array per color.
  • 2bpp (4 colors): Packed format, 2 bits per pixel.
  • 4bpp (16 colors): Packed format, 4 bits per pixel.
"},{"location":"tools/sprite_compiler/overview/#gui-cli","title":"\u2705 GUI & CLI","text":"
  • Modern GUI: Step-by-step card-based interface for easy configuration.
  • Powerful CLI: Perfect for build scripts and automation.
"},{"location":"tools/sprite_compiler/overview/#sprite-sheets","title":"\u2705 Sprite Sheets","text":"

Automatically split sprite sheets into individual sprites:

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --sprite 1,0,1,1 --out output.h\n

"},{"location":"tools/sprite_compiler/overview/#gui-interface","title":"GUI Interface","text":"

The GUI is designed to be intuitive and follows a 5-step process:

  1. Input Image: Select your PNG source.
  2. Grid Settings: Define the cell size and offsets.
  3. Sprite Selection: Pick which cells to export.
  4. Export Settings: Choose the mode (Layered, 2bpp, 4bpp), set a Prefix, and choose the output path.
  5. About: Quick access to version info and credits (via the ? button).
  6. Log: Technical feedback and performance alerts.
"},{"location":"tools/sprite_compiler/overview/#input-requirements","title":"Input Requirements","text":""},{"location":"tools/sprite_compiler/overview/#supported-formats","title":"Supported Formats","text":"
  • PNG: Primary format (recommended)
  • Indexed color PNG: Best for 1bpp conversion
  • Grayscale PNG: Automatically converted to 1bpp
  • RGB PNG: Converted using threshold or palette
"},{"location":"tools/sprite_compiler/overview/#image-constraints","title":"Image Constraints","text":"

For 1bpp sprites: - Maximum width: 16 pixels - Height: Any (typically 8, 16, 32 pixels) - Colors: Black and white (or converted automatically)

For 2bpp sprites: - Maximum width: 16 pixels - Colors: Up to 4 colors

For 4bpp sprites: - Maximum width: 16 pixels - Colors: Up to 16 colors

"},{"location":"tools/sprite_compiler/overview/#output-format","title":"Output Format","text":"

The compiler generates C header files with optimized arrays:

// Generated by PixelRoot32 Sprite Compiler\n\n// Optional palette mapping if using custom colors\nstatic const Color PLAYER_PALETTE_MAPPING[16] = {\n    (Color)0, (Color)1, (Color)2, (Color)3,\n    // ...\n};\n\n// Sprite data array (4bpp example)\nstatic const uint16_t PLAYER_SPRITE_0_4BPP[] = {\n    0x0000, 0x1234, 0x5678, // Row 0\n    // ... more rows\n};\n
"},{"location":"tools/sprite_compiler/overview/#use-cases","title":"Use Cases","text":""},{"location":"tools/sprite_compiler/overview/#1-single-sprite-conversion","title":"1. Single Sprite Conversion","text":"

Convert a single image to a sprite:

pr32-sprite-compiler player.png player_sprite.h --name PLAYER_SPRITE\n

"},{"location":"tools/sprite_compiler/overview/#2-animation-frames","title":"2. Animation Frames","text":"

Convert multiple frames for animation:

pr32-sprite-compiler --batch walk_*.png --output-dir animations/ --prefix WALK_\n

"},{"location":"tools/sprite_compiler/overview/#3-sprite-sheet-processing","title":"3. Sprite Sheet Processing","text":"

Split a sprite sheet into individual sprites:

pr32-sprite-compiler characters.png output.h --sheet 16x16 --count 8\n

"},{"location":"tools/sprite_compiler/overview/#4-batch-asset-processing","title":"4. Batch Asset Processing","text":"

Process entire asset directories:

pr32-sprite-compiler --batch assets/sprites/*.png --output-dir src/sprites/\n

"},{"location":"tools/sprite_compiler/overview/#workflow-integration","title":"Workflow Integration","text":""},{"location":"tools/sprite_compiler/overview/#typical-development-workflow","title":"Typical Development Workflow","text":"
  1. Create sprites in your image editor (Aseprite, Piskel, GIMP, etc.)
  2. Save as PNG with appropriate dimensions
  3. Run compiler to generate header files
  4. Include headers in your PixelRoot32 project
  5. Use sprites in your game code
"},{"location":"tools/sprite_compiler/overview/#automation-example","title":"Automation Example","text":"
#!/bin/bash\n# build-sprites.sh\n\n# Compile all sprites\npr32-sprite-compiler assets/sprites/*.png --output-dir src/sprites/\n\n# Continue with your build process\nplatformio run\n
"},{"location":"tools/sprite_compiler/overview/#advantages-over-manual-creation","title":"Advantages Over Manual Creation","text":""},{"location":"tools/sprite_compiler/overview/#time-saving","title":"\u2705 Time Saving","text":"
  • No manual bit pattern conversion
  • Automatic format optimization
  • Batch processing multiple sprites
"},{"location":"tools/sprite_compiler/overview/#accuracy","title":"\u2705 Accuracy","text":"
  • Correct bit ordering
  • Proper array formatting
  • Valid C++ syntax
"},{"location":"tools/sprite_compiler/overview/#consistency","title":"\u2705 Consistency","text":"
  • Uniform naming conventions
  • Standardized output format
  • Consistent code structure
"},{"location":"tools/sprite_compiler/overview/#maintainability","title":"\u2705 Maintainability","text":"
  • Easy to regenerate from source images
  • Version control friendly
  • Clear separation of assets and code
"},{"location":"tools/sprite_compiler/overview/#limitations","title":"Limitations","text":"
  • Width limit: 16 pixels for 1bpp (hardware constraint)
  • Color depth: Limited by format (1bpp = 2 colors, 2bpp = 4 colors, etc.)
  • File format: Primarily PNG (other formats may require conversion)
"},{"location":"tools/sprite_compiler/overview/#next-steps","title":"Next Steps","text":"
  • Installation Guide - Set up the compiler
  • Usage Guide - Learn how to use it
  • Advanced Features - Explore advanced options
"},{"location":"tools/sprite_compiler/overview/#see-also","title":"See Also","text":"
  • Manual - Sprites and Animation - Using sprites in games
  • Code Examples - Sprites - Sprite usage examples
  • Available Tools - All PixelRoot32 tools
"},{"location":"tools/sprite_compiler/usage_guide/","title":"Sprite Compiler Usage Guide","text":"

Complete guide to using the PixelRoot32 Sprite Compiler for converting images to sprite data.

"},{"location":"tools/sprite_compiler/usage_guide/#basic-usage","title":"Basic Usage","text":""},{"location":"tools/sprite_compiler/usage_guide/#launching-the-gui","title":"Launching the GUI","text":"

The easiest way to use the compiler is via the Graphical User Interface (GUI).

python main.py\n

This will open the application where you can interactively load images, configure the grid, and export sprites.

"},{"location":"tools/sprite_compiler/usage_guide/#command-line-interface-cli","title":"Command Line Interface (CLI)","text":"

For automation, you can use the CLI mode by passing arguments to the script.

python main.py [input] [options]\n

Required:

  • input: Input PNG image file
  • --grid WxH: Grid cell size (e.g., 16x16)
  • --sprite gx,gy,gw,gh: Sprite definition (can be repeated)

Optional:

  • --prefix NAME: Prefix for generated arrays (e.g., PLAYER_JUM)
  • --out FILE: Output header file (default: sprites.h)
  • --offset X,Y: Initial offset in pixels (default: 0,0)
  • --mode MODE: Export mode (layered, 2bpp, 4bpp)
"},{"location":"tools/sprite_compiler/usage_guide/#cli-examples","title":"CLI Examples","text":""},{"location":"tools/sprite_compiler/usage_guide/#simple-conversion","title":"Simple Conversion","text":"

Convert a single 16x16 sprite located at the top-left corner:

python main.py player.png --grid 16x16 --sprite 0,0,1,1 --out player.h\n
"},{"location":"tools/sprite_compiler/usage_guide/#multiple-sprites","title":"Multiple Sprites","text":"

Convert multiple sprites from a single sheet:

python main.py sheet.png --grid 16x16 \\\n  --sprite 0,0,1,1 \\\n  --sprite 1,0,1,1 \\\n  --sprite 2,0,1,1 \\\n  --out animations.h\n
"},{"location":"tools/sprite_compiler/usage_guide/#export-modes","title":"Export Modes","text":"

Layered (Default): Generates multiple uint16_t arrays, one for each color layer. Best for standard PixelRoot32 rendering.

python main.py icon.png --grid 16x16 --sprite 0,0,1,1 --mode layered\n

Packed 2bpp: Generates a single array with 2 bits per pixel (4 colors max).

python main.py icon.png --grid 16x16 --sprite 0,0,1,1 --mode 2bpp\n
"},{"location":"tools/sprite_compiler/usage_guide/#step-by-step-examples","title":"Step-by-Step Examples","text":""},{"location":"tools/sprite_compiler/usage_guide/#example-1-simple-player-sprite","title":"Example 1: Simple Player Sprite","text":"

Step 1: Create Image

  • Create an 8x8 pixel PNG image
  • Use black and white colors
  • Save as player.png

Step 2: Compile

python main.py player.png --grid 8x8 --sprite 0,0,1,1 --prefix PLAYER --out player_sprite.h\n

Step 3: Use in Code

#include \"player_sprite.h\"\n\nvoid draw() {\n    // PLAYER_SPRITE_0_LAYER_0 is generated automatically\n    renderer.drawSprite(PLAYER_SPRITE_0_LAYER_0, 100, 100, Color::White);\n}\n
"},{"location":"tools/sprite_compiler/usage_guide/#example-2-multiple-animation-frames","title":"Example 2: Multiple Animation Frames","text":"

Step 1: Prepare Images

  • Create frames: walk_0.png, walk_1.png, walk_2.png
  • All same size (e.g., 16x16)

Step 2: Batch Compile

pr32-sprite-compiler --batch walk_*.png --output-dir animations/ --prefix WALK_\n

Step 3: Use in Animation

#include \"animations/walk_0.h\"\n#include \"animations/walk_1.h\"\n#include \"animations/walk_2.h\"\n\nconst Sprite* WALK_FRAMES[] = {\n    &WALK_0_SPRITE,\n    &WALK_1_SPRITE,\n    &WALK_2_SPRITE\n};\n
"},{"location":"tools/sprite_compiler/usage_guide/#example-3-sprite-sheet","title":"Example 3: Sprite Sheet","text":"

Step 1: Create Sprite Sheet

  • Create a 64x64 image with 4x4 grid of 16x16 sprites
  • Save as characters.png

Step 2: Split Sheet

pr32-sprite-compiler characters.png characters.h --sheet 16x16 --count 16\n

Step 3: Use Individual Sprites

#include \"characters.h\"\n\n// Sprites named CHARACTER_0, CHARACTER_1, etc.\nrenderer.drawSprite(CHARACTER_0, 50, 50, Color::White);\nrenderer.drawSprite(CHARACTER_1, 70, 50, Color::White);\n
"},{"location":"tools/sprite_compiler/usage_guide/#batch-processing","title":"Batch Processing","text":""},{"location":"tools/sprite_compiler/usage_guide/#process-multiple-files","title":"Process Multiple Files","text":"

Process all PNG files in a directory:

pr32-sprite-compiler --batch sprites/*.png --output-dir generated/\n
"},{"location":"tools/sprite_compiler/usage_guide/#with-options","title":"With Options","text":"

Apply options to all files:

pr32-sprite-compiler --batch assets/*.png \\\n    --output-dir src/sprites/ \\\n    --format 1bpp \\\n    --prefix SPRITE_\n
"},{"location":"tools/sprite_compiler/usage_guide/#recursive-processing","title":"Recursive Processing","text":"

Process subdirectories:

pr32-sprite-compiler --batch assets/**/*.png --output-dir generated/\n
"},{"location":"tools/sprite_compiler/usage_guide/#sprite-sheets","title":"Sprite Sheets","text":""},{"location":"tools/sprite_compiler/usage_guide/#automatic-splitting","title":"Automatic Splitting","text":"

Split a sprite sheet into individual sprites:

pr32-sprite-compiler sheet.png output.h --sheet 8x8 --count 16\n

Parameters:

  • --sheet WxH: Tile size (width x height)
  • --count N: Number of sprites in sheet
"},{"location":"tools/sprite_compiler/usage_guide/#grid-layout","title":"Grid Layout","text":"

Specify grid dimensions:

pr32-sprite-compiler sheet.png output.h \\\n    --sheet 16x16 \\\n    --grid 4x4 \\\n    --count 16\n

Parameters:

  • --grid WxH: Grid dimensions (columns x rows)
"},{"location":"tools/sprite_compiler/usage_guide/#custom-naming","title":"Custom Naming","text":"

Name sprites with index:

pr32-sprite-compiler sheet.png output.h \\\n    --sheet 8x8 \\\n    --count 8 \\\n    --prefix CHARACTER_ \\\n    --indexed\n

Generates: CHARACTER_0, CHARACTER_1, etc.

"},{"location":"tools/sprite_compiler/usage_guide/#custom-palettes","title":"Custom Palettes","text":""},{"location":"tools/sprite_compiler/usage_guide/#using-palette-file","title":"Using Palette File","text":"

Convert with custom color palette:

pr32-sprite-compiler sprite.png output.h --palette palette.json\n

Palette JSON format:

{\n  \"colors\": [\n    {\"r\": 0, \"g\": 0, \"b\": 0, \"name\": \"black\"},\n    {\"r\": 255, \"g\": 255, \"b\": 255, \"name\": \"white\"}\n  ]\n}\n
"},{"location":"tools/sprite_compiler/usage_guide/#built-in-palettes","title":"Built-in Palettes","text":"

Use predefined palettes:

pr32-sprite-compiler sprite.png output.h --palette nes\npr32-sprite-compiler sprite.png output.h --palette gb\npr32-sprite-compiler sprite.png output.h --palette pico8\n
"},{"location":"tools/sprite_compiler/usage_guide/#advanced-options","title":"Advanced Options","text":""},{"location":"tools/sprite_compiler/usage_guide/#threshold-for-grayscale","title":"Threshold for Grayscale","text":"

Set threshold for black/white conversion:

pr32-sprite-compiler sprite.png output.h --threshold 128\n

Values: 0-255 (default: 127)

"},{"location":"tools/sprite_compiler/usage_guide/#dithering","title":"Dithering","text":"

Enable dithering for better gradients:

pr32-sprite-compiler sprite.png output.h --dither\n
"},{"location":"tools/sprite_compiler/usage_guide/#alignment","title":"Alignment","text":"

Control output alignment:

pr32-sprite-compiler sprite.png output.h --align 4\n
"},{"location":"tools/sprite_compiler/usage_guide/#endianness","title":"Endianness","text":"

Specify byte order:

pr32-sprite-compiler sprite.png output.h --endian little\npr32-sprite-compiler sprite.png output.h --endian big\n
"},{"location":"tools/sprite_compiler/usage_guide/#output-customization","title":"Output Customization","text":""},{"location":"tools/sprite_compiler/usage_guide/#namespace","title":"Namespace","text":"

Wrap output in namespace:

pr32-sprite-compiler sprite.png output.h --namespace MyGame\n
"},{"location":"tools/sprite_compiler/usage_guide/#header-guard","title":"Header Guard","text":"

Custom header guard:

pr32-sprite-compiler sprite.png output.h --guard MY_SPRITE_H\n
"},{"location":"tools/sprite_compiler/usage_guide/#include-paths","title":"Include Paths","text":"

Custom include paths:

pr32-sprite-compiler sprite.png output.h \\\n    --include \"<graphics/Sprite.h>\" \\\n    --include \"<stdint.h>\"\n
"},{"location":"tools/sprite_compiler/usage_guide/#integration-with-build-systems","title":"Integration with Build Systems","text":""},{"location":"tools/sprite_compiler/usage_guide/#platformio","title":"PlatformIO","text":"

Add to platformio.ini:

[env:esp32dev]\nextra_scripts = \n    pre:scripts/compile_sprites.py\n

compile_sprites.py:

Import(\"env\")\nimport subprocess\n\nsubprocess.run([\n    \"pr32-sprite-compiler\",\n    \"--batch\", \"assets/sprites/*.png\",\n    \"--output-dir\", \"src/sprites/\"\n])\n
"},{"location":"tools/sprite_compiler/usage_guide/#makefile","title":"Makefile","text":"
SPRITES = $(wildcard assets/sprites/*.png)\nSPRITE_HEADERS = $(SPRITES:assets/sprites/%.png=src/sprites/%.h)\n\nsrc/sprites/%.h: assets/sprites/%.png\n pr32-sprite-compiler $< $@ --name $(shell basename $< .png | tr '[:lower:]' '[:upper:]')_SPRITE\n\nsprites: $(SPRITE_HEADERS)\n
"},{"location":"tools/sprite_compiler/usage_guide/#cmake","title":"CMake","text":"
file(GLOB SPRITE_FILES \"assets/sprites/*.png\")\n\nforeach(SPRITE ${SPRITE_FILES})\n    get_filename_component(SPRITE_NAME ${SPRITE} NAME_WE)\n    add_custom_command(\n        OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/sprites/${SPRITE_NAME}.h\n        COMMAND pr32-sprite-compiler\n        ARGS ${SPRITE} ${CMAKE_CURRENT_SOURCE_DIR}/src/sprites/${SPRITE_NAME}.h\n        DEPENDS ${SPRITE}\n    )\nendforeach()\n
"},{"location":"tools/sprite_compiler/usage_guide/#gui-usage-if-available","title":"GUI Usage (If Available)","text":""},{"location":"tools/sprite_compiler/usage_guide/#opening-gui","title":"Opening GUI","text":"
pr32-sprite-compiler --gui\n

Or launch the GUI application directly.

"},{"location":"tools/sprite_compiler/usage_guide/#gui-workflow","title":"GUI Workflow","text":"
  1. Drag and drop images into the window
  2. Preview sprite data in real-time
  3. Adjust settings visually (format, threshold, etc.)
  4. Export to header files
  5. Batch process multiple files
"},{"location":"tools/sprite_compiler/usage_guide/#gui-features","title":"GUI Features","text":"
  • Visual preview of sprite conversion
  • Real-time threshold adjustment
  • Palette selection
  • Batch processing interface
  • Export options
"},{"location":"tools/sprite_compiler/usage_guide/#best-practices","title":"Best Practices","text":""},{"location":"tools/sprite_compiler/usage_guide/#image-preparation","title":"Image Preparation","text":"
  • Use indexed color PNG for best results
  • Keep sprites small (8x8, 16x16, 32x32)
  • Use black and white for 1bpp
  • Limit colors for 2bpp/4bpp formats
"},{"location":"tools/sprite_compiler/usage_guide/#file-organization","title":"File Organization","text":"
project/\n\u251c\u2500\u2500 assets/\n\u2502   \u2514\u2500\u2500 sprites/\n\u2502       \u251c\u2500\u2500 player.png\n\u2502       \u251c\u2500\u2500 enemy.png\n\u2502       \u2514\u2500\u2500 items.png\n\u251c\u2500\u2500 src/\n\u2502   \u2514\u2500\u2500 sprites/          # Generated headers\n\u2502       \u251c\u2500\u2500 player.h\n\u2502       \u251c\u2500\u2500 enemy.h\n\u2502       \u2514\u2500\u2500 items.h\n\u2514\u2500\u2500 platformio.ini\n
"},{"location":"tools/sprite_compiler/usage_guide/#naming-conventions","title":"Naming Conventions","text":"
  • Use descriptive names: player_walk_0.png \u2192 PLAYER_WALK_0_SPRITE
  • Be consistent: All caps for sprite names
  • Use prefixes: ENEMY_, PLAYER_, ITEM_
"},{"location":"tools/sprite_compiler/usage_guide/#version-control","title":"Version Control","text":"
  • Commit generated headers (they're part of the build)
  • Or add to .gitignore and regenerate on build
  • Keep source images in version control
"},{"location":"tools/sprite_compiler/usage_guide/#troubleshooting","title":"Troubleshooting","text":""},{"location":"tools/sprite_compiler/usage_guide/#common-issues","title":"Common Issues","text":"

\"Image too large\":

  • Sprites must be \u2264 16 pixels wide for 1bpp
  • Resize image or split into multiple sprites

\"Colors not converting correctly\":

  • Use indexed color PNG
  • For 1bpp: Use only black and white
  • For 2bpp: Use exactly 4 colors
  • For 4bpp: Use up to 16 colors

\"Output file not found\":

  • Check write permissions
  • Verify output directory exists
  • Use absolute paths if needed

\"Invalid format\":

  • Ensure input is PNG format
  • Check file is not corrupted
  • Try re-saving image in image editor
"},{"location":"tools/sprite_compiler/usage_guide/#getting-help","title":"Getting Help","text":"
pr32-sprite-compiler --help\n

Shows all available options and usage.

"},{"location":"tools/sprite_compiler/usage_guide/#next-steps","title":"Next Steps","text":"
  • Advanced Features - Explore advanced options
  • Overview - Learn more about the compiler
  • Manual - Sprites - Using sprites in games
"},{"location":"tools/sprite_compiler/usage_guide/#see-also","title":"See Also","text":"
  • Code Examples - Sprites - Sprite usage examples
  • Troubleshooting - Common issues and solutions
"},{"location":"tools/tilemap_editor/installation/","title":"Installation Guide","text":"

The PixelRoot32 Tilemap Editor can be run directly from source or as a standalone executable on Windows.

"},{"location":"tools/tilemap_editor/installation/#1-requirements","title":"1. Requirements","text":"
  • Python 3.13+ (if running from source).
  • Windows 10/11 (recommended).
"},{"location":"tools/tilemap_editor/installation/#2-install-from-source","title":"2. Install from Source","text":""},{"location":"tools/tilemap_editor/installation/#21-clone-the-repository","title":"2.1 Clone the Repository","text":"
git clone https://github.com/Gperez88/PixelRoot32-Tilemap-Editor.git\ncd PixelRoot32-Tilemap-Editor\n
"},{"location":"tools/tilemap_editor/installation/#22-install-dependencies","title":"2.2 Install Dependencies","text":"

The editor uses several Python libraries for the GUI and image processing:

pip install ttkbootstrap pillow jinja2\n
"},{"location":"tools/tilemap_editor/installation/#23-run-the-editor","title":"2.3 Run the Editor","text":"
python main.py\n
"},{"location":"tools/tilemap_editor/installation/#3-standalone-executable-windows","title":"3. Standalone Executable (Windows)","text":"

For a more convenient experience, you can use the pre-compiled version:

  1. Go to the Releases section of the repository.
  2. Download the latest PixelRoot32-Editor-win64.zip.
  3. Extract the contents to a folder.
  4. Run PixelRoot32-Editor.exe.

Note: No Python installation is required to run the standalone executable.

"},{"location":"tools/tilemap_editor/installation/#4-building-your-own-executable","title":"4. Building your own Executable","text":"

If you want to package the editor yourself:

  1. Install PyInstaller:
pip install pyinstaller\n
  1. Run the build command using the provided .spec file:
pyinstaller pixelroot32_editor.spec\n
  1. The executable will be available in the dist/ folder.
"},{"location":"tools/tilemap_editor/overview/","title":"Tilemap Editor Overview","text":"

The PixelRoot32 Tilemap Editor is a powerful visual tool designed to create complex multi-layered tile-based maps for the PixelRoot32 engine. It simplifies the process of designing game environments, managing tilesets, and exporting optimized C++ code.

"},{"location":"tools/tilemap_editor/overview/#what-it-does","title":"What It Does","text":"

The Tilemap Editor allows you to:

  • Visual Design: Paint tiles directly onto a canvas with layers and transparency.
  • Tileset Management: Import PNG images as tilesets and select single or multiple tiles.
  • Multi-Layer Support: Organize your map into up to 8 layers for parallax effects or depth.
  • Optimized Export: Generate C++ header and source files compatible with the PixelRoot32 renderer.
  • BPP Support: Export maps in 1bpp, 2bpp, or 4bpp formats to balance memory usage and color depth.
"},{"location":"tools/tilemap_editor/overview/#key-features","title":"Key Features","text":""},{"location":"tools/tilemap_editor/overview/#visual-editing-tools","title":"\u2705 Visual Editing Tools","text":"
  • Brush: Paint individual tiles or patterns.
  • Eraser: Remove tiles from the active layer.
  • Rectangle Fill: Quickly fill areas with a specific tile.
  • Pipette: Pick an existing tile from the canvas.
"},{"location":"tools/tilemap_editor/overview/#multi-layer-system","title":"\u2705 Multi-Layer System","text":"
  • Visibility Toggle: Hide/show layers to focus on specific parts of the map.
  • Opacity Control: Adjust layer transparency for complex blending effects.
  • Layer Reordering: Change the render order of your tilemaps.
"},{"location":"tools/tilemap_editor/overview/#tileset-selector","title":"\u2705 Tileset Selector","text":"
  • Smart Selection: Drag and select a rectangular area of tiles.
  • Multiple Tilesets: Support for multiple tilesets per project (planned).
  • Auto-import: Automatically detects tile size from the imported image.
"},{"location":"tools/tilemap_editor/overview/#engine-integration","title":"\u2705 Engine Integration","text":"
  • Workspace Selection: Link the editor to your PixelRoot32 projects directory.
  • Direct Export: Files are generated with the correct namespaces and structures for immediate use.
  • BPP Compatibility: Ensures exported data matches the engine's expected format for 1bpp, 2bpp, and 4bpp.
"},{"location":"tools/tilemap_editor/overview/#data-formats","title":"Data Formats","text":""},{"location":"tools/tilemap_editor/overview/#project-file-pr32scene","title":"Project File (.pr32scene)","text":"

The editor uses a custom JSON-based format to save your project state, including:

  • Tileset metadata (path, tile size, spacing).
  • Layer data (tile indices, width, height, position).
  • Project settings (BPP, namespace).
"},{"location":"tools/tilemap_editor/overview/#exported-c","title":"Exported C++","text":"

The editor generates <namespace>.h and <namespace>.cpp files containing:

  • Tilemap Data: One packed array of tile indices per layer (*_INDICES[]). Each layer is exposed as a TileMap4bpp (or TileMap2bpp/TileMap) with an indices pointer; use the same data for rendering and for tile-based collision in your game code.
  • Tilemap Structures: pixelroot32::graphics::TileMap (or TileMap2bpp/TileMap4bpp) definitions, plus tileset pool and palette.
  • Export options: Store data in Flash (ESP32) (default) emits static data with PROGMEM to reduce RAM use; Legacy format disables Flash attributes for backward compatibility or non-ESP32 builds.
  • Scene init: Call init() once before drawing; the generated code registers the palette and configures each layer for the engine.
"},{"location":"tools/tilemap_editor/usage_guide/","title":"Usage Guide","text":"

This guide covers the basic workflow for creating and exporting a tilemap using the PixelRoot32 Tilemap Editor.

"},{"location":"tools/tilemap_editor/usage_guide/#1-creating-a-new-project","title":"1. Creating a New Project","text":"
  1. Launch the editor.
  2. Go to File > New Project.
  3. Enter the project name and select the base Color Depth (BPP):
  4. 1bpp: Monochrome (2 colors).
  5. 2bpp: 4 colors.
  6. 4bpp: 16 colors.
  7. Set the Tile Size (e.g., 8x8, 16x16).
"},{"location":"tools/tilemap_editor/usage_guide/#2-importing-a-tileset","title":"2. Importing a Tileset","text":"
  1. In the Tileset panel, click on Load Tileset.
  2. Select a PNG image containing your tiles.
  3. The image will be sliced into tiles based on the tile size set in the project.
"},{"location":"tools/tilemap_editor/usage_guide/#3-painting-tiles","title":"3. Painting Tiles","text":"
  1. Select a tile (or a range of tiles) from the Tileset panel.
  2. Select the Brush tool (Shortcut: B).
  3. Click and drag on the canvas to paint.
  4. Use the Layers panel to switch between different layers.
"},{"location":"tools/tilemap_editor/usage_guide/#4-selection-and-transformations","title":"4. Selection and Transformations","text":"
  • Single Selection: Click on a tile in the tileset.
  • Area Selection: Click and drag in the tileset to select a rectangular block of tiles.
  • Pipette: Press P and click on the canvas to pick the tile under the cursor.
"},{"location":"tools/tilemap_editor/usage_guide/#5-exporting-to-c","title":"5. Exporting to C++","text":"
  1. Ensure you have at least one tileset imported.
  2. Click the Export button in the top right (or File > Export / Ctrl+E).
  3. In the export dialog:
  4. Set the C++ Namespace (e.g. forest_level); it defaults to the project name.
  5. Review the Color Depth (BPP); it is auto-detected from your tileset colors (1bpp, 2bpp, or 4bpp).
  6. Store data in Flash (ESP32): Checked by default; emits PROGMEM for palette, tileset, and layer data to reduce RAM on ESP32.
  7. Legacy format (no Flash attribute): Use for older projects or non-ESP32 builds.
  8. Click Export Now and choose the output directory.
  9. The editor generates:
  10. <namespace>.h: Declarations (e.g. TILE_SIZE, MAP_WIDTH, MAP_HEIGHT, layer TileMap4bpp externs, init()).
  11. <namespace>.cpp: Definitions (palette, tileset pool, layer indices, init() implementation). Use each layer's .indices in your game for drawing and tile-based collision.
"},{"location":"tools/tilemap_editor/usage_guide/#6-keyboard-shortcuts","title":"6. Keyboard Shortcuts","text":"Shortcut Action B Brush Tool E Eraser Tool R Rectangle Fill Tool P Pipette Tool Space + Drag Pan Canvas Mouse Wheel Zoom In/Out Ctrl + N New Project Ctrl + S Save Project Ctrl + E Export Project Esc Close floating panels"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"PixelRoot32 Documentation","text":"

PixelRoot32 is a lightweight 2D game engine designed for ESP32 and native desktop targets. This site provides official, versioned documentation with clear guides, conceptual explanations, API references, and complete examples to help you build games efficiently.

"},{"location":"#quick-links","title":"Quick Links","text":"
  • What is PixelRoot32? - Start here to understand the engine
  • Your First Project - Get up and running quickly
  • Fundamental Concepts - Learn the core concepts
  • Manual - Complete user guide
  • API Reference - Complete API documentation
  • Examples - Complete game examples
  • Tools - Available tools
  • FAQ - FAQ and troubleshooting
"},{"location":"#getting-started","title":"Getting Started","text":"

New to PixelRoot32? Follow this learning path:

  1. What is PixelRoot32? - Understand what the engine is and what it can do
  2. Why PixelRoot32? - Learn the advantages and use cases
  3. Fundamental Concepts - Learn the core architecture concepts
  4. Your First Project - Create and run your first project
"},{"location":"#about-this-documentation","title":"About This Documentation","text":"
  • Professional technical English across all pages
  • Search-enabled, mobile-friendly UI
  • Versioned with mike (stable/dev/experimental)
  • Cross-linked concepts, API, and examples
  • Progressive learning path from basics to advanced topics
"},{"location":"api_reference/audio/audio_config/","title":"AudioConfig","text":"

Configuration for the Audio subsystem.

"},{"location":"api_reference/audio/audio_config/#description","title":"Description","text":"

AudioConfig is a simple struct that holds configuration settings for the audio system, including the audio backend and sample rate. It is passed to AudioEngine during construction.

"},{"location":"api_reference/audio/audio_config/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    struct AudioConfig {\n        // ...\n    };\n}\n
"},{"location":"api_reference/audio/audio_config/#structure","title":"Structure","text":""},{"location":"api_reference/audio/audio_config/#audiobackend-backend","title":"AudioBackend* backend","text":"

Pointer to the platform-specific audio backend implementation.

Type: AudioBackend*

Access: Read-write

Default: nullptr

Notes: - Must be set to a valid backend instance - Backend is platform-specific: - ESP32: ESP32_DAC_AudioBackend or ESP32_I2S_AudioBackend - Native: SDL2_AudioBackend - Backend manages the actual audio hardware/API

Example:

#ifdef PLATFORM_ESP32\n    pixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\n    audioConfig.backend = &dacBackend;\n#elif PLATFORM_NATIVE\n    pixelroot32::drivers::native::SDL2_AudioBackend sdlBackend;\n    audioConfig.backend = &sdlBackend;\n#endif\n

"},{"location":"api_reference/audio/audio_config/#int-samplerate","title":"int sampleRate","text":"

Desired sample rate in Hz.

Type: int

Access: Read-write

Default: 22050

Notes: - Common values: 11025, 22050, 44100 - Lower rates use less CPU and memory (better for ESP32) - Higher rates provide better quality - Must match backend capabilities

Example:

audioConfig.sampleRate = 11025;  // Lower quality, less CPU (ESP32)\naudioConfig.sampleRate = 22050;  // Balanced (default)\naudioConfig.sampleRate = 44100; // Higher quality (Native)\n

"},{"location":"api_reference/audio/audio_config/#constructors","title":"Constructors","text":""},{"location":"api_reference/audio/audio_config/#audioconfigaudiobackend-backend-nullptr-int-samplerate-22050","title":"AudioConfig(AudioBackend* backend = nullptr, int sampleRate = 22050)","text":"

Default constructor.

Parameters: - backend (AudioBackend*, optional): Pointer to the audio backend implementation. Default: nullptr - sampleRate (int, optional): Desired sample rate in Hz. Default: 22050

Example:

// Default construction\npixelroot32::audio::AudioConfig audioConfig;\n\n// With backend\npixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\npixelroot32::audio::AudioConfig audioConfig(&dacBackend, 11025);\n

"},{"location":"api_reference/audio/audio_config/#usage-example","title":"Usage Example","text":""},{"location":"api_reference/audio/audio_config/#esp32-with-dac-backend","title":"ESP32 with DAC Backend","text":"
#ifdef PLATFORM_ESP32\n#include \"drivers/esp32/ESP32_DAC_AudioBackend.h\"\n\npixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &dacBackend;\naudioConfig.sampleRate = 11025;  // Lower rate for ESP32\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n#endif\n
"},{"location":"api_reference/audio/audio_config/#esp32-with-i2s-backend","title":"ESP32 with I2S Backend","text":"
#ifdef PLATFORM_ESP32\n#include \"drivers/esp32/ESP32_I2S_AudioBackend.h\"\n\npixelroot32::drivers::esp32::ESP32_I2S_AudioBackend i2sBackend;\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &i2sBackend;\naudioConfig.sampleRate = 22050;  // Higher quality with I2S\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n#endif\n
"},{"location":"api_reference/audio/audio_config/#native-with-sdl2-backend","title":"Native with SDL2 Backend","text":"
#ifdef PLATFORM_NATIVE\n#include \"drivers/native/SDL2_AudioBackend.h\"\n\npixelroot32::drivers::native::SDL2_AudioBackend sdlBackend;\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &sdlBackend;\naudioConfig.sampleRate = 44100;  // High quality for PC\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n#endif\n
"},{"location":"api_reference/audio/audio_config/#complete-engine-setup","title":"Complete Engine Setup","text":"
#include \"core/Engine.h\"\n#include \"graphics/DisplayConfig.h\"\n#include \"input/InputConfig.h\"\n#include \"audio/AudioConfig.h\"\n\nvoid setup() {\n    // Display config\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    displayConfig.width = 128;\n    displayConfig.height = 128;\n\n    // Input config\n    pixelroot32::input::InputConfig inputConfig;\n    // ... configure input\n\n    // Audio config\n    #ifdef PLATFORM_ESP32\n        pixelroot32::drivers::esp32::ESP32_DAC_AudioBackend dacBackend;\n        pixelroot32::audio::AudioConfig audioConfig(&dacBackend, 11025);\n    #elif PLATFORM_NATIVE\n        pixelroot32::drivers::native::SDL2_AudioBackend sdlBackend;\n        pixelroot32::audio::AudioConfig audioConfig(&sdlBackend, 44100);\n    #endif\n\n    // Create engine with all configs\n    pixelroot32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/audio/audio_config/#platform-specific-considerations","title":"Platform-Specific Considerations","text":""},{"location":"api_reference/audio/audio_config/#esp32-dac-backend","title":"ESP32 DAC Backend","text":"
  • Sample rate: 11025 Hz recommended (lower CPU usage)
  • Quality: Lower quality, but simple setup
  • Pin: Uses GPIO 25 or 26
  • Hardware: Requires simple amplifier circuit
"},{"location":"api_reference/audio/audio_config/#esp32-i2s-backend","title":"ESP32 I2S Backend","text":"
  • Sample rate: 22050 Hz recommended
  • Quality: Higher quality than DAC
  • Pins: Requires I2S pins (BCLK, LRCK, DOUT)
  • Hardware: Requires external I2S DAC
"},{"location":"api_reference/audio/audio_config/#native-sdl2-backend","title":"Native SDL2 Backend","text":"
  • Sample rate: 44100 Hz typical
  • Quality: High quality
  • Setup: Requires SDL2 library installed
  • Platforms: Windows, Linux, macOS
"},{"location":"api_reference/audio/audio_config/#performance-considerations","title":"Performance Considerations","text":"
  • Sample rate: Lower rates use less CPU and memory
  • Backend choice: DAC is simpler but lower quality than I2S
  • Buffer size: Configured in backend, affects latency vs stability
"},{"location":"api_reference/audio/audio_config/#see-also","title":"See Also","text":"
  • AudioEngine - Audio playback engine
  • Manual - Audio
  • Manual - Platforms and Drivers
  • API Overview
"},{"location":"api_reference/audio/audio_engine/","title":"AudioEngine","text":"

Core class for the NES-like audio subsystem.

"},{"location":"api_reference/audio/audio_engine/#description","title":"Description","text":"

AudioEngine manages the audio channels (Pulse, Triangle, Noise), mixes their output, and provides the audio stream to the backend. It implements a NES-like audio system with 4 fixed channels: 2 Pulse channels, 1 Triangle channel, and 1 Noise channel.

The engine is event-driven: you trigger sound effects via playEvent(), and the engine automatically manages channel allocation and playback.

"},{"location":"api_reference/audio/audio_engine/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    class AudioEngine {\n        // ...\n    };\n}\n
"},{"location":"api_reference/audio/audio_engine/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages audio engine instance)
"},{"location":"api_reference/audio/audio_engine/#constructors","title":"Constructors","text":""},{"location":"api_reference/audio/audio_engine/#audioengineconst-audioconfig-config","title":"AudioEngine(const AudioConfig& config)","text":"

Constructs the AudioEngine with the given configuration.

Parameters: - config (const AudioConfig&): Configuration struct containing the backend and parameters (sample rate, etc.)

Example:

#include \"audio/AudioEngine.h\"\n#include \"audio/AudioConfig.h\"\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = &audioBackend;  // Platform-specific backend\naudioConfig.sampleRate = 22050;       // 22.05 kHz for retro feel\n\npixelroot32::audio::AudioEngine audioEngine(audioConfig);\naudioEngine.init();\n

"},{"location":"api_reference/audio/audio_engine/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/audio/audio_engine/#void-init","title":"void init()","text":"

Initializes the audio subsystem and the backend.

Returns: - void

Notes: - Must be called after construction and before use - Initializes the platform-specific audio backend - Safe to call multiple times (idempotent) - Typically called automatically by Engine::init()

Example:

AudioEngine audioEngine(audioConfig);\naudioEngine.init();  // Initialize before use\n

"},{"location":"api_reference/audio/audio_engine/#void-updateunsigned-long-deltatime","title":"void update(unsigned long deltaTime)","text":"

Updates the audio state based on game time.

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Returns: - void

Notes: - Should be called from the main game loop (typically via Engine::update()) - Updates channel lifetimes and durations - Automatically stops channels when their duration expires - Must be called every frame for proper audio timing

Example:

void update(unsigned long deltaTime) override {\n    // Update audio (called automatically by Engine)\n    engine.getAudioEngine().update(deltaTime);\n\n    // Your game logic...\n}\n

"},{"location":"api_reference/audio/audio_engine/#void-generatesamplesint16_t-stream-int-length","title":"void generateSamples(int16_t* stream, int length)","text":"

Fills the provided buffer with mixed audio samples.

Parameters: - stream (int16_t*): Pointer to the buffer to fill - length (int): Number of samples to generate

Returns: - void

Notes: - This method is typically called by the AudioBackend from an audio callback or task - Not usually called directly by game code - Generates 16-bit signed integer PCM samples - Mixes all active channels into a mono stream

Advanced Usage:

// Typically not called directly, but if implementing custom backend:\nint16_t buffer[512];\naudioEngine.generateSamples(buffer, 512);\n

"},{"location":"api_reference/audio/audio_engine/#void-playeventconst-audioevent-event","title":"void playEvent(const AudioEvent& event)","text":"

Triggers a one-shot sound effect.

Parameters: - event (const AudioEvent&): The audio event to play

Returns: - void

Notes: - Automatically finds an available channel of the correct type - If no channel is available, the event may be dropped (no error) - Events are fire-and-forget (no need to track playback) - Use for sound effects, not background music

Example:

// Play a jump sound\npixelroot32::audio::AudioEvent jumpSound{};\njumpSound.type = pixelroot32::audio::WaveType::PULSE;\njumpSound.frequency = 800.0f;\njumpSound.duration = 0.1f;\njumpSound.volume = 0.7f;\njumpSound.duty = 0.5f;\n\nauto& audio = engine.getAudioEngine();\naudio.playEvent(jumpSound);\n\n// Play an explosion sound\npixelroot32::audio::AudioEvent explosion{};\nexplosion.type = pixelroot32::audio::WaveType::NOISE;\nexplosion.frequency = 1000.0f;\nexplosion.duration = 0.3f;\nexplosion.volume = 0.9f;\n\naudio.playEvent(explosion);\n

"},{"location":"api_reference/audio/audio_engine/#void-setmastervolumefloat-volume","title":"void setMasterVolume(float volume)","text":"

Sets the master volume for all audio output.

Parameters: - volume (float): Volume level (0.0 = silent, 1.0 = full volume)

Returns: - void

Notes: - Affects all channels and events - Clamped to [0.0, 1.0] range - Use for volume control menus or mute functionality

Example:

auto& audio = engine.getAudioEngine();\naudio.setMasterVolume(0.5f);  // 50% volume\naudio.setMasterVolume(0.0f);  // Mute\naudio.setMasterVolume(1.0f);  // Full volume\n

"},{"location":"api_reference/audio/audio_engine/#float-getmastervolume-const","title":"float getMasterVolume() const","text":"

Gets the current master volume.

Returns: - float: Current master volume (0.0 to 1.0)

Example:

float currentVolume = audioEngine.getMasterVolume();\n

"},{"location":"api_reference/audio/audio_engine/#audio-channels","title":"Audio Channels","text":"

The engine manages 4 fixed channels:

  1. Channel 0: Pulse wave
  2. Channel 1: Pulse wave
  3. Channel 2: Triangle wave
  4. Channel 3: Noise wave

Notes: - Channels are automatically allocated when playing events - If all channels of a type are busy, new events may be dropped - Background music typically uses one channel (via MusicPlayer)

"},{"location":"api_reference/audio/audio_engine/#usage-example","title":"Usage Example","text":"
#include \"audio/AudioEngine.h\"\n#include \"audio/AudioConfig.h\"\n\nclass MyScene : public pixelroot32::core::Scene {\nprivate:\n    void playJumpSound() {\n        auto& audio = engine.getAudioEngine();\n\n        pixelroot32::audio::AudioEvent sound{};\n        sound.type = pixelroot32::audio::WaveType::PULSE;\n        sound.frequency = 800.0f;\n        sound.duration = 0.1f;\n        sound.volume = 0.7f;\n        sound.duty = 0.5f;\n\n        audio.playEvent(sound);\n    }\n\n    void playHitSound() {\n        auto& audio = engine.getAudioEngine();\n\n        pixelroot32::audio::AudioEvent sound{};\n        sound.type = pixelroot32::audio::WaveType::NOISE;\n        sound.frequency = 500.0f;\n        sound.duration = 0.05f;\n        sound.volume = 0.5f;\n\n        audio.playEvent(sound);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Audio is updated automatically by Engine\n        // Just play events when needed\n        if (playerJumped) {\n            playJumpSound();\n            playerJumped = false;\n        }\n    }\n};\n
"},{"location":"api_reference/audio/audio_engine/#performance-considerations","title":"Performance Considerations","text":"
  • Channel limit: Only 4 channels total; plan sound effects accordingly
  • Event dropping: If all channels are busy, new events are silently dropped
  • Update frequency: update() must be called every frame for proper timing
  • Sample generation: generateSamples() is called by backend at audio rate (not game rate)
"},{"location":"api_reference/audio/audio_engine/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Sample rate: Lower sample rates (11025 Hz) use less CPU and memory
  • Backend choice: DAC backend is simpler but lower quality than I2S
  • Buffer size: Larger buffers reduce underruns but increase latency
  • Channel management: Limit simultaneous sounds to avoid channel conflicts
"},{"location":"api_reference/audio/audio_engine/#see-also","title":"See Also","text":"
  • AudioConfig - Audio configuration
  • AudioTypes - Audio data structures
  • MusicPlayer - Background music playback
  • Manual - Audio
  • API Overview
"},{"location":"api_reference/audio/audio_types/","title":"Audio Types","text":"

Data structures and types for the audio system.

"},{"location":"api_reference/audio/audio_types/#description","title":"Description","text":"

This document describes the data structures used by the audio system, including wave types, audio events, and channel state.

"},{"location":"api_reference/audio/audio_types/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    // Types and structures\n}\n
"},{"location":"api_reference/audio/audio_types/#wavetype-enum","title":"WaveType Enum","text":"

Defines the types of waveforms available.

Values: - WaveType::PULSE: Pulse wave (square wave with variable duty cycle) - WaveType::TRIANGLE: Triangle wave (smooth, melodic) - WaveType::NOISE: Noise wave (random, percussive)

Example:

pixelroot32::audio::WaveType wave = pixelroot32::audio::WaveType::PULSE;\n

"},{"location":"api_reference/audio/audio_types/#audioevent-structure","title":"AudioEvent Structure","text":"

A fire-and-forget sound event triggered by the game.

Members: - WaveType type: Type of waveform to use - float frequency: Frequency in Hz - float duration: Duration in seconds - float volume: Volume level (0.0 to 1.0) - float duty: Duty cycle for pulse wave (0.0 to 1.0, pulse only)

Example:

pixelroot32::audio::AudioEvent jumpSound{};\njumpSound.type = pixelroot32::audio::WaveType::PULSE;\njumpSound.frequency = 800.0f;\njumpSound.duration = 0.1f;\njumpSound.volume = 0.7f;\njumpSound.duty = 0.5f;\n\nauto& audio = engine.getAudioEngine();\naudio.playEvent(jumpSound);\n

"},{"location":"api_reference/audio/audio_types/#common-sound-effects","title":"Common Sound Effects","text":"

Jump Sound:

pixelroot32::audio::AudioEvent jump{};\njump.type = pixelroot32::audio::WaveType::PULSE;\njump.frequency = 800.0f;\njump.duration = 0.1f;\njump.volume = 0.7f;\njump.duty = 0.5f;\n

Hit Sound:

pixelroot32::audio::AudioEvent hit{};\nhit.type = pixelroot32::audio::WaveType::NOISE;\nhit.frequency = 500.0f;\nhit.duration = 0.05f;\nhit.volume = 0.5f;\n

Collect Sound:

pixelroot32::audio::AudioEvent collect{};\ncollect.type = pixelroot32::audio::WaveType::TRIANGLE;\ncollect.frequency = 1000.0f;\ncollect.duration = 0.15f;\ncollect.volume = 0.6f;\n

Explosion:

pixelroot32::audio::AudioEvent explosion{};\nexplosion.type = pixelroot32::audio::WaveType::NOISE;\nexplosion.frequency = 200.0f;\nexplosion.duration = 0.3f;\nexplosion.volume = 0.9f;\n

"},{"location":"api_reference/audio/audio_types/#audiochannel-structure","title":"AudioChannel Structure","text":"

Represents the internal state of a single audio channel.

Members: - bool enabled: Whether the channel is active - WaveType type: Type of waveform - float frequency: Current frequency in Hz - float phase: Current phase (0.0 to 1.0) - float phaseIncrement: Pre-calculated phase increment - float volume: Current volume (0.0 to 1.0) - float targetVolume: Target volume for envelopes - float dutyCycle: Duty cycle for pulse wave (0.0 to 1.0) - uint16_t noiseRegister: LFSR state for noise generation - unsigned long durationMs: Total duration in milliseconds - unsigned long remainingMs: Remaining duration in milliseconds

Methods: - void reset(): Resets the channel to inactive state

Notes: - Internal structure, typically not accessed directly - Managed automatically by AudioEngine - 4 channels total: 2 Pulse, 1 Triangle, 1 Noise

"},{"location":"api_reference/audio/audio_types/#frequency-reference","title":"Frequency Reference","text":"

Common frequencies for musical notes (A4 = 440 Hz):

  • C4: 261.63 Hz
  • D4: 293.66 Hz
  • E4: 329.63 Hz
  • F4: 349.23 Hz
  • G4: 392.00 Hz
  • A4: 440.00 Hz
  • B4: 493.88 Hz
  • C5: 523.25 Hz

Example:

// Play a C note\npixelroot32::audio::AudioEvent note{};\nnote.type = pixelroot32::audio::WaveType::PULSE;\nnote.frequency = 261.63f;  // C4\nnote.duration = 0.5f;\nnote.volume = 0.8f;\nnote.duty = 0.5f;\n

"},{"location":"api_reference/audio/audio_types/#duty-cycle-pulse-wave","title":"Duty Cycle (Pulse Wave)","text":"

Duty cycle controls the shape of the pulse wave:

  • 0.125 (12.5%): Thin pulse (NES-like)
  • 0.25 (25%): Narrow pulse
  • 0.5 (50%): Square wave (most common)
  • 0.75 (75%): Wide pulse

Example:

// Thin pulse (NES style)\nevent.duty = 0.125f;\n\n// Square wave (standard)\nevent.duty = 0.5f;\n

"},{"location":"api_reference/audio/audio_types/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/audio/audio_types/#creating-sound-effect-library","title":"Creating Sound Effect Library","text":"
namespace SoundEffects {\n    // Jump sound\n    inline pixelroot32::audio::AudioEvent jump() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 800.0f;\n        evt.duration = 0.1f;\n        evt.volume = 0.7f;\n        evt.duty = 0.5f;\n        return evt;\n    }\n\n    // Hit sound\n    inline pixelroot32::audio::AudioEvent hit() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::NOISE;\n        evt.frequency = 500.0f;\n        evt.duration = 0.05f;\n        evt.volume = 0.5f;\n        return evt;\n    }\n\n    // Collect sound\n    inline pixelroot32::audio::AudioEvent collect() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::TRIANGLE;\n        evt.frequency = 1000.0f;\n        evt.duration = 0.15f;\n        evt.volume = 0.6f;\n        return evt;\n    }\n}\n\n// Usage\nauto& audio = engine.getAudioEngine();\naudio.playEvent(SoundEffects::jump());\naudio.playEvent(SoundEffects::hit());\n
"},{"location":"api_reference/audio/audio_types/#frequency-sweep-effect","title":"Frequency Sweep Effect","text":"
void playSweepSound() {\n    auto& audio = engine.getAudioEngine();\n\n    // Create multiple events for sweep effect\n    for (int i = 0; i < 5; i++) {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 400.0f + (i * 200.0f);  // Sweep from 400 to 1200 Hz\n        evt.duration = 0.05f;\n        evt.volume = 0.6f;\n        evt.duty = 0.5f;\n\n        audio.playEvent(evt);\n        delay(50);  // Small delay between events\n    }\n}\n
"},{"location":"api_reference/audio/audio_types/#performance-considerations","title":"Performance Considerations","text":"
  • Event creation: Creating events is fast (just struct initialization)
  • Channel allocation: Events are queued and played when channels are available
  • Frequency range: Keep frequencies in reasonable range (100-5000 Hz) for best results
  • Duration: Shorter durations free channels faster
"},{"location":"api_reference/audio/audio_types/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Events are small structs, safe to create frequently
  • CPU: Audio generation is efficient but limit simultaneous sounds
  • Quality: Lower sample rates reduce CPU usage
"},{"location":"api_reference/audio/audio_types/#see-also","title":"See Also","text":"
  • AudioEngine - Audio playback engine
  • AudioConfig - Audio configuration
  • Manual - Audio
  • API Overview
"},{"location":"api_reference/audio/music_player/","title":"MusicPlayer","text":"

Lightweight sequencer built on top of AudioEngine to play background melodies as tracks.

"},{"location":"api_reference/audio/music_player/#description","title":"Description","text":"

MusicPlayer is a simple sequencer that plays MusicTrack structures. It advances notes based on game time, converts MusicNote entries to AudioEvent calls, and manages playback state (play, stop, pause, resume).

The player uses one audio channel (typically a Pulse channel) for music, leaving other channels available for sound effects.

"},{"location":"api_reference/audio/music_player/#namespace","title":"Namespace","text":"
namespace pixelroot32::audio {\n    class MusicPlayer {\n        // ...\n    };\n}\n
"},{"location":"api_reference/audio/music_player/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages music player instance)
"},{"location":"api_reference/audio/music_player/#constructors","title":"Constructors","text":""},{"location":"api_reference/audio/music_player/#musicplayeraudioengine-engine","title":"MusicPlayer(AudioEngine& engine)","text":"

Constructs the MusicPlayer.

Parameters: - engine (AudioEngine&): Reference to the AudioEngine used to play sounds

Notes: - Typically created and managed by Engine - Access via engine.getMusicPlayer()

Example:

auto& audio = engine.getAudioEngine();\npixelroot32::audio::MusicPlayer musicPlayer(audio);\n

"},{"location":"api_reference/audio/music_player/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/audio/music_player/#void-playconst-musictrack-track","title":"void play(const MusicTrack& track)","text":"

Starts playing a track.

Parameters: - track (const MusicTrack&): The track to play

Returns: - void

Notes: - Stops any currently playing track - Starts from the beginning of the track - If track has loop = true, will loop automatically - Uses one audio channel (typically Pulse)

Example:

static const MusicNote MELODY[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),\n};\n\nstatic const MusicTrack GAME_MUSIC = {\n    MELODY,\n    sizeof(MELODY) / sizeof(MusicNote),\n    true,  // loop\n    WaveType::PULSE,\n    0.5f   // volume\n};\n\nvoid init() override {\n    auto& music = engine.getMusicPlayer();\n    music.play(GAME_MUSIC);\n}\n

"},{"location":"api_reference/audio/music_player/#void-stop","title":"void stop()","text":"

Stops playback and silences the channel.

Returns: - void

Notes: - Immediately stops the current note - Resets playback to the beginning - Channel is freed for other use

Example:

void onGameOver() {\n    auto& music = engine.getMusicPlayer();\n    music.stop();\n}\n

"},{"location":"api_reference/audio/music_player/#void-pause","title":"void pause()","text":"

Pauses playback.

Returns: - void

Notes: - Current note continues until it ends, then playback pauses - Playback state is preserved (can resume from where it paused) - Use for pause menus

Example:

void onPause() {\n    auto& music = engine.getMusicPlayer();\n    music.pause();\n}\n

"},{"location":"api_reference/audio/music_player/#void-resume","title":"void resume()","text":"

Resumes playback.

Returns: - void

Notes: - Only works if playback was paused - Resumes from where it was paused - Use to unpause after pause menu

Example:

void onResume() {\n    auto& music = engine.getMusicPlayer();\n    music.resume();\n}\n

"},{"location":"api_reference/audio/music_player/#void-updateunsigned-long-deltatime","title":"void update(unsigned long deltaTime)","text":"

Updates the player state. Should be called every frame.

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Returns: - void

Notes: - Must be called every frame for proper timing - Advances note playback based on elapsed time - Automatically plays next notes in sequence - Typically called automatically by Engine

Example:

// Called automatically by Engine, but can be called manually:\nvoid update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);\n\n    // Music player is updated automatically by Engine\n    // No need to call manually\n}\n

"},{"location":"api_reference/audio/music_player/#bool-isplaying-const","title":"bool isPlaying() const","text":"

Checks if a track is currently playing.

Returns: - bool: true if playing, false otherwise

Notes: - Returns false if stopped or paused - Use to check playback state before operations

Example:

auto& music = engine.getMusicPlayer();\nif (music.isPlaying()) {\n    // Music is active\n} else {\n    // Music is stopped or paused\n}\n

"},{"location":"api_reference/audio/music_player/#void-settempofactorfloat-factor","title":"void setTempoFactor(float factor)","text":"

Sets the global tempo scaling factor.

Parameters: - factor (float): Tempo multiplier - 1.0f: Normal speed - 2.0f: Double speed - 0.5f: Half speed

Returns: - void

Notes: - Affects all note durations - Useful for speed-up effects or slow-motion - Applied to all tracks

Example:

auto& music = engine.getMusicPlayer();\nmusic.setTempoFactor(1.5f);  // 50% faster\nmusic.setTempoFactor(0.5f);   // 50% slower\nmusic.setTempoFactor(1.0f);   // Normal speed\n

"},{"location":"api_reference/audio/music_player/#float-gettempofactor-const","title":"float getTempoFactor() const","text":"

Gets the current tempo scaling factor.

Returns: - float: Current factor (default 1.0f)

Example:

float currentTempo = musicPlayer.getTempoFactor();\n

"},{"location":"api_reference/audio/music_player/#musictrack-structure","title":"MusicTrack Structure","text":"

A MusicTrack contains:

  • notes (const MusicNote*): Array of music notes
  • noteCount (size_t): Number of notes in the array
  • loop (bool): Whether to loop the track
  • waveType (WaveType): Wave type to use (typically PULSE)
  • volume (float): Volume level (0.0 to 1.0)
"},{"location":"api_reference/audio/music_player/#musicnote-structure","title":"MusicNote Structure","text":"

A MusicNote contains:

  • instrument (InstrumentPreset): Instrument preset to use
  • note (Note): Musical note (C, D, E, etc.)
  • duration (float): Duration in seconds

Use helper functions: - makeNote(instrument, note, duration): Create a note - makeRest(duration): Create a rest (silence)

"},{"location":"api_reference/audio/music_player/#usage-example","title":"Usage Example","text":"
#include \"audio/MusicPlayer.h\"\n#include \"audio/AudioMusicTypes.h\"\n\nusing namespace pixelroot32::audio;\n\n// Define a simple melody\nstatic const MusicNote MAIN_THEME[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.25f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.25f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.1f),\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.5f),\n    makeRest(0.2f),\n};\n\nstatic const MusicTrack MAIN_THEME_TRACK = {\n    MAIN_THEME,\n    sizeof(MAIN_THEME) / sizeof(MusicNote),\n    true,           // loop\n    WaveType::PULSE,\n    0.6f            // volume\n};\n\nclass GameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Start background music\n        auto& music = engine.getMusicPlayer();\n        music.play(MAIN_THEME_TRACK);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Music updates automatically\n    }\n\n    void onPauseMenu() {\n        auto& music = engine.getMusicPlayer();\n        music.pause();\n    }\n\n    void onResumeGame() {\n        auto& music = engine.getMusicPlayer();\n        music.resume();\n    }\n\n    void onGameOver() {\n        auto& music = engine.getMusicPlayer();\n        music.stop();\n    }\n};\n
"},{"location":"api_reference/audio/music_player/#performance-considerations","title":"Performance Considerations","text":"
  • One channel: Music uses one channel, leaving others for sound effects
  • Update frequency: update() must be called every frame
  • Track size: Larger tracks use more memory (store in flash)
  • Tempo factor: Changing tempo is fast (just a multiplier)
"},{"location":"api_reference/audio/music_player/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store tracks in flash (const/constexpr) to save RAM
  • CPU: Music playback is lightweight (simple sequencing)
  • Channel conflict: Music and sound effects share channels; plan accordingly
"},{"location":"api_reference/audio/music_player/#see-also","title":"See Also","text":"
  • AudioEngine - Audio playback engine
  • AudioTypes - Audio data structures
  • AudioMusicTypes - Music data structures
  • Manual - Audio
  • API Overview
"},{"location":"api_reference/core/actor/","title":"Actor","text":"

An Entity capable of physical interaction and collision.

"},{"location":"api_reference/core/actor/#description","title":"Description","text":"

Actor extends Entity with collision layers and masks. Actors are used for dynamic game objects like players, enemies, projectiles, and obstacles that need to interact with each other through collision detection.

Actors participate in the collision system and can detect collisions with other actors based on their collision layers and masks.

"},{"location":"api_reference/core/actor/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Actor : public Entity {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/actor/#inheritance","title":"Inheritance","text":"
  • Inherits from: Entity
  • Inherited by: PhysicsActor and your custom actor classes
"},{"location":"api_reference/core/actor/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/actor/#actorfloat-x-float-y-int-w-int-h","title":"Actor(float x, float y, int w, int h)","text":"

Creates a new actor with specified position and size.

Parameters: - x (float): Initial X position in world space - y (float): Initial Y position in world space - w (int): Actor width in pixels - h (int): Actor height in pixels

Notes: - Actor type is automatically set to EntityType::ACTOR - Collision layer and mask default to DefaultLayers::kNone - Must set collision layer and mask for collision detection to work

Example:

class PlayerActor : public pixelroot32::core::Actor {\npublic:\n    PlayerActor(float x, float y) \n        : Actor(x, y, 16, 16) {\n        // Set collision layer and mask\n        layer = pixelroot32::physics::DefaultLayers::kPlayer;\n        mask = pixelroot32::physics::DefaultLayers::kEnemy | \n               pixelroot32::physics::DefaultLayers::kObstacle;\n    }\n\n    void update(unsigned long deltaTime) override {\n        Actor::update(deltaTime);\n        // Player logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawSprite(playerSprite, \n                           static_cast<int>(x), \n                           static_cast<int>(y), \n                           Color::White);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        // Handle collision\n    }\n};\n

"},{"location":"api_reference/core/actor/#public-properties","title":"Public Properties","text":""},{"location":"api_reference/core/actor/#collisionlayer-layer","title":"CollisionLayer layer","text":"

The collision layer this actor belongs to.

Type: pixelroot32::physics::CollisionLayer (uint16_t)

Access: Read-write

Default: DefaultLayers::kNone

Notes: - Defines which layer this actor is on - Use bit flags to assign multiple layers (e.g., kPlayer | kProjectile) - Only actors with matching layers in their mask will collide

Example:

actor->layer = pixelroot32::physics::DefaultLayers::kPlayer;\n

"},{"location":"api_reference/core/actor/#collisionlayer-mask","title":"CollisionLayer mask","text":"

The collision layers this actor interacts with.

Type: pixelroot32::physics::CollisionLayer (uint16_t)

Access: Read-write

Default: DefaultLayers::kNone

Notes: - Defines which layers this actor can collide with - Use bit flags to check multiple layers (e.g., kEnemy | kObstacle) - Collision only occurs if the other actor's layer matches bits in this mask

Example:

// Actor collides with enemies and obstacles\nactor->mask = pixelroot32::physics::DefaultLayers::kEnemy | \n              pixelroot32::physics::DefaultLayers::kObstacle;\n

"},{"location":"api_reference/core/actor/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/actor/#void-setcollisionlayercollisionlayer-l","title":"void setCollisionLayer(CollisionLayer l)","text":"

Sets the collision layer for this actor.

Parameters: - l (pixelroot32::physics::CollisionLayer): The layer to set

Returns: - void

Notes: - Equivalent to setting layer directly - Use bit flags for multiple layers

Example:

actor->setCollisionLayer(pixelroot32::physics::DefaultLayers::kPlayer);\n

"},{"location":"api_reference/core/actor/#void-setcollisionmaskcollisionlayer-m","title":"void setCollisionMask(CollisionLayer m)","text":"

Sets the collision mask for this actor.

Parameters: - m (pixelroot32::physics::CollisionLayer): The mask to set

Returns: - void

Notes: - Equivalent to setting mask directly - Use bit flags for multiple layers

Example:

actor->setCollisionMask(pixelroot32::physics::DefaultLayers::kEnemy | \n                        pixelroot32::physics::DefaultLayers::kObstacle);\n

"},{"location":"api_reference/core/actor/#bool-isinlayeruint16_t-targetlayer-const","title":"bool isInLayer(uint16_t targetLayer) const","text":"

Checks if the Actor belongs to a specific collision layer.

Parameters: - targetLayer (uint16_t): The bit(s) to check (e.g., DefaultLayers::kPlayer)

Returns: - bool: true if the bit is set in the actor's layer

Notes: - Uses bitwise AND operation - Useful for checking if an actor is on a specific layer

Example:

if (actor->isInLayer(pixelroot32::physics::DefaultLayers::kPlayer)) {\n    // This is a player actor\n}\n

"},{"location":"api_reference/core/actor/#virtual-rect-gethitbox-0","title":"virtual Rect getHitBox() = 0","text":"

Gets the hitbox for collision detection. Must be implemented by derived classes.

Returns: - Rect: A rectangle representing the collision bounds

Notes: - Called by the collision system to check collisions - Should return the actual collision bounds (may differ from visual size) - Use AABB (Axis-Aligned Bounding Box) for efficiency

Example:

Rect getHitBox() override {\n    // Return collision bounds (may be smaller than visual)\n    return {x + 2, y + 2, width - 4, height - 4};\n}\n

"},{"location":"api_reference/core/actor/#virtual-void-oncollisionactor-other-0","title":"virtual void onCollision(Actor* other) = 0","text":"

Callback invoked when a collision occurs. Must be implemented by derived classes.

Parameters: - other (Actor*): The actor that this actor collided with

Notes: - Called automatically by the collision system when a collision is detected - Both actors' onCollision() methods are called - Use to handle collision responses (damage, bouncing, etc.)

Example:

void onCollision(Actor* other) override {\n    // Check what we collided with\n    if (other->isInLayer(pixelroot32::physics::DefaultLayers::kEnemy)) {\n        // Take damage\n        health--;\n        if (health <= 0) {\n            isEnabled = false;\n        }\n    } else if (other->isInLayer(pixelroot32::physics::DefaultLayers::kCollectible)) {\n        // Collect item\n        score += 10;\n        other->isEnabled = false;  // Remove collectible\n    }\n}\n

"},{"location":"api_reference/core/actor/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the actor logic. Default implementation does nothing.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Override to implement actor-specific update logic - Called automatically by Scene if isEnabled is true - Use deltaTime for frame-rate independent movement

Example:

void update(unsigned long deltaTime) override {\n    Actor::update(deltaTime);  // Call base implementation\n\n    // Move actor\n    float speed = 100.0f;  // pixels per second\n    x += (speed * deltaTime) / 1000.0f;\n}\n

"},{"location":"api_reference/core/actor/#collision-layers","title":"Collision Layers","text":"

Collision layers use bit flags to organize actors into groups. Common layers:

  • DefaultLayers::kNone (0): No layer
  • DefaultLayers::kPlayer (1 << 0): Player actors
  • DefaultLayers::kEnemy (1 << 1): Enemy actors
  • DefaultLayers::kObstacle (1 << 2): Obstacles/walls
  • DefaultLayers::kProjectile (1 << 3): Projectiles
  • DefaultLayers::kCollectible (1 << 4): Collectible items

Example:

// Player collides with enemies and obstacles\nplayer->layer = DefaultLayers::kPlayer;\nplayer->mask = DefaultLayers::kEnemy | DefaultLayers::kObstacle;\n\n// Enemy collides with player and obstacles\nenemy->layer = DefaultLayers::kEnemy;\nenemy->mask = DefaultLayers::kPlayer | DefaultLayers::kObstacle;\n\n// Projectile collides with enemies\nprojectile->layer = DefaultLayers::kProjectile;\nprojectile->mask = DefaultLayers::kEnemy;\n

"},{"location":"api_reference/core/actor/#usage-example","title":"Usage Example","text":"
#include \"core/Actor.h\"\n#include \"physics/CollisionTypes.h\"\n\nclass EnemyActor : public pixelroot32::core::Actor {\nprivate:\n    const pixelroot32::graphics::Sprite* sprite;\n    int health = 3;\n\npublic:\n    EnemyActor(float x, float y) \n        : Actor(x, y, 16, 16),\n          sprite(&enemySprite) {\n        // Set collision layer and mask\n        layer = pixelroot32::physics::DefaultLayers::kEnemy;\n        mask = pixelroot32::physics::DefaultLayers::kPlayer | \n               pixelroot32::physics::DefaultLayers::kProjectile;\n    }\n\n    void update(unsigned long deltaTime) override {\n        Actor::update(deltaTime);\n\n        // Move towards player\n        float speed = 50.0f;\n        // ... movement logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawSprite(*sprite, \n                           static_cast<int>(x), \n                           static_cast<int>(y), \n                           Color::Red);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        if (other->isInLayer(pixelroot32::physics::DefaultLayers::kProjectile)) {\n            // Hit by projectile\n            health--;\n            if (health <= 0) {\n                isEnabled = false;  // Remove enemy\n            }\n        }\n    }\n};\n
"},{"location":"api_reference/core/actor/#performance-considerations","title":"Performance Considerations","text":"
  • Collision layers: Use layers efficiently to reduce collision checks
  • Hitbox size: Keep hitboxes simple (AABB) for best performance
  • Collision callbacks: Keep onCollision() fast; avoid expensive operations
  • Layer organization: Group actors by layer to minimize checks
"},{"location":"api_reference/core/actor/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Collision checks: Collision system automatically optimizes using layers
  • Memory: Each actor consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse actors instead of creating/destroying frequently
"},{"location":"api_reference/core/actor/#see-also","title":"See Also","text":"
  • Entity - Base entity class
  • PhysicsActor - Entity with physics
  • CollisionSystem - Collision detection
  • CollisionTypes - Collision layer definitions
  • Manual - Scenes and Entities
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/core/engine/","title":"Engine","text":"

The main engine class that manages the game loop and core subsystems.

"},{"location":"api_reference/core/engine/#description","title":"Description","text":"

Engine acts as the central hub of the PixelRoot32 game engine. It initializes and manages the Renderer, InputManager, AudioEngine, and SceneManager. It runs the main game loop, handling timing (delta time), updating the current scene, and rendering frames.

The engine provides a unified interface for both ESP32 and Native (SDL2) platforms, abstracting platform-specific details while maintaining consistent behavior.

"},{"location":"api_reference/core/engine/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Engine {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/engine/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Application entry point (main.cpp)
"},{"location":"api_reference/core/engine/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/engine/#engineconst-displayconfig-displayconfig-const-inputconfig-inputconfig-const-audioconfig-audioconfig","title":"Engine(const DisplayConfig& displayConfig, const InputConfig& inputConfig, const AudioConfig& audioConfig)","text":"

Creates a new engine instance with custom display, input, and audio configurations.

Parameters: - displayConfig (const pixelroot32::graphics::DisplayConfig&): Configuration settings for the display (width, height, rotation, etc.) - inputConfig (const pixelroot32::input::InputConfig&): Configuration settings for the input system (pins, buttons) - audioConfig (const pixelroot32::audio::AudioConfig&): Configuration settings for the audio system (backend, sample rate, buffer size)

Example:

#include \"core/Engine.h\"\n#include \"graphics/DisplayConfig.h\"\n#include \"input/InputConfig.h\"\n#include \"audio/AudioConfig.h\"\n\npixelroot32::graphics::DisplayConfig displayConfig;\ndisplayConfig.logicalWidth = 128;\ndisplayConfig.logicalHeight = 128;\n\npixelroot32::input::InputConfig inputConfig;\n// Configure input pins...\n\npixelroot32::audio::AudioConfig audioConfig;\naudioConfig.backend = pixelroot32::audio::AudioConfig::Backend::ESP32_DAC;\naudioConfig.sampleRate = 11025;\n\npixelroot32::core::Engine engine(displayConfig, inputConfig, audioConfig);\nengine.init();\nengine.run();\n

"},{"location":"api_reference/core/engine/#engineconst-displayconfig-displayconfig-const-inputconfig-inputconfig","title":"Engine(const DisplayConfig& displayConfig, const InputConfig& inputConfig)","text":"

Creates a new engine instance with custom display and input configurations, using default audio settings.

Parameters: - displayConfig (const pixelroot32::graphics::DisplayConfig&): Configuration settings for the display - inputConfig (const pixelroot32::input::InputConfig&): Configuration settings for the input system

Example:

pixelroot32::core::Engine engine(displayConfig, inputConfig);\nengine.init();\nengine.run();\n

"},{"location":"api_reference/core/engine/#engineconst-displayconfig-displayconfig","title":"Engine(const DisplayConfig& displayConfig)","text":"

Creates a new engine instance with custom display configuration and default input/audio settings.

Parameters: - displayConfig (const pixelroot32::graphics::DisplayConfig&): Configuration settings for the display

Example:

pixelroot32::core::Engine engine(displayConfig);\nengine.init();\nengine.run();\n

"},{"location":"api_reference/core/engine/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/engine/#void-init","title":"void init()","text":"

Initializes the engine subsystems. This method must be called before run().

Returns: - void

Notes: - Initializes the Renderer, InputManager, and sets up the initial state - Must be called after construction and before run() - Safe to call multiple times (idempotent)

Example:

Engine engine(displayConfig);\nengine.init();  // Initialize subsystems\nengine.setScene(myScene);\nengine.run();   // Start game loop\n

"},{"location":"api_reference/core/engine/#void-run","title":"void run()","text":"

Starts the main game loop. This method contains the infinite loop that calls update() and draw() repeatedly until the application exits.

Returns: - void

Notes: - This method blocks until the application exits - Handles frame timing and delta time calculation automatically - Calls update() and draw() once per frame - Do not call this method multiple times

Example:

Engine engine(displayConfig);\nengine.init();\nengine.setScene(myScene);\nengine.run();  // Blocks here, runs game loop\n

"},{"location":"api_reference/core/engine/#unsigned-long-getdeltatime-const","title":"unsigned long getDeltaTime() const","text":"

Gets the time elapsed since the last frame.

Returns: - unsigned long: The delta time in milliseconds

Performance Notes: - Very fast (inline accessor) - Safe to call every frame - Use this value to make movement frame-rate independent

Example:

void update(unsigned long deltaTime) override {\n    auto& engine = getEngine();\n    unsigned long dt = engine.getDeltaTime();\n\n    // Move at constant speed regardless of FPS\n    float speed = 100.0f;  // pixels per second\n    x += (speed * dt) / 1000.0f;\n}\n

"},{"location":"api_reference/core/engine/#void-setscenescene-newscene","title":"void setScene(Scene* newScene)","text":"

Sets the current active scene to be updated and rendered.

Parameters: - newScene (Scene*): Pointer to the new Scene to become active. Can be nullptr to clear the current scene.

Notes: - The previous scene is replaced (not pushed onto a stack) - Use SceneManager for push/pop operations if needed - The scene's init() method will be called automatically - Safe to call during the game loop

Example:

class MainMenuScene : public pixelroot32::core::Scene {\n    // ...\n};\n\nclass GameScene : public pixelroot32::core::Scene {\n    // ...\n};\n\nMainMenuScene menuScene;\nGameScene gameScene;\n\nEngine engine(displayConfig);\nengine.init();\nengine.setScene(&menuScene);  // Start with menu\nengine.run();\n

"},{"location":"api_reference/core/engine/#scene-getcurrentscene-const","title":"Scene* getCurrentScene() const","text":"

Retrieves the currently active scene.

Returns: - Scene*: Pointer to the current Scene, or nullptr if none is set

Example:

auto* currentScene = engine.getCurrentScene();\nif (currentScene) {\n    // Scene is active\n}\n

"},{"location":"api_reference/core/engine/#void-setrendererrenderer-newrenderer","title":"void setRenderer(Renderer& newRenderer)","text":"

Replaces the current renderer instance.

Parameters: - newRenderer (pixelroot32::graphics::Renderer&): Reference to the new Renderer to use

Notes: - Advanced usage: typically not needed unless implementing custom renderer - The renderer must be properly initialized before use - Use with caution: may break existing rendering code

"},{"location":"api_reference/core/engine/#renderer-getrenderer","title":"Renderer& getRenderer()","text":"

Provides access to the Renderer subsystem.

Returns: - pixelroot32::graphics::Renderer&: Reference to the current Renderer

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    auto& engineRenderer = engine.getRenderer();\n    engineRenderer.drawSprite(mySprite, 100, 100, Color::White);\n}\n

"},{"location":"api_reference/core/engine/#inputmanager-getinputmanager","title":"InputManager& getInputManager()","text":"

Provides access to the InputManager subsystem.

Returns: - pixelroot32::input::InputManager&: Reference to the InputManager

Example:

void update(unsigned long deltaTime) override {\n    auto& input = engine.getInputManager();\n    if (input.isButtonPressed(Buttons::A)) {\n        // Handle button press\n    }\n}\n

"},{"location":"api_reference/core/engine/#audioengine-getaudioengine","title":"AudioEngine& getAudioEngine()","text":"

Provides access to the AudioEngine subsystem.

Returns: - pixelroot32::audio::AudioEngine&: Reference to the AudioEngine

Example:

void playSound() {\n    auto& audio = engine.getAudioEngine();\n    pixelroot32::audio::AudioEvent sound{};\n    sound.type = pixelroot32::audio::WaveType::PULSE;\n    sound.frequency = 800.0f;\n    sound.duration = 0.1f;\n    audio.playEvent(sound);\n}\n

"},{"location":"api_reference/core/engine/#musicplayer-getmusicplayer","title":"MusicPlayer& getMusicPlayer()","text":"

Provides access to the MusicPlayer subsystem.

Returns: - pixelroot32::audio::MusicPlayer&: Reference to the MusicPlayer

Example:

void playMusic() {\n    auto& music = engine.getMusicPlayer();\n    music.playTrack(myMusicTrack);\n}\n

"},{"location":"api_reference/core/engine/#optional-debug-statistics-overlay","title":"Optional: Debug Statistics Overlay","text":"

When the engine is built with the preprocessor define PIXELROOT32_ENABLE_DEBUG_OVERLAY, an on-screen technical overlay is drawn each frame.

Metrics Included:

  • FPS: Frames per second (Green).
  • RAM: Used heap memory in KB (Cyan).
  • CPU: Estimated processor load percentage (Yellow).

Platform Differences & CPU Metric

The CPU Load metric is an estimation based on the processing time vs. a 60 FPS target (16.6ms).

  • On ESP32: This is a realistic representation of how much time the CPU is spending on engine logic within its power limits.
  • On Native (PC): This metric may frequently show 100% or high values even if your PC is idle. This happens because the native loop is synchronized with the monitor's VSYNC (via SDL2), which often causes the frame time to exceed 16.6ms (e.g., 33ms for 30 FPS). This is a result of the operating system's scheduling and SDL's synchronization, not actual hardware saturation.

Behavior:

  • The overlay is drawn in the top-right area of the screen.
  • It is rendered after the scene, making it fixed and independent of the camera.

Performance:

  • Metric values are recalculated and formatted only every 16 frames (DEBUG_UPDATE_INTERVAL).
  • Cached strings are drawn every frame to minimize per-frame cost (division and snprintf).

How to enable:

In platformio.ini, add to your environment's build_flags:

build_flags =\n    -D PIXELROOT32_ENABLE_DEBUG_OVERLAY\n

Alternatively, you can enable it in EngineConfig.h. The implementation uses the private method drawDebugOverlay(Renderer& r), which is only compiled when the define is set.

See also: Performance Tuning - Profiling and Platforms and Drivers - Build flags.

"},{"location":"api_reference/core/engine/#usage-example","title":"Usage Example","text":"
#include \"core/Engine.h\"\n#include \"graphics/DisplayConfig.h\"\n#include \"MyScene.h\"\n\nvoid setup() {\n    // Configure display\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    displayConfig.logicalWidth = 128;\n    displayConfig.logicalHeight = 128;\n    displayConfig.rotation = 0;\n\n    // Create engine\n    pixelroot32::core::Engine engine(displayConfig);\n\n    // Initialize\n    engine.init();\n\n    // Create and set scene\n    MyScene myScene;\n    engine.setScene(&myScene);\n\n    // Run game loop\n    engine.run();\n}\n
"},{"location":"api_reference/core/engine/#performance-considerations","title":"Performance Considerations","text":"
  • Initialization: init() should be called once at startup, not in the game loop
  • Scene switching: Switching scenes is fast but avoid doing it every frame
  • Subsystem access: Getters are inline and very fast; safe to call every frame
  • Delta time: Use getDeltaTime() for frame-rate independent movement
"},{"location":"api_reference/core/engine/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Ensure init() completes before run() to avoid initialization issues
  • Monitor memory usage when switching scenes frequently
  • Use getDeltaTime() for consistent gameplay across different frame rates
"},{"location":"api_reference/core/engine/#see-also","title":"See Also","text":"
  • Scene - Scene management
  • Renderer - Rendering system
  • InputManager - Input handling
  • AudioEngine - Audio system
  • Getting Started - Fundamental Concepts
  • Manual - Scenes and Entities
  • API Overview
"},{"location":"api_reference/core/entity/","title":"Entity","text":"

Abstract base class for all game objects.

"},{"location":"api_reference/core/entity/#description","title":"Description","text":"

Entity is the fundamental building block of the scene. Entities have a position, size, and lifecycle methods (update, draw). All game objects inherit from Entity, including actors, UI elements, and custom game objects.

Entities are managed by Scene and are automatically updated and drawn each frame when enabled and visible.

"},{"location":"api_reference/core/entity/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Entity {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/entity/#inheritance","title":"Inheritance","text":"
  • Base class: None (abstract base class)
  • Inherited by: Actor, UI elements, and your custom entity classes
"},{"location":"api_reference/core/entity/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/entity/#entityfloat-x-float-y-int-w-int-h-entitytype-t","title":"Entity(float x, float y, int w, int h, EntityType t)","text":"

Creates a new entity with specified position, size, and type.

Parameters: - x (float): Initial X position in world space - y (float): Initial Y position in world space - w (int): Width in pixels - h (int): Height in pixels - t (EntityType): The type of entity (GENERIC, ACTOR, UI_ELEMENT)

Example:

class MyEntity : public pixelroot32::core::Entity {\npublic:\n    MyEntity(float x, float y) \n        : Entity(x, y, 16, 16, EntityType::GENERIC) {}\n\n    void update(unsigned long deltaTime) override {\n        // Update logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw logic\n    }\n};\n

"},{"location":"api_reference/core/entity/#public-properties","title":"Public Properties","text":""},{"location":"api_reference/core/entity/#float-x-y","title":"float x, y","text":"

Position of the entity in world space.

Type: float

Access: Read-write

Notes: - Position is in world coordinates, not screen coordinates - Can be modified directly or through helper methods - Use for entity positioning and movement

Example:

entity->x = 100.0f;\nentity->y = 50.0f;\n

"},{"location":"api_reference/core/entity/#int-width-height","title":"int width, height","text":"

Dimensions of the entity in pixels.

Type: int

Access: Read-write

Notes: - Used for collision detection, rendering bounds, and layout - Should match the visual size of the entity - Can be modified at runtime if needed

Example:

entity->width = 32;\nentity->height = 32;\n

"},{"location":"api_reference/core/entity/#entitytype-type","title":"EntityType type","text":"

The specific type of this entity.

Type: EntityType enum

Access: Read-only (set in constructor)

Values: - EntityType::GENERIC: Generic entity - EntityType::ACTOR: Actor entity (with collision) - EntityType::UI_ELEMENT: UI element

Notes: - Used for type-safe casting and logic differentiation - Set once in constructor, typically not changed

"},{"location":"api_reference/core/entity/#bool-isvisible","title":"bool isVisible","text":"

If false, the entity's draw() method will not be called.

Type: bool

Access: Read-write

Default: true

Notes: - Use to hide entities without removing them from the scene - More efficient than removing and re-adding entities - Useful for object pooling

Example:

entity->isVisible = false;  // Hide entity\nentity->setVisible(true);   // Show entity\n

"},{"location":"api_reference/core/entity/#bool-isenabled","title":"bool isEnabled","text":"

If false, the entity's update() method will not be called.

Type: bool

Access: Read-write

Default: true

Notes: - Use to disable entity logic without removing it - Entity still exists but doesn't update - Useful for paused entities or object pooling

Example:

entity->isEnabled = false;  // Disable updates\nentity->setEnabled(true);   // Enable updates\n

"},{"location":"api_reference/core/entity/#unsigned-char-renderlayer","title":"unsigned char renderLayer","text":"

The render layer this entity is drawn on.

Type: unsigned char

Access: Read-write

Default: 1

Notes: - Layers are drawn in ascending order (0 = background, 1 = gameplay, 2 = UI) - Entities on the same layer are drawn in add order - Use to control draw order without changing entity order

Example:

entity->renderLayer = 0;  // Background layer\nentity->setRenderLayer(2); // UI layer\n

"},{"location":"api_reference/core/entity/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/entity/#virtual-void-setvisiblebool-v","title":"virtual void setVisible(bool v)","text":"

Sets the visibility of the entity.

Parameters: - v (bool): true to show, false to hide

Returns: - void

Notes: - Equivalent to setting isVisible directly - Can be overridden for custom visibility logic

Example:

entity->setVisible(false);  // Hide\nentity->setVisible(true);   // Show\n

"},{"location":"api_reference/core/entity/#virtual-void-setenabledbool-e","title":"virtual void setEnabled(bool e)","text":"

Sets the enabled state of the entity.

Parameters: - e (bool): true to enable, false to disable

Returns: - void

Notes: - Equivalent to setting isEnabled directly - Can be overridden for custom enable logic

Example:

entity->setEnabled(false);  // Disable updates\nentity->setEnabled(true);   // Enable updates\n

"},{"location":"api_reference/core/entity/#unsigned-char-getrenderlayer-const","title":"unsigned char getRenderLayer() const","text":"

Gets the current render layer.

Returns: - unsigned char: The render layer (0-255)

Example:

unsigned char layer = entity->getRenderLayer();\n

"},{"location":"api_reference/core/entity/#virtual-void-setrenderlayerunsigned-char-layer","title":"virtual void setRenderLayer(unsigned char layer)","text":"

Sets the render layer for this entity.

Parameters: - layer (unsigned char): The render layer (0 = background, 1 = gameplay, 2 = UI)

Returns: - void

Example:

entity->setRenderLayer(0);  // Background\n

"},{"location":"api_reference/core/entity/#virtual-void-updateunsigned-long-deltatime-0","title":"virtual void update(unsigned long deltaTime) = 0","text":"

Updates the entity's logic. Must be implemented by derived classes.

Parameters: - deltaTime (unsigned long): Time elapsed since the last frame in milliseconds

Returns: - void

Notes: - Called automatically by Scene every frame if isEnabled is true - Use deltaTime for frame-rate independent movement - Override to implement entity-specific update logic

Example:

void update(unsigned long deltaTime) override {\n    // Move entity\n    float speed = 50.0f;  // pixels per second\n    x += (speed * deltaTime) / 1000.0f;\n\n    // Wrap around screen\n    if (x > 128) {\n        x = 0;\n    }\n}\n

"},{"location":"api_reference/core/entity/#virtual-void-drawrenderer-renderer-0","title":"virtual void draw(Renderer& renderer) = 0","text":"

Renders the entity. Must be implemented by derived classes.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer to use for drawing

Returns: - void

Notes: - Called automatically by Scene every frame if isVisible is true - Entities are drawn in render layer order, then in add order - Override to implement entity-specific drawing logic

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Draw sprite at entity position\n    renderer.drawSprite(mySprite, static_cast<int>(x), static_cast<int>(y), Color::White);\n}\n

"},{"location":"api_reference/core/entity/#entitytype-enum","title":"EntityType Enum","text":"

Categorizes entities for type-safe casting and logic differentiation.

Values: - EntityType::GENERIC: Generic entity (default) - EntityType::ACTOR: Actor entity (with collision support) - EntityType::UI_ELEMENT: UI element

Example:

if (entity->type == EntityType::ACTOR) {\n    Actor* actor = static_cast<Actor*>(entity);\n    // Use actor-specific methods\n}\n

"},{"location":"api_reference/core/entity/#rect-structure","title":"Rect Structure","text":"

Represents a 2D rectangle, typically used for hitboxes or bounds.

Members: - float x, y: Top-left corner coordinates - int width, height: Dimensions of the rectangle

Methods: - bool intersects(const Rect& other): Checks if this rectangle intersects with another

Example:

pixelroot32::core::Rect rect1{10.0f, 20.0f, 50, 50};\npixelroot32::core::Rect rect2{30.0f, 40.0f, 50, 50};\n\nif (rect1.intersects(rect2)) {\n    // Rectangles overlap\n}\n

"},{"location":"api_reference/core/entity/#usage-example","title":"Usage Example","text":"
#include \"core/Entity.h\"\n\nclass Collectible : public pixelroot32::core::Entity {\nprivate:\n    const pixelroot32::graphics::Sprite* sprite;\n\npublic:\n    Collectible(float x, float y) \n        : Entity(x, y, 8, 8, EntityType::GENERIC),\n          sprite(&collectibleSprite) {}\n\n    void update(unsigned long deltaTime) override {\n        // Rotate or animate\n        rotation += deltaTime * 0.001f;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        if (isVisible) {\n            renderer.drawSprite(*sprite, \n                               static_cast<int>(x), \n                               static_cast<int>(y), \n                               Color::Yellow);\n        }\n    }\n\nprivate:\n    float rotation = 0.0f;\n};\n
"},{"location":"api_reference/core/entity/#performance-considerations","title":"Performance Considerations","text":"
  • Visibility: Use isVisible = false instead of removing entities when hiding
  • Enable state: Use isEnabled = false to pause entity logic
  • Render layers: Organize entities by layer to minimize layer switches
  • Direct access: Direct property access is fast (no function call overhead)
"},{"location":"api_reference/core/entity/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Each entity consumes memory; stay within MAX_ENTITIES limit
  • Object pooling: Reuse entities instead of creating/destroying frequently
  • Update frequency: Disable entities that don't need to update every frame
"},{"location":"api_reference/core/entity/#see-also","title":"See Also","text":"
  • Scene - Scene management
  • Actor - Entity with collision support
  • PhysicsActor - Entity with physics
  • Manual - Scenes and Entities
  • API Overview
"},{"location":"api_reference/core/input_config/","title":"InputConfig","text":"

Configuration structure for the InputManager.

"},{"location":"api_reference/core/input_config/#description","title":"Description","text":"

InputConfig defines the mapping between logical inputs and physical pins (ESP32) or keyboard keys (Native/SDL2). It uses variadic arguments to allow flexible configuration of any number of inputs.

The configuration is platform-specific: ESP32 uses GPIO pin numbers, while Native uses SDL keyboard scancodes.

"},{"location":"api_reference/core/input_config/#namespace","title":"Namespace","text":"
namespace pixelroot32::input {\n    struct InputConfig {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/input_config/#structure","title":"Structure","text":""},{"location":"api_reference/core/input_config/#int-count","title":"int count","text":"

Total number of configured inputs.

Type: int

Access: Read-write

Default: 0

Notes: - Must match the number of arguments provided to constructor - Determines the size of the internal button array

"},{"location":"api_reference/core/input_config/#int-inputpins-esp32-only","title":"int* inputPins (ESP32 only)","text":"

Array of GPIO pin numbers for ESP32.

Type: int*

Access: Read-write

Default: nullptr

Notes: - Only available on ESP32 platform - Array size equals count - Pin numbers correspond to ESP32 GPIO pins - Use nullptr if count is 0

Example:

// ESP32: 6 buttons on pins 0, 2, 4, 5, 18, 19\npixelroot32::input::InputConfig config(6, 0, 2, 4, 5, 18, 19);\n// config.inputPins[0] = 0  (Up)\n// config.inputPins[1] = 2  (Down)\n// config.inputPins[2] = 4  (Left)\n// config.inputPins[3] = 5  (Right)\n// config.inputPins[4] = 18 (Button A)\n// config.inputPins[5] = 19 (Button B)\n

"},{"location":"api_reference/core/input_config/#uint8_t-buttonnames-native-only","title":"uint8_t* buttonNames (Native only)","text":"

Array of button mappings (scancodes) for Native.

Type: uint8_t*

Access: Read-write

Default: nullptr

Notes: - Only available on Native platform - Array size equals count - Values are SDL keyboard scancodes - Use nullptr if count is 0

Example:

// Native: Map to keyboard keys\n#include <SDL2/SDL.h>\n\npixelroot32::input::InputConfig config(6,\n    SDL_SCANCODE_UP,    // Index 0\n    SDL_SCANCODE_DOWN,  // Index 1\n    SDL_SCANCODE_LEFT,  // Index 2\n    SDL_SCANCODE_RIGHT, // Index 3\n    SDL_SCANCODE_X,     // Index 4 (Button A)\n    SDL_SCANCODE_Z      // Index 5 (Button B)\n);\n

"},{"location":"api_reference/core/input_config/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/input_config/#inputconfigint-count","title":"InputConfig(int count, ...)","text":"

Constructs a new InputConfig with variadic arguments.

Parameters: - count (int): Number of inputs to configure - ... (variadic): Variable arguments list of pins (ESP32) or scancodes (Native)

Notes: - If count <= 0, configuration is empty (nullptr arrays) - Allocates arrays dynamically based on count - Arguments must match count in number - Platform-specific: ESP32 expects int (GPIO pins), Native expects int (SDL scancodes)

ESP32 Example:

// Configure 4 directional buttons\npixelroot32::input::InputConfig config(4, 0, 2, 4, 5);\n// Pin 0 = Up, Pin 2 = Down, Pin 4 = Left, Pin 5 = Right\n\n// Configure 6 buttons (4 directions + 2 action buttons)\npixelroot32::input::InputConfig config(6, 0, 2, 4, 5, 18, 19);\n

Native Example:

#include <SDL2/SDL.h>\n\n// Configure 4 directional buttons\npixelroot32::input::InputConfig config(4,\n    SDL_SCANCODE_UP,\n    SDL_SCANCODE_DOWN,\n    SDL_SCANCODE_LEFT,\n    SDL_SCANCODE_RIGHT\n);\n\n// Configure 6 buttons (4 directions + 2 action buttons)\npixelroot32::input::InputConfig config(6,\n    SDL_SCANCODE_UP,\n    SDL_SCANCODE_DOWN,\n    SDL_SCANCODE_LEFT,\n    SDL_SCANCODE_RIGHT,\n    SDL_SCANCODE_X,  // Button A\n    SDL_SCANCODE_Z   // Button B\n);\n

"},{"location":"api_reference/core/input_config/#usage-example","title":"Usage Example","text":""},{"location":"api_reference/core/input_config/#esp32-configuration","title":"ESP32 Configuration","text":"
#include \"input/InputConfig.h\"\n#include \"input/InputManager.h\"\n#include \"core/Engine.h\"\n\nvoid setup() {\n    // Configure input: 6 buttons\n    // Pins: Up=0, Down=2, Left=4, Right=5, A=18, B=19\n    pixelroot32::input::InputConfig inputConfig(6, 0, 2, 4, 5, 18, 19);\n\n    // Create input manager\n    pixelroot32::input::InputManager inputManager(inputConfig);\n    inputManager.init();\n\n    // Or use with Engine\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    pixelroot32::core::Engine engine(displayConfig, inputConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/core/input_config/#native-configuration","title":"Native Configuration","text":"
#include \"input/InputConfig.h\"\n#include <SDL2/SDL.h>\n\nvoid setup() {\n    // Configure input: 6 buttons mapped to keyboard\n    pixelroot32::input::InputConfig inputConfig(6,\n        SDL_SCANCODE_UP,    // Index 0: Up\n        SDL_SCANCODE_DOWN,  // Index 1: Down\n        SDL_SCANCODE_LEFT,  // Index 2: Left\n        SDL_SCANCODE_RIGHT, // Index 3: Right\n        SDL_SCANCODE_X,     // Index 4: Button A\n        SDL_SCANCODE_Z      // Index 5: Button B\n    );\n\n    // Use with Engine\n    pixelroot32::graphics::DisplayConfig displayConfig;\n    pixelroot32::core::Engine engine(displayConfig, inputConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/core/input_config/#platform-agnostic-configuration","title":"Platform-Agnostic Configuration","text":"
#ifdef PLATFORM_ESP32\n    // ESP32: Use GPIO pins\n    pixelroot32::input::InputConfig inputConfig(6, 0, 2, 4, 5, 18, 19);\n#elif PLATFORM_NATIVE\n    // Native: Use SDL scancodes\n    #include <SDL2/SDL.h>\n    pixelroot32::input::InputConfig inputConfig(6,\n        SDL_SCANCODE_UP,\n        SDL_SCANCODE_DOWN,\n        SDL_SCANCODE_LEFT,\n        SDL_SCANCODE_RIGHT,\n        SDL_SCANCODE_X,\n        SDL_SCANCODE_Z\n    );\n#endif\n
"},{"location":"api_reference/core/input_config/#button-index-mapping","title":"Button Index Mapping","text":"

Button indices are determined by the order in the constructor:

Typical Convention: - Index 0: Up / Primary action - Index 1: Down / Secondary action - Index 2: Left - Index 3: Right - Index 4+: Additional buttons

Example:

// 4-button D-pad\nInputConfig config(4, UP_PIN, DOWN_PIN, LEFT_PIN, RIGHT_PIN);\n// Index 0 = Up, Index 1 = Down, Index 2 = Left, Index 3 = Right\n\n// 6-button setup (D-pad + 2 action buttons)\nInputConfig config(6, UP_PIN, DOWN_PIN, LEFT_PIN, RIGHT_PIN, A_PIN, B_PIN);\n// Index 0-3 = D-pad, Index 4 = A, Index 5 = B\n

"},{"location":"api_reference/core/input_config/#esp32-pin-considerations","title":"ESP32 Pin Considerations","text":"
  • GPIO pins: Use any available GPIO pin
  • Pull-up/pull-down: Configure resistors appropriately
  • Input mode: Pins are automatically configured as inputs
  • Restrictions: Some pins have special functions (check ESP32 datasheet)

Common Pin Choices: - GPIO 0, 2, 4, 5: Safe for buttons (watch for boot mode pins) - GPIO 18, 19: Good for additional buttons - Avoid: GPIO 6-11 (flash), GPIO 34-39 (input only, no pull-up)

"},{"location":"api_reference/core/input_config/#native-sdl-scancode-reference","title":"Native SDL Scancode Reference","text":"

Common SDL scancodes:

  • SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT: Arrow keys
  • SDL_SCANCODE_W, SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_D: WASD
  • SDL_SCANCODE_X, SDL_SCANCODE_Z: Common action buttons
  • SDL_SCANCODE_SPACE: Spacebar
  • SDL_SCANCODE_RETURN: Enter key

Example:

// WASD + Space + Enter\npixelroot32::input::InputConfig config(6,\n    SDL_SCANCODE_W,        // Up\n    SDL_SCANCODE_S,        // Down\n    SDL_SCANCODE_A,        // Left\n    SDL_SCANCODE_D,         // Right\n    SDL_SCANCODE_SPACE,    // Jump\n    SDL_SCANCODE_RETURN    // Action\n);\n

"},{"location":"api_reference/core/input_config/#performance-considerations","title":"Performance Considerations","text":"
  • Memory: Arrays are allocated dynamically (small overhead)
  • Configuration: Done once at startup, no runtime cost
  • Access: Button indices are fast (array access)
"},{"location":"api_reference/core/input_config/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Pin configuration: Ensure pins are not used by other peripherals
  • Debouncing: Hardware debouncing recommended for reliable input
  • Power: Buttons should use pull-up resistors to avoid floating pins
"},{"location":"api_reference/core/input_config/#see-also","title":"See Also","text":"
  • InputManager - Input handling
  • Engine - Engine that uses InputConfig
  • Manual - Input and Control
  • API Overview
"},{"location":"api_reference/core/input_manager/","title":"InputManager","text":"

Handles input from physical buttons or keyboard (on PC).

"},{"location":"api_reference/core/input_manager/#description","title":"Description","text":"

The InputManager polls configured pins (ESP32) or keyboard state (Native), handles debouncing, and tracks button states (Pressed, Released, Down, Clicked). It provides a unified input interface for both platforms.

The manager supports edge detection (just pressed/released) and continuous state (held down), making it suitable for both gameplay and UI navigation.

"},{"location":"api_reference/core/input_manager/#namespace","title":"Namespace","text":"
namespace pixelroot32::input {\n    class InputManager {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/input_manager/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages input manager instance)
"},{"location":"api_reference/core/input_manager/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/input_manager/#inputmanagerconst-inputconfig-config","title":"InputManager(const InputConfig& config)","text":"

Constructs the InputManager with a specific configuration.

Parameters: - config (const InputConfig&): The input configuration (pins, button count)

Example:

#include \"input/InputManager.h\"\n#include \"input/InputConfig.h\"\n\n// ESP32: Configure GPIO pins\npixelroot32::input::InputConfig inputConfig(6, 0, 2, 4, 5, 18, 19);\npixelroot32::input::InputManager inputManager(inputConfig);\ninputManager.init();\n\n// Native: Configure keyboard keys\n// (Configuration handled differently on Native)\n

"},{"location":"api_reference/core/input_manager/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/input_manager/#void-init","title":"void init()","text":"

Initializes the input pins.

Returns: - void

Notes: - Must be called after construction and before use - Configures GPIO pins (ESP32) or keyboard state (Native) - Safe to call multiple times (idempotent) - Typically called automatically by Engine::init()

Example:

InputManager inputManager(inputConfig);\ninputManager.init();  // Initialize before use\n

"},{"location":"api_reference/core/input_manager/#void-updateunsigned-long-dt","title":"void update(unsigned long dt)","text":"

Updates input state by polling hardware pins (ESP32) or keyboard state (Native).

Parameters: - dt (unsigned long): Delta time in milliseconds

Returns: - void

Notes: - Must be called every frame for proper input detection - Handles debouncing automatically - Updates button states and edge detection - Typically called automatically by Engine::update()

ESP32 Example:

void update(unsigned long deltaTime) override {\n    // Input is updated automatically by Engine\n    // Access input via engine.getInputManager()\n}\n

Native Example:

// On Native, update is called with keyboard state:\nvoid update(unsigned long dt, const uint8_t* keyboardState);\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttonpresseduint8_t-buttonindex-const","title":"bool isButtonPressed(uint8_t buttonIndex) const","text":"

Checks if a button was just pressed this frame.

Parameters: - buttonIndex (uint8_t): Index of the button to check (0-based)

Returns: - bool: true if the button transitioned from UP to DOWN this frame

Notes: - Returns true only on the frame the button was pressed - Useful for one-time actions (jump, shoot, menu select) - Resets automatically on next frame

Example:

auto& input = engine.getInputManager();\n\nif (input.isButtonPressed(0)) {  // Button A (index 0)\n    // Jump (only once per press)\n    player->jump();\n}\n\nif (input.isButtonPressed(1)) {  // Button B (index 1)\n    // Shoot (only once per press)\n    player->shoot();\n}\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttonreleaseduint8_t-buttonindex-const","title":"bool isButtonReleased(uint8_t buttonIndex) const","text":"

Checks if a button was just released this frame.

Parameters: - buttonIndex (uint8_t): Index of the button to check

Returns: - bool: true if the button transitioned from DOWN to UP this frame

Notes: - Returns true only on the frame the button was released - Useful for detecting button release events - Less commonly used than isButtonPressed()

Example:

auto& input = engine.getInputManager();\n\nif (input.isButtonReleased(0)) {\n    // Button A was just released\n    player->stopCharging();\n}\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttonclickeduint8_t-buttonindex-const","title":"bool isButtonClicked(uint8_t buttonIndex) const","text":"

Checks if a button was clicked (pressed and released).

Parameters: - buttonIndex (uint8_t): Index of the button to check

Returns: - bool: true if the button was clicked (pressed then released)

Notes: - Returns true when button is released after being pressed - Useful for UI buttons and menu selection - Detects complete press-release cycle

Example:

auto& input = engine.getInputManager();\n\nif (input.isButtonClicked(0)) {  // Button A clicked\n    // Select menu item\n    menu->select();\n}\n

"},{"location":"api_reference/core/input_manager/#bool-isbuttondownuint8_t-buttonindex-const","title":"bool isButtonDown(uint8_t buttonIndex) const","text":"

Checks if a button is currently held down.

Parameters: - buttonIndex (uint8_t): Index of the button to check

Returns: - bool: true if the button is currently in the DOWN state

Notes: - Returns true for as long as the button is held - Useful for continuous actions (movement, charging) - Use with deltaTime for frame-rate independent movement

Example:

auto& input = engine.getInputManager();\n\nfloat speed = 100.0f;  // pixels per second\nfloat vx = 0.0f, vy = 0.0f;\n\nif (input.isButtonDown(2)) {  // Left button\n    vx = -speed;\n}\nif (input.isButtonDown(3)) {  // Right button\n    vx = speed;\n}\nif (input.isButtonDown(0)) {  // Up button\n    vy = -speed;\n}\nif (input.isButtonDown(1)) {  // Down button\n    vy = speed;\n}\n\n// Apply movement (frame-rate independent)\nx += (vx * deltaTime) / 1000.0f;\ny += (vy * deltaTime) / 1000.0f;\n

"},{"location":"api_reference/core/input_manager/#button-indices","title":"Button Indices","text":"

Button indices are defined by the order in InputConfig:

Typical Mapping: - 0: Up / Button A - 1: Down / Button B - 2: Left - 3: Right - 4: Additional button 1 - 5: Additional button 2

Example:

// Configure 6 buttons: Up, Down, Left, Right, A, B\npixelroot32::input::InputConfig inputConfig(6, \n    GPIO_UP,    // Index 0\n    GPIO_DOWN,  // Index 1\n    GPIO_LEFT,  // Index 2\n    GPIO_RIGHT, // Index 3\n    GPIO_A,     // Index 4\n    GPIO_B      // Index 5\n);\n\n// Use indices\nif (input.isButtonDown(2)) {  // Left\n    moveLeft();\n}\nif (input.isButtonPressed(4)) {  // A button\n    jump();\n}\n

"},{"location":"api_reference/core/input_manager/#usage-example","title":"Usage Example","text":"
#include \"input/InputManager.h\"\n#include \"core/Engine.h\"\n\nclass PlayerController {\nprivate:\n    pixelroot32::core::Engine& engine;\n\npublic:\n    PlayerController(pixelroot32::core::Engine& eng) : engine(eng) {}\n\n    void update(unsigned long deltaTime) {\n        auto& input = engine.getInputManager();\n\n        // Movement (continuous)\n        float speed = 150.0f;  // pixels per second\n        float vx = 0.0f, vy = 0.0f;\n\n        if (input.isButtonDown(3)) {  // Right\n            vx = speed;\n        }\n        if (input.isButtonDown(2)) {  // Left\n            vx = -speed;\n        }\n        if (input.isButtonDown(0)) {  // Up\n            vy = -speed;\n        }\n        if (input.isButtonDown(1)) {  // Down\n            vy = speed;\n        }\n\n        // Apply movement\n        playerX += (vx * deltaTime) / 1000.0f;\n        playerY += (vy * deltaTime) / 1000.0f;\n\n        // Actions (one-time)\n        if (input.isButtonPressed(4)) {  // A button\n            player->jump();\n        }\n\n        if (input.isButtonPressed(5)) {  // B button\n            player->shoot();\n        }\n    }\n};\n
"},{"location":"api_reference/core/input_manager/#input-state-comparison","title":"Input State Comparison","text":"Method Returns true when Use Case isButtonPressed() Button just pressed this frame One-time actions (jump, shoot) isButtonReleased() Button just released this frame Release events (stop charging) isButtonClicked() Button pressed then released UI buttons, menu selection isButtonDown() Button currently held Continuous actions (movement)"},{"location":"api_reference/core/input_manager/#performance-considerations","title":"Performance Considerations","text":"
  • Update frequency: update() must be called every frame
  • Debouncing: Handled automatically, no performance impact
  • State queries: All query methods are fast (inline accessors)
  • Memory: Button state arrays are small and efficient
"},{"location":"api_reference/core/input_manager/#esp32-considerations","title":"ESP32 Considerations","text":"
  • GPIO pins: Configure pins in InputConfig
  • Pull-up/pull-down: Ensure proper resistor configuration
  • Debouncing: Hardware debouncing recommended for noisy buttons
  • Pin limits: Some ESP32 pins have restrictions (check datasheet)
"},{"location":"api_reference/core/input_manager/#native-considerations","title":"Native Considerations","text":"
  • Keyboard mapping: Uses SDL scancodes
  • Key detection: Automatically handles keyboard state
  • Multiple keys: Can detect multiple keys simultaneously
"},{"location":"api_reference/core/input_manager/#see-also","title":"See Also","text":"
  • InputConfig - Input configuration
  • Engine - Engine that manages InputManager
  • Manual - Input and Control
  • API Overview
"},{"location":"api_reference/core/physics_actor/","title":"PhysicsActor","text":"

An actor with basic 2D physics properties.

"},{"location":"api_reference/core/physics_actor/#description","title":"Description","text":"

PhysicsActor extends the base Actor class by adding velocity, acceleration, friction, restitution (bounciness), and world boundary collision resolution. It is designed for objects that need to move and bounce within a defined area, such as balls, projectiles, or platformer characters.

PhysicsActor automatically handles: - Velocity-based movement - Friction application - World boundary collision and bouncing - Collision callbacks

"},{"location":"api_reference/core/physics_actor/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class PhysicsActor : public Actor {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/physics_actor/#inheritance","title":"Inheritance","text":"
  • Inherits from: Actor
  • Inherited by: Your custom physics-enabled actor classes
"},{"location":"api_reference/core/physics_actor/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/physics_actor/#physicsactorfloat-x-float-y-float-w-float-h","title":"PhysicsActor(float x, float y, float w, float h)","text":"

Creates a physics-enabled actor with specified position and size.

Parameters: - x (float): Initial X position in world space - y (float): Initial Y position in world space - w (float): Actor width in pixels - h (float): Actor height in pixels

Notes: - Velocity starts at (0, 0) - Restitution defaults to 1.0 (perfect bounce) - Friction defaults to 0.0 (no friction) - No world limits by default

Example:

class BallActor : public pixelroot32::core::PhysicsActor {\npublic:\n    BallActor(float x, float y) \n        : PhysicsActor(x, y, 8.0f, 8.0f) {\n        // Set physics properties\n        setRestitution(0.8f);  // 80% bounce\n        setFriction(0.1f);     // Small friction\n        setWorldSize(128, 128); // World bounds\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledCircle(static_cast<int>(x + width/2), \n                                 static_cast<int>(y + height/2), \n                                 width/2, \n                                 Color::White);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        // Bounce off other actors\n    }\n\n    void onWorldCollision() override {\n        // Play bounce sound\n    }\n};\n

"},{"location":"api_reference/core/physics_actor/#protected-properties","title":"Protected Properties","text":""},{"location":"api_reference/core/physics_actor/#float-vx-vy","title":"float vx, vy","text":"

Horizontal and vertical velocity components.

Type: float

Access: Protected (use setVelocity() to modify)

Default: 0.0f

Notes: - Velocity is in pixels per second - Automatically applied during update() - Modified by friction and world collisions

"},{"location":"api_reference/core/physics_actor/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/physics_actor/#void-setvelocityfloat-x-float-y","title":"void setVelocity(float x, float y)","text":"

Sets the linear velocity of the actor.

Parameters: - x (float): Horizontal velocity in pixels per second - y (float): Vertical velocity in pixels per second

Returns: - void

Notes: - Velocity is applied every frame during update() - Use for initial velocity or impulse-based movement - Can be called every frame for continuous control

Example:

// Set initial velocity\nphysicsActor->setVelocity(100.0f, -200.0f);  // Move right and up\n\n// Continuous control (e.g., player movement)\nvoid update(unsigned long deltaTime) override {\n    PhysicsActor::update(deltaTime);\n\n    float speed = 150.0f;\n    float vx = 0.0f, vy = 0.0f;\n\n    if (input.isButtonDown(Buttons::LEFT)) vx = -speed;\n    if (input.isButtonDown(Buttons::RIGHT)) vx = speed;\n    if (input.isButtonDown(Buttons::UP)) vy = -speed;\n    if (input.isButtonDown(Buttons::DOWN)) vy = speed;\n\n    setVelocity(vx, vy);\n}\n

"},{"location":"api_reference/core/physics_actor/#void-setrestitutionfloat-r","title":"void setRestitution(float r)","text":"

Sets the restitution (bounciness) of the actor.

Parameters: - r (float): Restitution value (0.0 to 1.0+) - 0.0: No bounce (stops on impact) - 1.0: Perfect bounce (no energy loss) - > 1.0: Energy gain (unrealistic but possible)

Returns: - void

Notes: - Applied when actor collides with world boundaries - Higher values = more bouncy - Typical values: 0.5-0.9 for realistic bouncing

Example:

ball->setRestitution(0.8f);  // 80% bounce\n

"},{"location":"api_reference/core/physics_actor/#void-setfrictionfloat-f","title":"void setFriction(float f)","text":"

Sets the friction coefficient.

Parameters: - f (float): Friction value - 0.0: No friction (object continues moving) - > 0.0: Friction applied to velocity each frame

Returns: - void

Notes: - Applied every frame to reduce velocity - Higher values = more friction (slower movement) - Typical values: 0.05-0.2 for smooth deceleration

Example:

player->setFriction(0.1f);  // Light friction\n

"},{"location":"api_reference/core/physics_actor/#void-setlimitslimitrect-limits","title":"void setLimits(LimitRect limits)","text":"

Sets custom movement limits for the actor.

Parameters: - limits (LimitRect): A rectangle defining the allowed area

Returns: - void

Notes: - Overrides world size limits - Use -1 for any boundary to disable that limit - Actor will bounce off these boundaries

Example:

pixelroot32::core::LimitRect limits;\nlimits.left = 0;\nlimits.top = 0;\nlimits.right = 128;\nlimits.bottom = 128;\nphysicsActor->setLimits(limits);\n

"},{"location":"api_reference/core/physics_actor/#void-setworldsizeint-width-int-height","title":"void setWorldSize(int width, int height)","text":"

Defines the world size for boundary checking.

Parameters: - width (int): Width of the world in pixels - height (int): Height of the world in pixels

Returns: - void

Notes: - Used as default limits if no custom LimitRect is provided - Actor will bounce off world boundaries - Set to display size for screen boundaries

Example:

physicsActor->setWorldSize(128, 128);  // Match display size\n

"},{"location":"api_reference/core/physics_actor/#worldcollisioninfo-getworldcollisioninfo-const","title":"WorldCollisionInfo getWorldCollisionInfo() const","text":"

Gets information about collisions with the world boundaries.

Returns: - WorldCollisionInfo: A struct containing collision flags (left, right, top, bottom)

Notes: - Updated every frame during update() - Use to detect which boundary was hit - Useful for sound effects or special behaviors

Example:

void update(unsigned long deltaTime) override {\n    PhysicsActor::update(deltaTime);\n\n    auto collision = getWorldCollisionInfo();\n    if (collision.left || collision.right) {\n        // Hit side wall\n        playSound(wallHitSound);\n    }\n    if (collision.top || collision.bottom) {\n        // Hit top or bottom\n        playSound(ceilingHitSound);\n    }\n}\n

"},{"location":"api_reference/core/physics_actor/#virtual-void-oncollisionactor-other-override","title":"virtual void onCollision(Actor* other) override","text":"

Callback triggered when this actor collides with another actor.

Parameters: - other (Actor*): Pointer to the actor involved in the collision

Returns: - void

Notes: - Called automatically by the collision system - Override to implement custom collision responses - Default implementation does nothing

Example:

void onCollision(Actor* other) override {\n    if (other->isInLayer(DefaultLayers::kEnemy)) {\n        // Bounce off enemy\n        vx = -vx * 0.5f;\n        vy = -vy * 0.5f;\n    }\n}\n

"},{"location":"api_reference/core/physics_actor/#virtual-void-onworldcollision","title":"virtual void onWorldCollision()","text":"

Callback triggered when this actor collides with world boundaries.

Returns: - void

Notes: - Called automatically when a world boundary collision occurs - Override to implement custom behavior (sound effects, particles, etc.) - Default implementation does nothing

Example:

void onWorldCollision() override {\n    // Play bounce sound\n    auto& audio = engine.getAudioEngine();\n    pixelroot32::audio::AudioEvent sound{};\n    sound.type = pixelroot32::audio::WaveType::NOISE;\n    sound.frequency = 500.0f;\n    sound.duration = 0.05f;\n    audio.playEvent(sound);\n\n    // Spawn particles\n    spawnBounceParticles();\n}\n

"},{"location":"api_reference/core/physics_actor/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the actor state. Applies physics integration and checks for world boundary collisions.

Parameters: - deltaTime (unsigned long): Time elapsed since the last frame in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Applies velocity to position - Applies friction to velocity - Resolves world boundary collisions - Override to add custom update logic, but call PhysicsActor::update(deltaTime) first

Example:

void update(unsigned long deltaTime) override {\n    // Apply physics\n    PhysicsActor::update(deltaTime);\n\n    // Custom logic\n    if (shouldApplyGravity) {\n        vy += gravity * (deltaTime / 1000.0f);\n    }\n}\n

"},{"location":"api_reference/core/physics_actor/#limitrect-structure","title":"LimitRect Structure","text":"

Bounding rectangle for world-collision resolution.

Members: - int left: Left boundary (-1 means no limit) - int top: Top boundary (-1 means no limit) - int right: Right boundary (-1 means no limit) - int bottom: Bottom boundary (-1 means no limit)

Methods: - int width() const: Calculates width (right - left) - int height() const: Calculates height (bottom - top)

Example:

pixelroot32::core::LimitRect limits(10, 10, 118, 118);  // 10px margin\nphysicsActor->setLimits(limits);\n

"},{"location":"api_reference/core/physics_actor/#worldcollisioninfo-structure","title":"WorldCollisionInfo Structure","text":"

Information about world collisions in the current frame.

Members: - bool left: True if collided with the left boundary - bool right: True if collided with the right boundary - bool top: True if collided with the top boundary - bool bottom: True if collided with the bottom boundary

Example:

auto collision = physicsActor->getWorldCollisionInfo();\nif (collision.bottom) {\n    // On ground\n    canJump = true;\n}\n

"},{"location":"api_reference/core/physics_actor/#usage-example","title":"Usage Example","text":"
#include \"core/PhysicsActor.h\"\n\nclass BouncingBall : public pixelroot32::core::PhysicsActor {\npublic:\n    BouncingBall(float x, float y) \n        : PhysicsActor(x, y, 8.0f, 8.0f) {\n        // Set physics properties\n        setRestitution(0.9f);  // Very bouncy\n        setFriction(0.05f);    // Light friction\n        setWorldSize(128, 128);\n\n        // Set initial velocity\n        setVelocity(100.0f, -150.0f);\n\n        // Set collision layer\n        layer = pixelroot32::physics::DefaultLayers::kProjectile;\n        mask = pixelroot32::physics::DefaultLayers::kObstacle;\n    }\n\n    void update(unsigned long deltaTime) override {\n        PhysicsActor::update(deltaTime);\n\n        // Apply gravity\n        vy += 200.0f * (deltaTime / 1000.0f);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledCircle(static_cast<int>(x + width/2), \n                                 static_cast<int>(y + height/2), \n                                 width/2, \n                                 Color::White);\n    }\n\n    Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(Actor* other) override {\n        // Bounce off obstacles\n        vx = -vx * 0.8f;\n        vy = -vy * 0.8f;\n    }\n\n    void onWorldCollision() override {\n        // Play bounce sound\n        playBounceSound();\n    }\n};\n
"},{"location":"api_reference/core/physics_actor/#performance-considerations","title":"Performance Considerations","text":"
  • Physics integration: Very efficient (simple velocity integration)
  • World bounds: Boundary checks are fast (AABB)
  • Friction: Applied every frame; keep friction values reasonable
  • Collision callbacks: Keep onCollision() and onWorldCollision() fast
"},{"location":"api_reference/core/physics_actor/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Floating point: Uses float math; acceptable for ESP32 but integer math would be faster
  • Frame rate: Physics is frame-rate independent (uses deltaTime)
  • Memory: Each PhysicsActor consumes more memory than Actor (velocity, limits, etc.)
"},{"location":"api_reference/core/physics_actor/#see-also","title":"See Also","text":"
  • Actor - Base actor class
  • CollisionSystem - Collision detection
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/core/scene/","title":"Scene","text":"

Represents a game level or screen containing entities.

"},{"location":"api_reference/core/scene/#description","title":"Description","text":"

A Scene manages a collection of Entities and a CollisionSystem. It is responsible for updating and drawing all entities it contains. Scenes provide lifecycle hooks (init(), update(), draw()) to manage gameplay segments.

Scenes are the primary organizational unit in PixelRoot32, similar to levels or screens in other game engines. Each scene can contain up to MAX_ENTITIES (default 32; overridable via compiler flags) entities, and drawing uses up to MAX_LAYERS (default 3; overridable) render layers.

"},{"location":"api_reference/core/scene/#namespace","title":"Namespace","text":"
namespace pixelroot32::core {\n    class Scene {\n        // ...\n    };\n}\n
"},{"location":"api_reference/core/scene/#inheritance","title":"Inheritance","text":"
  • Base class: None (abstract base class)
  • Inherited by: Your custom scene classes (e.g., MainMenuScene, GameScene)
"},{"location":"api_reference/core/scene/#constructors","title":"Constructors","text":""},{"location":"api_reference/core/scene/#scene_1","title":"Scene()","text":"

Creates an empty scene ready to be populated with entities.

Notes: - The scene starts with no entities - init() should be called when the scene becomes active - The collision system is automatically initialized

Example:

class MyScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Initialize scene resources\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);  // Update entities and collisions\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        Scene::draw(renderer);  // Draw all entities\n    }\n};\n

"},{"location":"api_reference/core/scene/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/core/scene/#virtual-void-init","title":"virtual void init()","text":"

Initializes the scene. Called when entering the scene.

Returns: - void

Notes: - Called automatically when the scene is set via Engine::setScene() - Override this method to initialize scene-specific resources - Safe to call multiple times (idempotent) - Add entities here or in the constructor

Example:

class GameScene : public pixelroot32::core::Scene {\nprivate:\n    PlayerActor* player;\n    std::array<EnemyActor*, 10> enemies;\n\npublic:\n    void init() override {\n        // Create player\n        player = new PlayerActor();\n        addEntity(player);\n\n        // Create enemies\n        for (int i = 0; i < 10; i++) {\n            enemies[i] = new EnemyActor();\n            addEntity(enemies[i]);\n        }\n    }\n};\n

"},{"location":"api_reference/core/scene/#virtual-void-updateunsigned-long-deltatime","title":"virtual void update(unsigned long deltaTime)","text":"

Updates all entities in the scene and handles collisions.

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Notes: - Called automatically by the engine every frame - Updates all entities in the scene - Processes collisions between actors - Override to add custom update logic, but call Scene::update(deltaTime) to maintain entity updates

Example:

void update(unsigned long deltaTime) override {\n    // Custom update logic\n    gameTimer += deltaTime;\n\n    // Update entities and collisions\n    Scene::update(deltaTime);\n\n    // Additional logic after entity updates\n    if (gameTimer > 60000) {\n        // Game over after 60 seconds\n    }\n}\n

"},{"location":"api_reference/core/scene/#virtual-void-drawrenderer-renderer","title":"virtual void draw(Renderer& renderer)","text":"

Draws all visible entities in the scene.

Parameters: - renderer (pixelroot32::graphics::Renderer&): The renderer to use for drawing

Notes: - Called automatically by the engine every frame after update() - Draws all visible entities in the scene - Override to add custom drawing logic, but call Scene::draw(renderer) to maintain entity rendering - Entities are drawn in the order they were added

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Draw background\n    renderer.drawTileMap(backgroundTileMap, 0, 0, Color::White);\n\n    // Draw all entities\n    Scene::draw(renderer);\n\n    // Draw UI overlay\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n}\n

"},{"location":"api_reference/core/scene/#void-addentityentity-entity","title":"void addEntity(Entity* entity)","text":"

Adds an entity to the scene.

Parameters: - entity (Entity*): Pointer to the Entity to add. Must not be nullptr.

Notes: - Entities are added to an internal queue - Maximum of MAX_ENTITIES (default 32; overridable) entities per scene - If the limit is reached, the entity may not be added (check return value if available) - Entities are updated and drawn in the order they were added - The entity's lifetime is managed by the scene (do not delete manually while in scene)

Example:

void init() override {\n    // Create and add player\n    PlayerActor* player = new PlayerActor();\n    player->setPosition(64, 64);\n    addEntity(player);\n\n    // Create and add enemy\n    EnemyActor* enemy = new EnemyActor();\n    enemy->setPosition(100, 100);\n    addEntity(enemy);\n}\n

"},{"location":"api_reference/core/scene/#void-removeentityentity-entity","title":"void removeEntity(Entity* entity)","text":"

Removes an entity from the scene.

Parameters: - entity (Entity*): Pointer to the Entity to remove

Notes: - The entity is removed from the update and draw queues - The entity is not deleted automatically (you must manage its lifetime) - Safe to call even if the entity is not in the scene - Consider using object pooling instead of frequent add/remove

Example:

void onEnemyDestroyed(EnemyActor* enemy) {\n    removeEntity(enemy);\n    // Return to pool or delete\n    enemyPool.returnToPool(enemy);\n}\n

"},{"location":"api_reference/core/scene/#void-clearentities","title":"void clearEntities()","text":"

Removes all entities from the scene.

Notes: - All entities are removed from the update and draw queues - Entities are not deleted automatically (you must manage their lifetimes) - Useful for scene cleanup or reset - Consider using object pooling to reuse entities

Example:

void reset() {\n    clearEntities();\n    // Return all entities to pool\n    for (auto* entity : entityPool) {\n        entityPool.returnToPool(entity);\n    }\n}\n

"},{"location":"api_reference/core/scene/#protected-members","title":"Protected Members","text":""},{"location":"api_reference/core/scene/#arduinoqueue-entities","title":"ArduinoQueue entities

Queue of entities in the scene. Accessible to derived classes for custom entity management.

Type: ArduinoQueue<Entity*>

Notes: - Maximum capacity: MAX_ENTITIES (default 32; overridable) - Direct access allows custom iteration or filtering - Use with caution: modifying while iterating may cause issues

","text":""},{"location":"api_reference/core/scene/#collisionsystem-collisionsystem","title":"CollisionSystem collisionSystem

System to handle collisions between actors. Accessible to derived classes for custom collision handling.

Type: pixelroot32::physics::CollisionSystem

Notes: - Automatically processes collisions between actors - Uses collision layers and masks for filtering - Can be accessed for custom collision queries

","text":""},{"location":"api_reference/core/scene/#overriding-scene-limits-max_layers-max_entities","title":"Overriding scene limits (MAX_LAYERS / MAX_ENTITIES)","text":"

The engine defines default limits in core/Scene.h: MAX_LAYERS (default 3) and MAX_ENTITIES (default 32). These are guarded with #ifndef, so you can override them from your project without modifying the engine.

ESP32 platform limitation

The default of 3 for MAX_LAYERS is due to ESP32 platform constraints (memory and draw-loop cost). On native/PC you can safely use a higher value; on ESP32, increasing it may affect performance or memory.

"},{"location":"api_reference/core/scene/#option-a-compiler-flags-recommended","title":"Option A: Compiler flags (recommended)

In your project (e.g. in platformio.ini), add the defines to build_flags for the environment you use:

build_flags =\n    -DMAX_LAYERS=5\n    -DMAX_ENTITIES=64\n

The compiler defines MAX_LAYERS and MAX_ENTITIES before processing any .cpp file. Because Scene.h uses #ifndef MAX_LAYERS / #ifndef MAX_ENTITIES, it will not redefine them and your values will be used.

Effect: - MAX_LAYERS: Number of render layers drawn in Scene::draw() (layer 0 = background, 1+ = sprite context). Increasing this allows more distinct draw layers (e.g. background, platforms, gameplay, foreground, UI). - MAX_ENTITIES: On Arduino, the capacity of the scene entity queue when constructed with this value. On native (mock queue), the value is ignored (unbounded).

See also: Platforms and Drivers - Scene limits.

","text":""},{"location":"api_reference/core/scene/#usage-example","title":"Usage Example","text":"
#include \"core/Scene.h\"\n#include \"core/Actor.h\"\n\nclass MyGameScene : public pixelroot32::core::Scene {\nprivate:\n    PlayerActor* player;\n\npublic:\n    void init() override {\n        // Create player\n        player = new PlayerActor();\n        player->setPosition(64, 64);\n        addEntity(player);\n\n        // Create some enemies\n        for (int i = 0; i < 5; i++) {\n            EnemyActor* enemy = new EnemyActor();\n            enemy->setPosition(10 + i * 20, 10);\n            addEntity(enemy);\n        }\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Custom game logic\n        if (player->isDead()) {\n            // Handle game over\n        }\n\n        // Update entities and collisions\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background\n        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n\n        // Draw all entities\n        Scene::draw(renderer);\n\n        // Draw HUD\n        char scoreText[32];\n        snprintf(scoreText, sizeof(scoreText), \"Score: %d\", score);\n        renderer.drawText(scoreText, 10, 10, Color::White, 1);\n    }\n};\n
"},{"location":"api_reference/core/scene/#performance-considerations","title":"Performance Considerations","text":"
  • Entity limit: MAX_ENTITIES (default 32) can be overridden via compiler flags; plan accordingly
  • Add/Remove: Frequent add/remove operations can be expensive; use object pooling
  • Update order: Entities are updated in add order; consider order for dependencies
  • Collision checks: CollisionSystem automatically handles actor collisions efficiently
"},{"location":"api_reference/core/scene/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Each entity consumes memory; stay well below the limit
  • Object pooling: Essential for ESP32 to avoid memory fragmentation
  • Scene switching: Clearing and recreating scenes can fragment memory; reuse scenes when possible
"},{"location":"api_reference/core/scene/#see-also","title":"See Also","text":"
  • Entity - Base entity class
  • Actor - Entity with collision support
  • PhysicsActor - Entity with physics
  • CollisionSystem - Collision detection
  • Manual - Scenes and Entities
  • API Overview
"},{"location":"api_reference/graphics/camera2d/","title":"Camera2D","text":"

2D camera for scrolling and viewport control.

"},{"location":"api_reference/graphics/camera2d/#description","title":"Description","text":"

Camera2D controls viewport position and enables scrolling by shifting the renderer's display offset. It supports following targets, boundary constraints, and can be used for parallax effects.

The camera uses a dead-zone system: it only moves when the target is outside a central zone, creating smooth following behavior.

"},{"location":"api_reference/graphics/camera2d/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    class Camera2D {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/camera2d/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Scenes (for scrolling and camera control)
"},{"location":"api_reference/graphics/camera2d/#constructors","title":"Constructors","text":""},{"location":"api_reference/graphics/camera2d/#camera2dint-viewportwidth-int-viewportheight","title":"Camera2D(int viewportWidth, int viewportHeight)","text":"

Creates a new camera with specified viewport dimensions.

Parameters: - viewportWidth (int): Width of the viewport in pixels - viewportHeight (int): Height of the viewport in pixels

Notes: - Viewport size should match display size - Camera position starts at (0, 0) - No boundaries set by default (camera can move anywhere)

Example:

#include \"graphics/Camera2D.h\"\n\n// Create camera matching display size\npixelroot32::graphics::Camera2D camera(128, 128);\n\n// Or get from renderer\nint width = renderer.getWidth();\nint height = renderer.getHeight();\npixelroot32::graphics::Camera2D camera(width, height);\n

"},{"location":"api_reference/graphics/camera2d/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/graphics/camera2d/#void-setpositionfloat-x-float-y","title":"void setPosition(float x, float y)","text":"

Sets the camera position directly.

Parameters: - x (float): X position in world space - y (float): Y position in world space

Returns: - void

Notes: - Position is clamped to boundaries if set - Use for direct camera control or cutscenes - Overrides any following behavior

Example:

camera.setPosition(100.0f, 200.0f);\n

"},{"location":"api_reference/graphics/camera2d/#void-setboundsfloat-minx-float-maxx","title":"void setBounds(float minX, float maxX)","text":"

Sets horizontal boundaries for the camera.

Parameters: - minX (float): Minimum X position - maxX (float): Maximum X position

Returns: - void

Notes: - Camera position is clamped to these bounds - Use to prevent camera from going outside level bounds - Set both horizontal and vertical bounds for full constraint

Example:

// Level is 512 pixels wide, camera viewport is 128\n// Prevent camera from showing outside level\ncamera.setBounds(0.0f, 512.0f - 128.0f);\n

"},{"location":"api_reference/graphics/camera2d/#void-setverticalboundsfloat-miny-float-maxy","title":"void setVerticalBounds(float minY, float maxY)","text":"

Sets vertical boundaries for the camera.

Parameters: - minY (float): Minimum Y position - maxY (float): Maximum Y position

Returns: - void

Notes: - Camera position is clamped to these bounds - Use to prevent camera from going outside level bounds vertically

Example:

// Level is 512 pixels tall, camera viewport is 128\ncamera.setVerticalBounds(0.0f, 512.0f - 128.0f);\n

"},{"location":"api_reference/graphics/camera2d/#void-followtargetfloat-targetx","title":"void followTarget(float targetX)","text":"

Makes the camera follow a target horizontally only.

Parameters: - targetX (float): X position of the target to follow

Returns: - void

Notes: - Camera follows target with dead-zone behavior - Only horizontal movement; vertical position unchanged - Useful for side-scrolling games

Example:

void update(unsigned long deltaTime) override {\n    // Update player position\n    player->update(deltaTime);\n\n    // Camera follows player horizontally\n    camera.followTarget(player->x);\n    camera.apply(renderer);\n}\n

"},{"location":"api_reference/graphics/camera2d/#void-followtargetfloat-targetx-float-targety","title":"void followTarget(float targetX, float targetY)","text":"

Makes the camera follow a target in both axes.

Parameters: - targetX (float): X position of the target to follow - targetY (float): Y position of the target to follow

Returns: - void

Notes: - Camera follows target with dead-zone behavior - Both horizontal and vertical following - Useful for top-down or platformer games

Example:

void update(unsigned long deltaTime) override {\n    player->update(deltaTime);\n\n    // Camera follows player in both axes\n    camera.followTarget(player->x, player->y);\n    camera.apply(renderer);\n}\n

"},{"location":"api_reference/graphics/camera2d/#float-getx-const","title":"float getX() const","text":"

Gets the current X position of the camera.

Returns: - float: Current X position in world space

Example:

float cameraX = camera.getX();\n

"},{"location":"api_reference/graphics/camera2d/#float-gety-const","title":"float getY() const","text":"

Gets the current Y position of the camera.

Returns: - float: Current Y position in world space

Example:

float cameraY = camera.getY();\n

"},{"location":"api_reference/graphics/camera2d/#void-applyrenderer-renderer-const","title":"void apply(Renderer& renderer) const","text":"

Applies the camera's offset to the renderer.

Parameters: - renderer (Renderer&): The renderer to apply the camera offset to

Returns: - void

Notes: - Sets the renderer's display offset based on camera position - Should be called before drawing world elements - Negative offset is applied (camera moves right = world moves left)

Example:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera offset\n    camera.apply(renderer);\n\n    // Draw world (offset applied automatically)\n    renderer.drawTileMap(levelMap, 0, 0, Color::White);\n    renderer.drawSprite(playerSprite, playerX, playerY, Color::White);\n\n    // UI elements (not affected by camera)\n    renderer.setDisplayOffset(0, 0);  // Reset for UI\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n}\n

"},{"location":"api_reference/graphics/camera2d/#dead-zone-following","title":"Dead-Zone Following","text":"

The camera uses a dead-zone system for smooth following:

  • Dead zone: Central area where camera doesn't move
  • Following: Camera moves only when target leaves dead zone
  • Smooth: Creates natural, non-jarring camera movement

Example:

// Camera follows player with dead zone\nvoid update(unsigned long deltaTime) override {\n    player->update(deltaTime);\n\n    // Camera follows (dead zone handled internally)\n    camera.followTarget(player->x, player->y);\n}\n

"},{"location":"api_reference/graphics/camera2d/#usage-example","title":"Usage Example","text":"
#include \"graphics/Camera2D.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n    TileMap levelMap;\n\npublic:\n    void init() override {\n        // Create camera matching display size\n        auto& renderer = engine.getRenderer();\n        camera = pixelroot32::graphics::Camera2D(\n            renderer.getWidth(), \n            renderer.getHeight()\n        );\n\n        // Set level boundaries\n        // Level is 512x512, viewport is 128x128\n        camera.setBounds(0.0f, 512.0f - 128.0f);\n        camera.setVerticalBounds(0.0f, 512.0f - 128.0f);\n\n        // Create player\n        player = new PlayerActor(64, 64);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Camera follows player\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw world (camera offset applied)\n        renderer.drawTileMap(levelMap, 0, 0, Color::White);\n\n        // Draw entities (Scene::draw handles this)\n        Scene::draw(renderer);\n\n        // Reset offset for UI\n        renderer.setDisplayOffset(0, 0);\n        renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n    }\n};\n
"},{"location":"api_reference/graphics/camera2d/#parallax-scrolling","title":"Parallax Scrolling","text":"

Use multiple cameras or manual offset for parallax:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Background layer (slow parallax)\n    float bgOffsetX = camera.getX() * 0.5f;  // 50% speed\n    renderer.setDisplayOffset(-bgOffsetX, 0);\n    renderer.drawTileMap(backgroundMap, 0, 0, Color::White);\n\n    // Midground layer (normal speed)\n    camera.apply(renderer);\n    renderer.drawTileMap(midgroundMap, 0, 0, Color::White);\n\n    // Foreground (entities, normal speed)\n    Scene::draw(renderer);\n\n    // UI (no offset)\n    renderer.setDisplayOffset(0, 0);\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n}\n
"},{"location":"api_reference/graphics/camera2d/#performance-considerations","title":"Performance Considerations","text":"
  • Apply frequency: apply() is fast; safe to call every frame
  • Boundary checks: Boundary clamping is efficient
  • Following: Dead-zone calculations are lightweight
"},{"location":"api_reference/graphics/camera2d/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Float math: Uses floating point; acceptable but integer math would be faster
  • Memory: Camera is small (few floats); minimal memory usage
"},{"location":"api_reference/graphics/camera2d/#see-also","title":"See Also","text":"
  • Renderer - Rendering system
  • Manual - Cameras and Scrolling
  • API Overview
"},{"location":"api_reference/graphics/color/","title":"Color","text":"

Color constants and palette management system.

"},{"location":"api_reference/graphics/color/#description","title":"Description","text":"

The Color enum provides color constants that map to palette indices. The engine supports both legacy mode (single global palette) and dual palette mode (separate palettes for backgrounds and sprites).

Colors are resolved to 16-bit RGB565 values based on the active palette(s).

"},{"location":"api_reference/graphics/color/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    enum class Color : uint8_t {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/color/#color-enum-values","title":"Color Enum Values","text":""},{"location":"api_reference/graphics/color/#standard-colors-pr32-palette-indices","title":"Standard Colors (PR32 Palette Indices)","text":"
  • Color::Black (0)
  • Color::White (1)
  • Color::Navy (2)
  • Color::Blue (3)
  • Color::Cyan (4)
  • Color::DarkGreen (5)
  • Color::Green (6)
  • Color::LightGreen (7)
  • Color::Yellow (8)
  • Color::Orange (9)
  • Color::LightRed (10)
  • Color::Red (11)
  • Color::DarkRed (12)
  • Color::Purple (13)
  • Color::Magenta (14)
  • Color::Gray (15)
"},{"location":"api_reference/graphics/color/#color-aliases","title":"Color Aliases","text":"

For compatibility, several aliases map to the closest available color:

  • Color::DarkBlue \u2192 Navy
  • Color::LightBlue \u2192 Blue
  • Color::Teal \u2192 Cyan
  • Color::Olive \u2192 DarkGreen
  • Color::Gold \u2192 Yellow
  • Color::Brown \u2192 DarkRed
  • Color::Pink \u2192 Magenta
  • Color::LightPurple \u2192 Magenta
  • Color::Maroon \u2192 DarkRed
  • Color::MidGray \u2192 Gray
  • Color::LightGray \u2192 Gray
  • Color::DarkGray \u2192 Gray
  • Color::Silver \u2192 Gray
"},{"location":"api_reference/graphics/color/#special-colors","title":"Special Colors","text":"
  • Color::Transparent (255): Not a real color; must be handled by renderer (results in no-op)
  • Color::DebugRed \u2192 Red
  • Color::DebugGreen \u2192 Green
  • Color::DebugBlue \u2192 Blue
"},{"location":"api_reference/graphics/color/#palettetype-enum","title":"PaletteType Enum","text":"

Built-in palette types:

  • PaletteType::NES: NES color palette
  • PaletteType::GB: Game Boy (4 shades of green)
  • PaletteType::GBC: Game Boy Color palette
  • PaletteType::PICO8: PICO-8 palette
  • PaletteType::PR32: PixelRoot32 default palette
"},{"location":"api_reference/graphics/color/#palettecontext-enum","title":"PaletteContext Enum","text":"

Context for palette selection in dual palette mode:

  • PaletteContext::Background: For backgrounds, tilemaps, and background primitives
  • PaletteContext::Sprite: For sprites, characters, and gameplay elements
"},{"location":"api_reference/graphics/color/#palette-functions","title":"Palette Functions","text":""},{"location":"api_reference/graphics/color/#void-setpalettepalettetype-palette","title":"void setPalette(PaletteType palette)","text":"

Selects the active color palette (legacy mode). Sets both background and sprite palettes to the same value.

Parameters: - palette (PaletteType): The palette to use

Notes: - Does not enable dual palette mode - All rendering uses the same palette - Use for simple games with single palette

Example:

pixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n

"},{"location":"api_reference/graphics/color/#void-setcustompaletteconst-uint16_t-palette","title":"void setCustomPalette(const uint16_t* palette)","text":"

Sets a custom color palette (legacy mode). Sets both background and sprite palettes to the same value.

Parameters: - palette (const uint16_t*): Pointer to an array of 16 uint16_t RGB565 color values

Notes: - Array must remain valid (use static/global storage) - Engine does not copy the palette - Does not enable dual palette mode

Example:

static const uint16_t MY_PALETTE[16] = {\n    0x0000,  // Black\n    0xFFFF,  // White\n    0x001F,  // Blue\n    // ... 13 more colors\n};\n\npixelroot32::graphics::setCustomPalette(MY_PALETTE);\n

"},{"location":"api_reference/graphics/color/#void-enabledualpalettemodebool-enable","title":"void enableDualPaletteMode(bool enable)","text":"

Enables or disables dual palette mode.

Parameters: - enable (bool): true to enable dual palette mode, false for legacy mode

Notes: - When enabled: backgrounds and sprites use separate palettes - When disabled: single palette for all rendering (legacy mode)

Example:

pixelroot32::graphics::enableDualPaletteMode(true);\n

"},{"location":"api_reference/graphics/color/#void-setbackgroundpalettepalettetype-palette","title":"void setBackgroundPalette(PaletteType palette)","text":"

Sets the background palette (for backgrounds, tilemaps, etc.).

Parameters: - palette (PaletteType): The palette type to use for backgrounds

Notes: - Only used in dual palette mode - Affects tilemaps, background primitives, etc.

Example:

pixelroot32::graphics::enableDualPaletteMode(true);\npixelroot32::graphics::setBackgroundPalette(pixelroot32::graphics::PaletteType::NES);\n

"},{"location":"api_reference/graphics/color/#void-setspritepalettepalettetype-palette","title":"void setSpritePalette(PaletteType palette)","text":"

Sets the sprite palette (for sprites, characters, etc.).

Parameters: - palette (PaletteType): The palette type to use for sprites

Notes: - Only used in dual palette mode - Affects sprites, characters, gameplay elements

Example:

pixelroot32::graphics::setSpritePalette(pixelroot32::graphics::PaletteType::GB);\n

"},{"location":"api_reference/graphics/color/#void-setdualpalettepalettetype-bgpalette-palettetype-spritepalette","title":"void setDualPalette(PaletteType bgPalette, PaletteType spritePalette)","text":"

Sets both background and sprite palettes at once. Automatically enables dual palette mode.

Parameters: - bgPalette (PaletteType): The palette type to use for backgrounds - spritePalette (PaletteType): The palette type to use for sprites

Example:

pixelroot32::graphics::setDualPalette(\n    pixelroot32::graphics::PaletteType::NES,  // Background\n    pixelroot32::graphics::PaletteType::GB     // Sprites\n);\n

"},{"location":"api_reference/graphics/color/#void-setbackgroundcustompaletteconst-uint16_t-palette","title":"void setBackgroundCustomPalette(const uint16_t* palette)","text":"

Sets a custom background palette.

Parameters: - palette (const uint16_t*): Pointer to an array of 16 uint16_t RGB565 color values

Notes: - Array must remain valid (use static/global storage) - Only used in dual palette mode

Example:

static const uint16_t BG_PALETTE[16] = { /* ... */ };\npixelroot32::graphics::enableDualPaletteMode(true);\npixelroot32::graphics::setBackgroundCustomPalette(BG_PALETTE);\n

"},{"location":"api_reference/graphics/color/#void-setspritecustompaletteconst-uint16_t-palette","title":"void setSpriteCustomPalette(const uint16_t* palette)","text":"

Sets a custom sprite palette.

Parameters: - palette (const uint16_t*): Pointer to an array of 16 uint16_t RGB565 color values

Notes: - Array must remain valid (use static/global storage) - Only used in dual palette mode

Example:

static const uint16_t SPRITE_PALETTE[16] = { /* ... */ };\npixelroot32::graphics::setSpriteCustomPalette(SPRITE_PALETTE);\n

"},{"location":"api_reference/graphics/color/#void-setdualcustompaletteconst-uint16_t-bgpalette-const-uint16_t-spritepal","title":"void setDualCustomPalette(const uint16_t bgPalette, const uint16_t spritePal)","text":"

Sets both background and sprite custom palettes at once. Automatically enables dual palette mode.

Parameters: - bgPalette (const uint16_t): Pointer to background palette array (16 RGB565 values) - spritePal (const uint16_t): Pointer to sprite palette array (16 RGB565 values)

Example:

static const uint16_t BG_PAL[16] = { /* ... */ };\nstatic const uint16_t SPRITE_PAL[16] = { /* ... */ };\npixelroot32::graphics::setDualCustomPalette(BG_PAL, SPRITE_PAL);\n

"},{"location":"api_reference/graphics/color/#uint16_t-resolvecolorcolor-color","title":"uint16_t resolveColor(Color color)","text":"

Resolves a Color enum to its corresponding 16-bit color value (legacy mode).

Parameters: - color (Color): The Color enum value

Returns: - uint16_t: The 16-bit RGB565 color value

Notes: - Uses the current active palette (single palette mode) - Color::Transparent must not be resolved (handled by renderer) - Typically called internally by renderer

Example:

uint16_t rgb565 = pixelroot32::graphics::resolveColor(pixelroot32::graphics::Color::Red);\n

"},{"location":"api_reference/graphics/color/#uint16_t-resolvecolorcolor-color-palettecontext-context","title":"uint16_t resolveColor(Color color, PaletteContext context)","text":"

Resolves a Color enum with context (dual palette mode).

Parameters: - color (Color): The Color enum value - context (PaletteContext): The palette context (Background or Sprite)

Returns: - uint16_t: The 16-bit RGB565 color value

Notes: - Uses the appropriate palette based on context - In legacy mode, context is ignored - Color::Transparent must not be resolved

Example:

uint16_t bgColor = pixelroot32::graphics::resolveColor(\n    pixelroot32::graphics::Color::Blue,\n    pixelroot32::graphics::PaletteContext::Background\n);\n

"},{"location":"api_reference/graphics/color/#rgb565-format","title":"RGB565 Format","text":"

Colors are stored as 16-bit RGB565 values:

  • Bits 15-11: Red (5 bits, 0-31)
  • Bits 10-5: Green (6 bits, 0-63)
  • Bits 4-0: Blue (5 bits, 0-31)

Conversion Example:

// Convert RGB to RGB565\nuint16_t rgb565 = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\n

"},{"location":"api_reference/graphics/color/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/graphics/color/#legacy-mode-single-palette","title":"Legacy Mode (Single Palette)","text":"
// Set single palette for all rendering\npixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n\n// Use colors\nrenderer.drawSprite(sprite, 100, 100, pixelroot32::graphics::Color::Red);\nrenderer.drawFilledRectangle(10, 10, 50, 50, pixelroot32::graphics::Color::Blue);\n
"},{"location":"api_reference/graphics/color/#dual-palette-mode","title":"Dual Palette Mode","text":"
// Enable dual palette mode\npixelroot32::graphics::enableDualPaletteMode(true);\n\n// Set different palettes for backgrounds and sprites\npixelroot32::graphics::setBackgroundPalette(pixelroot32::graphics::PaletteType::NES);\npixelroot32::graphics::setSpritePalette(pixelroot32::graphics::PaletteType::GB);\n\n// Or use convenience function\npixelroot32::graphics::setDualPalette(\n    pixelroot32::graphics::PaletteType::NES,\n    pixelroot32::graphics::PaletteType::GB\n);\n
"},{"location":"api_reference/graphics/color/#custom-palettes","title":"Custom Palettes","text":"
// Define custom palette (RGB565 values)\nstatic const uint16_t CUSTOM_PALETTE[16] = {\n    0x0000,  // 0: Black\n    0xFFFF,  // 1: White\n    0x001F,  // 2: Blue\n    0x07E0,  // 3: Green\n    0xF800,  // 4: Red\n    // ... 11 more colors\n};\n\n// Use in legacy mode\npixelroot32::graphics::setCustomPalette(CUSTOM_PALETTE);\n\n// Or use in dual palette mode\npixelroot32::graphics::enableDualPaletteMode(true);\npixelroot32::graphics::setBackgroundCustomPalette(CUSTOM_PALETTE);\npixelroot32::graphics::setSpriteCustomPalette(CUSTOM_PALETTE);\n
"},{"location":"api_reference/graphics/color/#performance-considerations","title":"Performance Considerations","text":"
  • Color resolution: Fast lookup operation
  • Palette switching: Changing palettes is fast (just pointer assignment)
  • Memory: Palettes are stored in flash (const arrays) for best performance
  • Dual mode: Slightly more overhead than legacy mode, but minimal
"},{"location":"api_reference/graphics/color/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Flash storage: Store custom palettes in flash (const/constexpr)
  • Memory: Palettes are small (16 uint16_t = 32 bytes)
  • Palette switching: Avoid switching palettes every frame
"},{"location":"api_reference/graphics/color/#see-also","title":"See Also","text":"
  • Renderer - Rendering system
  • Manual - Color Palettes
  • API Overview
"},{"location":"api_reference/graphics/display_config/","title":"DisplayConfig","text":"

Configuration settings for initializing the display.

"},{"location":"api_reference/graphics/display_config/#description","title":"Description","text":"

DisplayConfig holds display parameters used by the renderer and camera to draw correctly on the target device. It defines the display type, dimensions, rotation, and creates the appropriate DrawSurface implementation for the platform.

"},{"location":"api_reference/graphics/display_config/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    struct DisplayConfig {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/display_config/#displaytype-enum","title":"DisplayType Enum","text":"

Supported display types:

  • DisplayType::ST7789: 240x240 TFT display
  • DisplayType::ST7735: 128x128 TFT display
  • DisplayType::NONE: For SDL2 native (no driver needed)
"},{"location":"api_reference/graphics/display_config/#structure","title":"Structure","text":""},{"location":"api_reference/graphics/display_config/#displaytype-type","title":"DisplayType type","text":"

The type of display.

Type: DisplayType enum

Access: Read-write

Notes: - Determines which driver to use (ESP32) - NONE for Native/SDL2 platform

"},{"location":"api_reference/graphics/display_config/#int-rotation","title":"int rotation","text":"

Display rotation. Supports both index-based (0-3) and degree-based (0, 90, 180, 270) values.

Type: int

Access: Read-write

Default: 0

Notes: - 0: Normal orientation (0\u00b0) - 1 or 90: Rotated 90 degrees clockwise - 2 or 180: Rotated 180 degrees - 3 or 270: Rotated 90 degrees counter-clockwise (270\u00b0) - Rotation is applied during initialization. - On ESP32, this affects both the hardware display orientation and the internal framebuffer. - On Native (SDL2), this rotates the rendered texture before presenting it.

"},{"location":"api_reference/graphics/display_config/#uint16_t-physicalwidth","title":"uint16_t physicalWidth","text":"

Physical hardware width of the display.

Type: uint16_t

Access: Read-write

Notes: - Defines the actual resolution of the display hardware.

"},{"location":"api_reference/graphics/display_config/#uint16_t-physicalheight","title":"uint16_t physicalHeight","text":"

Physical hardware height of the display.

Type: uint16_t

Access: Read-write

Notes: - Defines the actual resolution of the display hardware.

"},{"location":"api_reference/graphics/display_config/#uint16_t-logicalwidth","title":"uint16_t logicalWidth","text":"

Logical rendering width. This is the resolution the game \"sees\" and draws to.

Type: uint16_t

Access: Read-write

Notes: - If smaller than physicalWidth, the image will be scaled up. - Used for clipping, camera, and UI calculations. - Recommended values for ESP32: 160, 128, 96 (for 240 physical).

"},{"location":"api_reference/graphics/display_config/#uint16_t-logicalheight","title":"uint16_t logicalHeight","text":"

Logical rendering height. This is the resolution the game \"sees\" and draws to.

Type: uint16_t

Access: Read-write

Notes: - If smaller than physicalHeight, the image will be scaled up. - Used for clipping, camera, and UI calculations.

"},{"location":"api_reference/graphics/display_config/#uint16_t-width-deprecated","title":"uint16_t width() (Deprecated)","text":"

Alias for logicalWidth. Maintained for backward compatibility.

"},{"location":"api_reference/graphics/display_config/#uint16_t-height-deprecated","title":"uint16_t height() (Deprecated)","text":"

Alias for logicalHeight. Maintained for backward compatibility.

"},{"location":"api_reference/graphics/display_config/#int-xoffset","title":"int xOffset","text":"

X offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

"},{"location":"api_reference/graphics/display_config/#int-yoffset","title":"int yOffset","text":"

Y offset for display alignment.

Type: int

Access: Read-write

Default: 0

Notes: - Used to adjust display position - Some displays need offset for proper alignment

"},{"location":"api_reference/graphics/display_config/#drawsurface-getdrawsurface-const","title":"DrawSurface& getDrawSurface() const","text":"

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed - Provides access to low-level display driver - Platform-specific implementation

"},{"location":"api_reference/graphics/display_config/#resolution-helpers","title":"Resolution Helpers","text":""},{"location":"api_reference/graphics/display_config/#bool-needsscaling-const","title":"bool needsScaling() const","text":"

Checks if the logical resolution differs from the physical resolution.

Returns: - bool: true if scaling is active.

"},{"location":"api_reference/graphics/display_config/#float-getscalex-const","title":"float getScaleX() const","text":"

Gets the horizontal scaling factor (physicalWidth / logicalWidth).

"},{"location":"api_reference/graphics/display_config/#float-getscaley-const","title":"float getScaleY() const","text":"

Gets the vertical scaling factor (physicalHeight / logicalHeight).

"},{"location":"api_reference/graphics/display_config/#constructors","title":"Constructors","text":""},{"location":"api_reference/graphics/display_config/#displayconfigdisplaytype-type-const-int-rot-uint16_t-physw-uint16_t-physh-uint16_t-logw-uint16_t-logh-const-int-xoff-0-const-int-yoff-0","title":"DisplayConfig(DisplayType type, const int rot, uint16_t physW, uint16_t physH, uint16_t logW, uint16_t logH, const int xOff = 0, const int yOff = 0)","text":"

Extended constructor that allows defining separate physical and logical resolutions.

Parameters: - type (DisplayType): The display type. - rot (int): Rotation (0-3 or degrees depending on implementation). - physW (uint16_t): Physical hardware width. - physH (uint16_t): Physical hardware height. - logW (uint16_t): Logical rendering width (0 = same as physical). - logH (uint16_t): Logical rendering height (0 = same as physical). - xOff (int, optional): X alignment offset. - yOff (int, optional): Y alignment offset.

Example:

// 128x128 game logic scaled to 240x240 display\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7789,\n    0,    // rotation\n    240, 240, // physical\n    128, 128  // logical\n);\n

"},{"location":"api_reference/graphics/display_config/#displayconfigdisplaytype-type-const-int-rot-0-uint16_t-w-240-uint16_t-h-240-const-int-xoffset-0-const-int-yoffset-0","title":"DisplayConfig(DisplayType type, const int rot = 0, uint16_t w = 240, uint16_t h = 240, const int xOffset = 0, const int yOffset = 0)","text":"

Legacy constructor for backward compatibility. Sets both logical and physical resolutions to the same values.

Notes: - Automatically creates the appropriate DrawSurface for the platform - ESP32: Creates TFT_eSPI_Drawer based on display type - Native: Creates SDL2_Drawer

Example:

// ST7789 display, 240x240, no rotation\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7789\n);\n\n// ST7735 display, 128x128, rotated 90 degrees\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7735,\n    90,   // rotation\n    128,  // physical width\n    128,  // physical height\n    128,  // logical width\n    128   // logical height\n);\n\n// Native/SDL2 (no specific display type)\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::NONE,\n    0,    // rotation\n    128, 128, // physical\n    128, 128  // logical\n);\n

"},{"location":"api_reference/graphics/display_config/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/graphics/display_config/#esp32-with-st7789","title":"ESP32 with ST7789","text":"
#ifdef PLATFORM_ESP32\n#include \"graphics/DisplayConfig.h\"\n\nvoid setup() {\n    // Configure ST7789 display (240x240 physical, 128x128 logical)\n    pixelroot32::graphics::DisplayConfig displayConfig(\n        pixelroot32::graphics::DisplayType::ST7789,\n        0,    // rotation\n        240, 240, // physical\n        128, 128  // logical\n    );\n\n    // Use with Engine\n    pixelroot32::core::Engine engine(displayConfig);\n    engine.init();\n    engine.run();\n}\n#endif\n
"},{"location":"api_reference/graphics/display_config/#esp32-with-st7735","title":"ESP32 with ST7735","text":"
#ifdef PLATFORM_ESP32\n    // Configure ST7735 display (128x128)\n    pixelroot32::graphics::DisplayConfig displayConfig(\n        pixelroot32::graphics::DisplayType::ST7735,\n        0,    // rotation\n        128, 128 // physical & logical\n    );\n#endif\n
"},{"location":"api_reference/graphics/display_config/#nativesdl2","title":"Native/SDL2","text":"
#ifdef PLATFORM_NATIVE\n    // Native display (SDL2 window)\n    pixelroot32::graphics::DisplayConfig displayConfig(\n        pixelroot32::graphics::DisplayType::NONE,\n        0,    // rotation\n        240, 240 // logical & physical\n    );\n#endif\n
"},{"location":"api_reference/graphics/display_config/#platform-agnostic-setup","title":"Platform-Agnostic Setup","text":"
#include \"graphics/DisplayConfig.h\"\n#include \"core/Engine.h\"\n\nvoid setup() {\n    pixelroot32::graphics::DisplayConfig displayConfig;\n\n    #ifdef PLATFORM_ESP32\n        displayConfig.type = pixelroot32::graphics::DisplayType::ST7789;\n        displayConfig.physicalWidth = 240;\n        displayConfig.physicalHeight = 240;\n        displayConfig.logicalWidth = 160; // 160x160 logic\n        displayConfig.logicalHeight = 160;\n    #elif PLATFORM_NATIVE\n        displayConfig.type = pixelroot32::graphics::DisplayType::NONE;\n        displayConfig.logicalWidth = 128;\n        displayConfig.logicalHeight = 128;\n    #endif\n\n    displayConfig.rotation = 0;\n\n    pixelroot32::core::Engine engine(displayConfig);\n    engine.init();\n    engine.run();\n}\n
"},{"location":"api_reference/graphics/display_config/#display-type-details","title":"Display Type Details","text":""},{"location":"api_reference/graphics/display_config/#st7789","title":"ST7789","text":"
  • Resolution: Typically 240x240 or 240x320
  • Interface: SPI
  • Driver: TFT_eSPI
  • Common sizes: 240x240, 240x320
"},{"location":"api_reference/graphics/display_config/#st7735","title":"ST7735","text":"
  • Resolution: Typically 128x128 or 128x160
  • Interface: SPI
  • Driver: TFT_eSPI
  • Common sizes: 128x128, 128x160
"},{"location":"api_reference/graphics/display_config/#none-native","title":"NONE (Native)","text":"
  • Platform: Native/SDL2
  • Driver: SDL2_Drawer
  • Resolution: Configurable (any size)
  • Window: Creates SDL2 window
"},{"location":"api_reference/graphics/display_config/#rotation","title":"Rotation","text":"

Display rotation values:

  • 0: Normal orientation
  • 90: Rotated 90 degrees clockwise
  • 180: Rotated 180 degrees
  • 270: Rotated 90 degrees counter-clockwise

Notes: - Rotation affects coordinate system - Some displays may not support all rotations - Test rotation on your specific hardware

"},{"location":"api_reference/graphics/display_config/#performance-considerations","title":"Performance Considerations","text":"
  • Initialization: Display initialization happens once at startup
  • Driver selection: Automatic based on platform and type
  • Memory: DisplayConfig is small (few fields)
"},{"location":"api_reference/graphics/display_config/#esp32-considerations","title":"ESP32 Considerations","text":""},{"location":"api_reference/graphics/display_config/#tft_espi-configuration","title":"TFT_eSPI Configuration","text":"

DisplayConfig uses TFT_eSPI driver. Additional configuration may be needed in platformio.ini:

build_flags =\n    -DUSER_SETUP_LOADED=1\n    -DST7789_DRIVER=1\n    -DTFT_WIDTH=240\n    -DTFT_HEIGHT=240\n    # ... pin configuration\n
"},{"location":"api_reference/graphics/display_config/#pin-configuration","title":"Pin Configuration","text":"

GPIO pins must be configured separately (not in DisplayConfig):

  • MOSI: Data pin
  • SCLK: Clock pin
  • DC: Data/Command pin
  • RST: Reset pin
  • CS: Chip select pin (optional)
"},{"location":"api_reference/graphics/display_config/#see-also","title":"See Also","text":"
  • Renderer - Rendering system
  • Camera2D - Camera that uses display dimensions
  • Manual - Platforms and Drivers
  • API Overview
"},{"location":"api_reference/graphics/font/","title":"Font","text":"

Descriptor for a bitmap font using 1bpp sprites.

"},{"location":"api_reference/graphics/font/#description","title":"Description","text":"

A Font contains an array of Sprite structures, one for each character in the font's character set. Each glyph is rendered as a 1bpp sprite, allowing consistent rendering across platforms.

The font uses fixed-width glyphs for simplicity and performance. All glyphs share the same width and height, with spacing between characters controlled by the spacing field.

"},{"location":"api_reference/graphics/font/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    struct Font {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/font/#structure","title":"Structure","text":""},{"location":"api_reference/graphics/font/#const-sprite-glyphs","title":"const Sprite* glyphs","text":"

Array of sprites, one per character (indexed by character code - firstChar).

Type: const Sprite*

Access: Read-only

Notes: - Array must contain sprites for all characters from firstChar to lastChar - Each sprite represents one character glyph - Should be stored in flash (const/constexpr) for best performance

Example:

static const Sprite FONT_GLYPHS[] = {\n    spaceGlyph,    // Index 0 = ' ' (firstChar = 32)\n    exclamationGlyph, // Index 1 = '!'\n    // ... more glyphs\n};\n\nstatic const Font myFont = {\n    FONT_GLYPHS,\n    32,  // firstChar\n    126, // lastChar\n    5,   // glyphWidth\n    7,   // glyphHeight\n    1,   // spacing\n    8    // lineHeight\n};\n

"},{"location":"api_reference/graphics/font/#uint8_t-firstchar","title":"uint8_t firstChar","text":"

First character code in the font.

Type: uint8_t

Access: Read-only

Default: Typically 32 (space character)

Notes: - ASCII code of the first character - Common: 32 (space ' ') for ASCII fonts - Glyphs array starts at index 0 for this character

Example:

firstChar = 32;  // Starts at space character\n

"},{"location":"api_reference/graphics/font/#uint8_t-lastchar","title":"uint8_t lastChar","text":"

Last character code in the font.

Type: uint8_t

Access: Read-only

Default: Typically 126 (tilde '~')

Notes: - ASCII code of the last character - Common: 126 (tilde '~') for full ASCII fonts - Glyphs array must contain (lastChar - firstChar + 1) sprites

Example:

lastChar = 126;  // Ends at tilde character\n// Font contains characters 32-126 (95 characters)\n

"},{"location":"api_reference/graphics/font/#uint8_t-glyphwidth","title":"uint8_t glyphWidth","text":"

Fixed width of each glyph in pixels.

Type: uint8_t

Access: Read-only

Notes: - All glyphs must have the same width - Typical values: 5, 6, 8 pixels - Smaller = more characters per line, less readable

Example:

glyphWidth = 5;  // 5 pixels wide (like FONT_5X7)\n

"},{"location":"api_reference/graphics/font/#uint8_t-glyphheight","title":"uint8_t glyphHeight","text":"

Fixed height of each glyph in pixels.

Type: uint8_t

Access: Read-only

Notes: - All glyphs must have the same height - Typical values: 7, 8, 10 pixels - Smaller = more lines, less readable

Example:

glyphHeight = 7;  // 7 pixels tall (like FONT_5X7)\n

"},{"location":"api_reference/graphics/font/#uint8_t-spacing","title":"uint8_t spacing","text":"

Horizontal spacing between characters in pixels.

Type: uint8_t

Access: Read-only

Default: Typically 1

Notes: - Space added between characters - 0 = no spacing (characters touch) - 1 = 1 pixel gap (common) - Higher values = more readable but wider text

Example:

spacing = 1;  // 1 pixel between characters\n

"},{"location":"api_reference/graphics/font/#uint8_t-lineheight","title":"uint8_t lineHeight","text":"

Total line height including vertical spacing.

Type: uint8_t

Access: Read-only

Notes: - Should be glyphHeight + verticalSpacing - Used for line breaks and multi-line text - Typical: glyphHeight + 1 or glyphHeight + 2

Example:

lineHeight = 8;  // 7 pixel glyph + 1 pixel spacing\n

"},{"location":"api_reference/graphics/font/#built-in-fonts","title":"Built-in Fonts","text":""},{"location":"api_reference/graphics/font/#font_5x7","title":"FONT_5X7","text":"

Standard 5x7 pixel font (built-in).

Properties: - Width: 5 pixels - Height: 7 pixels - Characters: Typically ASCII 32-126 - Spacing: 1 pixel - Line height: 8 pixels

Usage:

#include \"graphics/Font.h\"\n\nrenderer.drawText(\"Hello\", 10, 10, Color::White, 1, &FONT_5X7);\n

"},{"location":"api_reference/graphics/font/#creating-custom-fonts","title":"Creating Custom Fonts","text":""},{"location":"api_reference/graphics/font/#step-1-create-glyph-sprites","title":"Step 1: Create Glyph Sprites","text":"
// Space character (ASCII 32)\nstatic const uint16_t SPACE_GLYPH[] = {\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000,\n    0b00000\n};\n\n// 'A' character (ASCII 65)\nstatic const uint16_t A_GLYPH[] = {\n    0b00100,\n    0b01010,\n    0b10001,\n    0b11111,\n    0b10001,\n    0b10001,\n    0b00000\n};\n\n// ... more glyphs\n
"},{"location":"api_reference/graphics/font/#step-2-create-glyph-array","title":"Step 2: Create Glyph Array","text":"
static const Sprite FONT_GLYPHS[] = {\n    {SPACE_GLYPH, 5, 7},  // Index 0 = ' ' (32)\n    // ... more glyphs\n    {A_GLYPH, 5, 7},      // Index 33 = 'A' (65)\n    // ... more glyphs\n};\n
"},{"location":"api_reference/graphics/font/#step-3-create-font-structure","title":"Step 3: Create Font Structure","text":"
static const Font MY_FONT = {\n    FONT_GLYPHS,  // glyphs array\n    32,           // firstChar (space)\n    126,          // lastChar (tilde)\n    5,            // glyphWidth\n    7,            // glyphHeight\n    1,            // spacing\n    8             // lineHeight\n};\n
"},{"location":"api_reference/graphics/font/#step-4-use-font","title":"Step 4: Use Font","text":"
renderer.drawText(\"Hello\", 10, 10, Color::White, 1, &MY_FONT);\n
"},{"location":"api_reference/graphics/font/#usage-example","title":"Usage Example","text":"
#include \"graphics/Font.h\"\n#include \"graphics/Renderer.h\"\n\n// Using built-in font\nvoid draw(Renderer& renderer) override {\n    // Default font\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n\n    // Explicit font\n    renderer.drawText(\"Score: 100\", 10, 30, Color::White, 1, &FONT_5X7);\n\n    // Centered text with font\n    renderer.drawTextCentered(\"Game Over\", 64, Color::Yellow, 2, &FONT_5X7);\n}\n\n// Custom font example\nstatic const uint16_t CUSTOM_GLYPHS[][7] = {\n    // Space, A, B, C, etc.\n};\n\nstatic const Sprite CUSTOM_SPRITES[] = {\n    {CUSTOM_GLYPHS[0], 6, 8},  // Space\n    {CUSTOM_GLYPHS[1], 6, 8},  // A\n    // ... more\n};\n\nstatic const Font CUSTOM_FONT = {\n    CUSTOM_SPRITES,\n    32,   // firstChar\n    90,   // lastChar (A-Z only)\n    6,    // width\n    8,    // height\n    1,    // spacing\n    9     // lineHeight\n};\n\nvoid draw(Renderer& renderer) override {\n    renderer.drawText(\"CUSTOM\", 10, 10, Color::White, 1, &CUSTOM_FONT);\n}\n
"},{"location":"api_reference/graphics/font/#text-sizing","title":"Text Sizing","text":"

Calculate text dimensions:

int getTextWidth(const Font* font, const char* text) {\n    if (!font || !text) return 0;\n\n    int width = 0;\n    for (int i = 0; text[i] != '\\0'; i++) {\n        if (text[i] >= font->firstChar && text[i] <= font->lastChar) {\n            width += font->glyphWidth + font->spacing;\n        }\n    }\n    return width - font->spacing;  // Remove last spacing\n}\n\nint getTextHeight(const Font* font) {\n    return font ? font->lineHeight : 8;\n}\n
"},{"location":"api_reference/graphics/font/#performance-considerations","title":"Performance Considerations","text":"
  • Font storage: Store fonts in flash (const/constexpr) for best performance
  • Glyph lookup: Fast array access (character code - firstChar)
  • Fixed width: Fixed-width fonts are faster than variable-width
  • Font switching: Changing fonts is fast (just pointer assignment)
"},{"location":"api_reference/graphics/font/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store font data in flash, not RAM
  • Font size: Larger fonts use more flash memory
  • Character range: Limit character range to save memory if not needed
"},{"location":"api_reference/graphics/font/#see-also","title":"See Also","text":"
  • Renderer - Rendering system that uses fonts
  • Sprite - Sprite structure used for glyphs
  • Manual - Basic Rendering
  • API Overview
"},{"location":"api_reference/graphics/renderer/","title":"Renderer","text":"

High-level graphics rendering system for drawing shapes, text, sprites, and tilemaps.

"},{"location":"api_reference/graphics/renderer/#description","title":"Description","text":"

The Renderer class provides a unified API for drawing shapes, text, and images. It abstracts the underlying hardware implementation (DrawSurface) and manages display configuration, including rotation and resolution scaling.

All drawing operations are performed in logical screen space. If the logical resolution differs from the physical resolution, the renderer will automatically scale the output to fit the display using a high-performance nearest-neighbor algorithm.

The renderer uses integer-only math for optimal performance on ESP32 and supports multiple sprite formats (1bpp, 2bpp, 4bpp) and multi-layer sprites.

"},{"location":"api_reference/graphics/renderer/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    class Renderer {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/renderer/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Engine (manages renderer instance)
"},{"location":"api_reference/graphics/renderer/#constructors","title":"Constructors","text":""},{"location":"api_reference/graphics/renderer/#rendererconst-displayconfig-config","title":"Renderer(const DisplayConfig& config)","text":"

Constructs the Renderer with a specific display configuration.

Parameters: - config (const DisplayConfig&): The display configuration settings (width, height, rotation, etc.)

Example:

#include \"graphics/Renderer.h\"\n#include \"graphics/DisplayConfig.h\"\n\n// 128x128 game logic scaled to 240x240 display\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::ST7789,\n    0,      // rotation\n    240, 240, // physical resolution\n    128, 128  // logical resolution (rendering space)\n);\n\npixelroot32::graphics::Renderer renderer(config);\nrenderer.init();\n

"},{"location":"api_reference/graphics/renderer/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/graphics/renderer/#void-init","title":"void init()","text":"

Initializes the renderer and the underlying draw surface.

Returns: - void

Notes: - Must be called after construction and before any drawing operations - Initializes the platform-specific DrawSurface implementation - Safe to call multiple times (idempotent)

Example:

Renderer renderer(displayConfig);\nrenderer.init();  // Initialize before use\n

"},{"location":"api_reference/graphics/renderer/#void-beginframe","title":"void beginFrame()","text":"

Prepares the buffer for a new frame (clears screen).

Returns: - void

Notes: - Should be called once at the start of each frame - Clears the display buffer - Typically called automatically by Engine, but can be called manually

Example:

void draw(Renderer& renderer) override {\n    renderer.beginFrame();\n    // Draw everything...\n    renderer.endFrame();\n}\n

"},{"location":"api_reference/graphics/renderer/#void-endframe","title":"void endFrame()","text":"

Finalizes the frame and sends the buffer to the display.

Returns: - void

Notes: - Should be called once at the end of each frame - Sends the completed frame buffer to the display - Typically called automatically by Engine, but can be called manually

"},{"location":"api_reference/graphics/renderer/#void-setoffsetbypassbool-bypass","title":"void setOffsetBypass(bool bypass)","text":"

Enables or disables camera offset bypass.

Parameters: - bypass (bool): true to ignore global offsets, false to apply them.

Notes: - When enabled, all subsequent draw calls will ignore xOffset and yOffset. - Useful for drawing fixed UI elements that should not move with the camera.

"},{"location":"api_reference/graphics/renderer/#bool-isoffsetbypassenabled-const","title":"bool isOffsetBypassEnabled() const","text":"

Checks if the offset bypass is currently active.

Returns: - bool: true if bypass is enabled.

"},{"location":"api_reference/graphics/renderer/#drawsurface-getdrawsurface","title":"DrawSurface& getDrawSurface()","text":"

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed unless implementing custom drawing - Provides low-level access to the display driver

"},{"location":"api_reference/graphics/renderer/#void-drawtextconst-char-text-int16_t-x-int16_t-y-color-color-uint8_t-size","title":"void drawText(const char* text, int16_t x, int16_t y, Color color, uint8_t size)","text":"

Draws a string of text using the default font and scaling.

Parameters: - text (const char*): The text to draw (null-terminated string) - x (int16_t): X coordinate (top-left corner of text) - y (int16_t): Y coordinate (top-left corner of text) - color (Color): Text color - size (uint8_t): Text size multiplier (1 = 5x7 pixels, 2 = 10x14 pixels, etc.)

Performance Notes: - Efficient for small amounts of text - Uses integer-only scaling (no floats)

Example:

renderer.drawText(\"Hello World\", 10, 10, Color::White, 1);\nrenderer.drawText(\"Score: 100\", 10, 30, Color::Yellow, 2);\n

"},{"location":"api_reference/graphics/renderer/#void-drawtextconst-char-text-int16_t-x-int16_t-y-color-color-uint8_t-size-const-font-font","title":"void drawText(const char text, int16_t x, int16_t y, Color color, uint8_t size, const Font font)","text":"

Draws a string of text using a specific font and scaling.

Parameters: - text (const char): The text to draw - x (int16_t): X coordinate - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size multiplier - font (const Font): Pointer to the font to use. If nullptr, uses the default font

Example:

const Font* customFont = &FONT_5X7;\nrenderer.drawText(\"Custom Font\", 10, 10, Color::White, 1, customFont);\n

"},{"location":"api_reference/graphics/renderer/#void-drawtextcenteredconst-char-text-int16_t-y-color-color-uint8_t-size","title":"void drawTextCentered(const char* text, int16_t y, Color color, uint8_t size)","text":"

Draws text centered horizontally at a given Y coordinate using the default font.

Parameters: - text (const char*): The text to draw - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size

Example:

renderer.drawTextCentered(\"Game Over\", 64, Color::White, 2);\n

"},{"location":"api_reference/graphics/renderer/#void-drawtextcenteredconst-char-text-int16_t-y-color-color-uint8_t-size-const-font-font","title":"void drawTextCentered(const char text, int16_t y, Color color, uint8_t size, const Font font)","text":"

Draws text centered horizontally at a given Y coordinate using a specific font.

Parameters: - text (const char): The text to draw - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size - font (const Font): Pointer to the font to use. If nullptr, uses the default font

"},{"location":"api_reference/graphics/renderer/#void-drawfilledcircleint-x-int-y-int-radius-color-color","title":"void drawFilledCircle(int x, int y, int radius, Color color)","text":"

Draws a filled circle.

Parameters: - x (int): Center X coordinate - y (int): Center Y coordinate - radius (int): Radius of the circle in pixels - color (Color): Fill color

Example:

renderer.drawFilledCircle(64, 64, 20, Color::Red);\n

"},{"location":"api_reference/graphics/renderer/#void-drawcircleint-x-int-y-int-radius-color-color","title":"void drawCircle(int x, int y, int radius, Color color)","text":"

Draws a circle outline.

Parameters: - x (int): Center X coordinate - y (int): Center Y coordinate - radius (int): Radius of the circle in pixels - color (Color): Outline color

Example:

renderer.drawCircle(64, 64, 20, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-drawrectangleint-x-int-y-int-width-int-height-color-color","title":"void drawRectangle(int x, int y, int width, int height, Color color)","text":"

Draws a rectangle outline.

Parameters: - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - width (int): Width of the rectangle in pixels - height (int): Height of the rectangle in pixels - color (Color): Outline color

Example:

renderer.drawRectangle(10, 10, 100, 50, Color::Blue);\n

"},{"location":"api_reference/graphics/renderer/#void-drawfilledrectangleint-x-int-y-int-width-int-height-color-color","title":"void drawFilledRectangle(int x, int y, int width, int height, Color color)","text":"

Draws a filled rectangle.

Parameters: - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - width (int): Width of the rectangle in pixels - height (int): Height of the rectangle in pixels - color (Color): Fill color

Example:

renderer.drawFilledRectangle(10, 10, 100, 50, Color::Green);\n

"},{"location":"api_reference/graphics/renderer/#void-drawlineint-x1-int-y1-int-x2-int-y2-color-color","title":"void drawLine(int x1, int y1, int x2, int y2, Color color)","text":"

Draws a line between two points.

Parameters: - x1 (int): Start X coordinate - y1 (int): Start Y coordinate - x2 (int): End X coordinate - y2 (int): End Y coordinate - color (Color): Line color

Example:

renderer.drawLine(0, 0, 128, 128, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-drawpixelint-x-int-y-color-color","title":"void drawPixel(int x, int y, Color color)","text":"

Draws a single pixel.

Parameters: - x (int): X coordinate - y (int): Y coordinate - color (Color): Pixel color

Performance Notes: - Very fast, but avoid calling thousands of times per frame - Use for special effects or debugging

Example:

renderer.drawPixel(64, 64, Color::Red);\n

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite-sprite-int-x-int-y-color-color-bool-flipx-false","title":"void drawSprite(const Sprite& sprite, int x, int y, Color color, bool flipX = false)","text":"

Draws a 1bpp monochrome sprite using the Sprite descriptor.

Parameters: - sprite (const Sprite&): Sprite descriptor (data, width, height) - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space - color (Color): Color used for \"on\" pixels - flipX (bool, optional): If true, sprite is mirrored horizontally. Default: false

Performance Notes: - Very efficient for 1bpp sprites (integer-only operations) - Sprite data should be stored in flash (const/constexpr) for best performance

Example:

renderer.drawSprite(playerSprite, 100, 100, Color::White);\nrenderer.drawSprite(playerSprite, 120, 100, Color::White, true);  // Flipped\n

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite-sprite-int-x-int-y-float-scalex-float-scaley-color-color-bool-flipx-false","title":"void drawSprite(const Sprite& sprite, int x, int y, float scaleX, float scaleY, Color color, bool flipX = false)","text":"

Draws a scaled 1bpp monochrome sprite using nearest-neighbor scaling.

Parameters: - sprite (const Sprite&): Sprite descriptor - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - scaleX (float): Horizontal scaling factor (e.g., 2.0 for double width) - scaleY (float): Vertical scaling factor - color (Color): Color used for \"on\" pixels - flipX (bool, optional): If true, sprite is mirrored horizontally before scaling. Default: false

Performance Notes: - Slower than non-scaled version due to scaling calculations - The destination size is calculated as ceil(width * scaleX) x ceil(height * scaleY)

Example:

renderer.drawSprite(playerSprite, 100, 100, 2.0f, 2.0f, Color::White);  // 2x size\n

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite2bpp-sprite-int-x-int-y-bool-flipx-false","title":"void drawSprite(const Sprite2bpp& sprite, int x, int y, bool flipX = false)","text":"

Draws a 2bpp sprite. Available when PIXELROOT32_ENABLE_2BPP_SPRITES is defined.

Parameters: - sprite (const Sprite2bpp&): 2bpp sprite descriptor - x (int): X coordinate - y (int): Y coordinate - flipX (bool, optional): Horizontal flip. Default: false

"},{"location":"api_reference/graphics/renderer/#void-drawspriteconst-sprite4bpp-sprite-int-x-int-y-bool-flipx-false","title":"void drawSprite(const Sprite4bpp& sprite, int x, int y, bool flipX = false)","text":"

Draws a 4bpp sprite. Available when PIXELROOT32_ENABLE_4BPP_SPRITES is defined.

Parameters: - sprite (const Sprite4bpp&): 4bpp sprite descriptor - x (int): X coordinate - y (int): Y coordinate - flipX (bool, optional): Horizontal flip. Default: false

"},{"location":"api_reference/graphics/renderer/#void-drawmultispriteconst-multisprite-sprite-int-x-int-y","title":"void drawMultiSprite(const MultiSprite& sprite, int x, int y)","text":"

Draws a multi-layer sprite composed of several 1bpp layers.

Parameters: - sprite (const MultiSprite&): Multi-layer sprite descriptor - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space

Performance Notes: - Each layer is rendered separately, so more layers = more draw calls - Still efficient as each layer uses 1bpp format - Use for multi-color sprites without higher bit-depths

Example:

static const SpriteLayer layers[] = {\n    { outlineData, Color::Black },\n    { fillData, Color::Red },\n    { highlightData, Color::Yellow }\n};\n\nstatic const MultiSprite playerMultiSprite = {\n    8,      // width\n    8,      // height\n    layers, // layers array\n    3       // layer count\n};\n\nrenderer.drawMultiSprite(playerMultiSprite, 100, 100);\n

"},{"location":"api_reference/graphics/renderer/#void-drawmultispriteconst-multisprite-sprite-int-x-int-y-float-scalex-float-scaley","title":"void drawMultiSprite(const MultiSprite& sprite, int x, int y, float scaleX, float scaleY)","text":"

Draws a scaled multi-layer sprite.

Parameters: - sprite (const MultiSprite&): Multi-layer sprite descriptor - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - scaleX (float): Horizontal scaling factor - scaleY (float): Vertical scaling factor

"},{"location":"api_reference/graphics/renderer/#void-drawtilemapconst-tilemap-map-int-originx-int-originy-color-color","title":"void drawTileMap(const TileMap& map, int originX, int originY, Color color)","text":"

Draws a 1bpp tilemap.

Parameters: - map (const TileMap&): Tilemap descriptor (indices, 1bpp tiles, dimensions) - originX (int): X coordinate of the top-left corner - originY (int): Y coordinate of the top-left corner - color (Color): Color used for all tiles in the map

"},{"location":"api_reference/graphics/renderer/#void-drawtilemapconst-tilemap2bpp-map-int-originx-int-originy","title":"void drawTileMap(const TileMap2bpp& map, int originX, int originY)","text":"

Draws a 2bpp tilemap. Available when PIXELROOT32_ENABLE_2BPP_SPRITES is defined.

Parameters: - map (const TileMap2bpp&): Tilemap descriptor (indices, 2bpp tiles, dimensions) - originX (int): X coordinate - originY (int): Y coordinate

"},{"location":"api_reference/graphics/renderer/#void-drawtilemapconst-tilemap4bpp-map-int-originx-int-originy","title":"void drawTileMap(const TileMap4bpp& map, int originX, int originY)","text":"

Draws a 4bpp tilemap. Available when PIXELROOT32_ENABLE_4BPP_SPRITES is defined.

Parameters: - map (const TileMap4bpp&): Tilemap descriptor (indices, 4bpp tiles, dimensions) - originX (int): X coordinate - originY (int): Y coordinate

Performance Notes: - Very efficient for rendering large backgrounds - Only visible tiles are drawn (viewport culling) - Use tilemaps instead of individual sprites for backgrounds

Example:

static const uint8_t levelIndices[] = {\n    0, 1, 2, 3,\n    4, 5, 6, 7,\n    // ... more rows\n};\n\nstatic const TileMap levelMap = {\n    levelIndices,\n    16,        // width in tiles\n    16,        // height in tiles\n    tileSprites, // tile sprite array\n    8,         // tile width\n    8,         // tile height\n    16         // tile count\n};\n\nrenderer.drawTileMap(levelMap, 0, 0, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#int-getlogicalwidth-const","title":"int getLogicalWidth() const","text":"

Gets the logical rendering width.

Returns: - int: The width of the logical screen space.

"},{"location":"api_reference/graphics/renderer/#int-getlogicalheight-const","title":"int getLogicalHeight() const","text":"

Gets the logical rendering height.

Returns: - int: The height of the logical screen space.

Note: These methods replace the deprecated getWidth() and getHeight().

"},{"location":"api_reference/graphics/renderer/#void-setdisplayoffsetint-x-int-y","title":"void setDisplayOffset(int x, int y)","text":"

Sets a global offset for all drawing operations. Useful for camera/parallax effects.

Parameters: - x (int): X offset in pixels - y (int): Y offset in pixels

Notes: - All subsequent drawing operations are offset by this amount - Useful for camera scrolling and parallax effects - Reset to (0, 0) to disable offset

Example:

// Camera scrolling\ncamera.setPosition(playerX - 64, playerY - 64);\nrenderer.setDisplayOffset(-camera.getX(), -camera.getY());\nrenderer.drawTileMap(background, 0, 0, Color::White);\n

"},{"location":"api_reference/graphics/renderer/#void-setdisplaysizeint-w-int-h","title":"void setDisplaySize(int w, int h)","text":"

Sets the logical display size.

Parameters: - w (int): Width in pixels - h (int): Height in pixels

Notes: - Typically set via DisplayConfig during construction - Use this to change display size at runtime if needed

"},{"location":"api_reference/graphics/renderer/#int-getwidth-const","title":"int getWidth() const","text":"

Gets the display width.

Returns: - int: Display width in pixels

"},{"location":"api_reference/graphics/renderer/#int-getheight-const","title":"int getHeight() const","text":"

Gets the display height.

Returns: - int: Display height in pixels

"},{"location":"api_reference/graphics/renderer/#int-getxoffset-const","title":"int getXOffset() const","text":"

Gets the current X display offset.

Returns: - int: X offset in pixels

"},{"location":"api_reference/graphics/renderer/#int-getyoffset-const","title":"int getYOffset() const","text":"

Gets the current Y display offset.

Returns: - int: Y offset in pixels

"},{"location":"api_reference/graphics/renderer/#void-setcontrastuint8_t-level","title":"void setContrast(uint8_t level)","text":"

Sets the display contrast (brightness).

Parameters: - level (uint8_t): Contrast level (0-255)

Notes: - Platform-specific: may not be supported on all displays - Higher values = brighter display

"},{"location":"api_reference/graphics/renderer/#void-setfontconst-uint8_t-font","title":"void setFont(const uint8_t* font)","text":"

Sets the font for text rendering.

Parameters: - font (const uint8_t*): Pointer to the font data

Notes: - Sets the default font for drawText() calls without font parameter - Use font constants like FONT_5X7 from Font.h

"},{"location":"api_reference/graphics/renderer/#usage-example","title":"Usage Example","text":"
#include \"graphics/Renderer.h\"\n#include \"graphics/DisplayConfig.h\"\n\nvoid draw(Renderer& renderer) override {\n    renderer.beginFrame();\n\n    // Draw background\n    renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n\n    // Draw sprites\n    renderer.drawSprite(playerSprite, playerX, playerY, Color::White);\n    renderer.drawSprite(enemySprite, enemyX, enemyY, Color::Red);\n\n    // Draw UI\n    renderer.drawText(\"Score: 100\", 10, 10, Color::White, 1);\n    renderer.drawTextCentered(\"Game Over\", 64, Color::Yellow, 2);\n\n    renderer.endFrame();\n}\n
"},{"location":"api_reference/graphics/renderer/#performance-considerations","title":"Performance Considerations","text":"
  • Integer-only math: All operations use integer arithmetic for ESP32 efficiency
  • Sprite storage: Store sprite data in flash (const/constexpr) for best performance
  • Batch operations: Group similar draw calls together
  • Tilemaps: Dibuja un mapa de tiles completo. Implementa viewport culling autom\u00e1tico y cach\u00e9 de paleta para m\u00e1ximo rendimiento.
  • Sprites 2bpp/4bpp: Optimizado para ESP32 (IRAM + acceso de 16 bits).
"},{"location":"api_reference/graphics/renderer/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Sprite data should be in flash, not RAM
  • Frame rate: Limit draw calls per frame for consistent FPS
  • Display offset: Use for scrolling instead of redrawing everything
"},{"location":"api_reference/graphics/renderer/#see-also","title":"See Also","text":"
  • Sprite - Sprite structure
  • MultiSprite - Multi-layer sprites
  • TileMap - Tilemap structure
  • Color - Color constants
  • DisplayConfig - Display configuration
  • Camera2D - Camera for scrolling
  • Manual - Basic Rendering
  • Manual - Sprites and Animation
  • API Overview
"},{"location":"api_reference/graphics/sprite/","title":"Sprite","text":"

Low-level bitmap descriptor and multi-layer composition for retro rendering.

"},{"location":"api_reference/graphics/sprite/#description","title":"Description","text":"

Sprites are the fundamental graphics primitive in PixelRoot32. The engine supports multiple sprite formats:

  • 1bpp (Standard): Monochrome sprites, most memory-efficient
  • 2bpp (Experimental): 4 colors per sprite
  • 4bpp (Experimental): 16 colors per sprite
  • MultiSprite: Multi-layer 1bpp sprites for multi-color effects
"},{"location":"api_reference/graphics/sprite/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    struct Sprite {\n        // ...\n    };\n\n    struct MultiSprite {\n        // ...\n    };\n\n    struct SpriteLayer {\n        // ...\n    };\n}\n
"},{"location":"api_reference/graphics/sprite/#sprite-structure-1bpp","title":"Sprite Structure (1bpp)","text":"

Compact sprite descriptor for monochrome bitmapped sprites.

"},{"location":"api_reference/graphics/sprite/#members","title":"Members","text":"
  • const uint16_t* data: Pointer to packed row data (size = height)
  • uint8_t width: Sprite width in pixels (\u2264 16)
  • uint8_t height: Sprite height in pixels
"},{"location":"api_reference/graphics/sprite/#data-format","title":"Data Format","text":"

Sprites are stored as an array of 16-bit rows. Each row packs horizontal pixels into bits:

  • Bit 0: Leftmost pixel of the row
  • Bit (width - 1): Rightmost pixel of the row
  • Bit value 1: Pixel on (colored)
  • Bit value 0: Pixel off (transparent/background)

Only the lowest width bits of each row are used.

"},{"location":"api_reference/graphics/sprite/#example","title":"Example","text":"
// 8x8 sprite (smiley face)\nstatic const uint16_t SMILEY_DATA[] = {\n    0b00111100,  // Row 0:  \u2588\u2588\u2588\u2588\n    0b01111110,  // Row 1:  \u2588\u2588\u2588\u2588\u2588\u2588\n    0b11011011,  // Row 2:  \u2588\u2588 \u2588\u2588 \u2588\u2588\n    0b11111111,  // Row 3:  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\n    0b11011011,  // Row 4:  \u2588\u2588 \u2588\u2588 \u2588\u2588\n    0b01100110,  // Row 5:  \u2588\u2588  \u2588\u2588\n    0b01111110,  // Row 6:  \u2588\u2588\u2588\u2588\u2588\u2588\n    0b00111100   // Row 7:  \u2588\u2588\u2588\u2588\n};\n\nstatic const Sprite SMILEY_SPRITE = {\n    SMILEY_DATA,\n    8,  // width\n    8   // height\n};\n
"},{"location":"api_reference/graphics/sprite/#spritelayer-structure","title":"SpriteLayer Structure","text":"

Single monochrome layer used by layered sprites.

"},{"location":"api_reference/graphics/sprite/#members_1","title":"Members","text":"
  • const uint16_t* data: Pointer to packed row data for this layer
  • Color color: Color used for \"on\" pixels in this layer
"},{"location":"api_reference/graphics/sprite/#notes","title":"Notes","text":"
  • Each layer uses the same width/height as its owning MultiSprite
  • Layers can have different colors
  • Layers are drawn in array order
"},{"location":"api_reference/graphics/sprite/#multisprite-structure","title":"MultiSprite Structure","text":"

Multi-layer, multi-color sprite built from 1bpp layers.

"},{"location":"api_reference/graphics/sprite/#members_2","title":"Members","text":"
  • uint8_t width: Sprite width in pixels (\u2264 16)
  • uint8_t height: Sprite height in pixels
  • const SpriteLayer* layers: Pointer to array of layers
  • uint8_t layerCount: Number of layers in the array
"},{"location":"api_reference/graphics/sprite/#notes_1","title":"Notes","text":"
  • Combines several 1bpp layers with different colors
  • Layers are drawn in array order
  • Enables multi-color sprites without higher bit-depths
  • More layers = more draw calls (but still efficient)
"},{"location":"api_reference/graphics/sprite/#example_1","title":"Example","text":"
// Outline layer\nstatic const uint16_t OUTLINE_DATA[] = {\n    0b11111111,\n    0b10000001,\n    0b10000001,\n    0b11111111\n};\n\n// Fill layer\nstatic const uint16_t FILL_DATA[] = {\n    0b00000000,\n    0b01111110,\n    0b01111110,\n    0b00000000\n};\n\nstatic const SpriteLayer LAYERS[] = {\n    {OUTLINE_DATA, Color::Black},  // Layer 0: Black outline\n    {FILL_DATA, Color::Red}       // Layer 1: Red fill\n};\n\nstatic const MultiSprite PLAYER_MULTISPRITE = {\n    8,      // width\n    8,      // height\n    LAYERS, // layers array\n    2       // layer count\n};\n
"},{"location":"api_reference/graphics/sprite/#sprite2bpp-structure-experimental","title":"Sprite2bpp Structure (Experimental)","text":"

2-bit per pixel sprite (4 colors).

Requires: PIXELROOT32_ENABLE_2BPP_SPRITES build flag

"},{"location":"api_reference/graphics/sprite/#members_3","title":"Members","text":"
  • const uint16_t* data: Datos empaquetados (4 p\u00edxeles por cada 8 bits, alineados a 16 bits)
  • const Color* palette: Local palette (4 colors)
  • uint8_t width: Sprite width
  • uint8_t height: Sprite height
  • uint8_t paletteSize: Number of colors (typically 4)
"},{"location":"api_reference/graphics/sprite/#notes_2","title":"Notes","text":"
  • Experimental feature
  • Uses more memory than 1bpp
  • Each pixel can be one of 4 colors from local palette
"},{"location":"api_reference/graphics/sprite/#sprite4bpp-structure-experimental","title":"Sprite4bpp Structure (Experimental)","text":"

4-bit per pixel sprite (16 colors).

Requires: PIXELROOT32_ENABLE_4BPP_SPRITES build flag

"},{"location":"api_reference/graphics/sprite/#members_4","title":"Members","text":"
  • const uint16_t* data: Datos empaquetados (2 p\u00edxeles por cada 8 bits, alineados a 16 bits)
  • const Color* palette: Local palette (16 colors)
  • uint8_t width: Sprite width
  • uint8_t height: Sprite height
  • uint8_t paletteSize: Number of colors (typically 16)
"},{"location":"api_reference/graphics/sprite/#notes_3","title":"Notes","text":"
  • Experimental feature
  • Uses more memory than 1bpp/2bpp
  • Each pixel can be one of 16 colors from local palette
"},{"location":"api_reference/graphics/sprite/#sprite-animation","title":"Sprite Animation","text":""},{"location":"api_reference/graphics/sprite/#spriteanimationframe-structure","title":"SpriteAnimationFrame Structure","text":"

Frame that can reference either a Sprite or a MultiSprite.

Members: - const Sprite* sprite: Optional pointer to a simple 1bpp sprite frame - const MultiSprite* multiSprite: Optional pointer to a layered sprite frame

Notes: - Exactly one pointer should be non-null for a valid frame - Allows same animation system for both sprite types

"},{"location":"api_reference/graphics/sprite/#spriteanimation-structure","title":"SpriteAnimation Structure","text":"

Lightweight, step-based sprite animation controller.

Members: - const SpriteAnimationFrame* frames: Pointer to immutable frame table - uint8_t frameCount: Number of frames in the table - uint8_t current: Current frame index [0, frameCount)

Methods: - void reset(): Reset to first frame - void step(): Advance to next frame (wrapping) - const SpriteAnimationFrame& getCurrentFrame() const: Get current frame - const Sprite* getCurrentSprite() const: Get current simple sprite - const MultiSprite* getCurrentMultiSprite() const: Get current multi-sprite

Example:

static const SpriteAnimationFrame WALK_FRAMES[] = {\n    {&walkFrame1, nullptr},\n    {&walkFrame2, nullptr},\n    {&walkFrame3, nullptr},\n    {&walkFrame2, nullptr}  // Loop back\n};\n\nstatic SpriteAnimation walkAnimation = {\n    WALK_FRAMES,\n    4,    // frameCount\n    0     // current\n};\n\n// In update\nwalkAnimation.step();\nconst Sprite* currentSprite = walkAnimation.getCurrentSprite();\n

"},{"location":"api_reference/graphics/sprite/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/graphics/sprite/#creating-1bpp-sprites","title":"Creating 1bpp Sprites","text":"
// 8x8 player sprite\nstatic const uint16_t PLAYER_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11011011,\n    0b11111111,\n    0b01111110,\n    0b00111100,\n    0b00011000\n};\n\nstatic const Sprite PLAYER_SPRITE = {\n    PLAYER_DATA,\n    8,  // width\n    8   // height\n};\n\n// Use in rendering\nrenderer.drawSprite(PLAYER_SPRITE, 100, 100, Color::White);\n
"},{"location":"api_reference/graphics/sprite/#creating-multisprite","title":"Creating MultiSprite","text":"
// Outline layer\nstatic const uint16_t OUTLINE[] = {\n    0b11111111,\n    0b10000001,\n    0b10000001,\n    0b11111111\n};\n\n// Fill layer\nstatic const uint16_t FILL[] = {\n    0b00000000,\n    0b01111110,\n    0b01111110,\n    0b00000000\n};\n\nstatic const SpriteLayer LAYERS[] = {\n    {OUTLINE, Color::Black},\n    {FILL, Color::Red}\n};\n\nstatic const MultiSprite ENEMY_SPRITE = {\n    8,      // width\n    8,      // height\n    LAYERS, // layers\n    2       // layer count\n};\n\n// Use in rendering\nrenderer.drawMultiSprite(ENEMY_SPRITE, 100, 100);\n
"},{"location":"api_reference/graphics/sprite/#sprite-animation_1","title":"Sprite Animation","text":"
class AnimatedActor : public pixelroot32::core::Actor {\nprivate:\n    SpriteAnimation animation;\n    unsigned long animTimer = 0;\n    unsigned long animInterval = 200;  // 200ms per frame\n\npublic:\n    void update(unsigned long deltaTime) override {\n        Actor::update(deltaTime);\n\n        animTimer += deltaTime;\n        if (animTimer >= animInterval) {\n            animTimer -= animInterval;\n            animation.step();\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        const Sprite* frame = animation.getCurrentSprite();\n        if (frame) {\n            renderer.drawSprite(*frame, \n                               static_cast<int>(x), \n                               static_cast<int>(y), \n                               Color::White);\n        }\n    }\n};\n
"},{"location":"api_reference/graphics/sprite/#sprite-flipping","title":"Sprite Flipping","text":"

Sprites can be flipped horizontally:

// Draw normal\nrenderer.drawSprite(sprite, 100, 100, Color::White, false);\n\n// Draw flipped\nrenderer.drawSprite(sprite, 100, 100, Color::White, true);\n
"},{"location":"api_reference/graphics/sprite/#performance-considerations","title":"Performance Considerations","text":"
  • 1bpp sprites: Most efficient (integer-only operations)
  • MultiSprite: Each layer is a separate draw call (still efficient)
  • 2bpp/4bpp: Experimental, uses more memory and CPU
  • Storage: Store sprite data in flash (const/constexpr) for best performance
  • Size limit: Sprites are limited to 16 pixels wide for 1bpp format
"},{"location":"api_reference/graphics/sprite/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store sprite data in flash, not RAM
  • Sprite size: Smaller sprites = faster drawing
  • Format choice: Use 1bpp when possible for best performance
  • MultiSprite: More layers = more draw calls (but acceptable)
"},{"location":"api_reference/graphics/sprite/#see-also","title":"See Also","text":"
  • Renderer - Rendering system that draws sprites
  • Color - Color constants for sprites
  • Manual - Sprites and Animation
  • API Overview
"},{"location":"api_reference/graphics/tilemap/","title":"TileMap","text":"

Generic structure for tile-based background rendering.

"},{"location":"api_reference/graphics/tilemap/#description","title":"Description","text":"

TileMapGeneric<T> is a template structure for rendering tile-based backgrounds efficiently. It supports multiple bit-depths (1bpp, 2bpp, 4bpp) by using the appropriate sprite type for tiles.

Tilemaps are ideal for large backgrounds, levels, and static environments. They support viewport culling (only visible tiles are drawn) for optimal performance.

"},{"location":"api_reference/graphics/tilemap/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics {\n    template<typename T>\n    struct TileMapGeneric {\n        // ...\n    };\n\n    using TileMap = TileMapGeneric<Sprite>;\n    using TileMap2bpp = TileMapGeneric<Sprite2bpp>;\n    using TileMap4bpp = TileMapGeneric<Sprite4bpp>;\n}\n
"},{"location":"api_reference/graphics/tilemap/#template-parameters","title":"Template Parameters","text":""},{"location":"api_reference/graphics/tilemap/#t","title":"T","text":"

The sprite type used for tiles.

Supported types: - Sprite (1bpp) - Sprite2bpp (2bpp) - Sprite4bpp (4bpp)

"},{"location":"api_reference/graphics/tilemap/#structure","title":"Structure","text":""},{"location":"api_reference/graphics/tilemap/#uint8_t-indices","title":"uint8_t* indices","text":"

Array of tile indices mapping to tile sprites.

Type: uint8_t*

Access: Read-write

Notes: - Array size = width * height - Each value is an index into the tiles array - 0 = first tile, 1 = second tile, etc. - Should be stored in flash (const) for best performance

Example:

// 16x16 tilemap (256 tiles)\nstatic const uint8_t LEVEL_INDICES[] = {\n    0, 0, 0, 0, 1, 1, 1, 1, // Row 0\n    0, 2, 2, 2, 2, 2, 2, 0, // Row 1\n    // ... more rows\n};\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-width","title":"uint8_t width","text":"

Width of the tilemap in tiles.

Type: uint8_t

Access: Read-write

Example:

width = 16;  // 16 tiles wide\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-height","title":"uint8_t height","text":"

Height of the tilemap in tiles.

Type: uint8_t

Access: Read-write

Example:

height = 16;  // 16 tiles tall\n

"},{"location":"api_reference/graphics/tilemap/#const-t-tiles","title":"const T* tiles","text":"

Array of tile sprites of type T.

Type: const T*

Access: Read-only

Notes: - Array of sprite pointers, one per unique tile - Indices reference this array - All tiles should be the same size - Should be stored in flash (const) for best performance

Example (1bpp):

static const Sprite TILE_SPRITES[] = {\n    EMPTY_TILE,   // Index 0\n    WALL_TILE,    // Index 1\n    FLOOR_TILE,   // Index 2\n    // ... more tiles\n};\n

Example (2bpp):

static const Sprite2bpp TILE_SPRITES_2BPP[] = {\n    TILE_GRASS,   // Index 0\n    TILE_DIRT,    // Index 1\n    // ... more tiles\n};\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-tilewidth","title":"uint8_t tileWidth","text":"

Width of each tile in pixels.

Type: uint8_t

Access: Read-write

Notes: - All tiles must have the same width - Common values: 8, 16 pixels - Should match sprite width

Example:

tileWidth = 8;  // 8x8 tiles\n

"},{"location":"api_reference/graphics/tilemap/#uint8_t-tileheight","title":"uint8_t tileHeight","text":"

Height of each tile in pixels.

Type: uint8_t

Access: Read-write

Notes: - All tiles must have the same height - Common values: 8, 16 pixels - Should match sprite height

Example:

tileHeight = 8;  // 8x8 tiles\n

"},{"location":"api_reference/graphics/tilemap/#uint16_t-tilecount","title":"uint16_t tileCount","text":"

Number of unique tiles in the tiles array.

Type: uint16_t

Access: Read-write

Notes: - Must match the size of the tiles array - Indices must be < tileCount

Example:

tileCount = 16;  // 16 unique tiles\n

"},{"location":"api_reference/graphics/tilemap/#creating-tilemaps","title":"Creating Tilemaps","text":""},{"location":"api_reference/graphics/tilemap/#step-1-create-tile-sprites","title":"Step 1: Create Tile Sprites","text":"
// Empty tile (index 0)\nstatic const uint16_t EMPTY_DATA[] = {\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000,\n    0b00000000\n};\n\n// Wall tile (index 1)\nstatic const uint16_t WALL_DATA[] = {\n    0b11111111,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b10000001,\n    0b11111111\n};\n\n// Floor tile (index 2)\nstatic const uint16_t FLOOR_DATA[] = {\n    0b00000000,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b01111110,\n    0b00000000\n};\n\nstatic const Sprite TILE_SPRITES[] = {\n    {EMPTY_DATA, 8, 8},  // Index 0\n    {WALL_DATA, 8, 8},   // Index 1\n    {FLOOR_DATA, 8, 8}   // Index 2\n};\n
"},{"location":"api_reference/graphics/tilemap/#step-2-create-index-array","title":"Step 2: Create Index Array","text":"
// 16x16 level (256 tiles)\n// 0 = empty, 1 = wall, 2 = floor\nstatic const uint8_t LEVEL_INDICES[] = {\n    // Row 0: Top wall\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n    // Row 1: Walls on sides\n    1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,\n    // Row 2\n    1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,\n    // ... more rows\n    // Row 15: Bottom wall\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n};\n
"},{"location":"api_reference/graphics/tilemap/#step-3-create-tilemap-structure","title":"Step 3: Create TileMap Structure","text":"
static const TileMap LEVEL_MAP = {\n    const_cast<uint8_t*>(LEVEL_INDICES),  // indices (non-const for struct)\n    16,        // width in tiles\n    16,        // height in tiles\n    TILE_SPRITES, // tile sprites array\n    8,         // tile width\n    8,         // tile height\n    3          // tile count\n};\n
"},{"location":"api_reference/graphics/tilemap/#rendering-tilemaps","title":"Rendering Tilemaps","text":"

Use Renderer::drawTileMap():

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Draw tilemap at origin (0, 0)\n    renderer.drawTileMap(LEVEL_MAP, 0, 0, Color::White);\n\n    // With camera offset\n    camera.apply(renderer);\n    renderer.drawTileMap(LEVEL_MAP, 0, 0, Color::White);\n}\n
"},{"location":"api_reference/graphics/tilemap/#viewport-culling","title":"Viewport Culling","text":"

Tilemaps automatically cull tiles outside the viewport:

  • Only visible tiles are drawn
  • Very efficient for large levels
  • Works with camera scrolling

Example:

// Large level (256x256 tiles)\n// Only tiles visible on screen are drawn\ncamera.apply(renderer);\nrenderer.drawTileMap(LARGE_LEVEL_MAP, 0, 0, Color::White);\n

"},{"location":"api_reference/graphics/tilemap/#collision-detection-with-tilemaps","title":"Collision Detection with Tilemaps","text":"

Check tile at world position:

bool isSolidTile(int worldX, int worldY, const TileMap& map) {\n    int tileX = worldX / map.tileWidth;\n    int tileY = worldY / map.tileHeight;\n\n    if (tileX < 0 || tileX >= map.width || \n        tileY < 0 || tileY >= map.height) {\n        return true;  // Outside map = solid\n    }\n\n    int index = tileY * map.width + tileX;\n    uint8_t tileIndex = map.indices[index];\n\n    // Check if tile is solid (e.g., wall = index 1)\n    return (tileIndex == 1);\n}\n
"},{"location":"api_reference/graphics/tilemap/#usage-example","title":"Usage Example","text":"
#include \"graphics/TileMap.h\"\n#include \"graphics/Renderer.h\"\n\nclass LevelScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::TileMap levelMap;\n    pixelroot32::graphics::Camera2D camera;\n\npublic:\n    void init() override {\n        // Level map is already defined (see above)\n        // Create camera\n        auto& renderer = engine.getRenderer();\n        camera = pixelroot32::graphics::Camera2D(\n            renderer.getWidth(),\n            renderer.getHeight()\n        );\n\n        // Set level boundaries\n        int levelWidth = levelMap.width * levelMap.tileWidth;\n        int levelHeight = levelMap.height * levelMap.tileHeight;\n        camera.setBounds(0.0f, levelWidth - renderer.getWidth());\n        camera.setVerticalBounds(0.0f, levelHeight - renderer.getHeight());\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Camera follows player\n        if (player) {\n            camera.followTarget(player->x, player->y);\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw tilemap (viewport culling automatic)\n        renderer.drawTileMap(levelMap, 0, 0, Color::White);\n\n        // Draw entities\n        Scene::draw(renderer);\n\n        // Reset for UI\n        renderer.setDisplayOffset(0, 0);\n    }\n\n    bool checkTileCollision(float x, float y) {\n        int tileX = static_cast<int>(x) / levelMap.tileWidth;\n        int tileY = static_cast<int>(y) / levelMap.tileHeight;\n\n        if (tileX < 0 || tileX >= levelMap.width || \n            tileY < 0 || tileY >= levelMap.height) {\n            return true;  // Outside = solid\n        }\n\n        int index = tileY * levelMap.width + tileX;\n        uint8_t tile = levelMap.indices[index];\n        return (tile == 1);  // Wall tile\n    }\n};\n
"},{"location":"api_reference/graphics/tilemap/#performance-considerations","title":"Performance Considerations","text":"
  • Viewport culling: Only visible tiles are drawn (automatic)
  • Tile reuse: Reuse tile sprites across the map
  • Index storage: Compact uint8_t indices (1 byte per tile)
  • Memory: Store indices and tiles in flash (const) for best performance
  • Tile size: Smaller tiles = more tiles to draw, but more detail
"},{"location":"api_reference/graphics/tilemap/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Store tilemap data in flash, not RAM
  • Map size: Large maps use more flash memory
  • Tile count: Limit unique tiles to save memory
  • Culling: Viewport culling is essential for large levels
"},{"location":"api_reference/graphics/tilemap/#see-also","title":"See Also","text":"
  • Renderer - Rendering system that draws tilemaps
  • Sprite - Sprite structure used for tiles
  • Camera2D - Camera for scrolling tilemaps
  • Manual - Tilemaps
  • API Overview
"},{"location":"api_reference/physics/collision_system/","title":"CollisionSystem","text":"

Manages collision detection between entities.

"},{"location":"api_reference/physics/collision_system/#description","title":"Description","text":"

CollisionSystem iterates through registered entities, checks if they are Actors, and performs AABB (Axis-Aligned Bounding Box) collision checks based on their collision layers and masks.

The system automatically filters collisions using layers and masks, avoiding unnecessary checks. When a collision is detected, it triggers the onCollision() callback on both actors.

"},{"location":"api_reference/physics/collision_system/#namespace","title":"Namespace","text":"
namespace pixelroot32::physics {\n    class CollisionSystem {\n        // ...\n    };\n}\n
"},{"location":"api_reference/physics/collision_system/#inheritance","title":"Inheritance","text":"
  • Base class: None (standalone class)
  • Used by: Scene (manages collision system instance)
"},{"location":"api_reference/physics/collision_system/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/physics/collision_system/#void-addentityentity-e","title":"void addEntity(Entity* e)","text":"

Adds an entity to the collision system.

Parameters: - e (pixelroot32::core::Entity*): Pointer to the entity to add

Returns: - void

Notes: - Only Actor entities participate in collisions - Entities are automatically added when added to Scene - Typically not called directly (handled by Scene)

Example:

// Typically handled automatically by Scene\nscene->addEntity(actor);  // Automatically added to collision system\n

"},{"location":"api_reference/physics/collision_system/#void-removeentityentity-e","title":"void removeEntity(Entity* e)","text":"

Removes an entity from the collision system.

Parameters: - e (pixelroot32::core::Entity*): Pointer to the entity to remove

Returns: - void

Notes: - Entities are automatically removed when removed from Scene - Typically not called directly

Example:

// Typically handled automatically by Scene\nscene->removeEntity(actor);  // Automatically removed from collision system\n

"},{"location":"api_reference/physics/collision_system/#void-update","title":"void update()","text":"

Performs collision detection for all registered entities.

Returns: - void

Notes: - Called automatically by Scene::update() - Iterates through all pairs of entities - Only checks collisions between Actors with matching layers/masks - Triggers onCollision() callbacks when collisions are detected - Uses AABB (Axis-Aligned Bounding Box) collision detection

Example:

// Called automatically by Scene, but can be called manually:\nvoid update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);  // Calls collisionSystem.update()\n\n    // Or manually:\n    collisionSystem.update();\n}\n

"},{"location":"api_reference/physics/collision_system/#how-it-works","title":"How It Works","text":"
  1. Entity Registration: Entities added to Scene are automatically registered
  2. Layer Filtering: Only actors with matching layers/masks are checked
  3. AABB Check: Uses Rect::intersects() for collision detection
  4. Callback: Calls onCollision() on both actors when collision detected
"},{"location":"api_reference/physics/collision_system/#collision-detection-algorithm","title":"Collision Detection Algorithm","text":"
for each actor1 in entities:\n    if actor1 is not an Actor: continue\n    for each actor2 in entities:\n        if actor2 is not an Actor: continue\n        if actor1 == actor2: continue\n\n        // Check layers/masks\n        if (actor1->layer & actor2->mask) == 0: continue\n        if (actor2->layer & actor1->mask) == 0: continue\n\n        // Check AABB intersection\n        Rect box1 = actor1->getHitBox();\n        Rect box2 = actor2->getHitBox();\n\n        if (box1.intersects(box2)) {\n            actor1->onCollision(actor2);\n            actor2->onCollision(actor1);\n        }\n
"},{"location":"api_reference/physics/collision_system/#usage-example","title":"Usage Example","text":"
#include \"physics/CollisionSystem.h\"\n#include \"core/Actor.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Create actors with collision layers\n        PlayerActor* player = new PlayerActor(64, 64);\n        player->layer = pixelroot32::physics::DefaultLayers::kPlayer;\n        player->mask = pixelroot32::physics::DefaultLayers::kEnemy | \n                       pixelroot32::physics::DefaultLayers::kObstacle;\n        addEntity(player);\n\n        EnemyActor* enemy = new EnemyActor(100, 100);\n        enemy->layer = pixelroot32::physics::DefaultLayers::kEnemy;\n        enemy->mask = pixelroot32::physics::DefaultLayers::kPlayer;\n        addEntity(enemy);\n\n        // Collision system is managed by Scene\n        // Collisions are checked automatically in Scene::update()\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Collision detection happens here automatically\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"api_reference/physics/collision_system/#performance-considerations","title":"Performance Considerations","text":"
  • Layer filtering: Very efficient; avoids most collision checks
  • AABB checks: Fast (simple rectangle intersection)
  • Pair checking: O(n\u00b2) complexity, but n is limited (MAX_ENTITIES = 32)
  • Update frequency: Called every frame; keep hitboxes simple
"},{"location":"api_reference/physics/collision_system/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Entity limit: MAX_ENTITIES = 32 limits collision pairs
  • Layer efficiency: Use layers effectively to minimize checks
  • Hitbox simplicity: Keep hitboxes as simple AABB for best performance
"},{"location":"api_reference/physics/collision_system/#see-also","title":"See Also","text":"
  • Actor - Actors that participate in collisions
  • CollisionTypes - Collision primitives and layers
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/physics/collision_types/","title":"Collision Types","text":"

Basic geometric types and collision layer definitions.

"},{"location":"api_reference/physics/collision_types/#description","title":"Description","text":"

This document describes the collision primitives (Rect, Circle, Segment) and collision layer system used by the collision detection system.

"},{"location":"api_reference/physics/collision_types/#namespace","title":"Namespace","text":"
namespace pixelroot32::physics {\n    // Types and functions\n}\n
"},{"location":"api_reference/physics/collision_types/#collisionlayer-type","title":"CollisionLayer Type","text":"

Collision layer type (bit flags).

Type: uint16_t (typedef)

Notes: - Uses bit flags for layer assignment - Actors can be on multiple layers (bitwise OR) - Masks define which layers an actor can collide with

"},{"location":"api_reference/physics/collision_types/#defaultlayers-namespace","title":"DefaultLayers Namespace","text":"

Predefined collision layers.

"},{"location":"api_reference/physics/collision_types/#knone","title":"kNone","text":"

No layer (0).

Value: 0

Usage:

actor->layer = pixelroot32::physics::DefaultLayers::kNone;\n

"},{"location":"api_reference/physics/collision_types/#kall","title":"kAll","text":"

All layers (0xFFFF).

Value: 0xFFFF

Usage:

actor->mask = pixelroot32::physics::DefaultLayers::kAll;  // Collide with everything\n

"},{"location":"api_reference/physics/collision_types/#custom-layers","title":"Custom Layers","text":"

Define custom layers using bit flags:

namespace MyLayers {\n    const pixelroot32::physics::CollisionLayer kPlayer = 1 << 0;      // Bit 0\n    const pixelroot32::physics::CollisionLayer kEnemy = 1 << 1;       // Bit 1\n    const pixelroot32::physics::CollisionLayer kObstacle = 1 << 2;    // Bit 2\n    const pixelroot32::physics::CollisionLayer kProjectile = 1 << 3;  // Bit 3\n    const pixelroot32::physics::CollisionLayer kCollectible = 1 << 4;  // Bit 4\n}\n\n// Usage\nactor->layer = MyLayers::kPlayer;\nactor->mask = MyLayers::kEnemy | MyLayers::kObstacle;\n
"},{"location":"api_reference/physics/collision_types/#circle-structure","title":"Circle Structure","text":"

Represents a circle for collision detection.

Members: - float x: Center X coordinate - float y: Center Y coordinate - float radius: Radius of the circle

Example:

pixelroot32::physics::Circle circle;\ncircle.x = 100.0f;\ncircle.y = 100.0f;\ncircle.radius = 10.0f;\n

"},{"location":"api_reference/physics/collision_types/#segment-structure","title":"Segment Structure","text":"

Represents a line segment for collision detection.

Members: - float x1, y1: Start point coordinates - float x2, y2: End point coordinates

Example:

pixelroot32::physics::Segment segment;\nsegment.x1 = 0.0f;\nsegment.y1 = 0.0f;\nsegment.x2 = 100.0f;\nsegment.y2 = 100.0f;\n

"},{"location":"api_reference/physics/collision_types/#intersection-functions","title":"Intersection Functions","text":""},{"location":"api_reference/physics/collision_types/#bool-intersectsconst-circle-a-const-circle-b","title":"bool intersects(const Circle& a, const Circle& b)","text":"

Checks if two circles intersect.

Parameters: - a (const Circle&): First circle - b (const Circle&): Second circle

Returns: - bool: true if circles intersect

Example:

pixelroot32::physics::Circle circle1{100.0f, 100.0f, 10.0f};\npixelroot32::physics::Circle circle2{110.0f, 100.0f, 10.0f};\n\nif (pixelroot32::physics::intersects(circle1, circle2)) {\n    // Circles overlap\n}\n

"},{"location":"api_reference/physics/collision_types/#bool-intersectsconst-circle-c-const-rect-r","title":"bool intersects(const Circle& c, const Rect& r)","text":"

Checks if a circle and rectangle intersect.

Parameters: - c (const Circle&): Circle - r (const Rect&): Rectangle

Returns: - bool: true if circle and rectangle intersect

Example:

pixelroot32::physics::Circle circle{100.0f, 100.0f, 10.0f};\npixelroot32::core::Rect rect{95.0f, 95.0f, 20, 20};\n\nif (pixelroot32::physics::intersects(circle, rect)) {\n    // Circle overlaps rectangle\n}\n

"},{"location":"api_reference/physics/collision_types/#bool-intersectsconst-segment-s-const-rect-r","title":"bool intersects(const Segment& s, const Rect& r)","text":"

Checks if a line segment and rectangle intersect.

Parameters: - s (const Segment&): Line segment - r (const Rect&): Rectangle

Returns: - bool: true if segment and rectangle intersect

Example:

pixelroot32::physics::Segment segment{0.0f, 0.0f, 100.0f, 100.0f};\npixelroot32::core::Rect rect{50.0f, 50.0f, 20, 20};\n\nif (pixelroot32::physics::intersects(segment, rect)) {\n    // Segment intersects rectangle\n}\n

"},{"location":"api_reference/physics/collision_types/#bool-sweepcirclevsrectconst-circle-start-const-circle-end-const-rect-target-float-thit","title":"bool sweepCircleVsRect(const Circle& start, const Circle& end, const Rect& target, float& tHit)","text":"

Performs a sweep test: checks if a moving circle collides with a rectangle.

Parameters: - start (const Circle&): Circle at start position - end (const Circle&): Circle at end position - target (const Rect&): Target rectangle - tHit (float&): Output parameter for collision time (0.0 to 1.0)

Returns: - bool: true if collision occurs during sweep

Notes: - Useful for fast-moving projectiles - tHit indicates when collision occurs (0.0 = start, 1.0 = end) - More expensive than simple AABB check

Example:

// Projectile moving from (0, 0) to (100, 100)\npixelroot32::physics::Circle start{0.0f, 0.0f, 5.0f};\npixelroot32::physics::Circle end{100.0f, 100.0f, 5.0f};\npixelroot32::core::Rect wall{50.0f, 50.0f, 20, 20};\n\nfloat tHit = 0.0f;\nif (pixelroot32::physics::sweepCircleVsRect(start, end, wall, tHit)) {\n    // Collision at time tHit\n    float hitX = 0.0f + (100.0f - 0.0f) * tHit;\n    float hitY = 0.0f + (100.0f - 0.0f) * tHit;\n}\n

"},{"location":"api_reference/physics/collision_types/#rect-structure-from-coreentityh","title":"Rect Structure (from core/Entity.h)","text":"

Represents a 2D rectangle for collision detection.

Members: - float x, y: Top-left corner coordinates - int width, height: Dimensions

Methods: - bool intersects(const Rect& other) const: Checks if rectangles overlap

Example:

pixelroot32::core::Rect rect1{10.0f, 20.0f, 50, 50};\npixelroot32::core::Rect rect2{30.0f, 40.0f, 50, 50};\n\nif (rect1.intersects(rect2)) {\n    // Rectangles overlap\n}\n

"},{"location":"api_reference/physics/collision_types/#usage-examples","title":"Usage Examples","text":""},{"location":"api_reference/physics/collision_types/#layer-based-collision","title":"Layer-Based Collision","text":"
// Define layers\nnamespace GameLayers {\n    const pixelroot32::physics::CollisionLayer kPlayer = 1 << 0;\n    const pixelroot32::physics::CollisionLayer kEnemy = 1 << 1;\n    const pixelroot32::physics::CollisionLayer kObstacle = 1 << 2;\n    const pixelroot32::physics::CollisionLayer kProjectile = 1 << 3;\n}\n\n// Player collides with enemies and obstacles\nplayer->layer = GameLayers::kPlayer;\nplayer->mask = GameLayers::kEnemy | GameLayers::kObstacle;\n\n// Enemy collides with player and obstacles\nenemy->layer = GameLayers::kEnemy;\nenemy->mask = GameLayers::kPlayer | GameLayers::kObstacle;\n\n// Projectile collides with enemies only\nprojectile->layer = GameLayers::kProjectile;\nprojectile->mask = GameLayers::kEnemy;\n
"},{"location":"api_reference/physics/collision_types/#circle-vs-circle-collision","title":"Circle vs Circle Collision","text":"
bool checkCollision(const Circle& a, const Circle& b) {\n    return pixelroot32::physics::intersects(a, b);\n}\n
"},{"location":"api_reference/physics/collision_types/#sweep-test-for-fast-projectiles","title":"Sweep Test for Fast Projectiles","text":"
class ProjectileActor : public pixelroot32::core::Actor {\nprivate:\n    float startX, startY;\n    float endX, endY;\n    float radius = 2.0f;\n\npublic:\n    bool checkWallCollision(const Rect& wall) {\n        pixelroot32::physics::Circle start{startX, startY, radius};\n        pixelroot32::physics::Circle end{endX, endY, radius};\n\n        float tHit = 0.0f;\n        if (pixelroot32::physics::sweepCircleVsRect(start, end, wall, tHit)) {\n            // Collision detected at time tHit\n            return true;\n        }\n        return false;\n    }\n};\n
"},{"location":"api_reference/physics/collision_types/#performance-considerations","title":"Performance Considerations","text":"
  • AABB checks: Very fast (simple rectangle intersection)
  • Circle checks: Slightly slower (distance calculation)
  • Sweep tests: More expensive (use only for fast-moving objects)
  • Layer filtering: Essential for performance with many actors
"},{"location":"api_reference/physics/collision_types/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Float math: Uses floating point; acceptable but integer math would be faster
  • Sweep tests: Use sparingly (more CPU intensive)
  • Layer efficiency: Use layers effectively to minimize checks
"},{"location":"api_reference/physics/collision_types/#see-also","title":"See Also","text":"
  • CollisionSystem - Collision detection system
  • Actor - Actors that use collision layers
  • Manual - Physics and Collisions
  • API Overview
"},{"location":"api_reference/ui/ui_button/","title":"UIButton","text":"

A clickable button UI element.

"},{"location":"api_reference/ui/ui_button/#description","title":"Description","text":"

UIButton is a clickable button that supports both physical (keyboard/gamepad) and touch input. It can trigger a callback function when pressed and integrates with UI layouts for automatic navigation.

Buttons support selection state (for D-pad navigation), custom styling, and text alignment.

"},{"location":"api_reference/ui/ui_button/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIButton : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_button/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom button classes (if needed)
"},{"location":"api_reference/ui/ui_button/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_button/#uibuttonstring-t-uint8_t-index-float-x-float-y-float-w-float-h-function-callback-textalignment-textalign-center-int-fontsize-2","title":"UIButton(string t, uint8_t index, float x, float y, float w, float h, function callback, TextAlignment textAlign = CENTER, int fontSize = 2)

Constructs a new UIButton.

Parameters: - t (std::string): Button label text - index (uint8_t): Navigation index (for D-pad navigation in layouts) - x (float): X position - y (float): Y position - w (float): Width - h (float): Height - callback (std::function): Function to call when clicked/pressed - textAlign (TextAlignment, optional): Text alignment. Default: CENTER - fontSize (int, optional): Text size multiplier. Default: 2

Example:

#include \"graphics/ui/UIButton.h\"\n\nvoid onStartButtonClicked() {\n    // Start game\n    engine.setScene(&gameScene);\n}\n\nvoid onQuitButtonClicked() {\n    // Quit game\n    engine.stop();\n}\n\n// Create buttons\npixelroot32::graphics::ui::UIButton* startButton = new pixelroot32::graphics::ui::UIButton(\n    \"Start\",\n    0,  // index\n    64.0f, 64.0f,  // position\n    100.0f, 30.0f, // size\n    onStartButtonClicked,\n    pixelroot32::graphics::ui::TextAlignment::CENTER,\n    2\n);\n\npixelroot32::graphics::ui::UIButton* quitButton = new pixelroot32::graphics::ui::UIButton(\n    \"Quit\",\n    1,  // index\n    64.0f, 100.0f,\n    100.0f, 30.0f,\n    onQuitButtonClicked\n);\n

","text":""},{"location":"api_reference/ui/ui_button/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_button/#void-setstylecolor-textcol-color-bgcol-bool-drawbg","title":"void setStyle(Color textCol, Color bgCol, bool drawBg)

Configures the button's visual style.

Parameters: - textCol (Color): Color of the text - bgCol (Color): Color of the background - drawBg (bool): Whether to draw the background rectangle

Returns: - void

Example:

button->setStyle(\n    pixelroot32::graphics::Color::White,  // Text color\n    pixelroot32::graphics::Color::Blue,   // Background color\n    true                                   // Draw background\n);\n

","text":""},{"location":"api_reference/ui/ui_button/#void-setselectedbool-selected","title":"void setSelected(bool selected)

Sets the selection state (e.g., focused via D-pad).

Parameters: - selected (bool): true if selected

Returns: - void

Notes: - Used by layouts for D-pad navigation - Selected buttons typically have different visual style - Can be set manually or automatically by layouts

Example:

button->setSelected(true);  // Highlight button\n

","text":""},{"location":"api_reference/ui/ui_button/#bool-getselected-const","title":"bool getSelected() const

Checks if the button is currently selected.

Returns: - bool: true if selected

Example:

if (button->getSelected()) {\n    // Button is focused\n}\n

","text":""},{"location":"api_reference/ui/ui_button/#bool-isfocusable-const-override","title":"bool isFocusable() const override

Returns true (Buttons are always focusable).

Returns: - bool: Always true

","text":""},{"location":"api_reference/ui/ui_button/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)

Handles input events. Checks for touch events within bounds or confirmation buttons if selected.

Parameters: - input (const pixelroot32::input::InputManager&): The input manager instance

Returns: - void

Notes: - Should be called every frame in update() - Checks if button is selected and action button is pressed - Triggers callback if conditions are met

Example:

void update(unsigned long deltaTime) override {\n    UIElement::update(deltaTime);\n\n    auto& input = engine.getInputManager();\n    button->handleInput(input);\n}\n

","text":""},{"location":"api_reference/ui/ui_button/#void-press","title":"void press()

Manually triggers the button's action.

Returns: - void

Notes: - Calls the button's callback function - Useful for programmatic button presses

Example:

button->press();  // Trigger button action\n

","text":""},{"location":"api_reference/ui/ui_button/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override

Updates the button state.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Handles input and updates button state - Override to add custom update logic

Example:

void update(unsigned long deltaTime) override {\n    UIButton::update(deltaTime);\n\n    // Custom update logic\n    if (shouldPulse) {\n        // Animate button\n    }\n}\n

","text":""},{"location":"api_reference/ui/ui_button/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override

Renders the button.

Parameters: - renderer (pixelroot32::graphics::Renderer&): The renderer to use

Returns: - void

Notes: - Called automatically by Scene if isVisible is true - Draws background (if enabled) and text - Selected state may change appearance

Example:

// Drawing is handled automatically\n// Override only for custom rendering\n

","text":""},{"location":"api_reference/ui/ui_button/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIButton.h\"\n#include \"core/Scene.h\"\n\nclass MainMenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIButton* startButton;\n    pixelroot32::graphics::ui::UIButton* quitButton;\n\npublic:\n    void init() override {\n        // Start button\n        startButton = new pixelroot32::graphics::ui::UIButton(\n            \"Start Game\",\n            0,  // index\n            64.0f, 50.0f,  // position (centered)\n            120.0f, 30.0f, // size\n            [this]() {\n                // Lambda callback\n                engine.setScene(&gameScene);\n            },\n            pixelroot32::graphics::ui::TextAlignment::CENTER,\n            2\n        );\n        startButton->setStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Blue,\n            true\n        );\n        addEntity(startButton);\n\n        // Quit button\n        quitButton = new pixelroot32::graphics::ui::UIButton(\n            \"Quit\",\n            1,  // index\n            64.0f, 90.0f,\n            120.0f, 30.0f,\n            [this]() {\n                // Quit game\n                engine.stop();\n            }\n        );\n        quitButton->setStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Red,\n            true\n        );\n        addEntity(quitButton);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Buttons handle input automatically\n        // Layouts handle navigation automatically\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background\n        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n\n        // Draw UI elements (buttons)\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"api_reference/ui/ui_button/#button-navigation","title":"Button Navigation","text":"

Buttons can be navigated with D-pad when in layouts:

// Buttons in a vertical layout\npixelroot32::graphics::ui::UIVerticalLayout* layout = new UIVerticalLayout(64.0f, 50.0f);\nlayout->addChild(startButton);  // Index 0\nlayout->addChild(quitButton);   // Index 1\n\n// D-pad navigation is automatic\n// UP/DOWN moves selection\n// Action button (A) triggers selected button\n
"},{"location":"api_reference/ui/ui_button/#performance-considerations","title":"Performance Considerations","text":"
  • Input handling: handleInput() is fast; safe to call every frame
  • Rendering: Simple rectangle and text; very efficient
  • Memory: Each button consumes memory (stay within MAX_ENTITIES)
"},{"location":"api_reference/ui/ui_button/#esp32-considerations","title":"ESP32 Considerations","text":"
  • String storage: Button labels use std::string; consider memory usage
  • Callback functions: Use function pointers or lambdas (both efficient)
"},{"location":"api_reference/ui/ui_button/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UILabel - Text label
  • UILayouts - Layout containers
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_checkbox/","title":"UICheckBox","text":"

A clickable checkbox UI element.

"},{"location":"api_reference/ui/ui_checkbox/#description","title":"Description","text":"

UICheckBox is a clickable checkbox that can be toggled between checked and unchecked states. It supports both physical (keyboard/gamepad) and touch input. It can trigger a callback function when its state changes and integrates with UI layouts for automatic navigation.

"},{"location":"api_reference/ui/ui_checkbox/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UICheckBox : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_checkbox/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
"},{"location":"api_reference/ui/ui_checkbox/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_checkbox/#uicheckboxstring-label-uint8_t-index-float-x-float-y-float-w-float-h-bool-checked-false-function-callback-nullptr-int-fontsize-2","title":"UICheckBox(string label, uint8_t index, float x, float y, float w, float h, bool checked = false, function callback = nullptr, int fontSize = 2)

Constructs a new UICheckBox.

Parameters: - label (std::string): Checkbox label text - index (uint8_t): Navigation index (for D-pad navigation in layouts) - x (float): X position - y (float): Y position - w (float): Width - h (float): Height - checked (bool, optional): Initial checked state. Default: false - callback (std::function, optional): Function to call when the state changes. Default: nullptr - fontSize (int, optional): Text size multiplier. Default: 2

Example:

#include \"graphics/ui/UICheckBox.h\"\n\nvoid onCheckChanged(bool checked) {\n    if (checked) {\n        // Sound enabled\n    } else {\n        // Sound disabled\n    }\n}\n\n// Create checkbox\npixelroot32::graphics::ui::UICheckBox* soundCheckbox = new pixelroot32::graphics::ui::UICheckBox(\n    \"Enable Sound\",\n    0,  // index\n    64.0f, 64.0f,  // position\n    120.0f, 20.0f, // size\n    true,          // initial state\n    onCheckChanged,\n    1              // font size\n);\n

","text":""},{"location":"api_reference/ui/ui_checkbox/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_checkbox/#void-setstylecolor-textcol-color-bgcol-bool-drawbg-false","title":"void setStyle(Color textCol, Color bgCol, bool drawBg = false)

Configures the checkbox's visual style.

Parameters: - textCol (Color): Color of the text - bgCol (Color): Color of the background - drawBg (bool, optional): Whether to draw the background rectangle. Default: false

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#void-setcheckedbool-checked","title":"void setChecked(bool checked)

Sets the checked state.

Parameters: - checked (bool): True if checked

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#bool-ischecked-const","title":"bool isChecked() const

Checks if the checkbox is currently checked.

Returns: - bool: true if checked

","text":""},{"location":"api_reference/ui/ui_checkbox/#void-toggle","title":"void toggle()

Toggles the checkbox state and triggers the callback.

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#void-setselectedbool-selected","title":"void setSelected(bool selected)

Sets the selection state (e.g., focused via D-pad).

Parameters: - selected (bool): True if selected

Returns: - void

","text":""},{"location":"api_reference/ui/ui_checkbox/#bool-getselected-const","title":"bool getSelected() const

Checks if the checkbox is currently selected.

Returns: - bool: true if selected

","text":""},{"location":"api_reference/ui/ui_checkbox/#callbacks","title":"Callbacks","text":""},{"location":"api_reference/ui/ui_checkbox/#oncheckchanged","title":"onCheckChanged

The onCheckChanged callback is a std::function<void(bool)> that is triggered whenever the checkbox state changes via setChecked() or toggle().

checkbox->onCheckChanged = [](bool isChecked) {\n    Serial.println(isChecked ? \"Checked!\" : \"Unchecked!\");\n};\n
","text":""},{"location":"api_reference/ui/ui_checkbox/#navigation-layouts","title":"Navigation & Layouts","text":"

UICheckBox is designed to work seamlessly with UILayout containers (like UIVerticalLayout).

  • Focusable: Returns true for isFocusable(), allowing it to receive focus in a layout.
  • Input Handling: When selected (focused), it listens for the button index provided in the constructor (typically the 'A' button) to toggle its state.
  • Visual Feedback: When selected, it displays a selection indicator (usually a > character) if no background is drawn, or highlights its text/border.
"},{"location":"api_reference/ui/ui_element/","title":"UIElement","text":"

Base class for all user interface elements.

"},{"location":"api_reference/ui/ui_element/#description","title":"Description","text":"

UIElement is the base class for all UI components (buttons, labels, panels, etc.). It inherits from Entity to integrate with the scene graph and automatically sets the entity type to UI_ELEMENT and render layer to 2 (UI layer).

"},{"location":"api_reference/ui/ui_element/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    enum class UIElementType {\n        GENERIC,\n        BUTTON,\n        LABEL,\n        CHECKBOX,\n        LAYOUT\n    };\n\n    class UIElement : public pixelroot32::core::Entity {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_element/#inheritance","title":"Inheritance","text":"
  • Inherits from: pixelroot32::core::Entity
  • Inherited by: UIButton, UICheckBox, UILabel, UIPanel, and all UI layouts
"},{"location":"api_reference/ui/ui_element/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_element/#uielementfloat-x-float-y-float-w-float-h-uielementtype-type-uielementtypegeneric","title":"UIElement(float x, float y, float w, float h, UIElementType type = UIElementType::GENERIC)","text":"

Constructs a new UIElement.

Parameters: - x (float): X position - y (float): Y position - w (float): Width - h (float): Height - type (UIElementType): The type of the element (default: GENERIC)

Notes: - Entity type is automatically set to UI_ELEMENT - Render layer is automatically set to 2 (UI layer) - Position and size can be modified after construction

Example:

class MyUIElement : public pixelroot32::graphics::ui::UIElement {\npublic:\n    MyUIElement(float x, float y) \n        : UIElement(x, y, 100.0f, 50.0f) {}\n\n    void update(unsigned long deltaTime) override {\n        // UI logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // UI rendering\n    }\n};\n

"},{"location":"api_reference/ui/ui_element/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_element/#uielementtype-gettype-const","title":"UIElementType getType() const","text":"

Returns the type of the UI element.

Returns: - UIElementType: The type enum value (GENERIC, BUTTON, LABEL, CHECKBOX, or LAYOUT)

"},{"location":"api_reference/ui/ui_element/#virtual-bool-isfocusable-const","title":"virtual bool isFocusable() const","text":"

Checks if the element is focusable/selectable. Useful for navigation logic.

Returns: - bool: true if focusable, false otherwise (default: false)

"},{"location":"api_reference/ui/ui_element/#void-setpositionfloat-newx-float-newy","title":"void setPosition(float newX, float newY)","text":"

Sets the position of the element.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Updates element position immediately - Use for manual positioning or animations

Example:

uiElement->setPosition(100.0f, 50.0f);\n

"},{"location":"api_reference/ui/ui_element/#void-setfixedpositionbool-fixed","title":"void setFixedPosition(bool fixed)","text":"

Sets whether the element is in a fixed position (HUD/Overlay).

Parameters: - fixed (bool): true to enable fixed position, false to disable.

Notes: - If true, this element (and its children if it's a container) will ignore Camera2D scroll and stay fixed at its logical screen coordinates. - This is essential for HUDs, overlays, and persistent menus.

"},{"location":"api_reference/ui/ui_element/#bool-isfixedposition-const","title":"bool isFixedPosition() const","text":"

Checks if the element is in a fixed position.

Returns: - bool: true if fixed position is enabled.

"},{"location":"api_reference/ui/ui_element/#virtual-void-getpreferredsizefloat-preferredwidth-float-preferredheight-const","title":"virtual void getPreferredSize(float& preferredWidth, float& preferredHeight) const","text":"

Gets the preferred size of the element. Used by layouts to determine how much space the element needs.

Parameters: - preferredWidth (float&): Output parameter for preferred width (or -1 if flexible) - preferredHeight (float&): Output parameter for preferred height (or -1 if flexible)

Returns: - void

Notes: - Default implementation returns current width/height - Override in derived classes for custom sizing logic - Layouts use this to arrange elements

Example:

void getPreferredSize(float& w, float& h) const override {\n    // Custom sizing logic\n    w = static_cast<float>(width);\n    h = static_cast<float>(height);\n}\n

"},{"location":"api_reference/ui/ui_element/#inherited-from-entity","title":"Inherited from Entity","text":"

UIElement inherits all properties and methods from Entity:

  • float x, y: Position
  • int width, height: Dimensions
  • bool isVisible: Visibility state
  • bool isEnabled: Enabled state
  • unsigned char renderLayer: Render layer (automatically set to 2)
  • void setVisible(bool v): Set visibility
  • void setEnabled(bool e): Set enabled state
  • virtual void update(unsigned long deltaTime): Update logic
  • virtual void draw(Renderer& renderer): Drawing logic
"},{"location":"api_reference/ui/ui_element/#textalignment-enum","title":"TextAlignment Enum","text":"

Text alignment options for UI elements.

Values: - TextAlignment::LEFT: Left-aligned text - TextAlignment::CENTER: Center-aligned text - TextAlignment::RIGHT: Right-aligned text

"},{"location":"api_reference/ui/ui_element/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIElement.h\"\n\nclass CustomUIElement : public pixelroot32::graphics::ui::UIElement {\nprivate:\n    pixelroot32::graphics::Color bgColor;\n\npublic:\n    CustomUIElement(float x, float y, float w, float h) \n        : UIElement(x, y, w, h),\n          bgColor(pixelroot32::graphics::Color::Blue) {}\n\n    void update(unsigned long deltaTime) override {\n        // Update logic (if needed)\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        if (isVisible) {\n            // Draw background\n            renderer.drawFilledRectangle(\n                static_cast<int>(x),\n                static_cast<int>(y),\n                width,\n                height,\n                bgColor\n            );\n\n            // Draw border\n            renderer.drawRectangle(\n                static_cast<int>(x),\n                static_cast<int>(y),\n                width,\n                height,\n                pixelroot32::graphics::Color::White\n            );\n        }\n    }\n\n    void getPreferredSize(float& w, float& h) const override {\n        w = static_cast<float>(width);\n        h = static_cast<float>(height);\n    }\n};\n
"},{"location":"api_reference/ui/ui_element/#performance-considerations","title":"Performance Considerations","text":"
  • Render layer: UI elements are on layer 2, drawn after gameplay
  • Visibility: Use isVisible = false to hide elements efficiently
  • Layout integration: Layouts automatically manage element positioning
"},{"location":"api_reference/ui/ui_element/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Each UI element consumes memory (stay within MAX_ENTITIES)
  • Object pooling: Reuse UI elements when possible
  • Update frequency: Disable UI elements that don't need to update
"},{"location":"api_reference/ui/ui_element/#see-also","title":"See Also","text":"
  • Entity - Base entity class
  • UIButton - Clickable button
  • UILabel - Text label
  • UILayout - Layout containers
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_label/","title":"UILabel","text":"

A simple text label UI element.

"},{"location":"api_reference/ui/ui_label/#description","title":"Description","text":"

UILabel displays a string of text on the screen. It auto-calculates its bounds based on text length and font size, making it easy to create dynamic text displays.

Labels are useful for displaying scores, status messages, menu text, and other UI information.

"},{"location":"api_reference/ui/ui_label/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UILabel : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_label/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom label classes (if needed)
"},{"location":"api_reference/ui/ui_label/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_label/#uilabelstring-t-float-x-float-y-color-col-uint8_t-sz","title":"UILabel(string t, float x, float y, Color col, uint8_t sz)","text":"

Constructs a new UILabel.

Parameters: - t (std::string): Initial text - x (float): X position - y (float): Y position - col (Color): Text color - sz (uint8_t): Text size multiplier

Example:

#include \"graphics/ui/UILabel.h\"\n\n// Create label\npixelroot32::graphics::ui::UILabel* scoreLabel = new pixelroot32::graphics::ui::UILabel(\n    \"Score: 0\",\n    10.0f, 10.0f,  // position\n    pixelroot32::graphics::Color::White,\n    1  // size\n);\n\n// Add to scene\nscene->addEntity(scoreLabel);\n

"},{"location":"api_reference/ui/ui_label/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_label/#void-settextconst-string-t","title":"void setText(const string& t)","text":"

Updates the label's text. Recalculates dimensions immediately using the active font metrics to ensure precise layout.

Parameters: - t (const std::string&): New text

Returns: - void

Notes: - Automatically recalculates width and height using FontManager::textWidth - Use for dynamic text (scores, timers, etc.) - Text is stored as std::string (consider memory on ESP32)

Example:

// Update score label\nchar scoreText[32];\nsnprintf(scoreText, sizeof(scoreText), \"Score: %d\", score);\nscoreLabel->setText(scoreText);\n

"},{"location":"api_reference/ui/ui_label/#void-setvisiblebool-v","title":"void setVisible(bool v)","text":"

Sets visibility.

Parameters: - v (bool): true to show, false to hide

Returns: - void

Notes: - Inherited from Entity - Hides label without removing from scene

Example:

label->setVisible(false);  // Hide\nlabel->setVisible(true);   // Show\n

"},{"location":"api_reference/ui/ui_label/#void-centerxint-screenwidth","title":"void centerX(int screenWidth)","text":"

Centers the label horizontally within a given width (typically the screen width). Recalculates dimensions before positioning to ensure perfect centering.

Parameters: - screenWidth (int): The width to center within (e.g., engine.getRenderer().getWidth())

Returns: - void

Example:

label->centerX(128); // Center on a 128px screen\n

"},{"location":"api_reference/ui/ui_label/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the label state.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Default implementation does nothing - Override to add custom update logic (animations, etc.)

Example:

void update(unsigned long deltaTime) override {\n    UILabel::update(deltaTime);\n\n    // Custom logic (e.g., update text based on game state)\n    if (scoreChanged) {\n        updateScoreText();\n    }\n}\n

"},{"location":"api_reference/ui/ui_label/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Renders the label.

Parameters: - renderer (pixelroot32::graphics::Renderer&): The renderer to use

Returns: - void

Notes: - Called automatically by Scene if isVisible is true - Draws text at label position - Uses default font

Example:

// Drawing is handled automatically\n// Override only for custom rendering\n

"},{"location":"api_reference/ui/ui_label/#auto-sizing","title":"Auto-Sizing","text":"

Labels automatically calculate their size based on text:

  • Width: text.length() * (6 * size) pixels
  • Height: 8 * size pixels

Example:

// Label with text \"Hello\" (5 characters), size 1\n// Width: 5 * 6 * 1 = 30 pixels\n// Height: 8 * 1 = 8 pixels\n\nUILabel label(\"Hello\", 10, 10, Color::White, 1);\n// label.width = 30, label.height = 8\n

"},{"location":"api_reference/ui/ui_label/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UILabel.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n    int score = 0;\n    int lives = 3;\n\npublic:\n    void init() override {\n        // Score label\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\",\n            10.0f, 10.0f,\n            pixelroot32::graphics::Color::White,\n            1\n        );\n        addEntity(scoreLabel);\n\n        // Lives label\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\",\n            10.0f, 25.0f,\n            pixelroot32::graphics::Color::Yellow,\n            1\n        );\n        addEntity(livesLabel);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Update labels\n        char text[32];\n        snprintf(text, sizeof(text), \"Score: %d\", score);\n        scoreLabel->setText(text);\n\n        snprintf(text, sizeof(text), \"Lives: %d\", lives);\n        livesLabel->setText(text);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw game\n        Scene::draw(renderer);\n\n        // Labels are drawn automatically by Scene::draw()\n    }\n};\n
"},{"location":"api_reference/ui/ui_label/#centered-labels","title":"Centered Labels","text":"
// Create centered title\npixelroot32::graphics::ui::UILabel* title = new pixelroot32::graphics::ui::UILabel(\n    \"Game Title\",\n    0, 20.0f,  // X will be adjusted\n    pixelroot32::graphics::Color::Yellow,\n    2  // Large text\n);\ntitle->centerX(128);  // Center on screen\naddEntity(title);\n
"},{"location":"api_reference/ui/ui_label/#performance-considerations","title":"Performance Considerations","text":"
  • Text updates: setText() recalculates size; avoid calling every frame if text doesn't change
  • String storage: Uses std::string; consider memory on ESP32
  • Rendering: Simple text drawing; very efficient
  • Static text: For static text, create once and don't update
"},{"location":"api_reference/ui/ui_label/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: std::string uses heap memory; use static buffers when possible
  • Text updates: Limit frequency of text updates
  • String length: Keep text short to save memory
"},{"location":"api_reference/ui/ui_label/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UIButton - Clickable button
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layout/","title":"UILayout","text":"

Base class for UI layout containers.

"},{"location":"api_reference/ui/ui_layout/#description","title":"Description","text":"

UILayout is the base class for all layout containers. Layouts organize UI elements automatically, handling positioning, spacing, and optional scrolling. Layouts are themselves UI elements that can be added to scenes.

"},{"location":"api_reference/ui/ui_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UILayout : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: UIVerticalLayout, UIHorizontalLayout, UIGridLayout, UIAnchorLayout
"},{"location":"api_reference/ui/ui_layout/#scrollbehavior-enum","title":"ScrollBehavior Enum","text":"

Defines how scrolling behaves in layouts.

Values: - ScrollBehavior::NONE: No scrolling allowed - ScrollBehavior::SCROLL: Scroll freely within bounds - ScrollBehavior::CLAMP: Scroll but clamp to content bounds

"},{"location":"api_reference/ui/ui_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layout/#virtual-void-addelementuielement-element-0","title":"virtual void addElement(UIElement* element) = 0","text":"

Adds a UI element to the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to add

"},{"location":"api_reference/ui/ui_layout/#virtual-void-removeelementuielement-element-0","title":"virtual void removeElement(UIElement* element) = 0","text":"

Removes a UI element from the layout. Must be implemented by derived classes.

Parameters: - element (UIElement*): Pointer to the element to remove

"},{"location":"api_reference/ui/ui_layout/#virtual-void-updatelayout-0","title":"virtual void updateLayout() = 0","text":"

Recalculates positions of all elements in the layout. Must be implemented by derived classes.

Returns: - void

Notes: - Should be called automatically when elements are added/removed

"},{"location":"api_reference/ui/ui_layout/#virtual-void-handleinputconst-inputmanager-input-0","title":"virtual void handleInput(const InputManager& input) = 0","text":"

Handles input for layout navigation (scroll, selection, etc.). Must be implemented by derived classes.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

"},{"location":"api_reference/ui/ui_layout/#void-setpaddingfloat-p","title":"void setPadding(float p)","text":"

Sets the padding (internal spacing) of the layout.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Layout is automatically recalculated

"},{"location":"api_reference/ui/ui_layout/#float-getpadding-const","title":"float getPadding() const","text":"

Gets the current padding.

Returns: - float: Padding value in pixels

"},{"location":"api_reference/ui/ui_layout/#void-setspacingfloat-s","title":"void setSpacing(float s)","text":"

Sets the spacing between elements.

Parameters: - s (float): Spacing value in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Default: 4.0 pixels

"},{"location":"api_reference/ui/ui_layout/#float-getspacing-const","title":"float getSpacing() const","text":"

Gets the current spacing.

Returns: - float: Spacing value in pixels

"},{"location":"api_reference/ui/ui_layout/#size_t-getelementcount-const","title":"size_t getElementCount() const","text":"

Gets the number of elements in the layout.

Returns: - size_t: Element count

"},{"location":"api_reference/ui/ui_layout/#uielement-getelementsize_t-index-const","title":"UIElement* getElement(size_t index) const","text":"

Gets the element at a specific index.

Parameters: - index (size_t): Element index

Returns: - UIElement*: Pointer to the element, or nullptr if index is invalid

"},{"location":"api_reference/ui/ui_layout/#void-clearelements","title":"void clearElements()","text":"

Clears all elements from the layout.

Returns: - void

Notes: - Elements are not deleted (you must manage their lifetimes) - Layout is automatically recalculated

"},{"location":"api_reference/ui/ui_layout/#void-setfixedpositionbool-fixed","title":"void setFixedPosition(bool fixed)","text":"

Enables or disables fixed positioning for the layout.

Parameters: - fixed (bool): true to stay fixed on screen, false to move with the camera.

Notes: - When enabled, the layout will automatically bypass camera offsets during its draw() cycle.

"},{"location":"api_reference/ui/ui_layout/#bool-isfixedposition-const","title":"bool isFixedPosition() const","text":"

Checks if the layout is in fixed position mode.

Returns: - bool: true if fixed positioning is enabled.

"},{"location":"api_reference/ui/ui_layout/#protected-members","title":"Protected Members","text":"
  • std::vector<UIElement*> elements: List of child elements
  • float padding: Internal padding
  • float spacing: Spacing between elements (default: 4.0)
  • float scrollOffset: Current scroll offset
  • bool enableScroll: Whether scrolling is enabled
  • ScrollBehavior scrollBehavior: Scroll behavior mode
"},{"location":"api_reference/ui/ui_layout/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UIVerticalLayout - Vertical layout
  • UIHorizontalLayout - Horizontal layout
  • UIGridLayout - Grid layout
  • UIAnchorLayout - Anchor layout
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/","title":"UIAnchorLayout","text":"

Layout that positions elements at fixed anchor points on the screen.

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#description","title":"Description","text":"

UIAnchorLayout positions UI elements at fixed anchor points (corners, center, edges) without reflow. Very efficient for HUDs, debug UI, and fixed-position elements. Positions are calculated once or when screen size changes.

This layout is ideal for HUD elements like score, lives, health bars, and other fixed-position UI.

Tip: For HUDs, remember to call setFixedPosition(true) on the layout so it doesn't move when the camera scrolls.

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIAnchorLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom anchor layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#anchor-enum","title":"Anchor Enum","text":"

Defines anchor points for positioning UI elements.

Values: - Anchor::TOP_LEFT: Top-left corner - Anchor::TOP_RIGHT: Top-right corner - Anchor::BOTTOM_LEFT: Bottom-left corner - Anchor::BOTTOM_RIGHT: Bottom-right corner - Anchor::CENTER: Center of screen - Anchor::TOP_CENTER: Top center - Anchor::BOTTOM_CENTER: Bottom center - Anchor::LEFT_CENTER: Left center - Anchor::RIGHT_CENTER: Right center

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/anchor_layout/#uianchorlayoutfloat-x-float-y-float-w-float-h","title":"UIAnchorLayout(float x, float y, float w, float h)","text":"

Constructs a new UIAnchorLayout.

Parameters: - x (float): X position of the layout container (usually 0) - y (float): Y position of the layout container (usually 0) - w (float): Width of the layout container (usually screen width) - h (float): Height of the layout container (usually screen height)

Example:

#include \"graphics/ui/UIAnchorLayout.h\"\n\n// Create full-screen anchor layout for HUD\nauto& renderer = engine.getRenderer();\npixelroot32::graphics::ui::UIAnchorLayout* hud = \n    new pixelroot32::graphics::ui::UIAnchorLayout(\n        0.0f, 0.0f,\n        static_cast<float>(renderer.getWidth()),\n        static_cast<float>(renderer.getHeight())\n    );\nhud->setScreenSize(\n    static_cast<float>(renderer.getWidth()),\n    static_cast<float>(renderer.getHeight())\n);\n

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-addelementuielement-element-anchor-anchor","title":"void addElement(UIElement* element, Anchor anchor)","text":"

Adds a UI element with a specific anchor point.

Parameters: - element (UIElement*): Pointer to the element to add - anchor (Anchor): Anchor point for positioning

Returns: - void

Example:

// Score label at top-right\nhud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\n// Lives label at top-left\nhud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout (defaults to TOP_LEFT anchor).

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements based on anchors.

Returns: - void

Notes: - Called automatically when screen size changes - Can be called manually if needed

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input (no-op for anchor layout, elements handle their own input).

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Anchor layout doesn't handle navigation - Elements handle their own input

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout and child elements.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws all elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#void-setscreensizefloat-screenwidth-float-screenheight","title":"void setScreenSize(float screenWidth, float screenHeight)","text":"

Sets the screen size for anchor calculations.

Parameters: - screenWidth (float): Screen width in pixels - screenHeight (float): Screen height in pixels

Returns: - void

Notes: - Used to calculate anchor positions - Should match actual display size - Layout is automatically recalculated

Example:

auto& renderer = engine.getRenderer();\nhud->setScreenSize(\n    static_cast<float>(renderer.getWidth()),\n    static_cast<float>(renderer.getHeight())\n);\n

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#float-getscreenwidth-const","title":"float getScreenWidth() const","text":"

Gets the screen width.

Returns: - float: Screen width in pixels

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#float-getscreenheight-const","title":"float getScreenHeight() const","text":"

Gets the screen height.

Returns: - float: Screen height in pixels

"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIAnchorLayout.h\"\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIAnchorLayout* hud;\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n\npublic:\n    void init() override {\n        auto& renderer = engine.getRenderer();\n\n        // Create HUD layout\n        hud = new pixelroot32::graphics::ui::UIAnchorLayout(\n            0.0f, 0.0f,\n            static_cast<float>(renderer.getWidth()),\n            static_cast<float>(renderer.getHeight())\n        );\n        hud->setScreenSize(\n            static_cast<float>(renderer.getWidth()),\n            static_cast<float>(renderer.getHeight())\n        );\n\n        // Score label (top-right)\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\",\n            0, 0,\n            Color::White,\n            1\n        );\n        hud->addElement(scoreLabel, \n                        pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\n        // Lives label (top-left)\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\",\n            0, 0,\n            Color::Yellow,\n            1\n        );\n        hud->addElement(livesLabel, \n                        pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n\n        addEntity(hud);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Update labels\n        char text[32];\n        snprintf(text, sizeof(text), \"Score: %d\", score);\n        scoreLabel->setText(text);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw game\n        Scene::draw(renderer);\n\n        // HUD is drawn automatically (on layer 2)\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#anchor-positioning","title":"Anchor Positioning","text":"

Elements are positioned based on their anchor:

  • TOP_LEFT: Element's top-left at screen top-left
  • TOP_RIGHT: Element's top-right at screen top-right
  • BOTTOM_LEFT: Element's bottom-left at screen bottom-left
  • BOTTOM_RIGHT: Element's bottom-right at screen bottom-right
  • CENTER: Element centered on screen
  • TOP_CENTER: Element centered horizontally, top-aligned
  • BOTTOM_CENTER: Element centered horizontally, bottom-aligned
  • LEFT_CENTER: Element centered vertically, left-aligned
  • RIGHT_CENTER: Element centered vertically, right-aligned
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#performance-considerations","title":"Performance Considerations","text":"
  • No reflow: Very efficient (positions calculated once)
  • Fixed positions: Ideal for HUD elements
  • Viewport independent: Elements stay in fixed screen positions
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Very efficient (no complex calculations)
  • Update frequency: Positions only recalculate when screen size changes
"},{"location":"api_reference/ui/ui_layouts/anchor_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class
  • UILabel - Labels for HUD
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/grid_layout/","title":"UIGridLayout","text":"

Grid layout container for organizing elements in a matrix.

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#description","title":"Description","text":"

UIGridLayout organizes UI elements in a fixed grid of rows and columns. It supports navigation in 4 directions (UP/DOWN/LEFT/RIGHT) and automatic positioning based on grid coordinates.

This layout is ideal for inventories, level selection screens, galleries, and any grid-based UI arrangement.

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIGridLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/grid_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom grid layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/grid_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/grid_layout/#uigridlayoutfloat-x-float-y-float-w-float-h","title":"UIGridLayout(float x, float y, float w, float h)","text":"

Constructs a new UIGridLayout.

Parameters: - x (float): X position of the layout container - y (float): Y position of the layout container - w (float): Width of the layout container - h (float): Height of the layout container

Example:

#include \"graphics/ui/UIGridLayout.h\"\n\n// Create 4x4 grid for inventory\npixelroot32::graphics::ui::UIGridLayout* inventory = \n    new pixelroot32::graphics::ui::UIGridLayout(\n        10.0f, 10.0f,  // position\n        108.0f, 108.0f // size\n    );\ninventory->setColumns(4);\n

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout.

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

Notes: - Elements are arranged in grid order (left to right, top to bottom) - Layout is automatically recalculated - Cell size is calculated based on columns and layout size

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements.

Returns: - void

Notes: - Recalculates cell dimensions - Recalculates row count - Repositions all elements

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input for navigation and selection.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Handles UP/DOWN/LEFT/RIGHT navigation - Manages selection state - Wraps around grid edges (if configured)

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout and child elements.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the layout and its visible elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setcolumnsuint8_t-cols","title":"void setColumns(uint8_t cols)","text":"

Sets the number of columns in the grid.

Parameters: - cols (uint8_t): Number of columns (must be > 0)

Returns: - void

Notes: - Layout is automatically recalculated - Row count is calculated based on element count and columns

Example:

inventory->setColumns(4);  // 4 columns\n

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#uint8_t-getcolumns-const","title":"uint8_t getColumns() const","text":"

Gets the number of columns.

Returns: - uint8_t: Number of columns

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#uint8_t-getrows-const","title":"uint8_t getRows() const","text":"

Gets the number of rows (calculated).

Returns: - uint8_t: Number of rows

Notes: - Calculated as ceil(elementCount / columns)

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#int-getselectedindex-const","title":"int getSelectedIndex() const","text":"

Gets the currently selected element index.

Returns: - int: Selected index, or -1 if none selected

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setselectedindexint-index","title":"void setSelectedIndex(int index)","text":"

Sets the selected element index.

Parameters: - index (int): Index to select (-1 to deselect)

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#uielement-getselectedelement-const","title":"UIElement* getSelectedElement() const","text":"

Gets the selected element.

Returns: - UIElement*: Pointer to selected element, or nullptr if none selected

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setnavigationbuttonsuint8_t-upbutton-uint8_t-downbutton-uint8_t-leftbutton-uint8_t-rightbutton","title":"void setNavigationButtons(uint8_t upButton, uint8_t downButton, uint8_t leftButton, uint8_t rightButton)","text":"

Sets the navigation button indices.

Parameters: - upButton (uint8_t): Button index for UP navigation - downButton (uint8_t): Button index for DOWN navigation - leftButton (uint8_t): Button index for LEFT navigation - rightButton (uint8_t): Button index for RIGHT navigation

Returns: - void

Notes: - Default: UP=0, DOWN=1, LEFT=2, RIGHT=3 - Change if your input mapping differs

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#void-setbuttonstylecolor-selectedtextcol-color-selectedbgcol-color-unselectedtextcol-color-unselectedbgcol","title":"void setButtonStyle(Color selectedTextCol, Color selectedBgCol, Color unselectedTextCol, Color unselectedBgCol)","text":"

Sets the style colors for selected and unselected buttons.

Parameters: - selectedTextCol (Color): Text color when selected - selectedBgCol (Color): Background color when selected - unselectedTextCol (Color): Text color when not selected - unselectedBgCol (Color): Background color when not selected

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/grid_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIGridLayout.h\"\n\nclass InventoryScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIGridLayout* inventory;\n\npublic:\n    void init() override {\n        // Create 4x4 inventory grid\n        inventory = new pixelroot32::graphics::ui::UIGridLayout(\n            10.0f, 10.0f,\n            108.0f, 108.0f\n        );\n        inventory->setColumns(4);\n        inventory->setSpacing(2.0f);\n        inventory->setPadding(4.0f);\n\n        // Add inventory slots\n        for (int i = 0; i < 16; i++) {\n            auto* slot = createInventorySlot(i);\n            inventory->addElement(slot);\n        }\n\n        addEntity(inventory);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/grid_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class (abstract)
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/","title":"UIHorizontalLayout","text":"

Horizontal layout container with scroll support.

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#description","title":"Description","text":"

UIHorizontalLayout organizes UI elements horizontally, one next to another. It supports scrolling when content exceeds the visible viewport and handles keyboard/D-pad navigation automatically.

This layout is ideal for toolbars, tab bars, horizontal menus, and any horizontal arrangement of UI elements.

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIHorizontalLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom horizontal layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#uihorizontallayoutfloat-x-float-y-float-w-float-h","title":"UIHorizontalLayout(float x, float y, float w, float h)","text":"

Constructs a new UIHorizontalLayout.

Parameters: - x (float): X position of the layout container - y (float): Y position of the layout container - w (float): Width of the layout container (viewport width) - h (float): Height of the layout container

Example:

#include \"graphics/ui/UIHorizontalLayout.h\"\n\n// Create horizontal layout for toolbar\npixelroot32::graphics::ui::UIHorizontalLayout* toolbar = \n    new pixelroot32::graphics::ui::UIHorizontalLayout(\n        0.0f, 0.0f,   // position (top of screen)\n        128.0f, 20.0f // size\n    );\n

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout.

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

Notes: - Elements are arranged horizontally, left to right - Layout is automatically recalculated - Elements are positioned based on spacing and padding

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements.

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input for navigation and scrolling.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Handles LEFT/RIGHT navigation - Manages selection state - Handles scrolling if enabled

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout (handles smooth scrolling).

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the layout and its visible elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setscrollenabledbool-enable","title":"void setScrollEnabled(bool enable)","text":"

Enables or disables scrolling.

Parameters: - enable (bool): true to enable scrolling

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setviewportwidthfloat-w","title":"void setViewportWidth(float w)","text":"

Sets the viewport width (visible area).

Parameters: - w (float): Viewport width in pixels

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#float-getscrolloffset-const","title":"float getScrollOffset() const","text":"

Gets the current scroll offset.

Returns: - float: Scroll offset in pixels

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setscrolloffsetfloat-offset","title":"void setScrollOffset(float offset)","text":"

Sets the scroll offset directly.

Parameters: - offset (float): Scroll offset in pixels

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#float-getcontentwidth-const","title":"float getContentWidth() const","text":"

Gets the total content width.

Returns: - float: Content width in pixels

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#int-getselectedindex-const","title":"int getSelectedIndex() const","text":"

Gets the currently selected element index.

Returns: - int: Selected index, or -1 if none selected

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setselectedindexint-index","title":"void setSelectedIndex(int index)","text":"

Sets the selected element index.

Parameters: - index (int): Index to select (-1 to deselect)

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#uielement-getselectedelement-const","title":"UIElement* getSelectedElement() const","text":"

Gets the selected element.

Returns: - UIElement*: Pointer to selected element, or nullptr if none selected

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setscrollspeedfloat-speed","title":"void setScrollSpeed(float speed)","text":"

Sets the scroll speed for smooth scrolling.

Parameters: - speed (float): Pixels per millisecond

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setnavigationbuttonsuint8_t-leftbutton-uint8_t-rightbutton","title":"void setNavigationButtons(uint8_t leftButton, uint8_t rightButton)","text":"

Sets the navigation button indices.

Parameters: - leftButton (uint8_t): Button index for LEFT navigation - rightButton (uint8_t): Button index for RIGHT navigation

Returns: - void

Notes: - Default: LEFT = 2, RIGHT = 3 - Change if your input mapping differs

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#void-setbuttonstylecolor-selectedtextcol-color-selectedbgcol-color-unselectedtextcol-color-unselectedbgcol","title":"void setButtonStyle(Color selectedTextCol, Color selectedBgCol, Color unselectedTextCol, Color unselectedBgCol)","text":"

Sets the style colors for selected and unselected buttons.

Parameters: - selectedTextCol (Color): Text color when selected - selectedBgCol (Color): Background color when selected - unselectedTextCol (Color): Text color when not selected - unselectedBgCol (Color): Background color when not selected

Returns: - void

"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIHorizontalLayout.h\"\n\nclass ToolbarScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIHorizontalLayout* toolbar;\n\npublic:\n    void init() override {\n        // Create horizontal toolbar\n        toolbar = new pixelroot32::graphics::ui::UIHorizontalLayout(\n            0.0f, 0.0f,    // Top of screen\n            128.0f, 20.0f  // Full width, 20px tall\n        );\n        toolbar->setSpacing(4.0f);\n        toolbar->setPadding(2.0f);\n\n        // Add toolbar buttons\n        toolbar->addElement(newButton(\"File\", ...));\n        toolbar->addElement(newButton(\"Edit\", ...));\n        toolbar->addElement(newButton(\"View\", ...));\n\n        addEntity(toolbar);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/horizontal_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class (abstract)
  • UIVerticalLayout - Vertical layout
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/padding_container/","title":"UIPaddingContainer","text":"

Container that wraps a single UI element and applies padding.

"},{"location":"api_reference/ui/ui_layouts/padding_container/#description","title":"Description","text":"

UIPaddingContainer adds padding/margin around a single child element without organizing multiple elements. Useful for adding spacing to individual elements or nesting layouts with custom padding.

This container is simpler than UIPanel (no background/border) and focuses only on spacing.

"},{"location":"api_reference/ui/ui_layouts/padding_container/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIPaddingContainer : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/padding_container/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom padding containers (if needed)
"},{"location":"api_reference/ui/ui_layouts/padding_container/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/padding_container/#uipaddingcontainerfloat-x-float-y-float-w-float-h","title":"UIPaddingContainer(float x, float y, float w, float h)","text":"

Constructs a new UIPaddingContainer.

Parameters: - x (float): X position of the container - y (float): Y position of the container - w (float): Width of the container - h (float): Height of the container

Example:

#include \"graphics/ui/UIPaddingContainer.h\"\n\n// Create padding container\npixelroot32::graphics::ui::UIPaddingContainer* padded = \n    new pixelroot32::graphics::ui::UIPaddingContainer(\n        10.0f, 10.0f,\n        108.0f, 108.0f\n    );\npadded->setPadding(8.0f);  // 8px padding on all sides\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setchilduielement-element","title":"void setChild(UIElement* element)","text":"

Sets the child element.

Parameters: - element (UIElement*): Pointer to the UI element to wrap

Returns: - void

Notes: - Child element is positioned with padding applied - Can wrap any UI element (button, label, layout, etc.)

Example:

padded->setChild(button);\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#uielement-getchild-const","title":"UIElement* getChild() const","text":"

Gets the child element.

Returns: - UIElement*: Pointer to the child element, or nullptr if none set

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setpaddingfloat-p","title":"void setPadding(float p)","text":"

Sets uniform padding on all sides.

Parameters: - p (float): Padding value in pixels

Returns: - void

Notes: - Applies same padding to all sides - Child position is automatically updated

Example:

padded->setPadding(10.0f);  // 10px padding all around\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setpaddingfloat-left-float-right-float-top-float-bottom","title":"void setPadding(float left, float right, float top, float bottom)","text":"

Sets asymmetric padding.

Parameters: - left (float): Left padding in pixels - right (float): Right padding in pixels - top (float): Top padding in pixels - bottom (float): Bottom padding in pixels

Returns: - void

Example:

padded->setPadding(10.0f, 5.0f, 8.0f, 12.0f);  // Different padding per side\n

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingleft-const","title":"float getPaddingLeft() const","text":"

Gets the left padding.

Returns: - float: Left padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingright-const","title":"float getPaddingRight() const","text":"

Gets the right padding.

Returns: - float: Right padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingtop-const","title":"float getPaddingTop() const","text":"

Gets the top padding.

Returns: - float: Top padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#float-getpaddingbottom-const","title":"float getPaddingBottom() const","text":"

Gets the bottom padding.

Returns: - float: Bottom padding in pixels

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-setpositionfloat-newx-float-newy","title":"void setPosition(float newX, float newY)","text":"

Sets the position of the container. Also updates the child element's position.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Child element position is updated automatically with padding applied

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the container and child element.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Updates child element if set - Called automatically by Scene

"},{"location":"api_reference/ui/ui_layouts/padding_container/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the child element.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

Notes: - Only draws child element (no background/border) - Child is drawn at padded position

"},{"location":"api_reference/ui/ui_layouts/padding_container/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIPaddingContainer.h\"\n\nclass MenuScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Create button\n        auto* button = new UIButton(\"Start\", 0, 0, 0, 100.0f, 30.0f, \n                                    [this]() { startGame(); });\n\n        // Wrap button with padding\n        auto* paddedButton = new pixelroot32::graphics::ui::UIPaddingContainer(\n            64.0f, 50.0f,  // position\n            120.0f, 50.0f  // size (button + padding)\n        );\n        paddedButton->setPadding(10.0f);  // 10px padding\n        paddedButton->setChild(button);\n\n        addEntity(paddedButton);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/padding_container/#nesting-with-layouts","title":"Nesting with Layouts","text":"
// Create layout\nauto* layout = new UIVerticalLayout(10, 10, 108, 108);\n\n// Wrap layout with padding\nauto* paddedLayout = new UIPaddingContainer(0, 0, 128, 128);\npaddedLayout->setPadding(10.0f, 10.0f, 20.0f, 20.0f);  // Asymmetric\npaddedLayout->setChild(layout);\n
"},{"location":"api_reference/ui/ui_layouts/padding_container/#performance-considerations","title":"Performance Considerations","text":"
  • Rendering: Very efficient (just draws child)
  • Position calculation: Fast (simple addition)
  • Memory: Minimal overhead
"},{"location":"api_reference/ui/ui_layouts/padding_container/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Very lightweight
  • Update frequency: Position only recalculates when padding/position changes
"},{"location":"api_reference/ui/ui_layouts/padding_container/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UIPanel - Panel with background and border
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/panel/","title":"UIPanel","text":"

Visual container that draws a background and border around a child element.

"},{"location":"api_reference/ui/ui_layouts/panel/#description","title":"Description","text":"

UIPanel provides a retro-style window/panel appearance with a background color and border. Typically contains a UILayout or other UI elements. Useful for dialogs, menus, and information panels.

The panel wraps a single child element and draws a background rectangle and border around it.

"},{"location":"api_reference/ui/ui_layouts/panel/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIPanel : public UIElement {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/panel/#inheritance","title":"Inheritance","text":"
  • Inherits from: UIElement
  • Inherited by: Your custom panel classes (if needed)
"},{"location":"api_reference/ui/ui_layouts/panel/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/panel/#uipanelfloat-x-float-y-float-w-float-h","title":"UIPanel(float x, float y, float w, float h)","text":"

Constructs a new UIPanel.

Parameters: - x (float): X position of the panel - y (float): Y position of the panel - w (float): Width of the panel - h (float): Height of the panel

Example:

#include \"graphics/ui/UIPanel.h\"\n\n// Create dialog panel\npixelroot32::graphics::ui::UIPanel* dialog = \n    new pixelroot32::graphics::ui::UIPanel(\n        20.0f, 30.0f,  // position\n        88.0f, 68.0f   // size\n    );\n

"},{"location":"api_reference/ui/ui_layouts/panel/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/panel/#void-setchilduielement-element","title":"void setChild(UIElement* element)","text":"

Sets the child element.

Parameters: - element (UIElement*): Pointer to the UI element to wrap (typically a UILayout)

Returns: - void

Notes: - Child element is positioned inside the panel (with padding) - Typically a layout (VerticalLayout, etc.)

Example:

// Create panel\nauto* panel = new UIPanel(20, 30, 88, 68);\n\n// Create layout for panel content\nauto* layout = new UIVerticalLayout(0, 0, 80, 60);\nlayout->addElement(button1);\nlayout->addElement(button2);\n\n// Set layout as panel child\npanel->setChild(layout);\n

"},{"location":"api_reference/ui/ui_layouts/panel/#uielement-getchild-const","title":"UIElement* getChild() const","text":"

Gets the child element.

Returns: - UIElement*: Pointer to the child element, or nullptr if none set

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setbackgroundcolorcolor-color","title":"void setBackgroundColor(Color color)","text":"

Sets the background color.

Parameters: - color (Color): Background color

Returns: - void

Example:

panel->setBackgroundColor(Color::Blue);\n

"},{"location":"api_reference/ui/ui_layouts/panel/#color-getbackgroundcolor-const","title":"Color getBackgroundColor() const","text":"

Gets the background color.

Returns: - Color: Background color

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setbordercolorcolor-color","title":"void setBorderColor(Color color)","text":"

Sets the border color.

Parameters: - color (Color): Border color

Returns: - void

Example:

panel->setBorderColor(Color::White);\n

"},{"location":"api_reference/ui/ui_layouts/panel/#color-getbordercolor-const","title":"Color getBorderColor() const","text":"

Gets the border color.

Returns: - Color: Border color

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setborderwidthuint8_t-width","title":"void setBorderWidth(uint8_t width)","text":"

Sets the border width.

Parameters: - width (uint8_t): Border width in pixels

Returns: - void

Notes: - Default: 1 pixel - Higher values = thicker border

Example:

panel->setBorderWidth(2);  // 2 pixel border\n

"},{"location":"api_reference/ui/ui_layouts/panel/#uint8_t-getborderwidth-const","title":"uint8_t getBorderWidth() const","text":"

Gets the border width.

Returns: - uint8_t: Border width in pixels

"},{"location":"api_reference/ui/ui_layouts/panel/#void-setpositionfloat-newx-float-newy","title":"void setPosition(float newX, float newY)","text":"

Sets the position of the panel. Also updates the child element's position.

Parameters: - newX (float): New X coordinate - newY (float): New Y coordinate

Returns: - void

Notes: - Child element position is updated automatically

"},{"location":"api_reference/ui/ui_layouts/panel/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the panel and child element.

Parameters: - deltaTime (unsigned long): Time elapsed in milliseconds

Returns: - void

Notes: - Updates child element if set - Called automatically by Scene

"},{"location":"api_reference/ui/ui_layouts/panel/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the panel (background, border) and child element.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

Notes: - Draws background rectangle - Draws border rectangle - Draws child element if set

"},{"location":"api_reference/ui/ui_layouts/panel/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIPanel.h\"\n#include \"graphics/ui/UIVerticalLayout.h\"\n\nclass DialogScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIPanel* dialog;\n\npublic:\n    void init() override {\n        // Create dialog panel\n        dialog = new pixelroot32::graphics::ui::UIPanel(\n            20.0f, 30.0f,  // position\n            88.0f, 68.0f   // size\n        );\n        dialog->setBackgroundColor(Color::Navy);\n        dialog->setBorderColor(Color::White);\n        dialog->setBorderWidth(2);\n\n        // Create layout for dialog content\n        auto* layout = new pixelroot32::graphics::ui::UIVerticalLayout(\n            4.0f, 4.0f,  // Position inside panel\n            80.0f, 60.0f // Size inside panel\n        );\n        layout->setSpacing(8.0f);\n\n        // Add buttons\n        auto* okButton = new UIButton(\"OK\", 0, 0, 0, 70.0f, 20.0f, \n                                     [this]() { closeDialog(); });\n        auto* cancelButton = new UIButton(\"Cancel\", 1, 0, 0, 70.0f, 20.0f,\n                                         [this]() { closeDialog(); });\n\n        layout->addElement(okButton);\n        layout->addElement(cancelButton);\n\n        // Set layout as panel child\n        dialog->setChild(layout);\n\n        addEntity(dialog);\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/panel/#performance-considerations","title":"Performance Considerations","text":"
  • Rendering: Simple rectangles; very efficient
  • Child updates: Child element updates are fast
  • Memory: Small overhead (just colors and border width)
"},{"location":"api_reference/ui/ui_layouts/panel/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Memory: Panel is lightweight
  • Rendering: Two rectangles (background + border); minimal overhead
"},{"location":"api_reference/ui/ui_layouts/panel/#see-also","title":"See Also","text":"
  • UIElement - Base UI element class
  • UILayouts - Layout containers to use inside panels
  • Manual - User Interface
  • API Overview
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/","title":"UIVerticalLayout","text":"

Vertical layout container with scroll support.

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#description","title":"Description","text":"

UIVerticalLayout organizes UI elements vertically, one below another. It supports scrolling when content exceeds the visible viewport and handles keyboard/D-pad navigation automatically.

This layout is ideal for menus, lists, and any vertical arrangement of UI elements.

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#namespace","title":"Namespace","text":"
namespace pixelroot32::graphics::ui {\n    class UIVerticalLayout : public UILayout {\n        // ...\n    };\n}\n
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#inheritance","title":"Inheritance","text":"
  • Inherits from: UILayout
  • Inherited by: Your custom vertical layouts (if needed)
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#constructors","title":"Constructors","text":""},{"location":"api_reference/ui/ui_layouts/vertical_layout/#uiverticallayoutfloat-x-float-y-float-w-float-h","title":"UIVerticalLayout(float x, float y, float w, float h)","text":"

Constructs a new UIVerticalLayout.

Parameters: - x (float): X position of the layout container - y (float): Y position of the layout container - w (float): Width of the layout container - h (float): Height of the layout container (viewport height)

Example:

#include \"graphics/ui/UIVerticalLayout.h\"\n\n// Create vertical layout for menu\npixelroot32::graphics::ui::UIVerticalLayout* menuLayout = \n    new pixelroot32::graphics::ui::UIVerticalLayout(\n        20.0f, 20.0f,  // position\n        88.0f, 88.0f   // size (viewport)\n    );\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#public-methods","title":"Public Methods","text":""},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-addelementuielement-element","title":"void addElement(UIElement* element)","text":"

Adds a UI element to the layout.

Parameters: - element (UIElement*): Pointer to the element to add

Returns: - void

Notes: - Elements are arranged vertically, one below another - Layout is automatically recalculated - Elements are positioned based on spacing and padding

Example:

menuLayout->addElement(startButton);\nmenuLayout->addElement(quitButton);\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-removeelementuielement-element","title":"void removeElement(UIElement* element)","text":"

Removes a UI element from the layout.

Parameters: - element (UIElement*): Pointer to the element to remove

Returns: - void

Notes: - Layout is automatically recalculated - Element is not deleted (you must manage its lifetime)

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-updatelayout","title":"void updateLayout()","text":"

Recalculates positions of all elements.

Returns: - void

Notes: - Called automatically when elements are added/removed - Can be called manually if needed - Recalculates all element positions and content height

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-handleinputconst-inputmanager-input","title":"void handleInput(const InputManager& input)","text":"

Handles input for navigation and scrolling.

Parameters: - input (const pixelroot32::input::InputManager&): Reference to the InputManager

Returns: - void

Notes: - Handles UP/DOWN navigation - Manages selection state - Handles scrolling if enabled - Should be called every frame in update()

Example:

void update(unsigned long deltaTime) override {\n    UIVerticalLayout::update(deltaTime);\n\n    auto& input = engine.getInputManager();\n    menuLayout->handleInput(input);\n}\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-updateunsigned-long-deltatime-override","title":"void update(unsigned long deltaTime) override","text":"

Updates the layout (handles smooth scrolling).

Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds

Returns: - void

Notes: - Called automatically by Scene if isEnabled is true - Updates smooth scrolling animation - Updates child elements

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-drawrenderer-renderer-override","title":"void draw(Renderer& renderer) override","text":"

Draws the layout and its visible elements.

Parameters: - renderer (pixelroot32::graphics::Renderer&): Reference to the renderer

Returns: - void

Notes: - Called automatically by Scene if isVisible is true - Only draws visible elements (viewport culling) - Draws elements in order

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setscrollenabledbool-enable","title":"void setScrollEnabled(bool enable)","text":"

Enables or disables scrolling.

Parameters: - enable (bool): true to enable scrolling

Returns: - void

Notes: - When disabled, scroll offset is reset to 0 - Scrolling is useful when content exceeds viewport height

Example:

menuLayout->setScrollEnabled(true);  // Enable scrolling\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-enablescrollbool-enable","title":"void enableScroll(bool enable)","text":"

Alias for setScrollEnabled().

Parameters: - enable (bool): true to enable scrolling

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setviewportheightfloat-h","title":"void setViewportHeight(float h)","text":"

Sets the viewport height (visible area).

Parameters: - h (float): Viewport height in pixels

Returns: - void

Notes: - Layout is automatically recalculated - Use to adjust visible area

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#float-getscrolloffset-const","title":"float getScrollOffset() const","text":"

Gets the current scroll offset.

Returns: - float: Scroll offset in pixels

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setscrolloffsetfloat-offset","title":"void setScrollOffset(float offset)","text":"

Sets the scroll offset directly.

Parameters: - offset (float): Scroll offset in pixels

Returns: - void

Notes: - Offset is clamped to valid range automatically - Use for programmatic scrolling

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#float-getcontentheight-const","title":"float getContentHeight() const","text":"

Gets the total content height.

Returns: - float: Content height in pixels

Notes: - Includes all elements plus spacing and padding - Useful for scroll calculations

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#int-getselectedindex-const","title":"int getSelectedIndex() const","text":"

Gets the currently selected element index.

Returns: - int: Selected index, or -1 if none selected

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setselectedindexint-index","title":"void setSelectedIndex(int index)","text":"

Sets the selected element index.

Parameters: - index (int): Index to select (-1 to deselect)

Returns: - void

Notes: - Selected element is highlighted - Selection is scrolled into view if needed

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#uielement-getselectedelement-const","title":"UIElement* getSelectedElement() const","text":"

Gets the selected element.

Returns: - UIElement*: Pointer to selected element, or nullptr if none selected

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setscrollspeedfloat-speed","title":"void setScrollSpeed(float speed)","text":"

Sets the scroll speed for smooth scrolling.

Parameters: - speed (float): Pixels per millisecond

Returns: - void

Notes: - Default: 0.5 pixels per millisecond - Higher values = faster scrolling

Example:

menuLayout->setScrollSpeed(1.0f);  // Faster scrolling\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setnavigationbuttonsuint8_t-upbutton-uint8_t-downbutton","title":"void setNavigationButtons(uint8_t upButton, uint8_t downButton)","text":"

Sets the navigation button indices.

Parameters: - upButton (uint8_t): Button index for UP navigation - downButton (uint8_t): Button index for DOWN navigation

Returns: - void

Notes: - Default: UP = 0, DOWN = 1 - Change if your input mapping differs

Example:

menuLayout->setNavigationButtons(0, 1);  // UP=0, DOWN=1\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#void-setbuttonstylecolor-selectedtextcol-color-selectedbgcol-color-unselectedtextcol-color-unselectedbgcol","title":"void setButtonStyle(Color selectedTextCol, Color selectedBgCol, Color unselectedTextCol, Color unselectedBgCol)","text":"

Sets the style colors for selected and unselected buttons.

Parameters: - selectedTextCol (Color): Text color when selected - selectedBgCol (Color): Background color when selected - unselectedTextCol (Color): Text color when not selected - unselectedBgCol (Color): Background color when not selected

Returns: - void

Example:

menuLayout->setButtonStyle(\n    Color::Yellow,  // Selected text\n    Color::Blue,    // Selected background\n    Color::White,   // Unselected text\n    Color::Black    // Unselected background\n);\n

"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#usage-example","title":"Usage Example","text":"
#include \"graphics/ui/UIVerticalLayout.h\"\n#include \"graphics/ui/UIButton.h\"\n\nclass MainMenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIVerticalLayout* menuLayout;\n\npublic:\n    void init() override {\n        // Create menu layout\n        menuLayout = new pixelroot32::graphics::ui::UIVerticalLayout(\n            20.0f, 20.0f,  // position\n            88.0f, 88.0f   // size\n        );\n        menuLayout->setScrollEnabled(true);\n        menuLayout->setSpacing(8.0f);\n        menuLayout->setPadding(4.0f);\n\n        // Create buttons\n        auto* startButton = new pixelroot32::graphics::ui::UIButton(\n            \"Start\",\n            0, 64.0f, 50.0f, 100.0f, 30.0f,\n            [this]() { engine.setScene(&gameScene); }\n        );\n\n        auto* quitButton = new pixelroot32::graphics::ui::UIButton(\n            \"Quit\",\n            1, 64.0f, 50.0f, 100.0f, 30.0f,\n            [this]() { engine.stop(); }\n        );\n\n        // Add buttons to layout\n        menuLayout->addElement(startButton);\n        menuLayout->addElement(quitButton);\n\n        // Add layout to scene\n        addEntity(menuLayout);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Layout handles input automatically\n        auto& input = engine.getInputManager();\n        menuLayout->handleInput(input);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);\n        Scene::draw(renderer);  // Draws layout and buttons\n    }\n};\n
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#navigation","title":"Navigation","text":"

The layout handles D-pad navigation automatically:

  • UP button: Moves selection up
  • DOWN button: Moves selection down
  • Action button: Triggers selected button's callback
  • Scrolling: Automatically scrolls to keep selected element visible
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#performance-considerations","title":"Performance Considerations","text":"
  • Viewport culling: Only visible elements are drawn
  • Layout recalculation: Fast (simple positioning)
  • Scrolling: Smooth scrolling is efficient
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#esp32-considerations","title":"ESP32 Considerations","text":"
  • Element count: Stay within MAX_ENTITIES limit
  • Scrolling: Smooth scrolling uses minimal CPU
"},{"location":"api_reference/ui/ui_layouts/vertical_layout/#see-also","title":"See Also","text":"
  • UILayout - Base layout class (abstract)
  • UIButton - Buttons for menus
  • Manual - User Interface
  • API Overview
"},{"location":"getting_started/fundamental_concepts/","title":"Fundamental Concepts","text":"

Before you start programming, it's important to understand the basic concepts that form PixelRoot32's architecture. This section explains how the engine works at a conceptual level, without going into code details.

"},{"location":"getting_started/fundamental_concepts/#engine-architecture","title":"Engine Architecture","text":""},{"location":"getting_started/fundamental_concepts/#engine-the-heart-of-the-engine","title":"Engine: The Heart of the Engine","text":"

The Engine is the main class that orchestrates the entire system. Think of it as the conductor that coordinates all subsystems:

  • Renderer: Handles drawing everything on screen
  • InputManager: Reads and processes user input (buttons, keyboard)
  • AudioEngine: Generates and plays sounds and music
  • SceneManager: Manages game scenes (menus, levels, etc.)

The Engine runs the main game loop: an infinite cycle that updates game logic and draws each frame on screen. It also calculates delta time (time elapsed between frames) so the game runs at the same speed regardless of framerate.

"},{"location":"getting_started/fundamental_concepts/#scene-organizing-your-game","title":"Scene: Organizing Your Game","text":"

A Scene represents a screen or level in your game. For example: - A scene for the main menu - A scene for each game level - A scene for the game over screen - A scene for the pause menu

Each scene contains and manages a set of entities (characters, enemies, objects, etc.). The scene is responsible for: - Initializing its entities when loaded - Updating the logic of all its entities each frame - Drawing all its visible entities each frame - Managing collisions between entities that can collide

The Engine can only have one active scene at a time, but you can easily switch between scenes (for example, go from menu to game, or from game to pause menu).

"},{"location":"getting_started/fundamental_concepts/#entity-the-fundamental-building-blocks","title":"Entity: The Fundamental Building Blocks","text":"

An Entity is any object in your game that has: - Position (x, y) in the world - Size (width and height) - Visibility (can be visible or not) - Active state (can be enabled or disabled) - Render layer (in what order it's drawn)

Entities are the foundation of everything in your game: the player, enemies, projectiles, objects, UI elements\u2014everything is an entity or inherits from Entity.

Each entity has two main methods: - update(): Called each frame to update the entity's logic (movement, animation, etc.) - draw(): Called each frame to draw the entity on screen

"},{"location":"getting_started/fundamental_concepts/#actor-entities-that-can-collide","title":"Actor: Entities That Can Collide","text":"

An Actor is a special entity that can participate in the collision system. In addition to everything an Entity has, an Actor has: - Collision layer: Which group it belongs to (e.g., \"player\", \"enemy\", \"projectile\") - Collision mask: Which other groups it can collide with - Hitbox: The shape used to detect collisions (usually a rectangle)

For example, a player might be on the \"player\" layer and have a mask that allows it to collide with \"enemies\" and \"obstacles\", but not with \"other players\".

When two actors collide, the system calls their onCollision() method so they can react (e.g., player loses health, enemy is destroyed, etc.).

"},{"location":"getting_started/fundamental_concepts/#physicsactor-entities-with-physics","title":"PhysicsActor: Entities with Physics","text":"

A PhysicsActor is an Actor that also has physical properties: - Velocity (vx, vy): Moves automatically according to its velocity - Gravity: Can fall automatically - Friction: Gradually loses velocity - Restitution: Bounces when it collides (like a ball)

The PhysicsActor updates automatically each frame, applying physics and moving the entity. It can also detect collisions with world boundaries (the walls of the play area).

"},{"location":"getting_started/fundamental_concepts/#entity-hierarchy","title":"Entity Hierarchy","text":"

The relationship between these classes is hierarchical:

Entity (base)\n  \u2514\u2500\u2500 Actor (can collide)\n       \u2514\u2500\u2500 PhysicsActor (has physics)\n

This means: - Every Actor is also an Entity - Every PhysicsActor is also an Actor and an Entity - You can use Entity for simple objects that don't need collisions - You can use Actor for objects that need to detect collisions - You can use PhysicsActor for objects that need automatic physics

"},{"location":"getting_started/fundamental_concepts/#rendering-system","title":"Rendering System","text":""},{"location":"getting_started/fundamental_concepts/#render-layers","title":"Render Layers","text":"

To control the order in which things are drawn, PixelRoot32 uses render layers:

  • Layer 0 (Background): Backgrounds, tilemaps, background elements
  • Layer 1 (Gameplay): Characters, enemies, projectiles, game objects
  • Layer 2 (UI): Menus, HUD, text, interface elements

Layers are drawn in order: first 0, then 1, and finally 2. This ensures the background is always behind, gameplay in the middle, and UI always visible in front.

Each entity has a renderLayer property that indicates which layer it should be drawn on. You can change this property to move entities between layers.

"},{"location":"getting_started/fundamental_concepts/#resolution-scaling","title":"Resolution Scaling","text":"

PixelRoot32 supports Independent Resolution Scaling. This means your game logic can run at a different resolution (the logical resolution) than the physical screen (physical resolution).

  • Logical Resolution: The resolution you program for (e.g., 128x128). All coordinates and sizes in your code refer to this space.
  • Physical Resolution: The actual number of pixels on your display (e.g., 240x240).

The engine automatically handles the scaling using an optimized hardware-accelerated process, allowing you to create low-resolution retro games that look crisp on modern high-resolution micro-displays.

"},{"location":"getting_started/fundamental_concepts/#rendering-pipeline","title":"Rendering Pipeline","text":"

The rendering process works like this:

  1. beginFrame(): The screen is cleared (painted black or background color)
  2. Draw entities: All visible entities are traversed, organized by layer
  3. endFrame(): The complete frame is sent to the display

The Renderer abstracts hardware details, so the same code works on both ESP32 (TFT_eSPI) and PC (SDL2).

"},{"location":"getting_started/fundamental_concepts/#coordinates-and-space","title":"Coordinates and Space","text":"

PixelRoot32 uses a standard coordinate system: - Origin (0, 0): Top-left corner - X-axis: Increases to the right - Y-axis: Increases downward

Coordinates are in pixels. If your display is 240x240, coordinates range from (0, 0) to (239, 239).

"},{"location":"getting_started/fundamental_concepts/#lifecycle","title":"Lifecycle","text":""},{"location":"getting_started/fundamental_concepts/#initialization","title":"Initialization","text":"

When your game starts:

  1. Configuration: Configuration objects are created (DisplayConfig, InputConfig, AudioConfig)
  2. Engine: The Engine is created with these configurations
  3. init(): engine.init() is called to initialize all subsystems
  4. Scene: The initial scene is created and configured
  5. setScene(): The scene is assigned to the Engine
"},{"location":"getting_started/fundamental_concepts/#game-loop","title":"Game Loop","text":"

Once initialized, the Engine enters the game loop:

While the game is running:\n  1. Calculate deltaTime (time since last frame)\n  2. Update InputManager (read buttons/keyboard)\n  3. Update AudioEngine (advance sounds and music)\n  4. Update current scene (update all entities)\n  5. Detect collisions in the scene\n  6. Draw the scene (draw all visible entities)\n  7. Repeat\n

This cycle runs continuously, typically at 30-60 FPS on ESP32, or faster on PC.

"},{"location":"getting_started/fundamental_concepts/#update","title":"Update","text":"

Each frame, all enabled entities receive a call to their update(deltaTime) method. This is where: - Entities move - Animations update - Game logic is processed - User input is read - Sound effects are played

The deltaTime is passed in milliseconds and represents how much time has passed since the last frame. This allows movement to be framerate-independent.

"},{"location":"getting_started/fundamental_concepts/#rendering-draw","title":"Rendering (Draw)","text":"

After updating, all visible entities receive a call to their draw(renderer) method. This is where: - Sprites are drawn - Text is drawn - Primitives are drawn (rectangles, circles, etc.)

The renderer is passed as a parameter so entities can draw themselves.

"},{"location":"getting_started/fundamental_concepts/#cleanup","title":"Cleanup","text":"

When you change scenes or end the game: - Entities from the previous scene can be cleaned up - Resources are freed - The new scene is initialized

"},{"location":"getting_started/fundamental_concepts/#conceptual-summary","title":"Conceptual Summary","text":"

To summarize, PixelRoot32 works like this:

  1. Engine coordinates everything and runs the game loop
  2. Scene organizes your game into screens/levels
  3. Entity is any object in your game
  4. Actor is an entity that can collide
  5. PhysicsActor is an actor with automatic physics
  6. Renderer draws everything on screen using layers
  7. Each frame updates logic and then draws

All of this works automatically once you configure the Engine and create your scenes and entities. You don't need to worry about game loop details; you just need to implement update() and draw() in your entities.

"},{"location":"getting_started/fundamental_concepts/#next-step","title":"Next Step","text":"

Now that you understand the fundamental concepts, you're ready to create your first project and see these concepts in action with real code.

See also: - What is PixelRoot32? - Why PixelRoot32? - Your First Project - Manual - Scenes and Entities

"},{"location":"getting_started/installation/","title":"Installation","text":"

This guide covers installing the PixelRoot32 documentation environment and preparing your development setup for ESP32 and Native (PC) targets.

"},{"location":"getting_started/installation/#requirements","title":"Requirements","text":"
  • Python 3.11 or newer
  • Git (recommended for source management)
  • VS Code (or your preferred IDE)
  • For ESP32 targets: PlatformIO (VS Code extension) with ESP32 toolchain
  • For Native targets: a C++ build toolchain (CMake or your OS-native toolchain)
"},{"location":"getting_started/installation/#install-documentation-tooling","title":"Install Documentation Tooling","text":"

To build and preview this documentation locally:

pip install mkdocs mkdocs-material mkdocs-minify-plugin mkdocs-git-revision-date-localized-plugin mike\nmkdocs serve\n

Open http://127.0.0.1:8000 in your browser to preview.

"},{"location":"getting_started/installation/#esp32-setup-recommended","title":"ESP32 Setup (Recommended)","text":"
  1. Install VS Code
  2. Install PlatformIO IDE extension
  3. Install ESP32 platform/toolchain via PlatformIO
  4. Clone the engine repository:
  5. https://github.com/Gperez88/PixelRoot32-Game-Engine
  6. Open the engine or example project in VS Code (PlatformIO)
  7. Build and upload to your ESP32 board

Tip: Use boards based on ESP32-WROOM/WROVER for best compatibility. Ensure a reliable USB cable and correct serial port selection.

"},{"location":"getting_started/installation/#native-pc-setup","title":"Native (PC) Setup","text":"
  1. Install a C++ toolchain (e.g., MSVC or MinGW on Windows)
  2. Install CMake (if the engine provides CMake build files)
  3. Clone the engine repository:
  4. https://github.com/Gperez88/PixelRoot32-Game-Engine
  5. Configure and build the native runtime:
  6. Follow the engine\u2019s native build instructions (Development \u2192 Compiling)
"},{"location":"getting_started/installation/#verify-your-environment","title":"Verify Your Environment","text":"
  • ESP32: Build and flash a minimal sample; confirm serial output and display if applicable
  • Native: Run the executable; confirm window output and input handling
"},{"location":"getting_started/installation/#troubleshooting","title":"Troubleshooting","text":"
  • If PlatformIO cannot find the ESP32 platform, update PlatformIO and retry
  • If native builds fail, verify compiler versions and CMake generator settings
  • Use Community \u2192 Troubleshooting for common issues and fixes
"},{"location":"getting_started/installation/#next-steps","title":"Next Steps","text":"
  • First Project
  • Concepts
"},{"location":"getting_started/what_is_pixelroot32/","title":"What is PixelRoot32?","text":"

PixelRoot32 is a lightweight, modular 2D game engine written in C++ designed specifically for ESP32 microcontrollers, with a native simulation layer for PC (SDL2) that allows you to develop and debug quickly on your desktop before deploying to hardware.

"},{"location":"getting_started/what_is_pixelroot32/#simple-definition","title":"Simple Definition","text":"

PixelRoot32 is a game engine that lets you create retro-style 8-bit/16-bit video games directly on an ESP32 board, with the ability to develop and test on your PC before transferring code to hardware.

"},{"location":"getting_started/what_is_pixelroot32/#key-features","title":"Key Features","text":""},{"location":"getting_started/what_is_pixelroot32/#scene-based-architecture","title":"\ud83c\udfae Scene-Based Architecture","text":"
  • Scene system inspired by Godot Engine
  • Intuitive management of levels, menus, and screens
  • Simple transitions between scenes
"},{"location":"getting_started/what_is_pixelroot32/#optimized-rendering","title":"\ud83c\udfa8 Optimized Rendering","text":"
  • 1bpp (monochrome) sprites as the standard format
  • Support for multi-layer sprites (MultiSprite)
  • Experimental 2bpp and 4bpp formats for higher fidelity
  • Retro color palette system (NES, GameBoy, PICO-8, etc.)
  • Compact tilemaps for backgrounds and levels
  • 2D camera with dead-zone for smooth scrolling
  • Render layer system (background, gameplay, UI)
"},{"location":"getting_started/what_is_pixelroot32/#nes-like-audio","title":"\ud83d\udd0a NES-like Audio","text":"
  • 4 audio channels (2 Pulse, 1 Triangle, 1 Noise)
  • Integrated sound effects system
  • Music player for background melodies
  • Backends for ESP32 (internal DAC or external I2S) and SDL2
"},{"location":"getting_started/what_is_pixelroot32/#physics-and-collisions","title":"\ud83c\udfaf Physics and Collisions","text":"
  • AABB (Axis-Aligned Bounding Box) collision system
  • PhysicsActor with gravity, friction, and restitution
  • Collision layers and masks for fine control
  • World boundary collision detection
"},{"location":"getting_started/what_is_pixelroot32/#user-interface","title":"\ud83d\udda5\ufe0f User Interface","text":"
  • Basic elements: Labels, Buttons, Panels
  • Automatic layouts: Vertical, Horizontal, Grid, Anchor
  • Integrated D-pad navigation
  • Scroll and viewport culling for long lists
"},{"location":"getting_started/what_is_pixelroot32/#optimized-for-esp32","title":"\u26a1 Optimized for ESP32","text":"
  • Efficient memory management
  • Integrated object pooling
  • No dynamic allocations in the game loop
  • Performance optimized for limited hardware
"},{"location":"getting_started/what_is_pixelroot32/#typical-use-cases","title":"Typical Use Cases","text":"

PixelRoot32 is ideal for creating:

  • Arcade Games: Space Invaders, Pong, Breakout
  • Platformers: Horizontal scrolling games with simple physics
  • Puzzles: Tetris, Snake, logic games
  • Simple RPGs: Basic role-playing games with tilemaps
  • Shooters: Vertical or horizontal shooting games
  • Rapid Prototypes: Quick development of game ideas
"},{"location":"getting_started/what_is_pixelroot32/#supported-platforms","title":"Supported Platforms","text":""},{"location":"getting_started/what_is_pixelroot32/#esp32","title":"ESP32","text":"
  • Display: TFT_eSPI (ST7735, ILI9341, ST7789, etc.)
  • Audio: Internal DAC (GPIO 25/26) or external I2S (MAX98357A, PCM5102)
  • Input: Digital buttons, D-pad
  • Hardware: Any ESP32 board (ESP32-WROOM, ESP32-WROVER, etc.)
"},{"location":"getting_started/what_is_pixelroot32/#desktopnative-pc","title":"Desktop/Native (PC)","text":"
  • Display: SDL2 (Windows, Linux, macOS)
  • Audio: SDL2 Audio
  • Input: Keyboard, mouse
  • Usage: Development, debugging, testing

Note: Support for u8g2 (OLEDs) is planned for the future.

"},{"location":"getting_started/what_is_pixelroot32/#project-status","title":"Project Status","text":"

Current Version: v0.2.0-dev

PixelRoot32 is under active development. APIs may change and some subsystems are still experimental. Occasional changes or breaking changes are expected, especially on less-tested configurations.

"},{"location":"getting_started/what_is_pixelroot32/#stable-features","title":"Stable Features","text":"
  • Scene and entity system
  • Basic rendering (1bpp sprites)
  • NES-like audio system
  • Basic physics and collisions
  • Basic UI system
  • ESP32 and Native support
"},{"location":"getting_started/what_is_pixelroot32/#experimental-features","title":"Experimental Features","text":"
  • 2bpp and 4bpp sprites (require compilation flags)
  • Scene Arena (advanced memory management)
"},{"location":"getting_started/what_is_pixelroot32/#planned-features","title":"Planned Features","text":"
  • Support for u8g2 (OLEDs)
  • Music compiler
  • Tilemap compiler
  • Save/load system
  • Spatial partitioning for collisions
"},{"location":"getting_started/what_is_pixelroot32/#quick-comparison","title":"Quick Comparison","text":""},{"location":"getting_started/what_is_pixelroot32/#when-to-use-pixelroot32","title":"When to use PixelRoot32?","text":"

\u2705 Use PixelRoot32 if: - You want to create retro games on ESP32 - You need a lightweight and efficient engine - You prefer a simple and clear architecture - You want to develop on PC and deploy to ESP32 - You like 8-bit/16-bit style games

\u274c Don't use PixelRoot32 if: - You need 3D graphics - You require advanced shaders - You need complex physics (advanced physics engines) - You want to create modern AAA games - You need support for multiple mobile platforms

"},{"location":"getting_started/what_is_pixelroot32/#next-step","title":"Next Step","text":"

Now that you understand what PixelRoot32 is, discover why you should use it or go directly to your first project.

See also: - Fundamental Concepts - Installation - API Reference

"},{"location":"getting_started/why_pixelroot32/","title":"Why PixelRoot32?","text":"

PixelRoot32 is specifically designed to solve the unique challenges of creating video games on embedded hardware like the ESP32, while maintaining the simplicity and productivity of modern development.

"},{"location":"getting_started/why_pixelroot32/#main-advantages","title":"Main Advantages","text":""},{"location":"getting_started/why_pixelroot32/#optimized-for-esp32","title":"\ud83c\udfaf Optimized for ESP32","text":"

Memory Efficient - 1bpp sprite system that minimizes RAM and Flash usage - Integrated object pooling to avoid memory fragmentation - Compact tilemaps that reuse sprites - No dynamic allocations in the game loop

Performance Optimized - Rendering optimized for ESP32 limitations - Efficient render layer system - Viewport culling to reduce draw calls - Rendering pipeline designed for limited hardware

Real Hardware - Direct support for common TFT displays (ST7735, ILI9341, ST7789) - Integrated audio (internal DAC or external I2S) - Simple pin and hardware configuration

"},{"location":"getting_started/why_pixelroot32/#cross-platform-development","title":"\ud83d\udda5\ufe0f Cross-Platform Development","text":"

Develop on PC, Deploy to ESP32 - Same code works on PC (SDL2) and ESP32 - Fast debugging on desktop - Testing without hardware needed - Rapid development iteration

Visual Consistency - Native bitmap font system (pixel-perfect) - Same rendering on PC and ESP32 - Consistent color palettes - No surprises when transferring to hardware

"},{"location":"getting_started/why_pixelroot32/#retro-palette-system","title":"\ud83c\udfa8 Retro Palette System","text":"

Authentic Style - Predefined palettes: NES, GameBoy, GameBoy Color, PICO-8 - Dual palette mode for visual contrasts - Custom palettes for unique styles - Automatic color resolution (RGB565)

Easy to Use - Change palette with one line of code - Consistent visualization across all sprites - No need to manually convert assets

"},{"location":"getting_started/why_pixelroot32/#integrated-audio","title":"\ud83d\udd0a Integrated Audio","text":"

Complete NES-like System - 4 audio channels (2 Pulse, 1 Triangle, 1 Noise) - Simple sound effects to create - Integrated music system - Backends for different hardware configurations

No External Dependencies - Software-generated audio - No heavy audio libraries required - Full control over sound - Deterministic and predictable

"},{"location":"getting_started/why_pixelroot32/#simple-and-clear-architecture","title":"\ud83c\udfd7\ufe0f Simple and Clear Architecture","text":"

Easy to Understand - Intuitive scene system (inspired by Godot) - Clear hierarchy: Entity \u2192 Actor \u2192 PhysicsActor - Consistent and predictable APIs - Clean and well-organized code

Quick to Learn - Familiar concepts for game developers - Clear documentation and complete examples - Smooth learning curve - Active community and support

"},{"location":"getting_started/why_pixelroot32/#complete-features","title":"\ud83c\udfae Complete Features","text":"

Everything Needed for Games - Rendering (sprites, tilemaps, primitives) - Audio (effects and music) - Physics (gravity, collisions, basic physics) - UI (layouts, buttons, navigation) - Input (buttons, keyboard) - Camera (scroll, parallax)

No Bloat - Only the essentials, nothing more - No heavy dependencies - Small and maintainable codebase - Easy to understand and modify

"},{"location":"getting_started/why_pixelroot32/#tools-and-ecosystem","title":"\ud83d\udee0\ufe0f Tools and Ecosystem","text":"

Available Tools - Sprite Compiler to convert PNG to sprites - Complete game examples - Templates and starter code - Extensive documentation

Community and Support - Active and developing project - Open source (MIT License) - Feedback and contributions welcome - Examples available

"},{"location":"getting_started/why_pixelroot32/#comparison-with-alternatives","title":"Comparison with Alternatives","text":""},{"location":"getting_started/why_pixelroot32/#vs-full-engines-unity-godot-etc","title":"vs. Full Engines (Unity, Godot, etc.)","text":"

PixelRoot32 Advantages: - \u2705 Much lighter (fits in ESP32) - \u2705 No unnecessary overhead - \u2705 Full control over code - \u2705 Specifically optimized for limited hardware

Disadvantages: - \u274c Fewer advanced features - \u274c No visual editor - \u274c Fewer resources and community

"},{"location":"getting_started/why_pixelroot32/#vs-writing-everything-from-scratch","title":"vs. Writing Everything from Scratch","text":"

PixelRoot32 Advantages: - \u2705 Rendering system already implemented - \u2705 Integrated and working audio - \u2705 Physics and collisions ready - \u2705 Complete UI system - \u2705 Saves months of development

Disadvantages: - \u274c Less control over internal implementation - \u274c You must learn the engine API

"},{"location":"getting_started/why_pixelroot32/#vs-other-esp32-engines","title":"vs. Other ESP32 Engines","text":"

PixelRoot32 Advantages: - \u2705 More modern and clear architecture - \u2705 Better documentation - \u2705 Unique palette system - \u2705 Integrated NES-like audio - \u2705 Real cross-platform development

"},{"location":"getting_started/why_pixelroot32/#ideal-use-cases","title":"Ideal Use Cases","text":"

PixelRoot32 is perfect for:

  1. Educational Projects
  2. Learn game development
  3. Understand engine architecture
  4. Student projects

  5. Rapid Prototypes

  6. Quickly validate game ideas
  7. Create demos and proof-of-concepts
  8. Test mechanics

  9. Retro Games

  10. 8-bit/16-bit style games
  11. Arcade games
  12. Games with retro aesthetics

  13. Hardware Projects

  14. Games on small displays
  15. DIY portable consoles
  16. Maker/retro projects

  17. C++ Learning

  18. Clean and well-structured code
  19. Good programming practices
  20. Real and functional examples
"},{"location":"getting_started/why_pixelroot32/#limitations-to-consider","title":"Limitations to Consider","text":"

To be honest, PixelRoot32 has limitations:

  • Limited Hardware: Designed for ESP32, not powerful PCs
  • Simple Graphics: No 3D, no advanced shaders
  • Basic Physics: Not a complete physics engine
  • Restricted Memory: MAX_ENTITIES = 32 per scene
  • In Development: Some features are experimental

If you need advanced features or powerful hardware, consider other engines. But for retro games on ESP32, PixelRoot32 is an excellent choice.

"},{"location":"getting_started/why_pixelroot32/#conclusion","title":"Conclusion","text":"

PixelRoot32 combines:

  • \u2705 Simplicity of use
  • \u2705 Efficiency for limited hardware
  • \u2705 Completeness of essential features
  • \u2705 Clarity of architecture
  • \u2705 Productivity in development

If you want to create retro games on ESP32 without the complexity of large engines, PixelRoot32 is the right choice.

"},{"location":"getting_started/why_pixelroot32/#next-step","title":"Next Step","text":"

Now that you understand why PixelRoot32 is a good option, learn the fundamental concepts or start directly with your first project.

See also: - What is PixelRoot32? - Fundamental Concepts - Your First Project

"},{"location":"getting_started/your_first_project/","title":"Your First Project","text":"

This guide will walk you through creating and running your first PixelRoot32 project step by step. By the end, you'll have a working project that displays a simple scene on both ESP32 and PC.

"},{"location":"getting_started/your_first_project/#prerequisites","title":"Prerequisites","text":""},{"location":"getting_started/your_first_project/#required-software","title":"Required Software","text":"
  • PlatformIO: Install the PlatformIO IDE extension in VS Code
  • Open VS Code
  • Go to Extensions (Ctrl+Shift+X)
  • Search for \"PlatformIO IDE\"
  • Install and restart VS Code

  • Python 3.8+: Required for PlatformIO (usually installed automatically)

"},{"location":"getting_started/your_first_project/#for-esp32-development","title":"For ESP32 Development","text":"
  • ESP32 Board: Any ESP32 development board (ESP32-WROOM, ESP32-WROVER, etc.)
  • USB Cable: To connect and program your ESP32
  • TFT Display: Compatible display (ST7735, ST7789, ILI9341, etc.)
  • Buttons: 5-6 digital buttons for input (optional for first project)
  • Audio Hardware (optional): Speaker + amplifier (PAM8302A) or I2S DAC (MAX98357A)
"},{"location":"getting_started/your_first_project/#for-native-pc-development","title":"For Native (PC) Development","text":"
  • SDL2: Development libraries
  • Windows (MSYS2): pacman -S mingw-w64-x86_64-SDL2
  • Linux: sudo apt-get install libsdl2-dev
  • macOS: brew install sdl2
"},{"location":"getting_started/your_first_project/#step-1-create-a-new-platformio-project","title":"Step 1: Create a New PlatformIO Project","text":"
  1. Open VS Code with PlatformIO installed

  2. Create New Project:

  3. Click on the PlatformIO icon in the sidebar
  4. Click \"New Project\"
  5. Name: my-first-pixelroot32-game
  6. Board: Select \"ESP32 Dev Module\" (or your specific board)
  7. Framework: Arduino
  8. Location: Choose your workspace folder
  9. Click \"Finish\"

  10. Project Structure: Your project should now have this structure:

    my-first-pixelroot32-game/\n\u251c\u2500\u2500 .pio/\n\u251c\u2500\u2500 include/\n\u251c\u2500\u2500 lib/\n\u251c\u2500\u2500 src/\n\u2502   \u2514\u2500\u2500 main.cpp\n\u251c\u2500\u2500 test/\n\u2514\u2500\u2500 platformio.ini\n

"},{"location":"getting_started/your_first_project/#step-2-install-pixelroot32-engine","title":"Step 2: Install PixelRoot32 Engine","text":""},{"location":"getting_started/your_first_project/#option-a-via-platformio-library-manager-recommended","title":"Option A: Via PlatformIO Library Manager (Recommended)","text":"
  1. Open platformio.ini

  2. Add the library dependency:

[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = arduino\nlib_deps = \n    gperez88/PixelRoot32-Game-Engine@0.2.0-dev\n

\u26a0\ufe0f IMPORTANT: Use the exact version 0.2.0-dev. Do NOT use ^ or fuzzy versioning.

  1. Save the file. PlatformIO will automatically download the library.
"},{"location":"getting_started/your_first_project/#option-b-git-submodule","title":"Option B: Git Submodule","text":"
  1. Open terminal in your project root

  2. Add as submodule:

    git submodule add https://github.com/Gperez88/PixelRoot32-Game-Engine.git lib/PixelRoot32-Game-Engine\n

  3. Update platformio.ini:

    lib_extra_dirs = lib\n

"},{"location":"getting_started/your_first_project/#step-3-configure-hardware-esp32","title":"Step 3: Configure Hardware (ESP32)","text":""},{"location":"getting_started/your_first_project/#configure-tft_espi-display","title":"Configure TFT_eSPI Display","text":"

Edit platformio.ini and add build flags for your display. Here are two common configurations:

For ST7789 (240x240):

[env:esp32dev]\nplatform = espressif32\nboard = esp32dev\nframework = arduino\nlib_deps = \n    gperez88/PixelRoot32-Game-Engine@0.2.0-dev\n    bodmer/TFT_eSPI@^2.5.43\n\nbuild_flags = \n    -D ST7789_DRIVER\n    -D TFT_WIDTH=240\n    -D TFT_HEIGHT=240\n    -D TFT_MOSI=23\n    -D TFT_SCLK=18\n    -D TFT_DC=2\n    -D TFT_RST=4\n    -D TFT_CS=-1\n    -D LOAD_GLCD\n    -D LOAD_FONT2\n    -D LOAD_FONT4\n    -D LOAD_FONT6\n    -D LOAD_FONT7\n    -D LOAD_FONT8\n    -D LOAD_GFXFF\n    -D SMOOTH_FONT\n    -D SPI_FREQUENCY=40000000\n    -D SPI_READ_FREQUENCY=20000000\n

For ST7735 (128x128):

build_flags = \n    -D ST7735_DRIVER\n    -D ST7735_GREENTAB3\n    -D TFT_WIDTH=128\n    -D TFT_HEIGHT=128\n    -D TFT_MOSI=23\n    -D TFT_SCLK=18\n    -D TFT_DC=2\n    -D TFT_RST=4\n    -D TFT_CS=-1\n    -D LOAD_GLCD\n    -D LOAD_FONT2\n    -D LOAD_FONT4\n    -D LOAD_FONT6\n    -D LOAD_FONT7\n    -D LOAD_FONT8\n    -D LOAD_GFXFF\n    -D SMOOTH_FONT\n    -D SPI_FREQUENCY=27000000\n    -D SPI_READ_FREQUENCY=20000000\n

Note: Adjust the pin numbers (TFT_MOSI, TFT_SCLK, TFT_DC, TFT_RST) to match your hardware wiring.

"},{"location":"getting_started/your_first_project/#configure-input-optional-for-first-project","title":"Configure Input (Optional for First Project)","text":"

If you have buttons connected, note the GPIO pins. For now, we'll create a project that works without input.

"},{"location":"getting_started/your_first_project/#configure-audio-optional-for-first-project","title":"Configure Audio (Optional for First Project)","text":"

Audio is optional for the first project. We'll add it later.

"},{"location":"getting_started/your_first_project/#step-4-create-your-first-scene","title":"Step 4: Create Your First Scene","text":"

Create a new file src/MyFirstScene.h:

#pragma once\n#include <core/Scene.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass MyFirstScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Called when the scene is initialized\n        // Set up your scene here\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Called every frame\n        // Update game logic here\n        Scene::update(deltaTime); // Don't forget to call parent update!\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Called every frame to draw\n        // Draw your scene here\n\n        // Example: Draw a simple rectangle\n        renderer.drawFilledRectangle(50, 50, 100, 100, pixelroot32::graphics::Color::Blue);\n\n        // Example: Draw text\n        renderer.drawText(\"Hello PixelRoot32!\", 20, 20, pixelroot32::graphics::Color::White, 2);\n\n        // Don't forget to call parent draw to draw all entities!\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"getting_started/your_first_project/#step-5-create-main-file-esp32","title":"Step 5: Create Main File (ESP32)","text":"

Replace the contents of src/main.cpp with:

#include <Arduino.h>\n#include <core/Engine.h>\n#include <drivers/esp32/TFT_eSPI_Drawer.h>\n#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n#include \"MyFirstScene.h\"\n\nnamespace pr32 = pixelroot32;\n\n// Audio configuration (optional - can be omitted for first project)\nconst int DAC_PIN = 25; // GPIO 25 or 26\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\n// Display configuration\n// 128x128 game logic scaled to 240x240 display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::ST7789, \n    0,      // rotation\n    240, 240, // physical resolution (hardware)\n    128, 128  // logical resolution (rendering space)\n);\n\n// Input configuration (6 buttons: UP, DOWN, LEFT, RIGHT, A, B)\n// For now, we'll use dummy pins - you can change these later\npr32::input::InputConfig inputConfig(\n    6,      // button count\n    32,     // UP pin\n    27,     // DOWN pin\n    33,     // LEFT pin\n    14,     // RIGHT pin\n    13,     // A button pin\n    12      // B button pin\n);\n\n// Audio configuration\npr32::audio::AudioConfig audioConfig(&audioBackend, audioBackend.getSampleRate());\n\n// Create the engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\n// Create your scene\nMyFirstScene myScene;\n\nvoid setup() {\n    Serial.begin(115200);\n\n    // Initialize the engine\n    engine.init();\n\n    // Initialize and set the scene\n    myScene.init();\n    engine.setScene(&myScene);\n\n    Serial.println(\"PixelRoot32 initialized!\");\n}\n\nvoid loop() {\n    // Run the game loop\n    engine.run();\n}\n
"},{"location":"getting_started/your_first_project/#step-6-create-native-version-optional","title":"Step 6: Create Native Version (Optional)","text":"

If you want to test on PC first, create src/main_native.cpp:

#define SDL_MAIN_HANDLED\n#include <SDL2/SDL.h>\n#include <core/Engine.h>\n#include <drivers/native/SDL2_Drawer.h>\n#include <drivers/native/SDL2_AudioBackend.h>\n#include \"MyFirstScene.h\"\n\nnamespace pr32 = pixelroot32;\n\n// Audio configuration\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\n\n// Display configuration (NONE defaults to SDL2 on Native)\n// 128x128 game logic scaled to 240x240 display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::NONE,\n    0,      // rotation\n    240, 240, // physical resolution\n    128, 128  // logical resolution\n);\n\n// Input configuration (SDL scancodes)\npr32::input::InputConfig inputConfig(\n    6,                      // button count\n    SDL_SCANCODE_UP,        // UP\n    SDL_SCANCODE_DOWN,      // DOWN\n    SDL_SCANCODE_LEFT,      // LEFT\n    SDL_SCANCODE_RIGHT,     // RIGHT\n    SDL_SCANCODE_SPACE,     // A button\n    SDL_SCANCODE_RETURN     // B button\n);\n\n// Audio configuration\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n\n// Create the engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\n// Create your scene\nMyFirstScene myScene;\n\nint main(int argc, char* argv[]) {\n    (void)argc;\n    (void)argv;\n\n    // Initialize the engine\n    engine.init();\n\n    // Initialize and set the scene\n    myScene.init();\n    engine.setScene(&myScene);\n\n    // Run the game loop\n    engine.run();\n\n    return 0;\n}\n
"},{"location":"getting_started/your_first_project/#configure-native-build","title":"Configure Native Build","text":"

Add to platformio.ini:

[env:native]\nplatform = native\nbuild_src_filter = \n    +<*>\n    -<main.cpp>\nlib_extra_dirs = lib\nbuild_flags = \n    -D PLATFORM_NATIVE\n    -Isrc\n    -Ilib/PixelRoot32-Game-Engine/include\n    -IC:/msys64/mingw64/include/SDL2    # Windows MSYS2 path - adjust for your system\n    -LC:/msys64/mingw64/lib             # Windows MSYS2 path - adjust for your system\n    -O2\n    -Wall\n    -Wextra\n    -std=c++17\n    -lSDL2\n    -mconsole\n

Note: Adjust the SDL2 include and library paths for your system.

"},{"location":"getting_started/your_first_project/#step-7-build-and-run","title":"Step 7: Build and Run","text":""},{"location":"getting_started/your_first_project/#for-esp32","title":"For ESP32","text":"
  1. Connect your ESP32 via USB
  2. Select the environment: Click on the PlatformIO icon \u2192 Select env:esp32dev
  3. Build: Click the checkmark icon (\u2713) or press Ctrl+Alt+B
  4. Upload: Click the arrow icon (\u2192) or press Ctrl+Alt+U
  5. Monitor: Click the plug icon to open serial monitor

You should see \"PixelRoot32 initialized!\" in the serial monitor and your display should show a blue rectangle and text.

"},{"location":"getting_started/your_first_project/#for-native-pc","title":"For Native (PC)","text":"
  1. Select the environment: Click on the PlatformIO icon \u2192 Select env:native
  2. Build and Run: Click the play icon (\u25b6) or press Ctrl+Alt+R

A window should open showing your scene with a blue rectangle and \"Hello PixelRoot32!\" text.

"},{"location":"getting_started/your_first_project/#step-8-verify-it-works","title":"Step 8: Verify It Works","text":"

If everything is set up correctly, you should see:

  • ESP32: Display shows a blue rectangle at (50, 50) and white text \"Hello PixelRoot32!\" at (20, 20)
  • Native: Window shows the same content

If you see this, congratulations! Your first PixelRoot32 project is working.

"},{"location":"getting_started/your_first_project/#troubleshooting","title":"Troubleshooting","text":""},{"location":"getting_started/your_first_project/#esp32-issues","title":"ESP32 Issues","text":"

Display is blank: - Check wiring connections - Verify pin numbers in platformio.ini match your hardware - Check SPI frequency (try lowering it) - Verify display type (ST7789 vs ST7735)

Compilation errors: - Ensure library version is exactly 0.2.0-dev - Check that TFT_eSPI is installed - Verify all include paths are correct

Upload fails: - Check USB cable connection - Try different USB port - Press BOOT button on ESP32 during upload - Check COM port in PlatformIO

"},{"location":"getting_started/your_first_project/#native-issues","title":"Native Issues","text":"

SDL2 not found: - Verify SDL2 is installed - Check include/library paths in platformio.ini - On Windows, ensure MSYS2 paths are correct

Window doesn't open: - Check console for error messages - Verify SDL2 is properly linked - Try running from terminal to see errors

"},{"location":"getting_started/your_first_project/#next-steps","title":"Next Steps","text":"

Now that you have a working project, you can:

  1. Learn about Scenes and Entities: See how to create game objects
  2. Add Input: Make your scene respond to buttons
  3. Add Sprites: Draw custom graphics
  4. Add Audio: Play sounds and music

Continue with the Development Guide to learn more.

See also: - Fundamental Concepts - Installation - Manual - Scenes and Entities - API Reference

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/","title":"Cameras and Scrolling","text":"

Camera2D allows you to create worlds larger than the screen by scrolling the view. This guide covers camera setup, following targets, boundaries, and parallax effects.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera2d-basics","title":"Camera2D Basics","text":"

A Camera2D defines what portion of your game world is visible on screen.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#creating-a-camera","title":"Creating a Camera","text":"
#include <graphics/Camera2D.h>\n\n// Create camera with viewport size\npixelroot32::graphics::Camera2D camera(240, 240); // Screen width, height\n\n// Set camera position\ncamera.setPosition(0, 0);\n\n// Apply camera to renderer (in draw method)\ncamera.apply(renderer);\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#how-it-works","title":"How It Works","text":"

The camera translates world coordinates to screen coordinates: - Objects at world position (100, 50) with camera at (0, 0) appear at screen (100, 50) - Objects at world position (100, 50) with camera at (50, 0) appear at screen (50, 50) - The camera effectively \"moves\" the world relative to the screen

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#following-a-target","title":"Following a Target","text":"

The most common use is following a player or other target.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#basic-follow","title":"Basic Follow","text":"
class GameScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        // Create camera\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n\n        // Create player\n        player = new PlayerActor(500, 300); // World position\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Make camera follow player\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera before drawing\n        camera.apply(renderer);\n\n        // Now all drawing uses camera coordinates\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#dead-zone-smooth-following","title":"Dead Zone (Smooth Following)","text":"

For smoother following, you can implement a dead zone where the camera doesn't move until the target leaves the zone:

void update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);\n\n    // Get screen center\n    int screenCenterX = engine.getRenderer().getWidth() / 2;\n    int screenCenterY = engine.getRenderer().getHeight() / 2;\n\n    // Calculate player position relative to screen center\n    float playerScreenX = player->x - camera.getX();\n    float playerScreenY = player->y - camera.getY();\n\n    // Dead zone size\n    const int DEAD_ZONE_X = 40;\n    const int DEAD_ZONE_Y = 40;\n\n    // Move camera if player leaves dead zone\n    if (playerScreenX < screenCenterX - DEAD_ZONE_X) {\n        camera.setPosition(player->x - (screenCenterX - DEAD_ZONE_X), camera.getY());\n    } else if (playerScreenX > screenCenterX + DEAD_ZONE_X) {\n        camera.setPosition(player->x - (screenCenterX + DEAD_ZONE_X), camera.getY());\n    }\n\n    if (playerScreenY < screenCenterY - DEAD_ZONE_Y) {\n        camera.setPosition(camera.getX(), player->y - (screenCenterY - DEAD_ZONE_Y));\n    } else if (playerScreenY > screenCenterY + DEAD_ZONE_Y) {\n        camera.setPosition(camera.getX(), player->y - (screenCenterY + DEAD_ZONE_Y));\n    }\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-boundaries","title":"Camera Boundaries","text":"

Limit camera movement to keep it within your level bounds.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#setting-boundaries","title":"Setting Boundaries","text":"
void init() override {\n    // Create camera\n    camera = pixelroot32::graphics::Camera2D(240, 240);\n\n    // Set horizontal boundaries (level is 2000 pixels wide)\n    camera.setBounds(0, 2000 - 240); // minX, maxX\n\n    // Set vertical boundaries (level is 1000 pixels tall)\n    camera.setVerticalBounds(0, 1000 - 240); // minY, maxY\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#example-side-scroller-with-boundaries","title":"Example: Side-Scroller with Boundaries","text":"
class SideScrollerScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n    static const int LEVEL_WIDTH = 2000;\n    static const int LEVEL_HEIGHT = 240;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n\n        // Set boundaries (camera can't go outside level)\n        camera.setBounds(0, LEVEL_WIDTH - screenWidth);\n        camera.setVerticalBounds(0, LEVEL_HEIGHT - screenHeight);\n\n        // Create player at start\n        player = new PlayerActor(100, 100);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Follow player horizontally\n        camera.followTarget(player->x, camera.getY());\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#parallax-scrolling","title":"Parallax Scrolling","text":"

Parallax creates depth by moving background layers at different speeds.

"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#basic-parallax","title":"Basic Parallax","text":"
class ParallaxBackground : public pixelroot32::core::Entity {\nprivate:\n    float parallaxSpeed; // 0.0 to 1.0 (1.0 = normal, 0.5 = half speed)\n    float baseX;\n\npublic:\n    ParallaxBackground(float speed)\n        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::GENERIC),\n          parallaxSpeed(speed), baseX(0) {\n        setRenderLayer(0);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Get camera position\n        auto& camera = getCamera(); // You'll need to pass camera reference\n\n        // Calculate parallax offset\n        baseX = camera.getX() * parallaxSpeed;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background with parallax offset\n        renderer.drawTileMap(backgroundTileMap, \n            static_cast<int>(baseX), 0, \n            pixelroot32::graphics::Color::White);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#multiple-parallax-layers","title":"Multiple Parallax Layers","text":"
class ParallaxScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n\n    // Parallax layers (farther = slower)\n    ParallaxLayer* farBackground;    // Speed: 0.2\n    ParallaxLayer* midBackground;      // Speed: 0.5\n    ParallaxLayer* nearBackground;     // Speed: 0.8\n    PlayerActor* player;               // Speed: 1.0 (normal)\n\npublic:\n    void init() override {\n        camera = pixelroot32::graphics::Camera2D(240, 240);\n\n        // Create parallax layers\n        farBackground = new ParallaxLayer(0.2f);  // Moves slowest\n        midBackground = new ParallaxLayer(0.5f);\n        nearBackground = new ParallaxLayer(0.8f);\n\n        addEntity(farBackground);\n        addEntity(midBackground);\n        addEntity(nearBackground);\n\n        player = new PlayerActor(100, 100);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Update parallax layers with camera position\n        farBackground->updateParallax(camera.getX());\n        midBackground->updateParallax(camera.getX());\n        nearBackground->updateParallax(camera.getX());\n\n        // Follow player\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#using-setdisplayoffset-for-parallax","title":"Using setDisplayOffset for Parallax","text":"

For simpler parallax, you can use setDisplayOffset():

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera\n    camera.apply(renderer);\n\n    // Draw far background with offset (moves slower)\n    renderer.setDisplayOffset(\n        static_cast<int>(camera.getX() * 0.3f), \n        0\n    );\n    renderer.drawTileMap(farBackground, 0, 0, Color::White);\n\n    // Draw mid background\n    renderer.setDisplayOffset(\n        static_cast<int>(camera.getX() * 0.6f), \n        0\n    );\n    renderer.drawTileMap(midBackground, 0, 0, Color::White);\n\n    // Reset offset for normal drawing\n    renderer.setDisplayOffset(0, 0);\n\n    // Draw game objects (normal speed)\n    Scene::draw(renderer);\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#complete-example-platformer-with-camera","title":"Complete Example: Platformer with Camera","text":"
class PlatformerScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n    static const int LEVEL_WIDTH = 3000;\n    static const int LEVEL_HEIGHT = 800;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        // Create camera\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n\n        // Set boundaries\n        camera.setBounds(0, LEVEL_WIDTH - screenWidth);\n        camera.setVerticalBounds(0, LEVEL_HEIGHT - screenHeight);\n\n        // Create player\n        player = new PlayerActor(100, 400);\n        addEntity(player);\n\n        // Create platforms, enemies, etc.\n        // ...\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Follow player with dead zone\n        int screenCenterX = engine.getRenderer().getWidth() / 2;\n        int screenCenterY = engine.getRenderer().getHeight() / 2;\n\n        float playerScreenX = player->x - camera.getX();\n        float playerScreenY = player->y - camera.getY();\n\n        const int DEAD_ZONE = 60;\n\n        // Horizontal follow\n        if (playerScreenX < screenCenterX - DEAD_ZONE) {\n            camera.setPosition(player->x - (screenCenterX - DEAD_ZONE), camera.getY());\n        } else if (playerScreenX > screenCenterX + DEAD_ZONE) {\n            camera.setPosition(player->x - (screenCenterX + DEAD_ZONE), camera.getY());\n        }\n\n        // Vertical follow (only when falling or jumping high)\n        if (playerScreenY < screenCenterY - DEAD_ZONE || \n            playerScreenY > screenCenterY + DEAD_ZONE) {\n            camera.setPosition(camera.getX(), player->y - screenCenterY);\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw background (parallax)\n        renderer.setDisplayOffset(\n            static_cast<int>(camera.getX() * 0.3f), \n            0\n        );\n        renderer.drawTileMap(backgroundTileMap, 0, 0, Color::DarkGray);\n        renderer.setDisplayOffset(0, 0);\n\n        // Draw game objects\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-movement","title":"Camera Movement","text":"
  • Use dead zones: Prevents jittery camera movement
  • Smooth transitions: Consider lerping camera position for smoother movement
  • Set boundaries: Always limit camera to level bounds
  • Test on hardware: Camera performance may differ on ESP32
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#parallax","title":"Parallax","text":"
  • Layer speeds: Farther layers move slower (0.2-0.5), closer move faster (0.7-0.9)
  • Limit layers: Too many parallax layers can impact performance
  • Use tilemaps: Parallax works best with tilemaps
  • Test visually: Ensure parallax effect is noticeable but not distracting
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#performance","title":"Performance","text":"
  • Apply once: Call camera.apply() once per frame, at start of draw()
  • Cull off-screen: Don't draw entities outside camera view
  • Limit parallax layers: 2-3 layers is usually enough
  • Optimize tilemaps: Use efficient tilemap rendering
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-helper-class","title":"Camera Helper Class","text":"
class CameraController {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    float targetX, targetY;\n    float smoothSpeed = 0.1f;\n\npublic:\n    void followTarget(float x, float y) {\n        targetX = x;\n        targetY = y;\n    }\n\n    void update(unsigned long deltaTime) {\n        // Smooth camera movement\n        float currentX = camera.getX();\n        float currentY = camera.getY();\n\n        float newX = currentX + (targetX - currentX) * smoothSpeed;\n        float newY = currentY + (targetY - currentY) * smoothSpeed;\n\n        camera.setPosition(newX, newY);\n    }\n\n    void apply(pixelroot32::graphics::Renderer& renderer) {\n        camera.apply(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#viewport-culling","title":"Viewport Culling","text":"

Only draw entities within camera view:

bool isVisible(float x, float y, int width, int height) {\n    float cameraX = camera.getX();\n    float cameraY = camera.getY();\n    int screenWidth = engine.getRenderer().getWidth();\n    int screenHeight = engine.getRenderer().getHeight();\n\n    return !(x + width < cameraX || \n             x > cameraX + screenWidth ||\n             y + height < cameraY || \n             y > cameraY + screenHeight);\n}\n
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/cameras_and_scrolling/#camera-not-moving","title":"Camera Not Moving","text":"
  • Verify camera.apply() is called in draw()
  • Check followTarget() or setPosition() is called in update()
  • Ensure camera is created with correct viewport size
  • Check boundaries aren't preventing movement
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#objects-not-visible","title":"Objects Not Visible","text":"
  • Verify objects are within camera view
  • Check world coordinates vs screen coordinates
  • Ensure camera is applied before drawing
  • Verify render layers are correct
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#parallax-not-working","title":"Parallax Not Working","text":"
  • Check setDisplayOffset() is used correctly
  • Verify parallax speed values (0.0 to 1.0)
  • Ensure offset is reset after parallax layers
  • Test with different speed values
"},{"location":"manual/advanced_graphics/cameras_and_scrolling/#next-steps","title":"Next Steps","text":"

Now that you understand cameras and scrolling, learn about: - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects - Performance Optimization - Optimize your game

See also: - API Reference - Camera2D - Manual - Basic Rendering - Manual - Tilemaps

"},{"location":"manual/advanced_graphics/color_palettes/","title":"Color Palettes","text":"

PixelRoot32 uses a palette-based color system that allows you to easily change the visual style of your game. This guide covers built-in palettes, dual palette mode, and custom palettes.

"},{"location":"manual/advanced_graphics/color_palettes/#built-in-palettes","title":"Built-in Palettes","text":"

PixelRoot32 includes several predefined palettes inspired by classic gaming systems:

"},{"location":"manual/advanced_graphics/color_palettes/#available-palettes","title":"Available Palettes","text":"
#include <graphics/PaletteDefs.h>\n\nnamespace pixelroot32::graphics {\n\nenum class PaletteType {\n    PR32,    // PixelRoot32 default palette\n    NES,     // Nintendo Entertainment System\n    GB,      // GameBoy (4 shades of green)\n    GBC,     // GameBoy Color\n    PICO8    // PICO-8 palette\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#using-built-in-palettes","title":"Using Built-in Palettes","text":"
#include <graphics/PaletteDefs.h>\n\n// Set palette globally (legacy mode)\npixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n\n// All sprites will now use NES colors\nrenderer.drawSprite(MY_SPRITE, 100, 100, pixelroot32::graphics::Color::White);\n
"},{"location":"manual/advanced_graphics/color_palettes/#palette-characteristics","title":"Palette Characteristics","text":"

PR32 (Default) - Modern, balanced colors - Good contrast - Suitable for most games

NES - Classic 8-bit console colors - Limited color range - Nostalgic feel

GB (GameBoy) - 4 shades of green - Monochrome aesthetic - Classic handheld look

GBC (GameBoy Color) - Expanded color range - More vibrant than GB - Classic portable console

PICO8 - PICO-8 fantasy console palette - 16 carefully chosen colors - Popular for retro games

"},{"location":"manual/advanced_graphics/color_palettes/#legacy-mode-single-global-palette","title":"Legacy Mode (Single Global Palette)","text":"

In legacy mode, one palette is used for all sprites:

void MyScene::init() override {\n    // Set global palette\n    pixelroot32::graphics::setPalette(pixelroot32::graphics::PaletteType::NES);\n\n    // All sprites use NES colors\n    // This is the simplest mode\n}\n

When to use: - Simple games - Consistent visual style - Maximum compatibility

"},{"location":"manual/advanced_graphics/color_palettes/#dual-palette-mode","title":"Dual Palette Mode","text":"

Dual palette mode allows different palettes for background elements and sprites, creating visual contrast.

"},{"location":"manual/advanced_graphics/color_palettes/#enabling-dual-palette-mode","title":"Enabling Dual Palette Mode","text":"
#include <graphics/PaletteDefs.h>\n\nvoid MyScene::init() override {\n    // Enable dual palette mode\n    pixelroot32::graphics::enableDualPaletteMode();\n\n    // Set background palette\n    pixelroot32::graphics::setBackgroundPalette(\n        pixelroot32::graphics::PaletteType::GB\n    );\n\n    // Set sprite palette\n    pixelroot32::graphics::setSpritePalette(\n        pixelroot32::graphics::PaletteType::NES\n    );\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#how-it-works","title":"How It Works","text":"
  • Background palette: Used for tilemaps, primitives, and background sprites
  • Sprite palette: Used for game objects, characters, and foreground sprites
  • Automatic context: The renderer automatically selects the correct palette based on what you're drawing
"},{"location":"manual/advanced_graphics/color_palettes/#example-contrasting-styles","title":"Example: Contrasting Styles","text":"
void MyScene::init() override {\n    pixelroot32::graphics::enableDualPaletteMode();\n\n    // Dark, muted background (GameBoy green)\n    pixelroot32::graphics::setBackgroundPalette(\n        pixelroot32::graphics::PaletteType::GB\n    );\n\n    // Bright, colorful sprites (NES)\n    pixelroot32::graphics::setSpritePalette(\n        pixelroot32::graphics::PaletteType::NES\n    );\n\n    // Background uses GB palette\n    renderer.drawTileMap(backgroundTileMap, 0, 0, \n        pixelroot32::graphics::Color::White);\n\n    // Sprites use NES palette\n    renderer.drawSprite(playerSprite, 100, 100, \n        pixelroot32::graphics::Color::White);\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#when-to-use-dual-palette-mode","title":"When to Use Dual Palette Mode","text":"
  • Visual contrast: Make sprites stand out from background
  • Artistic style: Different palettes for different layers
  • Retro aesthetics: Classic console color separation
  • Performance: No performance impact, just visual variety
"},{"location":"manual/advanced_graphics/color_palettes/#custom-palettes","title":"Custom Palettes","text":"

Create your own color palettes for unique visual styles.

"},{"location":"manual/advanced_graphics/color_palettes/#creating-a-custom-palette","title":"Creating a Custom Palette","text":"
#include <graphics/PaletteDefs.h>\n#include <graphics/Color.h>\n\n// Define custom colors (RGB565 format)\nstatic const pixelroot32::graphics::Color CUSTOM_PALETTE[] = {\n    pixelroot32::graphics::Color::Black,      // 0: Transparent/background\n    pixelroot32::graphics::Color::DarkBlue,   // 1\n    pixelroot32::graphics::Color::Blue,       // 2\n    pixelroot32::graphics::Color::LightBlue, // 3\n    pixelroot32::graphics::Color::Cyan,      // 4\n    pixelroot32::graphics::Color::White,      // 5\n    // ... more colors\n};\n\n// Set custom palette\npixelroot32::graphics::setCustomPalette(\n    CUSTOM_PALETTE,\n    sizeof(CUSTOM_PALETTE) / sizeof(pixelroot32::graphics::Color)\n);\n
"},{"location":"manual/advanced_graphics/color_palettes/#rgb565-color-format","title":"RGB565 Color Format","text":"

Colors in PixelRoot32 use RGB565 format (16-bit):

// RGB565: 5 bits red, 6 bits green, 5 bits blue\n// Format: RRRRR GGGGGG BBBBB\n\n// Create custom RGB565 color\nuint16_t myColor = (31 << 11) | (63 << 5) | 31; // White\nuint16_t myColor = (0 << 11) | (0 << 5) | 0;    // Black\nuint16_t myColor = (31 << 11) | (0 << 5) | 0;   // Red\n\n// Or use Color constants\npixelroot32::graphics::Color::Red\npixelroot32::graphics::Color::Green\npixelroot32::graphics::Color::Blue\n
"},{"location":"manual/advanced_graphics/color_palettes/#helper-function-for-custom-colors","title":"Helper Function for Custom Colors","text":"
// Create RGB565 color from RGB values (0-255)\nuint16_t rgb565(uint8_t r, uint8_t g, uint8_t b) {\n    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);\n}\n\n// Usage\nstatic const pixelroot32::graphics::Color MY_PALETTE[] = {\n    rgb565(0, 0, 0),        // Black\n    rgb565(255, 0, 0),      // Red\n    rgb565(0, 255, 0),      // Green\n    rgb565(0, 0, 255),      // Blue\n    rgb565(255, 255, 255),  // White\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#complete-custom-palette-example","title":"Complete Custom Palette Example","text":"
class CustomPaletteScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Define custom palette (ocean theme)\n        static const pixelroot32::graphics::Color OCEAN_PALETTE[] = {\n            pixelroot32::graphics::Color::Black,      // 0: Deep ocean\n            pixelroot32::graphics::Color::Navy,        // 1: Dark blue\n            pixelroot32::graphics::Color::Blue,       // 2: Medium blue\n            pixelroot32::graphics::Color::Cyan,       // 3: Light blue\n            pixelroot32::graphics::Color::LightBlue, // 4: Surface\n            pixelroot32::graphics::Color::White,      // 5: Foam\n        };\n\n        // Set custom palette\n        pixelroot32::graphics::setCustomPalette(\n            OCEAN_PALETTE,\n            sizeof(OCEAN_PALETTE) / sizeof(pixelroot32::graphics::Color)\n        );\n\n        // Now all sprites use the ocean palette\n    }\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#color-constants","title":"Color Constants","text":"

PixelRoot32 provides predefined color constants:

namespace pixelroot32::graphics {\n    Color::Black\n    Color::White\n    Color::Red\n    Color::Green\n    Color::Blue\n    Color::Yellow\n    Color::Cyan\n    Color::Magenta\n    Color::DarkGray\n    Color::LightGray\n    Color::Navy\n    Color::DarkGreen\n    Color::DarkRed\n    Color::Brown\n    Color::Purple\n    Color::Orange\n    Color::Pink\n    Color::Gold\n    Color::LightBlue\n    Color::LightGreen\n    Color::LightRed\n    Color::Transparent\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/color_palettes/#palette-selection","title":"Palette Selection","text":"
  • Match game style: Choose palette that fits your game's theme
  • Test on hardware: Colors may look different on ESP32 display
  • Consider contrast: Ensure sprites are visible against background
  • Consistency: Stick with one palette per scene (or use dual mode)
"},{"location":"manual/advanced_graphics/color_palettes/#dual-palette-mode_1","title":"Dual Palette Mode","text":"
  • Use sparingly: Not all games need dual palettes
  • Test combinations: Some palette combinations work better than others
  • Clear separation: Use for clear visual distinction between layers
  • Performance: No performance cost, use freely
"},{"location":"manual/advanced_graphics/color_palettes/#custom-palettes_1","title":"Custom Palettes","text":"
  • Limit colors: Keep palette size reasonable (8-16 colors)
  • Plan ahead: Design palette before creating sprites
  • Test thoroughly: Verify colors work well together
  • Document: Comment your palette choices
"},{"location":"manual/advanced_graphics/color_palettes/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/color_palettes/#palette-switching","title":"Palette Switching","text":"
class GameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Set initial palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::NES\n        );\n    }\n\n    void changeToNightMode() {\n        // Switch to darker palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::GB\n        );\n    }\n\n    void changeToDayMode() {\n        // Switch to brighter palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::PICO8\n        );\n    }\n};\n
"},{"location":"manual/advanced_graphics/color_palettes/#theme-based-palettes","title":"Theme-Based Palettes","text":"
namespace GamePalettes {\n    // Forest theme\n    static const pixelroot32::graphics::Color FOREST[] = {\n        Color::Black,\n        Color::DarkGreen,\n        Color::Green,\n        Color::LightGreen,\n        Color::Brown,\n        Color::Yellow\n    };\n\n    // Desert theme\n    static const pixelroot32::graphics::Color DESERT[] = {\n        Color::Black,\n        Color::Brown,\n        Color::Yellow,\n        Color::Gold,\n        Color::Orange,\n        Color::White\n    };\n\n    // Ocean theme\n    static const pixelroot32::graphics::Color OCEAN[] = {\n        Color::Black,\n        Color::Navy,\n        Color::Blue,\n        Color::Cyan,\n        Color::LightBlue,\n        Color::White\n    };\n}\n
"},{"location":"manual/advanced_graphics/color_palettes/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/color_palettes/#colors-not-changing","title":"Colors Not Changing","text":"
  • Verify setPalette() is called before drawing
  • Check palette is set in init(), not update()
  • Ensure dual palette mode is enabled if using separate palettes
  • Verify Color constants are from correct namespace
"},{"location":"manual/advanced_graphics/color_palettes/#colors-look-wrong-on-hardware","title":"Colors Look Wrong on Hardware","text":"
  • ESP32 displays may render colors differently
  • Test on actual hardware, not just PC
  • Adjust palette colors if needed
  • Consider display calibration
"},{"location":"manual/advanced_graphics/color_palettes/#dual-palette-not-working","title":"Dual Palette Not Working","text":"
  • Ensure enableDualPaletteMode() is called first
  • Verify both palettes are set
  • Check that you're drawing in correct context
  • Review renderer documentation
"},{"location":"manual/advanced_graphics/color_palettes/#next-steps","title":"Next Steps","text":"

Now that you understand palettes, learn about: - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles - Particles and Effects - Add visual effects

See also: - API Reference - PaletteDefs - API Reference - Color - Manual - Basic Rendering

"},{"location":"manual/advanced_graphics/particles_and_effects/","title":"Particles and Effects","text":"

The particle system allows you to create visual effects like fire, explosions, smoke, and sparks. This guide covers ParticleEmitter, ParticleConfig, and the included presets.

"},{"location":"manual/advanced_graphics/particles_and_effects/#particleemitter-basics","title":"ParticleEmitter Basics","text":"

A ParticleEmitter is an Entity that manages a pool of particles to create visual effects.

"},{"location":"manual/advanced_graphics/particles_and_effects/#creating-a-particle-emitter","title":"Creating a Particle Emitter","text":"
#include <graphics/particles/ParticleEmitter.h>\n#include <graphics/particles/ParticleConfig.h>\n\n// Create particle configuration\npixelroot32::graphics::particles::ParticleConfig config;\nconfig.startColor = pixelroot32::graphics::Color::Red;\nconfig.endColor = pixelroot32::graphics::Color::Yellow;\nconfig.lifetime = 1.0f; // 1 second\nconfig.speed = 50.0f;\nconfig.gravity = -100.0f; // Upward (negative = up)\n\n// Create emitter\npixelroot32::graphics::particles::ParticleEmitter* emitter = \n    new pixelroot32::graphics::particles::ParticleEmitter(100, 100, config);\n\n// Add to scene\naddEntity(emitter);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#emitting-particles","title":"Emitting Particles","text":"
// Emit a burst of particles\nemitter->burst(100, 100, 10); // x, y, particle count\n\n// Particles will automatically update and draw\n// No additional code needed!\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#particleconfig","title":"ParticleConfig","text":"

ParticleConfig defines how particles behave:

#include <graphics/particles/ParticleConfig.h>\n\npixelroot32::graphics::particles::ParticleConfig config;\n\n// Colors\nconfig.startColor = pixelroot32::graphics::Color::Red;   // Color at spawn\nconfig.endColor = pixelroot32::graphics::Color::Yellow;  // Color at death\n\n// Lifetime\nconfig.lifetime = 0.5f; // Duration in seconds\n\n// Velocity\nconfig.speed = 100.0f;           // Base speed\nconfig.speedVariation = 20.0f;   // Random variation\nconfig.direction = 90.0f;        // Direction in degrees (0 = right, 90 = up)\nconfig.directionVariation = 45.0f; // Random direction spread\n\n// Physics\nconfig.gravity = 200.0f;  // Gravity force (positive = down)\nconfig.friction = 0.95f;   // Friction (0.0 to 1.0, 1.0 = no friction)\n\n// Size\nconfig.startSize = 2;     // Size at spawn (pixels)\nconfig.endSize = 1;       // Size at death\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#complete-config-example","title":"Complete Config Example","text":"
pixelroot32::graphics::particles::ParticleConfig fireConfig;\n\n// Fire colors (red to yellow)\nfireConfig.startColor = pixelroot32::graphics::Color::Red;\nfireConfig.endColor = pixelroot32::graphics::Color::Yellow;\n\n// Short lifetime\nfireConfig.lifetime = 0.3f;\n\n// Upward movement with variation\nfireConfig.speed = 80.0f;\nfireConfig.speedVariation = 30.0f;\nfireConfig.direction = 90.0f; // Up\nfireConfig.directionVariation = 30.0f; // Spread\n\n// Upward gravity (negative)\nfireConfig.gravity = -50.0f;\n\n// Slight friction\nfireConfig.friction = 0.98f;\n\n// Size\nfireConfig.startSize = 3;\nfireConfig.endSize = 1;\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#built-in-presets","title":"Built-in Presets","text":"

PixelRoot32 includes several particle presets for common effects:

"},{"location":"manual/advanced_graphics/particles_and_effects/#fire","title":"Fire","text":"
#include <graphics/particles/ParticlePresets.h>\n\n// Create fire emitter\npixelroot32::graphics::particles::ParticleEmitter* fire = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Fire()\n    );\n\n// Emit continuous fire\nvoid update(unsigned long deltaTime) override {\n    fire->burst(100, 100, 2); // Emit 2 particles per frame\n    Scene::update(deltaTime);\n}\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#explosion","title":"Explosion","text":"
// Create explosion emitter\npixelroot32::graphics::particles::ParticleEmitter* explosion = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Explosion()\n    );\n\n// Emit explosion burst\nexplosion->burst(100, 100, 20); // 20 particles at once\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#sparks","title":"Sparks","text":"
// Create sparks emitter\npixelroot32::graphics::particles::ParticleEmitter* sparks = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Sparks()\n    );\n\n// Emit sparks\nsparks->burst(100, 100, 10);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#smoke","title":"Smoke","text":"
// Create smoke emitter\npixelroot32::graphics::particles::ParticleEmitter* smoke = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Smoke()\n    );\n\n// Emit smoke\nsmoke->burst(100, 100, 3);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#dust","title":"Dust","text":"
// Create dust emitter\npixelroot32::graphics::particles::ParticleEmitter* dust = \n    new pixelroot32::graphics::particles::ParticleEmitter(\n        100, 100,\n        pixelroot32::graphics::particles::ParticlePresets::Dust()\n    );\n\n// Emit dust\ndust->burst(100, 100, 5);\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#complete-example-explosion-effect","title":"Complete Example: Explosion Effect","text":"
#include <core/Scene.h>\n#include <graphics/particles/ParticleEmitter.h>\n#include <graphics/particles/ParticlePresets.h>\n\nclass ExplosionEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* explosion;\n    bool active = false;\n\npublic:\n    ExplosionEffect()\n        : Entity(0, 0, 1, 1, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n\n        // Create explosion emitter\n        explosion = new pixelroot32::graphics::particles::ParticleEmitter(\n            0, 0,\n            pixelroot32::graphics::particles::ParticlePresets::Explosion()\n        );\n    }\n\n    void trigger(float x, float y) {\n        active = true;\n        this->x = x;\n        this->y = y;\n\n        // Emit explosion burst\n        explosion->burst(x, y, 25);\n    }\n\n    void update(unsigned long deltaTime) override {\n        explosion->update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        explosion->draw(renderer);\n    }\n};\n\n// Usage in scene\nvoid MyScene::init() override {\n    explosionEffect = new ExplosionEffect();\n    addEntity(explosionEffect);\n}\n\nvoid MyScene::update(unsigned long deltaTime) override {\n    auto& input = engine.getInputManager();\n\n    // Trigger explosion on button press\n    if (input.isButtonPressed(4)) { // Button A\n        explosionEffect->trigger(player->x, player->y);\n    }\n\n    Scene::update(deltaTime);\n}\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#continuous-effects","title":"Continuous Effects","text":"

For continuous effects like fire or smoke:

class FireEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* fire;\n    unsigned long emitTimer = 0;\n    const unsigned long EMIT_INTERVAL_MS = 50; // Emit every 50ms\n\npublic:\n    FireEffect(float x, float y)\n        : Entity(x, y, 1, 1, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n\n        fire = new pixelroot32::graphics::particles::ParticleEmitter(\n            x, y,\n            pixelroot32::graphics::particles::ParticlePresets::Fire()\n        );\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Emit particles continuously\n        emitTimer += deltaTime;\n        if (emitTimer >= EMIT_INTERVAL_MS) {\n            emitTimer -= EMIT_INTERVAL_MS;\n            fire->burst(x, y, 2); // 2 particles per interval\n        }\n\n        fire->update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        fire->draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#custom-particle-effects","title":"Custom Particle Effects","text":"

Create your own particle effects by customizing ParticleConfig:

"},{"location":"manual/advanced_graphics/particles_and_effects/#magic-spell-effect","title":"Magic Spell Effect","text":"
pixelroot32::graphics::particles::ParticleConfig magicConfig;\n\n// Magical colors (purple to cyan)\nmagicConfig.startColor = pixelroot32::graphics::Color::Purple;\nmagicConfig.endColor = pixelroot32::graphics::Color::Cyan;\n\n// Medium lifetime\nmagicConfig.lifetime = 0.8f;\n\n// Outward spread\nmagicConfig.speed = 60.0f;\nmagicConfig.speedVariation = 20.0f;\nmagicConfig.direction = 0.0f; // Right\nmagicConfig.directionVariation = 360.0f; // Full circle\n\n// Slight upward float\nmagicConfig.gravity = -30.0f;\n\n// Low friction (floaty)\nmagicConfig.friction = 0.92f;\n\n// Size\nmagicConfig.startSize = 2;\nmagicConfig.endSize = 1;\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#rain-effect","title":"Rain Effect","text":"
pixelroot32::graphics::particles::ParticleConfig rainConfig;\n\n// Rain color (light blue)\nrainConfig.startColor = pixelroot32::graphics::Color::LightBlue;\nrainConfig.endColor = pixelroot32::graphics::Color::LightBlue;\n\n// Long lifetime\nrainConfig.lifetime = 2.0f;\n\n// Downward movement\nrainConfig.speed = 150.0f;\nrainConfig.speedVariation = 20.0f;\nrainConfig.direction = 270.0f; // Down\nrainConfig.directionVariation = 5.0f; // Slight angle variation\n\n// Downward gravity\nrainConfig.gravity = 200.0f;\n\n// No friction\nrainConfig.friction = 1.0f;\n\n// Small size\nrainConfig.startSize = 1;\nrainConfig.endSize = 1;\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/particles_and_effects/#performance","title":"Performance","text":"
  • Limit particle count: Each emitter has MAX_PARTICLES_PER_EMITTER (50)
  • Reuse emitters: Don't create new emitters every frame
  • Disable when not visible: Set isVisible = false when off-screen
  • Limit active emitters: Too many emitters can impact performance
"},{"location":"manual/advanced_graphics/particles_and_effects/#visual-design","title":"Visual Design","text":"
  • Match game style: Particle effects should fit your game's aesthetic
  • Use appropriate colors: Match particle colors to game palette
  • Test on hardware: ESP32 may render particles differently
  • Keep it simple: Simple effects often look better than complex ones
"},{"location":"manual/advanced_graphics/particles_and_effects/#timing","title":"Timing","text":"
  • Burst timing: Space out bursts for better visual effect
  • Continuous effects: Use timers to control emission rate
  • Lifetime: Adjust lifetime to match effect duration
  • Cleanup: Particles automatically clean up when lifetime expires
"},{"location":"manual/advanced_graphics/particles_and_effects/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/particles_and_effects/#one-shot-effect","title":"One-Shot Effect","text":"
class OneShotEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* emitter;\n    bool hasEmitted = false;\n\npublic:\n    void trigger(float x, float y) {\n        if (!hasEmitted) {\n            emitter->burst(x, y, 20);\n            hasEmitted = true;\n        }\n    }\n\n    void reset() {\n        hasEmitted = false;\n    }\n};\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#attached-effect","title":"Attached Effect","text":"
class AttachedParticleEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* emitter;\n    pixelroot32::core::Actor* target;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        // Update emitter position to follow target\n        emitter->x = target->x;\n        emitter->y = target->y;\n\n        // Emit particles\n        emitter->burst(target->x, target->y, 1);\n\n        emitter->update(deltaTime);\n    }\n};\n
"},{"location":"manual/advanced_graphics/particles_and_effects/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/particles_and_effects/#particles-not-appearing","title":"Particles Not Appearing","text":"
  • Verify emitter is added to scene
  • Check particle config is valid
  • Ensure burst() is being called
  • Verify emitter position is on-screen
"},{"location":"manual/advanced_graphics/particles_and_effects/#performance-issues","title":"Performance Issues","text":"
  • Reduce particle count per burst
  • Limit number of active emitters
  • Use simpler particle configs
  • Disable emitters when not visible
"},{"location":"manual/advanced_graphics/particles_and_effects/#particles-not-moving","title":"Particles Not Moving","text":"
  • Check gravity value (positive = down, negative = up)
  • Verify speed is not 0
  • Check friction isn't too high (1.0 = no movement)
  • Ensure direction is correct (degrees: 0=right, 90=up, 180=left, 270=down)
"},{"location":"manual/advanced_graphics/particles_and_effects/#next-steps","title":"Next Steps","text":"

Now that you understand particles, you've completed the advanced graphics section. Continue with: - Performance Optimization - Optimize your game - Memory Management - Manage memory efficiently - API Reference - Complete API documentation

See also: - API Reference - ParticleEmitter - API Reference - ParticleConfig - API Reference - ParticlePresets - Manual - Basic Rendering

"},{"location":"manual/advanced_graphics/resolution_scaling/","title":"Resolution Scaling","text":"

PixelRoot32 features a powerful Independent Resolution Scaling system. This allows the engine to render internally at a lower resolution (Logical Resolution) and then scale the final image to the display's actual hardware resolution (Physical Resolution).

"},{"location":"manual/advanced_graphics/resolution_scaling/#why-use-resolution-scaling","title":"Why use Resolution Scaling?","text":"

On microcontrollers like the ESP32, memory and processing power are limited. Rendering at a full 240x240 resolution consumes significant RAM and CPU cycles for every pixel drawn.

By using a lower logical resolution (e.g., 128x128): 1. Memory Savings: A 128x128 8bpp buffer uses ~16KB, while 240x240 uses ~57KB (72% reduction). 2. Performance Boost: Fewer pixels to process means more complex scenes and higher FPS. 3. Retro Aesthetic: Nearest-neighbor scaling preserves the pixel-art look perfectly.

"},{"location":"manual/advanced_graphics/resolution_scaling/#logical-vs-physical-resolution","title":"Logical vs Physical Resolution","text":"
  • Logical Resolution: The virtual canvas where your game logic, sprites, and UI are drawn.
  • Physical Resolution: The actual pixel dimensions of your hardware display.
flowchart LR\n    subgraph Logical [Logical Resolution 128x128]\n        A[Game Logic] --> B[Renderer API]\n        B --> C[Internal Framebuffer]\n    end\n\n    subgraph Scaling [Hardware Scaling]\n        C --> D[Nearest Neighbor Scaler]\n    end\n\n    subgraph Physical [Physical Display 240x240]\n        D --> E[SPI/DMA Transfer]\n        E --> F[LCD Hardware]\n    end
"},{"location":"manual/advanced_graphics/resolution_scaling/#configuration","title":"Configuration","text":""},{"location":"manual/advanced_graphics/resolution_scaling/#using-presets","title":"Using Presets","text":"

The easiest way to configure scaling is using the ResolutionPresets helper.

#include <graphics/ResolutionPresets.h>\n\n// Create a config for 128x128 logical resolution scaled to 240x240 physical\nauto config = pr32::graphics::ResolutionPresets::create(\n    pr32::graphics::RES_128x128,\n    pr32::graphics::ST7789\n);\n
"},{"location":"manual/advanced_graphics/resolution_scaling/#manual-configuration","title":"Manual Configuration","text":"

You can also specify custom dimensions in the DisplayConfig constructor.

pr32::graphics::DisplayConfig config(\n    pr32::graphics::ST7789, // Driver\n    0,                      // Rotation\n    240, 240,               // Physical Width, Physical Height\n    160, 160                // Logical Width, Logical Height\n);\n
"},{"location":"manual/advanced_graphics/resolution_scaling/#performance-impact","title":"Performance Impact","text":"

The following table shows estimated savings on an ESP32 for a standard 240x240 display:

Logical Resolution Memory (8bpp) RAM Savings FPS Gain (est.) 240x240 (Full) 57.6 KB 0% Baseline 160x160 25.6 KB ~55% +30% 128x128 16.4 KB ~72% +60% 96x96 9.2 KB ~84% +100%

Final FPS Analysis

It is very important to understand that at 240x240 physical pixels, your maximum limit is ~14 FPS due to the SPI bus speed (40MHz).

  • 128x128 physical pixels: You send 16k pixels \u2192 ~43 FPS.
  • 240x240 physical pixels: You send 57k pixels (3.5 times more) \u2192 The bus takes 3.5 times longer to transmit, dropping to ~12-14 FPS.

Even if you render internally at 128x128 (logical), the system must ultimately send 57,600 pixels to the physical display to fill it. There is no way to bypass this physical limit unless a smaller display or a faster bus is used.

"},{"location":"manual/advanced_graphics/resolution_scaling/#implementation-details","title":"Implementation Details","text":""},{"location":"manual/advanced_graphics/resolution_scaling/#nearest-neighbor-scaling","title":"Nearest Neighbor Scaling","text":"

The engine uses a Nearest Neighbor algorithm optimized for ESP32. It avoids floating-point math by using pre-calculated Lookup Tables (LUTs).

"},{"location":"manual/advanced_graphics/resolution_scaling/#on-the-fly-scaling","title":"On-the-fly Scaling","text":"

To save even more RAM, the engine does not maintain a physical-sized buffer. Instead, it scales the image line-by-line during the SPI DMA transfer. This means the only large buffer in memory is the small logical one.

"},{"location":"manual/advanced_graphics/resolution_scaling/#profiling","title":"Profiling","text":"

You can measure the performance of the scaling system by enabling the Debug Statistics Overlay. This provides real-time data on FPS, CPU load, and RAM usage directly on the screen.

See Engine - Debug Overlay for instructions on how to enable it.

Alternatively, you can enable low-level profiling in EngineConfig.h:

#define PIXELROOT32_ENABLE_PROFILING\n

This will output the time taken for scaling and transfer to the Serial monitor: [PROFILING] Scaled Transfer: 12450 us (80 FPS max)

"},{"location":"manual/advanced_graphics/resolution_scaling/#best-practices","title":"Best Practices","text":"
  1. Aspect Ratio: Keep the logical aspect ratio the same as the physical one to avoid stretching.
  2. Integer Multiples: For the sharpest results, try to use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen).
  3. Hardware Recommendation: For high-action games requiring 30+ FPS (like the Metroidvania sample), it is highly recommended to use a 128x128 physical display. Larger displays like 240x240 are limited to ~14 FPS by the 40MHz SPI bus, regardless of the logical resolution used.
  4. UI Positioning: Use UIAnchorLayout to ensure your UI elements stay correctly positioned regardless of the logical resolution chosen.
"},{"location":"manual/advanced_graphics/sprites_and_animation/","title":"Sprites and Animation","text":"

This guide covers advanced sprite techniques and animation in PixelRoot32, including different sprite formats, creating animations, and best practices.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-formats","title":"Sprite Formats","text":"

PixelRoot32 supports multiple sprite formats, each optimized for different use cases.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#1bpp-standard-monochrome","title":"1bpp (Standard, Monochrome)","text":"

The standard format uses 1 bit per pixel (monochrome). This is the most memory-efficient format:

#include <graphics/Renderer.h>\n\n// Define sprite data (8x8 example)\nstatic const uint16_t PLAYER_SPRITE_DATA[] = {\n    0b00111100,  // Row 0\n    0b01111110,  // Row 1\n    0b11111111,  // Row 2\n    0b11111111,  // Row 3\n    0b11111111,  // Row 4\n    0b01111110,  // Row 5\n    0b00111100,  // Row 6\n    0b00000000   // Row 7\n};\n\n// Create sprite descriptor\nstatic const pixelroot32::graphics::Sprite PLAYER_SPRITE = {\n    PLAYER_SPRITE_DATA,\n    8,  // width\n    8   // height\n};\n\n// Draw sprite\nrenderer.drawSprite(PLAYER_SPRITE, 100, 100, pixelroot32::graphics::Color::White);\n

Characteristics: - Most memory-efficient - 1 bit per pixel - Maximum width: 16 pixels - Color applied at draw time - Best for: Simple graphics, retro style

"},{"location":"manual/advanced_graphics/sprites_and_animation/#2bpp-experimental-4-colors","title":"2bpp (Experimental, 4 Colors)","text":"

2 bits per pixel allows 4 colors per sprite:

#ifdef PIXELROOT32_ENABLE_2BPP_SPRITES\n#include <graphics/Renderer.h>\n\n// Define 2bpp sprite data\nstatic const uint8_t COLORFUL_SPRITE_DATA[] = {\n    // Each byte represents 4 pixels (2 bits each)\n    // Format: [pixel3][pixel2][pixel1][pixel0]\n    0x00, 0x11, 0x22, 0x33,  // Row 0\n    0x11, 0x22, 0x33, 0x00,  // Row 1\n    // ... more rows\n};\n\n// Define palette (4 colors)\nstatic const pixelroot32::graphics::Color SPRITE_PALETTE[] = {\n    pixelroot32::graphics::Color::Transparent,\n    pixelroot32::graphics::Color::Red,\n    pixelroot32::graphics::Color::Green,\n    pixelroot32::graphics::Color::Blue\n};\n\n// Create 2bpp sprite\nstatic const pixelroot32::graphics::Sprite2bpp COLORFUL_SPRITE = {\n    COLORFUL_SPRITE_DATA,\n    SPRITE_PALETTE,\n    16,  // width\n    8,   // height\n    4    // palette size\n};\n\n// Draw 2bpp sprite\nrenderer.drawSprite(COLORFUL_SPRITE, 100, 100, false);\n#endif\n

Characteristics: - 2 bits per pixel (4 colors) - Requires custom palette - More memory than 1bpp - Best for: More colorful sprites without full color

"},{"location":"manual/advanced_graphics/sprites_and_animation/#4bpp-experimental-16-colors","title":"4bpp (Experimental, 16 Colors)","text":"

4 bits per pixel allows 16 colors per sprite:

#ifdef PIXELROOT32_ENABLE_4BPP_SPRITES\n#include <graphics/Renderer.h>\n\n// Define 4bpp sprite data\nstatic const uint8_t RICH_SPRITE_DATA[] = {\n    // Each byte represents 2 pixels (4 bits each)\n    // Format: [pixel1][pixel0]\n    0x01, 0x23, 0x45, 0x67,  // Row 0\n    // ... more rows\n};\n\n// Define palette (16 colors)\nstatic const pixelroot32::graphics::Color RICH_PALETTE[] = {\n    pixelroot32::graphics::Color::Transparent,\n    pixelroot32::graphics::Color::Black,\n    pixelroot32::graphics::Color::DarkGray,\n    // ... 13 more colors\n};\n\n// Create 4bpp sprite\nstatic const pixelroot32::graphics::Sprite4bpp RICH_SPRITE = {\n    RICH_SPRITE_DATA,\n    RICH_PALETTE,\n    16,  // width\n    16,  // height\n    16   // palette size\n};\n\n// Draw 4bpp sprite\nrenderer.drawSprite(RICH_SPRITE, 100, 100, false);\n#endif\n

Characteristics: - 4 bits per pixel (16 colors) - Requires custom palette - Most memory-intensive - Best for: Detailed sprites with many colors

"},{"location":"manual/advanced_graphics/sprites_and_animation/#multisprite-multi-layer","title":"MultiSprite (Multi-Layer)","text":"

MultiSprite combines multiple 1bpp layers to create multi-color sprites:

#include <graphics/Renderer.h>\n\n// Define layers (each is 1bpp)\nstatic const uint16_t BASE_LAYER_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b01111110,\n    0b00111100,\n    0b00000000\n};\n\nstatic const uint16_t HIGHLIGHT_LAYER_DATA[] = {\n    0b00000000,\n    0b00011000,\n    0b00111100,\n    0b00111100,\n    0b00111100,\n    0b00011000,\n    0b00000000,\n    0b00000000\n};\n\n// Create layers\nstatic const pixelroot32::graphics::SpriteLayer LAYERS[] = {\n    { BASE_LAYER_DATA, pixelroot32::graphics::Color::Blue },      // Base layer\n    { HIGHLIGHT_LAYER_DATA, pixelroot32::graphics::Color::Cyan }  // Highlight layer\n};\n\n// Create MultiSprite\nstatic const pixelroot32::graphics::MultiSprite PLAYER_MULTI = {\n    8,      // width\n    8,      // height\n    LAYERS, // layers array\n    2       // layer count\n};\n\n// Draw MultiSprite\nrenderer.drawSprite(PLAYER_MULTI, 100, 100, false);\n

Characteristics: - Combines multiple 1bpp layers - Each layer can have different color - Layers drawn in order (first = bottom) - Best for: Complex sprites with highlights, outlines, etc.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#creating-sprites","title":"Creating Sprites","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#manual-creation-1bpp","title":"Manual Creation (1bpp)","text":"

For simple sprites, you can create them manually:

// 8x8 sprite: Simple circle\nstatic const uint16_t CIRCLE_SPRITE_DATA[] = {\n    0b00111100,  //   ####\n    0b01111110,  //  ######\n    0b11111111,  // ########\n    0b11111111,  // ########\n    0b11111111,  // ########\n    0b11111111,  // ########\n    0b01111110,  //  ######\n    0b00111100   //   ####\n};\n\nstatic const pixelroot32::graphics::Sprite CIRCLE_SPRITE = {\n    CIRCLE_SPRITE_DATA,\n    8,\n    8\n};\n

Tips: - Use binary notation for clarity - Comment each row to visualize - Keep sprites small (8x8, 16x16) - Reuse sprites when possible

"},{"location":"manual/advanced_graphics/sprites_and_animation/#using-sprite-compiler","title":"Using Sprite Compiler","text":"

For complex sprites, use the Sprite Compiler tool (if available) to convert PNG images to sprite data.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-animation","title":"Sprite Animation","text":"

PixelRoot32 uses a step-based animation system that's lightweight and efficient.

"},{"location":"manual/advanced_graphics/sprites_and_animation/#spriteanimation-structure","title":"SpriteAnimation Structure","text":"
#include <graphics/Renderer.h>\n\n// Define animation frames\nstatic const uint16_t FRAME1_DATA[] = { /* ... */ };\nstatic const uint16_t FRAME2_DATA[] = { /* ... */ };\nstatic const uint16_t FRAME3_DATA[] = { /* ... */ };\n\nstatic const pixelroot32::graphics::Sprite FRAME1 = { FRAME1_DATA, 8, 8 };\nstatic const pixelroot32::graphics::Sprite FRAME2 = { FRAME2_DATA, 8, 8 };\nstatic const pixelroot32::graphics::Sprite FRAME3 = { FRAME3_DATA, 8, 8 };\n\n// Create animation frames\nstatic const pixelroot32::graphics::SpriteAnimationFrame ANIMATION_FRAMES[] = {\n    { &FRAME1, nullptr },  // Frame 1 (no mask)\n    { &FRAME2, nullptr },  // Frame 2\n    { &FRAME3, nullptr }   // Frame 3\n};\n\n// Create animation\npixelroot32::graphics::SpriteAnimation walkAnimation;\nwalkAnimation.frames = ANIMATION_FRAMES;\nwalkAnimation.frameCount = 3;\nwalkAnimation.current = 0;\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#using-animations-in-actors","title":"Using Animations in Actors","text":"
#include <core/Actor.h>\n#include <graphics/Renderer.h>\n\nclass AnimatedPlayer : public pixelroot32::core::Actor {\nprivate:\n    pixelroot32::graphics::SpriteAnimation walkAnimation;\n    unsigned long animationTimer = 0;\n    const unsigned long FRAME_DURATION_MS = 100; // 100ms per frame\n\npublic:\n    AnimatedPlayer(float x, float y)\n        : Actor(x, y, 8, 8) {\n        setRenderLayer(1);\n\n        // Initialize animation\n        walkAnimation.frames = WALK_ANIMATION_FRAMES;\n        walkAnimation.frameCount = 3;\n        walkAnimation.current = 0;\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update animation\n        animationTimer += deltaTime;\n        if (animationTimer >= FRAME_DURATION_MS) {\n            animationTimer -= FRAME_DURATION_MS;\n            walkAnimation.step(); // Advance to next frame\n        }\n\n        // Movement logic...\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Get current frame\n        const pixelroot32::graphics::Sprite* currentFrame = \n            walkAnimation.frames[walkAnimation.current].sprite;\n\n        // Draw current frame\n        renderer.drawSprite(\n            *currentFrame,\n            static_cast<int>(x),\n            static_cast<int>(y),\n            pixelroot32::graphics::Color::White,\n            false // flipX\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collision\n    }\n};\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#animation-control","title":"Animation Control","text":"
// Reset animation to first frame\nwalkAnimation.reset();\n\n// Step to next frame (loops automatically)\nwalkAnimation.step();\n\n// Get current frame\nconst pixelroot32::graphics::Sprite* frame = \n    walkAnimation.frames[walkAnimation.current].sprite;\n\n// Check if animation is at specific frame\nif (walkAnimation.current == 0) {\n    // At first frame\n}\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#multiple-animations","title":"Multiple Animations","text":"

For actors with multiple animations (idle, walk, jump):

class PlayerActor : public pixelroot32::core::Actor {\nprivate:\n    enum class AnimationState {\n        IDLE,\n        WALK,\n        JUMP\n    };\n\n    AnimationState currentState = AnimationState::IDLE;\n    pixelroot32::graphics::SpriteAnimation idleAnim;\n    pixelroot32::graphics::SpriteAnimation walkAnim;\n    pixelroot32::graphics::SpriteAnimation jumpAnim;\n\n    pixelroot32::graphics::SpriteAnimation* getCurrentAnimation() {\n        switch (currentState) {\n            case AnimationState::IDLE: return &idleAnim;\n            case AnimationState::WALK: return &walkAnim;\n            case AnimationState::JUMP: return &jumpAnim;\n        }\n        return &idleAnim;\n    }\n\npublic:\n    void update(unsigned long deltaTime) override {\n        // Update current animation\n        auto* anim = getCurrentAnimation();\n        animationTimer += deltaTime;\n        if (animationTimer >= FRAME_DURATION_MS) {\n            animationTimer -= FRAME_DURATION_MS;\n            anim->step();\n        }\n\n        // Change animation state based on game logic\n        if (isMoving) {\n            if (currentState != AnimationState::WALK) {\n                currentState = AnimationState::WALK;\n                walkAnim.reset();\n            }\n        } else if (isJumping) {\n            if (currentState != AnimationState::JUMP) {\n                currentState = AnimationState::JUMP;\n                jumpAnim.reset();\n            }\n        } else {\n            if (currentState != AnimationState::IDLE) {\n                currentState = AnimationState::IDLE;\n                idleAnim.reset();\n            }\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        auto* anim = getCurrentAnimation();\n        const auto* frame = anim->frames[anim->current].sprite;\n        renderer.drawSprite(*frame, static_cast<int>(x), static_cast<int>(y), \n            pixelroot32::graphics::Color::White);\n    }\n};\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-flipping","title":"Sprite Flipping","text":"

Flip sprites horizontally for facing direction:

bool facingRight = true;\n\nvoid draw(pixelroot32::graphics::Renderer& renderer) override {\n    renderer.drawSprite(\n        PLAYER_SPRITE,\n        static_cast<int>(x),\n        static_cast<int>(y),\n        pixelroot32::graphics::Color::White,\n        !facingRight // Flip if facing left\n    );\n}\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#memory-optimization","title":"Memory Optimization","text":"
  • Reuse sprites: Define sprites once, use many times
  • Use 1bpp when possible: Most memory-efficient
  • Store in flash: Use static const to keep in flash memory
  • Limit sprite count: Too many unique sprites can exhaust memory
"},{"location":"manual/advanced_graphics/sprites_and_animation/#performance","title":"Performance","text":"
  • Pre-calculate animations: Set up animations in init(), not update()
  • Limit active animations: Only animate visible entities
  • Use appropriate formats: Don't use 4bpp if 1bpp works
  • Batch similar sprites: Draw similar sprites together
"},{"location":"manual/advanced_graphics/sprites_and_animation/#organization","title":"Organization","text":"
  • Group related sprites: Keep sprite data together
  • Use meaningful names: Name sprites clearly
  • Document complex sprites: Comment sprite bit patterns
  • Create sprite libraries: Reusable sprite collections
"},{"location":"manual/advanced_graphics/sprites_and_animation/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#sprite-sheet-pattern","title":"Sprite Sheet Pattern","text":"

Organize multiple sprites in arrays:

namespace PlayerSprites {\n    static const uint16_t IDLE_FRAME1[] = { /* ... */ };\n    static const uint16_t IDLE_FRAME2[] = { /* ... */ };\n    static const uint16_t WALK_FRAME1[] = { /* ... */ };\n    static const uint16_t WALK_FRAME2[] = { /* ... */ };\n\n    static const pixelroot32::graphics::Sprite IDLE[] = {\n        { IDLE_FRAME1, 8, 8 },\n        { IDLE_FRAME2, 8, 8 }\n    };\n\n    static const pixelroot32::graphics::Sprite WALK[] = {\n        { WALK_FRAME1, 8, 8 },\n        { WALK_FRAME2, 8, 8 }\n    };\n}\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#animation-helper","title":"Animation Helper","text":"

Create a helper class for animation management:

class AnimationController {\nprivate:\n    pixelroot32::graphics::SpriteAnimation* currentAnim;\n    unsigned long timer = 0;\n    unsigned long frameDuration;\n\npublic:\n    void setAnimation(pixelroot32::graphics::SpriteAnimation* anim) {\n        if (currentAnim != anim) {\n            currentAnim = anim;\n            currentAnim->reset();\n            timer = 0;\n        }\n    }\n\n    void update(unsigned long deltaTime) {\n        if (currentAnim) {\n            timer += deltaTime;\n            if (timer >= frameDuration) {\n                timer -= frameDuration;\n                currentAnim->step();\n            }\n        }\n    }\n\n    const pixelroot32::graphics::Sprite* getCurrentFrame() {\n        if (currentAnim && currentAnim->frameCount > 0) {\n            return currentAnim->frames[currentAnim->current].sprite;\n        }\n        return nullptr;\n    }\n};\n
"},{"location":"manual/advanced_graphics/sprites_and_animation/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/sprites_and_animation/#sprites-not-displaying","title":"Sprites Not Displaying","text":"
  • Check sprite data is valid
  • Verify width/height match data
  • Ensure sprite is within screen bounds
  • Check render layer is correct
"},{"location":"manual/advanced_graphics/sprites_and_animation/#animation-not-playing","title":"Animation Not Playing","text":"
  • Verify animation frames are set
  • Check step() is being called
  • Ensure timer logic is correct
  • Verify frame count matches array size
"},{"location":"manual/advanced_graphics/sprites_and_animation/#memory-issues","title":"Memory Issues","text":"
  • Reduce sprite count
  • Use 1bpp instead of 2bpp/4bpp
  • Reuse sprites more
  • Check available flash memory
"},{"location":"manual/advanced_graphics/sprites_and_animation/#next-steps","title":"Next Steps","text":"

Now that you understand sprites and animation, learn about: - Color Palettes - Use different color schemes - Cameras and Scrolling - Create scrolling levels - Tilemaps - Build levels with tiles

See also: - API Reference - Sprite - API Reference - SpriteAnimation - Manual - Basic Rendering

"},{"location":"manual/advanced_graphics/tilemaps/","title":"Tilemaps","text":"

Tilemaps allow you to build levels efficiently by reusing small tile sprites. This guide covers creating tilemaps, rendering them, and using them with scrolling cameras.

"},{"location":"manual/advanced_graphics/tilemaps/#what-are-tilemaps","title":"What are Tilemaps?","text":"

A tilemap is a 2D grid where each cell references a tile sprite. Instead of placing individual sprites, you define which tile appears at each grid position.

Advantages: - Memory efficient: Reuse tile sprites many times - Easy level design: Edit level data, not code - Fast rendering: Optimized tilemap drawing - Large levels: Create levels bigger than screen - Multiple Bit-Depths: Support for 1bpp, 2bpp, and 4bpp tilemaps for higher graphical fidelity

"},{"location":"manual/advanced_graphics/tilemaps/#creating-a-tilemap","title":"Creating a Tilemap","text":""},{"location":"manual/advanced_graphics/tilemaps/#1-define-tiles","title":"1. Define Tiles","text":"

First, create the tile sprites you'll reuse. You can use standard 1bpp sprites or multi-bpp sprites (2bpp/4bpp) if enabled.

"},{"location":"manual/advanced_graphics/tilemaps/#1bpp-tiles-example","title":"1bpp Tiles Example","text":"
#include <graphics/Renderer.h>\n\n// Ground tile (solid)\nstatic const uint16_t TILE_GROUND_BITS[] = {\n    0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,\n    0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF\n};\n\n// Create tile sprites (8x8 tiles)\nstatic const pixelroot32::graphics::Sprite TILES[] = {\n    { TILE_EMPTY_BITS, 8, 8 },  // Index 0: Empty\n    { TILE_GROUND_BITS, 8, 8 }  // Index 1: Ground\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#2bpp-tiles-example-multi-color","title":"2bpp Tiles Example (Multi-color)","text":"
#include <graphics/Renderer.h>\n\n// 2bpp grass tile\nstatic const uint8_t TILE_GRASS_DATA[] = {\n    0b01010101, 0b01010101, // Packed 2bpp data\n    // ...\n};\n\nstatic const Color GRASS_PALETTE[] = {\n    Color::Transparent, Color::DarkGreen, Color::Green, Color::LightGreen\n};\n\nstatic const pixelroot32::graphics::Sprite2bpp TILES_2BPP[] = {\n    { TILE_GRASS_DATA, GRASS_PALETTE, 8, 8, 4 }\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#2-create-tile-index-array","title":"2. Create Tile Index Array","text":"

Define which tile appears at each position:

// Tilemap dimensions (30 tiles wide, 20 tiles tall)\nstatic const int TILEMAP_WIDTH = 30;\nstatic const int TILEMAP_HEIGHT = 20;\n\n// Array of tile indices (each byte is a tile index)\nstatic uint8_t TILEMAP_INDICES[TILEMAP_WIDTH * TILEMAP_HEIGHT];\n\n// Initialize to empty\nvoid initTilemap() {\n    for (int i = 0; i < TILEMAP_WIDTH * TILEMAP_HEIGHT; i++) {\n        TILEMAP_INDICES[i] = 0; // Empty\n    }\n\n    // Draw ground at bottom\n    int groundRow = TILEMAP_HEIGHT - 1;\n    for (int x = 0; x < TILEMAP_WIDTH; x++) {\n        TILEMAP_INDICES[groundRow * TILEMAP_WIDTH + x] = 1; // Ground tile\n    }\n\n    // Add some walls\n    TILEMAP_INDICES[5 * TILEMAP_WIDTH + 10] = 2; // Wall at (10, 5)\n    TILEMAP_INDICES[5 * TILEMAP_WIDTH + 11] = 2;\n    TILEMAP_INDICES[5 * TILEMAP_WIDTH + 12] = 2;\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#3-create-tilemap-structure","title":"3. Create TileMap Structure","text":"
#include <graphics/Renderer.h>\n\nstatic pixelroot32::graphics::TileMap myTileMap = {\n    TILEMAP_INDICES,                    // indices array\n    TILEMAP_WIDTH,                      // width (in tiles)\n    TILEMAP_HEIGHT,                     // height (in tiles)\n    TILES,                              // tiles array\n    8,                                  // tile width (pixels)\n    8,                                  // tile height (pixels)\n    sizeof(TILES) / sizeof(pixelroot32::graphics::Sprite) // tile count\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#rendering-tilemaps","title":"Rendering Tilemaps","text":""},{"location":"manual/advanced_graphics/tilemaps/#basic-rendering","title":"Basic Rendering","text":"
void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // 1bpp Tilemap (requires a color)\n    renderer.drawTileMap(\n        myTileMap,\n        0, 0,\n        pixelroot32::graphics::Color::White\n    );\n\n    // 2bpp/4bpp Tilemap (colors are in the sprite palettes)\n    renderer.drawTileMap(myTileMap2bpp, 0, 100);\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#with-camerascrolling","title":"With Camera/Scrolling","text":"
void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera first\n    camera.apply(renderer);\n\n    // Draw tilemap (camera offset is automatically applied)\n    renderer.drawTileMap(\n        myTileMap,\n        0,                              // World position (0, 0)\n        0,\n        pixelroot32::graphics::Color::White\n    );\n\n    // Draw game objects\n    Scene::draw(renderer);\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#complete-example-platformer-level","title":"Complete Example: Platformer Level","text":"
#include <core/Scene.h>\n#include <graphics/Renderer.h>\n#include <graphics/Camera2D.h>\n\nclass PlatformerLevel : public pixelroot32::core::Scene {\nprivate:\n    static const int TILE_SIZE = 8;\n    static const int TILEMAP_WIDTH = 100;  // 800 pixels wide\n    static const int TILEMAP_HEIGHT = 30;   // 240 pixels tall\n\n    // Tile definitions\n    static const uint16_t TILE_EMPTY_BITS[] = {\n        0x0000, 0x0000, 0x0000, 0x0000,\n        0x0000, 0x0000, 0x0000, 0x0000\n    };\n\n    static const uint16_t TILE_GROUND_BITS[] = {\n        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,\n        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF\n    };\n\n    static const uint16_t TILE_GRASS_BITS[] = {\n        0x0000, 0x0000, 0x0000, 0x0000,\n        0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF\n    };\n\n    static const pixelroot32::graphics::Sprite TILES[] = {\n        { TILE_EMPTY_BITS, TILE_SIZE, TILE_SIZE },  // 0: Empty\n        { TILE_GROUND_BITS, TILE_SIZE, TILE_SIZE }, // 1: Ground\n        { TILE_GRASS_BITS, TILE_SIZE, TILE_SIZE }   // 2: Grass top\n    };\n\n    static uint8_t LEVEL_INDICES[TILEMAP_WIDTH * TILEMAP_HEIGHT];\n\n    pixelroot32::graphics::TileMap levelTileMap;\n    pixelroot32::graphics::Camera2D camera;\n\npublic:\n    PlatformerLevel() \n        : camera(240, 240) {\n        // Initialize tilemap structure\n        levelTileMap = {\n            LEVEL_INDICES,\n            TILEMAP_WIDTH,\n            TILEMAP_HEIGHT,\n            TILES,\n            TILE_SIZE,\n            TILE_SIZE,\n            sizeof(TILES) / sizeof(pixelroot32::graphics::Sprite)\n        };\n    }\n\n    void init() override {\n        // Initialize all tiles to empty\n        for (int i = 0; i < TILEMAP_WIDTH * TILEMAP_HEIGHT; i++) {\n            LEVEL_INDICES[i] = 0;\n        }\n\n        // Create ground level\n        int groundY = TILEMAP_HEIGHT - 1;\n        for (int x = 0; x < TILEMAP_WIDTH; x++) {\n            LEVEL_INDICES[groundY * TILEMAP_WIDTH + x] = 1; // Ground\n        }\n\n        // Add grass on top of ground\n        int grassY = groundY - 1;\n        for (int x = 0; x < TILEMAP_WIDTH; x++) {\n            LEVEL_INDICES[grassY * TILEMAP_WIDTH + x] = 2; // Grass\n        }\n\n        // Add platforms\n        // Platform 1: x=10 to x=15, y=20\n        for (int x = 10; x < 16; x++) {\n            LEVEL_INDICES[20 * TILEMAP_WIDTH + x] = 1; // Ground tile\n        }\n\n        // Platform 2: x=30 to x=35, y=15\n        for (int x = 30; x < 36; x++) {\n            LEVEL_INDICES[15 * TILEMAP_WIDTH + x] = 1;\n        }\n\n        // Set camera boundaries\n        camera.setBounds(0, TILEMAP_WIDTH * TILE_SIZE - 240);\n        camera.setVerticalBounds(0, TILEMAP_HEIGHT * TILE_SIZE - 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Follow player (example)\n        // camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Apply camera\n        camera.apply(renderer);\n\n        // Draw tilemap\n        renderer.drawTileMap(\n            levelTileMap,\n            0, 0,\n            pixelroot32::graphics::Color::White\n        );\n\n        // Draw game objects\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/advanced_graphics/tilemaps/#tilemap-with-scroll","title":"Tilemap with Scroll","text":"

For scrolling levels, combine tilemaps with cameras:

void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // Apply camera (handles scrolling)\n    camera.apply(renderer);\n\n    // Draw tilemap (automatically scrolled by camera)\n    renderer.drawTileMap(\n        levelTileMap,\n        0, 0,\n        pixelroot32::graphics::Color::White\n    );\n\n    // Draw entities (also scrolled)\n    Scene::draw(renderer);\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#optimizing-tilemap-rendering","title":"Optimizing Tilemap Rendering","text":""},{"location":"manual/advanced_graphics/tilemaps/#viewport-culling","title":"Viewport Culling","text":"

Only draw visible tiles:

void drawTileMapOptimized(\n    pixelroot32::graphics::Renderer& renderer,\n    const pixelroot32::graphics::TileMap& tileMap,\n    int offsetX, int offsetY,\n    pixelroot32::graphics::Color color\n) {\n    int screenWidth = renderer.getWidth();\n    int screenHeight = renderer.getHeight();\n\n    // Calculate which tiles are visible\n    int startTileX = (offsetX < 0) ? (-offsetX / tileMap.tileWidth) : 0;\n    int startTileY = (offsetY < 0) ? (-offsetY / tileMap.tileHeight) : 0;\n    int endTileX = startTileX + (screenWidth / tileMap.tileWidth) + 1;\n    int endTileY = startTileY + (screenHeight / tileMap.tileHeight) + 1;\n\n    // Clamp to tilemap bounds\n    if (startTileX < 0) startTileX = 0;\n    if (startTileY < 0) startTileY = 0;\n    if (endTileX > tileMap.width) endTileX = tileMap.width;\n    if (endTileY > tileMap.height) endTileY = tileMap.height;\n\n    // Draw only visible tiles\n    for (int ty = startTileY; ty < endTileY; ty++) {\n        for (int tx = startTileX; tx < endTileX; tx++) {\n            uint8_t tileIndex = tileMap.indices[ty * tileMap.width + tx];\n            if (tileIndex < tileMap.tileCount) {\n                int x = tx * tileMap.tileWidth + offsetX;\n                int y = ty * tileMap.tileHeight + offsetY;\n                renderer.drawSprite(\n                    tileMap.tiles[tileIndex],\n                    x, y,\n                    color,\n                    false\n                );\n            }\n        }\n    }\n}\n

Note: The built-in drawTileMap() already performs viewport culling, so you typically don't need to implement this yourself.

"},{"location":"manual/advanced_graphics/tilemaps/#best-practices","title":"Best Practices","text":""},{"location":"manual/advanced_graphics/tilemaps/#tile-design","title":"Tile Design","text":"
  • Keep tiles small: 8x8 or 16x16 pixels work best
  • Reuse tiles: Design tiles that can be used in multiple ways
  • Consistent style: All tiles should match visually
  • Limit tile count: Too many unique tiles uses more memory
"},{"location":"manual/advanced_graphics/tilemaps/#level-design","title":"Level Design","text":"
  • Use indices efficiently: 0 = empty, 1+ = different tiles
  • Plan layout: Design level on paper/grid first
  • Test on hardware: Large tilemaps may impact performance
  • Optimize data: Use compact level data format
"},{"location":"manual/advanced_graphics/tilemaps/#performance","title":"Performance","text":"
  • Limit tilemap size: Very large tilemaps can be slow
  • Use appropriate tile size: Smaller tiles = more tiles to draw
  • Combine with culling: Only draw visible area
  • Test scrolling: Ensure smooth scrolling performance
"},{"location":"manual/advanced_graphics/tilemaps/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/advanced_graphics/tilemaps/#level-data-in-code","title":"Level Data in Code","text":"
// Define level as 2D array (easier to read)\nstatic const uint8_t LEVEL_DATA[][TILEMAP_WIDTH] = {\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},\n    {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, // Ground\n};\n\n// Copy to tilemap indices\nvoid loadLevel() {\n    for (int y = 0; y < TILEMAP_HEIGHT; y++) {\n        for (int x = 0; x < TILEMAP_WIDTH; x++) {\n            TILEMAP_INDICES[y * TILEMAP_WIDTH + x] = LEVEL_DATA[y][x];\n        }\n    }\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#collision-detection-with-tilemaps","title":"Collision Detection with Tilemaps","text":"
bool isTileSolid(int tileX, int tileY) {\n    if (tileX < 0 || tileX >= TILEMAP_WIDTH ||\n        tileY < 0 || tileY >= TILEMAP_HEIGHT) {\n        return true; // Out of bounds = solid\n    }\n\n    uint8_t tileIndex = TILEMAP_INDICES[tileY * TILEMAP_WIDTH + tileX];\n    return tileIndex != 0; // 0 = empty, others = solid\n}\n\nbool checkCollision(float x, float y, int width, int height) {\n    // Convert world position to tile coordinates\n    int tileX1 = static_cast<int>(x) / TILE_SIZE;\n    int tileY1 = static_cast<int>(y) / TILE_SIZE;\n    int tileX2 = static_cast<int>(x + width) / TILE_SIZE;\n    int tileY2 = static_cast<int>(y + height) / TILE_SIZE;\n\n    // Check all tiles actor overlaps\n    for (int ty = tileY1; ty <= tileY2; ty++) {\n        for (int tx = tileX1; tx <= tileX2; tx++) {\n            if (isTileSolid(tx, ty)) {\n                return true; // Collision!\n            }\n        }\n    }\n\n    return false; // No collision\n}\n
"},{"location":"manual/advanced_graphics/tilemaps/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/advanced_graphics/tilemaps/#tiles-not-appearing","title":"Tiles Not Appearing","text":"
  • Verify tile indices are correct (0 = first tile, 1 = second, etc.)
  • Check tilemap dimensions match indices array size
  • Ensure tiles array has enough entries
  • Verify tile size matches sprite size
"},{"location":"manual/advanced_graphics/tilemaps/#performance-issues","title":"Performance Issues","text":"
  • Reduce tilemap size
  • Use smaller tiles
  • Limit number of unique tiles
  • Test viewport culling
"},{"location":"manual/advanced_graphics/tilemaps/#scrolling-problems","title":"Scrolling Problems","text":"
  • Ensure camera is applied before drawing tilemap
  • Check tilemap position matches camera offset
  • Verify tilemap boundaries are correct
  • Test with simple tilemap first
"},{"location":"manual/advanced_graphics/tilemaps/#next-steps","title":"Next Steps","text":"

Now that you understand tilemaps, learn about: - Particles and Effects - Add visual effects - Cameras and Scrolling - Combine with scrolling - Performance Optimization - Optimize rendering

See also: - API Reference - TileMap - API Reference - Renderer - Manual - Cameras and Scrolling

"},{"location":"manual/game_development/audio/","title":"Audio","text":"

PixelRoot32 includes a complete NES-like audio system with 4 channels for sound effects and background music. This guide shows you how to add sound and music to your games.

"},{"location":"manual/game_development/audio/#audio-configuration","title":"Audio Configuration","text":"

Before using audio, you need to configure an AudioBackend. This is done when creating the Engine:

"},{"location":"manual/game_development/audio/#esp32-internal-dac","title":"ESP32: Internal DAC","text":"
#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nconst int DAC_PIN = 25; // GPIO 25 or 26\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\npr32::audio::AudioConfig audioConfig(&audioBackend, audioBackend.getSampleRate());\n
"},{"location":"manual/game_development/audio/#esp32-external-i2s-dac","title":"ESP32: External I2S DAC","text":"
#include <drivers/esp32/ESP32_I2S_AudioBackend.h>\n\nconst int I2S_BCLK = 26;  // Bit clock\nconst int I2S_LRCK = 25;  // Left/Right clock\nconst int I2S_DOUT = 22;  // Data out\n\npr32::drivers::esp32::ESP32_I2S_AudioBackend audioBackend(\n    I2S_BCLK, I2S_LRCK, I2S_DOUT, 22050\n);\n\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n
"},{"location":"manual/game_development/audio/#native-pc-sdl2","title":"Native (PC): SDL2","text":"
#include <drivers/native/SDL2_AudioBackend.h>\n\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\n\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n
"},{"location":"manual/game_development/audio/#sound-effects","title":"Sound Effects","text":"

Sound effects are created using AudioEvent structures and played through the AudioEngine.

"},{"location":"manual/game_development/audio/#audioevent-structure","title":"AudioEvent Structure","text":"
#include <audio/AudioTypes.h>\n\npr32::audio::AudioEvent soundEffect{};\nsoundEffect.type = pr32::audio::WaveType::PULSE;  // Waveform type\nsoundEffect.frequency = 1500.0f;                  // Frequency in Hz\nsoundEffect.duration = 0.12f;                      // Duration in seconds\nsoundEffect.volume = 0.8f;                         // Volume (0.0 to 1.0)\nsoundEffect.duty = 0.5f;                           // Duty cycle (for PULSE only)\n
"},{"location":"manual/game_development/audio/#wave-types","title":"Wave Types","text":"

PixelRoot32 supports three wave types:

  • PULSE: Square wave with variable duty cycle
  • Duty cycles: 0.125 (thin), 0.25 (classic NES), 0.5 (symmetric), 0.75 (fat)
  • Good for: Beeps, jumps, UI sounds, leads

  • TRIANGLE: Triangle wave (fixed volume/duty)

  • Softer, smoother sound
  • Good for: Bass lines, pads, background tones

  • NOISE: Pseudo-random noise

  • Harsh, chaotic sound
  • Good for: Explosions, hits, impacts, drums
"},{"location":"manual/game_development/audio/#playing-sound-effects","title":"Playing Sound Effects","text":"
// Get the audio engine\nauto& audio = engine.getAudioEngine();\n\n// Create and play a sound\npr32::audio::AudioEvent jumpSound{};\njumpSound.type = pr32::audio::WaveType::PULSE;\njumpSound.frequency = 800.0f;\njumpSound.duration = 0.1f;\njumpSound.volume = 0.7f;\njumpSound.duty = 0.25f;\n\naudio.playEvent(jumpSound);\n
"},{"location":"manual/game_development/audio/#common-sound-effects","title":"Common Sound Effects","text":"

Here are some example sound effects you can use:

namespace SoundEffects {\n    // Jump sound\n    inline pr32::audio::AudioEvent jump() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::PULSE;\n        evt.frequency = 600.0f;\n        evt.duration = 0.1f;\n        evt.volume = 0.7f;\n        evt.duty = 0.25f;\n        return evt;\n    }\n\n    // Coin/collect sound\n    inline pr32::audio::AudioEvent coin() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::PULSE;\n        evt.frequency = 1500.0f;\n        evt.duration = 0.12f;\n        evt.volume = 0.8f;\n        evt.duty = 0.5f;\n        return evt;\n    }\n\n    // Explosion\n    inline pr32::audio::AudioEvent explosion() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::NOISE;\n        evt.frequency = 200.0f;\n        evt.duration = 0.3f;\n        evt.volume = 0.9f;\n        return evt;\n    }\n\n    // Hit/damage\n    inline pr32::audio::AudioEvent hit() {\n        pr32::audio::AudioEvent evt{};\n        evt.type = pr32::audio::WaveType::NOISE;\n        evt.frequency = 300.0f;\n        evt.duration = 0.15f;\n        evt.volume = 0.6f;\n        return evt;\n    }\n}\n\n// Usage\naudio.playEvent(SoundEffects::jump());\n
"},{"location":"manual/game_development/audio/#background-music","title":"Background Music","text":"

Background music uses the MusicPlayer system, which sequences notes over time.

"},{"location":"manual/game_development/audio/#music-notes","title":"Music Notes","text":"

Music is built from MusicNote structures:

#include <audio/AudioMusicTypes.h>\n\nusing namespace pr32::audio;\n\nMusicNote note{};\nnote.note = Note::C;        // Musical note (C, D, E, F, G, A, B, or Rest)\nnote.octave = 4;            // Octave (0-8)\nnote.duration = 0.2f;       // Duration in seconds\nnote.volume = 0.7f;         // Volume (0.0 to 1.0)\n
"},{"location":"manual/game_development/audio/#instrument-presets","title":"Instrument Presets","text":"

For convenience, use predefined instrument presets:

using namespace pr32::audio;\n\n// Available presets:\n// - INSTR_PULSE_LEAD: Main lead pulse (octave 4)\n// - INSTR_PULSE_BASS: Bass pulse (octave 3)\n// - INSTR_PULSE_CHIP_HIGH: High-pitched chiptune (octave 5)\n// - INSTR_TRIANGLE_PAD: Soft triangle pad (octave 4)\n
"},{"location":"manual/game_development/audio/#creating-a-melody","title":"Creating a Melody","text":"
#include <audio/AudioMusicTypes.h>\n\nusing namespace pr32::audio;\n\n// Define melody notes\nstatic const MusicNote MELODY_NOTES[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),  // Rest (silence)\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),\n};\n\n// Create music track\nstatic const MusicTrack GAME_MUSIC = {\n    MELODY_NOTES,                              // notes array\n    sizeof(MELODY_NOTES) / sizeof(MusicNote),  // note count\n    true,                                       // loop\n    WaveType::PULSE,                           // channel type\n    0.5f                                       // duty cycle\n};\n
"},{"location":"manual/game_development/audio/#playing-music","title":"Playing Music","text":"
// Get the music player\nauto& music = engine.getMusicPlayer();\n\n// Play a track\nmusic.play(GAME_MUSIC);\n\n// Control playback\nmusic.stop();   // Stop playback\nmusic.pause();  // Pause (time doesn't advance)\nmusic.resume(); // Resume after pause\n\n// Check status\nif (music.isPlaying()) {\n    // Music is currently playing\n}\n
"},{"location":"manual/game_development/audio/#music-in-scene","title":"Music in Scene","text":"

Typically, you start music in your scene's init():

void MyGameScene::init() override {\n    // Start background music\n    engine.getMusicPlayer().play(GAME_MUSIC);\n\n    // ... rest of initialization\n}\n
"},{"location":"manual/game_development/audio/#master-volume","title":"Master Volume","text":"

Control overall volume without changing individual sounds:

auto& audio = engine.getAudioEngine();\n\n// Set master volume (0.0 to 1.0)\naudio.setMasterVolume(0.5f); // 50% volume\n\n// Get current volume\nfloat currentVolume = audio.getMasterVolume();\n
"},{"location":"manual/game_development/audio/#complete-example","title":"Complete Example","text":"

Here's a complete example combining sound effects and music:

#include <core/Scene.h>\n#include <audio/AudioTypes.h>\n#include <audio/AudioMusicTypes.h>\n\nusing namespace pr32::audio;\n\n// Background music\nstatic const MusicNote GAME_MELODY[] = {\n    makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),\n    makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),\n    makeRest(0.10f),\n};\n\nstatic const MusicTrack BACKGROUND_MUSIC = {\n    GAME_MELODY,\n    sizeof(GAME_MELODY) / sizeof(MusicNote),\n    true,  // loop\n    WaveType::PULSE,\n    0.5f\n};\n\nclass AudioExampleScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Start background music\n        engine.getMusicPlayer().play(BACKGROUND_MUSIC);\n\n        // Set master volume\n        engine.getAudioEngine().setMasterVolume(0.8f);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        auto& audio = engine.getAudioEngine();\n\n        // Play sound effect on button press\n        if (input.isButtonPressed(4)) { // Button A\n            AudioEvent jumpSound{};\n            jumpSound.type = WaveType::PULSE;\n            jumpSound.frequency = 800.0f;\n            jumpSound.duration = 0.1f;\n            jumpSound.volume = 0.7f;\n            jumpSound.duty = 0.25f;\n\n            audio.playEvent(jumpSound);\n        }\n\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/audio/#designing-nes-like-sounds","title":"Designing NES-like Sounds","text":""},{"location":"manual/game_development/audio/#frequency-guidelines","title":"Frequency Guidelines","text":"
  • Low frequencies (200-400 Hz): Bass, impacts, explosions
  • Mid frequencies (400-1000 Hz): Main sounds, jumps, UI
  • High frequencies (1000-2000 Hz): Beeps, coins, pickups
  • Very high (2000+ Hz): Sharp sounds, alerts
"},{"location":"manual/game_development/audio/#duration-guidelines","title":"Duration Guidelines","text":"
  • Short (0.05-0.1s): UI clicks, small effects
  • Medium (0.1-0.2s): Jumps, hits, pickups
  • Long (0.2-0.5s): Explosions, power-ups, transitions
"},{"location":"manual/game_development/audio/#duty-cycle-pulse-only","title":"Duty Cycle (PULSE only)","text":"
  • 0.125: Thin, sharp, piercing
  • 0.25: Classic NES lead sound
  • 0.5: Symmetric, full, fat
  • 0.75: Very fat, bass-like
"},{"location":"manual/game_development/audio/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/audio/#sound-design","title":"Sound Design","text":"
  • Keep sounds short: Long sounds can overlap and cause issues
  • Use appropriate volumes: 0.6-0.8 is usually good for effects
  • Vary frequencies: Don't use the same frequency for everything
  • Test on hardware: ESP32 audio may sound different than PC
"},{"location":"manual/game_development/audio/#music","title":"Music","text":"
  • Use one channel for music: Leave other channels for SFX
  • Keep melodies simple: Complex melodies can be hard to follow
  • Loop seamlessly: End your melody where it can loop naturally
  • Consider tempo: Faster games need faster music
"},{"location":"manual/game_development/audio/#performance","title":"Performance","text":"
  • Limit simultaneous sounds: Only 4 channels total
  • Music uses one channel: Plan your SFX accordingly
  • Don't spam sounds: Too many sounds can cause audio glitches
  • Use master volume: Easier than adjusting individual sounds
"},{"location":"manual/game_development/audio/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/audio/#sound-effect-helper-function","title":"Sound Effect Helper Function","text":"
void playJumpSound() {\n    auto& audio = engine.getAudioEngine();\n    AudioEvent evt{};\n    evt.type = WaveType::PULSE;\n    evt.frequency = 600.0f;\n    evt.duration = 0.1f;\n    evt.volume = 0.7f;\n    evt.duty = 0.25f;\n    audio.playEvent(evt);\n}\n
"},{"location":"manual/game_development/audio/#music-state-management","title":"Music State Management","text":"
class GameScene : public Scene {\n    bool musicStarted = false;\n\n    void init() override {\n        // Don't start music here if scene can be re-initialized\n    }\n\n    void update(unsigned long deltaTime) override {\n        if (!musicStarted) {\n            engine.getMusicPlayer().play(GAME_MUSIC);\n            musicStarted = true;\n        }\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"manual/game_development/audio/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/game_development/audio/#no-sound","title":"No Sound","text":"
  • Check audio backend is configured correctly
  • Verify sample rate matches backend
  • Check master volume is not 0
  • Ensure audio is initialized (engine.init())
"},{"location":"manual/game_development/audio/#distorted-sound","title":"Distorted Sound","text":"
  • Lower volume levels
  • Reduce sample rate (ESP32 DAC works better at 11025 Hz)
  • Check for too many simultaneous sounds
  • Verify hardware connections (ESP32)
"},{"location":"manual/game_development/audio/#music-not-playing","title":"Music Not Playing","text":"
  • Check music.isPlaying() status
  • Ensure track is properly defined
  • Verify MusicPlayer is updated (happens automatically)
  • Check that music channel is not being used by SFX
"},{"location":"manual/game_development/audio/#next-steps","title":"Next Steps","text":"

Now that you can add audio, learn about: - NES Audio Reference - Advanced audio techniques - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs

See also: - API Reference - AudioEngine - API Reference - MusicPlayer - API Reference - Audio Types - Manual - Audio Overview

"},{"location":"manual/game_development/basic_rendering/","title":"Basic Rendering","text":"

Rendering is how you draw everything on screen. This guide covers the fundamental drawing operations in PixelRoot32: primitives, sprites, and text.

"},{"location":"manual/game_development/basic_rendering/#accessing-the-renderer","title":"Accessing the Renderer","text":"

You can access the renderer in two ways:

"},{"location":"manual/game_development/basic_rendering/#from-the-engine","title":"From the Engine","text":"
auto& renderer = engine.getRenderer();\n
"},{"location":"manual/game_development/basic_rendering/#from-a-scene","title":"From a Scene","text":"
void MyScene::draw(pixelroot32::graphics::Renderer& renderer) override {\n    // renderer is passed as parameter\n    // Drawing covers the entire logical screen (e.g., 128x128)\n    renderer.drawFilledRectangle(0, 0, renderer.getLogicalWidth(), renderer.getLogicalHeight(), Color::Black);\n}\n
"},{"location":"manual/game_development/basic_rendering/#drawing-primitives","title":"Drawing Primitives","text":""},{"location":"manual/game_development/basic_rendering/#pixels","title":"Pixels","text":"

Draw a single pixel:

renderer.drawPixel(100, 100, pixelroot32::graphics::Color::White);\n
"},{"location":"manual/game_development/basic_rendering/#lines","title":"Lines","text":"

Draw a line between two points:

renderer.drawLine(10, 10, 200, 200, pixelroot32::graphics::Color::Red);\n
"},{"location":"manual/game_development/basic_rendering/#rectangles","title":"Rectangles","text":"

Draw a rectangle outline:

renderer.drawRectangle(50, 50, 100, 80, pixelroot32::graphics::Color::Blue);\n

Draw a filled rectangle:

renderer.drawFilledRectangle(50, 50, 100, 80, pixelroot32::graphics::Color::Blue);\n
"},{"location":"manual/game_development/basic_rendering/#circles","title":"Circles","text":"

Draw a circle outline:

renderer.drawCircle(120, 120, 30, pixelroot32::graphics::Color::Green);\n

Draw a filled circle:

renderer.drawFilledCircle(120, 120, 30, pixelroot32::graphics::Color::Green);\n
"},{"location":"manual/game_development/basic_rendering/#simple-sprites-1bpp","title":"Simple Sprites (1bpp)","text":"

Sprites are the primary way to draw game graphics. The standard format is 1bpp (1 bit per pixel), which is memory-efficient and perfect for retro-style graphics.

"},{"location":"manual/game_development/basic_rendering/#creating-a-sprite-manually","title":"Creating a Sprite Manually","text":"

A 1bpp sprite is defined as an array of uint16_t, where each value represents one row:

#include <graphics/Renderer.h>\n\n// Example: 8x8 sprite (8 rows, each row is a uint16_t)\n// Bit 0 = leftmost pixel, bit 7 = rightmost pixel\nstatic const uint16_t MY_SPRITE_DATA[] = {\n    0b00111100,  // Row 0:   ..####..\n    0b01111110,  // Row 1:  .######.\n    0b11111111,  // Row 2:  ########\n    0b11111111,  // Row 3:  ########\n    0b11111111,  // Row 4:  ########\n    0b01111110,  // Row 5:  .######.\n    0b00111100,  // Row 6:   ..####..\n    0b00000000   // Row 7:  ........\n};\n\n// Create sprite descriptor\nstatic const pixelroot32::graphics::Sprite MY_SPRITE = {\n    MY_SPRITE_DATA,  // data pointer\n    8,                // width\n    8                 // height\n};\n
"},{"location":"manual/game_development/basic_rendering/#drawing-a-sprite","title":"Drawing a Sprite","text":"
renderer.drawSprite(\n    MY_SPRITE,                                    // sprite\n    100,                                          // x position\n    100,                                          // y position\n    pixelroot32::graphics::Color::White,         // color\n    false                                         // flipX (optional, default false)\n);\n
"},{"location":"manual/game_development/basic_rendering/#sprite-bit-convention","title":"Sprite Bit Convention","text":"
  • Each uint16_t represents one row
  • Bit 0 (rightmost bit) = leftmost pixel
  • Bit (width - 1) = rightmost pixel
  • 0 = transparent/off, 1 = on (colored)

Example: For an 8-pixel wide sprite:

Row value: 0b00111100\nPixels:    ..####..\n           ^      ^\n         bit 7  bit 0 (leftmost)\n

"},{"location":"manual/game_development/basic_rendering/#flipping-sprites","title":"Flipping Sprites","text":"

You can flip a sprite horizontally:

renderer.drawSprite(MY_SPRITE, 100, 100, Color::White, true); // flipped\n
"},{"location":"manual/game_development/basic_rendering/#text-rendering","title":"Text Rendering","text":"

PixelRoot32 uses a native bitmap font system for pixel-perfect text rendering.

"},{"location":"manual/game_development/basic_rendering/#drawing-text","title":"Drawing Text","text":"
renderer.drawText(\n    \"Hello World!\",                           // text string\n    10,                                       // x position\n    20,                                       // y position\n    pixelroot32::graphics::Color::White,     // color\n    1                                         // size multiplier (1=normal, 2=double, etc.)\n);\n
"},{"location":"manual/game_development/basic_rendering/#centered-text","title":"Centered Text","text":"
renderer.drawTextCentered(\n    \"Game Over\",                              // text\n    120,                                      // y position (centered horizontally)\n    pixelroot32::graphics::Color::Red,       // color\n    2                                         // size\n);\n
"},{"location":"manual/game_development/basic_rendering/#text-size","title":"Text Size","text":"

The size parameter multiplies the font size: - 1 = normal size (5x7 pixels per character with default font) - 2 = double size (10x14 pixels) - 3 = triple size (15x21 pixels) - etc.

"},{"location":"manual/game_development/basic_rendering/#supported-characters","title":"Supported Characters","text":"

The default font (FONT_5X7) supports ASCII characters 32-126: - Letters: A-Z, a-z - Numbers: 0-9 - Symbols: !@#$%^&*()_+-=[]{}|;:'\",.<>?/ etc.

"},{"location":"manual/game_development/basic_rendering/#render-layers","title":"Render Layers","text":"

Entities are drawn in order based on their renderLayer property:

  • Layer 0 (Background): Drawn first (behind everything)
  • Layer 1 (Gameplay): Drawn second (main game objects)
  • Layer 2 (UI): Drawn last (on top of everything)

Set the render layer when creating an entity:

myEntity->setRenderLayer(0); // Background\nmyEntity->setRenderLayer(1); // Gameplay (default)\nmyEntity->setRenderLayer(2); // UI\n
"},{"location":"manual/game_development/basic_rendering/#complete-example","title":"Complete Example","text":"

Here's a complete example that draws various primitives and a sprite:

#include <core/Scene.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\n// Simple sprite data (8x8 circle)\nstatic const uint16_t CIRCLE_SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b01111110,\n    0b00111100\n};\n\nstatic const pixelroot32::graphics::Sprite CIRCLE_SPRITE = {\n    CIRCLE_SPRITE_DATA,\n    8,\n    8\n};\n\nclass RenderingExampleScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Set palette\n        pixelroot32::graphics::setPalette(\n            pixelroot32::graphics::PaletteType::NES\n        );\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background (layer 0)\n        renderer.drawFilledRectangle(0, 0, 240, 240, \n            pixelroot32::graphics::Color::Navy);\n\n        // Draw primitives (layer 1)\n        renderer.drawRectangle(10, 10, 100, 80, \n            pixelroot32::graphics::Color::White);\n        renderer.drawFilledCircle(120, 120, 30, \n            pixelroot32::graphics::Color::Red);\n        renderer.drawLine(0, 0, 240, 240, \n            pixelroot32::graphics::Color::Yellow);\n\n        // Draw sprite\n        renderer.drawSprite(CIRCLE_SPRITE, 50, 50, \n            pixelroot32::graphics::Color::Cyan);\n\n        // Draw text (layer 2 - UI)\n        renderer.drawText(\"Score: 100\", 10, 10, \n            pixelroot32::graphics::Color::White, 1);\n        renderer.drawTextCentered(\"Rendering Demo\", 200, \n            pixelroot32::graphics::Color::Yellow, 2);\n\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/basic_rendering/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/basic_rendering/#performance","title":"Performance","text":"
  • Minimize draw calls: Batch similar operations when possible
  • Use render layers efficiently: Don't mix layers unnecessarily
  • Avoid drawing off-screen: Check bounds before drawing
  • Reuse sprites: Define sprites once, use many times
"},{"location":"manual/game_development/basic_rendering/#organization","title":"Organization","text":"
  • Define sprites as static const: Keep them in flash memory
  • Use meaningful names: Name your sprites clearly
  • Group related sprites: Organize sprite data logically
  • Document complex sprites: Comment sprite bit patterns if needed
"},{"location":"manual/game_development/basic_rendering/#text","title":"Text","text":"
  • Avoid frequent text updates: Text rendering has overhead
  • Use appropriate sizes: Larger text uses more memory
  • Cache text dimensions: Use FontManager::textWidth() if needed
  • Keep text simple: Complex formatting is not supported
"},{"location":"manual/game_development/basic_rendering/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/basic_rendering/#drawing-a-background","title":"Drawing a Background","text":"
void drawBackground(Renderer& renderer) {\n    // Solid color background\n    renderer.drawFilledRectangle(0, 0, 240, 240, Color::Black);\n\n    // Or use a tilemap (see Advanced Graphics section)\n}\n
"},{"location":"manual/game_development/basic_rendering/#drawing-a-hud","title":"Drawing a HUD","text":"
void drawHUD(Renderer& renderer, int score, int lives) {\n    char buffer[32];\n    snprintf(buffer, sizeof(buffer), \"Score: %d\", score);\n    renderer.drawText(buffer, 10, 10, Color::White, 1);\n\n    snprintf(buffer, sizeof(buffer), \"Lives: %d\", lives);\n    renderer.drawText(buffer, 10, 20, Color::White, 1);\n}\n
"},{"location":"manual/game_development/basic_rendering/#drawing-multiple-sprites","title":"Drawing Multiple Sprites","text":"
void drawSpriteArray(Renderer& renderer, const Sprite& sprite, \n                     int count, int startX, int startY, int spacing) {\n    for (int i = 0; i < count; i++) {\n        int x = startX + (i * (sprite.width + spacing));\n        renderer.drawSprite(sprite, x, startY, Color::White);\n    }\n}\n
"},{"location":"manual/game_development/basic_rendering/#next-steps","title":"Next Steps","text":"

Now that you can draw basic graphics, learn about: - Sprites and Animation - Advanced sprite techniques - Input and Control - Make your game interactive - Palettes - Use different color schemes

See also: - API Reference - Renderer - API Reference - Sprite - Render Layers

"},{"location":"manual/game_development/input_and_control/","title":"Input and Control","text":"

Handling user input is essential for any interactive game. This guide covers how to read and process input from buttons (ESP32) or keyboard (Native) in PixelRoot32.

"},{"location":"manual/game_development/input_and_control/#input-configuration","title":"Input Configuration","text":"

Before you can read input, you need to configure the InputManager. This is done when creating the Engine:

"},{"location":"manual/game_development/input_and_control/#esp32-configuration","title":"ESP32 Configuration","text":"
#include <input/InputConfig.h>\n\n// InputConfig(buttonCount, UP, DOWN, LEFT, RIGHT, A, B)\npr32::input::InputConfig inputConfig(\n    6,      // Total number of buttons\n    32,     // UP button GPIO pin\n    27,     // DOWN button GPIO pin\n    33,     // LEFT button GPIO pin\n    14,     // RIGHT button GPIO pin\n    13,     // A button GPIO pin\n    12      // B button GPIO pin\n);\n
"},{"location":"manual/game_development/input_and_control/#native-pc-configuration","title":"Native (PC) Configuration","text":"
#include <SDL2/SDL.h>\n#include <input/InputConfig.h>\n\n// InputConfig(buttonCount, UP, DOWN, LEFT, RIGHT, A, B)\npr32::input::InputConfig inputConfig(\n    6,                      // Total number of buttons\n    SDL_SCANCODE_UP,        // UP key\n    SDL_SCANCODE_DOWN,      // DOWN key\n    SDL_SCANCODE_LEFT,      // LEFT key\n    SDL_SCANCODE_RIGHT,     // RIGHT key\n    SDL_SCANCODE_SPACE,     // A button (Space)\n    SDL_SCANCODE_RETURN     // B button (Enter)\n);\n
"},{"location":"manual/game_development/input_and_control/#reading-input","title":"Reading Input","text":"

Access the InputManager through the Engine:

auto& input = engine.getInputManager();\n
"},{"location":"manual/game_development/input_and_control/#input-states","title":"Input States","text":"

The InputManager provides four different ways to check button state:

"},{"location":"manual/game_development/input_and_control/#1-isbuttonpressed","title":"1. isButtonPressed()","text":"

Returns true only on the frame when the button was just pressed:

if (input.isButtonPressed(4)) { // Button A (index 4)\n    // This code runs only once when button is first pressed\n    jump();\n}\n

Use for: Actions that should trigger once per press (jump, shoot, select menu item).

"},{"location":"manual/game_development/input_and_control/#2-isbuttonreleased","title":"2. isButtonReleased()","text":"

Returns true only on the frame when the button was just released:

if (input.isButtonReleased(4)) {\n    // This code runs only once when button is released\n    stopCharging();\n}\n

Use for: Actions that trigger on release (charge attacks, menu confirmation).

"},{"location":"manual/game_development/input_and_control/#3-isbuttondown","title":"3. isButtonDown()","text":"

Returns true while the button is currently held down:

if (input.isButtonDown(2)) { // LEFT button (index 2)\n    // This code runs every frame while button is held\n    playerX -= speed * (deltaTime * 0.001f);\n}\n

Use for: Continuous actions (movement, holding, charging).

"},{"location":"manual/game_development/input_and_control/#4-isbuttonclicked","title":"4. isButtonClicked()","text":"

Returns true when the button was pressed and then released:

if (input.isButtonClicked(4)) {\n    // This code runs once per click (press + release cycle)\n    toggleMenu();\n}\n

Use for: Toggle actions, menu selections, click interactions.

"},{"location":"manual/game_development/input_and_control/#button-indices","title":"Button Indices","text":"

The button indices correspond to the order in InputConfig:

  • Index 0: UP
  • Index 1: DOWN
  • Index 2: LEFT
  • Index 3: RIGHT
  • Index 4: A button
  • Index 5: B button

For convenience, you can define constants:

namespace Buttons {\n    constexpr uint8_t UP = 0;\n    constexpr uint8_t DOWN = 1;\n    constexpr uint8_t LEFT = 2;\n    constexpr uint8_t RIGHT = 3;\n    constexpr uint8_t A = 4;\n    constexpr uint8_t B = 5;\n}\n\n// Usage\nif (input.isButtonPressed(Buttons::A)) {\n    // ...\n}\n
"},{"location":"manual/game_development/input_and_control/#character-control-example","title":"Character Control Example","text":"

Here's a complete example of character movement:

#include <core/Actor.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass PlayerActor : public pixelroot32::core::Actor {\npublic:\n    float speed = 100.0f; // pixels per second\n\n    PlayerActor(float x, float y)\n        : Actor(x, y, 16, 16) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f; // Convert to seconds\n\n        // Horizontal movement\n        if (input.isButtonDown(Buttons::LEFT)) {\n            x -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::RIGHT)) {\n            x += speed * dt;\n        }\n\n        // Vertical movement\n        if (input.isButtonDown(Buttons::UP)) {\n            y -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::DOWN)) {\n            y += speed * dt;\n        }\n\n        // Keep player on screen\n        if (x < 0) x = 0;\n        if (x > 224) x = 224;\n        if (y < 0) y = 0;\n        if (y > 224) y = 224;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width,\n            height,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collisions\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#jumping-example","title":"Jumping Example","text":"

For platformer-style jumping:

class PlatformerPlayer : public pixelroot32::core::PhysicsActor {\npublic:\n    bool canJump = true;\n    float jumpForce = 200.0f;\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        // Horizontal movement\n        float moveSpeed = 80.0f;\n        if (input.isButtonDown(Buttons::LEFT)) {\n            setVelocity(-moveSpeed, vy);\n        } else if (input.isButtonDown(Buttons::RIGHT)) {\n            setVelocity(moveSpeed, vy);\n        } else {\n            setVelocity(0, vy);\n        }\n\n        // Jump (only on press, and only if on ground)\n        if (input.isButtonPressed(Buttons::A) && canJump) {\n            setVelocity(vx, -jumpForce);\n            canJump = false;\n        }\n\n        // Check if on ground (for jump reset)\n        auto collisionInfo = getWorldCollisionInfo();\n        if (collisionInfo.bottom) {\n            canJump = true;\n        }\n\n        PhysicsActor::update(deltaTime);\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#shooting-example","title":"Shooting Example","text":"

For shooting projectiles:

class ShooterActor : public pixelroot32::core::Actor {\nprivate:\n    bool fireInputReady = true;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n\n        // Shooting (with cooldown)\n        if (input.isButtonPressed(Buttons::A) && fireInputReady) {\n            shoot();\n            fireInputReady = false;\n        }\n\n        // Reset fire input when button is released\n        if (input.isButtonReleased(Buttons::A)) {\n            fireInputReady = true;\n        }\n    }\n\n    void shoot() {\n        // Create projectile\n        // ...\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#menu-navigation-example","title":"Menu Navigation Example","text":"

For menu navigation:

class MenuScene : public pixelroot32::core::Scene {\nprivate:\n    int selectedIndex = 0;\n    static const int MENU_ITEMS = 3;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n\n        // Navigate menu\n        if (input.isButtonPressed(Buttons::UP)) {\n            selectedIndex--;\n            if (selectedIndex < 0) selectedIndex = MENU_ITEMS - 1;\n        }\n\n        if (input.isButtonPressed(Buttons::DOWN)) {\n            selectedIndex++;\n            if (selectedIndex >= MENU_ITEMS) selectedIndex = 0;\n        }\n\n        // Select menu item\n        if (input.isButtonPressed(Buttons::A)) {\n            selectMenuItem(selectedIndex);\n        }\n\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/input_and_control/#frame-rate-independence","title":"Frame-Rate Independence","text":"

Always multiply movement by delta time:

// \u2705 GOOD: Framerate-independent\nx += speed * (deltaTime * 0.001f);\n\n// \u274c BAD: Framerate-dependent\nx += speed;\n
"},{"location":"manual/game_development/input_and_control/#input-debouncing","title":"Input Debouncing","text":"

For actions that should only trigger once:

// Use isButtonPressed() instead of isButtonDown()\nif (input.isButtonPressed(Buttons::A)) {\n    // Triggers once per press\n}\n
"},{"location":"manual/game_development/input_and_control/#input-buffering","title":"Input Buffering","text":"

For responsive controls, you can buffer input:

class InputBuffer {\n    uint8_t bufferedInput = 0;\n\npublic:\n    void update(const InputManager& input) {\n        if (input.isButtonPressed(Buttons::A)) {\n            bufferedInput = Buttons::A;\n        }\n    }\n\n    bool hasBufferedInput() const { return bufferedInput != 0; }\n    uint8_t consumeInput() {\n        uint8_t result = bufferedInput;\n        bufferedInput = 0;\n        return result;\n    }\n};\n
"},{"location":"manual/game_development/input_and_control/#multiple-input-methods","title":"Multiple Input Methods","text":"

Support both button presses and held buttons:

// Allow both tap and hold for rapid fire\nif (input.isButtonPressed(Buttons::A) || \n    (input.isButtonDown(Buttons::A) && rapidFireTimer <= 0)) {\n    shoot();\n    rapidFireTimer = RAPID_FIRE_DELAY;\n}\n
"},{"location":"manual/game_development/input_and_control/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/input_and_control/#directional-input","title":"Directional Input","text":"
float getHorizontalInput() {\n    auto& input = engine.getInputManager();\n    float dir = 0.0f;\n    if (input.isButtonDown(Buttons::LEFT)) dir -= 1.0f;\n    if (input.isButtonDown(Buttons::RIGHT)) dir += 1.0f;\n    return dir;\n}\n\nfloat getVerticalInput() {\n    auto& input = engine.getInputManager();\n    float dir = 0.0f;\n    if (input.isButtonDown(Buttons::UP)) dir -= 1.0f;\n    if (input.isButtonDown(Buttons::DOWN)) dir += 1.0f;\n    return dir;\n}\n
"},{"location":"manual/game_development/input_and_control/#input-state-machine","title":"Input State Machine","text":"

For complex input handling:

enum class InputState {\n    IDLE,\n    PRESSED,\n    HELD,\n    RELEASED\n};\n\nInputState getButtonState(const InputManager& input, uint8_t button) {\n    if (input.isButtonPressed(button)) return InputState::PRESSED;\n    if (input.isButtonDown(button)) return InputState::HELD;\n    if (input.isButtonReleased(button)) return InputState::RELEASED;\n    return InputState::IDLE;\n}\n
"},{"location":"manual/game_development/input_and_control/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/game_development/input_and_control/#button-not-responding","title":"Button Not Responding","text":"
  • Check button indices match your InputConfig
  • Verify GPIO pins (ESP32) or scancodes (Native) are correct
  • Ensure InputManager is being updated (happens automatically in Engine)
"},{"location":"manual/game_development/input_and_control/#input-feels-laggy","title":"Input Feels Laggy","text":"
  • Ensure you're using deltaTime for movement
  • Check that input is read in update(), not draw()
  • Verify framerate is stable
"},{"location":"manual/game_development/input_and_control/#multiple-triggers","title":"Multiple Triggers","text":"
  • Use isButtonPressed() instead of isButtonDown() for one-time actions
  • Implement input buffering or cooldown timers
"},{"location":"manual/game_development/input_and_control/#next-steps","title":"Next Steps","text":"

Now that you can handle input, learn about: - Audio - Add sound effects and music - Physics and Collisions - Make objects interact - User Interface - Create menus and HUDs

See also: - API Reference - InputManager - API Reference - InputConfig - Manual - Input Overview

"},{"location":"manual/game_development/physics_and_collisions/","title":"Physics and Collisions","text":"

PixelRoot32 provides a physics system for moving objects and collision detection. This guide covers PhysicsActor for automatic physics and the collision system for detecting interactions between objects.

"},{"location":"manual/game_development/physics_and_collisions/#physicsactor","title":"PhysicsActor","text":"

A PhysicsActor is an Actor that automatically handles physics: velocity, gravity, friction, and world boundary collisions.

"},{"location":"manual/game_development/physics_and_collisions/#creating-a-physicsactor","title":"Creating a PhysicsActor","text":"
#include <core/PhysicsActor.h>\n\nclass Ball : public pixelroot32::core::PhysicsActor {\npublic:\n    Ball(float x, float y, float radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRenderLayer(1);\n\n        // Set physics properties\n        setRestitution(0.8f);  // Bounciness (0.8 = 80% bounce)\n        setFriction(0.1f);     // Friction (0.1 = slight friction)\n\n        // Set world boundaries\n        setWorldSize(240, 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Apply gravity\n        // (PhysicsActor handles this automatically, but you can add custom forces)\n\n        // Call parent update to apply physics\n        PhysicsActor::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        int radius = width / 2;\n        renderer.drawFilledCircle(\n            static_cast<int>(x + radius),\n            static_cast<int>(y + radius),\n            radius,\n            pixelroot32::graphics::Color::White\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collision with other actors\n    }\n\n    void onWorldCollision() override {\n        // Called when hitting world boundaries\n        // You can play a sound effect here, for example\n    }\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#physics-properties","title":"Physics Properties","text":""},{"location":"manual/game_development/physics_and_collisions/#velocity","title":"Velocity","text":"

Set the velocity directly:

ball->setVelocity(100.0f, -50.0f); // Move right at 100 px/s, up at 50 px/s\n

Or modify existing velocity:

float vx = ball->vx; // Access velocity components (protected, use getter if needed)\nball->setVelocity(vx + 10.0f, ball->vy); // Accelerate horizontally\n
"},{"location":"manual/game_development/physics_and_collisions/#restitution-bounciness","title":"Restitution (Bounciness)","text":"

Controls how much energy is conserved in collisions:

ball->setRestitution(1.0f);  // Perfect bounce (no energy loss)\nball->setRestitution(0.5f);  // 50% energy loss\nball->setRestitution(0.0f);  // No bounce (stops on impact)\n
"},{"location":"manual/game_development/physics_and_collisions/#friction","title":"Friction","text":"

Applies gradual velocity reduction:

ball->setFriction(0.0f);  // No friction (slides forever)\nball->setFriction(0.5f);  // Moderate friction\nball->setFriction(1.0f);  // High friction (stops quickly)\n
"},{"location":"manual/game_development/physics_and_collisions/#world-boundaries","title":"World Boundaries","text":"

Set the playable area:

// Set world size (used as default boundaries)\nball->setWorldSize(240, 240);\n\n// Or set custom boundaries\npixelroot32::core::LimitRect limits(10, 10, 230, 230); // Left, Top, Right, Bottom\nball->setLimits(limits);\n
"},{"location":"manual/game_development/physics_and_collisions/#world-collision-detection","title":"World Collision Detection","text":"

Check if the actor hit world boundaries:

void update(unsigned long deltaTime) override {\n    PhysicsActor::update(deltaTime);\n\n    auto collisionInfo = getWorldCollisionInfo();\n\n    if (collisionInfo.left || collisionInfo.right) {\n        // Hit side walls\n    }\n\n    if (collisionInfo.top || collisionInfo.bottom) {\n        // Hit top/bottom walls\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#collision-system","title":"Collision System","text":"

The collision system detects when Actors overlap and triggers callbacks.

"},{"location":"manual/game_development/physics_and_collisions/#collision-layers","title":"Collision Layers","text":"

Use bit flags to organize actors into groups:

// Define layers (typically in GameLayers.h)\nnamespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;    // Bit 0\n    constexpr uint16_t ENEMY = 0x0002;     // Bit 1\n    constexpr uint16_t PROJECTILE = 0x0004; // Bit 2\n    constexpr uint16_t WALL = 0x0008;      // Bit 3\n    constexpr uint16_t PICKUP = 0x0010;    // Bit 4\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#setting-up-collisions","title":"Setting Up Collisions","text":"

Configure each actor's collision layer and mask:

class PlayerActor : public pixelroot32::core::Actor {\npublic:\n    PlayerActor(float x, float y)\n        : Actor(x, y, 16, 16) {\n        // This actor belongs to the PLAYER layer\n        setCollisionLayer(Layers::PLAYER);\n\n        // This actor can collide with ENEMY, WALL, and PICKUP\n        setCollisionMask(Layers::ENEMY | Layers::WALL | Layers::PICKUP);\n    }\n\n    // ... rest of implementation\n};\n\nclass EnemyActor : public pixelroot32::core::Actor {\npublic:\n    EnemyActor(float x, float y)\n        : Actor(x, y, 16, 16) {\n        // This actor belongs to the ENEMY layer\n        setCollisionLayer(Layers::ENEMY);\n\n        // This actor can collide with PLAYER and PROJECTILE\n        setCollisionMask(Layers::PLAYER | Layers::PROJECTILE);\n    }\n\n    // ... rest of implementation\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#collision-detection","title":"Collision Detection","text":"

Collisions are automatically detected by the Scene's CollisionSystem. You handle collisions in onCollision():

void PlayerActor::onCollision(pixelroot32::core::Actor* other) override {\n    // Check what we collided with\n    if (other->isInLayer(Layers::ENEMY)) {\n        // Hit an enemy - take damage\n        takeDamage();\n    } else if (other->isInLayer(Layers::PICKUP)) {\n        // Hit a pickup - collect it\n        collectPickup(other);\n    } else if (other->isInLayer(Layers::WALL)) {\n        // Hit a wall - stop movement\n        stopMovement();\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#hitbox","title":"Hitbox","text":"

Define the collision shape:

pixelroot32::core::Rect getHitBox() override {\n    // Simple AABB (Axis-Aligned Bounding Box)\n    return {x, y, width, height};\n\n    // Or use a smaller hitbox for more forgiving collisions\n    // return {x + 2, y + 2, width - 4, height - 4};\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#complete-example-bouncing-ball","title":"Complete Example: Bouncing Ball","text":"
#include <core/PhysicsActor.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass BouncingBall : public pixelroot32::core::PhysicsActor {\npublic:\n    BouncingBall(float x, float y, float radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRenderLayer(1);\n\n        // Physics setup\n        setRestitution(0.9f);  // Very bouncy\n        setFriction(0.05f);    // Low friction\n        setWorldSize(240, 240); // World boundaries\n\n        // Initial velocity\n        setVelocity(50.0f, -30.0f);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Apply gravity\n        float gravity = 200.0f; // pixels per second squared\n        float dt = deltaTime * 0.001f;\n        setVelocity(vx, vy + gravity * dt);\n\n        // Update physics\n        PhysicsActor::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        int radius = width / 2;\n        renderer.drawFilledCircle(\n            static_cast<int>(x + radius),\n            static_cast<int>(y + radius),\n            radius,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Bounce off other objects\n        // (PhysicsActor handles world boundaries automatically)\n    }\n\n    void onWorldCollision() override {\n        // Play bounce sound when hitting walls\n        // (Implementation depends on your audio setup)\n    }\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#complete-example-platformer-player","title":"Complete Example: Platformer Player","text":"
class PlatformerPlayer : public pixelroot32::core::PhysicsActor {\nprivate:\n    bool onGround = false;\n    float jumpForce = 250.0f;\n    float moveSpeed = 100.0f;\n\npublic:\n    PlatformerPlayer(float x, float y)\n        : PhysicsActor(x, y, 16, 16) {\n        setRenderLayer(1);\n        setFriction(0.3f);  // Ground friction\n        setWorldSize(240, 240);\n\n        // Collision setup\n        setCollisionLayer(Layers::PLAYER);\n        setCollisionMask(Layers::ENEMY | Layers::PLATFORM);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        // Horizontal movement\n        float moveDir = 0.0f;\n        if (input.isButtonDown(Buttons::LEFT)) moveDir -= 1.0f;\n        if (input.isButtonDown(Buttons::RIGHT)) moveDir += 1.0f;\n\n        setVelocity(moveDir * moveSpeed, vy);\n\n        // Apply gravity\n        float gravity = 300.0f;\n        setVelocity(vx, vy + gravity * dt);\n\n        // Jump\n        if (input.isButtonPressed(Buttons::A) && onGround) {\n            setVelocity(vx, -jumpForce);\n            onGround = false;\n        }\n\n        // Update physics\n        PhysicsActor::update(deltaTime);\n\n        // Check if on ground\n        auto collisionInfo = getWorldCollisionInfo();\n        onGround = collisionInfo.bottom;\n\n        // Also check collision with platforms\n        // (This would be handled in onCollision)\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        if (other->isInLayer(Layers::PLATFORM)) {\n            // Land on platform\n            auto platformRect = other->getHitBox();\n            if (y + height <= platformRect.y + 5) { // Within 5 pixels of top\n                y = platformRect.y - height;\n                vy = 0;\n                onGround = true;\n            }\n        } else if (other->isInLayer(Layers::ENEMY)) {\n            // Hit enemy\n            takeDamage();\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width,\n            height,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"manual/game_development/physics_and_collisions/#sweep-tests","title":"Sweep Tests","text":"

For fast-moving projectiles, use sweep tests to detect collisions between positions:

#include <physics/CollisionPrimitives.h>\n\nbool checkProjectileHit(PhysicsActor* projectile, Actor* target) {\n    // Get previous and current positions\n    float prevX = projectile->x - (projectile->vx * deltaTime * 0.001f);\n    float prevY = projectile->y - (projectile->vy * deltaTime * 0.001f);\n\n    // Create circles for sweep test\n    pixelroot32::physics::Circle startCircle;\n    startCircle.x = prevX + projectile->width / 2;\n    startCircle.y = prevY + projectile->height / 2;\n    startCircle.radius = projectile->width / 2;\n\n    pixelroot32::physics::Circle endCircle;\n    endCircle.x = projectile->x + projectile->width / 2;\n    endCircle.y = projectile->y + projectile->height / 2;\n    endCircle.radius = projectile->width / 2;\n\n    // Get target rectangle\n    auto targetRect = target->getHitBox();\n\n    // Perform sweep test\n    float tHit;\n    if (pixelroot32::physics::sweepCircleVsRect(\n        startCircle, endCircle, targetRect, tHit)) {\n        // Collision detected at time tHit (0.0 = at start, 1.0 = at end)\n        return true;\n    }\n\n    return false;\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/physics_and_collisions/#collision-layers_1","title":"Collision Layers","text":"
  • Plan your layers: Design the layer system before coding
  • Use bit flags: Makes combining layers easy with | operator
  • Keep it simple: Don't create too many layers
  • Document layers: Create a GameLayers.h file with all definitions
"},{"location":"manual/game_development/physics_and_collisions/#physics","title":"Physics","text":"
  • Use appropriate values: Test gravity, speed, and forces
  • Frame-rate independence: Always use deltaTime
  • Limit world size: Keep boundaries reasonable
  • Test on hardware: Physics may behave differently on ESP32 vs PC
"},{"location":"manual/game_development/physics_and_collisions/#performance","title":"Performance","text":"
  • Limit active actors: Fewer actors = faster collision checks
  • Use layers efficiently: Reduce unnecessary collision pairs
  • Simple hitboxes: AABB is fast, complex shapes are slow
  • Sweep tests sparingly: Only for fast-moving objects
"},{"location":"manual/game_development/physics_and_collisions/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/physics_and_collisions/#collision-layer-helper","title":"Collision Layer Helper","text":"
namespace CollisionLayers {\n    constexpr uint16_t PLAYER = 0x0001;\n    constexpr uint16_t ENEMY = 0x0002;\n    constexpr uint16_t PROJECTILE = 0x0004;\n    constexpr uint16_t WALL = 0x0008;\n    constexpr uint16_t PICKUP = 0x0010;\n\n    // Helper to check if actor is in specific layer\n    bool isPlayer(Actor* actor) {\n        return actor->isInLayer(PLAYER);\n    }\n\n    bool isEnemy(Actor* actor) {\n        return actor->isInLayer(ENEMY);\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#platform-collision","title":"Platform Collision","text":"
void PlatformerPlayer::onCollision(Actor* other) override {\n    if (other->isInLayer(Layers::PLATFORM)) {\n        auto platform = other->getHitBox();\n\n        // Check if landing on top of platform\n        float playerBottom = y + height;\n        float platformTop = platform.y;\n\n        if (playerBottom <= platformTop + 5 && vy > 0) {\n            // Land on platform\n            y = platformTop - height;\n            vy = 0;\n            onGround = true;\n        }\n    }\n}\n
"},{"location":"manual/game_development/physics_and_collisions/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/game_development/physics_and_collisions/#collisions-not-detected","title":"Collisions Not Detected","text":"
  • Verify collision layers and masks overlap
  • Check that actors are added to the scene
  • Ensure Scene::update() is called
  • Verify hitboxes are correct
"},{"location":"manual/game_development/physics_and_collisions/#physics-too-fastslow","title":"Physics Too Fast/Slow","text":"
  • Adjust values based on deltaTime
  • Check gravity and velocity values
  • Test on actual hardware (ESP32 may run slower)
"},{"location":"manual/game_development/physics_and_collisions/#objects-passing-through","title":"Objects Passing Through","text":"
  • Use sweep tests for fast objects
  • Increase collision detection frequency
  • Check hitbox sizes match visual size
"},{"location":"manual/game_development/physics_and_collisions/#next-steps","title":"Next Steps","text":"

Now that you understand physics and collisions, learn about: - User Interface - Create menus and HUDs - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels

See also: - API Reference - PhysicsActor - API Reference - CollisionSystem - Manual - Physics Overview - Manual - Collision Detection

"},{"location":"manual/game_development/scenes_and_entities/","title":"Scenes and Entities","text":"

Scenes and entities are the foundation of every PixelRoot32 game. This guide teaches you how to organize your game using scenes and create interactive game objects with entities.

"},{"location":"manual/game_development/scenes_and_entities/#creating-a-scene","title":"Creating a Scene","text":"

A Scene represents a screen or level in your game. To create a scene, inherit from pixelroot32::core::Scene and implement the three main methods:

#include <core/Scene.h>\n#include <graphics/Renderer.h>\n\nclass MyGameScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Called once when the scene is initialized\n        // Set up your scene here: create entities, load resources, etc.\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Called every frame\n        // Update game logic here\n\n        // IMPORTANT: Always call parent update to update all entities\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Called every frame to draw\n        // Draw your scene here\n\n        // IMPORTANT: Always call parent draw to draw all entities\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#scene-lifecycle","title":"Scene Lifecycle","text":"
  1. init(): Called once when the scene is set as active
  2. Create and initialize entities
  3. Set up game state
  4. Load resources
  5. Configure palettes, audio, etc.

  6. update(deltaTime): Called every frame

  7. Process input
  8. Update game logic
  9. Handle collisions
  10. Must call Scene::update(deltaTime) to update all entities

  11. draw(renderer): Called every frame

  12. Draw background elements
  13. Draw UI elements
  14. Must call Scene::draw(renderer) to draw all entities
"},{"location":"manual/game_development/scenes_and_entities/#basic-entities","title":"Basic Entities","text":"

An Entity is any object in your game. To create an entity, inherit from pixelroot32::core::Entity:

#include <core/Entity.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\nclass SimpleEntity : public pixelroot32::core::Entity {\npublic:\n    SimpleEntity(float x, float y)\n        : Entity(x, y, 16, 16, pixelroot32::core::EntityType::GENERIC) {\n        // Set render layer (0=background, 1=gameplay, 2=UI)\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update entity logic\n        // For example, move the entity\n        this->x += 1.0f * (deltaTime * 0.001f); // Move right at 1 pixel per second\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw the entity\n        renderer.drawFilledRectangle(\n            static_cast<int>(x), \n            static_cast<int>(y), \n            width, \n            height, \n            pixelroot32::graphics::Color::Red\n        );\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#entity-properties","title":"Entity Properties","text":"

Every entity has these properties:

  • x, y: Position in world space (float)
  • width, height: Dimensions (int)
  • isVisible: If false, draw() is not called
  • isEnabled: If false, update() is not called
  • renderLayer: Which layer to draw on (0, 1, or 2)
"},{"location":"manual/game_development/scenes_and_entities/#adding-entities-to-a-scene","title":"Adding Entities to a Scene","text":"

Add entities to your scene in init():

void MyGameScene::init() override {\n    // Create entities\n    SimpleEntity* entity1 = new SimpleEntity(50, 50);\n    SimpleEntity* entity2 = new SimpleEntity(100, 100);\n\n    // Add them to the scene\n    addEntity(entity1);\n    addEntity(entity2);\n}\n

The scene automatically manages these entities: - Calls update() on all enabled entities each frame - Calls draw() on all visible entities each frame - Handles cleanup when the scene is destroyed

"},{"location":"manual/game_development/scenes_and_entities/#actors-entities-with-collisions","title":"Actors: Entities with Collisions","text":"

An Actor is an entity that can participate in collision detection. Inherit from pixelroot32::core::Actor:

#include <core/Actor.h>\n#include <physics/CollisionTypes.h>\n\nclass MyActor : public pixelroot32::core::Actor {\npublic:\n    MyActor(float x, float y, int w, int h)\n        : Actor(x, y, w, h) {\n        // Set collision layer (what group this actor belongs to)\n        setCollisionLayer(0x0001); // Example: layer 1\n\n        // Set collision mask (what groups this actor can collide with)\n        setCollisionMask(0x0002); // Example: can collide with layer 2\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update actor logic\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw the actor\n    }\n\n    // REQUIRED: Define the hitbox for collision detection\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    // REQUIRED: Handle collisions\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // React to collision\n        // For example: take damage, destroy self, etc.\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#collision-layers-and-masks","title":"Collision Layers and Masks","text":"

Collision layers use bit flags to organize actors into groups:

// Define your layers (typically in a GameLayers.h file)\nnamespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;  // Bit 0\n    constexpr uint16_t ENEMY = 0x0002;  // Bit 1\n    constexpr uint16_t PROJECTILE = 0x0004; // Bit 2\n    constexpr uint16_t WALL = 0x0008;   // Bit 3\n}\n\n// Set up a player actor\nplayer->setCollisionLayer(Layers::PLAYER);\nplayer->setCollisionMask(Layers::ENEMY | Layers::WALL); // Can collide with enemies and walls\n\n// Set up an enemy actor\nenemy->setCollisionLayer(Layers::ENEMY);\nenemy->setCollisionMask(Layers::PLAYER | Layers::PROJECTILE); // Can collide with player and projectiles\n

The collision system only checks collisions between actors whose layers and masks overlap. This is much more efficient than checking every pair.

"},{"location":"manual/game_development/scenes_and_entities/#scene-management","title":"Scene Management","text":""},{"location":"manual/game_development/scenes_and_entities/#setting-the-active-scene","title":"Setting the Active Scene","text":"

From your main code, set the active scene:

MyGameScene gameScene;\n\nvoid setup() {\n    engine.init();\n    gameScene.init();\n    engine.setScene(&gameScene); // Set as active scene\n}\n
"},{"location":"manual/game_development/scenes_and_entities/#switching-scenes","title":"Switching Scenes","text":"

To switch to a different scene:

MenuScene menuScene;\nGameScene gameScene;\n\nvoid switchToGame() {\n    gameScene.init();\n    engine.setScene(&gameScene); // Replaces current scene\n}\n
"},{"location":"manual/game_development/scenes_and_entities/#scene-stack-pushpop","title":"Scene Stack (Push/Pop)","text":"

For menus and pause screens, use the scene stack:

// Push a pause menu (game scene stays in background)\nvoid pauseGame() {\n    pauseMenu.init();\n    engine.getCurrentScene()->getSceneManager().pushScene(&pauseMenu);\n}\n\n// Pop the pause menu (resume game)\nvoid resumeGame() {\n    engine.getCurrentScene()->getSceneManager().popScene();\n}\n

Note: Scene stack management is handled internally by the Engine's SceneManager. You typically access it through engine.getCurrentScene().

"},{"location":"manual/game_development/scenes_and_entities/#complete-example","title":"Complete Example","text":"

Here's a complete example of a scene with multiple entities:

#include <core/Scene.h>\n#include <core/Entity.h>\n#include <core/Actor.h>\n#include <graphics/Renderer.h>\n#include <graphics/Color.h>\n\n// A simple moving entity\nclass MovingBox : public pixelroot32::core::Entity {\npublic:\n    MovingBox(float x, float y) \n        : Entity(x, y, 20, 20, pixelroot32::core::EntityType::GENERIC),\n          speedX(50.0f), speedY(30.0f) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        float dt = deltaTime * 0.001f; // Convert to seconds\n\n        x += speedX * dt;\n        y += speedY * dt;\n\n        // Bounce off screen edges\n        if (x < 0 || x > 220) speedX = -speedX;\n        if (y < 0 || y > 220) speedY = -speedY;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x), \n            static_cast<int>(y), \n            width, \n            height, \n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\nprivate:\n    float speedX, speedY;\n};\n\n// A simple actor that can collide\nclass CollidableBox : public pixelroot32::core::Actor {\npublic:\n    CollidableBox(float x, float y)\n        : Actor(x, y, 30, 30) {\n        setRenderLayer(1);\n        setCollisionLayer(0x0001);\n        setCollisionMask(0x0001);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Static actor, no movement\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x), \n            static_cast<int>(y), \n            width, \n            height, \n            pixelroot32::graphics::Color::Yellow\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Change color when collided\n        // (In a real game, you'd handle collision logic here)\n    }\n};\n\n// The scene\nclass ExampleScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Create and add entities\n        addEntity(new MovingBox(50, 50));\n        addEntity(new MovingBox(150, 100));\n        addEntity(new CollidableBox(100, 100));\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime); // Update all entities\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // Draw background\n        renderer.drawFilledRectangle(0, 0, 240, 240, \n            pixelroot32::graphics::Color::Black);\n\n        Scene::draw(renderer); // Draw all entities\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/scenes_and_entities/#entity-management","title":"Entity Management","text":"
  • Pre-allocate entities: Create entities in init(), not in update()
  • Reuse entities: Instead of creating/destroying, enable/disable entities
  • Limit entity count: MAX_ENTITIES = 32 per scene
  • Use object pooling: For frequently created/destroyed entities (projectiles, particles)
"},{"location":"manual/game_development/scenes_and_entities/#scene-organization","title":"Scene Organization","text":"
  • One scene per screen: Menu, game, game over, etc.
  • Keep scenes focused: Each scene should have a single responsibility
  • Initialize in init(): Don't do heavy work in the constructor
  • Clean up properly: Remove entities when switching scenes
"},{"location":"manual/game_development/scenes_and_entities/#collision-layers","title":"Collision Layers","text":"
  • Plan your layers: Design your layer system before coding
  • Use bit flags: Makes layer combinations easy
  • Keep it simple: Don't over-complicate with too many layers
  • Document your layers: Create a GameLayers.h file
"},{"location":"manual/game_development/scenes_and_entities/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/scenes_and_entities/#entity-pool-pattern","title":"Entity Pool Pattern","text":"

For entities that are frequently created and destroyed (like projectiles):

class ProjectilePool {\n    static const int POOL_SIZE = 10;\n    ProjectileActor pool[POOL_SIZE];\n\npublic:\n    ProjectileActor* getAvailable() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!pool[i].isActive) {\n                pool[i].isActive = true;\n                return &pool[i];\n            }\n        }\n        return nullptr; // Pool exhausted\n    }\n};\n
"},{"location":"manual/game_development/scenes_and_entities/#entity-factory-pattern","title":"Entity Factory Pattern","text":"

Create entities through factory functions:

Entity* createEnemy(EnemyType type, float x, float y) {\n    switch (type) {\n        case EnemyType::BASIC:\n            return new BasicEnemy(x, y);\n        case EnemyType::FAST:\n            return new FastEnemy(x, y);\n        // ...\n    }\n}\n
"},{"location":"manual/game_development/scenes_and_entities/#next-steps","title":"Next Steps","text":"

Now that you understand scenes and entities, learn about: - Basic Rendering - Draw sprites, text, and primitives - Input and Control - Handle user input - Physics and Collisions - Advanced collision handling

See also: - Fundamental Concepts - API Reference - Scene - API Reference - Entity - API Reference - Actor

"},{"location":"manual/game_development/user_interface/","title":"User Interface","text":"

PixelRoot32 provides a complete UI system for creating menus, HUDs, and interface elements. This guide covers all UI components and layout systems.

"},{"location":"manual/game_development/user_interface/#ui-elements","title":"UI Elements","text":"

All UI elements inherit from UIElement, which itself inherits from Entity. This means UI elements can be added to scenes just like any other entity.

"},{"location":"manual/game_development/user_interface/#uilabel","title":"UILabel","text":"

Display text on screen:

#include <graphics/ui/UILabel.h>\n\n// Create a label\npixelroot32::graphics::ui::UILabel* scoreLabel = new pixelroot32::graphics::ui::UILabel(\n    \"Score: 0\",                    // text\n    10,                            // x position\n    10,                            // y position\n    pixelroot32::graphics::Color::White,  // color\n    1                              // size multiplier\n);\n\n// Add to scene\naddEntity(scoreLabel);\n\n// Update text dynamically\nscoreLabel->setText(\"Score: 100\");\n\n// Center horizontally\nscoreLabel->centerX(240); // Screen width\n
"},{"location":"manual/game_development/user_interface/#uibutton","title":"UIButton","text":"

Create clickable buttons:

#include <graphics/ui/UIButton.h>\n\n// Create a button\npixelroot32::graphics::ui::UIButton* startButton = new pixelroot32::graphics::ui::UIButton(\n    \"Start Game\",                  // text\n    4,                             // navigation index\n    50,                            // x position\n    100,                           // y position\n    140,                           // width\n    30,                            // height\n    []() {                         // callback function\n        // Button clicked - start game\n        startGame();\n    }\n);\n\n// Configure style\nstartButton->setStyle(\n    pixelroot32::graphics::Color::White,   // text color\n    pixelroot32::graphics::Color::Blue,    // background color\n    true                                    // draw background\n);\n\n// Add to scene\naddEntity(startButton);\n
"},{"location":"manual/game_development/user_interface/#uicheckbox","title":"UICheckBox","text":"

Create interactive checkboxes:

#include <graphics/ui/UICheckBox.h>\n\n// Create a checkbox\npixelroot32::graphics::ui::UICheckBox* soundCheckbox = new pixelroot32::graphics::ui::UICheckBox(\n    \"Enable Sound\",                // text\n    4,                             // navigation index\n    50,                            // x position\n    140,                           // y position\n    140,                           // width\n    20,                            // height\n    true,                          // initial checked state\n    [](bool checked) {             // callback function\n        // Checkbox state changed\n        setSoundEnabled(checked);\n    },\n    1                              // font size\n);\n\n// Configure style\nsoundCheckbox->setStyle(\n    pixelroot32::graphics::Color::White,   // text color\n    pixelroot32::graphics::Color::Blue,    // background color\n    false                                  // draw background\n);\n\n// Add to scene\naddEntity(soundCheckbox);\n
"},{"location":"manual/game_development/user_interface/#uipanel","title":"UIPanel","text":"

Create visual containers with background and border:

#include <graphics/ui/UIPanel.h>\n\n// Create a panel\npixelroot32::graphics::ui::UIPanel* dialog = new pixelroot32::graphics::ui::UIPanel(\n    50,   // x\n    50,   // y\n    140,  // width\n    140   // height\n);\n\n// Configure appearance\ndialog->setBackgroundColor(pixelroot32::graphics::Color::Black);\ndialog->setBorderColor(pixelroot32::graphics::Color::White);\ndialog->setBorderWidth(2);\n\n// Add content (typically a layout)\ndialog->setChild(menuLayout);\n\n// Add to scene\naddEntity(dialog);\n
"},{"location":"manual/game_development/user_interface/#layouts","title":"Layouts","text":"

Layouts automatically organize UI elements, eliminating the need for manual position calculations.

"},{"location":"manual/game_development/user_interface/#uiverticallayout","title":"UIVerticalLayout","text":"

Organize elements vertically with automatic scrolling:

#include <graphics/ui/UIVerticalLayout.h>\n\n// Create vertical layout\npixelroot32::graphics::ui::UIVerticalLayout* menu = new pixelroot32::graphics::ui::UIVerticalLayout(\n    10,   // x\n    60,   // y\n    220,  // width\n    160   // height (viewport)\n);\n\n// Configure layout\nmenu->setPadding(5);        // Internal padding\nmenu->setSpacing(6);        // Space between elements\nmenu->setScrollEnabled(true); // Enable scrolling\n\n// Set navigation buttons\nmenu->setNavigationButtons(0, 1); // UP=0, DOWN=1\n\n// Set button styles\nmenu->setButtonStyle(\n    pixelroot32::graphics::Color::White,  // selected text\n    pixelroot32::graphics::Color::Cyan,    // selected background\n    pixelroot32::graphics::Color::White,  // unselected text\n    pixelroot32::graphics::Color::Black   // unselected background\n);\n\n// Add buttons (no manual positioning needed!)\nfor (int i = 0; i < 10; i++) {\n    UIButton* btn = new UIButton(\n        \"Option \" + std::to_string(i),\n        i,\n        0, 0,  // Position ignored - layout handles it\n        200, 20,\n        [i]() { handleOption(i); }\n    );\n    menu->addElement(btn);\n}\n\n// Add layout to scene\nmenu->setRenderLayer(2); // UI layer\naddEntity(menu);\n
"},{"location":"manual/game_development/user_interface/#uihorizontallayout","title":"UIHorizontalLayout","text":"

Organize elements horizontally:

#include <graphics/ui/UIHorizontalLayout.h>\n\n// Create horizontal layout (menu bar)\npixelroot32::graphics::ui::UIHorizontalLayout* menuBar = new pixelroot32::graphics::ui::UIHorizontalLayout(\n    0,    // x\n    0,    // y\n    240,  // width\n    30    // height\n);\n\nmenuBar->setPadding(5);\nmenuBar->setSpacing(4);\nmenuBar->setScrollEnabled(true);\nmenuBar->setNavigationButtons(2, 3); // LEFT=2, RIGHT=3\n\n// Add menu items\nmenuBar->addElement(new UIButton(\"File\", 0, 0, 0, 60, 20, []() {}));\nmenuBar->addElement(new UIButton(\"Edit\", 1, 0, 0, 60, 20, []() {}));\nmenuBar->addElement(new UIButton(\"View\", 2, 0, 0, 60, 20, []() {}));\n\naddEntity(menuBar);\n
"},{"location":"manual/game_development/user_interface/#uigridlayout","title":"UIGridLayout","text":"

Organize elements in a grid (matrix):

#include <graphics/ui/UIGridLayout.h>\n\n// Create grid layout (inventory)\npixelroot32::graphics::ui::UIGridLayout* inventory = new pixelroot32::graphics::ui::UIGridLayout(\n    10,   // x\n    60,   // y\n    220,  // width\n    160   // height\n);\n\ninventory->setColumns(4);  // 4 columns\ninventory->setPadding(5);\ninventory->setSpacing(4);\ninventory->setNavigationButtons(0, 1, 2, 3); // UP, DOWN, LEFT, RIGHT\n\n// Add items (automatically arranged in grid)\nfor (int i = 0; i < 16; i++) {\n    UIButton* item = new UIButton(\n        \"Item \" + std::to_string(i),\n        i,\n        0, 0,  // Position ignored\n        50, 50,\n        [i]() { useItem(i); }\n    );\n    inventory->addElement(item);\n}\n\naddEntity(inventory);\n
"},{"location":"manual/game_development/user_interface/#uianchorlayout","title":"UIAnchorLayout","text":"

Position elements at fixed screen positions (perfect for HUDs):

#include <graphics/ui/UIAnchorLayout.h>\n\n// Create anchor layout for HUD\npixelroot32::graphics::ui::UIAnchorLayout* hud = new pixelroot32::graphics::ui::UIAnchorLayout(\n    0,    // x\n    0,    // y\n    240,  // screen width\n    240   // screen height\n);\n\nhud->setScreenSize(240, 240);\n\n// Add HUD elements at different anchor points\nUILabel* scoreLabel = new UILabel(\"Score: 0\", 0, 0, Color::White, 1);\nUILabel* livesLabel = new UILabel(\"Lives: 3\", 0, 0, Color::White, 1);\n\nhud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\nhud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\naddEntity(hud);\n

Available Anchors: - TOP_LEFT, TOP_RIGHT, TOP_CENTER - BOTTOM_LEFT, BOTTOM_RIGHT, BOTTOM_CENTER - LEFT_CENTER, RIGHT_CENTER - CENTER

"},{"location":"manual/game_development/user_interface/#uipaddingcontainer","title":"UIPaddingContainer","text":"

Add padding around a single element:

#include <graphics/ui/UIPaddingContainer.h>\n\n// Create padding container\npixelroot32::graphics::ui::UIPaddingContainer* container = new pixelroot32::graphics::ui::UIPaddingContainer(\n    10,   // x\n    10,   // y\n    200,  // width\n    100   // height\n);\n\n// Set uniform padding\ncontainer->setPadding(10);\n\n// Or set asymmetric padding\ncontainer->setPadding(5, 15, 10, 10); // left, right, top, bottom\n```cpp\n// Add child element\ncontainer->setChild(button);\n\naddEntity(container);\n
"},{"location":"manual/game_development/user_interface/#fixed-position-ui-huds","title":"Fixed Position UI (HUDs)","text":"

By default, UI elements behave like world objects: if you move the Camera2D, the UI elements will scroll with the world. For elements that should stay fixed on screen (like a HUD, health bar, or pause menu), you can use the fixedPosition property.

When setFixedPosition(true) is called on an element: 1. It ignores any Camera2D offsets (xOffset/yOffset). 2. It remains at its logical screen coordinates regardless of camera movement. 3. If the element is a layout (like UIAnchorLayout), all its children will also become fixed on screen.

"},{"location":"manual/game_development/user_interface/#example-fixed-hud","title":"Example: Fixed HUD","text":"
// Create an anchor layout for HUD\npixelroot32::graphics::ui::UIAnchorLayout* hud = new pixelroot32::graphics::ui::UIAnchorLayout(0, 0, 240, 240);\nhud->setScreenSize(240, 240);\n\n// IMPORTANT: Make the HUD stay fixed on screen\nhud->setFixedPosition(true);\n\n// Add health label at TOP_LEFT\nUILabel* healthLabel = new UILabel(\"HP: 100\", 0, 0, Color::Red, 1);\nhud->addElement(healthLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n\n// Add score label at TOP_RIGHT\nUILabel* scoreLabel = new UILabel(\"Score: 0\", 0, 0, Color::White, 1);\nhud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n\naddEntity(hud);\n
"},{"location":"manual/game_development/user_interface/#navigation","title":"Navigation","text":"

Layouts handle D-pad navigation automatically:

"},{"location":"manual/game_development/user_interface/#vertical-navigation","title":"Vertical Navigation","text":"
verticalLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN);\n\n// Layout automatically:\n// - Highlights selected button\n// - Scrolls to keep selected button visible\n// - Handles wrapping (optional)\n
"},{"location":"manual/game_development/user_interface/#horizontal-navigation","title":"Horizontal Navigation","text":"
horizontalLayout->setNavigationButtons(Buttons::LEFT, Buttons::RIGHT);\n
"},{"location":"manual/game_development/user_interface/#grid-navigation","title":"Grid Navigation","text":"
gridLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN, Buttons::LEFT, Buttons::RIGHT);\n\n// Layout automatically:\n// - Handles 4-direction navigation\n// - Wraps around edges\n// - Updates selection\n
"},{"location":"manual/game_development/user_interface/#manual-selection","title":"Manual Selection","text":"
// Set selected element programmatically\nlayout->setSelectedIndex(2);\n\n// Get selected element\nint selected = layout->getSelectedIndex();\nUIElement* element = layout->getSelectedElement();\n
"},{"location":"manual/game_development/user_interface/#complete-example-main-menu","title":"Complete Example: Main Menu","text":"
#include <core/Scene.h>\n#include <graphics/ui/UIVerticalLayout.h>\n#include <graphics/ui/UIButton.h>\n#include <graphics/ui/UILabel.h>\n#include <graphics/ui/UIPanel.h>\n\nclass MainMenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIVerticalLayout* menuLayout;\n    pixelroot32::graphics::ui::UIPanel* menuPanel;\n\npublic:\n    void init() override {\n        // Create panel\n        menuPanel = new pixelroot32::graphics::ui::UIPanel(40, 40, 160, 160);\n        menuPanel->setBackgroundColor(pixelroot32::graphics::Color::Black);\n        menuPanel->setBorderColor(pixelroot32::graphics::Color::White);\n        menuPanel->setBorderWidth(2);\n        menuPanel->setRenderLayer(2);\n        addEntity(menuPanel);\n\n        // Create layout inside panel\n        menuLayout = new pixelroot32::graphics::ui::UIVerticalLayout(0, 0, 160, 160);\n        menuLayout->setPadding(10);\n        menuLayout->setSpacing(8);\n        menuLayout->setNavigationButtons(0, 1);\n        menuLayout->setButtonStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Cyan,\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Black\n        );\n\n        // Add title\n        pixelroot32::graphics::ui::UILabel* title = new pixelroot32::graphics::ui::UILabel(\n            \"GAME MENU\", 0, 0, pixelroot32::graphics::Color::Yellow, 2\n        );\n        menuLayout->addElement(title);\n\n        // Add menu buttons\n        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Start Game\", 0, 0, 0, 140, 25, []() { startGame(); }\n        ));\n\n        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Options\", 1, 0, 0, 140, 25, []() { showOptions(); }\n        ));\n\n        menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Quit\", 2, 0, 0, 140, 25, []() { quitGame(); }\n        ));\n\n        menuPanel->setChild(menuLayout);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Handle input for layout navigation\n        auto& input = engine.getInputManager();\n        menuLayout->handleInput(input);\n\n        Scene::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"manual/game_development/user_interface/#complete-example-hud","title":"Complete Example: HUD","text":"
class GameHUD : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::ui::UIAnchorLayout* hud;\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n    pixelroot32::graphics::ui::UILabel* healthLabel;\n\npublic:\n    GameHUD()\n        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::UI_ELEMENT) {\n        setRenderLayer(2); // UI layer\n\n        // Create HUD layout\n        hud = new pixelroot32::graphics::ui::UIAnchorLayout(0, 0, 240, 240);\n        hud->setScreenSize(240, 240);\n\n        // Create labels\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\", 0, 0, pixelroot32::graphics::Color::White, 1\n        );\n\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\", 0, 0, pixelroot32::graphics::Color::White, 1\n        );\n\n        healthLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Health: 100%\", 0, 0, pixelroot32::graphics::Color::Green, 1\n        );\n\n        // Position labels\n        hud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);\n        hud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);\n        hud->addElement(healthLabel, pixelroot32::graphics::ui::Anchor::BOTTOM_CENTER);\n    }\n\n    void update(unsigned long deltaTime) override {\n        // Update HUD text (example)\n        char buffer[32];\n        snprintf(buffer, sizeof(buffer), \"Score: %d\", currentScore);\n        scoreLabel->setText(buffer);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        // HUD draws itself through its layout\n    }\n\n    // Add HUD to scene\n    void addToScene(Scene* scene) {\n        scene->addEntity(hud);\n    }\n};\n
"},{"location":"manual/game_development/user_interface/#best-practices","title":"Best Practices","text":""},{"location":"manual/game_development/user_interface/#organization","title":"Organization","text":"
  • Use render layer 2: Keep all UI on the top layer
  • Group related elements: Use panels to group menu items
  • Separate HUD from menus: Use different layouts for different UI types
  • Reuse layouts: Create layout factories for common patterns
"},{"location":"manual/game_development/user_interface/#performance","title":"Performance","text":"
  • Layouts use viewport culling: Only visible elements are rendered
  • Minimize text updates: Updating text has overhead
  • Use appropriate layouts: Choose the right layout for your needs
  • Limit element count: Too many elements can impact performance
"},{"location":"manual/game_development/user_interface/#fixed-position-ui-huds-overlays","title":"Fixed Position UI (HUDs & Overlays)","text":"

By default, UI elements placed in a scene will move with the Camera2D just like any other entity. To create a HUD or a menu that stays fixed on the screen regardless of camera movement, use the fixedPosition flag on your layouts:

// Create a HUD layout\npixelroot32::graphics::ui::UIVerticalLayout* hud = new pixelroot32::graphics::ui::UIVerticalLayout(10, 10, 100, 50);\n\n// Enable fixed positioning\nhud->setFixedPosition(true); // <--- This layout will now ignore Camera2D scrolling\n\n// Add to scene\naddEntity(hud);\n

When setFixedPosition(true) is called: 1. The layout and all its children will ignore the global camera offset. 2. The coordinates (x, y) of the layout become relative to the screen, not the world. 3. This is the recommended way to implement HUDs, pause menus, and screen-space overlays.

"},{"location":"manual/game_development/user_interface/#navigation_1","title":"Navigation","text":"
  • Set navigation buttons: Configure D-pad navigation for layouts
  • Handle input in update(): Check for button presses to trigger actions
  • Provide visual feedback: Selected buttons should be clearly visible
  • Test navigation flow: Ensure navigation feels responsive
"},{"location":"manual/game_development/user_interface/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/game_development/user_interface/#menu-system","title":"Menu System","text":"
class MenuSystem {\n    UIVerticalLayout* currentMenu;\n\npublic:\n    void showMainMenu() {\n        currentMenu = createMainMenu();\n        scene->addEntity(currentMenu);\n    }\n\n    void showPauseMenu() {\n        currentMenu = createPauseMenu();\n        scene->addEntity(currentMenu);\n    }\n\n    void hideMenu() {\n        if (currentMenu) {\n            scene->removeEntity(currentMenu);\n            currentMenu = nullptr;\n        }\n    }\n};\n
"},{"location":"manual/game_development/user_interface/#dynamic-ui-updates","title":"Dynamic UI Updates","text":"
void updateHUD(int score, int lives, int health) {\n    char buffer[32];\n\n    snprintf(buffer, sizeof(buffer), \"Score: %d\", score);\n    scoreLabel->setText(buffer);\n\n    snprintf(buffer, sizeof(buffer), \"Lives: %d\", lives);\n    livesLabel->setText(buffer);\n\n    snprintf(buffer, sizeof(buffer), \"Health: %d%%\", health);\n    healthLabel->setText(buffer);\n}\n
"},{"location":"manual/game_development/user_interface/#next-steps","title":"Next Steps","text":"

Now that you understand the UI system, you've completed the core game development topics. Continue with: - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels - Performance Tuning - Improve performance

See also: - API Reference - UIElement - API Reference - UIButton - API Reference - UI Layouts - Manual - UI Overview

"},{"location":"manual/optimization/extensibility/","title":"Extensibility","text":"

PixelRoot32 is designed to be extensible. This guide covers how to create custom drivers, audio backends, and extend existing systems.

"},{"location":"manual/optimization/extensibility/#creating-custom-display-drivers","title":"Creating Custom Display Drivers","text":"

To support a new display, implement the DrawSurface interface.

"},{"location":"manual/optimization/extensibility/#drawsurface-interface","title":"DrawSurface Interface","text":"
#include <graphics/DrawSurface.h>\n\nclass MyCustomDrawer : public pixelroot32::graphics::DrawSurface {\npublic:\n    // Required methods\n    void init() override;\n    void setRotation(uint8_t rotation) override;\n    void clearBuffer() override;\n    void sendBuffer() override;\n\n    // Drawing primitives\n    void drawPixel(int x, int y, uint16_t color) override;\n    void drawLine(int x1, int y1, int x2, int y2, uint16_t color) override;\n    void drawRectangle(int x, int y, int width, int height, uint16_t color) override;\n    void drawFilledRectangle(int x, int y, int width, int height, uint16_t color) override;\n    void drawCircle(int x, int y, int radius, uint16_t color) override;\n    void drawFilledCircle(int x, int y, int radius, uint16_t color) override;\n    void drawBitmap(int x, int y, int width, int height, const uint8_t* bitmap, uint16_t color) override;\n\n    // Text (deprecated, but must implement)\n    void drawText(const char* text, int16_t x, int16_t y, uint16_t color, uint8_t size) override;\n    void drawTextCentered(const char* text, int16_t y, uint16_t color, uint8_t size) override;\n\n    // State management\n    void setTextColor(uint16_t color) override;\n    void setTextSize(uint8_t size) override;\n    void setCursor(int16_t x, int16_t y) override;\n    void setContrast(uint8_t level) override;\n    void setDisplaySize(int w, int h) override;\n\n    // Utilities\n    uint16_t color565(uint8_t r, uint8_t g, uint8_t b) override;\n    bool processEvents() override;\n    void present() override;\n};\n
"},{"location":"manual/optimization/extensibility/#example-simple-custom-drawer","title":"Example: Simple Custom Drawer","text":"
#include <graphics/DrawSurface.h>\n\nclass SimpleDrawer : public pixelroot32::graphics::DrawSurface {\nprivate:\n    uint16_t* framebuffer;\n    int width, height;\n\npublic:\n    SimpleDrawer(int w, int h) : width(w), height(h) {\n        framebuffer = new uint16_t[w * h];\n    }\n\n    ~SimpleDrawer() {\n        delete[] framebuffer;\n    }\n\n    void init() override {\n        // Initialize your display hardware\n        // Clear framebuffer\n        clearBuffer();\n    }\n\n    void clearBuffer() override {\n        for (int i = 0; i < width * height; i++) {\n            framebuffer[i] = 0x0000; // Black\n        }\n    }\n\n    void sendBuffer() override {\n        // Send framebuffer to display\n        // Implementation depends on your hardware\n    }\n\n    void drawPixel(int x, int y, uint16_t color) override {\n        if (x >= 0 && x < width && y >= 0 && y < height) {\n            framebuffer[y * width + x] = color;\n        }\n    }\n\n    void drawFilledRectangle(int x, int y, int w, int h, uint16_t color) override {\n        for (int py = y; py < y + h; py++) {\n            for (int px = x; px < x + w; px++) {\n                drawPixel(px, py, color);\n            }\n        }\n    }\n\n    // Implement other required methods...\n    // (See TFT_eSPI_Drawer or SDL2_Drawer for reference implementations)\n};\n
"},{"location":"manual/optimization/extensibility/#integrating-custom-driver","title":"Integrating Custom Driver","text":"
// Create custom drawer\nSimpleDrawer* customDrawer = new SimpleDrawer(240, 240);\n\n// Create renderer with custom drawer\npixelroot32::graphics::DisplayConfig config(\n    pixelroot32::graphics::DisplayType::NONE, // Use NONE for custom\n    0, 240, 240\n);\n\n// You'll need to modify Engine to accept custom DrawSurface\n// Or create a custom Engine wrapper\n
"},{"location":"manual/optimization/extensibility/#creating-custom-audio-backends","title":"Creating Custom Audio Backends","text":"

Implement the AudioBackend interface for custom audio hardware.

"},{"location":"manual/optimization/extensibility/#audiobackend-interface","title":"AudioBackend Interface","text":"
#include <audio/AudioBackend.h>\n\nclass MyCustomAudioBackend : public pixelroot32::audio::AudioBackend {\npublic:\n    // Required methods\n    void init() override;\n    void start() override;\n    void stop() override;\n    uint32_t getSampleRate() const override;\n\n    // Audio generation\n    int16_t generateSample() override;\n\n    // Channel management\n    void setChannelWave(int channel, pixelroot32::audio::WaveType type, float frequency, float duty) override;\n    void setChannelVolume(int channel, float volume) override;\n    void stopChannel(int channel) override;\n};\n
"},{"location":"manual/optimization/extensibility/#example-custom-audio-backend","title":"Example: Custom Audio Backend","text":"
#include <audio/AudioBackend.h>\n\nclass CustomAudioBackend : public pixelroot32::audio::AudioBackend {\nprivate:\n    uint32_t sampleRate;\n    float phase[4] = {0, 0, 0, 0}; // 4 channels\n    float frequency[4] = {0, 0, 0, 0};\n    float volume[4] = {0, 0, 0, 0};\n    pixelroot32::audio::WaveType waveType[4];\n\npublic:\n    CustomAudioBackend(uint32_t rate) : sampleRate(rate) {\n        for (int i = 0; i < 4; i++) {\n            waveType[i] = pixelroot32::audio::WaveType::PULSE;\n            volume[i] = 0.0f;\n        }\n    }\n\n    void init() override {\n        // Initialize your audio hardware\n    }\n\n    void start() override {\n        // Start audio output\n    }\n\n    void stop() override {\n        // Stop audio output\n    }\n\n    uint32_t getSampleRate() const override {\n        return sampleRate;\n    }\n\n    int16_t generateSample() override {\n        float sample = 0.0f;\n\n        for (int ch = 0; ch < 4; ch++) {\n            if (frequency[ch] > 0 && volume[ch] > 0) {\n                float phaseIncrement = frequency[ch] / sampleRate;\n                phase[ch] += phaseIncrement;\n                if (phase[ch] >= 1.0f) phase[ch] -= 1.0f;\n\n                float channelSample = 0.0f;\n                switch (waveType[ch]) {\n                    case pixelroot32::audio::WaveType::PULSE:\n                        channelSample = (phase[ch] < 0.5f) ? 1.0f : -1.0f;\n                        break;\n                    case pixelroot32::audio::WaveType::TRIANGLE:\n                        channelSample = (phase[ch] < 0.5f) ? \n                            (phase[ch] * 4.0f - 1.0f) : \n                            (3.0f - phase[ch] * 4.0f);\n                        break;\n                    // ... other wave types\n                }\n\n                sample += channelSample * volume[ch];\n            }\n        }\n\n        // Clamp and convert to int16_t\n        if (sample > 1.0f) sample = 1.0f;\n        if (sample < -1.0f) sample = -1.0f;\n        return static_cast<int16_t>(sample * 32767.0f);\n    }\n\n    void setChannelWave(int ch, pixelroot32::audio::WaveType type, \n                       float freq, float duty) override {\n        if (ch >= 0 && ch < 4) {\n            waveType[ch] = type;\n            frequency[ch] = freq;\n        }\n    }\n\n    void setChannelVolume(int ch, float vol) override {\n        if (ch >= 0 && ch < 4) {\n            volume[ch] = vol;\n        }\n    }\n\n    void stopChannel(int ch) override {\n        if (ch >= 0 && ch < 4) {\n            frequency[ch] = 0.0f;\n            volume[ch] = 0.0f;\n        }\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#extending-existing-systems","title":"Extending Existing Systems","text":""},{"location":"manual/optimization/extensibility/#custom-entity-types","title":"Custom Entity Types","text":"

Create specialized entity types:

class PowerUpActor : public pixelroot32::core::Actor {\nprivate:\n    PowerUpType type;\n    float lifetime = 5.0f; // 5 seconds\n\npublic:\n    PowerUpActor(float x, float y, PowerUpType t)\n        : Actor(x, y, 8, 8), type(t) {\n        setRenderLayer(1);\n        setCollisionLayer(Layers::POWERUP);\n        setCollisionMask(Layers::PLAYER);\n    }\n\n    void update(unsigned long deltaTime) override {\n        lifetime -= deltaTime * 0.001f;\n        if (lifetime <= 0) {\n            isEnabled = false;\n            isVisible = false;\n        }\n\n        // Animate (bob up and down)\n        y += sin(millis() * 0.005f) * 0.5f;\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        if (other->isInLayer(Layers::PLAYER)) {\n            applyPowerUp(other);\n            isEnabled = false;\n            isVisible = false;\n        }\n    }\n\nprivate:\n    void applyPowerUp(pixelroot32::core::Actor* player) {\n        switch (type) {\n            case PowerUpType::SPEED:\n                // Increase player speed\n                break;\n            case PowerUpType::HEALTH:\n                // Restore health\n                break;\n            // ...\n        }\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#custom-ui-layouts","title":"Custom UI Layouts","text":"

Create new layout types:

#include <graphics/ui/UILayout.h>\n\nclass UICircularLayout : public pixelroot32::graphics::ui::UILayout {\nprivate:\n    float radius;\n    float startAngle;\n\npublic:\n    UICircularLayout(float x, float y, float w, float h, float r)\n        : UILayout(x, y, w, h), radius(r), startAngle(0.0f) {\n    }\n\n    void updateLayout() override {\n        int count = elements.size();\n        float angleStep = 360.0f / count;\n\n        for (size_t i = 0; i < elements.size(); i++) {\n            float angle = startAngle + (i * angleStep);\n            float rad = angle * M_PI / 180.0f;\n\n            float elementX = x + (radius * cos(rad)) - (elements[i]->width / 2);\n            float elementY = y + (radius * sin(rad)) - (elements[i]->height / 2);\n\n            elements[i]->x = elementX;\n            elements[i]->y = elementY;\n        }\n    }\n\n    void handleInput(const pixelroot32::input::InputManager& input) override {\n        // Implement circular navigation\n        // ...\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#custom-collision-primitives","title":"Custom Collision Primitives","text":"

Extend collision system with new shapes:

// Add to your game code (not engine modification)\nstruct Triangle {\n    float x1, y1, x2, y2, x3, y3;\n};\n\nbool intersects(const Triangle& tri, const pixelroot32::core::Rect& rect) {\n    // Implement triangle-rectangle intersection\n    // ...\n    return false;\n}\n\nbool intersects(const Triangle& tri1, const Triangle& tri2) {\n    // Implement triangle-triangle intersection\n    // ...\n    return false;\n}\n
"},{"location":"manual/optimization/extensibility/#best-practices","title":"Best Practices","text":""},{"location":"manual/optimization/extensibility/#maintain-compatibility","title":"Maintain Compatibility","text":"
  • Don't break existing APIs: Extend, don't modify
  • Use inheritance: Inherit from base classes
  • Follow patterns: Match existing code patterns
  • Document extensions: Comment your custom code
"},{"location":"manual/optimization/extensibility/#testing","title":"Testing","text":"
  • Test on both platforms: ESP32 and Native
  • Test edge cases: Boundary conditions, null pointers
  • Performance testing: Ensure extensions don't hurt performance
  • Memory testing: Check for leaks with custom code
"},{"location":"manual/optimization/extensibility/#documentation","title":"Documentation","text":"
  • Comment your code: Explain why, not just what
  • Provide examples: Show how to use your extensions
  • Document limitations: State what doesn't work
  • Version compatibility: Note which engine version
"},{"location":"manual/optimization/extensibility/#common-extension-patterns","title":"Common Extension Patterns","text":""},{"location":"manual/optimization/extensibility/#factory-pattern","title":"Factory Pattern","text":"
class EntityFactory {\npublic:\n    static pixelroot32::core::Entity* createEnemy(EnemyType type, float x, float y) {\n        switch (type) {\n            case EnemyType::BASIC:\n                return new BasicEnemy(x, y);\n            case EnemyType::FAST:\n                return new FastEnemy(x, y);\n            case EnemyType::TANK:\n                return new TankEnemy(x, y);\n            default:\n                return nullptr;\n        }\n    }\n\n    static pixelroot32::core::Entity* createPowerUp(PowerUpType type, float x, float y) {\n        return new PowerUpActor(x, y, type);\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#strategy-pattern","title":"Strategy Pattern","text":"
class MovementStrategy {\npublic:\n    virtual void update(pixelroot32::core::Actor* actor, unsigned long deltaTime) = 0;\n};\n\nclass LinearMovement : public MovementStrategy {\npublic:\n    void update(pixelroot32::core::Actor* actor, unsigned long deltaTime) override {\n        actor->x += speed * (deltaTime * 0.001f);\n    }\n};\n\nclass CircularMovement : public MovementStrategy {\npublic:\n    void update(pixelroot32::core::Actor* actor, unsigned long deltaTime) override {\n        float angle = millis() * 0.001f;\n        actor->x = centerX + radius * cos(angle);\n        actor->y = centerY + radius * sin(angle);\n    }\n};\n\nclass SmartEnemy : public pixelroot32::core::Actor {\nprivate:\n    MovementStrategy* movement;\n\npublic:\n    void setMovement(MovementStrategy* strat) {\n        movement = strat;\n    }\n\n    void update(unsigned long deltaTime) override {\n        if (movement) {\n            movement->update(this, deltaTime);\n        }\n    }\n};\n
"},{"location":"manual/optimization/extensibility/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/extensibility/#driver-not-working","title":"Driver Not Working","text":"
  • Verify all interface methods are implemented
  • Check initialization order
  • Test with simple drawing first
  • Verify hardware connections
"},{"location":"manual/optimization/extensibility/#audio-backend-issues","title":"Audio Backend Issues","text":"
  • Check sample rate matches hardware
  • Verify audio generation logic
  • Test with simple tones first
  • Check channel management
"},{"location":"manual/optimization/extensibility/#extension-conflicts","title":"Extension Conflicts","text":"
  • Ensure namespace isolation
  • Avoid modifying engine code directly
  • Use composition over modification
  • Test with engine updates
"},{"location":"manual/optimization/extensibility/#next-steps","title":"Next Steps","text":"

Now that you understand extensibility, you've completed the optimization section. Continue with: - API Reference - Complete API documentation - Examples - Code examples - Resources - Tools and troubleshooting

See also: - API Reference - DrawSurface - API Reference - AudioBackend - Manual - Platforms and Drivers

"},{"location":"manual/optimization/memory_management/","title":"Memory Management","text":"

ESP32 has limited memory, so efficient memory management is crucial for PixelRoot32 games. This guide covers memory constraints, object pooling, and best practices.

"},{"location":"manual/optimization/memory_management/#esp32-memory-constraints","title":"ESP32 Memory Constraints","text":""},{"location":"manual/optimization/memory_management/#available-memory","title":"Available Memory","text":"

ESP32 typically has: - RAM: ~320KB total (varies by model) - Flash: 4MB+ (for program storage) - Heap: Limited and fragmented over time

"},{"location":"manual/optimization/memory_management/#real-world-limits","title":"Real-World Limits","text":"
  • MAX_ENTITIES: 32 per scene (hard limit)
  • Sprite data: Stored in flash (const/constexpr)
  • Dynamic allocation: Should be avoided in game loop
  • Stack: Limited (~8KB), avoid large stack allocations
"},{"location":"manual/optimization/memory_management/#object-pooling","title":"Object Pooling","text":"

Object pooling reuses objects instead of creating/destroying them, avoiding memory fragmentation.

"},{"location":"manual/optimization/memory_management/#basic-pool-pattern","title":"Basic Pool Pattern","text":"
class ProjectilePool {\nprivate:\n    static const int POOL_SIZE = 10;\n    ProjectileActor pool[POOL_SIZE];\n    bool inUse[POOL_SIZE];\n\npublic:\n    ProjectilePool() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            inUse[i] = false;\n        }\n    }\n\n    ProjectileActor* getAvailable() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!inUse[i]) {\n                inUse[i] = true;\n                return &pool[i];\n            }\n        }\n        return nullptr; // Pool exhausted\n    }\n\n    void release(ProjectileActor* projectile) {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (&pool[i] == projectile) {\n                inUse[i] = false;\n                projectile->isEnabled = false;\n                projectile->isVisible = false;\n                break;\n            }\n        }\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#using-object-pools","title":"Using Object Pools","text":"
class GameScene : public pixelroot32::core::Scene {\nprivate:\n    ProjectilePool projectilePool;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n\n        // Fire projectile\n        if (input.isButtonPressed(Buttons::A)) {\n            ProjectileActor* proj = projectilePool.getAvailable();\n            if (proj) {\n                proj->x = player->x;\n                proj->y = player->y;\n                proj->isEnabled = true;\n                proj->isVisible = true;\n                // ... initialize projectile\n            }\n        }\n\n        // Clean up projectiles that hit target\n        for (auto* entity : entities) {\n            if (auto* proj = dynamic_cast<ProjectileActor*>(entity)) {\n                if (proj->hitTarget) {\n                    projectilePool.release(proj);\n                }\n            }\n        }\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#complete-example-entity-pool","title":"Complete Example: Entity Pool","text":"
template<typename T, int POOL_SIZE>\nclass EntityPool {\nprivate:\n    T pool[POOL_SIZE];\n    bool inUse[POOL_SIZE];\n    int activeCount = 0;\n\npublic:\n    EntityPool() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            inUse[i] = false;\n        }\n    }\n\n    T* acquire() {\n        if (activeCount >= POOL_SIZE) {\n            return nullptr; // Pool full\n        }\n\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!inUse[i]) {\n                inUse[i] = true;\n                activeCount++;\n                return &pool[i];\n            }\n        }\n        return nullptr;\n    }\n\n    void release(T* obj) {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (&pool[i] == obj) {\n                inUse[i] = false;\n                activeCount--;\n                obj->isEnabled = false;\n                obj->isVisible = false;\n                break;\n            }\n        }\n    }\n\n    int getActiveCount() const { return activeCount; }\n    int getAvailableCount() const { return POOL_SIZE - activeCount; }\n};\n\n// Usage\nEntityPool<EnemyActor, 8> enemyPool;\nEntityPool<ParticleEmitter, 5> particlePool;\n
"},{"location":"manual/optimization/memory_management/#scene-arena-experimental","title":"Scene Arena (Experimental)","text":"

Scene Arena provides a memory arena for scene-specific allocations, reducing fragmentation.

"},{"location":"manual/optimization/memory_management/#what-is-scene-arena","title":"What is Scene Arena?","text":"

Scene Arena is a contiguous memory block pre-allocated for a scene. All scene entities are allocated from this arena instead of the heap.

"},{"location":"manual/optimization/memory_management/#when-to-use","title":"When to Use","text":"
  • Large scenes: Scenes with many entities
  • Frequent allocation: Scenes that create/destroy entities often
  • Memory fragmentation: When heap fragmentation is a problem
  • Performance: When you need predictable allocation performance
"},{"location":"manual/optimization/memory_management/#configuration","title":"Configuration","text":"
#ifdef PIXELROOT32_ENABLE_SCENE_ARENA\n#include <core/Scene.h>\n\n// Define arena buffer (typically in scene header)\nstatic unsigned char MY_SCENE_ARENA_BUFFER[8192]; // 8KB arena\n\nclass MyScene : public pixelroot32::core::Scene {\npublic:\n    void init() override {\n        // Initialize arena\n        arena.init(MY_SCENE_ARENA_BUFFER, sizeof(MY_SCENE_ARENA_BUFFER));\n\n        // Now entities allocated with arena will use this memory\n        // (Requires custom allocation functions)\n    }\n};\n#endif\n
"},{"location":"manual/optimization/memory_management/#limitations","title":"Limitations","text":"
  • Experimental: May have bugs or limitations
  • Fixed size: Arena size must be determined at compile time
  • No reallocation: Can't resize arena at runtime
  • Manual management: Requires careful memory management

Note: Scene Arena is an experimental feature. Use object pooling for most cases.

"},{"location":"manual/optimization/memory_management/#best-practices","title":"Best Practices","text":""},{"location":"manual/optimization/memory_management/#avoid-dynamic-allocation-in-game-loop","title":"Avoid Dynamic Allocation in Game Loop","text":"
// \u274c BAD: Allocates every frame\nvoid update(unsigned long deltaTime) override {\n    if (shouldSpawnEnemy) {\n        EnemyActor* enemy = new EnemyActor(x, y);\n        addEntity(enemy);\n    }\n}\n\n// \u2705 GOOD: Use pool\nvoid update(unsigned long deltaTime) override {\n    if (shouldSpawnEnemy) {\n        EnemyActor* enemy = enemyPool.getAvailable();\n        if (enemy) {\n            enemy->reset(x, y);\n            enemy->isEnabled = true;\n        }\n    }\n}\n
"},{"location":"manual/optimization/memory_management/#pre-allocate-resources","title":"Pre-allocate Resources","text":"
class GameScene : public pixelroot32::core::Scene {\nprivate:\n    // Pre-allocated pools\n    ProjectilePool projectiles;\n    EnemyPool enemies;\n    ParticlePool particles;\n\npublic:\n    void init() override {\n        // All pools created in constructor\n        // No allocation in init() or update()\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#reuse-objects","title":"Reuse Objects","text":"
class EnemyActor : public pixelroot32::core::Actor {\npublic:\n    void reset(float x, float y) {\n        this->x = x;\n        this->y = y;\n        this->isEnabled = true;\n        this->isVisible = true;\n        this->health = maxHealth;\n        // Reset all state\n    }\n\n    void deactivate() {\n        isEnabled = false;\n        isVisible = false;\n    }\n};\n\n// Usage\nEnemyActor* enemy = enemyPool.getAvailable();\nif (enemy) {\n    enemy->reset(spawnX, spawnY);\n    addEntity(enemy);\n}\n
"},{"location":"manual/optimization/memory_management/#avoid-strings-and-dynamic-memory","title":"Avoid Strings and Dynamic Memory","text":"
// \u274c BAD: String allocation\nvoid draw(Renderer& renderer) override {\n    std::string scoreText = \"Score: \" + std::to_string(score);\n    renderer.drawText(scoreText.c_str(), 10, 10, Color::White, 1);\n}\n\n// \u2705 GOOD: Static buffer\nvoid draw(Renderer& renderer) override {\n    char scoreBuffer[32];\n    snprintf(scoreBuffer, sizeof(scoreBuffer), \"Score: %d\", score);\n    renderer.drawText(scoreBuffer, 10, 10, Color::White, 1);\n}\n
"},{"location":"manual/optimization/memory_management/#store-data-in-flash","title":"Store Data in Flash","text":"
// \u2705 GOOD: Stored in flash (const/constexpr)\nstatic const uint16_t SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    // ...\n};\n\n// \u274c BAD: Stored in RAM\nuint16_t spriteData[] = {\n    0b00111100,\n    0b01111110,\n    // ...\n};\n
"},{"location":"manual/optimization/memory_management/#memory-monitoring","title":"Memory Monitoring","text":""},{"location":"manual/optimization/memory_management/#check-available-memory","title":"Check Available Memory","text":"
#ifdef PLATFORM_ESP32\n#include <Arduino.h>\n\nvoid checkMemory() {\n    Serial.print(\"Free heap: \");\n    Serial.println(ESP.getFreeHeap());\n    Serial.print(\"Largest free block: \");\n    Serial.println(ESP.getMaxAllocHeap());\n}\n#endif\n
"},{"location":"manual/optimization/memory_management/#monitor-entity-count","title":"Monitor Entity Count","text":"
void update(unsigned long deltaTime) override {\n    Scene::update(deltaTime);\n\n    // Check entity count\n    int entityCount = getEntityCount();\n    if (entityCount >= MAX_ENTITIES) {\n        Serial.println(\"WARNING: Entity limit reached!\");\n    }\n}\n
"},{"location":"manual/optimization/memory_management/#common-patterns","title":"Common Patterns","text":""},{"location":"manual/optimization/memory_management/#entity-lifecycle-management","title":"Entity Lifecycle Management","text":"
class ManagedEntity {\nprivate:\n    bool isActive = false;\n\npublic:\n    void activate(float x, float y) {\n        this->x = x;\n        this->y = y;\n        isActive = true;\n        isEnabled = true;\n        isVisible = true;\n    }\n\n    void deactivate() {\n        isActive = false;\n        isEnabled = false;\n        isVisible = false;\n    }\n\n    bool getIsActive() const { return isActive; }\n};\n\n// Pool manages lifecycle\nclass EntityManager {\nprivate:\n    EntityPool<ManagedEntity, 20> pool;\n\npublic:\n    ManagedEntity* spawn(float x, float y) {\n        auto* entity = pool.acquire();\n        if (entity) {\n            entity->activate(x, y);\n        }\n        return entity;\n    }\n\n    void despawn(ManagedEntity* entity) {\n        if (entity) {\n            entity->deactivate();\n            pool.release(entity);\n        }\n    }\n};\n
"},{"location":"manual/optimization/memory_management/#memory-efficient-collections","title":"Memory-Efficient Collections","text":"
// Fixed-size array instead of vector\nclass EntityArray {\nprivate:\n    static const int MAX_SIZE = 32;\n    pixelroot32::core::Entity* entities[MAX_SIZE];\n    int count = 0;\n\npublic:\n    bool add(pixelroot32::core::Entity* entity) {\n        if (count >= MAX_SIZE) return false;\n        entities[count++] = entity;\n        return true;\n    }\n\n    void remove(pixelroot32::core::Entity* entity) {\n        for (int i = 0; i < count; i++) {\n            if (entities[i] == entity) {\n                entities[i] = entities[--count];\n                break;\n            }\n        }\n    }\n\n    int size() const { return count; }\n    pixelroot32::core::Entity* operator[](int index) { return entities[index]; }\n};\n
"},{"location":"manual/optimization/memory_management/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/memory_management/#out-of-memory-errors","title":"Out of Memory Errors","text":"
  • Reduce pool sizes
  • Use fewer entities
  • Store more data in flash
  • Avoid dynamic allocation
  • Check for memory leaks
"},{"location":"manual/optimization/memory_management/#entity-limit-reached","title":"Entity Limit Reached","text":"
  • MAX_ENTITIES = 32 is a hard limit
  • Use object pooling to reuse entities
  • Deactivate entities instead of removing
  • Combine multiple entities into one
"},{"location":"manual/optimization/memory_management/#memory-fragmentation","title":"Memory Fragmentation","text":"
  • Use object pooling
  • Pre-allocate all resources
  • Avoid frequent new/delete
  • Consider Scene Arena (experimental)
"},{"location":"manual/optimization/memory_management/#next-steps","title":"Next Steps","text":"

Now that you understand memory management, learn about: - Performance Optimization - Improve game performance - Platforms and Drivers - Understand platform specifics - Extensibility - Extend the engine

See also: - API Reference - Scene - Manual - Scenes and Entities

"},{"location":"manual/optimization/performance_tuning/","title":"Performance Optimization","text":"

This guide covers techniques to improve game performance on ESP32, including rendering optimization, logic optimization, and profiling.

"},{"location":"manual/optimization/performance_tuning/#esp32-performance-characteristics","title":"ESP32 Performance Characteristics","text":""},{"location":"manual/optimization/performance_tuning/#cpu-limitations","title":"CPU Limitations","text":"
  • Dual-core: 240MHz (typically)
  • Single-threaded game loop: One core handles everything
  • Target FPS: 30-60 FPS (depends on game complexity)
  • Frame budget: ~16-33ms per frame at 60 FPS
"},{"location":"manual/optimization/performance_tuning/#common-bottlenecks","title":"Common Bottlenecks","text":"
  1. Rendering: Too many draw calls
  2. Collision detection: Too many collision checks
  3. Memory allocation: Dynamic allocation in game loop
  4. Complex calculations: Expensive math operations
  5. String operations: String concatenation/formatting
"},{"location":"manual/optimization/performance_tuning/#tecnicas-de-optimizacion","title":"T\u00e9cnicas de Optimizaci\u00f3n","text":"

El motor utiliza varias t\u00e9cnicas para maximizar los FPS, especialmente en hardware limitado como el ESP32.

"},{"location":"manual/optimization/performance_tuning/#1-independent-resolution-scaling-escalado-de-resolucion","title":"1. Independent Resolution Scaling (Escalado de Resoluci\u00f3n)","text":"

Esta es probablemente la optimizaci\u00f3n m\u00e1s impactante para el ESP32. Permite renderizar el juego a una resoluci\u00f3n l\u00f3gica menor (ej: 128x128) y reescalarla autom\u00e1ticamente a la resoluci\u00f3n f\u00edsica de la pantalla (ej: 240x240).

  • Reducci\u00f3n de Memoria: Un buffer de 128x128 (8bpp) consume solo 16KB, comparado con los 57KB de uno de 240x240.
  • Aumento de FPS: Al haber menos p\u00edxeles que procesar por cada primitiva o sprite, el rendimiento puede duplicarse.
  • Implementaci\u00f3n: Se realiza mediante Hardware-accelerated Nearest Neighbor durante la transferencia DMA.

Consulta la gu\u00eda completa de Resolution Scaling para aprender a configurarlo.

"},{"location":"manual/optimization/performance_tuning/#2-viewport-culling-recorte-de-camara","title":"2. Viewport Culling (Recorte de C\u00e1mara)","text":"

No proceses objetos que est\u00e1n fuera de la pantalla. El motor lo hace autom\u00e1ticamente en drawTileMap, pero debes implementarlo en tu l\u00f3gica de actualizaci\u00f3n:

bool isOnScreen(float x, float y, int width, int height, \n                const Camera2D& camera) {\n    float cameraX = camera.getX();\n    float cameraY = camera.getY();\n    int screenWidth = engine.getRenderer().getLogicalWidth();\n    int screenHeight = engine.getRenderer().getLogicalHeight();\n\n    return !(x + width < cameraX || \n             x > cameraX + screenWidth ||\n             y + height < cameraY || \n             y > cameraY + screenHeight);\n}\n
"},{"location":"manual/optimization/performance_tuning/#2-optimizacion-de-memoria-y-cpu-esp32","title":"2. Optimizaci\u00f3n de Memoria y CPU (ESP32)","text":"

Para la plataforma ESP32, se han implementado optimizaciones de bajo nivel cr\u00edticas:

  • IRAM_ATTR: Las funciones cr\u00edticas de renderizado (drawSprite, drawTileMap, etc.) est\u00e1n marcadas para ejecutarse desde la RAM interna (IRAM), eliminando la latencia de lectura de la Flash SPI.
  • DMA (Direct Memory Access): El volcado del buffer a la pantalla TFT se realiza mediante DMA, lo que permite que la CPU comience a procesar el siguiente frame mientras el hardware transfiere los datos.
  • Acceso a Datos de 16 bits: Los sprites de 2bpp y 4bpp utilizan punteros uint16_t* para garantizar accesos alineados a memoria, lo cual es significativamente m\u00e1s r\u00e1pido en la arquitectura Xtensa del ESP32.
"},{"location":"manual/optimization/performance_tuning/#3-optimizacion-de-tilemaps","title":"3. Optimizaci\u00f3n de TileMaps","text":"

El renderizado de mapas de tiles es una de las operaciones m\u00e1s costosas. PixelRoot32 utiliza:

  • Cach\u00e9 de Paleta: Durante el dibujado de un tilemap, se genera una tabla de b\u00fasqueda (LUT) temporal para evitar c\u00e1lculos de color redundantes por cada p\u00edxel.
  • Dibujado por Columnas: Optimizado para minimizar los saltos de memoria en el framebuffer.
"},{"location":"manual/optimization/performance_tuning/#4-colisiones-eficientes","title":"4. Colisiones Eficientes","text":"

Usa colisiones basadas en tiles siempre que sea posible. Acceder a un array de tiles es O(1), mientras que iterar sobre una lista de entidades es O(n).

// Ejemplo de colisi\u00f3n r\u00e1pida con el mapa\nint tileX = x / 8;\nint tileY = y / 8;\nif (levelMap.data[tileY * levelMap.width + tileX] != 0) {\n    // Colisi\u00f3n detectada\n}\n
"},{"location":"manual/optimization/performance_tuning/#recomendaciones-generales","title":"Recomendaciones Generales","text":"
  • Sprites Indexados: Prefiere Sprite2bpp (4 colores) o Sprite4bpp (16 colores) sobre Sprite (1bpp) si necesitas color, ya que est\u00e1n altamente optimizados.
  • Evitar std::string en el Loop: Las concatenaciones de strings generan fragmentaci\u00f3n de memoria. Usa buffers est\u00e1ticos o char[] para textos din\u00e1micos.
  • Perfilado: Activa el overlay de estad\u00edsticas de depuraci\u00f3n compilando con PIXELROOT32_ENABLE_DEBUG_OVERLAY (ver Engine - Debug Overlay) para monitorear FPS, RAM y carga de CPU en tiempo real.
"},{"location":"manual/optimization/performance_tuning/#common-optimization-patterns","title":"Common Optimization Patterns","text":""},{"location":"manual/optimization/performance_tuning/#update-frequency-reduction","title":"Update Frequency Reduction","text":"
class LowFrequencyUpdater {\nprivate:\n    unsigned long timer = 0;\n    unsigned long interval = 100; // Update every 100ms\n\npublic:\n    void update(unsigned long deltaTime) {\n        timer += deltaTime;\n        if (timer >= interval) {\n            timer -= interval;\n            // Do expensive update\n            expensiveUpdate();\n        }\n    }\n};\n
"},{"location":"manual/optimization/performance_tuning/#spatial-partitioning-simple","title":"Spatial Partitioning (Simple)","text":"
// Divide screen into zones\nclass SpatialGrid {\nprivate:\n    static const int GRID_SIZE = 4;\n    static const int CELL_WIDTH = 60;\n    static const int CELL_HEIGHT = 60;\n\n    std::vector<Actor*> grid[GRID_SIZE][GRID_SIZE];\n\npublic:\n    void add(Actor* actor) {\n        int cellX = static_cast<int>(actor->x) / CELL_WIDTH;\n        int cellY = static_cast<int>(actor->y) / CELL_HEIGHT;\n        if (cellX >= 0 && cellX < GRID_SIZE && \n            cellY >= 0 && cellY < GRID_SIZE) {\n            grid[cellY][cellX].push_back(actor);\n        }\n    }\n\n    void checkCollisions() {\n        // Only check collisions within same cell\n        for (int y = 0; y < GRID_SIZE; y++) {\n            for (int x = 0; x < GRID_SIZE; x++) {\n                auto& cell = grid[y][x];\n                for (size_t i = 0; i < cell.size(); i++) {\n                    for (size_t j = i + 1; j < cell.size(); j++) {\n                        checkCollision(cell[i], cell[j]);\n                    }\n                }\n            }\n        }\n    }\n};\n
"},{"location":"manual/optimization/performance_tuning/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/performance_tuning/#low-fps","title":"Low FPS","text":"
  • Profile to find bottlenecks
  • Reduce entity count
  • Optimize rendering (culling, batching)
  • Simplify collision detection
  • Reduce update frequency
"},{"location":"manual/optimization/performance_tuning/#frame-drops","title":"Frame Drops","text":"
  • Check for expensive operations in update()
  • Avoid dynamic allocation
  • Cache calculations
  • Reduce draw calls
"},{"location":"manual/optimization/performance_tuning/#stuttering","title":"Stuttering","text":"
  • Ensure frame-rate independence (use deltaTime)
  • Avoid blocking operations
  • Pre-load resources
  • Use object pooling
"},{"location":"manual/optimization/performance_tuning/#next-steps","title":"Next Steps","text":"

Now that you understand performance optimization, learn about: - Memory Management - Manage memory efficiently - Platforms and Drivers - Platform-specific optimizations - Extensibility - Extend the engine

See also: - Manual - Basic Rendering - Manual - Physics and Collisions

"},{"location":"manual/optimization/platforms_and_drivers/","title":"Platforms and Drivers","text":"

PixelRoot32 supports multiple platforms through driver abstraction. This guide covers supported platforms, display drivers, audio backends, and build configuration.

"},{"location":"manual/optimization/platforms_and_drivers/#supported-platforms","title":"Supported Platforms","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32","title":"ESP32","text":"

Primary platform for PixelRoot32 games.

Characteristics: - TFT_eSPI display driver - Internal DAC or I2S audio - GPIO button input - Limited RAM/Flash - Real hardware constraints

Use for: - Final game deployment - Hardware testing - Production builds

"},{"location":"manual/optimization/platforms_and_drivers/#nativedesktop-sdl2","title":"Native/Desktop (SDL2)","text":"

Development platform for rapid iteration.

Characteristics: - SDL2 display driver - SDL2 audio backend - Keyboard input - Unlimited resources (for testing) - Fast development cycle

Use for: - Development and debugging - Testing without hardware - Rapid prototyping - CI/CD testing

"},{"location":"manual/optimization/platforms_and_drivers/#display-drivers","title":"Display Drivers","text":""},{"location":"manual/optimization/platforms_and_drivers/#tft_espi-esp32","title":"TFT_eSPI (ESP32)","text":"

TFT_eSPI is the display driver for ESP32, supporting many TFT displays.

"},{"location":"manual/optimization/platforms_and_drivers/#optimizaciones-esp32","title":"Optimizaciones ESP32","text":"

Para maximizar el rendimiento en ESP32, PixelRoot32 utiliza:

  • DMA (Direct Memory Access): Las transferencias al display se realizan en segundo plano, permitiendo que la CPU prepare el siguiente frame mientras se env\u00eda el actual.
  • Independent Resolution Scaling: El driver soporta resoluciones l\u00f3gicas menores que las f\u00edsicas, realizando el escalado Nearest-Neighbor on-the-fly durante la transferencia DMA para ahorrar RAM y ganar FPS.
  • Doble Buffer con IRAM: El motor utiliza un buffer de pantalla (Sprite de TFT_eSPI) optimizado para transferencias r\u00e1pidas.
  • Alineaci\u00f3n de 16 bits: Los datos de sprites 2bpp/4bpp est\u00e1n alineados a palabras de 16 bits para aprovechar la arquitectura Xtensa.
  • IRAM_ATTR: Las funciones cr\u00edticas de renderizado est\u00e1n marcadas para residir en la RAM de instrucciones, evitando cuellos de botella por acceso a la Flash.
"},{"location":"manual/optimization/platforms_and_drivers/#configuracion-dma","title":"Configuraci\u00f3n DMA","text":"

El DMA se activa autom\u00e1ticamente si el hardware lo soporta. Aseg\u00farate de configurar la frecuencia SPI adecuada para tu display (usualmente 40MHz u 80MHz).

[env:esp32dev]\nbuild_flags = \n    -D ST7789_DRIVER          # Display type\n    -D TFT_WIDTH=240          # Display width\n    -D TFT_HEIGHT=240         # Display height\n    -D TFT_MOSI=23            # SPI MOSI pin\n    -D TFT_SCLK=18            # SPI clock pin\n    -D TFT_DC=2               # Data/Command pin\n    -D TFT_RST=4              # Reset pin\n    -D TFT_CS=-1              # Chip select (-1 if not used)\n    -D SPI_FREQUENCY=40000000 # SPI frequency\n
"},{"location":"manual/optimization/platforms_and_drivers/#supported-displays","title":"Supported Displays","text":"
  • ST7735: 128x128, 128x160
  • ST7789: 240x240, 240x320
  • ILI9341: 240x320
  • And more: See TFT_eSPI documentation
"},{"location":"manual/optimization/platforms_and_drivers/#usage","title":"Usage","text":"
#include <drivers/esp32/TFT_eSPI_Drawer.h>\n\n// Display configuration\n// 128x128 logic scaled to 240x240 hardware\npixelroot32::graphics::DisplayConfig displayConfig(\n    pixelroot32::graphics::DisplayType::ST7789,\n    0,      // rotation\n    240, 240, // physical width, height\n    128, 128  // logical width, height\n);\n\n// TFT_eSPI_Drawer is created automatically by Engine\n// No manual driver creation needed\n
"},{"location":"manual/optimization/platforms_and_drivers/#sdl2_drawer-native","title":"SDL2_Drawer (Native)","text":"

SDL2_Drawer provides display output for PC/desktop development.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration","title":"Configuration","text":"
#include <drivers/native/SDL2_Drawer.h>\n\n// Display configuration (NONE defaults to SDL2)\npixelroot32::graphics::DisplayConfig displayConfig(\n    pixelroot32::graphics::DisplayType::NONE,\n    0,      // rotation\n    240,    // width\n    240     // height\n);\n\n// SDL2_Drawer is created automatically\n
"},{"location":"manual/optimization/platforms_and_drivers/#sdl2-installation","title":"SDL2 Installation","text":"

Windows (MSYS2):

pacman -S mingw-w64-x86_64-SDL2\n

Linux:

sudo apt-get install libsdl2-dev\n

macOS:

brew install sdl2\n

"},{"location":"manual/optimization/platforms_and_drivers/#audio-backends","title":"Audio Backends","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32_dac_audiobackend","title":"ESP32_DAC_AudioBackend","text":"

Uses ESP32's internal DAC for audio output.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration_1","title":"Configuration","text":"
#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nconst int DAC_PIN = 25; // GPIO 25 or 26\npixelroot32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(\n    DAC_PIN,    // DAC pin (25 or 26)\n    11025       // Sample rate (Hz)\n);\n\npixelroot32::audio::AudioConfig audioConfig(\n    &audioBackend, \n    audioBackend.getSampleRate()\n);\n

Characteristics: - Simple setup (just one pin) - Lower quality than I2S - Good for basic audio - Sample rate: 11025 Hz recommended

"},{"location":"manual/optimization/platforms_and_drivers/#esp32_i2s_audiobackend","title":"ESP32_I2S_AudioBackend","text":"

Uses ESP32's I2S peripheral for higher quality audio.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration_2","title":"Configuration","text":"
#include <drivers/esp32/ESP32_I2S_AudioBackend.h>\n\nconst int I2S_BCLK = 26;  // Bit clock pin\nconst int I2S_LRCK = 25;  // Left/Right clock pin\nconst int I2S_DOUT = 22;  // Data out pin\n\npixelroot32::drivers::esp32::ESP32_I2S_AudioBackend audioBackend(\n    I2S_BCLK,\n    I2S_LRCK,\n    I2S_DOUT,\n    22050  // Sample rate (Hz)\n);\n\npixelroot32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n

Characteristics: - Higher quality than DAC - Requires external I2S DAC (e.g., MAX98357A) - Better for music - Sample rate: 22050 Hz recommended

"},{"location":"manual/optimization/platforms_and_drivers/#sdl2_audiobackend-native","title":"SDL2_AudioBackend (Native)","text":"

SDL2 audio for PC development.

"},{"location":"manual/optimization/platforms_and_drivers/#configuration_3","title":"Configuration","text":"
#include <drivers/native/SDL2_AudioBackend.h>\n\npixelroot32::drivers::native::SDL2_AudioBackend audioBackend(\n    22050,  // Sample rate\n    1024    // Buffer size\n);\n\npixelroot32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n
"},{"location":"manual/optimization/platforms_and_drivers/#build-flags","title":"Build Flags","text":""},{"location":"manual/optimization/platforms_and_drivers/#experimental-features","title":"Experimental Features","text":"

Enable experimental features with build flags:

[env:esp32dev]\nbuild_flags = \n    -D PIXELROOT32_ENABLE_2BPP_SPRITES    # Enable 2bpp sprite format\n    - D PIXELROOT32_ENABLE_4BPP_SPRITES   # Enable 4bpp sprite format\n    - D PIXELROOT32_ENABLE_SCENE_ARENA    # Enable Scene Arena (experimental)\n    - D PIXELROOT32_ENABLE_DEBUG_OVERLAY  # On-screen debug statistics (FPS, RAM, CPU load; throttled update)\n
"},{"location":"manual/optimization/platforms_and_drivers/#debug-statistics-overlay-pixelroot32_enable_debug_overlay","title":"Debug Statistics Overlay (PIXELROOT32_ENABLE_DEBUG_OVERLAY)","text":"

When defined, the engine draws a technical overlay (FPS, RAM, CPU load) in the top-right area of the screen each frame. Values are updated every 16 frames to maintain performance. No code changes are required. See API Reference - Engine - Optional: Debug Overlay for details.

"},{"location":"manual/optimization/platforms_and_drivers/#scene-limits-max_layers-max_entities","title":"Scene limits (MAX_LAYERS / MAX_ENTITIES)","text":"

You can override the default scene limits from your project without modifying the engine. The default of 3 for MAX_LAYERS is due to ESP32 platform constraints (memory and draw-loop cost); on native/PC you can use a higher value.

Option A: Compiler flags (recommended) \u2014 in platformio.ini, add to build_flags for your environment:

build_flags =\n    -DMAX_LAYERS=5\n    -DMAX_ENTITIES=64\n

The compiler defines these before any .cpp is processed. Because Scene.h uses #ifndef MAX_LAYERS / #ifndef MAX_ENTITIES, your values are used (more render layers drawn in Scene::draw, and on Arduino the entity queue capacity when built with MAX_ENTITIES).

See API Reference - Scene - Overriding scene limits for details.

"},{"location":"manual/optimization/platforms_and_drivers/#platform-detection","title":"Platform Detection","text":"
#ifdef PLATFORM_ESP32\n    // ESP32-specific code\n    Serial.println(\"Running on ESP32\");\n#endif\n\n#ifdef PLATFORM_NATIVE\n    // Native/PC-specific code\n    printf(\"Running on PC\\n\");\n#endif\n
"},{"location":"manual/optimization/platforms_and_drivers/#optimization-flags","title":"Optimization Flags","text":"
[env:esp32dev]\nbuild_flags = \n    -O2              # Optimization level\n    -ffunction-sections\n    -fdata-sections\n    -Wl,--gc-sections\n
"},{"location":"manual/optimization/platforms_and_drivers/#complete-platform-setup-examples","title":"Complete Platform Setup Examples","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32-complete-setup","title":"ESP32 Complete Setup","text":"
#include <Arduino.h>\n#include <core/Engine.h>\n#include <drivers/esp32/TFT_eSPI_Drawer.h>\n#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\n// Audio\nconst int DAC_PIN = 25;\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\n// Display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::ST7789,\n    0, 240, 240\n);\n\n// Input\npr32::input::InputConfig inputConfig(\n    6, 32, 27, 33, 14, 13, 12  // 6 buttons, pins\n);\n\n// Audio config\npr32::audio::AudioConfig audioConfig(&audioBackend, 11025);\n\n// Engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nvoid setup() {\n    Serial.begin(115200);\n    engine.init();\n    // ... scene setup\n}\n\nvoid loop() {\n    engine.run();\n}\n
"},{"location":"manual/optimization/platforms_and_drivers/#native-complete-setup","title":"Native Complete Setup","text":"
#define SDL_MAIN_HANDLED\n#include <SDL2/SDL.h>\n#include <core/Engine.h>\n#include <drivers/native/SDL2_Drawer.h>\n#include <drivers/native/SDL2_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\n// Audio\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\n\n// Display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::NONE,\n    0, 240, 240\n);\n\n// Input (SDL scancodes)\npr32::input::InputConfig inputConfig(\n    6,\n    SDL_SCANCODE_UP,\n    SDL_SCANCODE_DOWN,\n    SDL_SCANCODE_LEFT,\n    SDL_SCANCODE_RIGHT,\n    SDL_SCANCODE_SPACE,\n    SDL_SCANCODE_RETURN\n);\n\n// Audio config\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n\n// Engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nint main(int argc, char* argv[]) {\n    engine.init();\n    // ... scene setup\n    engine.run();\n    return 0;\n}\n
"},{"location":"manual/optimization/platforms_and_drivers/#platform-specific-considerations","title":"Platform-Specific Considerations","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32_1","title":"ESP32","text":"

Memory: - Limited RAM (~320KB) - Use object pooling - Store data in flash - Avoid dynamic allocation

Performance: - Target 30-60 FPS - Optimize rendering - Reduce entity count - Profile on hardware

Hardware: - GPIO pin configuration - SPI display setup - Audio hardware connections - Power considerations

"},{"location":"manual/optimization/platforms_and_drivers/#native","title":"Native","text":"

Development: - Fast iteration - Easy debugging - Unlimited resources - Visual debugging tools

Testing: - Test logic without hardware - Rapid prototyping - CI/CD integration - Cross-platform testing

"},{"location":"manual/optimization/platforms_and_drivers/#troubleshooting","title":"Troubleshooting","text":""},{"location":"manual/optimization/platforms_and_drivers/#esp32-display-issues","title":"ESP32 Display Issues","text":"
  • Check wiring connections
  • Verify pin numbers
  • Lower SPI frequency
  • Check display type matches
  • Verify power supply
"},{"location":"manual/optimization/platforms_and_drivers/#esp32-audio-issues","title":"ESP32 Audio Issues","text":"
  • Check DAC/I2S pin configuration
  • Verify sample rate
  • Check hardware connections
  • Lower volume if distorted
  • Test with different sample rates
"},{"location":"manual/optimization/platforms_and_drivers/#native-build-issues","title":"Native Build Issues","text":"
  • Verify SDL2 installation
  • Check include/library paths
  • Ensure SDL2 version compatibility
  • Check linker flags
"},{"location":"manual/optimization/platforms_and_drivers/#next-steps","title":"Next Steps","text":"

Now that you understand platforms and drivers, learn about: - Extensibility - Create custom drivers - Memory Management - ESP32 memory constraints - Performance Optimization - Platform-specific optimization

See also: - API Reference - DrawSurface - API Reference - AudioBackend - Getting Started - Your First Project

"},{"location":"reference/api_overview/","title":"API Reference Overview","text":"

This document provides a complete technical reference for all PixelRoot32 APIs, organized by module. Each class includes descriptions, constructors, methods, properties, and usage examples.

"},{"location":"reference/api_overview/#organization","title":"Organization","text":"

The API is organized into the following modules:

  • Core: Engine, Scene, Entity, Actor, PhysicsActor, SceneManager
  • Graphics: Renderer, Camera2D, Color, Font, Sprite, TileMap, DrawSurface
  • Audio: AudioEngine, MusicPlayer, AudioTypes, AudioConfig, AudioBackend
  • Input: InputManager, InputConfig
  • Physics: CollisionSystem, CollisionTypes
  • UI: UIElement, UIButton, UILabel, UILayouts
  • Particles: ParticleEmitter, ParticleConfig, ParticlePresets
"},{"location":"reference/api_overview/#quick-navigation","title":"Quick Navigation","text":""},{"location":"reference/api_overview/#core-module","title":"Core Module","text":"
  • Engine - Main engine class, game loop management
  • Scene - Scene/level management
  • Entity - Base game object class
  • Actor - Entity with collision support
  • PhysicsActor - Actor with automatic physics
  • InputManager - Input handling
  • InputConfig - Input configuration
"},{"location":"reference/api_overview/#graphics-module","title":"Graphics Module","text":"
  • Renderer - High-level rendering API
  • Camera2D - 2D camera for scrolling
  • Color - Color constants and utilities
  • Font - Bitmap font system
  • Sprite - Sprite structures and formats
  • TileMap - Tilemap structure
  • DisplayConfig - Display configuration
"},{"location":"reference/api_overview/#audio-module","title":"Audio Module","text":"
  • AudioEngine - Sound effects playback
  • MusicPlayer - Background music playback
  • AudioTypes - Audio data structures
  • AudioConfig - Audio configuration
"},{"location":"reference/api_overview/#physics-module","title":"Physics Module","text":"
  • CollisionSystem - Collision detection
  • CollisionTypes - Collision primitives
"},{"location":"reference/api_overview/#ui-module","title":"UI Module","text":"
  • UIElement - Base UI element class
  • UIButton - Clickable button
  • UILabel - Text label
  • UILayouts - Layout containers
"},{"location":"reference/api_overview/#api-documentation-format","title":"API Documentation Format","text":"

Each API reference page follows this structure:

"},{"location":"reference/api_overview/#class-name","title":"Class Name","text":"

Brief description of the class and its purpose.

"},{"location":"reference/api_overview/#namespace","title":"Namespace","text":"
namespace pixelroot32::module {\n    class ClassName {\n        // ...\n    };\n}\n
"},{"location":"reference/api_overview/#constructors","title":"Constructors","text":"

List of all constructors with parameters.

"},{"location":"reference/api_overview/#public-methods","title":"Public Methods","text":"Method Description Parameters Returns methodName() Description param: type return type"},{"location":"reference/api_overview/#properties","title":"Properties","text":"Property Type Description property type Description"},{"location":"reference/api_overview/#usage-example","title":"Usage Example","text":"
// Example code showing typical usage\n
"},{"location":"reference/api_overview/#performance-notes","title":"Performance Notes","text":"

Any performance considerations or limitations.

"},{"location":"reference/api_overview/#see-also","title":"See Also","text":"

Links to related APIs and documentation.

"},{"location":"reference/api_overview/#finding-apis","title":"Finding APIs","text":""},{"location":"reference/api_overview/#by-functionality","title":"By Functionality","text":"
  • Game Loop: See Engine
  • Rendering: See Renderer
  • Input: See InputManager
  • Audio: See AudioEngine and MusicPlayer
  • Physics: See PhysicsActor and CollisionSystem
  • UI: See UIElement and layouts
"},{"location":"reference/api_overview/#by-module","title":"By Module","text":"

Navigate to the specific module folder: - api_reference/core/ - Core engine classes - api_reference/graphics/ - Rendering and graphics - api_reference/audio/ - Audio system - api_reference/physics/ - Physics and collisions - api_reference/ui/ - User interface

"},{"location":"reference/api_overview/#complete-api-list","title":"Complete API List","text":""},{"location":"reference/api_overview/#core","title":"Core","text":"
  • Engine
  • Scene
  • Entity
  • Actor
  • PhysicsActor
  • InputManager
  • InputConfig
"},{"location":"reference/api_overview/#graphics","title":"Graphics","text":"
  • Renderer
  • Camera2D
  • Color
  • Font
  • Sprite
  • TileMap
  • DisplayConfig
"},{"location":"reference/api_overview/#audio","title":"Audio","text":"
  • AudioEngine
  • MusicPlayer
  • AudioTypes
  • AudioConfig
"},{"location":"reference/api_overview/#physics","title":"Physics","text":"
  • CollisionSystem
  • CollisionTypes
"},{"location":"reference/api_overview/#ui","title":"UI","text":"
  • UIElement
  • UIButton
  • UILabel
  • UIVerticalLayout
  • UIHorizontalLayout
  • UIGridLayout
  • UIAnchorLayout
  • UIPanel
  • UIPaddingContainer
"},{"location":"reference/api_overview/#related-documentation","title":"Related Documentation","text":"
  • Manual - Game Development - How to use the APIs
  • Manual - Advanced Graphics - Advanced techniques
  • Code Examples - Reusable code snippets
  • Game Examples Guide - Learn from complete games

Note: This is an overview. For detailed API documentation, see the individual reference pages linked above.

"},{"location":"reference/code_examples/","title":"Code Examples","text":"

A library of reusable code snippets for common PixelRoot32 tasks. All examples are complete and functional.

"},{"location":"reference/code_examples/#initialization","title":"Initialization","text":""},{"location":"reference/code_examples/#basic-engine-setup-esp32","title":"Basic Engine Setup (ESP32)","text":"
#include <Arduino.h>\n#include <core/Engine.h>\n#include <drivers/esp32/TFT_eSPI_Drawer.h>\n#include <drivers/esp32/ESP32_DAC_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\n// Audio\nconst int DAC_PIN = 25;\npr32::drivers::esp32::ESP32_DAC_AudioBackend audioBackend(DAC_PIN, 11025);\n\n// Display\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::ST7789,\n    0, 240, 240\n);\n\n// Input\npr32::input::InputConfig inputConfig(6, 32, 27, 33, 14, 13, 12);\n\n// Audio config\npr32::audio::AudioConfig audioConfig(&audioBackend, 11025);\n\n// Engine\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nvoid setup() {\n    Serial.begin(115200);\n    engine.init();\n    // ... scene setup\n}\n\nvoid loop() {\n    engine.run();\n}\n
"},{"location":"reference/code_examples/#basic-engine-setup-native","title":"Basic Engine Setup (Native)","text":"
#define SDL_MAIN_HANDLED\n#include <SDL2/SDL.h>\n#include <core/Engine.h>\n#include <drivers/native/SDL2_Drawer.h>\n#include <drivers/native/SDL2_AudioBackend.h>\n\nnamespace pr32 = pixelroot32;\n\npr32::drivers::native::SDL2_AudioBackend audioBackend(22050, 1024);\npr32::graphics::DisplayConfig displayConfig(\n    pr32::graphics::DisplayType::NONE, 0, 240, 240\n);\npr32::input::InputConfig inputConfig(\n    6, SDL_SCANCODE_UP, SDL_SCANCODE_DOWN, \n    SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT,\n    SDL_SCANCODE_SPACE, SDL_SCANCODE_RETURN\n);\npr32::audio::AudioConfig audioConfig(&audioBackend, 22050);\n\npr32::core::Engine engine(displayConfig, inputConfig, audioConfig);\n\nint main(int argc, char* argv[]) {\n    engine.init();\n    // ... scene setup\n    engine.run();\n    return 0;\n}\n
"},{"location":"reference/code_examples/#entity-movement","title":"Entity Movement","text":""},{"location":"reference/code_examples/#simple-movement","title":"Simple Movement","text":"
class MovingEntity : public pixelroot32::core::Entity {\nprivate:\n    float speedX = 50.0f;\n    float speedY = 30.0f;\n\npublic:\n    MovingEntity(float x, float y)\n        : Entity(x, y, 16, 16, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        float dt = deltaTime * 0.001f;\n        x += speedX * dt;\n        y += speedY * dt;\n\n        // Bounce off edges\n        if (x < 0 || x > 224) speedX = -speedX;\n        if (y < 0 || y > 224) speedY = -speedY;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width, height,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n};\n
"},{"location":"reference/code_examples/#input-based-movement","title":"Input-Based Movement","text":"
class PlayerEntity : public pixelroot32::core::Actor {\nprivate:\n    float speed = 100.0f;\n\npublic:\n    PlayerEntity(float x, float y)\n        : Actor(x, y, 16, 16) {\n        setRenderLayer(1);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        if (input.isButtonDown(Buttons::LEFT)) {\n            x -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::RIGHT)) {\n            x += speed * dt;\n        }\n        if (input.isButtonDown(Buttons::UP)) {\n            y -= speed * dt;\n        }\n        if (input.isButtonDown(Buttons::DOWN)) {\n            y += speed * dt;\n        }\n\n        // Keep on screen\n        if (x < 0) x = 0;\n        if (x > 224) x = 224;\n        if (y < 0) y = 0;\n        if (y > 224) y = 224;\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        renderer.drawFilledRectangle(\n            static_cast<int>(x),\n            static_cast<int>(y),\n            width, height,\n            pixelroot32::graphics::Color::White\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        // Handle collision\n    }\n};\n
"},{"location":"reference/code_examples/#collisions","title":"Collisions","text":""},{"location":"reference/code_examples/#basic-collision-detection","title":"Basic Collision Detection","text":"
class CollidableEntity : public pixelroot32::core::Actor {\npublic:\n    CollidableEntity(float x, float y)\n        : Actor(x, y, 16, 16) {\n        setRenderLayer(1);\n        setCollisionLayer(Layers::PLAYER);\n        setCollisionMask(Layers::ENEMY | Layers::WALL);\n    }\n\n    void onCollision(pixelroot32::core::Actor* other) override {\n        if (other->isInLayer(Layers::ENEMY)) {\n            // Hit enemy\n            takeDamage();\n        } else if (other->isInLayer(Layers::WALL)) {\n            // Hit wall\n            stopMovement();\n        }\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"reference/code_examples/#collision-layers-setup","title":"Collision Layers Setup","text":"
// Define in GameLayers.h\nnamespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;\n    constexpr uint16_t ENEMY = 0x0002;\n    constexpr uint16_t PROJECTILE = 0x0004;\n    constexpr uint16_t WALL = 0x0008;\n    constexpr uint16_t PICKUP = 0x0010;\n}\n\n// Usage\nplayer->setCollisionLayer(Layers::PLAYER);\nplayer->setCollisionMask(Layers::ENEMY | Layers::WALL);\n\nenemy->setCollisionLayer(Layers::ENEMY);\nenemy->setCollisionMask(Layers::PLAYER | Layers::PROJECTILE);\n
"},{"location":"reference/code_examples/#sound-effects","title":"Sound Effects","text":""},{"location":"reference/code_examples/#common-sound-effects","title":"Common Sound Effects","text":"
namespace SoundEffects {\n    inline pixelroot32::audio::AudioEvent jump() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 600.0f;\n        evt.duration = 0.1f;\n        evt.volume = 0.7f;\n        evt.duty = 0.25f;\n        return evt;\n    }\n\n    inline pixelroot32::audio::AudioEvent coin() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::PULSE;\n        evt.frequency = 1500.0f;\n        evt.duration = 0.12f;\n        evt.volume = 0.8f;\n        evt.duty = 0.5f;\n        return evt;\n    }\n\n    inline pixelroot32::audio::AudioEvent explosion() {\n        pixelroot32::audio::AudioEvent evt{};\n        evt.type = pixelroot32::audio::WaveType::NOISE;\n        evt.frequency = 200.0f;\n        evt.duration = 0.3f;\n        evt.volume = 0.9f;\n        return evt;\n    }\n}\n\n// Usage\nengine.getAudioEngine().playEvent(SoundEffects::jump());\n
"},{"location":"reference/code_examples/#playing-sound-on-event","title":"Playing Sound on Event","text":"
class PlayerActor : public pixelroot32::core::Actor {\npublic:\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n\n        if (input.isButtonPressed(Buttons::A)) {\n            // Play jump sound\n            pixelroot32::audio::AudioEvent jumpSound{};\n            jumpSound.type = pixelroot32::audio::WaveType::PULSE;\n            jumpSound.frequency = 800.0f;\n            jumpSound.duration = 0.1f;\n            jumpSound.volume = 0.7f;\n            jumpSound.duty = 0.25f;\n\n            engine.getAudioEngine().playEvent(jumpSound);\n\n            // Jump logic\n            jump();\n        }\n    }\n};\n
"},{"location":"reference/code_examples/#ui-components","title":"UI Components","text":""},{"location":"reference/code_examples/#simple-menu","title":"Simple Menu","text":"
class MenuScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::ui::UIVerticalLayout* menu;\n\npublic:\n    void init() override {\n        menu = new pixelroot32::graphics::ui::UIVerticalLayout(40, 60, 160, 160);\n        menu->setPadding(10);\n        menu->setSpacing(8);\n        menu->setNavigationButtons(0, 1);\n        menu->setButtonStyle(\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Cyan,\n            pixelroot32::graphics::Color::White,\n            pixelroot32::graphics::Color::Black\n        );\n\n        menu->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Start\", 0, 0, 0, 140, 25, []() { startGame(); }\n        ));\n\n        menu->addElement(new pixelroot32::graphics::ui::UIButton(\n            \"Options\", 1, 0, 0, 140, 25, []() { showOptions(); }\n        ));\n\n        addEntity(menu);\n    }\n\n    void update(unsigned long deltaTime) override {\n        menu->handleInput(engine.getInputManager());\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"reference/code_examples/#hud-with-labels","title":"HUD with Labels","text":"
class GameHUD : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::ui::UILabel* scoreLabel;\n    pixelroot32::graphics::ui::UILabel* livesLabel;\n\npublic:\n    GameHUD()\n        : Entity(0, 0, 240, 240, pixelroot32::core::EntityType::UI_ELEMENT) {\n        setRenderLayer(2);\n\n        scoreLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Score: 0\", 10, 10,\n            pixelroot32::graphics::Color::White, 1\n        );\n\n        livesLabel = new pixelroot32::graphics::ui::UILabel(\n            \"Lives: 3\", 10, 20,\n            pixelroot32::graphics::Color::White, 1\n        );\n    }\n\n    void updateHUD(int score, int lives) {\n        char buffer[32];\n        snprintf(buffer, sizeof(buffer), \"Score: %d\", score);\n        scoreLabel->setText(buffer);\n\n        snprintf(buffer, sizeof(buffer), \"Lives: %d\", lives);\n        livesLabel->setText(buffer);\n    }\n};\n
"},{"location":"reference/code_examples/#physics","title":"Physics","text":""},{"location":"reference/code_examples/#bouncing-ball","title":"Bouncing Ball","text":"
class BouncingBall : public pixelroot32::core::PhysicsActor {\npublic:\n    BouncingBall(float x, float y, float radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRenderLayer(1);\n        setRestitution(0.9f);\n        setFriction(0.05f);\n        setWorldSize(240, 240);\n        setVelocity(50.0f, -30.0f);\n    }\n\n    void update(unsigned long deltaTime) override {\n        float gravity = 200.0f;\n        float dt = deltaTime * 0.001f;\n        setVelocity(vx, vy + gravity * dt);\n        PhysicsActor::update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        int radius = width / 2;\n        renderer.drawFilledCircle(\n            static_cast<int>(x + radius),\n            static_cast<int>(y + radius),\n            radius,\n            pixelroot32::graphics::Color::Cyan\n        );\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"reference/code_examples/#platformer-player","title":"Platformer Player","text":"
class PlatformerPlayer : public pixelroot32::core::PhysicsActor {\nprivate:\n    bool canJump = true;\n    float jumpForce = 250.0f;\n    float moveSpeed = 100.0f;\n\npublic:\n    PlatformerPlayer(float x, float y)\n        : PhysicsActor(x, y, 16, 16) {\n        setRenderLayer(1);\n        setFriction(0.3f);\n        setWorldSize(240, 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        auto& input = engine.getInputManager();\n        float dt = deltaTime * 0.001f;\n\n        // Horizontal movement\n        float moveDir = 0.0f;\n        if (input.isButtonDown(Buttons::LEFT)) moveDir -= 1.0f;\n        if (input.isButtonDown(Buttons::RIGHT)) moveDir += 1.0f;\n        setVelocity(moveDir * moveSpeed, vy);\n\n        // Gravity\n        float gravity = 300.0f;\n        setVelocity(vx, vy + gravity * dt);\n\n        // Jump\n        if (input.isButtonPressed(Buttons::A) && canJump) {\n            setVelocity(vx, -jumpForce);\n            canJump = false;\n        }\n\n        PhysicsActor::update(deltaTime);\n\n        // Check if on ground\n        auto collisionInfo = getWorldCollisionInfo();\n        if (collisionInfo.bottom) {\n            canJump = true;\n        }\n    }\n\n    pixelroot32::core::Rect getHitBox() override {\n        return {x, y, width, height};\n    }\n};\n
"},{"location":"reference/code_examples/#sprites-and-animation","title":"Sprites and Animation","text":""},{"location":"reference/code_examples/#simple-sprite","title":"Simple Sprite","text":"
// Define sprite data\nstatic const uint16_t PLAYER_SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    0b11111111,\n    0b11111111,\n    0b01111110,\n    0b00111100,\n    0b00000000\n};\n\nstatic const pixelroot32::graphics::Sprite PLAYER_SPRITE = {\n    PLAYER_SPRITE_DATA, 8, 8\n};\n\n// Draw sprite\nrenderer.drawSprite(PLAYER_SPRITE, 100, 100, \n    pixelroot32::graphics::Color::White);\n
"},{"location":"reference/code_examples/#sprite-animation","title":"Sprite Animation","text":"
class AnimatedActor : public pixelroot32::core::Actor {\nprivate:\n    pixelroot32::graphics::SpriteAnimation animation;\n    unsigned long timer = 0;\n    const unsigned long FRAME_DURATION_MS = 100;\n\npublic:\n    AnimatedActor(float x, float y)\n        : Actor(x, y, 8, 8) {\n        setRenderLayer(1);\n        animation.frames = WALK_ANIMATION_FRAMES;\n        animation.frameCount = 3;\n        animation.current = 0;\n    }\n\n    void update(unsigned long deltaTime) override {\n        timer += deltaTime;\n        if (timer >= FRAME_DURATION_MS) {\n            timer -= FRAME_DURATION_MS;\n            animation.step();\n        }\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        const auto* frame = animation.frames[animation.current].sprite;\n        renderer.drawSprite(*frame, static_cast<int>(x), static_cast<int>(y),\n            pixelroot32::graphics::Color::White);\n    }\n};\n
"},{"location":"reference/code_examples/#camera-and-scrolling","title":"Camera and Scrolling","text":""},{"location":"reference/code_examples/#basic-camera-follow","title":"Basic Camera Follow","text":"
class ScrollingScene : public pixelroot32::core::Scene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    PlayerActor* player;\n\npublic:\n    void init() override {\n        int screenWidth = engine.getRenderer().getWidth();\n        int screenHeight = engine.getRenderer().getHeight();\n\n        camera = pixelroot32::graphics::Camera2D(screenWidth, screenHeight);\n        camera.setBounds(0, 2000 - screenWidth);\n\n        player = new PlayerActor(100, 100);\n        addEntity(player);\n    }\n\n    void update(unsigned long deltaTime) override {\n        Scene::update(deltaTime);\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"reference/code_examples/#tilemaps","title":"Tilemaps","text":""},{"location":"reference/code_examples/#simple-tilemap","title":"Simple Tilemap","text":"
// Define tiles\nstatic const uint16_t TILE_EMPTY_BITS[] = { /* ... */ };\nstatic const uint16_t TILE_GROUND_BITS[] = { /* ... */ };\n\nstatic const pixelroot32::graphics::Sprite TILES[] = {\n    { TILE_EMPTY_BITS, 8, 8 },\n    { TILE_GROUND_BITS, 8, 8 }\n};\n\n// Create tilemap\nstatic uint8_t TILEMAP_INDICES[30 * 20];\nstatic pixelroot32::graphics::TileMap levelTileMap = {\n    TILEMAP_INDICES, 30, 20, TILES, 8, 8, 2\n};\n\n// Initialize\nvoid initTilemap() {\n    for (int i = 0; i < 30 * 20; i++) {\n        TILEMAP_INDICES[i] = 0;\n    }\n    // Set ground row\n    for (int x = 0; x < 30; x++) {\n        TILEMAP_INDICES[19 * 30 + x] = 1; // Ground tile\n    }\n}\n\n// Draw\nrenderer.drawTileMap(levelTileMap, 0, 0, \n    pixelroot32::graphics::Color::White);\n
"},{"location":"reference/code_examples/#particles","title":"Particles","text":""},{"location":"reference/code_examples/#explosion-effect","title":"Explosion Effect","text":"
#include <graphics/particles/ParticleEmitter.h>\n#include <graphics/particles/ParticlePresets.h>\n\nclass ExplosionEffect : public pixelroot32::core::Entity {\nprivate:\n    pixelroot32::graphics::particles::ParticleEmitter* emitter;\n\npublic:\n    ExplosionEffect()\n        : Entity(0, 0, 1, 1, pixelroot32::core::EntityType::GENERIC) {\n        setRenderLayer(1);\n        emitter = new pixelroot32::graphics::particles::ParticleEmitter(\n            0, 0,\n            pixelroot32::graphics::particles::ParticlePresets::Explosion()\n        );\n    }\n\n    void trigger(float x, float y) {\n        this->x = x;\n        this->y = y;\n        emitter->burst(x, y, 25);\n    }\n\n    void update(unsigned long deltaTime) override {\n        emitter->update(deltaTime);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        emitter->draw(renderer);\n    }\n};\n
"},{"location":"reference/code_examples/#object-pooling","title":"Object Pooling","text":""},{"location":"reference/code_examples/#entity-pool","title":"Entity Pool","text":"
template<typename T, int POOL_SIZE>\nclass EntityPool {\nprivate:\n    T pool[POOL_SIZE];\n    bool inUse[POOL_SIZE];\n    int activeCount = 0;\n\npublic:\n    EntityPool() {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            inUse[i] = false;\n        }\n    }\n\n    T* acquire() {\n        if (activeCount >= POOL_SIZE) return nullptr;\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (!inUse[i]) {\n                inUse[i] = true;\n                activeCount++;\n                return &pool[i];\n            }\n        }\n        return nullptr;\n    }\n\n    void release(T* obj) {\n        for (int i = 0; i < POOL_SIZE; i++) {\n            if (&pool[i] == obj) {\n                inUse[i] = false;\n                activeCount--;\n                obj->isEnabled = false;\n                obj->isVisible = false;\n                break;\n            }\n        }\n    }\n};\n
"},{"location":"reference/code_examples/#common-patterns","title":"Common Patterns","text":""},{"location":"reference/code_examples/#state-machine","title":"State Machine","text":"
enum class GameState {\n    MENU,\n    PLAYING,\n    PAUSED,\n    GAME_OVER\n};\n\nclass GameScene : public pixelroot32::core::Scene {\nprivate:\n    GameState currentState = GameState::MENU;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        switch (currentState) {\n            case GameState::MENU:\n                updateMenu();\n                break;\n            case GameState::PLAYING:\n                updateGame();\n                break;\n            case GameState::PAUSED:\n                updatePause();\n                break;\n            case GameState::GAME_OVER:\n                updateGameOver();\n                break;\n        }\n        Scene::update(deltaTime);\n    }\n};\n
"},{"location":"reference/code_examples/#timer-pattern","title":"Timer Pattern","text":"
class Timer {\nprivate:\n    unsigned long duration;\n    unsigned long elapsed = 0;\n    bool active = false;\n\npublic:\n    Timer(unsigned long ms) : duration(ms) {}\n\n    void start() {\n        active = true;\n        elapsed = 0;\n    }\n\n    void update(unsigned long deltaTime) {\n        if (active) {\n            elapsed += deltaTime;\n            if (elapsed >= duration) {\n                active = false;\n            }\n        }\n    }\n\n    bool isFinished() const { return !active && elapsed >= duration; }\n    bool isActive() const { return active; }\n    float getProgress() const { return static_cast<float>(elapsed) / duration; }\n};\n
"},{"location":"reference/code_examples/#see-also","title":"See Also","text":"
  • API Reference Overview - Complete API documentation
  • Game Examples Guide - Learn from complete games
  • Manual - Game Development - Detailed guides
"},{"location":"reference/game_examples_guide/","title":"Game Examples Guide","text":"

This guide analyzes the complete game examples included with PixelRoot32, explaining their architecture, patterns, and lessons learned.

"},{"location":"reference/game_examples_guide/#available-examples","title":"Available Examples","text":"

PixelRoot32 (in the PixelRoot32 Game Samples project) includes these games and demos:

  • Metroidvania: 2D platformer with multi-layer 4bpp tilemap and tile-based collision (requires PIXELROOT32_ENABLE_4BPP_SPRITES; no scroll/camera)
  • Space Invaders: Full shooter with enemies, projectiles, bunkers and audio
  • Pong: Classic with physics and collisions
  • BrickBreaker: Breakout-style with particles and advanced audio
  • Snake: Grid-based game with entity pooling
  • TicTacToe: Turn-based with simple AI
  • CameraDemo: Platformer with camera and parallax
  • SpritesDemo: 2bpp and 4bpp sprites
  • TileMapDemo: 4bpp tilemaps (with viewport culling)
"},{"location":"reference/game_examples_guide/#space-invaders","title":"Space Invaders","text":"

Location: src/examples/SpaceInvaders/

"},{"location":"reference/game_examples_guide/#architecture","title":"Architecture","text":"

Space Invaders demonstrates a complete game with multiple systems:

  • Scene Management: SpaceInvadersScene manages game state
  • Actor Hierarchy: PlayerActor, AlienActor, ProjectileActor, BunkerActor
  • Collision System: Uses collision layers for player, enemies, projectiles
  • Audio Integration: Sound effects for shooting, explosions, music
  • Background: Starfield (code-generated star pattern) or tilemap
"},{"location":"reference/game_examples_guide/#key-systems","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#collision-layers","title":"Collision Layers","text":"
namespace Layers {\n    constexpr uint16_t PLAYER = 0x0001;\n    constexpr uint16_t ALIEN = 0x0002;\n    constexpr uint16_t PROJECTILE = 0x0004;\n    constexpr uint16_t BUNKER = 0x0008;\n}\n\n// Player can collide with aliens and bunkers\nplayer->setCollisionLayer(Layers::PLAYER);\nplayer->setCollisionMask(Layers::ALIEN | Layers::BUNKER);\n\n// Projectiles can hit aliens and bunkers\nprojectile->setCollisionLayer(Layers::PROJECTILE);\nprojectile->setCollisionMask(Layers::ALIEN | Layers::BUNKER);\n
"},{"location":"reference/game_examples_guide/#entity-management","title":"Entity Management","text":"
  • Uses object pooling for projectiles
  • Manages alien formation with grid layout
  • Handles game state (playing, game over)
"},{"location":"reference/game_examples_guide/#audio-integration","title":"Audio Integration","text":"
  • Background music using MusicPlayer
  • Sound effects for various events
  • Audio events triggered on collisions
"},{"location":"reference/game_examples_guide/#patterns-used","title":"Patterns Used","text":"
  • Object Pooling: Projectiles are pooled and reused
  • State Machine: Game states (playing, game over, victory)
  • Grid Layout: Alien formation uses grid-based positioning
  • Event-Driven Audio: Sounds triggered by game events
"},{"location":"reference/game_examples_guide/#lessons-learned","title":"Lessons Learned","text":"
  • Collision layers are essential for complex games
  • Object pooling improves performance
  • Starfield or tilemap backgrounds are efficient
  • Audio enhances game feel significantly
"},{"location":"reference/game_examples_guide/#metroidvania","title":"Metroidvania","text":"

Location: src/examples/Games/Metroidvania/

Assets: Sprites and tilesets for this example come from the Tiny Metroidvania 8x8 pack by Kenmi (kenmi-art.itch.io).

"},{"location":"reference/game_examples_guide/#architecture_1","title":"Architecture","text":"

Metroidvania is a 2D platformer example with multi-layer tilemap and optimizations aimed at ESP32. It does not use scroll or camera; the level is drawn with a fixed origin (0,0).

  • Scene: MetroidvaniaScene with a single PlayerActor and several tilemap layers (background, platforms, details, stairs).
  • PlayerActor: Horizontal and vertical movement, stairs, tile-based collision (no rectangle lists).
  • Tilemap: 4bpp (TileMap4bpp), with viewport culling and palette cache in the engine. Level 40\u00d730 tiles (320\u00d7240 px).
  • No camera: The view does not follow the player; for scroll you would use Camera2D and apply offset in the renderer (as in CameraDemo).
"},{"location":"reference/game_examples_guide/#engine-features-used","title":"Engine features used","text":"
  • Tile-based collision: Direct tile checks around the player (getTileAt), instead of iterating over platformRects.
  • 4bpp sprites: Player with animations (idle, run, jump) from generated headers (e.g. Sprite Compiler).
  • Rendering optimizations: Viewport culling in drawTileMap, optimized 4bpp drawSprite, layers culled by viewport.
  • Optional: Scene arena, DMA, IRAM_ATTR on critical paths (per example optimization plan).
"},{"location":"reference/game_examples_guide/#patterns-used_1","title":"Patterns used","text":"
  • Tile-based collision: Single O(1) access per tile instead of O(N) rectangles.
  • Stair detection: Single result reused for collision and state change.
  • Simplified hitbox: Fewer vertical check points (head and feet).
"},{"location":"reference/game_examples_guide/#lessons-learned_1","title":"Lessons learned","text":"
  • Tile-based collision scales better than rectangle lists on large levels.
  • Viewport and 4bpp optimizations improve FPS on ESP32.
  • Metroidvania serves as a reference for platformers with tilemap and camera.
"},{"location":"reference/game_examples_guide/#pong","title":"Pong","text":"

Location: src/examples/Pong/

"},{"location":"reference/game_examples_guide/#architecture_2","title":"Architecture","text":"

Pong demonstrates physics and collision handling:

  • PhysicsActor: Ball uses PhysicsActor for automatic physics
  • Collision Callbacks: Paddles and ball handle collisions
  • Score System: Simple score tracking and display
  • Game State: Reset and game over handling
"},{"location":"reference/game_examples_guide/#key-systems_1","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#physics-setup","title":"Physics Setup","text":"
class BallActor : public pixelroot32::core::PhysicsActor {\npublic:\n    BallActor(float x, float y, float speed, int radius)\n        : PhysicsActor(x, y, radius * 2, radius * 2) {\n        setRestitution(0.8f);  // Bouncy\n        setFriction(0.1f);     // Low friction\n        setWorldSize(240, 240);\n    }\n};\n
"},{"location":"reference/game_examples_guide/#collision-response","title":"Collision Response","text":"
void BallActor::onCollision(pixelroot32::core::Actor* other) {\n    // Adjust ball position\n    // Modify velocity based on impact point\n    // Play bounce sound\n}\n
"},{"location":"reference/game_examples_guide/#patterns-used_2","title":"Patterns Used","text":"
  • Physics Integration: Uses PhysicsActor for automatic movement
  • Collision Response: Custom collision handling
  • Score Management: Simple state tracking
  • Audio Feedback: Sound on collision
"},{"location":"reference/game_examples_guide/#lessons-learned_2","title":"Lessons Learned","text":"
  • PhysicsActor simplifies physics-based games
  • Collision callbacks allow custom response logic
  • Simple games can be very effective
"},{"location":"reference/game_examples_guide/#snake","title":"Snake","text":"

Location: src/examples/Snake/

"},{"location":"reference/game_examples_guide/#architecture_3","title":"Architecture","text":"

Snake demonstrates entity pooling and grid-based movement:

  • Entity Pooling: Snake segments are pooled
  • Grid Movement: Movement constrained to grid
  • Game Logic: Food spawning, collision detection
  • State Management: Game over, reset functionality
"},{"location":"reference/game_examples_guide/#key-systems_2","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#entity-pooling","title":"Entity Pooling","text":"
class SnakeScene {\nprivate:\n    std::vector<SnakeSegmentActor*> segmentPool;\n    std::vector<SnakeSegmentActor*> snakeSegments;\n\n    void resetGame() {\n        // Reuse pooled segments\n        for (int i = 0; i < initialLength; ++i) {\n            SnakeSegmentActor* segment = segmentPool[i];\n            segment->resetAlive();\n            snakeSegments.push_back(segment);\n            addEntity(segment);\n        }\n    }\n};\n
"},{"location":"reference/game_examples_guide/#grid-based-movement","title":"Grid-Based Movement","text":"
class SnakeSegmentActor : public pixelroot32::core::Actor {\nprivate:\n    int cellX, cellY;  // Grid position\n\npublic:\n    void setCellPosition(int x, int y) {\n        cellX = x;\n        cellY = y;\n        // Convert to world position\n        this->x = cellX * CELL_SIZE;\n        this->y = cellY * CELL_SIZE;\n    }\n};\n
"},{"location":"reference/game_examples_guide/#patterns-used_3","title":"Patterns Used","text":"
  • Object Pooling: Segments are pre-allocated and reused
  • Grid System: Discrete grid-based movement
  • Linked List: Snake segments form a linked structure
  • Food Spawning: Random food placement with collision checking
"},{"location":"reference/game_examples_guide/#lessons-learned_3","title":"Lessons Learned","text":"
  • Entity pooling is essential for dynamic entities
  • Grid-based movement simplifies collision detection
  • Pre-allocation avoids memory fragmentation
"},{"location":"reference/game_examples_guide/#tictactoe","title":"TicTacToe","text":"

Location: src/examples/TicTacToe/

"},{"location":"reference/game_examples_guide/#architecture_4","title":"Architecture","text":"

TicTacToe demonstrates turn-based logic and simple AI:

  • Turn Management: Player vs AI turns
  • Game Board: 3x3 grid representation
  • Win Detection: Check for winning conditions
  • Simple AI: Random move selection
"},{"location":"reference/game_examples_guide/#key-systems_3","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#board-representation","title":"Board Representation","text":"
class TicTacToeScene {\nprivate:\n    int board[3][3];  // 0=empty, 1=X, 2=O\n    bool playerTurn = true;\n\n    bool makeMove(int row, int col, int player) {\n        if (board[row][col] == 0) {\n            board[row][col] = player;\n            return true;\n        }\n        return false;\n    }\n};\n
"},{"location":"reference/game_examples_guide/#win-detection","title":"Win Detection","text":"
int checkWinner() {\n    // Check rows\n    for (int i = 0; i < 3; i++) {\n        if (board[i][0] == board[i][1] && board[i][1] == board[i][2]) {\n            return board[i][0];\n        }\n    }\n    // Check columns, diagonals...\n    return 0; // No winner\n}\n
"},{"location":"reference/game_examples_guide/#patterns-used_4","title":"Patterns Used","text":"
  • State Machine: Turn-based state management
  • Grid Logic: 2D array for board representation
  • Simple AI: Random valid move selection
  • UI Integration: Buttons for player input
"},{"location":"reference/game_examples_guide/#lessons-learned_4","title":"Lessons Learned","text":"
  • Turn-based games are straightforward to implement
  • Simple AI can be effective for basic games
  • Grid-based logic is easy to reason about
"},{"location":"reference/game_examples_guide/#camerademo","title":"CameraDemo","text":"

Location: src/examples/CameraDemo/

"},{"location":"reference/game_examples_guide/#architecture_5","title":"Architecture","text":"

CameraDemo demonstrates scrolling and parallax:

  • Camera2D: Camera following player
  • Tilemap: Level built with tilemap
  • Parallax: Multiple background layers
  • Platformer Physics: Player with jumping and gravity
"},{"location":"reference/game_examples_guide/#key-systems_4","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#camera-setup","title":"Camera Setup","text":"
class CameraDemoScene {\nprivate:\n    pixelroot32::graphics::Camera2D camera;\n    float levelWidth;\n\npublic:\n    void init() override {\n        camera = pixelroot32::graphics::Camera2D(240, 240);\n        camera.setBounds(0, levelWidth - 240);\n    }\n\n    void update(unsigned long deltaTime) override {\n        camera.followTarget(player->x, player->y);\n    }\n\n    void draw(pixelroot32::graphics::Renderer& renderer) override {\n        camera.apply(renderer);\n        renderer.drawTileMap(levelTileMap, 0, 0, Color::White);\n        Scene::draw(renderer);\n    }\n};\n
"},{"location":"reference/game_examples_guide/#platformer-physics","title":"Platformer Physics","text":"
class PlayerCube : public pixelroot32::core::PhysicsActor {\npublic:\n    void update(unsigned long deltaTime) override {\n        // Input handling\n        // Gravity application\n        // Jump logic\n        // Platform collision\n        PhysicsActor::update(deltaTime);\n    }\n};\n
"},{"location":"reference/game_examples_guide/#patterns-used_5","title":"Patterns Used","text":"
  • Camera Following: Dead-zone camera following
  • Tilemap Rendering: Efficient level rendering
  • Parallax Scrolling: Multiple background layers
  • Platform Collision: Custom collision with platforms
"},{"location":"reference/game_examples_guide/#lessons-learned_5","title":"Lessons Learned","text":"
  • Camera system enables large levels
  • Tilemaps are efficient for level data
  • Parallax adds depth to 2D games
  • Platform collision requires custom logic
"},{"location":"reference/game_examples_guide/#spritesdemo","title":"SpritesDemo","text":"

Location: src/examples/SpritesDemo/

"},{"location":"reference/game_examples_guide/#architecture_6","title":"Architecture","text":"

SpritesDemo showcases advanced sprite formats:

  • 2bpp Sprites: 4-color sprite format
  • 4bpp Sprites: 16-color sprite format (if enabled)
  • Animation: Sprite animation examples
  • Format Comparison: Side-by-side format display
"},{"location":"reference/game_examples_guide/#key-systems_5","title":"Key Systems","text":""},{"location":"reference/game_examples_guide/#2bpp-sprite-usage","title":"2bpp Sprite Usage","text":"
#ifdef PIXELROOT32_ENABLE_2BPP_SPRITES\nstatic const pixelroot32::graphics::Sprite2bpp SPRITE_2BPP = {\n    SPRITE_DATA,\n    SPRITE_PALETTE,\n    16, 32, 4\n};\n\nrenderer.drawSprite(SPRITE_2BPP, x, y, false);\n#endif\n
"},{"location":"reference/game_examples_guide/#animation-display","title":"Animation Display","text":"
class SpritesDemoActor : public pixelroot32::core::Entity {\nprivate:\n    unsigned long timer = 0;\n    uint8_t currentFrame = 0;\n\npublic:\n    void update(unsigned long deltaTime) override {\n        timer += deltaTime;\n        if (timer >= 150) {\n            timer -= 150;\n            currentFrame = (currentFrame + 1) % 9;\n        }\n    }\n};\n
"},{"location":"reference/game_examples_guide/#patterns-used_6","title":"Patterns Used","text":"
  • Format Comparison: Shows different sprite formats
  • Animation Loop: Frame-based animation
  • Conditional Compilation: Uses build flags
"},{"location":"reference/game_examples_guide/#lessons-learned_6","title":"Lessons Learned","text":"
  • Advanced formats provide more color options
  • Animation is straightforward with frame arrays
  • Build flags enable/disable experimental features
"},{"location":"reference/game_examples_guide/#common-patterns-across-examples","title":"Common Patterns Across Examples","text":""},{"location":"reference/game_examples_guide/#screen-resolution","title":"Screen Resolution","text":"

All examples are configured for a 240x240 screen resolution.

"},{"location":"reference/game_examples_guide/#scene-initialization","title":"Scene Initialization","text":"

All examples follow this pattern:

void init() override {\n    // 1. Set palette\n    pixelroot32::graphics::setPalette(PaletteType::NES);\n\n    // 2. Create background entity\n    addEntity(new BackgroundEntity());\n\n    // 3. Create game entities\n    player = new PlayerActor(...);\n    addEntity(player);\n\n    // 4. Initialize game state\n    resetGame();\n}\n
"},{"location":"reference/game_examples_guide/#update-pattern","title":"Update Pattern","text":"
void update(unsigned long deltaTime) override {\n    // 1. Process input\n    handleInput();\n\n    // 2. Update game logic\n    updateGameLogic();\n\n    // 3. Call parent update (updates all entities)\n    Scene::update(deltaTime);\n\n    // 4. Post-update logic\n    checkGameState();\n}\n
"},{"location":"reference/game_examples_guide/#draw-pattern","title":"Draw Pattern","text":"
void draw(pixelroot32::graphics::Renderer& renderer) override {\n    // 1. Apply camera (if used)\n    camera.apply(renderer);\n\n    // 2. Draw background/tilemap\n    renderer.drawTileMap(background, 0, 0, Color::White);\n\n    // 3. Call parent draw (draws all entities)\n    Scene::draw(renderer);\n\n    // 4. Draw UI/HUD\n    drawHUD(renderer);\n}\n
"},{"location":"reference/game_examples_guide/#learning-path","title":"Learning Path","text":""},{"location":"reference/game_examples_guide/#beginner-examples","title":"Beginner Examples","text":"
  1. Pong: Basic physics and collisions
  2. TicTacToe: Turn-based logic
  3. Snake: Entity pooling and grid
"},{"location":"reference/game_examples_guide/#intermediate-examples","title":"Intermediate Examples","text":"
  1. CameraDemo: Camera and parallax
  2. SpritesDemo: 2bpp and 4bpp formats
  3. BrickBreaker: Physics, particles and audio
"},{"location":"reference/game_examples_guide/#advanced-examples","title":"Advanced Examples","text":"
  1. Space Invaders: Full game (1bpp sprites, collisions, audio)
  2. Metroidvania: Platformer with multi-layer 4bpp tilemap, tile-based collision and ESP32 optimizations (no scroll/camera)
"},{"location":"reference/game_examples_guide/#code-study-recommendations","title":"Code Study Recommendations","text":""},{"location":"reference/game_examples_guide/#for-learning-physics","title":"For Learning Physics","text":"
  • Study Pong/BallActor.cpp - PhysicsActor usage
  • Study CameraDemo/PlayerCube.cpp - Platformer physics
"},{"location":"reference/game_examples_guide/#for-learning-collisions","title":"For Learning Collisions","text":"
  • Study SpaceInvaders - Complex collision layers
  • Study Pong - Simple collision response
"},{"location":"reference/game_examples_guide/#for-learning-memory-management","title":"For Learning Memory Management","text":"
  • Study Snake/SnakeScene.cpp - Entity pooling
  • Study SpaceInvaders - Projectile pooling
"},{"location":"reference/game_examples_guide/#for-learning-audio","title":"For Learning Audio","text":"
  • Study SpaceInvaders - Music and sound effects
  • Study Pong - Simple audio integration
"},{"location":"reference/game_examples_guide/#for-learning-ui","title":"For Learning UI","text":"
  • Study TicTacToe - Button-based UI
  • Study menu scenes - Layout usage
"},{"location":"reference/game_examples_guide/#extending-examples","title":"Extending Examples","text":""},{"location":"reference/game_examples_guide/#adding-features","title":"Adding Features","text":"
  • Pong: Add power-ups, multiple balls
  • Snake: Add obstacles, multiple food types
  • Space Invaders: Add boss battles, power-ups
"},{"location":"reference/game_examples_guide/#creating-variations","title":"Creating Variations","text":"
  • Pong: Make it vertical, add walls
  • Snake: Change to hexagonal grid
  • TicTacToe: Make it 4x4 or 5x5
"},{"location":"reference/game_examples_guide/#best-practices-from-examples","title":"Best Practices from Examples","text":"
  1. Pre-allocate Resources: All examples pre-allocate entities
  2. Use Object Pooling: For frequently created/destroyed entities
  3. Organize by Layers: Clear collision layer organization
  4. Separate Concerns: Game logic separate from rendering
  5. State Management: Clear game state handling
"},{"location":"reference/game_examples_guide/#see-also","title":"See Also","text":"
  • Code Examples - Reusable code snippets
  • API Reference Overview - Complete API documentation
  • Manual - Game Development - Detailed guides

Note: All example code is available in the src/examples/ directory of the PixelRoot32 Game Samples project.

"},{"location":"resources/available_tools/","title":"Available Tools","text":"

This guide documents tools available to facilitate PixelRoot32 game development.

"},{"location":"resources/available_tools/#sprite-compiler-pr32-sprite-compiler","title":"Sprite Compiler (pr32-sprite-compiler)","text":"

The Sprite Compiler converts PNG images to PixelRoot32 sprite data formats, making it easy to create sprites from image files.

Read more in the Sprite Compiler Guide

From Source:

git clone https://github.com/Gperez88/pr32-sprite-compiler.git\ncd pr32-sprite-compiler\nnpm install\nnpm link  # Optional: install globally\n

As NPM Package:

npm install -g pr32-sprite-compiler\n
"},{"location":"resources/available_tools/#basic-usage","title":"Basic Usage","text":"

Command Line:

pr32-sprite-compiler input.png output.h\n

With Options:

pr32-sprite-compiler input.png output.h --format 1bpp --name MY_SPRITE\n
"},{"location":"resources/available_tools/#supported-formats","title":"Supported Formats","text":"
  • 1bpp (default): Monochrome, most memory-efficient
  • 2bpp: 4 colors per sprite (requires PIXELROOT32_ENABLE_2BPP_SPRITES)
  • 4bpp: 16 colors per sprite (requires PIXELROOT32_ENABLE_4BPP_SPRITES)
"},{"location":"resources/available_tools/#output-format","title":"Output Format","text":"

The compiler generates C++ header files with sprite data:

// output.h\n#ifndef SPRITE_DATA_H\n#define SPRITE_DATA_H\n\n#include <stdint.h>\n\nstatic const uint16_t MY_SPRITE_DATA[] = {\n    0b00111100,\n    0b01111110,\n    0b11111111,\n    // ... more rows\n};\n\nstatic const pixelroot32::graphics::Sprite MY_SPRITE = {\n    MY_SPRITE_DATA,\n    8,  // width\n    8   // height\n};\n\n#endif\n
"},{"location":"resources/available_tools/#advanced-options","title":"Advanced Options","text":"

Batch Processing:

pr32-sprite-compiler --batch sprites/*.png --output-dir sprites/out/\n

Custom Palette:

pr32-sprite-compiler input.png output.h --palette custom_palette.json\n

Sprite Sheet:

pr32-sprite-compiler sheet.png output.h --sheet 8x8 --count 16\n
"},{"location":"resources/available_tools/#gui-version","title":"GUI Version","text":"

If available, a GUI version provides visual feedback:

  • Drag and drop images
  • Preview sprite data
  • Adjust settings visually
  • Export to header files
"},{"location":"resources/available_tools/#step-by-step-example","title":"Step-by-Step Example","text":"
  1. Create or find a PNG image (8x8, 16x16, etc.)

  2. Run the compiler:

pr32-sprite-compiler player.png player_sprite.h --name PLAYER_SPRITE\n
  1. Include in your project:
#include \"player_sprite.h\"\n\nvoid draw() {\n    renderer.drawSprite(PLAYER_SPRITE, 100, 100, Color::White);\n}\n
"},{"location":"resources/available_tools/#troubleshooting","title":"Troubleshooting","text":"

Image too large:

  • Sprites must be \u2264 16 pixels wide for 1bpp
  • Reduce image size or split into multiple sprites

Colors not converting correctly:

  • Ensure image uses indexed colors
  • Use black/white for 1bpp
  • Use 4 colors for 2bpp, 16 for 4bpp

Output file not found:

  • Check write permissions
  • Verify output path exists
"},{"location":"resources/available_tools/#future-tools","title":"Future Tools","text":""},{"location":"resources/available_tools/#music-compiler-planned","title":"Music Compiler (Planned)","text":"

A tool to convert music files or MIDI to PixelRoot32 MusicTrack format.

Planned Features:

  • MIDI to MusicTrack conversion
  • Visual music editor
  • Instrument preset management
  • Export to C++ header files
"},{"location":"resources/available_tools/#tilemap-compiler-planned","title":"Tilemap Compiler (Planned)","text":"

A tool to create tilemaps from image files or tile editors.

Planned Features:

  • Image to tilemap conversion
  • Tile editor integration
  • Export to C++ arrays
  • Collision data generation
"},{"location":"resources/available_tools/#other-planned-tools","title":"Other Planned Tools","text":"
  • Save System Generator: Generate save/load code
  • Asset Packer: Bundle assets for distribution
  • Performance Profiler: Analyze game performance
"},{"location":"resources/available_tools/#using-tools-in-development","title":"Using Tools in Development","text":""},{"location":"resources/available_tools/#workflow-integration","title":"Workflow Integration","text":"

Typical Workflow:

  1. Create/edit sprites in image editor
  2. Compile sprites to C++ headers
  3. Include headers in project
  4. Use sprites in code

Automation:

# Build script example\n#!/bin/bash\npr32-sprite-compiler assets/sprites/*.png --output-dir src/sprites/\n# Continue with build...\n
"},{"location":"resources/available_tools/#best-practices","title":"Best Practices","text":"
  • Organize assets: Keep source images separate from generated code
  • Version control: Commit generated headers, not source images (or both)
  • Naming conventions: Use consistent naming for sprites
  • Batch processing: Process multiple sprites at once when possible
"},{"location":"resources/available_tools/#see-also","title":"See Also","text":"
  • Sprite Compiler Documentation - Detailed sprite compiler guide
  • Manual - Sprites and Animation - Using sprites in games
  • Troubleshooting - Common tool issues

Note: Tool availability may vary. Check the PixelRoot32 repository for the latest tool information.

"},{"location":"resources/faq/","title":"Frequently Asked Questions","text":"

Common questions about PixelRoot32, organized by category.

"},{"location":"resources/faq/#general","title":"General","text":""},{"location":"resources/faq/#what-is-pixelroot32","title":"What is PixelRoot32?","text":"

PixelRoot32 is a lightweight, modular 2D game engine designed for ESP32 microcontrollers. It provides a complete game development framework with rendering, audio, physics, input, and UI systems, optimized for limited hardware resources.

"},{"location":"resources/faq/#what-platforms-does-it-support","title":"What platforms does it support?","text":"
  • ESP32: Primary platform (TFT displays, GPIO buttons, DAC/I2S audio)
  • Native/Desktop: Development platform (SDL2, keyboard, SDL2 audio)
"},{"location":"resources/faq/#what-kind-of-games-can-i-make","title":"What kind of games can I make?","text":"

PixelRoot32 is ideal for: - Retro/arcade-style games - 2D platformers - Shooters - Puzzle games - Simple RPGs - Educational games

See Limitations and Considerations for what's not suitable.

"},{"location":"resources/faq/#is-it-free-to-use","title":"Is it free to use?","text":"

Yes, PixelRoot32 is open source and licensed under the MIT License. You can use it freely for personal and commercial projects.

"},{"location":"resources/faq/#where-can-i-find-the-source-code","title":"Where can I find the source code?","text":"
  • Engine: https://github.com/Gperez88/PixelRoot32-Game-Engine
  • Samples: https://github.com/Gperez88/PixelRoot32-Game-Samples
  • Documentation: https://github.com/PixelRoot32-Game-Engine/PixelRoot32-Docs
"},{"location":"resources/faq/#installation-and-configuration","title":"Installation and Configuration","text":""},{"location":"resources/faq/#how-do-i-install-pixelroot32","title":"How do I install PixelRoot32?","text":"

See Your First Project for detailed installation instructions.

Quick answer: 1. Install PlatformIO in VS Code 2. Create new ESP32 project 3. Add library dependency: gperez88/PixelRoot32-Game-Engine@0.2.0-dev 4. Configure hardware in platformio.ini

"},{"location":"resources/faq/#what-version-should-i-use","title":"What version should I use?","text":"

Use the exact version 0.2.0-dev. Do NOT use ^ or fuzzy versioning, as the API may change.

"},{"location":"resources/faq/#how-do-i-configure-my-display","title":"How do I configure my display?","text":"

Configure TFT_eSPI via build flags in platformio.ini. See Your First Project for examples.

"},{"location":"resources/faq/#how-do-i-set-up-audio","title":"How do I set up audio?","text":"

Choose an audio backend: - ESP32_DAC: Simple, one pin (GPIO 25 or 26) - ESP32_I2S: Higher quality, requires external DAC - SDL2_AudioBackend: For Native/PC development

See Audio for details.

"},{"location":"resources/faq/#development","title":"Development","text":""},{"location":"resources/faq/#how-do-i-create-a-scene","title":"How do I create a scene?","text":"

Inherit from pixelroot32::core::Scene and implement init(), update(), and draw(). See Scenes and Entities.

"},{"location":"resources/faq/#how-do-i-add-entities-to-a-scene","title":"How do I add entities to a scene?","text":"

Create entities and call addEntity() in init(). The scene manages them automatically.

"},{"location":"resources/faq/#whats-the-difference-between-entity-actor-and-physicsactor","title":"What's the difference between Entity, Actor, and PhysicsActor?","text":"
  • Entity: Base class, can be drawn and updated
  • Actor: Entity with collision detection
  • PhysicsActor: Actor with automatic physics (velocity, gravity, friction)

See Scenes and Entities for details.

"},{"location":"resources/faq/#how-do-i-handle-input","title":"How do I handle input?","text":"

Access InputManager through the engine:

auto& input = engine.getInputManager();\nif (input.isButtonPressed(Buttons::A)) {\n    // Handle input\n}\n

See Input and Control.

"},{"location":"resources/faq/#how-do-i-play-sounds","title":"How do I play sounds?","text":"

Create an AudioEvent and play it:

pixelroot32::audio::AudioEvent sound{};\nsound.type = pixelroot32::audio::WaveType::PULSE;\nsound.frequency = 800.0f;\nsound.duration = 0.1f;\nengine.getAudioEngine().playEvent(sound);\n

See Audio.

"},{"location":"resources/faq/#how-do-i-create-sprites","title":"How do I create sprites?","text":"

Define sprite data manually or use the Sprite Compiler tool. See Sprites and Animation.

"},{"location":"resources/faq/#can-i-use-images-instead-of-manual-sprite-data","title":"Can I use images instead of manual sprite data?","text":"

Yes, use the Sprite Compiler tool to convert PNG images to sprite data. See Available Tools.

"},{"location":"resources/faq/#performance","title":"Performance","text":""},{"location":"resources/faq/#why-is-my-game-running-slowly","title":"Why is my game running slowly?","text":"

Common causes: - Too many entities (MAX_ENTITIES = 32) - Too many draw calls - Expensive calculations in update() - Memory issues

See Performance Tuning for solutions.

"},{"location":"resources/faq/#what-fps-should-i-target","title":"What FPS should I target?","text":"

30-60 FPS is typical. Lower complexity games can achieve 60 FPS, more complex games may need to target 30 FPS.

"},{"location":"resources/faq/#how-do-i-optimize-my-game","title":"How do I optimize my game?","text":"
  • Use object pooling
  • Implement viewport culling
  • Reduce entity count
  • Cache calculations
  • Use tilemaps for backgrounds

See Performance Tuning.

"},{"location":"resources/faq/#memory","title":"Memory","text":""},{"location":"resources/faq/#why-do-i-get-out-of-memory-errors","title":"Why do I get \"out of memory\" errors?","text":"

ESP32 has limited RAM (~320KB). Solutions: - Use object pooling - Store data in flash (const/constexpr) - Reduce entity count - Avoid dynamic allocation

See Memory Management.

"},{"location":"resources/faq/#what-is-max_entities","title":"What is MAX_ENTITIES?","text":"

MAX_ENTITIES = 32 is a hard limit per scene. This includes all entities: actors, UI elements, particles, etc.

Solutions: - Use object pooling to reuse entities - Disable entities instead of removing - Combine multiple entities into one

"},{"location":"resources/faq/#how-do-i-check-available-memory","title":"How do I check available memory?","text":"
#ifdef PLATFORM_ESP32\nSerial.print(\"Free heap: \");\nSerial.println(ESP.getFreeHeap());\n#endif\n
"},{"location":"resources/faq/#hardware","title":"Hardware","text":""},{"location":"resources/faq/#which-esp32-board-should-i-use","title":"Which ESP32 board should I use?","text":"

Any ESP32 board works. Common choices: - ESP32-WROOM-32 - ESP32-WROVER (more RAM) - ESP32-DevKit

"},{"location":"resources/faq/#which-display-should-i-use","title":"Which display should I use?","text":"

Popular choices: - ST7789: 240x240, good quality - ST7735: 128x128, smaller/cheaper - ILI9341: 240x320, larger

See Platforms and Drivers.

"},{"location":"resources/faq/#how-many-buttons-do-i-need","title":"How many buttons do I need?","text":"

Minimum: 4 (UP, DOWN, LEFT, RIGHT) Recommended: 6 (add A and B buttons) More buttons can be added if needed.

"},{"location":"resources/faq/#can-i-use-analog-joysticks","title":"Can I use analog joysticks?","text":"

Not directly supported. You can read analog pins manually and convert to digital input, but the engine expects digital buttons.

"},{"location":"resources/faq/#troubleshooting","title":"Troubleshooting","text":""},{"location":"resources/faq/#my-display-is-blank-whats-wrong","title":"My display is blank. What's wrong?","text":"
  1. Check wiring connections
  2. Verify pin numbers in platformio.ini
  3. Lower SPI frequency
  4. Check display type matches hardware
  5. Verify power supply

See Troubleshooting.

"},{"location":"resources/faq/#buttons-dont-work-why","title":"Buttons don't work. Why?","text":"
  1. Check button wiring
  2. Verify pin numbers in InputConfig
  3. Check pull-up/pull-down resistors
  4. Ensure InputManager is being updated
  5. Test with isButtonDown() vs isButtonPressed()
"},{"location":"resources/faq/#audio-is-distorted-how-do-i-fix-it","title":"Audio is distorted. How do I fix it?","text":"
  1. Lower volume levels
  2. Reduce sample rate (try 11025 Hz)
  3. Check for too many simultaneous sounds
  4. Verify hardware connections
  5. Check power supply
"},{"location":"resources/faq/#game-crashes-randomly-whats-happening","title":"Game crashes randomly. What's happening?","text":"

Common causes: - Out of memory - Too many entities - Infinite loops - Stack overflow - Watchdog timeout

See Troubleshooting for debugging techniques.

"},{"location":"resources/faq/#advanced","title":"Advanced","text":""},{"location":"resources/faq/#can-i-extend-the-engine","title":"Can I extend the engine?","text":"

Yes, PixelRoot32 is designed to be extensible. You can: - Create custom display drivers - Create custom audio backends - Extend existing systems

See Extensibility.

"},{"location":"resources/faq/#can-i-use-3d-graphics","title":"Can I use 3D graphics?","text":"

No, PixelRoot32 is 2D-only. It's designed for sprite-based 2D games.

"},{"location":"resources/faq/#can-i-add-networking","title":"Can I add networking?","text":"

Not currently supported. The engine focuses on single-player games.

"},{"location":"resources/faq/#can-i-save-game-data","title":"Can I save game data?","text":"

Not currently supported. A save system is planned for future versions.

"},{"location":"resources/faq/#can-i-use-multiple-scenes-at-once","title":"Can I use multiple scenes at once?","text":"

Yes, use SceneManager to push/pop scenes. This is useful for menus and pause screens.

"},{"location":"resources/faq/#getting-help","title":"Getting Help","text":""},{"location":"resources/faq/#where-can-i-get-help","title":"Where can I get help?","text":"
  • Documentation: This documentation site
  • Examples: Study example games in the samples project
  • Discord: Community Discord server
  • GitHub: Open an issue for bugs
"},{"location":"resources/faq/#how-do-i-report-a-bug","title":"How do I report a bug?","text":"

Create a detailed bug report with: - Platform (ESP32 or Native) - Hardware details - Minimal reproduction code - Error messages - Expected vs actual behavior

"},{"location":"resources/faq/#can-i-contribute","title":"Can I contribute?","text":"

Yes! PixelRoot32 is open source. Check the main repository for contribution guidelines.

"},{"location":"resources/faq/#see-also","title":"See Also","text":"
  • Troubleshooting - Detailed problem solving
  • Limitations and Considerations - What the engine can/can't do
  • Getting Started - Start here if you're new
  • Manual - Complete development guides

Can't find your question? Check the Troubleshooting guide or ask on the Discord server.

"},{"location":"resources/limitations_and_considerations/","title":"Limitations and Considerations","text":"

This document honestly documents what PixelRoot32 can and cannot do, helping you make informed decisions about using the engine.

"},{"location":"resources/limitations_and_considerations/#hardware-limitations-esp32","title":"Hardware Limitations (ESP32)","text":""},{"location":"resources/limitations_and_considerations/#memory-constraints","title":"Memory Constraints","text":"

RAM: - Available: ~320KB total (varies by ESP32 model) - Heap: Limited and fragmented over time - Stack: ~8KB, avoid large stack allocations - Impact: Limits entity count, sprite data, and dynamic allocation

Flash: - Available: 4MB+ (varies by model) - Usage: Program code, sprite data, assets - Impact: Large games may approach limits

Recommendations: - Use object pooling - Store data in flash (const/constexpr) - Avoid dynamic allocation in game loop - Keep entity count low

"},{"location":"resources/limitations_and_considerations/#cpu-limitations","title":"CPU Limitations","text":"

Performance: - Clock Speed: 240MHz (typically) - Single-threaded: One core handles everything - Target FPS: 30-60 FPS (depends on complexity) - Frame Budget: ~16-33ms per frame at 60 FPS

Impact: - Complex games may struggle - Many entities reduce performance - Expensive calculations hurt FPS

Recommendations: - Optimize rendering - Reduce entity count - Cache calculations - Profile on hardware

"},{"location":"resources/limitations_and_considerations/#display-limitations","title":"Display Limitations","text":"

Supported Displays: - TFT displays via SPI (ST7735, ST7789, ILI9341, etc.) - Limited to SPI displays - Resolution typically 128x128 to 320x240

Constraints: - SPI communication speed limits - Display initialization complexity - Power consumption

"},{"location":"resources/limitations_and_considerations/#audio-limitations","title":"Audio Limitations","text":"

Hardware: - Internal DAC: Lower quality, simple setup - I2S: Higher quality, requires external DAC - Sample rates: 11025 Hz (DAC) or 22050 Hz (I2S)

Constraints: - 4 channels total (2 Pulse, 1 Triangle, 1 Noise) - Music uses one channel - Limited simultaneous sounds - Quality limited by hardware

"},{"location":"resources/limitations_and_considerations/#software-limitations","title":"Software Limitations","text":""},{"location":"resources/limitations_and_considerations/#entity-system","title":"Entity System","text":"

MAX_ENTITIES = 32 per scene - Hard limit, cannot be changed easily - Applies to all entities (actors, UI, particles, etc.) - Must manage entity count carefully

Workarounds: - Use object pooling - Reuse entities - Disable entities instead of removing - Combine multiple entities into one

"},{"location":"resources/limitations_and_considerations/#no-rtti-runtime-type-information","title":"No RTTI (Runtime Type Information)","text":"

Impact: - Cannot use dynamic_cast in most code - Type checking must be done manually - Limits polymorphism patterns

Alternatives: - Use virtual functions - Manual type checking - Tag-based systems

"},{"location":"resources/limitations_and_considerations/#no-exceptions-in-critical-code","title":"No Exceptions in Critical Code","text":"

Impact: - Cannot use try/catch in game loop - Error handling must be explicit - Crashes instead of exceptions

Best Practices: - Validate inputs - Check return values - Use assertions for debugging - Handle errors explicitly

"},{"location":"resources/limitations_and_considerations/#no-dynamic-allocation-in-game-loop","title":"No Dynamic Allocation in Game Loop","text":"

Impact: - Cannot use new/delete during gameplay - Must pre-allocate resources - Limits flexibility

Solutions: - Object pooling - Pre-allocation in init() - Static buffers - Fixed-size arrays

"},{"location":"resources/limitations_and_considerations/#no-advanced-features","title":"No Advanced Features","text":"

Not Supported: - 3D graphics - Shaders - Advanced physics (joints, constraints) - Networking - File system (ESP32) - Advanced audio effects

Focus: - 2D sprite-based games - Simple physics - Retro-style games - Embedded-friendly features

"},{"location":"resources/limitations_and_considerations/#experimental-features","title":"Experimental Features","text":""},{"location":"resources/limitations_and_considerations/#2bpp-sprites","title":"2bpp Sprites","text":"

Status: Experimental - Requires PIXELROOT32_ENABLE_2BPP_SPRITES flag - May have bugs or limitations - Not fully tested

Use with caution: - Test thoroughly - May change in future versions - Report issues if found

"},{"location":"resources/limitations_and_considerations/#4bpp-sprites","title":"4bpp Sprites","text":"

Status: Experimental - Requires PIXELROOT32_ENABLE_4BPP_SPRITES flag - More experimental than 2bpp - Higher memory usage

Use with caution: - Test extensively - Monitor memory usage - May be unstable

"},{"location":"resources/limitations_and_considerations/#scene-arena","title":"Scene Arena","text":"

Status: Experimental - Requires PIXELROOT32_ENABLE_SCENE_ARENA flag - Alternative memory management - May have bugs

Recommendations: - Use object pooling instead (more stable) - Test thoroughly if using - May be removed or changed

"},{"location":"resources/limitations_and_considerations/#unsupported-features-current","title":"Unsupported Features (Current)","text":""},{"location":"resources/limitations_and_considerations/#planned-but-not-available","title":"Planned but Not Available","text":"
  • u8g2 Driver: Alternative display driver (planned)
  • Music Compiler: Tool to convert music files (planned)
  • Tilemap Compiler: Tool to create tilemaps (planned)
  • Save System: Persistent storage system (planned)
  • Spatial Partitioning: Advanced collision optimization (planned)
"},{"location":"resources/limitations_and_considerations/#not-planned","title":"Not Planned","text":"
  • 3D Graphics: 2D-only engine
  • Networking: No network support
  • File System: No file I/O on ESP32
  • Advanced Audio: NES-like audio only
  • Scripting: No Lua/JavaScript support
"},{"location":"resources/limitations_and_considerations/#best-practices-for-esp32","title":"Best Practices for ESP32","text":""},{"location":"resources/limitations_and_considerations/#memory-management","title":"Memory Management","text":"
  • Pre-allocate: All resources in init()
  • Object pooling: Reuse entities
  • Flash storage: Use const/constexpr for data
  • Avoid strings: Use static buffers
  • Monitor usage: Check heap regularly
"},{"location":"resources/limitations_and_considerations/#performance","title":"Performance","text":"
  • Limit entities: Stay well below MAX_ENTITIES
  • Optimize rendering: Use culling, batching
  • Cache calculations: Avoid repeated work
  • Profile on hardware: PC performance \u2260 ESP32
"},{"location":"resources/limitations_and_considerations/#development","title":"Development","text":"
  • Test on hardware: Don't rely only on Native
  • Start simple: Add complexity gradually
  • Monitor memory: Watch for leaks
  • Optimize incrementally: Profile and optimize
"},{"location":"resources/limitations_and_considerations/#what-pixelroot32-is-good-for","title":"What PixelRoot32 IS Good For","text":"

\u2705 Retro-style 2D games \u2705 Arcade games \u2705 Puzzle games \u2705 Platformers \u2705 Shooters \u2705 Educational projects \u2705 Prototyping \u2705 Embedded game development

"},{"location":"resources/limitations_and_considerations/#what-pixelroot32-is-not-good-for","title":"What PixelRoot32 is NOT Good For","text":"

\u274c 3D games \u274c Complex physics simulations \u274c Large open worlds \u274c Games requiring many entities \u274c Games with complex graphics \u274c Network multiplayer \u274c Games requiring file I/O

"},{"location":"resources/limitations_and_considerations/#making-informed-decisions","title":"Making Informed Decisions","text":""},{"location":"resources/limitations_and_considerations/#before-starting-a-project","title":"Before Starting a Project","text":"
  1. Assess requirements: Does PixelRoot32 fit?
  2. Check limitations: Can you work within constraints?
  3. Plan architecture: Design around limitations
  4. Test early: Verify on hardware early
"},{"location":"resources/limitations_and_considerations/#if-limitations-are-a-problem","title":"If Limitations Are a Problem","text":"

Consider alternatives: - Full game engines (Unity, Godot) for complex games - Custom solutions for specific needs - Different hardware for more resources

Or work within limits: - Simplify game design - Optimize aggressively - Use creative solutions

"},{"location":"resources/limitations_and_considerations/#version-compatibility","title":"Version Compatibility","text":""},{"location":"resources/limitations_and_considerations/#current-version","title":"Current Version","text":"
  • Engine Version: 0.2.0-dev
  • API Stability: May change
  • Breaking Changes: Possible in future versions

Recommendations: - Pin exact version in platformio.ini - Don't use ^ or fuzzy versioning - Test after engine updates - Review changelog

"},{"location":"resources/limitations_and_considerations/#honest-assessment","title":"Honest Assessment","text":"

PixelRoot32 is designed for: - Simple to medium complexity games - Retro/arcade style - ESP32 hardware constraints - Rapid development

It is not designed for: - AAA game complexity - Modern graphics - Large-scale games - Unlimited resources

"},{"location":"resources/limitations_and_considerations/#see-also","title":"See Also","text":"
  • Memory Management - Working with memory limits
  • Performance Tuning - Optimizing performance
  • Troubleshooting - Solving problems
  • FAQ - Common questions

Remember: Understanding limitations helps you build better games within PixelRoot32's capabilities.

"},{"location":"resources/troubleshooting/","title":"Troubleshooting","text":"

This guide helps you diagnose and fix common issues when developing with PixelRoot32.

"},{"location":"resources/troubleshooting/#compilation-problems","title":"Compilation Problems","text":""},{"location":"resources/troubleshooting/#common-compilation-errors","title":"Common Compilation Errors","text":"

Error: Library not found

Solution: Ensure PixelRoot32-Game-Engine is properly installed\n- Check platformio.ini has correct lib_deps\n- Verify library version matches (use exact version, not ^)\n- Try: pio lib install\n

Error: Include file not found

Solution: Check include paths\n- Verify lib_extra_dirs in platformio.ini\n- Check that library is in lib/ directory\n- Ensure correct namespace (pixelroot32::)\n

Error: Undefined reference

Solution: Link missing libraries\n- Check all required libraries are listed\n- Verify TFT_eSPI is installed for ESP32\n- Check SDL2 is installed for Native builds\n

Error: Build flags not recognized

Solution: Verify build flag syntax\n- Use -D FLAG_NAME (not --define)\n- Check flag names are correct\n- Ensure flags are in correct environment section\n

"},{"location":"resources/troubleshooting/#configuration-issues","title":"Configuration Issues","text":"

Wrong display type: - Verify DisplayType matches your hardware - Check TFT_eSPI build flags match display - Test with different display types

Incorrect pin configuration: - Verify GPIO pins match your wiring - Check pin numbers in platformio.ini - Ensure pins aren't used by other peripherals

"},{"location":"resources/troubleshooting/#hardware-problems-esp32","title":"Hardware Problems (ESP32)","text":""},{"location":"resources/troubleshooting/#display-not-working","title":"Display Not Working","text":"

Symptoms: - Blank screen - Garbled display - No output

Solutions: 1. Check wiring: - Verify SPI connections (MOSI, SCLK, DC, RST) - Check power supply (3.3V or 5V as required) - Ensure ground connections

  1. Verify configuration:
  2. Check display type matches hardware
  3. Verify pin numbers in platformio.ini
  4. Test with known working configuration

  5. SPI frequency:

  6. Lower SPI frequency (try 20MHz instead of 40MHz)
  7. Some displays need slower speeds
  8. Check display datasheet for max frequency

  9. Display initialization:

  10. Try different rotation values
  11. Check display width/height settings
  12. Verify TFT_eSPI driver is correct
"},{"location":"resources/troubleshooting/#resolution-scaling-issues","title":"Resolution Scaling Issues","text":"

Symptoms: - Image is not scaled to full screen - Visual artifacts (jittery pixels) - Frame rate drops when scaling is enabled

Solutions: 1. Verify DisplayConfig: - Ensure physicalWidth and physicalHeight match your hardware resolution (e.g., 240x240). - Check that logicalWidth and logicalHeight are set correctly (e.g., 128x128). - Use displayConfig.needsScaling() to check if the engine thinks scaling is required.

  1. Check Scaling Performance:
  2. Enabling scaling is generally faster than native high resolution, but still has some overhead.
  3. Use the Debug Statistics Overlay to check CPU load.
  4. Ensure you are using integer-only coordinates for drawing.

  5. Visual Quality:

  6. The engine uses nearest-neighbor scaling. Some aspect ratios might look \"blocky\" or have uneven pixel sizes.
  7. For best results, use logical resolutions that are simple fractions of the physical resolution (e.g., 120x120 for a 240x240 screen).
"},{"location":"resources/troubleshooting/#buttons-not-responding","title":"Buttons Not Responding","text":"

Symptoms: - No input detected - Buttons don't trigger actions - Input feels laggy

Solutions: 1. Check wiring: - Verify button connections to GPIO pins - Check pull-up/pull-down resistors - Test buttons with multimeter

  1. Verify pin configuration:
  2. Check InputConfig pin numbers
  3. Ensure pins match hardware
  4. Verify pins aren't used elsewhere

  5. Input debouncing:

  6. Add hardware debouncing (capacitor)
  7. Check InputManager is being updated
  8. Verify input is read in update(), not draw()

  9. Button logic:

  10. Test with isButtonDown() vs isButtonPressed()
  11. Check button indices match configuration
  12. Verify input is accessed correctly
"},{"location":"resources/troubleshooting/#audio-not-working","title":"Audio Not Working","text":"

Symptoms: - No sound output - Distorted audio - Audio glitches

Solutions: 1. DAC Configuration: - Verify DAC pin (25 or 26 for ESP32) - Check sample rate (11025 Hz recommended) - Ensure audio backend is initialized

  1. I2S Configuration:
  2. Verify I2S pin connections (BCLK, LRCK, DOUT)
  3. Check external DAC is powered
  4. Verify I2S DAC is compatible

  5. Audio quality:

  6. Lower sample rate if distorted
  7. Reduce volume levels
  8. Check for too many simultaneous sounds
  9. Verify audio buffer size

  10. Hardware:

  11. Check speaker connections
  12. Verify amplifier is powered
  13. Test with different audio hardware
  14. Check audio cable connections
"},{"location":"resources/troubleshooting/#power-issues","title":"Power Issues","text":"

Symptoms: - ESP32 resets randomly - Display flickers - Unstable operation

Solutions: 1. Power supply: - Use adequate power supply (500mA+ recommended) - Check voltage is stable (3.3V) - Add decoupling capacitors

  1. Current draw:
  2. Display draws significant current
  3. Audio amplifier adds load
  4. Reduce brightness if possible

  5. Wiring:

  6. Use thick wires for power
  7. Keep power wires short
  8. Add capacitors near ESP32
"},{"location":"resources/troubleshooting/#performance-problems","title":"Performance Problems","text":""},{"location":"resources/troubleshooting/#low-fps","title":"Low FPS","text":"

Symptoms: - Game runs slowly - Laggy movement - Stuttering

Solutions: 1. Reduce entity count: - Limit active entities (MAX_ENTITIES = 32) - Disable off-screen entities - Use object pooling

  1. Optimize rendering:
  2. Use viewport culling
  3. Reduce draw calls
  4. Use tilemaps instead of individual sprites
  5. Limit sprite count

  6. Simplify logic:

  7. Cache expensive calculations
  8. Reduce collision checks
  9. Lower update frequency for non-critical entities

  10. Check hardware:

  11. Verify ESP32 is running at full speed (240MHz)
  12. Check for thermal throttling
  13. Ensure adequate power supply
"},{"location":"resources/troubleshooting/#frame-drops","title":"Frame Drops","text":"

Symptoms: - Occasional stuttering - Inconsistent frame times - Periodic freezes

Solutions: 1. Identify bottlenecks: - Profile frame time - Check for expensive operations - Look for blocking code

  1. Optimize update loop:
  2. Avoid dynamic allocation
  3. Cache calculations
  4. Reduce string operations

  5. Memory issues:

  6. Check for memory leaks
  7. Reduce memory usage
  8. Use object pooling
"},{"location":"resources/troubleshooting/#freezescrashes","title":"Freezes/Crashes","text":"

Symptoms: - Game stops responding - ESP32 resets - Watchdog resets

Solutions: 1. Memory issues: - Check available heap memory - Reduce entity count - Avoid dynamic allocation - Use object pooling

  1. Infinite loops:
  2. Check for infinite loops in update()
  3. Verify collision detection doesn't loop
  4. Check animation logic

  5. Stack overflow:

  6. Avoid large stack allocations
  7. Reduce recursion depth
  8. Move large data to heap (carefully)

  9. Watchdog:

  10. Ensure update() completes quickly
  11. Add yield() calls if needed
  12. Check for blocking operations
"},{"location":"resources/troubleshooting/#memory-problems","title":"Memory Problems","text":""},{"location":"resources/troubleshooting/#out-of-memory","title":"Out of Memory","text":"

Symptoms: - Compilation fails - Runtime crashes - \"Allocation failed\" errors

Solutions: 1. Reduce memory usage: - Use 1bpp sprites instead of 2bpp/4bpp - Store data in flash (const/constexpr) - Reduce entity count - Use object pooling

  1. Optimize data:
  2. Reuse sprites
  3. Compress tilemap data
  4. Remove unused code/data

  5. Memory management:

  6. Avoid dynamic allocation in game loop
  7. Pre-allocate all resources
  8. Use static buffers
"},{"location":"resources/troubleshooting/#memory-fragmentation","title":"Memory Fragmentation","text":"

Symptoms: - Gradual performance degradation - Allocation failures over time - Crashes after running for a while

Solutions: 1. Use object pooling: - Pre-allocate entities - Reuse objects instead of creating/destroying - Avoid frequent new/delete

  1. Pre-allocate resources:
  2. Allocate everything in init()
  3. Use fixed-size arrays
  4. Avoid dynamic containers
"},{"location":"resources/troubleshooting/#native-build-problems","title":"Native Build Problems","text":""},{"location":"resources/troubleshooting/#sdl2-not-found","title":"SDL2 Not Found","text":"

Symptoms: - Compilation fails - Linker errors - Missing SDL2 symbols

Solutions: 1. Install SDL2: - Windows (MSYS2): pacman -S mingw-w64-x86_64-SDL2 - Linux: sudo apt-get install libsdl2-dev - macOS: brew install sdl2

  1. Check paths:
  2. Verify include paths in platformio.ini
  3. Check library paths
  4. Ensure SDL2 version is compatible

  5. Linker flags:

  6. Verify -lSDL2 is in build flags
  7. Check library search paths
  8. Ensure SDL2 DLL is accessible (Windows)
"},{"location":"resources/troubleshooting/#window-not-opening","title":"Window Not Opening","text":"

Symptoms: - Program runs but no window - Console shows errors - Immediate exit

Solutions: 1. Check SDL2 initialization: - Verify SDL2 is properly initialized - Check for SDL2 error messages - Ensure display config is correct

  1. Graphics drivers:
  2. Update graphics drivers
  3. Check SDL2 video backend
  4. Test with simple SDL2 program

  5. Console output:

  6. Run from terminal to see errors
  7. Check for error messages
  8. Verify SDL2 is working
"},{"location":"resources/troubleshooting/#debugging-techniques","title":"Debugging Techniques","text":""},{"location":"resources/troubleshooting/#serial-debugging-esp32","title":"Serial Debugging (ESP32)","text":"
void setup() {\n    Serial.begin(115200);\n    // ... initialization\n\n    Serial.println(\"Engine initialized\");\n}\n\nvoid update(unsigned long deltaTime) override {\n    // Debug output\n    if (frameCount % 60 == 0) {\n        Serial.print(\"FPS: \");\n        Serial.println(1000.0f / deltaTime);\n    }\n    frameCount++;\n}\n
"},{"location":"resources/troubleshooting/#memory-monitoring","title":"Memory Monitoring","text":"
#ifdef PLATFORM_ESP32\n#include <Arduino.h>\n\nvoid checkMemory() {\n    Serial.print(\"Free heap: \");\n    Serial.println(ESP.getFreeHeap());\n    Serial.print(\"Largest block: \");\n    Serial.println(ESP.getMaxAllocHeap());\n}\n#endif\n
"},{"location":"resources/troubleshooting/#performance-profiling","title":"Performance Profiling","text":"
class Profiler {\nprivate:\n    unsigned long updateTime = 0;\n    unsigned long drawTime = 0;\n\npublic:\n    void startUpdate() {\n        updateTime = micros();\n    }\n\n    void endUpdate() {\n        updateTime = micros() - updateTime;\n    }\n\n    void log() {\n        Serial.print(\"Update: \");\n        Serial.print(updateTime);\n        Serial.print(\"us, Draw: \");\n        Serial.println(drawTime);\n    }\n};\n
"},{"location":"resources/troubleshooting/#visual-debugging","title":"Visual Debugging","text":"
  • Draw hitboxes: Visualize collision boxes
  • Show FPS: Display frame rate on screen
  • Entity count: Show active entity count
  • Memory usage: Display memory statistics
"},{"location":"resources/troubleshooting/#common-patterns-for-debugging","title":"Common Patterns for Debugging","text":""},{"location":"resources/troubleshooting/#isolate-the-problem","title":"Isolate the Problem","text":"
  1. Minimal reproduction: Create smallest code that shows issue
  2. Disable features: Turn off systems one by one
  3. Test incrementally: Add features back one at a time
"},{"location":"resources/troubleshooting/#check-the-basics","title":"Check the Basics","text":"
  1. Verify initialization: Ensure engine.init() is called
  2. Check scene setup: Verify scene is set and initialized
  3. Test on both platforms: Compare ESP32 vs Native behavior
  4. Review recent changes: What changed before the issue?
"},{"location":"resources/troubleshooting/#use-logging","title":"Use Logging","text":"
#define DEBUG_MODE\n\n#ifdef DEBUG_MODE\n    #define DEBUG_LOG(x) Serial.println(x)\n#else\n    #define DEBUG_LOG(x)\n#endif\n\n// Usage\nDEBUG_LOG(\"Entity created\");\nDEBUG_LOG(\"Collision detected\");\n
"},{"location":"resources/troubleshooting/#getting-help","title":"Getting Help","text":"

If you can't resolve an issue:

  1. Check documentation: Review relevant guides
  2. Search examples: Look at example games
  3. Review code: Check engine source code
  4. Community: Ask on Discord or GitHub
  5. Report issue: Create detailed bug report
"},{"location":"resources/troubleshooting/#bug-report-template","title":"Bug Report Template","text":"

When reporting issues, include:

  • Platform: ESP32 or Native
  • Hardware: Display type, ESP32 model
  • Code: Minimal reproduction code
  • Error messages: Full error output
  • Expected behavior: What should happen
  • Actual behavior: What actually happens
  • Steps to reproduce: How to trigger the issue
"},{"location":"resources/troubleshooting/#see-also","title":"See Also","text":"
  • Limitations and Considerations - Known limitations
  • Performance Tuning - Performance optimization
  • Memory Management - Memory optimization
  • FAQ - Frequently asked questions

Note: Many issues are configuration-related. Double-check your setup before assuming a bug.

"},{"location":"tools/sprite_compiler/advanced_features/","title":"Sprite Compiler Advanced Features","text":"

Advanced features and options for the PixelRoot32 Sprite Compiler to optimize sprite conversion and handle complex scenarios.

"},{"location":"tools/sprite_compiler/advanced_features/#automatic-palette-detection","title":"Automatic Palette Detection","text":"

The Sprite Compiler automatically detects if your sprite uses one of the engine's built-in palettes. This simplifies your workflow and ensures color consistency.

"},{"location":"tools/sprite_compiler/advanced_features/#predefined-engine-palettes","title":"Predefined Engine Palettes","text":"

The engine includes 5 optimized palettes: - PR32 (Default PixelRoot32 palette) - NES (Nintendo style) - GB (GameBoy style) - GBC (GameBoy Color style) - PICO8 (Fantasy console style)

"},{"location":"tools/sprite_compiler/advanced_features/#how-it-works","title":"How it works","text":"
  1. Detection: When you compile an image, the tool compares all unique colors found in the sprite with the colors in the 5 engine palettes.
  2. Match: If all colors in your sprite belong to one of these palettes, the compiler:
  3. Omits generating a color array in the header.
  4. Assumes you will use the engine's built-in palette definitions at runtime.
  5. Custom Palette: If your sprite uses colors not found in the engine palettes, it automatically generates a {PREFIX}_PALETTE_MAPPING[16] array in the header file.
"},{"location":"tools/sprite_compiler/advanced_features/#naming-with-prefixes","title":"Naming with Prefixes","text":"

You can organize your generated code by using the --prefix parameter (or the Prefix field in the GUI).

"},{"location":"tools/sprite_compiler/advanced_features/#using-prefixes","title":"Using Prefixes","text":"

By default, sprites are named SPRITE_N_.... Using a prefix allows you to create more descriptive names and avoid naming collisions.

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --prefix PLAYER_JUM\n

Generated names will follow this pattern: - PLAYER_JUM_SPRITE_0_LAYER_0 - PLAYER_JUM_SPRITE_0_2BPP - PLAYER_JUM_SPRITE_0_4BPP - PLAYER_JUM_PALETTE_MAPPING (if a custom palette is used)

"},{"location":"tools/sprite_compiler/advanced_features/#export-modes","title":"Export Modes","text":""},{"location":"tools/sprite_compiler/advanced_features/#layered-1bpp","title":"Layered (1bpp)","text":"

Best for standard PixelRoot32 rendering. It extracts each color into its own bitmask (1bpp). The engine then renders these layers sequentially.

"},{"location":"tools/sprite_compiler/advanced_features/#packed-2bpp-4bpp","title":"Packed (2bpp / 4bpp)","text":"

Generates a single packed array where each pixel uses multiple bits. - 2bpp: 4 colors max (Index 0 is always transparent). - 4bpp: 16 colors max (Index 0 is always transparent).

These modes are more efficient for sprites with many colors as they require only a single draw call.

"},{"location":"tools/sprite_compiler/installation/","title":"Sprite Compiler Installation","text":"

This guide walks you through installing the PixelRoot32 Sprite Compiler on your system.

"},{"location":"tools/sprite_compiler/installation/#prerequisites","title":"Prerequisites","text":""},{"location":"tools/sprite_compiler/installation/#required-software","title":"Required Software","text":"
  • Python: Version 3.8 or higher
  • pip: Usually included with Python
"},{"location":"tools/sprite_compiler/installation/#verify-prerequisites","title":"Verify Prerequisites","text":"

Check if Python is installed:

python --version\n# Should show 3.8.0 or higher\n

Check if pip is installed:

pip --version\n# Should show version number\n

If not installed, download from python.org

"},{"location":"tools/sprite_compiler/installation/#installation-methods","title":"Installation Methods","text":""},{"location":"tools/sprite_compiler/installation/#method-1-from-source-recommended","title":"Method 1: From Source (Recommended)","text":""},{"location":"tools/sprite_compiler/installation/#step-1-clone-repository","title":"Step 1: Clone Repository","text":"
git clone https://github.com/Gperez88/PixelRoot32-Sprite-Compiler.git\ncd PixelRoot32-Sprite-Compiler\n
"},{"location":"tools/sprite_compiler/installation/#step-2-install-dependencies","title":"Step 2: Install Dependencies","text":"
pip install -r requirements.txt\n
"},{"location":"tools/sprite_compiler/installation/#step-3-verify-installation","title":"Step 3: Verify Installation","text":"
python main.py --help\n
"},{"location":"tools/sprite_compiler/installation/#method-2-standalone-executable-windows","title":"Method 2: Standalone Executable (Windows)","text":"

If you are on Windows, you can download the latest standalone .exe from the Releases section of the repository. This does not require Python or any dependencies to be installed.

"},{"location":"tools/sprite_compiler/installation/#platform-specific-instructions","title":"Platform-Specific Instructions","text":""},{"location":"tools/sprite_compiler/installation/#windows","title":"Windows","text":""},{"location":"tools/sprite_compiler/installation/#using-npm-recommended","title":"Using npm (Recommended)","text":"
  1. Install Node.js from nodejs.org
  2. Download the Windows installer
  3. Run the installer
  4. Restart your terminal/command prompt

  5. Open Command Prompt or PowerShell

  6. Install globally:

    npm install -g pr32-sprite-compiler\n

  7. Verify:

    pr32-sprite-compiler --version\n

"},{"location":"tools/sprite_compiler/installation/#troubleshooting-windows-issues","title":"Troubleshooting Windows Issues","text":"

\"pr32-sprite-compiler is not recognized\": - Ensure Node.js is in your PATH - Restart terminal after installation - Try using full path: C:\\Users\\YourName\\AppData\\Roaming\\npm\\pr32-sprite-compiler.cmd

Permission errors: - Run terminal as Administrator - Or install locally: npm install pr32-sprite-compiler (without -g)

"},{"location":"tools/sprite_compiler/installation/#linux","title":"Linux","text":""},{"location":"tools/sprite_compiler/installation/#using-npm","title":"Using npm","text":"
  1. Install Node.js (if not already installed):

Ubuntu/Debian:

curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -\nsudo apt-get install -y nodejs\n

Fedora/RHEL:

sudo dnf install nodejs npm\n

  1. Install Sprite Compiler:

    sudo npm install -g pr32-sprite-compiler\n

  2. Verify:

    pr32-sprite-compiler --version\n

"},{"location":"tools/sprite_compiler/installation/#troubleshooting-linux-issues","title":"Troubleshooting Linux Issues","text":"

Permission denied: - Use sudo for global installation - Or install locally without -g flag

Command not found: - Check npm global bin path: npm config get prefix - Add to PATH if needed: export PATH=$PATH:$(npm config get prefix)/bin

"},{"location":"tools/sprite_compiler/installation/#macos","title":"macOS","text":""},{"location":"tools/sprite_compiler/installation/#using-npm_1","title":"Using npm","text":"
  1. Install Node.js:
  2. Download from nodejs.org
  3. Or use Homebrew: brew install node

  4. Install Sprite Compiler:

    npm install -g pr32-sprite-compiler\n

  5. Verify:

    pr32-sprite-compiler --version\n

"},{"location":"tools/sprite_compiler/installation/#using-homebrew-alternative","title":"Using Homebrew (Alternative)","text":"

If available as a Homebrew formula:

brew install pr32-sprite-compiler\n

"},{"location":"tools/sprite_compiler/installation/#gui-version-installation","title":"GUI Version Installation","text":"

If a GUI version is available:

"},{"location":"tools/sprite_compiler/installation/#windows_1","title":"Windows","text":"

Download the installer from the releases page and run it.

"},{"location":"tools/sprite_compiler/installation/#linux_1","title":"Linux","text":"
# Download AppImage or .deb package\n# Make executable and run\nchmod +x pr32-sprite-compiler-gui.AppImage\n./pr32-sprite-compiler-gui.AppImage\n
"},{"location":"tools/sprite_compiler/installation/#macos_1","title":"macOS","text":"

Download the .dmg file from releases and install.

"},{"location":"tools/sprite_compiler/installation/#verification","title":"Verification","text":"

After installation, verify everything works:

"},{"location":"tools/sprite_compiler/installation/#test-basic-functionality","title":"Test Basic Functionality","text":"
  1. Create a test image:
  2. Create an 8x8 pixel PNG image (black and white)
  3. Save as test.png

  4. Run compiler:

    pr32-sprite-compiler test.png test_output.h\n

  5. Check output:

  6. File test_output.h should be created
  7. Should contain sprite data arrays
"},{"location":"tools/sprite_compiler/installation/#check-version","title":"Check Version","text":"
pr32-sprite-compiler --version\n
"},{"location":"tools/sprite_compiler/installation/#check-help","title":"Check Help","text":"
pr32-sprite-compiler --help\n
"},{"location":"tools/sprite_compiler/installation/#updating","title":"Updating","text":""},{"location":"tools/sprite_compiler/installation/#update-via-npm","title":"Update via npm","text":"
npm update -g pr32-sprite-compiler\n
"},{"location":"tools/sprite_compiler/installation/#update-from-source","title":"Update from Source","text":"
cd pr32-sprite-compiler\ngit pull\nnpm install\n
"},{"location":"tools/sprite_compiler/installation/#uninstallation","title":"Uninstallation","text":""},{"location":"tools/sprite_compiler/installation/#remove-global-installation","title":"Remove Global Installation","text":"
npm uninstall -g pr32-sprite-compiler\n
"},{"location":"tools/sprite_compiler/installation/#remove-local-installation","title":"Remove Local Installation","text":"
npm uninstall pr32-sprite-compiler\n
"},{"location":"tools/sprite_compiler/installation/#troubleshooting","title":"Troubleshooting","text":""},{"location":"tools/sprite_compiler/installation/#common-issues","title":"Common Issues","text":"

\"Command not found\" after installation: - Restart your terminal - Check npm global bin path: npm config get prefix - Verify PATH includes npm bin directory

Permission errors: - On Linux/macOS: Use sudo for global install - Or install locally without -g flag - On Windows: Run terminal as Administrator

Module not found errors: - Reinstall: npm install -g pr32-sprite-compiler - Clear npm cache: npm cache clean --force

Version conflicts: - Check Node.js version: node --version - Update Node.js if version is too old - Use nvm (Node Version Manager) to manage versions

"},{"location":"tools/sprite_compiler/installation/#getting-help","title":"Getting Help","text":"
  • Check the Usage Guide for usage examples
  • Review Troubleshooting for common issues
  • Open an issue on GitHub if problems persist
"},{"location":"tools/sprite_compiler/installation/#next-steps","title":"Next Steps","text":"

Once installed, proceed to: - Usage Guide - Learn how to use the compiler - Advanced Features - Explore advanced options

"},{"location":"tools/sprite_compiler/installation/#see-also","title":"See Also","text":"
  • Overview - What the Sprite Compiler does
  • Available Tools - All PixelRoot32 tools
"},{"location":"tools/sprite_compiler/overview/","title":"Sprite Compiler Overview","text":"

The Sprite Compiler is a tool that converts PNG images into PixelRoot32 sprite data formats. It provides both a graphical interface (GUI) and a command-line interface (CLI) to automate the process of creating sprite arrays from image files.

"},{"location":"tools/sprite_compiler/overview/#what-it-does","title":"What It Does","text":"

The Sprite Compiler takes bitmap images (PNG) and converts them into C header files containing:

  • Sprite data arrays: Optimized uint16_t arrays for various formats.
  • Layered support: Generates multiple 1bpp layers for complex sprites.
  • Packed formats: Supports 2bpp and 4bpp packed formats.
  • Sprite sheets: Handles grid-based sprite sheets with auto-detection.
"},{"location":"tools/sprite_compiler/overview/#key-features","title":"Key Features","text":""},{"location":"tools/sprite_compiler/overview/#format-support","title":"\u2705 Format Support","text":"
  • Layered (1bpp): Standard format, generates one array per color.
  • 2bpp (4 colors): Packed format, 2 bits per pixel.
  • 4bpp (16 colors): Packed format, 4 bits per pixel.
"},{"location":"tools/sprite_compiler/overview/#gui-cli","title":"\u2705 GUI & CLI","text":"
  • Modern GUI: Step-by-step card-based interface for easy configuration.
  • Powerful CLI: Perfect for build scripts and automation.
"},{"location":"tools/sprite_compiler/overview/#sprite-sheets","title":"\u2705 Sprite Sheets","text":"

Automatically split sprite sheets into individual sprites:

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --sprite 1,0,1,1 --out output.h\n

"},{"location":"tools/sprite_compiler/overview/#gui-interface","title":"GUI Interface","text":"

The GUI is designed to be intuitive and follows a 5-step process:

  1. Input Image: Select your PNG source.
  2. Grid Settings: Define the cell size and offsets.
  3. Sprite Selection: Pick which cells to export.
  4. Export Settings: Choose the mode (Layered, 2bpp, 4bpp), set a Prefix, and choose the output path.
  5. About: Quick access to version info and credits (via the ? button).
  6. Log: Technical feedback and performance alerts.
"},{"location":"tools/sprite_compiler/overview/#input-requirements","title":"Input Requirements","text":""},{"location":"tools/sprite_compiler/overview/#supported-formats","title":"Supported Formats","text":"
  • PNG: Primary format (recommended)
  • Indexed color PNG: Best for 1bpp conversion
  • Grayscale PNG: Automatically converted to 1bpp
  • RGB PNG: Converted using threshold or palette
"},{"location":"tools/sprite_compiler/overview/#image-constraints","title":"Image Constraints","text":"

For 1bpp sprites: - Maximum width: 16 pixels - Height: Any (typically 8, 16, 32 pixels) - Colors: Black and white (or converted automatically)

For 2bpp sprites: - Maximum width: 16 pixels - Colors: Up to 4 colors

For 4bpp sprites: - Maximum width: 16 pixels - Colors: Up to 16 colors

"},{"location":"tools/sprite_compiler/overview/#output-format","title":"Output Format","text":"

The compiler generates C header files with optimized arrays:

// Generated by PixelRoot32 Sprite Compiler\n\n// Optional palette mapping if using custom colors\nstatic const Color PLAYER_PALETTE_MAPPING[16] = {\n    (Color)0, (Color)1, (Color)2, (Color)3,\n    // ...\n};\n\n// Sprite data array (4bpp example)\nstatic const uint16_t PLAYER_SPRITE_0_4BPP[] = {\n    0x0000, 0x1234, 0x5678, // Row 0\n    // ... more rows\n};\n
"},{"location":"tools/sprite_compiler/overview/#use-cases","title":"Use Cases","text":""},{"location":"tools/sprite_compiler/overview/#1-single-sprite-conversion","title":"1. Single Sprite Conversion","text":"

Convert a single image to a sprite:

pr32-sprite-compiler player.png player_sprite.h --name PLAYER_SPRITE\n

"},{"location":"tools/sprite_compiler/overview/#2-animation-frames","title":"2. Animation Frames","text":"

Convert multiple frames for animation:

pr32-sprite-compiler --batch walk_*.png --output-dir animations/ --prefix WALK_\n

"},{"location":"tools/sprite_compiler/overview/#3-sprite-sheet-processing","title":"3. Sprite Sheet Processing","text":"

Split a sprite sheet into individual sprites:

pr32-sprite-compiler characters.png output.h --sheet 16x16 --count 8\n

"},{"location":"tools/sprite_compiler/overview/#4-batch-asset-processing","title":"4. Batch Asset Processing","text":"

Process entire asset directories:

pr32-sprite-compiler --batch assets/sprites/*.png --output-dir src/sprites/\n

"},{"location":"tools/sprite_compiler/overview/#workflow-integration","title":"Workflow Integration","text":""},{"location":"tools/sprite_compiler/overview/#typical-development-workflow","title":"Typical Development Workflow","text":"
  1. Create sprites in your image editor (Aseprite, Piskel, GIMP, etc.)
  2. Save as PNG with appropriate dimensions
  3. Run compiler to generate header files
  4. Include headers in your PixelRoot32 project
  5. Use sprites in your game code
"},{"location":"tools/sprite_compiler/overview/#automation-example","title":"Automation Example","text":"
#!/bin/bash\n# build-sprites.sh\n\n# Compile all sprites\npr32-sprite-compiler assets/sprites/*.png --output-dir src/sprites/\n\n# Continue with your build process\nplatformio run\n
"},{"location":"tools/sprite_compiler/overview/#advantages-over-manual-creation","title":"Advantages Over Manual Creation","text":""},{"location":"tools/sprite_compiler/overview/#time-saving","title":"\u2705 Time Saving","text":"
  • No manual bit pattern conversion
  • Automatic format optimization
  • Batch processing multiple sprites
"},{"location":"tools/sprite_compiler/overview/#accuracy","title":"\u2705 Accuracy","text":"
  • Correct bit ordering
  • Proper array formatting
  • Valid C++ syntax
"},{"location":"tools/sprite_compiler/overview/#consistency","title":"\u2705 Consistency","text":"
  • Uniform naming conventions
  • Standardized output format
  • Consistent code structure
"},{"location":"tools/sprite_compiler/overview/#maintainability","title":"\u2705 Maintainability","text":"
  • Easy to regenerate from source images
  • Version control friendly
  • Clear separation of assets and code
"},{"location":"tools/sprite_compiler/overview/#limitations","title":"Limitations","text":"
  • Width limit: 16 pixels for 1bpp (hardware constraint)
  • Color depth: Limited by format (1bpp = 2 colors, 2bpp = 4 colors, etc.)
  • File format: Primarily PNG (other formats may require conversion)
"},{"location":"tools/sprite_compiler/overview/#next-steps","title":"Next Steps","text":"
  • Installation Guide - Set up the compiler
  • Usage Guide - Learn how to use it
  • Advanced Features - Explore advanced options
"},{"location":"tools/sprite_compiler/overview/#see-also","title":"See Also","text":"
  • Manual - Sprites and Animation - Using sprites in games
  • Code Examples - Sprites - Sprite usage examples
  • Available Tools - All PixelRoot32 tools
"},{"location":"tools/sprite_compiler/usage_guide/","title":"Sprite Compiler Usage Guide","text":"

Complete guide to using the PixelRoot32 Sprite Compiler for converting images to sprite data.

"},{"location":"tools/sprite_compiler/usage_guide/#basic-usage","title":"Basic Usage","text":""},{"location":"tools/sprite_compiler/usage_guide/#launching-the-gui","title":"Launching the GUI","text":"

The easiest way to use the compiler is via the Graphical User Interface (GUI).

python main.py\n

This will open the application where you can interactively load images, configure the grid, and export sprites.

"},{"location":"tools/sprite_compiler/usage_guide/#command-line-interface-cli","title":"Command Line Interface (CLI)","text":"

For automation, you can use the CLI mode by passing arguments to the script.

python main.py [input] [options]\n

Required:

  • input: Input PNG image file
  • --grid WxH: Grid cell size (e.g., 16x16)
  • --sprite gx,gy,gw,gh: Sprite definition (can be repeated)

Optional:

  • --prefix NAME: Prefix for generated arrays (e.g., PLAYER_JUM)
  • --out FILE: Output header file (default: sprites.h)
  • --offset X,Y: Initial offset in pixels (default: 0,0)
  • --mode MODE: Export mode (layered, 2bpp, 4bpp)
"},{"location":"tools/sprite_compiler/usage_guide/#cli-examples","title":"CLI Examples","text":""},{"location":"tools/sprite_compiler/usage_guide/#simple-conversion","title":"Simple Conversion","text":"

Convert a single 16x16 sprite located at the top-left corner:

python main.py player.png --grid 16x16 --sprite 0,0,1,1 --out player.h\n
"},{"location":"tools/sprite_compiler/usage_guide/#multiple-sprites","title":"Multiple Sprites","text":"

Convert multiple sprites from a single sheet:

python main.py sheet.png --grid 16x16 \\\n  --sprite 0,0,1,1 \\\n  --sprite 1,0,1,1 \\\n  --sprite 2,0,1,1 \\\n  --out animations.h\n
"},{"location":"tools/sprite_compiler/usage_guide/#export-modes","title":"Export Modes","text":"

Layered (Default): Generates multiple uint16_t arrays, one for each color layer. Best for standard PixelRoot32 rendering.

python main.py icon.png --grid 16x16 --sprite 0,0,1,1 --mode layered\n

Packed 2bpp: Generates a single array with 2 bits per pixel (4 colors max).

python main.py icon.png --grid 16x16 --sprite 0,0,1,1 --mode 2bpp\n
"},{"location":"tools/sprite_compiler/usage_guide/#step-by-step-examples","title":"Step-by-Step Examples","text":""},{"location":"tools/sprite_compiler/usage_guide/#example-1-simple-player-sprite","title":"Example 1: Simple Player Sprite","text":"

Step 1: Create Image

  • Create an 8x8 pixel PNG image
  • Use black and white colors
  • Save as player.png

Step 2: Compile

python main.py player.png --grid 8x8 --sprite 0,0,1,1 --prefix PLAYER --out player_sprite.h\n

Step 3: Use in Code

#include \"player_sprite.h\"\n\nvoid draw() {\n    // PLAYER_SPRITE_0_LAYER_0 is generated automatically\n    renderer.drawSprite(PLAYER_SPRITE_0_LAYER_0, 100, 100, Color::White);\n}\n
"},{"location":"tools/sprite_compiler/usage_guide/#example-2-multiple-animation-frames","title":"Example 2: Multiple Animation Frames","text":"

Step 1: Prepare Images

  • Create frames: walk_0.png, walk_1.png, walk_2.png
  • All same size (e.g., 16x16)

Step 2: Batch Compile

pr32-sprite-compiler --batch walk_*.png --output-dir animations/ --prefix WALK_\n

Step 3: Use in Animation

#include \"animations/walk_0.h\"\n#include \"animations/walk_1.h\"\n#include \"animations/walk_2.h\"\n\nconst Sprite* WALK_FRAMES[] = {\n    &WALK_0_SPRITE,\n    &WALK_1_SPRITE,\n    &WALK_2_SPRITE\n};\n
"},{"location":"tools/sprite_compiler/usage_guide/#example-3-sprite-sheet","title":"Example 3: Sprite Sheet","text":"

Step 1: Create Sprite Sheet

  • Create a 64x64 image with 4x4 grid of 16x16 sprites
  • Save as characters.png

Step 2: Split Sheet

pr32-sprite-compiler characters.png characters.h --sheet 16x16 --count 16\n

Step 3: Use Individual Sprites

#include \"characters.h\"\n\n// Sprites named CHARACTER_0, CHARACTER_1, etc.\nrenderer.drawSprite(CHARACTER_0, 50, 50, Color::White);\nrenderer.drawSprite(CHARACTER_1, 70, 50, Color::White);\n
"},{"location":"tools/sprite_compiler/usage_guide/#batch-processing","title":"Batch Processing","text":""},{"location":"tools/sprite_compiler/usage_guide/#process-multiple-files","title":"Process Multiple Files","text":"

Process all PNG files in a directory:

pr32-sprite-compiler --batch sprites/*.png --output-dir generated/\n
"},{"location":"tools/sprite_compiler/usage_guide/#with-options","title":"With Options","text":"

Apply options to all files:

pr32-sprite-compiler --batch assets/*.png \\\n    --output-dir src/sprites/ \\\n    --format 1bpp \\\n    --prefix SPRITE_\n
"},{"location":"tools/sprite_compiler/usage_guide/#recursive-processing","title":"Recursive Processing","text":"

Process subdirectories:

pr32-sprite-compiler --batch assets/**/*.png --output-dir generated/\n
"},{"location":"tools/sprite_compiler/usage_guide/#sprite-sheets","title":"Sprite Sheets","text":""},{"location":"tools/sprite_compiler/usage_guide/#automatic-splitting","title":"Automatic Splitting","text":"

Split a sprite sheet into individual sprites:

pr32-sprite-compiler sheet.png output.h --sheet 8x8 --count 16\n

Parameters:

  • --sheet WxH: Tile size (width x height)
  • --count N: Number of sprites in sheet
"},{"location":"tools/sprite_compiler/usage_guide/#grid-layout","title":"Grid Layout","text":"

Specify grid dimensions:

pr32-sprite-compiler sheet.png output.h \\\n    --sheet 16x16 \\\n    --grid 4x4 \\\n    --count 16\n

Parameters:

  • --grid WxH: Grid dimensions (columns x rows)
"},{"location":"tools/sprite_compiler/usage_guide/#custom-naming","title":"Custom Naming","text":"

Name sprites with index:

pr32-sprite-compiler sheet.png output.h \\\n    --sheet 8x8 \\\n    --count 8 \\\n    --prefix CHARACTER_ \\\n    --indexed\n

Generates: CHARACTER_0, CHARACTER_1, etc.

"},{"location":"tools/sprite_compiler/usage_guide/#custom-palettes","title":"Custom Palettes","text":""},{"location":"tools/sprite_compiler/usage_guide/#using-palette-file","title":"Using Palette File","text":"

Convert with custom color palette:

pr32-sprite-compiler sprite.png output.h --palette palette.json\n

Palette JSON format:

{\n  \"colors\": [\n    {\"r\": 0, \"g\": 0, \"b\": 0, \"name\": \"black\"},\n    {\"r\": 255, \"g\": 255, \"b\": 255, \"name\": \"white\"}\n  ]\n}\n
"},{"location":"tools/sprite_compiler/usage_guide/#built-in-palettes","title":"Built-in Palettes","text":"

Use predefined palettes:

pr32-sprite-compiler sprite.png output.h --palette nes\npr32-sprite-compiler sprite.png output.h --palette gb\npr32-sprite-compiler sprite.png output.h --palette pico8\n
"},{"location":"tools/sprite_compiler/usage_guide/#advanced-options","title":"Advanced Options","text":""},{"location":"tools/sprite_compiler/usage_guide/#threshold-for-grayscale","title":"Threshold for Grayscale","text":"

Set threshold for black/white conversion:

pr32-sprite-compiler sprite.png output.h --threshold 128\n

Values: 0-255 (default: 127)

"},{"location":"tools/sprite_compiler/usage_guide/#dithering","title":"Dithering","text":"

Enable dithering for better gradients:

pr32-sprite-compiler sprite.png output.h --dither\n
"},{"location":"tools/sprite_compiler/usage_guide/#alignment","title":"Alignment","text":"

Control output alignment:

pr32-sprite-compiler sprite.png output.h --align 4\n
"},{"location":"tools/sprite_compiler/usage_guide/#endianness","title":"Endianness","text":"

Specify byte order:

pr32-sprite-compiler sprite.png output.h --endian little\npr32-sprite-compiler sprite.png output.h --endian big\n
"},{"location":"tools/sprite_compiler/usage_guide/#output-customization","title":"Output Customization","text":""},{"location":"tools/sprite_compiler/usage_guide/#namespace","title":"Namespace","text":"

Wrap output in namespace:

pr32-sprite-compiler sprite.png output.h --namespace MyGame\n
"},{"location":"tools/sprite_compiler/usage_guide/#header-guard","title":"Header Guard","text":"

Custom header guard:

pr32-sprite-compiler sprite.png output.h --guard MY_SPRITE_H\n
"},{"location":"tools/sprite_compiler/usage_guide/#include-paths","title":"Include Paths","text":"

Custom include paths:

pr32-sprite-compiler sprite.png output.h \\\n    --include \"<graphics/Sprite.h>\" \\\n    --include \"<stdint.h>\"\n
"},{"location":"tools/sprite_compiler/usage_guide/#integration-with-build-systems","title":"Integration with Build Systems","text":""},{"location":"tools/sprite_compiler/usage_guide/#platformio","title":"PlatformIO","text":"

Add to platformio.ini:

[env:esp32dev]\nextra_scripts = \n    pre:scripts/compile_sprites.py\n

compile_sprites.py:

Import(\"env\")\nimport subprocess\n\nsubprocess.run([\n    \"pr32-sprite-compiler\",\n    \"--batch\", \"assets/sprites/*.png\",\n    \"--output-dir\", \"src/sprites/\"\n])\n
"},{"location":"tools/sprite_compiler/usage_guide/#makefile","title":"Makefile","text":"
SPRITES = $(wildcard assets/sprites/*.png)\nSPRITE_HEADERS = $(SPRITES:assets/sprites/%.png=src/sprites/%.h)\n\nsrc/sprites/%.h: assets/sprites/%.png\n pr32-sprite-compiler $< $@ --name $(shell basename $< .png | tr '[:lower:]' '[:upper:]')_SPRITE\n\nsprites: $(SPRITE_HEADERS)\n
"},{"location":"tools/sprite_compiler/usage_guide/#cmake","title":"CMake","text":"
file(GLOB SPRITE_FILES \"assets/sprites/*.png\")\n\nforeach(SPRITE ${SPRITE_FILES})\n    get_filename_component(SPRITE_NAME ${SPRITE} NAME_WE)\n    add_custom_command(\n        OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/src/sprites/${SPRITE_NAME}.h\n        COMMAND pr32-sprite-compiler\n        ARGS ${SPRITE} ${CMAKE_CURRENT_SOURCE_DIR}/src/sprites/${SPRITE_NAME}.h\n        DEPENDS ${SPRITE}\n    )\nendforeach()\n
"},{"location":"tools/sprite_compiler/usage_guide/#gui-usage-if-available","title":"GUI Usage (If Available)","text":""},{"location":"tools/sprite_compiler/usage_guide/#opening-gui","title":"Opening GUI","text":"
pr32-sprite-compiler --gui\n

Or launch the GUI application directly.

"},{"location":"tools/sprite_compiler/usage_guide/#gui-workflow","title":"GUI Workflow","text":"
  1. Drag and drop images into the window
  2. Preview sprite data in real-time
  3. Adjust settings visually (format, threshold, etc.)
  4. Export to header files
  5. Batch process multiple files
"},{"location":"tools/sprite_compiler/usage_guide/#gui-features","title":"GUI Features","text":"
  • Visual preview of sprite conversion
  • Real-time threshold adjustment
  • Palette selection
  • Batch processing interface
  • Export options
"},{"location":"tools/sprite_compiler/usage_guide/#best-practices","title":"Best Practices","text":""},{"location":"tools/sprite_compiler/usage_guide/#image-preparation","title":"Image Preparation","text":"
  • Use indexed color PNG for best results
  • Keep sprites small (8x8, 16x16, 32x32)
  • Use black and white for 1bpp
  • Limit colors for 2bpp/4bpp formats
"},{"location":"tools/sprite_compiler/usage_guide/#file-organization","title":"File Organization","text":"
project/\n\u251c\u2500\u2500 assets/\n\u2502   \u2514\u2500\u2500 sprites/\n\u2502       \u251c\u2500\u2500 player.png\n\u2502       \u251c\u2500\u2500 enemy.png\n\u2502       \u2514\u2500\u2500 items.png\n\u251c\u2500\u2500 src/\n\u2502   \u2514\u2500\u2500 sprites/          # Generated headers\n\u2502       \u251c\u2500\u2500 player.h\n\u2502       \u251c\u2500\u2500 enemy.h\n\u2502       \u2514\u2500\u2500 items.h\n\u2514\u2500\u2500 platformio.ini\n
"},{"location":"tools/sprite_compiler/usage_guide/#naming-conventions","title":"Naming Conventions","text":"
  • Use descriptive names: player_walk_0.png \u2192 PLAYER_WALK_0_SPRITE
  • Be consistent: All caps for sprite names
  • Use prefixes: ENEMY_, PLAYER_, ITEM_
"},{"location":"tools/sprite_compiler/usage_guide/#version-control","title":"Version Control","text":"
  • Commit generated headers (they're part of the build)
  • Or add to .gitignore and regenerate on build
  • Keep source images in version control
"},{"location":"tools/sprite_compiler/usage_guide/#troubleshooting","title":"Troubleshooting","text":""},{"location":"tools/sprite_compiler/usage_guide/#common-issues","title":"Common Issues","text":"

\"Image too large\":

  • Sprites must be \u2264 16 pixels wide for 1bpp
  • Resize image or split into multiple sprites

\"Colors not converting correctly\":

  • Use indexed color PNG
  • For 1bpp: Use only black and white
  • For 2bpp: Use exactly 4 colors
  • For 4bpp: Use up to 16 colors

\"Output file not found\":

  • Check write permissions
  • Verify output directory exists
  • Use absolute paths if needed

\"Invalid format\":

  • Ensure input is PNG format
  • Check file is not corrupted
  • Try re-saving image in image editor
"},{"location":"tools/sprite_compiler/usage_guide/#getting-help","title":"Getting Help","text":"
pr32-sprite-compiler --help\n

Shows all available options and usage.

"},{"location":"tools/sprite_compiler/usage_guide/#next-steps","title":"Next Steps","text":"
  • Advanced Features - Explore advanced options
  • Overview - Learn more about the compiler
  • Manual - Sprites - Using sprites in games
"},{"location":"tools/sprite_compiler/usage_guide/#see-also","title":"See Also","text":"
  • Code Examples - Sprites - Sprite usage examples
  • Troubleshooting - Common issues and solutions
"},{"location":"tools/tilemap_editor/installation/","title":"Installation Guide","text":"

The PixelRoot32 Tilemap Editor can be run directly from source or as a standalone executable on Windows.

"},{"location":"tools/tilemap_editor/installation/#1-requirements","title":"1. Requirements","text":"
  • Python 3.13+ (if running from source).
  • Windows 10/11 (recommended).
"},{"location":"tools/tilemap_editor/installation/#2-install-from-source","title":"2. Install from Source","text":""},{"location":"tools/tilemap_editor/installation/#21-clone-the-repository","title":"2.1 Clone the Repository","text":"
git clone https://github.com/Gperez88/PixelRoot32-Tilemap-Editor.git\ncd PixelRoot32-Tilemap-Editor\n
"},{"location":"tools/tilemap_editor/installation/#22-install-dependencies","title":"2.2 Install Dependencies","text":"

The editor uses several Python libraries for the GUI and image processing:

pip install ttkbootstrap pillow jinja2\n
"},{"location":"tools/tilemap_editor/installation/#23-run-the-editor","title":"2.3 Run the Editor","text":"
python main.py\n
"},{"location":"tools/tilemap_editor/installation/#3-standalone-executable-windows","title":"3. Standalone Executable (Windows)","text":"

For a more convenient experience, you can use the pre-compiled version:

  1. Go to the Releases section of the repository.
  2. Download the latest PixelRoot32-Editor-win64.zip.
  3. Extract the contents to a folder.
  4. Run PixelRoot32-Editor.exe.

Note: No Python installation is required to run the standalone executable.

"},{"location":"tools/tilemap_editor/installation/#4-building-your-own-executable","title":"4. Building your own Executable","text":"

If you want to package the editor yourself:

  1. Install PyInstaller:
pip install pyinstaller\n
  1. Run the build command using the provided .spec file:
pyinstaller pixelroot32_editor.spec\n
  1. The executable will be available in the dist/ folder.
"},{"location":"tools/tilemap_editor/overview/","title":"Tilemap Editor Overview","text":"

The PixelRoot32 Tilemap Editor is a powerful visual tool designed to create complex multi-layered tile-based maps for the PixelRoot32 engine. It simplifies the process of designing game environments, managing tilesets, and exporting optimized C++ code.

"},{"location":"tools/tilemap_editor/overview/#what-it-does","title":"What It Does","text":"

The Tilemap Editor allows you to:

  • Visual Design: Paint tiles directly onto a canvas with layers and transparency.
  • Tileset Management: Import PNG images as tilesets and select single or multiple tiles.
  • Multi-Scene Support: Create multiple scenes within a single project, sharing the same tilesets.
  • Onion Skinning: Visualize adjacent scenes as translucent overlays for seamless transitions.
  • Multi-Layer Support: Organize each scene into up to 8 layers for parallax effects or depth.
  • Optimized Export: Generate C++ header and source files compatible with the PixelRoot32 renderer.
  • BPP Support: Export maps in 1bpp, 2bpp, or 4bpp formats to balance memory usage and color depth.
"},{"location":"tools/tilemap_editor/overview/#key-features","title":"Key Features","text":""},{"location":"tools/tilemap_editor/overview/#visual-editing-tools","title":"\u2705 Visual Editing Tools","text":"
  • Brush: Paint individual tiles or patterns.
  • Eraser: Remove tiles from the active layer.
  • Rectangle Fill: Quickly fill areas with a specific tile.
  • Pipette: Pick an existing tile from the canvas.
"},{"location":"tools/tilemap_editor/overview/#multi-scene-system","title":"\u2705 Multi-Scene System","text":"
  • Multiple Scenes: Manage levels, rooms, or map sections within one project.
  • Onion Skinning: Overlay other scenes with adjustable opacity to ensure continuity.
  • Independent Dimensions: Each scene can have its own width and height.
"},{"location":"tools/tilemap_editor/overview/#multi-layer-system","title":"\u2705 Multi-Layer System","text":"
  • Per-Scene Layers: Each scene maintains its own independent stack of up to 8 layers.
  • Visibility Toggle: Hide/show layers to focus on specific parts of the map.
  • Opacity Control: Adjust layer transparency for complex blending effects.
  • Layer Reordering: Change the render order of your tilemaps.
"},{"location":"tools/tilemap_editor/overview/#tileset-selector","title":"\u2705 Tileset Selector","text":"
  • Smart Selection: Drag and select a rectangular area of tiles.
  • Multiple Tilesets: Support for multiple tilesets per project (planned).
  • Auto-import: Automatically detects tile size from the imported image.
"},{"location":"tools/tilemap_editor/overview/#engine-integration","title":"\u2705 Engine Integration","text":"
  • Workspace Selection: Link the editor to your PixelRoot32 projects directory.
  • Direct Export: Files are generated with the correct namespaces and structures for immediate use.
  • BPP Compatibility: Ensures exported data matches the engine's expected format for 1bpp, 2bpp, and 4bpp.
"},{"location":"tools/tilemap_editor/overview/#data-formats","title":"Data Formats","text":""},{"location":"tools/tilemap_editor/overview/#project-file-pr32scene","title":"Project File (.pr32scene)","text":"

The editor uses a custom JSON-based format to save your project state, including:

  • Tileset metadata (path, tile size, spacing).
  • Layer data (tile indices, width, height, position).
  • Project settings (BPP, namespace).
"},{"location":"tools/tilemap_editor/overview/#exported-c","title":"Exported C++","text":"

The editor generates modular C++ files for each scene:

  • Scene Files: scene_<name>.h and scene_<name>.cpp for each individual scene.
  • Global Header: scenes.h acts as a master entry point.
  • Tilemap Data: One packed array of tile indices per layer (*_INDICES[]). Each layer is exposed as a TileMap4bpp (or TileMap2bpp/TileMap) with an indices pointer; use the same data for rendering and for tile-based collision in your game code.
  • Global Assets: Tilesets and palettes are exported once and shared across all scenes to minimize memory footprint.
  • Export options: Store data in Flash (ESP32) (default) emits static data with PROGMEM to reduce RAM use; Legacy format disables Flash attributes for backward compatibility or non-ESP32 builds.
"},{"location":"tools/tilemap_editor/usage_guide/","title":"Usage Guide","text":"

This guide covers the basic workflow for creating and exporting a tilemap using the PixelRoot32 Tilemap Editor.

"},{"location":"tools/tilemap_editor/usage_guide/#1-creating-a-new-project","title":"1. Creating a New Project","text":"
  1. Launch the editor.
  2. Go to File > New Project.
  3. Enter the project name and select the base Color Depth (BPP):
  4. 1bpp: Monochrome (2 colors).
  5. 2bpp: 4 colors.
  6. 4bpp: 16 colors.
  7. Set the Tile Size (e.g., 8x8, 16x16).
"},{"location":"tools/tilemap_editor/usage_guide/#2-importing-a-tileset","title":"2. Importing a Tileset","text":"
  1. In the Tileset panel, click on Load Tileset.
  2. Select a PNG image containing your tiles.
  3. The image will be sliced into tiles based on the tile size set in the project.
"},{"location":"tools/tilemap_editor/usage_guide/#3-managing-scenes","title":"3. Managing Scenes","text":"
  1. In the Scenes panel, click the + button to add a new scene.
  2. Select a scene from the list to make it active.
  3. Use the icons to rename, delete, or duplicate scenes.
  4. Adjust the dimensions of the active scene via the Settings cog in the toolbar.
"},{"location":"tools/tilemap_editor/usage_guide/#4-using-onion-skinning","title":"4. Using Onion Skinning","text":"
  1. To see another scene behind your active one, click the Onion icon (layers icon) next to that scene in the Scenes list.
  2. Ensure the Show Onion Skin master checkbox is enabled.
  3. Use the Opacity Slider at the bottom of the panel to adjust the visibility of the overlays.
"},{"location":"tools/tilemap_editor/usage_guide/#5-painting-tiles","title":"5. Painting Tiles","text":"
  1. Select a tile (or a range of tiles) from the Tileset panel.
  2. Select the Brush tool (Shortcut: B).
  3. Click and drag on the canvas to paint on the active scene's layers.
  4. Use the Layers panel to switch between different layers of the active scene.
"},{"location":"tools/tilemap_editor/usage_guide/#6-selection-and-transformations","title":"6. Selection and Transformations","text":"
  • Single Selection: Click on a tile in the tileset.
  • Area Selection: Click and drag in the tileset to select a rectangular block of tiles.
  • Pipette: Press P and click on the canvas to pick the tile under the cursor.
"},{"location":"tools/tilemap_editor/usage_guide/#7-exporting-to-c","title":"7. Exporting to C++","text":"
  1. Ensure you have at least one tileset imported and at least one scene designed.
  2. Click the Export button in the top right (or File > Export / Ctrl+E).
  3. In the export dialog:
  4. Set the C++ Namespace (e.g. forest_level); it defaults to the project name.
  5. Review the Color Depth (BPP); it is auto-detected from your tileset colors (1bpp, 2bpp, or 4bpp).
  6. Store data in Flash (ESP32): Checked by default; emits PROGMEM for palette, tileset, and layer data to reduce RAM on ESP32.
  7. Legacy format (no Flash attribute): Use for older projects or non-ESP32 builds.
  8. Click Export Now and choose the output directory.
  9. The editor generates a modular output:
  10. scene_<name>.h / .cpp: Independent data files for each scene.
  11. scenes.h: Master entry point including all scenes.
  12. Global assets (shared tilesets and palettes) are exported once.
  13. Each layer is exported as a TileMap object (BPP-specific) with its own indices array.
"},{"location":"tools/tilemap_editor/usage_guide/#8-keyboard-shortcuts","title":"8. Keyboard Shortcuts","text":"Shortcut Action B Brush Tool E Eraser Tool R Rectangle Fill Tool P Pipette Tool Space + Drag Pan Canvas Mouse Wheel Zoom In/Out Ctrl + N New Project Ctrl + S Save Project Ctrl + E Export Project Esc Close floating panels"}]} \ No newline at end of file diff --git a/site/sitemap.xml b/site/sitemap.xml index d4029de..63bd309 100644 --- a/site/sitemap.xml +++ b/site/sitemap.xml @@ -2,270 +2,270 @@ https://pixelroot32-game-engine.github.io/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/audio/audio_config/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/audio/audio_engine/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/audio/audio_types/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/audio/music_player/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/core/actor/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/core/engine/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/core/entity/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/core/input_config/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/core/input_manager/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/core/physics_actor/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/core/scene/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/graphics/camera2d/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/graphics/color/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/graphics/display_config/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/graphics/font/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/graphics/renderer/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/graphics/sprite/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/graphics/tilemap/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/physics/collision_system/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/physics/collision_types/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_button/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_checkbox/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_element/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_label/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layout/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layouts/anchor_layout/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layouts/grid_layout/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layouts/horizontal_layout/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layouts/padding_container/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layouts/panel/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/api_reference/ui/ui_layouts/vertical_layout/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/getting_started/fundamental_concepts/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/getting_started/installation/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/getting_started/what_is_pixelroot32/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/getting_started/why_pixelroot32/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/getting_started/your_first_project/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/advanced_graphics/cameras_and_scrolling/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/advanced_graphics/color_palettes/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/advanced_graphics/particles_and_effects/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/advanced_graphics/resolution_scaling/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/advanced_graphics/sprites_and_animation/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/advanced_graphics/tilemaps/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/game_development/audio/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/game_development/basic_rendering/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/game_development/input_and_control/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/game_development/physics_and_collisions/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/game_development/scenes_and_entities/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/game_development/user_interface/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/optimization/extensibility/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/optimization/memory_management/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/optimization/performance_tuning/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/manual/optimization/platforms_and_drivers/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/reference/api_overview/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/reference/code_examples/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/reference/game_examples_guide/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/resources/available_tools/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/resources/faq/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/resources/limitations_and_considerations/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/resources/troubleshooting/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/tools/sprite_compiler/advanced_features/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/tools/sprite_compiler/installation/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/tools/sprite_compiler/overview/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/tools/sprite_compiler/usage_guide/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/tools/tilemap_editor/installation/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/tools/tilemap_editor/overview/ - 2026-01-30 + 2026-01-31 https://pixelroot32-game-engine.github.io/tools/tilemap_editor/usage_guide/ - 2026-01-30 + 2026-01-31 \ No newline at end of file diff --git a/site/sitemap.xml.gz b/site/sitemap.xml.gz index 18757df8c3db411feb3088e77003d941458def78..72131939877f482820dc66ce76def5646ac7998a 100644 GIT binary patch delta 701 zcmV;u0z&=h2IvL{ABzYG07iY02OWP&3M|@1;@qfg(Vq^4=s zJ#_(%5hON4Nk7cTpEIPNK3ztCcfwpKhUd-0?tXKJ!A3`6c;5W;_g~u&n@{_9Pc{33 zd?%AbdEOkE)1O^;KA(4m7)MBD7xT~+dz25QTL!!P-N()T-JQJJ4d!>#>&bsdyKi?X za+^dK^f^X;|F|7s#4Uz_0`3OlV?FFBc28ZK|N3$$JVv*Fynp;-d;hR~{~%MAvH5x3 z%L9M!(U8bw>@kZ~u!HK_So>{k3_T4x+2*M_+4!2UXhR!oA#0L{D`q`xHf8~|9JMiN zi?0QWiLc6_D5T2jwBi-o2myZvbwQtwS4qfXGzNdMs44b`4CyGg>a0x8@aQz6MX$+? zFIE-fib^{Ehy$xlVG8nQ)WTXK48^}i|CB89tVLS@Bc zCHXOj${d3>D(S`S=R>?`<3dRT)TC-NmWKm+eNfj}StnKLAlPHf${`?!OinqX7?Hlp zLJwX!Xad(ZhFZDAAeUvmph0Ugm+pjA^AXrkF|V%Fg?H78CK-@TPr0y3IsS`w z)qEHsRPY_RlamMn908Y;B?2QBCF#-xYw&jar*U{fAJf#3%qIZ~!48vN0y!wJv;N_Q zF%&wGU-?+*7Tkzq%-7}gW$pctTYyQN8uQrn+i(p!bmwQ2zXBG2B0TFLveBWz3yjI5 z5+hA=@*T+xl^m`MR-_lPVjVaEc{q3p{1|=F0oB779UxvZkf#j%zLJW_N@X$+>0p!! zq>BH_QKqk~TyqG`6}s4JOi}^oAC+;Bz%{R%lD84H?6usc)1a=m$!d`meSJBb;g){O jpriIh3SB;Z1E6n9r+VB`?4G(d|Mlfic#Q7wxPSa@yMMp^u$L*z*!;Zi z<$=HUXh>u-_L#*g*gtw4sf)kTuD}4YM9L8?yjfj@p>C z#n%GG#5ZM76jEh%TJZ{PgaChox}Z;|nJ`cw$UA%L&*}F|V%Fg?H16CK-@TPr0y3IsT1y z)qEHsRPY_Rvy%t{908}3B?2QBDe2M#Yw&jar*U{jAJf#3%qIZ~!H$z&0y!uzv;N_g zF%&wIU-?+*9^8my%(vzAW$pctdw@xt8uQrn+i(p!bmvEtzXBG2CcNk%veBWzD~!pb z5+hA=@(sxhl^m`MR-_lPVjVaGc{q9r{1|=F0oB95IzYT+AWs?iZ6y_vmC9ru(!nSd zNEQE;lT2S(x#kd>D|E5dn4|*E-z(!DfoonjCGR6@*=xB^r$Jrslhq Advanced Features - PixelRoot32 Documentation

Sprite Compiler Advanced Features

Advanced features and options for the PixelRoot32 Sprite Compiler to optimize sprite conversion and handle complex scenarios.

Automatic Palette Detection

The Sprite Compiler automatically detects if your sprite uses one of the engine's built-in palettes. This simplifies your workflow and ensures color consistency.

Predefined Engine Palettes

The engine includes 5 optimized palettes: - PR32 (Default PixelRoot32 palette) - NES (Nintendo style) - GB (GameBoy style) - GBC (GameBoy Color style) - PICO8 (Fantasy console style)

How it works

  1. Detection: When you compile an image, the tool compares all unique colors found in the sprite with the colors in the 5 engine palettes.
  2. Match: If all colors in your sprite belong to one of these palettes, the compiler:
  3. Omits generating a color array in the header.
  4. Assumes you will use the engine's built-in palette definitions at runtime.
  5. Custom Palette: If your sprite uses colors not found in the engine palettes, it automatically generates a {PREFIX}_PALETTE_MAPPING[16] array in the header file.

Naming with Prefixes

You can organize your generated code by using the --prefix parameter (or the Prefix field in the GUI).

Using Prefixes

By default, sprites are named SPRITE_N_.... Using a prefix allows you to create more descriptive names and avoid naming collisions.

python main.py sheet.png --grid 16x16 --sprite 0,0,1,1 --prefix PLAYER_JUM
-

Generated names will follow this pattern: - PLAYER_JUM_SPRITE_0_LAYER_0 - PLAYER_JUM_SPRITE_0_2BPP - PLAYER_JUM_SPRITE_0_4BPP - PLAYER_JUM_PALETTE_MAPPING (if a custom palette is used)

Export Modes

Layered (1bpp)

Best for standard PixelRoot32 rendering. It extracts each color into its own bitmask (1bpp). The engine then renders these layers sequentially.

Packed (2bpp / 4bpp)

Generates a single packed array where each pixel uses multiple bits. - 2bpp: 4 colors max (Index 0 is always transparent). - 4bpp: 16 colors max (Index 0 is always transparent).

These modes are more efficient for sprites with many colors as they require only a single draw call.

\ No newline at end of file +

Generated names will follow this pattern: - PLAYER_JUM_SPRITE_0_LAYER_0 - PLAYER_JUM_SPRITE_0_2BPP - PLAYER_JUM_SPRITE_0_4BPP - PLAYER_JUM_PALETTE_MAPPING (if a custom palette is used)

Export Modes

Layered (1bpp)

Best for standard PixelRoot32 rendering. It extracts each color into its own bitmask (1bpp). The engine then renders these layers sequentially.

Packed (2bpp / 4bpp)

Generates a single packed array where each pixel uses multiple bits. - 2bpp: 4 colors max (Index 0 is always transparent). - 4bpp: 16 colors max (Index 0 is always transparent).

These modes are more efficient for sprites with many colors as they require only a single draw call.

\ No newline at end of file diff --git a/site/tools/sprite_compiler/installation/index.html b/site/tools/sprite_compiler/installation/index.html index c40b365..ba0b0a8 100644 --- a/site/tools/sprite_compiler/installation/index.html +++ b/site/tools/sprite_compiler/installation/index.html @@ -29,4 +29,4 @@ npm install

Uninstallation

Remove Global Installation

npm uninstall -g pr32-sprite-compiler
 

Remove Local Installation

npm uninstall pr32-sprite-compiler
-

Troubleshooting

Common Issues

"Command not found" after installation: - Restart your terminal - Check npm global bin path: npm config get prefix - Verify PATH includes npm bin directory

Permission errors: - On Linux/macOS: Use sudo for global install - Or install locally without -g flag - On Windows: Run terminal as Administrator

Module not found errors: - Reinstall: npm install -g pr32-sprite-compiler - Clear npm cache: npm cache clean --force

Version conflicts: - Check Node.js version: node --version - Update Node.js if version is too old - Use nvm (Node Version Manager) to manage versions

Getting Help

Next Steps

Once installed, proceed to: - Usage Guide - Learn how to use the compiler - Advanced Features - Explore advanced options

See Also

\ No newline at end of file +

Troubleshooting

Common Issues

"Command not found" after installation: - Restart your terminal - Check npm global bin path: npm config get prefix - Verify PATH includes npm bin directory

Permission errors: - On Linux/macOS: Use sudo for global install - Or install locally without -g flag - On Windows: Run terminal as Administrator

Module not found errors: - Reinstall: npm install -g pr32-sprite-compiler - Clear npm cache: npm cache clean --force

Version conflicts: - Check Node.js version: node --version - Update Node.js if version is too old - Use nvm (Node Version Manager) to manage versions

Getting Help

Next Steps

Once installed, proceed to: - Usage Guide - Learn how to use the compiler - Advanced Features - Explore advanced options

See Also

\ No newline at end of file diff --git a/site/tools/sprite_compiler/overview/index.html b/site/tools/sprite_compiler/overview/index.html index faecac0..1ed9c7c 100644 --- a/site/tools/sprite_compiler/overview/index.html +++ b/site/tools/sprite_compiler/overview/index.html @@ -24,4 +24,4 @@ # Continue with your build process platformio run -

Advantages Over Manual Creation

✅ Time Saving

  • No manual bit pattern conversion
  • Automatic format optimization
  • Batch processing multiple sprites

✅ Accuracy

  • Correct bit ordering
  • Proper array formatting
  • Valid C++ syntax

✅ Consistency

  • Uniform naming conventions
  • Standardized output format
  • Consistent code structure

✅ Maintainability

  • Easy to regenerate from source images
  • Version control friendly
  • Clear separation of assets and code

Limitations

  • Width limit: 16 pixels for 1bpp (hardware constraint)
  • Color depth: Limited by format (1bpp = 2 colors, 2bpp = 4 colors, etc.)
  • File format: Primarily PNG (other formats may require conversion)

Next Steps

See Also

\ No newline at end of file +

Advantages Over Manual Creation

✅ Time Saving

  • No manual bit pattern conversion
  • Automatic format optimization
  • Batch processing multiple sprites

✅ Accuracy

  • Correct bit ordering
  • Proper array formatting
  • Valid C++ syntax

✅ Consistency

  • Uniform naming conventions
  • Standardized output format
  • Consistent code structure

✅ Maintainability

  • Easy to regenerate from source images
  • Version control friendly
  • Clear separation of assets and code

Limitations

  • Width limit: 16 pixels for 1bpp (hardware constraint)
  • Color depth: Limited by format (1bpp = 2 colors, 2bpp = 4 colors, etc.)
  • File format: Primarily PNG (other formats may require conversion)

Next Steps

See Also

\ No newline at end of file diff --git a/site/tools/sprite_compiler/usage_guide/index.html b/site/tools/sprite_compiler/usage_guide/index.html index d7a8d28..ed21cda 100644 --- a/site/tools/sprite_compiler/usage_guide/index.html +++ b/site/tools/sprite_compiler/usage_guide/index.html @@ -110,4 +110,4 @@ │ └── items.h └── platformio.ini

Naming Conventions

  • Use descriptive names: player_walk_0.pngPLAYER_WALK_0_SPRITE
  • Be consistent: All caps for sprite names
  • Use prefixes: ENEMY_, PLAYER_, ITEM_

Version Control

  • Commit generated headers (they're part of the build)
  • Or add to .gitignore and regenerate on build
  • Keep source images in version control

Troubleshooting

Common Issues

"Image too large":

  • Sprites must be ≤ 16 pixels wide for 1bpp
  • Resize image or split into multiple sprites

"Colors not converting correctly":

  • Use indexed color PNG
  • For 1bpp: Use only black and white
  • For 2bpp: Use exactly 4 colors
  • For 4bpp: Use up to 16 colors

"Output file not found":

  • Check write permissions
  • Verify output directory exists
  • Use absolute paths if needed

"Invalid format":

  • Ensure input is PNG format
  • Check file is not corrupted
  • Try re-saving image in image editor

Getting Help

pr32-sprite-compiler --help
-

Shows all available options and usage.

Next Steps

See Also

\ No newline at end of file +

Shows all available options and usage.

Next Steps

See Also

\ No newline at end of file diff --git a/site/tools/tilemap_editor/installation/index.html b/site/tools/tilemap_editor/installation/index.html index 6cca496..ed4c7ca 100644 --- a/site/tools/tilemap_editor/installation/index.html +++ b/site/tools/tilemap_editor/installation/index.html @@ -4,4 +4,4 @@

2.3 Run the Editor

python main.py
 

3. Standalone Executable (Windows)

For a more convenient experience, you can use the pre-compiled version:

  1. Go to the Releases section of the repository.
  2. Download the latest PixelRoot32-Editor-win64.zip.
  3. Extract the contents to a folder.
  4. Run PixelRoot32-Editor.exe.

Note: No Python installation is required to run the standalone executable.

4. Building your own Executable

If you want to package the editor yourself:

  1. Install PyInstaller:
pip install pyinstaller
 
  1. Run the build command using the provided .spec file:
pyinstaller pixelroot32_editor.spec
-
  1. The executable will be available in the dist/ folder.
\ No newline at end of file +
  1. The executable will be available in the dist/ folder.
\ No newline at end of file diff --git a/site/tools/tilemap_editor/overview/index.html b/site/tools/tilemap_editor/overview/index.html index 4edb0c5..4705dc5 100644 --- a/site/tools/tilemap_editor/overview/index.html +++ b/site/tools/tilemap_editor/overview/index.html @@ -1 +1 @@ - Tilemap Editor Overview - PixelRoot32 Documentation

Tilemap Editor Overview

The PixelRoot32 Tilemap Editor is a powerful visual tool designed to create complex multi-layered tile-based maps for the PixelRoot32 engine. It simplifies the process of designing game environments, managing tilesets, and exporting optimized C++ code.

What It Does

The Tilemap Editor allows you to:

  • Visual Design: Paint tiles directly onto a canvas with layers and transparency.
  • Tileset Management: Import PNG images as tilesets and select single or multiple tiles.
  • Multi-Layer Support: Organize your map into up to 8 layers for parallax effects or depth.
  • Optimized Export: Generate C++ header and source files compatible with the PixelRoot32 renderer.
  • BPP Support: Export maps in 1bpp, 2bpp, or 4bpp formats to balance memory usage and color depth.

Key Features

✅ Visual Editing Tools

  • Brush: Paint individual tiles or patterns.
  • Eraser: Remove tiles from the active layer.
  • Rectangle Fill: Quickly fill areas with a specific tile.
  • Pipette: Pick an existing tile from the canvas.

✅ Multi-Layer System

  • Visibility Toggle: Hide/show layers to focus on specific parts of the map.
  • Opacity Control: Adjust layer transparency for complex blending effects.
  • Layer Reordering: Change the render order of your tilemaps.

✅ Tileset Selector

  • Smart Selection: Drag and select a rectangular area of tiles.
  • Multiple Tilesets: Support for multiple tilesets per project (planned).
  • Auto-import: Automatically detects tile size from the imported image.

✅ Engine Integration

  • Workspace Selection: Link the editor to your PixelRoot32 projects directory.
  • Direct Export: Files are generated with the correct namespaces and structures for immediate use.
  • BPP Compatibility: Ensures exported data matches the engine's expected format for 1bpp, 2bpp, and 4bpp.

Data Formats

Project File (.pr32scene)

The editor uses a custom JSON-based format to save your project state, including:

  • Tileset metadata (path, tile size, spacing).
  • Layer data (tile indices, width, height, position).
  • Project settings (BPP, namespace).

Exported C++

The editor generates <namespace>.h and <namespace>.cpp files containing:

  • Tilemap Data: One packed array of tile indices per layer (*_INDICES[]). Each layer is exposed as a TileMap4bpp (or TileMap2bpp/TileMap) with an indices pointer; use the same data for rendering and for tile-based collision in your game code.
  • Tilemap Structures: pixelroot32::graphics::TileMap (or TileMap2bpp/TileMap4bpp) definitions, plus tileset pool and palette.
  • Export options: Store data in Flash (ESP32) (default) emits static data with PROGMEM to reduce RAM use; Legacy format disables Flash attributes for backward compatibility or non-ESP32 builds.
  • Scene init: Call init() once before drawing; the generated code registers the palette and configures each layer for the engine.
\ No newline at end of file + Tilemap Editor Overview - PixelRoot32 Documentation

Tilemap Editor Overview

The PixelRoot32 Tilemap Editor is a powerful visual tool designed to create complex multi-layered tile-based maps for the PixelRoot32 engine. It simplifies the process of designing game environments, managing tilesets, and exporting optimized C++ code.

What It Does

The Tilemap Editor allows you to:

  • Visual Design: Paint tiles directly onto a canvas with layers and transparency.
  • Tileset Management: Import PNG images as tilesets and select single or multiple tiles.
  • Multi-Scene Support: Create multiple scenes within a single project, sharing the same tilesets.
  • Onion Skinning: Visualize adjacent scenes as translucent overlays for seamless transitions.
  • Multi-Layer Support: Organize each scene into up to 8 layers for parallax effects or depth.
  • Optimized Export: Generate C++ header and source files compatible with the PixelRoot32 renderer.
  • BPP Support: Export maps in 1bpp, 2bpp, or 4bpp formats to balance memory usage and color depth.

Key Features

✅ Visual Editing Tools

  • Brush: Paint individual tiles or patterns.
  • Eraser: Remove tiles from the active layer.
  • Rectangle Fill: Quickly fill areas with a specific tile.
  • Pipette: Pick an existing tile from the canvas.

✅ Multi-Scene System

  • Multiple Scenes: Manage levels, rooms, or map sections within one project.
  • Onion Skinning: Overlay other scenes with adjustable opacity to ensure continuity.
  • Independent Dimensions: Each scene can have its own width and height.

✅ Multi-Layer System

  • Per-Scene Layers: Each scene maintains its own independent stack of up to 8 layers.
  • Visibility Toggle: Hide/show layers to focus on specific parts of the map.
  • Opacity Control: Adjust layer transparency for complex blending effects.
  • Layer Reordering: Change the render order of your tilemaps.

✅ Tileset Selector

  • Smart Selection: Drag and select a rectangular area of tiles.
  • Multiple Tilesets: Support for multiple tilesets per project (planned).
  • Auto-import: Automatically detects tile size from the imported image.

✅ Engine Integration

  • Workspace Selection: Link the editor to your PixelRoot32 projects directory.
  • Direct Export: Files are generated with the correct namespaces and structures for immediate use.
  • BPP Compatibility: Ensures exported data matches the engine's expected format for 1bpp, 2bpp, and 4bpp.

Data Formats

Project File (.pr32scene)

The editor uses a custom JSON-based format to save your project state, including:

  • Tileset metadata (path, tile size, spacing).
  • Layer data (tile indices, width, height, position).
  • Project settings (BPP, namespace).

Exported C++

The editor generates modular C++ files for each scene:

  • Scene Files: scene_<name>.h and scene_<name>.cpp for each individual scene.
  • Global Header: scenes.h acts as a master entry point.
  • Tilemap Data: One packed array of tile indices per layer (*_INDICES[]). Each layer is exposed as a TileMap4bpp (or TileMap2bpp/TileMap) with an indices pointer; use the same data for rendering and for tile-based collision in your game code.
  • Global Assets: Tilesets and palettes are exported once and shared across all scenes to minimize memory footprint.
  • Export options: Store data in Flash (ESP32) (default) emits static data with PROGMEM to reduce RAM use; Legacy format disables Flash attributes for backward compatibility or non-ESP32 builds.
\ No newline at end of file diff --git a/site/tools/tilemap_editor/usage_guide/index.html b/site/tools/tilemap_editor/usage_guide/index.html index e870840..22fa65f 100644 --- a/site/tools/tilemap_editor/usage_guide/index.html +++ b/site/tools/tilemap_editor/usage_guide/index.html @@ -1 +1 @@ - Usage Guide - PixelRoot32 Documentation

Usage Guide

This guide covers the basic workflow for creating and exporting a tilemap using the PixelRoot32 Tilemap Editor.

1. Creating a New Project

  1. Launch the editor.
  2. Go to File > New Project.
  3. Enter the project name and select the base Color Depth (BPP):
  4. 1bpp: Monochrome (2 colors).
  5. 2bpp: 4 colors.
  6. 4bpp: 16 colors.
  7. Set the Tile Size (e.g., 8x8, 16x16).

2. Importing a Tileset

  1. In the Tileset panel, click on Load Tileset.
  2. Select a PNG image containing your tiles.
  3. The image will be sliced into tiles based on the tile size set in the project.

3. Painting Tiles

  1. Select a tile (or a range of tiles) from the Tileset panel.
  2. Select the Brush tool (Shortcut: B).
  3. Click and drag on the canvas to paint.
  4. Use the Layers panel to switch between different layers.

4. Selection and Transformations

  • Single Selection: Click on a tile in the tileset.
  • Area Selection: Click and drag in the tileset to select a rectangular block of tiles.
  • Pipette: Press P and click on the canvas to pick the tile under the cursor.

5. Exporting to C++

  1. Ensure you have at least one tileset imported.
  2. Click the Export button in the top right (or File > Export / Ctrl+E).
  3. In the export dialog:
  4. Set the C++ Namespace (e.g. forest_level); it defaults to the project name.
  5. Review the Color Depth (BPP); it is auto-detected from your tileset colors (1bpp, 2bpp, or 4bpp).
  6. Store data in Flash (ESP32): Checked by default; emits PROGMEM for palette, tileset, and layer data to reduce RAM on ESP32.
  7. Legacy format (no Flash attribute): Use for older projects or non-ESP32 builds.
  8. Click Export Now and choose the output directory.
  9. The editor generates:
  10. <namespace>.h: Declarations (e.g. TILE_SIZE, MAP_WIDTH, MAP_HEIGHT, layer TileMap4bpp externs, init()).
  11. <namespace>.cpp: Definitions (palette, tileset pool, layer indices, init() implementation). Use each layer's .indices in your game for drawing and tile-based collision.

6. Keyboard Shortcuts

Shortcut Action
B Brush Tool
E Eraser Tool
R Rectangle Fill Tool
P Pipette Tool
Space + Drag Pan Canvas
Mouse Wheel Zoom In/Out
Ctrl + N New Project
Ctrl + S Save Project
Ctrl + E Export Project
Esc Close floating panels
\ No newline at end of file + Usage Guide - PixelRoot32 Documentation

Usage Guide

This guide covers the basic workflow for creating and exporting a tilemap using the PixelRoot32 Tilemap Editor.

1. Creating a New Project

  1. Launch the editor.
  2. Go to File > New Project.
  3. Enter the project name and select the base Color Depth (BPP):
  4. 1bpp: Monochrome (2 colors).
  5. 2bpp: 4 colors.
  6. 4bpp: 16 colors.
  7. Set the Tile Size (e.g., 8x8, 16x16).

2. Importing a Tileset

  1. In the Tileset panel, click on Load Tileset.
  2. Select a PNG image containing your tiles.
  3. The image will be sliced into tiles based on the tile size set in the project.

3. Managing Scenes

  1. In the Scenes panel, click the + button to add a new scene.
  2. Select a scene from the list to make it active.
  3. Use the icons to rename, delete, or duplicate scenes.
  4. Adjust the dimensions of the active scene via the Settings cog in the toolbar.

4. Using Onion Skinning

  1. To see another scene behind your active one, click the Onion icon (layers icon) next to that scene in the Scenes list.
  2. Ensure the Show Onion Skin master checkbox is enabled.
  3. Use the Opacity Slider at the bottom of the panel to adjust the visibility of the overlays.

5. Painting Tiles

  1. Select a tile (or a range of tiles) from the Tileset panel.
  2. Select the Brush tool (Shortcut: B).
  3. Click and drag on the canvas to paint on the active scene's layers.
  4. Use the Layers panel to switch between different layers of the active scene.

6. Selection and Transformations

  • Single Selection: Click on a tile in the tileset.
  • Area Selection: Click and drag in the tileset to select a rectangular block of tiles.
  • Pipette: Press P and click on the canvas to pick the tile under the cursor.

7. Exporting to C++

  1. Ensure you have at least one tileset imported and at least one scene designed.
  2. Click the Export button in the top right (or File > Export / Ctrl+E).
  3. In the export dialog:
  4. Set the C++ Namespace (e.g. forest_level); it defaults to the project name.
  5. Review the Color Depth (BPP); it is auto-detected from your tileset colors (1bpp, 2bpp, or 4bpp).
  6. Store data in Flash (ESP32): Checked by default; emits PROGMEM for palette, tileset, and layer data to reduce RAM on ESP32.
  7. Legacy format (no Flash attribute): Use for older projects or non-ESP32 builds.
  8. Click Export Now and choose the output directory.
  9. The editor generates a modular output:
  10. scene_<name>.h / .cpp: Independent data files for each scene.
  11. scenes.h: Master entry point including all scenes.
  12. Global assets (shared tilesets and palettes) are exported once.
  13. Each layer is exported as a TileMap object (BPP-specific) with its own indices array.

8. Keyboard Shortcuts

Shortcut Action
B Brush Tool
E Eraser Tool
R Rectangle Fill Tool
P Pipette Tool
Space + Drag Pan Canvas
Mouse Wheel Zoom In/Out
Ctrl + N New Project
Ctrl + S Save Project
Ctrl + E Export Project
Esc Close floating panels
\ No newline at end of file