simvx.core.nodes_2d.camera

Camera2D – 2D camera with smoothing, zoom, bounds, and shake.

Module Contents

Classes

Camera2D

2D camera for scrolling games.

API

class simvx.core.nodes_2d.camera.Camera2D(**kwargs)[source]

Bases: simvx.core.nodes_2d.node2d.Node2D

2D camera for scrolling games.

Provides target following with smoothing, zoom, viewport bounds/limits, and screen shake effects. The active Camera2D’s offset is applied by the renderer to all 2D draw calls.

Initialization

zoom

‘Property(…)’

smoothing

‘Property(…)’

limit_left

‘Property(…)’

limit_right

‘Property(…)’

limit_top

‘Property(…)’

limit_bottom

‘Property(…)’

cull_mask

‘Bitmask(…)’

gizmo_colour

‘Colour(…)’

set_cull_mask_layer(index: int, enabled: bool = True) → None[source]

Enable or disable a specific cull mask layer (0-31).

is_cull_mask_layer_enabled(index: int) → bool[source]

Check if a specific cull mask layer is enabled (0-31).

property current: simvx.core.math.types.Vec2[source]

Current smoothed camera position in world space.

Reads the post-smoothing, post-limit-clamp position the renderer uses to translate 2D draws. Assignment teleports the camera (skips smoothing for that frame): equivalent to :meth:snap_to without rebinding to the target’s world_position.

on_enter_tree()[source]
on_exit_tree() → None[source]

Clear the tree’s current-camera reference if it points at us.

Without this, destroying the active Camera2D leaves a stale reference on the tree: the renderer keeps following the freed camera each frame, panning over to whatever world_position arrives via stale _current. Other Camera2D instances claim the slot back via their own on_enter_tree(); the only failure mode is “active camera was the last one in the scene”, which now correctly resets to None.

shake(intensity: float = 5.0, duration: float = 0.3)[source]

Start a screen shake effect.

snap_to(pos: simvx.core.math.types.Vec2 | None = None) → None[source]

Skip smoothing this frame.

If pos is given, snap there. If pos is None, snap to the current target’s world_position (or the camera’s own world_position if no target). Bounds limits and zoom are honoured; shake jitter continues uninterrupted.

on_update(dt: float)[source]
canvas_transform(screen_size: simvx.core.math.types.Vec2 | tuple[float, float], shake: simvx.core.math.types.Vec2 | tuple[float, float] | None = None) → tuple[float, float, float, float, float, float][source]

The single Camera2D screen mapping: world -> screen affine (a,b,c,d,tx,ty).

This is the one source of truth. The renderer bakes this exact matrix into the 2D vertex stream, world_to_screen/screen_to_world invert it, and every Family-B pass (lights, particles, tiles) routes through it, so hit-testing and rendering provably agree under zoom + pan + shake.

screen_size is the viewport size in pixels; shake defaults to the camera’s current per-frame jitter (_shake_offset). A point p maps to (a*p.x + c*p.y + tx, b*p.x + d*p.y + ty) (rotation-free: b == c == 0).

world_to_screen(world_pos: simvx.core.math.types.Vec2, screen_size: simvx.core.math.types.Vec2 | tuple[float, float] | None = None) → simvx.core.math.types.Vec2[source]

Convert a world position to screen coordinates (via :meth:canvas_transform).

screen_size defaults to the tree’s screen size.

screen_to_world(screen_pos: simvx.core.math.types.Vec2, screen_size: simvx.core.math.types.Vec2 | tuple[float, float] | None = None) → simvx.core.math.types.Vec2[source]

Convert screen coordinates to world position (inverse of :meth:canvas_transform).

screen_size defaults to the tree’s screen size.

get_gizmo_lines() → list[tuple[simvx.core.math.types.Vec2, simvx.core.math.types.Vec2]][source]

Return line segments for viewport bounds rectangle and crosshair at camera position.

position

‘_SpatialVecProperty(…)’

rotation

‘Property(…)’

scale

‘_SpatialVecProperty(…)’

top_level

‘Property(…)’

z_index

‘Property(…)’

z_as_relative

‘Property(…)’

render_layer

‘Property(…)’

set_render_layer(index: int, enabled: bool = True) → None
is_on_render_layer(index: int) → bool
property absolute_z_index: int
property rotation_degrees: float
property world_position: simvx.core.math.types.Vec2
property world_rotation: float
property world_scale: simvx.core.math.types.Vec2
property world_transform: tuple[simvx.core.math.types.Vec2, simvx.core.math.types.Vec2, float]
property forward: simvx.core.math.types.Vec2
property right: simvx.core.math.types.Vec2
translate(offset: tuple[float, float] | numpy.ndarray)
rotate(radians: float)
rotate_deg(degrees: float)
look_at(target: tuple[float, float] | numpy.ndarray)
to_global(point) → simvx.core.math.types.Vec2
to_local(point) → simvx.core.math.types.Vec2
transform_points(points: list[simvx.core.math.types.Vec2]) → list[simvx.core.math.types.Vec2]
wrap_screen(margin: float = 20)
post_processed

‘Property(…)’

property transform_render_dirty: bool
strict_errors: ClassVar[bool]

True

dev_checks: ClassVar[bool]

None

dev_warnings: ClassVar[bool]

None

freeze_check_interval: ClassVar[float]

1.0

dynamic: bool

False

visible

‘Property(…)’

update_mode

‘Property(…)’

focus_mode

‘Property(…)’

drag_threshold

‘Property(…)’

focus_entered

‘Signal(…)’

focus_exited

‘Signal(…)’

__properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]

None

classmethod __init_subclass__(**kwargs)
property name: str
property visible_in_tree: bool
property input_player: simvx.core.input.players.InputPlayer
property input_context: simvx.core.input.contexts.InputContext | None
reset_error() → None
add_child(node: simvx.core.node.T) → simvx.core.node.T
remove_child(node: simvx.core.node.Node) → None
reparent(new_parent: simvx.core.node.Node)
node_at(path, default=_NO_DEFAULT)
find(target, *, direct: bool = False)
find_all(target, *, direct: bool = False)
expect(target, *, direct: bool = False)
ancestor(target)
walk(*, include_self: bool = True) → collections.abc.Iterator[simvx.core.node.Node]
property path: str
property is_scene_root: bool
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) → bool
on_ready() → None
on_fixed_update(dt: float) → None
on_draw(canvas) → None
on_draw_3d(gizmos) → None
on_picked(event: simvx.core.input.events.PickEvent) → bool | None
on_gui_input(event: simvx.core.input.events.GuiInputEvent) → bool | None
start_coroutine(gen: simvx.core.descriptors.Coroutine) → simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
property focused: bool
property focus_rect: tuple[float, float, float, float] | None
drag_threshold_for(pointer_type: simvx.core.input.enums.PointerType | str) → float
grab_focus() → None
release_focus() → None
capture_pointer(pointer_id: int | None = None) → None
release_pointer(pointer_id: int | None = None) → None
queue_redraw() → None
property render_dirty: bool
clear_children()
destroy()
property destroying: bool
property destroyed: bool
call_deferred(method: collections.abc.Callable[..., Any], *args: Any) → None
property app
property tree: simvx.core.scene_tree.SceneTree
property viewport_size: simvx.core.math.types.Vec2
property viewport_insets: tuple[float, float, float, float]
property physics
property physics_2d
__getitem__(key: str)
classmethod get_properties() → dict[str, simvx.core.descriptors.Property]
__repr__()