camera.py

Camera System - Advanced 2D Camera with Smooth Movement, Effects, and Parallax

LOCATION: lunaengine/graphics/camera.py

DESCRIPTION:
A flexible, high‑performance 2D camera system for LunaEngine. Features:
- Unified coordinate system: camera.position = center of viewport
- Strategy‑based follow modes (extensible via FollowStrategy)
- Smooth interpolation with multiple easing types
- Constraints (zoom limits, world boundaries)
- Stackable effects (shake, trauma, fade, etc.)
- Optimised parallax backgrounds with tile support

LIBRARIES USED:
- pygame: Vector2, Rect, Surface operations
- numpy: Random for shake, vectorized operations (optional)
- abc, enum, dataclasses, typing

class CameraMode

Description

Legacy follow modes – kept for backward compatibility.
Internally mapped to FollowStrategy instances.

Attributes
FIXED: Any = 'fixed'
FOLLOW: Any = 'follow'
PLATFORMER: Any = 'platformer'
TOPDOWN: Any = 'topdown'
Methods

No methods defined.

class CameraShakeType

Description

Type of camera shake effect.

Attributes
POSITIONAL: Any = 'positional'
ROTATIONAL: Any = 'rotational'
TRAUMA: Any = 'trauma'
Methods

No methods defined.

class InterpolationType

Description

Easing functions for smooth camera movement.

Attributes
LINEAR: Any = 'linear'
SMOOTHSTEP: Any = 'smoothstep'
QUADRATIC_IN: Any = 'quadratic_in'
QUADRATIC_OUT: Any = 'quadratic_out'
QUADRATIC_IN_OUT: Any = 'quadratic_in_out'
CUBIC_IN: Any = 'cubic_in'
CUBIC_OUT: Any = 'cubic_out'
CUBIC_IN_OUT: Any = 'cubic_in_out'
Methods

No methods defined.

class FollowStrategy

Description

Abstract base class for camera follow behaviours.

Methods
def get_target_position(self: Any, camera: 'Camera', dt: float) -> pygame.Vector2
Return the desired world position of the camera (center).

class SimpleFollow

Description

Follow the target's world position directly.

Methods
def get_target_position(self: Any, camera: 'Camera', dt: float) -> pygame.Vector2
No documentation

class FixedFollow

Description

Keep the camera at a fixed world position, ignoring the target.

Methods
def __init__(self: Any, fixed_position: Union[Tuple[float, float], pygame.Vector2]) -> Any
No documentation
def get_target_position(self: Any, camera: 'Camera', dt: float) -> pygame.Vector2
No documentation

class PlatformerFollow

Description

Platformer-style camera with a deadzone in screen space.
The camera moves only when the target leaves the deadzone rectangle.

Methods
def __init__(self: Any, deadzone_rect: Optional[pygame.Rect] = None) -> Any
No documentation
def get_target_position(self: Any, camera: 'Camera', dt: float) -> pygame.Vector2
No documentation

class TopDownFollow

Description

Top-down RPG style camera with look‑ahead based on target velocity/direction.

Methods
def __init__(self: Any, lead_factor: float = 0.3) -> Any
No documentation
def get_target_position(self: Any, camera: 'Camera', dt: float) -> pygame.Vector2
No documentation

class CameraConstraints

Description

Limits applied to camera movement and zoom.

Attributes
min_zoom: float = 0.1
max_zoom: float = 10.0
bounds: Optional[pygame.Rect] = None
rotation_range: Tuple[float, float] = (-180.0, 180.0)
Methods

No methods defined.

class CameraEffect

Description

Base class for temporary camera effects (shake, fade, flash, etc.).

Methods
def update(self: Any, dt: float) -> bool
Update effect state. Return True if still active, False when finished.
def apply(self: Any, camera: 'Camera') -> None
Modify the camera's offset, rotation, zoom, etc.

class ShakeEffect

Description

Positional or rotational shake with intensity decay.

Methods
def __init__(self: Any, intensity: float = 1.0, duration: float = 0.5, shake_type: CameraShakeType = CameraShakeType.POSITIONAL) -> Any
No documentation
def update(self: Any, dt: float) -> bool
No documentation
def apply(self: Any, camera: 'Camera') -> None
No documentation

class TraumaEffect

Description

Trauma‑based shake – intensity scales with trauma^2.

Methods
def __init__(self: Any, trauma: float = 1.0, decay_rate: float = 1.5) -> Any
No documentation
def update(self: Any, dt: float) -> bool
No documentation
def apply(self: Any, camera: 'Camera') -> None
No documentation

class ParallaxLayer

Description

A single parallax layer with tile support.

Methods
def __init__(self: Any, surface: pygame.Surface, speed_factor: float, tile_mode: bool = True, offset: Tuple[float, float] = (0, 0)) -> Any
No documentation
def update(self: Any, camera_position: pygame.Vector2, dt: float) -> Any
Update the layer's world offset based on camera position.
def render(self: Any, camera: 'Camera', renderer: Any) -> None
Render the layer using the provided renderer.
def _draw_surface(self: Any, renderer: Any, surface: pygame.Surface, x: int, y: int) -> Any
Renderer‑agnostic surface drawing.

class ParallaxBackground

Description

Collection of parallax layers with optional caching.

Methods
def __init__(self: Any, camera: 'Camera') -> Any
No documentation
def add_layer(self: Any, surface: pygame.Surface, speed_factor: float, tile_mode: bool = True, offset: Tuple[float, float] = (0, 0)) -> ParallaxLayer
Add a new layer and return it.
def remove_layer(self: Any, layer: ParallaxLayer) -> Any
Remove a layer if present.
def clear_layers(self: Any) -> Any
Remove all layers.
def update(self: Any, dt: float) -> Any
Update all layers.
def render(self: Any, renderer: Any) -> bool
Render all layers in order (back to front).

class Camera

Description

Advanced 2D Camera with unified coordinate system (position = viewport center).
Supports multiple follow strategies, constraints, effects, and parallax.

Methods
def __init__(self: Any, scene: 'Scene', width: int, height: int) -> Any
No documentation
def position(self: Any) -> pygame.Vector2
Camera position with active shake offset applied.
def position(self: Any, value: Any) -> Any
Set the base camera position (center of viewport).
def base_position(self: Any) -> pygame.Vector2
Base camera position without shake offset.
def mode(self: Any) -> CameraMode
Legacy: get current follow mode (maps to strategy).
def mode(self: Any, value: CameraMode) -> Any
Legacy: set follow mode and update strategy accordingly.
def viewport_rect(self: Any) -> pygame.Rect
World rectangle visible through the camera (topleft in world coordinates).
def set_target(self: Any, target: Any, mode: Optional[CameraMode] = None) -> Any
Set the camera target. If mode is provided, it updates the follow strategy.
def set_follow_strategy(self: Any, strategy: FollowStrategy) -> Any
Set a custom follow strategy.
def set_bounds(self: Any, bounds: pygame.Rect) -> Any
Set world boundaries (legacy).
def set_zoom(self: Any, zoom: float, smooth: bool = True) -> Any
Set target zoom level.
def shake(self: Any, intensity: float = 1.0, duration: float = 0.5, shake_type: CameraShakeType = CameraShakeType.POSITIONAL) -> Any
Start a camera shake effect.
def add_trauma(self: Any, amount: float) -> Any
Add trauma (if a TraumaEffect exists, increase it; otherwise create one).
def add_effect(self: Any, effect: CameraEffect) -> Any
Add a new camera effect (will be updated/removed automatically).
def remove_effect(self: Any, effect: CameraEffect) -> Any
Remove a specific effect.
def clear_effects(self: Any) -> Any
Remove all active effects.
def update(self: Any, dt: float) -> Any
Update camera position, zoom, effects, and parallax.
def _apply_smooth_movement(self: Any, dt: float) -> Any
Interpolate _position towards target_position.
def _apply_smooth_zoom(self: Any, dt: float) -> Any
Interpolate zoom towards target_zoom.
def _update_effects(self: Any, dt: float) -> Any
Update all active effects and remove finished ones.
def _apply_constraints(self: Any) -> Any
Apply world bounds and zoom limits.
def _update_viewport_rect(self: Any) -> Any
Recalculate viewport_rect based on current position and zoom.
def _update_renderer_camera_position(self: Any) -> Any
Push camera position to the renderer.
def world_to_screen(self: Any, world_pos: Union[Tuple[float, float], pygame.Vector2, List[float], np.ndarray]) -> pygame.Vector2
Convert world coordinates to screen pixels (top‑left origin).
def world_to_screen_list(self: Any, world_positions: List, return_type: str = 'list') -> Any
Batch conversion for lists of world positions.
def screen_to_world(self: Any, screen_pos: Union[Tuple[float, float], pygame.Vector2, List[float], np.ndarray]) -> pygame.Vector2
Convert screen pixel coordinates to world coordinates.
def screen_to_world_list(self: Any, screen_positions: List) -> List[pygame.Vector2]
Batch conversion for lists of screen positions.
def screen_to_world_vector(self: Any, screen_vec: Union[Tuple[float, float], pygame.Vector2]) -> pygame.Vector2
Convert a screen vector (e.g., movement) to world vector (ignores viewport offset).
def convert_size_zoom(self: Any, size: Union[Tuple[float, float], List[float], float, pygame.Vector2]) -> Any
Scale a size from world units to screen pixels, or vice‑versa.
def convert_size_zoom_list(self: Any, sizes: List, return_type: str = 'list') -> Any
Batch version of convert_size_zoom.
def get_visible_rect(self: Any) -> pygame.Rect
Alias for viewport_rect.
def is_visible(self: Any, world_pos: Union[Tuple[float, float], pygame.Vector2], margin: float = 0.0) -> bool
Check if a world point is inside the viewport (plus optional margin).
def _get_target_position(self: Any) -> pygame.Vector2
Extract the world position of the current target (if any).
def add_parallax_layer(self: Any, surface: pygame.Surface, speed_factor: float, tile_mode: bool = True, offset: Tuple[float, float] = (0, 0)) -> ParallaxLayer
Add a new parallax layer to the camera.
def remove_parallax_layer(self: Any, layer: ParallaxLayer) -> Any
Remove a parallax layer.
def clear_parallax_layers(self: Any) -> Any
Remove all parallax layers.
def render_parallax(self: Any, renderer: Any) -> bool
Render the parallax background.
def enable_parallax(self: Any, enabled: bool = True) -> Any
Enable/disable parallax rendering.
def get_parallax_layer_count(self: Any) -> int
Number of active parallax layers.

Global Functions

def _interpolate_linear(start: float, end: float, t: float) -> float

No documentation

def _interpolate_smoothstep(start: float, end: float, t: float) -> float

No documentation

def _interpolate_quadratic_in(start: float, end: float, t: float) -> float

No documentation

def _interpolate_quadratic_out(start: float, end: float, t: float) -> float

No documentation

def _interpolate_quadratic_in_out(start: float, end: float, t: float) -> float

No documentation

def _interpolate_cubic_in(start: float, end: float, t: float) -> float

No documentation

def _interpolate_cubic_out(start: float, end: float, t: float) -> float

No documentation

def _interpolate_cubic_in_out(start: float, end: float, t: float) -> float

No documentation

def interpolate(start: Union[float, pygame.Vector2], end: Union[float, pygame.Vector2], t: float, itype: InterpolationType = InterpolationType.LINEAR) -> Union[float, pygame.Vector2]

Interpolate between start and end using the specified easing function.

Back to Graphics Module