simvx.core.physics.engine

Physics engine — rigid body dynamics, collision response, joints, raycasting.

Pure-Python physics built on numpy. Integrates with the node lifecycle via physics_process(dt) and the existing collision shapes from simvx.core.collision.

Architecture: PhysicsServer (singleton) manages bodies and steps the simulation. RigidBody2D/3D nodes register themselves with the server on enter_tree and unregister on exit_tree. The SceneTree’s physics tick calls physics_process on all nodes, which triggers force integration.

Module Contents

Classes

PhysicsMaterial

Surface properties for physics bodies.

BodyMode

Physics body simulation mode.

Contact

A single collision contact between two bodies.

PhysicsServer

Central physics simulation manager.

RigidBody3D

3D rigid body with full physics simulation.

RigidBody2D

2D rigid body with full physics simulation.

StaticBody3D

Immovable 3D physics body. Used for floors, walls, and obstacles.

StaticBody2D

Immovable 2D physics body. Used for platforms and walls.

KinematicBody3D

3D body moved by code that participates in collisions.

KinematicBody2D

2D body moved by code that participates in collisions.

Joint2D

Base class for 2D physics joints.

Joint3D

Base class for 3D physics joints.

PinJoint2D

Pin joint — constrains two 2D bodies to maintain a fixed distance.

PinJoint3D

Pin joint — constrains two 3D bodies to maintain a fixed distance.

HingeJoint3D

Hinge joint — constrains two 3D bodies to rotate around a shared axis.

RayCast3D

Persistent ray query node for 3D physics.

RayCast2D

Persistent ray query node for 2D physics.

Data

API

simvx.core.physics.engine.log

‘getLogger(…)’

simvx.core.physics.engine.__all__

[‘PhysicsMaterial’, ‘BodyMode’, ‘PhysicsServer’, ‘RigidBody2D’, ‘RigidBody3D’, ‘StaticBody2D’, ‘Stat…

class simvx.core.physics.engine.PhysicsMaterial

Surface properties for physics bodies.

Attributes: friction: Coefficient of friction [0..1]. Higher = more grip. restitution: Coefficient of restitution [0..1]. 1 = perfectly elastic bounce. density: Mass per unit volume. Used for auto-computing mass from shape volume.

friction: float

0.5

restitution: float

0.3

density: float

1.0

class simvx.core.physics.engine.BodyMode

Bases: enum.IntEnum

Physics body simulation mode.

Initialization

Initialize self. See help(type(self)) for accurate signature.

DYNAMIC

0

KINEMATIC

1

STATIC

2

__abs__()
__add__()
__and__()
__bool__()
__ceil__()
__delattr__()
__dir__()
__divmod__()
__eq__()
__float__()
__floor__()
__floordiv__()
__format__()
__ge__()
__getattribute__()
__getnewargs__()
__getstate__()
__gt__()
__hash__()
__index__()
__int__()
__invert__()
__le__()
__lshift__()
__lt__()
__mod__()
__mul__()
__ne__()
__neg__()
__new__()
__or__()
__pos__()
__pow__()
__radd__()
__rand__()
__rdivmod__()
__reduce__()
__reduce_ex__()
__repr__()
__rfloordiv__()
__rlshift__()
__rmod__()
__rmul__()
__ror__()
__round__()
__rpow__()
__rrshift__()
__rshift__()
__rsub__()
__rtruediv__()
__rxor__()
__setattr__()
__sizeof__()
__str__()
__sub__()
__subclasshook__()
__truediv__()
__trunc__()
__xor__()
as_integer_ratio()
bit_count()
bit_length()
conjugate()
class denominator
class imag
is_integer()
class numerator
class real
to_bytes()
__deepcopy__(memo)
__copy__()
name()
value()
class simvx.core.physics.engine.Contact

A single collision contact between two bodies.

Attributes: body_a: First body in the collision pair. body_b: Second body in the collision pair. normal: Contact normal pointing from A to B (normalized). point: Contact point in world space. depth: Penetration depth (positive when overlapping).

body_a: Any

None

body_b: Any

None

normal: numpy.ndarray

None

point: numpy.ndarray

None

depth: float

None

class simvx.core.physics.engine.PhysicsServer(cell_size: float = 2.0)

Central physics simulation manager.

Manages all physics bodies, runs broadphase/narrowphase collision detection, resolves contacts with impulse-based response, and provides raycasting.

Usage: server = PhysicsServer.get() server.set_gravity(Vec3(0, -9.8, 0))

Initialization

classmethod get() simvx.core.physics.engine.PhysicsServer

Return the singleton PhysicsServer, creating it if needed.

classmethod reset() None

Reset the singleton (useful for tests).

set_gravity(gravity) None

Set global gravity vector.

Args: gravity: Gravity as Vec3, tuple, or ndarray. Default (0, -9.8, 0).

property gravity: numpy.ndarray
add_body(body) None

Register a physics body node with the server.

remove_body(body) None

Unregister a physics body from the server.

step(dt: float) None

Advance the physics simulation by dt seconds.

This performs:

  1. Sync positions from nodes

  2. Apply gravity and forces → integrate velocities

  3. Broadphase + narrowphase collision detection

  4. Iterative impulse-based collision response

  5. Integrate positions

  6. Write results back to nodes

  7. Emit body_entered/body_exited signals

raycast(origin, direction, max_dist: float = 1000.0, layer_mask: int = 4294967295) list[simvx.core.collision.RayHit]

Cast a ray through the physics world.

Args: origin: Ray start position (Vec3, tuple, or ndarray). direction: Ray direction (will be normalized). max_dist: Maximum ray length. layer_mask: Bitmask to filter bodies by collision layer.

Returns: List of RayHit sorted by distance.

get_overlapping_bodies(body) list

Return all bodies currently overlapping the given body.

property body_count: int
class simvx.core.physics.engine.RigidBody3D(**kwargs)

Bases: simvx.core.physics.engine._PhysicsBodyMixin, simvx.core.engine.Node3D

3D rigid body with full physics simulation.

Supports dynamic, kinematic, and static modes. Collision shapes are set via set_collision_shape() or auto-detected from child nodes.

Signals: body_entered: Emitted when another body starts overlapping. body_exited: Emitted when a previously overlapping body separates.

Example: class Ball(RigidBody3D): mass = Property(2.0) physics_material = PhysicsMaterial(restitution=0.8)

    def ready(self):
        self.set_collision_shape(SphereShape(radius=0.5))

Initialization

mass

‘Property(…)’

gravity_scale

‘Property(…)’

linear_damp

‘Property(…)’

angular_damp

‘Property(…)’

collision_layer

‘Property(…)’

collision_mask

‘Property(…)’

enter_tree() None
exit_tree() None
physics_process(dt: float) None

Called each physics tick. Override for custom behavior.

The PhysicsServer handles integration; this hook runs after forces are accumulated but before the server step.

apply_force(force, position=None) None
apply_impulse(impulse, position=None) None
apply_torque(torque) None
set_collision_shape(shape: simvx.core.collision.CollisionShape) None
property position
property rotation: simvx.core.math.types.Quat
property scale
property rotation_degrees: simvx.core.math.types.Vec3
property global_position: simvx.core.math.types.Vec3
property global_rotation: simvx.core.math.types.Quat
property global_scale: simvx.core.math.types.Vec3
property forward: simvx.core.math.types.Vec3
property right: simvx.core.math.types.Vec3
property up: simvx.core.math.types.Vec3
translate(offset: tuple[float, float, float] | numpy.ndarray)
translate_global(offset: tuple[float, float, float] | numpy.ndarray)
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)
rotate_x(angle: float)
rotate_y(angle: float)
rotate_z(angle: float)
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()
class simvx.core.physics.engine.RigidBody2D(**kwargs)

Bases: simvx.core.physics.engine._PhysicsBodyMixin, simvx.core.engine.Node2D

2D rigid body with full physics simulation.

Same API as RigidBody3D but works in 2D space (x, y). Angular velocity is a scalar (rotation around the z-axis).

Example: class Ball2D(RigidBody2D): mass = Property(1.0)

    def ready(self):
        self.set_collision_shape(SphereShape(radius=10))

Initialization

mass

‘Property(…)’

gravity_scale

‘Property(…)’

linear_damp

‘Property(…)’

angular_damp

‘Property(…)’

collision_layer

‘Property(…)’

collision_mask

‘Property(…)’

enter_tree() None
exit_tree() None
physics_process(dt: float) None
apply_force(force, position=None) None
apply_impulse(impulse, position=None) None
apply_torque(torque) None
set_collision_shape(shape: simvx.core.collision.CollisionShape) None
z_index

‘Property(…)’

z_as_relative

‘Property(…)’

property absolute_z_index: int
property position: simvx.core.math.types.Vec2
property rotation: float
property rotation_degrees: float
property scale: simvx.core.math.types.Vec2
property global_position: simvx.core.math.types.Vec2
property global_rotation: float
property global_scale: simvx.core.math.types.Vec2
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)
transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]
draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, color=None)
wrap_screen(margin: float = 20)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()
class simvx.core.physics.engine.StaticBody3D(**kwargs)

Bases: simvx.core.physics.engine._PhysicsBodyMixin, simvx.core.engine.Node3D

Immovable 3D physics body. Used for floors, walls, and obstacles.

Has infinite effective mass — never moved by forces or collisions, but other bodies collide against it normally.

Example: ground = StaticBody3D(position=Vec3(0, -1, 0)) ground.set_collision_shape(BoxShape(half_extents=(50, 1, 50)))

Initialization

collision_layer

‘Property(…)’

collision_mask

‘Property(…)’

enter_tree() None
exit_tree() None
apply_force(force, position=None) None
apply_impulse(impulse, position=None) None
apply_torque(torque) None
set_collision_shape(shape: simvx.core.collision.CollisionShape) None
property position
property rotation: simvx.core.math.types.Quat
property scale
property rotation_degrees: simvx.core.math.types.Vec3
property global_position: simvx.core.math.types.Vec3
property global_rotation: simvx.core.math.types.Quat
property global_scale: simvx.core.math.types.Vec3
property forward: simvx.core.math.types.Vec3
property right: simvx.core.math.types.Vec3
property up: simvx.core.math.types.Vec3
translate(offset: tuple[float, float, float] | numpy.ndarray)
translate_global(offset: tuple[float, float, float] | numpy.ndarray)
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)
rotate_x(angle: float)
rotate_y(angle: float)
rotate_z(angle: float)
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
process(dt: float) None
physics_process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()
class simvx.core.physics.engine.StaticBody2D(**kwargs)

Bases: simvx.core.physics.engine._PhysicsBodyMixin, simvx.core.engine.Node2D

Immovable 2D physics body. Used for platforms and walls.

Same behavior as StaticBody3D but in 2D space.

Initialization

collision_layer

‘Property(…)’

collision_mask

‘Property(…)’

enter_tree() None
exit_tree() None
apply_force(force, position=None) None
apply_impulse(impulse, position=None) None
apply_torque(torque) None
set_collision_shape(shape: simvx.core.collision.CollisionShape) None
z_index

‘Property(…)’

z_as_relative

‘Property(…)’

property absolute_z_index: int
property position: simvx.core.math.types.Vec2
property rotation: float
property rotation_degrees: float
property scale: simvx.core.math.types.Vec2
property global_position: simvx.core.math.types.Vec2
property global_rotation: float
property global_scale: simvx.core.math.types.Vec2
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)
transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]
draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, color=None)
wrap_screen(margin: float = 20)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
process(dt: float) None
physics_process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()
class simvx.core.physics.engine.KinematicBody3D(**kwargs)

Bases: simvx.core.physics.engine._PhysicsBodyMixin, simvx.core.engine.Node3D

3D body moved by code that participates in collisions.

Not affected by gravity or forces, but pushes dynamic bodies. Use move_and_collide() for movement with collision detection.

Example: class Platform(KinematicBody3D): def physics_process(self, dt): self.linear_velocity = Vec3(0, math.sin(time) * 2, 0)

Initialization

collision_layer

‘Property(…)’

collision_mask

‘Property(…)’

enter_tree() None
exit_tree() None
move_and_collide(velocity, dt: float = 1.0) simvx.core.physics.engine.Contact | None

Move by velocity*dt and return the first contact, or None.

physics_process(dt: float) None
apply_force(force, position=None) None
apply_impulse(impulse, position=None) None
apply_torque(torque) None
set_collision_shape(shape: simvx.core.collision.CollisionShape) None
property position
property rotation: simvx.core.math.types.Quat
property scale
property rotation_degrees: simvx.core.math.types.Vec3
property global_position: simvx.core.math.types.Vec3
property global_rotation: simvx.core.math.types.Quat
property global_scale: simvx.core.math.types.Vec3
property forward: simvx.core.math.types.Vec3
property right: simvx.core.math.types.Vec3
property up: simvx.core.math.types.Vec3
translate(offset: tuple[float, float, float] | numpy.ndarray)
translate_global(offset: tuple[float, float, float] | numpy.ndarray)
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)
rotate_x(angle: float)
rotate_y(angle: float)
rotate_z(angle: float)
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()
class simvx.core.physics.engine.KinematicBody2D(**kwargs)

Bases: simvx.core.physics.engine._PhysicsBodyMixin, simvx.core.engine.Node2D

2D body moved by code that participates in collisions.

Same behavior as KinematicBody3D but in 2D space.

Initialization

collision_layer

‘Property(…)’

collision_mask

‘Property(…)’

enter_tree() None
exit_tree() None
move_and_collide(velocity, dt: float = 1.0) simvx.core.physics.engine.Contact | None

Move by velocity*dt and return the first contact, or None.

physics_process(dt: float) None
apply_force(force, position=None) None
apply_impulse(impulse, position=None) None
apply_torque(torque) None
set_collision_shape(shape: simvx.core.collision.CollisionShape) None
z_index

‘Property(…)’

z_as_relative

‘Property(…)’

property absolute_z_index: int
property position: simvx.core.math.types.Vec2
property rotation: float
property rotation_degrees: float
property scale: simvx.core.math.types.Vec2
property global_position: simvx.core.math.types.Vec2
property global_rotation: float
property global_scale: simvx.core.math.types.Vec2
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)
transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]
draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, color=None)
wrap_screen(margin: float = 20)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()
class simvx.core.physics.engine.Joint2D(body_a=None, body_b=None, **kwargs)

Bases: simvx.core.engine.Node2D

Base class for 2D physics joints.

Connects two physics bodies with a constraint. Subclass to implement specific joint types (pin, spring, etc.).

Attributes: body_a: First connected body (set after adding to tree). body_b: Second connected body (set after adding to tree).

Initialization

solve(dt: float) None

Override to implement constraint solving.

physics_process(dt: float) None
z_index

‘Property(…)’

z_as_relative

‘Property(…)’

property absolute_z_index: int
property position: simvx.core.math.types.Vec2
property rotation: float
property rotation_degrees: float
property scale: simvx.core.math.types.Vec2
property global_position: simvx.core.math.types.Vec2
property global_rotation: float
property global_scale: simvx.core.math.types.Vec2
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)
transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]
draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, color=None)
wrap_screen(margin: float = 20)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
enter_tree() None
exit_tree() None
process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()
class simvx.core.physics.engine.Joint3D(body_a=None, body_b=None, **kwargs)

Bases: simvx.core.engine.Node3D

Base class for 3D physics joints.

Connects two physics bodies with a constraint.

Initialization

solve(dt: float) None

Override to implement constraint solving.

physics_process(dt: float) None
property position
property rotation: simvx.core.math.types.Quat
property scale
property rotation_degrees: simvx.core.math.types.Vec3
property global_position: simvx.core.math.types.Vec3
property global_rotation: simvx.core.math.types.Quat
property global_scale: simvx.core.math.types.Vec3
property forward: simvx.core.math.types.Vec3
property right: simvx.core.math.types.Vec3
property up: simvx.core.math.types.Vec3
translate(offset: tuple[float, float, float] | numpy.ndarray)
translate_global(offset: tuple[float, float, float] | numpy.ndarray)
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)
rotate_x(angle: float)
rotate_y(angle: float)
rotate_z(angle: float)
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
enter_tree() None
exit_tree() None
process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()
class simvx.core.physics.engine.PinJoint2D(body_a=None, body_b=None, distance: float = 0.0, stiffness: float = 1.0, damping: float = 0.1, **kwargs)

Bases: simvx.core.physics.engine.Joint2D

Pin joint — constrains two 2D bodies to maintain a fixed distance.

The anchor points are at the bodies’ positions when the joint is created, or can be overridden via anchor_a and anchor_b.

Attributes: distance: Rest distance between anchors. 0 = compute from initial positions. stiffness: Constraint stiffness [0..1]. 1 = rigid, lower = springy. damping: Velocity damping factor for the constraint.

Initialization

solve(dt: float) None
physics_process(dt: float) None
z_index

‘Property(…)’

z_as_relative

‘Property(…)’

property absolute_z_index: int
property position: simvx.core.math.types.Vec2
property rotation: float
property rotation_degrees: float
property scale: simvx.core.math.types.Vec2
property global_position: simvx.core.math.types.Vec2
property global_rotation: float
property global_scale: simvx.core.math.types.Vec2
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)
transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]
draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, color=None)
wrap_screen(margin: float = 20)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
enter_tree() None
exit_tree() None
process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()
class simvx.core.physics.engine.PinJoint3D(body_a=None, body_b=None, distance: float = 0.0, stiffness: float = 1.0, damping: float = 0.1, **kwargs)

Bases: simvx.core.physics.engine.Joint3D

Pin joint — constrains two 3D bodies to maintain a fixed distance.

Attributes: distance: Rest distance. 0 = auto-compute from initial positions. stiffness: Constraint stiffness [0..1]. damping: Velocity damping along the constraint axis.

Initialization

solve(dt: float) None
physics_process(dt: float) None
property position
property rotation: simvx.core.math.types.Quat
property scale
property rotation_degrees: simvx.core.math.types.Vec3
property global_position: simvx.core.math.types.Vec3
property global_rotation: simvx.core.math.types.Quat
property global_scale: simvx.core.math.types.Vec3
property forward: simvx.core.math.types.Vec3
property right: simvx.core.math.types.Vec3
property up: simvx.core.math.types.Vec3
translate(offset: tuple[float, float, float] | numpy.ndarray)
translate_global(offset: tuple[float, float, float] | numpy.ndarray)
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)
rotate_x(angle: float)
rotate_y(angle: float)
rotate_z(angle: float)
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
enter_tree() None
exit_tree() None
process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()
class simvx.core.physics.engine.HingeJoint3D(body_a=None, body_b=None, axis=None, distance: float = 0.0, stiffness: float = 1.0, damping: float = 0.1, angular_limit_min: float = 0.0, angular_limit_max: float = 0.0, **kwargs)

Bases: simvx.core.physics.engine.Joint3D

Hinge joint — constrains two 3D bodies to rotate around a shared axis.

Maintains a fixed distance (like PinJoint) and restricts relative rotation to a single axis.

Attributes: axis: Hinge rotation axis in world space (normalized). distance: Rest distance between body centers. stiffness: Position constraint stiffness. damping: Velocity damping. angular_limit_min: Minimum angle in degrees (0 = no limit). angular_limit_max: Maximum angle in degrees (0 = no limit).

Initialization

solve(dt: float) None
physics_process(dt: float) None
property position
property rotation: simvx.core.math.types.Quat
property scale
property rotation_degrees: simvx.core.math.types.Vec3
property global_position: simvx.core.math.types.Vec3
property global_rotation: simvx.core.math.types.Quat
property global_scale: simvx.core.math.types.Vec3
property forward: simvx.core.math.types.Vec3
property right: simvx.core.math.types.Vec3
property up: simvx.core.math.types.Vec3
translate(offset: tuple[float, float, float] | numpy.ndarray)
translate_global(offset: tuple[float, float, float] | numpy.ndarray)
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)
rotate_x(angle: float)
rotate_y(angle: float)
rotate_z(angle: float)
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
enter_tree() None
exit_tree() None
process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()
class simvx.core.physics.engine.RayCast3D(target_position=None, collision_mask: int = 4294967295, enabled: bool = True, **kwargs)

Bases: simvx.core.engine.Node3D

Persistent ray query node for 3D physics.

Casts a ray from the node’s global position towards target_position (in local space) each physics frame and caches the result. Useful for ground detection, line-of-sight checks, lasers, etc.

Example: ray = RayCast3D(target_position=Vec3(0, -2, 0)) player.add_child(ray) # Later, in physics_process: if ray.is_colliding(): print(“Hit:”, ray.get_collider(), “at”, ray.get_collision_point())

Initialization

target_position

‘Property(…)’

collision_mask

‘Property(…)’

enabled

‘Property(…)’

physics_process(dt: float) None
is_colliding() bool

True if the ray hit something on the last physics frame.

get_collider() simvx.core.engine.Node3D | None

Return the first body hit, or None.

get_collision_point() simvx.core.math.types.Vec3

Return the world-space collision point of the first hit.

get_collision_normal() simvx.core.math.types.Vec3

Return the collision normal (stub — RayHit lacks normal data).

get_all_hits() list[simvx.core.collision.RayHit]

Return all hits from the last cast, sorted by distance.

property position
property rotation: simvx.core.math.types.Quat
property scale
property rotation_degrees: simvx.core.math.types.Vec3
property global_position: simvx.core.math.types.Vec3
property global_rotation: simvx.core.math.types.Quat
property global_scale: simvx.core.math.types.Vec3
property forward: simvx.core.math.types.Vec3
property right: simvx.core.math.types.Vec3
property up: simvx.core.math.types.Vec3
translate(offset: tuple[float, float, float] | numpy.ndarray)
translate_global(offset: tuple[float, float, float] | numpy.ndarray)
rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)
rotate_x(angle: float)
rotate_y(angle: float)
rotate_z(angle: float)
look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)
wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
enter_tree() None
exit_tree() None
process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()
class simvx.core.physics.engine.RayCast2D(target_position=None, collision_mask: int = 4294967295, enabled: bool = True, **kwargs)

Bases: simvx.core.engine.Node2D

Persistent ray query node for 2D physics.

Casts a ray from the node’s global position towards target_position (in local space) each physics frame and caches the result.

Example: ray = RayCast2D(target_position=Vec2(0, 100)) player.add_child(ray) if ray.is_colliding(): print(“Hit:”, ray.get_collider())

Initialization

target_position

‘Property(…)’

collision_mask

‘Property(…)’

enabled

‘Property(…)’

physics_process(dt: float) None
is_colliding() bool

True if the ray hit something on the last physics frame.

get_collider() simvx.core.engine.Node2D | None

Return the first body hit, or None.

get_collision_point() simvx.core.math.types.Vec2

Return the world-space collision point of the first hit.

get_collision_normal() simvx.core.math.types.Vec2

Return the collision normal (stub — RayHit lacks normal data).

get_all_hits() list[simvx.core.collision.RayHit]

Return all hits from the last cast, sorted by distance.

z_index

‘Property(…)’

z_as_relative

‘Property(…)’

property absolute_z_index: int
property position: simvx.core.math.types.Vec2
property rotation: float
property rotation_degrees: float
property scale: simvx.core.math.types.Vec2
property global_position: simvx.core.math.types.Vec2
property global_rotation: float
property global_scale: simvx.core.math.types.Vec2
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)
transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]
draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, color=None)
wrap_screen(margin: float = 20)
script_error_raised

‘Signal(…)’

classmethod __init_subclass__(**kwargs)
property name: str
property process_mode: simvx.core.descriptors.ProcessMode
reset_error() None
add_child(node: simvx.core.node.Node) simvx.core.node.Node
remove_child(node: simvx.core.node.Node)
reparent(new_parent: simvx.core.node.Node)
get_node(path: str) simvx.core.node.Node
find_child(name: str, recursive: bool = False) simvx.core.node.Node | None
find(node_type: type) simvx.core.node.Node | None
find_all(node_type: type, recursive: bool = True) list
property path: str
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
ready() None
enter_tree() None
exit_tree() None
process(dt: float) None
draw(renderer) None
input_event(event: simvx.core.events.InputEvent) None
input(event: simvx.core.events.TreeInputEvent) None
unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
destroy()
queue_free

None

property tree: simvx.core.scene_tree.SceneTree
get_tree() simvx.core.scene_tree.SceneTree
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
get_settings

None

__repr__()