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 includes several complete game examples:

  • Space Invaders: Full-featured shooter with enemies, projectiles, and audio
  • Pong: Classic arcade game with physics and collisions
  • Snake: Grid-based game with entity pooling
  • TicTacToe: Turn-based game with simple AI
  • CameraDemo: Platformer with scrolling camera and parallax
  • SpritesDemo: Demonstration of advanced sprite formats

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
  • Tilemap Background: Starfield using tilemap system

Key Systems

Collision Layers

namespace Layers {
    constexpr uint16_t PLAYER = 0x0001;
    constexpr uint16_t ALIEN = 0x0002;
    constexpr uint16_t PROJECTILE = 0x0004;
    constexpr uint16_t BUNKER = 0x0008;
}

// Player can collide with aliens and bunkers
player->setCollisionLayer(Layers::PLAYER);
player->setCollisionMask(Layers::ALIEN | Layers::BUNKER);

// Projectiles can hit aliens and bunkers
projectile->setCollisionLayer(Layers::PROJECTILE);
projectile->setCollisionMask(Layers::ALIEN | Layers::BUNKER);

Entity Management

  • Uses object pooling for projectiles
  • Manages alien formation with grid layout
  • Handles game state (playing, game over)

Audio Integration

  • Background music using MusicPlayer
  • Sound effects for various events
  • Audio events triggered on collisions

Patterns Used

  • 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

Lessons Learned

  • Collision layers are essential for complex games
  • Object pooling improves performance
  • Tilemaps are efficient for backgrounds
  • Audio enhances game feel significantly

Pong

Location: src/examples/Pong/

Architecture

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

Key Systems

Physics Setup

class BallActor : public pixelroot32::core::PhysicsActor {
public:
    BallActor(float x, float y, float speed, int radius)
        : PhysicsActor(x, y, radius * 2, radius * 2) {
        setRestitution(0.8f);  // Bouncy
        setFriction(0.1f);     // Low friction
        setWorldSize(240, 240);
    }
};

Collision Response

void BallActor::onCollision(pixelroot32::core::Actor* other) {
    // Adjust ball position
    // Modify velocity based on impact point
    // Play bounce sound
}

Patterns Used

  • Physics Integration: Uses PhysicsActor for automatic movement
  • Collision Response: Custom collision handling
  • Score Management: Simple state tracking
  • Audio Feedback: Sound on collision

Lessons Learned

  • PhysicsActor simplifies physics-based games
  • Collision callbacks allow custom response logic
  • Simple games can be very effective

Snake

Location: src/examples/Snake/

Architecture

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

Key Systems

Entity Pooling

class SnakeScene {
private:
    std::vector<SnakeSegmentActor*> segmentPool;
    std::vector<SnakeSegmentActor*> snakeSegments;

    void resetGame() {
        // Reuse pooled segments
        for (int i = 0; i < initialLength; ++i) {
            SnakeSegmentActor* segment = segmentPool[i];
            segment->resetAlive();
            snakeSegments.push_back(segment);
            addEntity(segment);
        }
    }
};

Grid-Based Movement

class SnakeSegmentActor : public pixelroot32::core::Actor {
private:
    int cellX, cellY;  // Grid position

public:
    void setCellPosition(int x, int y) {
        cellX = x;
        cellY = y;
        // Convert to world position
        this->x = cellX * CELL_SIZE;
        this->y = cellY * CELL_SIZE;
    }
};

Patterns Used

  • 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

Lessons Learned

  • Entity pooling is essential for dynamic entities
  • Grid-based movement simplifies collision detection
  • Pre-allocation avoids memory fragmentation

TicTacToe

Location: src/examples/TicTacToe/

Architecture

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

Key Systems

Board Representation

class TicTacToeScene {
private:
    int board[3][3];  // 0=empty, 1=X, 2=O
    bool playerTurn = true;

    bool makeMove(int row, int col, int player) {
        if (board[row][col] == 0) {
            board[row][col] = player;
            return true;
        }
        return false;
    }
};

Win Detection

int checkWinner() {
    // Check rows
    for (int i = 0; i < 3; i++) {
        if (board[i][0] == board[i][1] && board[i][1] == board[i][2]) {
            return board[i][0];
        }
    }
    // Check columns, diagonals...
    return 0; // No winner
}

Patterns Used

  • 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

Lessons Learned

  • Turn-based games are straightforward to implement
  • Simple AI can be effective for basic games
  • Grid-based logic is easy to reason about

CameraDemo

Location: src/examples/CameraDemo/

Architecture

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

Key Systems

Camera Setup

class CameraDemoScene {
private:
    pixelroot32::graphics::Camera2D camera;
    float levelWidth;

public:
    void init() override {
        camera = pixelroot32::graphics::Camera2D(240, 240);
        camera.setBounds(0, levelWidth - 240);
    }

    void update(unsigned long deltaTime) override {
        camera.followTarget(player->x, player->y);
    }

    void draw(pixelroot32::graphics::Renderer& renderer) override {
        camera.apply(renderer);
        renderer.drawTileMap(levelTileMap, 0, 0, Color::White);
        Scene::draw(renderer);
    }
};

Platformer Physics

class PlayerCube : public pixelroot32::core::PhysicsActor {
public:
    void update(unsigned long deltaTime) override {
        // Input handling
        // Gravity application
        // Jump logic
        // Platform collision
        PhysicsActor::update(deltaTime);
    }
};

Patterns Used

  • Camera Following: Dead-zone camera following
  • Tilemap Rendering: Efficient level rendering
  • Parallax Scrolling: Multiple background layers
  • Platform Collision: Custom collision with platforms

Lessons Learned

  • Camera system enables large levels
  • Tilemaps are efficient for level data
  • Parallax adds depth to 2D games
  • Platform collision requires custom logic

SpritesDemo

Location: src/examples/SpritesDemo/

Architecture

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

Key Systems

2bpp Sprite Usage

#ifdef PIXELROOT32_ENABLE_2BPP_SPRITES
static const pixelroot32::graphics::Sprite2bpp SPRITE_2BPP = {
    SPRITE_DATA,
    SPRITE_PALETTE,
    16, 32, 4
};

renderer.drawSprite(SPRITE_2BPP, x, y, false);
#endif

Animation Display

class SpritesDemoActor : public pixelroot32::core::Entity {
private:
    unsigned long timer = 0;
    uint8_t currentFrame = 0;

public:
    void update(unsigned long deltaTime) override {
        timer += deltaTime;
        if (timer >= 150) {
            timer -= 150;
            currentFrame = (currentFrame + 1) % 9;
        }
    }
};

Patterns Used

  • Format Comparison: Shows different sprite formats
  • Animation Loop: Frame-based animation
  • Conditional Compilation: Uses build flags

Lessons Learned

  • Advanced formats provide more color options
  • Animation is straightforward with frame arrays
  • Build flags enable/disable experimental features

Common Patterns Across Examples

Scene Initialization

All examples follow this pattern:

void init() override {
    // 1. Set palette
    pixelroot32::graphics::setPalette(PaletteType::NES);

    // 2. Create background entity
    addEntity(new BackgroundEntity());

    // 3. Create game entities
    player = new PlayerActor(...);
    addEntity(player);

    // 4. Initialize game state
    resetGame();
}

Update Pattern

void update(unsigned long deltaTime) override {
    // 1. Process input
    handleInput();

    // 2. Update game logic
    updateGameLogic();

    // 3. Call parent update (updates all entities)
    Scene::update(deltaTime);

    // 4. Post-update logic
    checkGameState();
}

Draw Pattern

void draw(pixelroot32::graphics::Renderer& renderer) override {
    // 1. Apply camera (if used)
    camera.apply(renderer);

    // 2. Draw background/tilemap
    renderer.drawTileMap(background, 0, 0, Color::White);

    // 3. Call parent draw (draws all entities)
    Scene::draw(renderer);

    // 4. Draw UI/HUD
    drawHUD(renderer);
}

Learning Path

Beginner Examples

  1. Pong: Start here - simple physics and collisions
  2. TicTacToe: Learn turn-based logic
  3. Snake: Understand entity pooling

Intermediate Examples

  1. CameraDemo: Learn scrolling and parallax
  2. SpritesDemo: Explore sprite formats

Advanced Examples

  1. Space Invaders: Complete game with all systems

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.