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 (32) entities.

Namespace

namespace pixelroot32::core {
    class Scene {
        // ...
    };
}

Inheritance

  • Base class: None (abstract base class)
  • Inherited by: Your custom scene classes (e.g., MainMenuScene, GameScene)

Constructors

Scene()

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 {
public:
    void init() override {
        // Initialize scene resources
    }

    void update(unsigned long deltaTime) override {
        Scene::update(deltaTime);  // Update entities and collisions
    }

    void draw(pixelroot32::graphics::Renderer& renderer) override {
        Scene::draw(renderer);  // Draw all entities
    }
};

Public Methods

virtual void init()

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 {
private:
    PlayerActor* player;
    std::array<EnemyActor*, 10> enemies;

public:
    void init() override {
        // Create player
        player = new PlayerActor();
        addEntity(player);

        // Create enemies
        for (int i = 0; i < 10; i++) {
            enemies[i] = new EnemyActor();
            addEntity(enemies[i]);
        }
    }
};

virtual void update(unsigned long deltaTime)

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 {
    // Custom update logic
    gameTimer += deltaTime;

    // Update entities and collisions
    Scene::update(deltaTime);

    // Additional logic after entity updates
    if (gameTimer > 60000) {
        // Game over after 60 seconds
    }
}

virtual void draw(Renderer& renderer)

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 {
    // Draw background
    renderer.drawTileMap(backgroundTileMap, 0, 0, Color::White);

    // Draw all entities
    Scene::draw(renderer);

    // Draw UI overlay
    renderer.drawText("Score: 100", 10, 10, Color::White, 1);
}

void addEntity(Entity* entity)

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 (32) 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 {
    // Create and add player
    PlayerActor* player = new PlayerActor();
    player->setPosition(64, 64);
    addEntity(player);

    // Create and add enemy
    EnemyActor* enemy = new EnemyActor();
    enemy->setPosition(100, 100);
    addEntity(enemy);
}

void removeEntity(Entity* entity)

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) {
    removeEntity(enemy);
    // Return to pool or delete
    enemyPool.returnToPool(enemy);
}

void clearEntities()

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() {
    clearEntities();
    // Return all entities to pool
    for (auto* entity : entityPool) {
        entityPool.returnToPool(entity);
    }
}

Protected Members

ArduinoQueue entities

Queue of entities in the scene. Accessible to derived classes for custom entity management.

Type: ArduinoQueue<Entity*>

Notes: - Maximum capacity: MAX_ENTITIES (32) - Direct access allows custom iteration or filtering - Use with caution: modifying while iterating may cause issues

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

MAX_ENTITIES Constant

The maximum number of entities allowed per scene.

Value: 32

Notes: - Hard limit: cannot be changed without modifying engine code - Includes all entity types: actors, UI elements, particles, etc. - Plan your entity usage carefully - Use object pooling to reuse entities instead of creating new ones

Usage Example

#include "core/Scene.h"
#include "core/Actor.h"

class MyGameScene : public pixelroot32::core::Scene {
private:
    PlayerActor* player;

public:
    void init() override {
        // Create player
        player = new PlayerActor();
        player->setPosition(64, 64);
        addEntity(player);

        // Create some enemies
        for (int i = 0; i < 5; i++) {
            EnemyActor* enemy = new EnemyActor();
            enemy->setPosition(10 + i * 20, 10);
            addEntity(enemy);
        }
    }

    void update(unsigned long deltaTime) override {
        // Custom game logic
        if (player->isDead()) {
            // Handle game over
        }

        // Update entities and collisions
        Scene::update(deltaTime);
    }

    void draw(pixelroot32::graphics::Renderer& renderer) override {
        // Draw background
        renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);

        // Draw all entities
        Scene::draw(renderer);

        // Draw HUD
        char scoreText[32];
        snprintf(scoreText, sizeof(scoreText), "Score: %d", score);
        renderer.drawText(scoreText, 10, 10, Color::White, 1);
    }
};

Performance Considerations

  • Entity limit: MAX_ENTITIES = 32 is a hard limit; 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