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¶
Inheritance¶
- Base class: None (standalone class)
- Used by: Scenes (for scrolling and camera control)
Constructors¶
Camera2D(int viewportWidth, int viewportHeight)¶
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"
// Create camera matching display size
pixelroot32::graphics::Camera2D camera(128, 128);
// Or get from renderer
int width = renderer.getWidth();
int height = renderer.getHeight();
pixelroot32::graphics::Camera2D camera(width, height);
Public Methods¶
void setPosition(float x, float y)¶
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:
void setBounds(float minX, float maxX)¶
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
// Prevent camera from showing outside level
camera.setBounds(0.0f, 512.0f - 128.0f);
void setVerticalBounds(float minY, float maxY)¶
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
camera.setVerticalBounds(0.0f, 512.0f - 128.0f);
void followTarget(float targetX)¶
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 {
// Update player position
player->update(deltaTime);
// Camera follows player horizontally
camera.followTarget(player->x);
camera.apply(renderer);
}
void followTarget(float targetX, float targetY)¶
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 {
player->update(deltaTime);
// Camera follows player in both axes
camera.followTarget(player->x, player->y);
camera.apply(renderer);
}
float getX() const¶
Gets the current X position of the camera.
Returns: - float: Current X position in world space
Example:
float getY() const¶
Gets the current Y position of the camera.
Returns: - float: Current Y position in world space
Example:
void apply(Renderer& renderer) const¶
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 {
// Apply camera offset
camera.apply(renderer);
// Draw world (offset applied automatically)
renderer.drawTileMap(levelMap, 0, 0, Color::White);
renderer.drawSprite(playerSprite, playerX, playerY, Color::White);
// UI elements (not affected by camera)
renderer.setDisplayOffset(0, 0); // Reset for UI
renderer.drawText("Score: 100", 10, 10, Color::White, 1);
}
Dead-Zone Following¶
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
void update(unsigned long deltaTime) override {
player->update(deltaTime);
// Camera follows (dead zone handled internally)
camera.followTarget(player->x, player->y);
}
Usage Example¶
#include "graphics/Camera2D.h"
class GameScene : public pixelroot32::core::Scene {
private:
pixelroot32::graphics::Camera2D camera;
PlayerActor* player;
TileMap levelMap;
public:
void init() override {
// Create camera matching display size
auto& renderer = engine.getRenderer();
camera = pixelroot32::graphics::Camera2D(
renderer.getWidth(),
renderer.getHeight()
);
// Set level boundaries
// Level is 512x512, viewport is 128x128
camera.setBounds(0.0f, 512.0f - 128.0f);
camera.setVerticalBounds(0.0f, 512.0f - 128.0f);
// Create player
player = new PlayerActor(64, 64);
addEntity(player);
}
void update(unsigned long deltaTime) override {
Scene::update(deltaTime);
// Camera follows player
camera.followTarget(player->x, player->y);
}
void draw(pixelroot32::graphics::Renderer& renderer) override {
// Apply camera
camera.apply(renderer);
// Draw world (camera offset applied)
renderer.drawTileMap(levelMap, 0, 0, Color::White);
// Draw entities (Scene::draw handles this)
Scene::draw(renderer);
// Reset offset for UI
renderer.setDisplayOffset(0, 0);
renderer.drawText("Score: 100", 10, 10, Color::White, 1);
}
};
Parallax Scrolling¶
Use multiple cameras or manual offset for parallax:
void draw(pixelroot32::graphics::Renderer& renderer) override {
// Background layer (slow parallax)
float bgOffsetX = camera.getX() * 0.5f; // 50% speed
renderer.setDisplayOffset(-bgOffsetX, 0);
renderer.drawTileMap(backgroundMap, 0, 0, Color::White);
// Midground layer (normal speed)
camera.apply(renderer);
renderer.drawTileMap(midgroundMap, 0, 0, Color::White);
// Foreground (entities, normal speed)
Scene::draw(renderer);
// UI (no offset)
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¶
- Renderer - Rendering system
- Manual - Cameras and Scrolling
- API Overview