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 {
    class Actor : public Entity {
        // ...
    };
}

Inheritance

  • Inherits from: Entity
  • Inherited by: PhysicsActor and your custom actor classes

Constructors

Actor(float x, float y, int w, int h)

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 {
public:
    PlayerActor(float x, float y) 
        : Actor(x, y, 16, 16) {
        // Set collision layer and mask
        layer = pixelroot32::physics::DefaultLayers::kPlayer;
        mask = pixelroot32::physics::DefaultLayers::kEnemy | 
               pixelroot32::physics::DefaultLayers::kObstacle;
    }

    void update(unsigned long deltaTime) override {
        Actor::update(deltaTime);
        // Player logic
    }

    void draw(pixelroot32::graphics::Renderer& renderer) override {
        renderer.drawSprite(playerSprite, 
                           static_cast<int>(x), 
                           static_cast<int>(y), 
                           Color::White);
    }

    Rect getHitBox() override {
        return {x, y, width, height};
    }

    void onCollision(Actor* other) override {
        // Handle collision
    }
};

Public Properties

CollisionLayer layer

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;

CollisionLayer mask

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
actor->mask = pixelroot32::physics::DefaultLayers::kEnemy | 
              pixelroot32::physics::DefaultLayers::kObstacle;

Public Methods

void setCollisionLayer(CollisionLayer l)

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);

void setCollisionMask(CollisionLayer m)

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 | 
                        pixelroot32::physics::DefaultLayers::kObstacle);

bool isInLayer(uint16_t targetLayer) const

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)) {
    // This is a player actor
}

virtual Rect getHitBox() = 0

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 {
    // Return collision bounds (may be smaller than visual)
    return {x + 2, y + 2, width - 4, height - 4};
}

virtual void onCollision(Actor* other) = 0

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 {
    // Check what we collided with
    if (other->isInLayer(pixelroot32::physics::DefaultLayers::kEnemy)) {
        // Take damage
        health--;
        if (health <= 0) {
            isEnabled = false;
        }
    } else if (other->isInLayer(pixelroot32::physics::DefaultLayers::kCollectible)) {
        // Collect item
        score += 10;
        other->isEnabled = false;  // Remove collectible
    }
}

void update(unsigned long deltaTime) override

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 {
    Actor::update(deltaTime);  // Call base implementation

    // Move actor
    float speed = 100.0f;  // pixels per second
    x += (speed * deltaTime) / 1000.0f;
}

Collision Layers

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
player->layer = DefaultLayers::kPlayer;
player->mask = DefaultLayers::kEnemy | DefaultLayers::kObstacle;

// Enemy collides with player and obstacles
enemy->layer = DefaultLayers::kEnemy;
enemy->mask = DefaultLayers::kPlayer | DefaultLayers::kObstacle;

// Projectile collides with enemies
projectile->layer = DefaultLayers::kProjectile;
projectile->mask = DefaultLayers::kEnemy;

Usage Example

#include "core/Actor.h"
#include "physics/CollisionTypes.h"

class EnemyActor : public pixelroot32::core::Actor {
private:
    const pixelroot32::graphics::Sprite* sprite;
    int health = 3;

public:
    EnemyActor(float x, float y) 
        : Actor(x, y, 16, 16),
          sprite(&enemySprite) {
        // Set collision layer and mask
        layer = pixelroot32::physics::DefaultLayers::kEnemy;
        mask = pixelroot32::physics::DefaultLayers::kPlayer | 
               pixelroot32::physics::DefaultLayers::kProjectile;
    }

    void update(unsigned long deltaTime) override {
        Actor::update(deltaTime);

        // Move towards player
        float speed = 50.0f;
        // ... movement logic
    }

    void draw(pixelroot32::graphics::Renderer& renderer) override {
        renderer.drawSprite(*sprite, 
                           static_cast<int>(x), 
                           static_cast<int>(y), 
                           Color::Red);
    }

    Rect getHitBox() override {
        return {x, y, width, height};
    }

    void onCollision(Actor* other) override {
        if (other->isInLayer(pixelroot32::physics::DefaultLayers::kProjectile)) {
            // Hit by projectile
            health--;
            if (health <= 0) {
                isEnabled = false;  // Remove enemy
            }
        }
    }
};

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