simvx.core.physics._pose_reconcile¶
Node-transform -> physics-handle pose reconciliation.
A physics node (PhysicsBody2D/PhysicsBody3D, CharacterBody2D/
CharacterBody3D) owns BOTH a Node transform and a seam handle in a
physics world. The scene tree syncs handle -> node every step, and render
interpolation does it every frame. Without the reverse direction, a direct
node.position = x would move only the visual node, and the next step /
move_and_slide would snap it back to the stale handle pose (the body teleports
to the world corner). That made attribute assignment – the obvious way to place
a node – silently wrong.
This mixin closes the loop: assigning the node’s OWN transform eagerly teleports
the seam handle to match. So node.position = spawn is the single, canonical
way to place a physics node (there is deliberately no separate teleport()
method: it would be a pure behavioural alias). Because the push is eager, every
later read – the step, move_and_slide, and raycast/overlap queries – sees
the assigned pose with no further bookkeeping.
Mechanics:
_invalidate_transformis the single transform choke point (localposition, theworld_positionsetter, in-placeVecmutation, androtation’son_change). The override pushes the node world pose into the handle, but ONLY for a direct write to THIS node (_from_parentFalse) and NOT during the engine’s own handle->node write-backs (_applying_physics_pose). Skipping_from_parentmeans a character parented under a moving node is not dragged through its handle (which would overridemove_and_slide).The engine’s handle->node write-backs (bulk scatter, render interpolation,
move_and_slide/move_and_collide) MUST route through- meth:
_write_pose_from_seam, which sets the guard so they never bounce the simulated / interpolated pose back into the handle (that would, depending on backend, zero velocity, wake sleepers, or corrupt interpolation).
Subclass contract: implement :meth:_push_node_pose_to_seam to write
(world_position, world_rotation) into the handle, a no-op when inert (no
handle yet, e.g. before on_enter_tree or with no collider). Subclasses that
create their handle in __init__ order must set their seam fields BEFORE
super().__init__ so the hook, which can fire on a position= kwarg during
base init, reads valid state.