simvx.core.physics.root¶
PhysicsRoot: branch-isolating physics node + node->world resolution.
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.
The factory used to build a world for a root (and for the default) is pluggable
so the backend can be selected without changing the resolution logic. Which
backend a root builds is decided by :mod:simvx.core.physics.backends
(precedence: explicit PhysicsRoot(backend=) > project physics_backend
setting > auto-discovered native > Builtin); a direct factory= argument is
the test escape hatch that bypasses precedence.
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, and it 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. Registered worlds
are advanced by SceneTree.physics_tick.
The one exception 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).
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.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, the most specific level of the selection precedence: explicit > project
physics_backendsetting > auto-discovered native > Builtin.None(default) defers to the setting / auto / Builtin levels. An unknown name degrades to the next level 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
- dev_checks: ClassVar[bool]¶
None
- script_error_raised¶
‘Signal(…)’
- dynamic: bool¶
False
- visible¶
‘Property(…)’
- update_mode¶
‘Property(…)’
- __properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]¶
None
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property visible_in_tree: bool¶
- 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_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)¶
- queue_redraw() None¶
- property render_dirty: bool¶
- clear_children()¶
- destroy()¶
- property destroying: bool¶
- 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: a distinct class rather than adimsflag, so it matches the node taxonomy split and the resolution walk stays 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, the most specific level of the selection precedence (see :class:PhysicsRoot).Nonedefers to the project setting / auto / Builtin levels. 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
- dev_checks: ClassVar[bool]¶
None
- script_error_raised¶
‘Signal(…)’
- dynamic: bool¶
False
- visible¶
‘Property(…)’
- update_mode¶
‘Property(…)’
- __properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]¶
None
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property visible_in_tree: bool¶
- 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_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)¶
- queue_redraw() None¶
- property render_dirty: bool¶
- clear_children()¶
- destroy()¶
- property destroying: bool¶
- 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…