simvx.core.physics.root¶
Role¶
A PhysicsRoot node carves its sub-branch of the scene tree into a separate,
isolated :class:~simvx.core.physics.world.PhysicsWorld. Bodies resolve their
world by walking up to the nearest PhysicsRoot ancestor; if there is none,
they fall back to a default world (one per scene tree). Nested roots: the
innermost wins. This mirrors the scoping pattern the codebase already uses and
is the future unit of cross-world parallelism.
The factory used to build a world for a root (and for the default) is pluggable
so a backend (BuiltinPhysics now, JoltPhysics later) can be selected
without changing the resolution logic. Which backend a root builds is decided by
- mod:
simvx.core.physics.backends(precedence: explicitPhysicsRoot(backend=)
project
physics_backendsetting > auto-discovered native > Builtin); a directfactory=argument is the test escape hatch that bypasses precedence.
Stage 2 status¶
The new seam is now wired into SceneTree.physics_tick. World ownership is
SceneTree-owned: the default world (for bodies with no PhysicsRoot
ancestor) lives on the tree as tree.physics_world (lazy, tree-scoped,
survives change_scene like the event bus), and each PhysicsRoot
registers its own isolated world with the tree on enter and unregisters +
drops it on exit, so no worlds leak on teardown.
The sole provisional remnant is the treeless fallback: a single
module-level default world used only when :func:resolve_world is given a node
with no SceneTree (standalone unit tests that call step() manually).
PhysicsRoot: branch-isolating physics node + node->world resolution.
Module Contents¶
Classes¶
A node that owns an isolated :class: |
|
A node that owns an isolated :class: |
Functions¶
Resolve the :class: |
|
Resolve the :class: |
Data¶
API¶
- simvx.core.physics.root.WorldFactory¶
None
- simvx.core.physics.root.WorldFactory2D¶
None
- simvx.core.physics.root.resolve_world(node: simvx.core.node.Node) simvx.core.physics.world.PhysicsWorld[source]¶
Resolve the :class:
PhysicsWorlda node’s bodies belong to.Walks up from
node(inclusive) to the nearest :class:PhysicsRootancestor and returns that root’s world. If noPhysicsRootis found, returns the tree’s default world (node.tree.physics_world), or, for a treeless node, the module-level fallback world.Args: node: The node whose world to resolve.
Returns: The resolved :class:
PhysicsWorld(innermost root wins; tree default otherwise; treeless fallback when the node is not in a tree).
- simvx.core.physics.root.resolve_world_2d(node: simvx.core.node.Node) simvx.core.physics.world2d.Physics2DWorld[source]¶
Resolve the :class:
Physics2DWorlda node’s 2D bodies belong to.The 2D sibling of :func:
resolve_world. Walks up fromnode(inclusive) to the nearest :class:PhysicsRoot2Dancestor and returns that root’s 2D world. If none is found, returns the tree’s default 2D world (node.tree.physics_world_2d), or, for a treeless node, the module-level 2D fallback world.Args: node: The node whose 2D world to resolve.
Returns: The resolved :class:
Physics2DWorld(innermostPhysicsRoot2Dwins; tree 2D default otherwise; treeless 2D fallback when not in a tree).
- class simvx.core.physics.root.PhysicsRoot(name: str = '', *, gravity: simvx.core.math.Vec3 = _DEFAULT_GRAVITY, backend: str | None = None, factory: simvx.core.physics.root.WorldFactory | None = None, **kwargs: object)[source]¶
Bases:
simvx.core.node.NodeA node that owns an isolated :class:
PhysicsWorldfor its sub-branch.Bodies under a
PhysicsRoot(with no nearerPhysicsRoot) simulate in this node’s world, fully isolated from the rest of the tree: independent gravity and stepping. Resolve a node’s world with :func:resolve_world.The world is created lazily on first access via the configured
factory(defaults toBuiltinPhysics), so constructing the node is cheap and the backend choice stays in one place.Stage 2: this root registers its world with the SceneTree on enter so the fixed-step loop (
SceneTree.physics_tick) advances it, and unregisters + drops it on exit so nothing leaks across scene swaps or teardown.Initialization
Initialise the physics root.
Args: name: Node name (defaults to the class name). gravity: Gravity for this root’s isolated world. backend: Explicit backend-name override (arm 1 of the selection precedence: explicit > project
physics_backendsetting > auto-discovered native > Builtin).None(default) defers to the setting / auto / Builtin arms. An unknown name degrades to the next arm with a warning (a missing optional native backend does not crash the game). factory: Direct backend-factory escape hatch. When given it bypasses thebackendprecedence entirely and is used verbatim (used by tests to inject a stub world). Defaults toNone-> resolve viabackendprecedence. **kwargs: Forwarded to :class:~simvx.core.node.Node.- property world: simvx.core.physics.world.PhysicsWorld[source]¶
This root’s isolated world, created lazily on first access.
Built from the explicit
factoryif one was given, else from the backend resolved by precedence (explicitbackend> project setting > auto-discovered native > Builtin).
- on_exit_tree() None[source]¶
Unregister + drop this root’s world (no leaked worlds on teardown).
Uses
self._world(not the creating.worldproperty) so exit never builds a world a never-used root never had. Re-entering the tree rebuilds a fresh world lazily and re-registers it; the registry guard makes the re-register idempotent.
- strict_errors: ClassVar[bool]¶
True
- script_error_raised¶
‘Signal(…)’
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property update_mode: simvx.core.descriptors.UpdateMode¶
- property visible: bool¶
- 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¶
- get_node_or_none(path: str) simvx.core.node.Node | None¶
- find(target, *, direct: bool = False)¶
- find_all(target, *, direct: bool = False)¶
- walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]¶
- property path: str¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) bool¶
- on_ready() None¶
- on_update(dt: float) None¶
- on_fixed_update(dt: float) None¶
- on_draw(renderer) None¶
- on_picked(event: simvx.core.events.InputEvent) None¶
- on_unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- clear_children()¶
- destroy()¶
- call_deferred(method: collections.abc.Callable[..., Any], *args: Any) None¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- property physics¶
- property physics_2d¶
- __getitem__(key: str)¶
- classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶
- class simvx.core.physics.root.PhysicsRoot2D(name: str = '', *, gravity: simvx.core.math.Vec2 = _DEFAULT_GRAVITY_2D, backend: str | None = None, factory: simvx.core.physics.root.WorldFactory2D | None = None, **kwargs: object)[source]¶
Bases:
simvx.core.physics.root.PhysicsRootA node that owns an isolated :class:
Physics2DWorldfor its sub-branch.The 2D sibling of :class:
PhysicsRoot(recommended over adimsflag, per the design: it matches the taxonomy split and the resolution walk is a plainisinstancetest). 2D bodies under aPhysicsRoot2D(with no nearerPhysicsRoot2D) simulate in this node’s 2D world, isolated from the tree’s default 2D world. Resolve a node’s 2D world with :func:resolve_world_2d.It deliberately does NOT reuse the 3D base’s
_worldslot /worldproperty (those build a 3DBuiltinPhysics): aPhysicsRoot2Downs its own 2D world via :attr:world_2d, built lazily by the 2Dfactory(defaults toBuiltinPhysics2D), and registers THAT world with the tree.Initialization
Initialise the 2D physics root.
Args: name: Node name (defaults to the class name). gravity: Gravity (
Vec2) for this root’s isolated 2D world. backend: Explicit backend-name override (arm 1 of the selection precedence; see :class:PhysicsRoot).Nonedefers to the project setting / auto / Builtin arms. factory: Direct 2D backend-factory escape hatch; when given it bypasses thebackendprecedence and is used verbatim (test injection). Defaults toNone-> resolve viabackendprecedence. **kwargs: Forwarded to :class:~simvx.core.node.Node.- property world_2d: simvx.core.physics.world2d.Physics2DWorld[source]¶
This root’s isolated 2D world, created lazily on first access.
Built from the explicit
factoryif one was given, else from the backend resolved by precedence (explicitbackend> project setting > auto-discovered native > Builtin).
- on_enter_tree() None[source]¶
Register this root’s isolated 2D world with the tree so it gets stepped.
- on_exit_tree() None[source]¶
Unregister + drop this root’s 2D world (no leaked worlds on teardown).
Uses
self._world_2d_obj(not the creating.world_2dproperty) so exit never builds a world a never-used root never had. Re-entering rebuilds a fresh world lazily and re-registers it (the registry guard is idempotent).
- property world: simvx.core.physics.world.PhysicsWorld¶
- strict_errors: ClassVar[bool]¶
True
- script_error_raised¶
‘Signal(…)’
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property update_mode: simvx.core.descriptors.UpdateMode¶
- property visible: bool¶
- 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¶
- get_node_or_none(path: str) simvx.core.node.Node | None¶
- find(target, *, direct: bool = False)¶
- find_all(target, *, direct: bool = False)¶
- walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]¶
- property path: str¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) bool¶
- on_ready() None¶
- on_update(dt: float) None¶
- on_fixed_update(dt: float) None¶
- on_draw(renderer) None¶
- on_picked(event: simvx.core.events.InputEvent) None¶
- on_unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- clear_children()¶
- destroy()¶
- call_deferred(method: collections.abc.Callable[..., Any], *args: Any) None¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- property physics¶
- property physics_2d¶
- __getitem__(key: str)¶
- classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶
- simvx.core.physics.root.__all__¶
[‘PhysicsRoot’, ‘PhysicsRoot2D’, ‘resolve_world’, ‘resolve_world_2d’, ‘WorldFactory’, ‘WorldFactory2…