Skip to content

API Reference: Physics Module ​

Source of truth:

  • include/core/Actor.h, include/core/PhysicsActor.h
  • include/physics/CollisionSystem.h
  • include/physics/PhysicsScheduler.h
  • include/physics/KinematicActor.h, include/physics/RigidActor.h
  • include/physics/StaticActor.h, include/physics/SensorActor.h
  • include/physics/TileAttributes.h
  • include/physics/TileCollisionBuilder.h, include/physics/TileConsumptionHelper.h

Overview ​

(Requires PIXELROOT32_ENABLE_PHYSICS=1)

The Physics module provides a custom, highly optimized 2D physics engine. It uses a Flat Solver architecture optimized for embedded devices without hardware floating-point units, resolving collisions through discrete SAT (Separating Axis Theorem) and iterative impulse resolution.

Key Concepts ​

Actor ​

Actor is the base class for entities that occupy space in the world. An Actor is technically an Entity, but specifically manages spatial bounds (width, height, x, y).

Collision Shapes:

  • RECTANGLE (Default): AABB (Axis-Aligned Bounding Box) collision.
  • CIRCLE: Radial collision, great for players or projectiles.

PhysicsActor ​

The core class of the physics system. It extends Actor with physical properties and behaviors.

Key Physical Properties:

  • velocity: The current speed and direction (units per second).
  • mass / invMass: Determines how the actor responds to impulses (0 mass = infinite mass/static).
  • restitution: Bounciness (0.0 to 1.0).
  • friction: Resistance to sliding.
  • drag: Air resistance or fluid drag.
  • collisionLayer & collisionMask: Bitmasks used to filter which actors collide.

Collision Resolution:

  • Handled internally by the CollisionSystem.
  • Users interact via moveAndCollide() (for kinematic bodies) or applyImpulse() (for rigid bodies).

Default Layers ​

MacroValueDescription
LAYER_DEFAULT0x0001Default layer for actors.
LAYER_PLAYER0x0002Typically used for the player character.
LAYER_ENEMY0x0004Typically used for enemies.
LAYER_ENVIRONMENT0x0008Used for solid world boundaries/tiles.

Actor Types ​

StaticActor ​

A PhysicsActor with infinite mass that does not move. Used for walls, floors, and platforms.

cpp
auto wall = scene.createEntity<pixelroot32::physics::StaticActor>();
wall->setSize(100, 20);
wall->setPosition(50, 200);
wall->setCollisionLayer(LAYER_ENVIRONMENT);

SensorActor ​

An actor that detects overlaps but does not physically collide or stop other actors.

cpp
auto trigger = scene.createEntity<pixelroot32::physics::SensorActor>();
trigger->setSize(30, 30);
trigger->setOnOverlap([](PhysicsActor* self, PhysicsActor* other, const WorldCollisionInfo& info) {
    if (other->getCollisionLayer() == LAYER_PLAYER) {
        // Player entered the zone
    }
});

KinematicActor ​

An actor whose movement is fully controlled by the game logic (not forces/impulses), but it stops when hitting solid objects (like a StaticActor).

cpp
auto platform = scene.createEntity<pixelroot32::physics::KinematicActor>();
platform->setSize(40, 10);
// In update loop:
platform->moveAndCollide(Vector2(50.0f * dt, 0));

RigidActor ​

An actor entirely driven by the physics simulation (gravity, impulses, velocity). Best for physics objects like crates or a bouncing ball.

cpp
auto crate = scene.createEntity<pixelroot32::physics::RigidActor>();
crate->setSize(16, 16);
crate->setMass(10.0f);
crate->setRestitution(0.4f);
// In game logic:
crate->applyImpulse(Vector2(0.0f, -200.0f)); // Jump/bounce

CircleActor (Pattern) ​

While not a specific class, setting the collision shape to CIRCLE transforms the actor:

cpp
auto ball = scene.createEntity<pixelroot32::physics::RigidActor>();
ball->setCollisionShape(CollisionShape::CIRCLE);
ball->setSize(16, 16); // Sets radius to 8

Architecture Notes ​

CollisionSystem (The Flat Solver) ​

The CollisionSystem is attached to a Scene. It manages the broadphase (Spatial Grid) and narrowphase collision detection.

  • Uses Discrete Collision Detection.
  • Solves penetration using projection (positional correction).
  • Solves velocities using iterative impulses.
  • Emits overlap and collision callbacks.

PhysicsScheduler ​

Ensures the physics simulation runs at a fixed time step regardless of the rendering frame rate. This guarantees deterministic jumps and collision responses.

  • Default timestep: 1/60.0f seconds.
  • Cap: MAX_FRAME_ACCUMULATOR prevents the "spiral of death" during lag spikes.

Configuration & Data Structures ​

WorldCollisionInfo ​

Struct passed to collision callbacks.

  • normal: The collision normal (pointing away from the other object).
  • penetration: Depth of the overlap.
  • contactPoint: The estimated point of impact.

LimitRect ​

A structural boundary used to restrict actor movement (e.g., keeping the player inside the camera view or level bounds).

CollisionSystem Constants ​

ConstantDescription
PHYSICS_MAX_PAIRSMax broadphase collision pairs (default: 128).
PHYSICS_MAX_CONTACTSMax simultaneous narrowphase contacts (default: 128).
VELOCITY_ITERATIONSNumber of passes in the impulse solver (default: 2).

Tile Collision Utilities ​

TileAttributes ​

Custom metadata attached to tiles. Managed via TileConsumptionHelper.

IMPORTANT

Since attributes are stored in Flash memory on ESP32, use PIXELROOT32_STRCMP_P or PIXELROOT32_MEMCPY_P to compare or copy strings from attributes.

TileConsumptionHelper ​

A utility to consume tilemap arrays and extract custom properties (like solid/water/damage flags).

TileCollisionBuilder ​

A utility that converts grid-based tilemaps into optimized StaticActor collision blocks. It merges adjacent solid tiles into larger rectangles to drastically reduce the broadphase entity count.

Example Usage:

cpp
using pixelroot32::physics::TileCollisionBuilder;
using pixelroot32::physics::CollisionBox;

std::vector<CollisionBox> boxes;
TileCollisionBuilder::buildOptimizedBoxes(
    mapWidth, mapHeight, tileSize,
    [&](int x, int y) {
        return isTileSolid(x, y); // Your logic
    },
    boxes
);

// Spawn a StaticActor for each resulting box
for (const auto& box : boxes) {
    auto actor = scene.createEntity<StaticActor>();
    actor->setPosition(box.x, box.y);
    actor->setSize(box.width, box.height);
}

Released under the MIT License.