acron.character_body¶
CharacterBody3D – a kinematic collide-and-slide mover on Bullet sweep tests.
Acron’s BulletCharacterControllerNode sinks through the floor when pressed
against a wall (it loses ground contact), so this is a direct port of Godot’s
move_and_slide (character_body_3d.cpp): sweep the capsule by the desired
motion, and on a hit, advance to the contact and slide the remaining motion along
the surface, for a few iterations. is_on_floor is set when a hit normal
points up enough.
The mover is a plain NodePath we reposition ourselves via sweep tests – Bullet
never integrates it, so nothing can wedge/sink. It is additionally backed by a
KINEMATIC BulletRigidBodyNode (mass 0) carrying the capsule, so other
queries (bullets, line-of-sight rays) can hit the character; without this
“presence body” the character does not exist in the physics world at all.
NB the presence body’s transform is synced into Bullet by the WORLD STEP
(do_physics), not by moving the NodePath – on Acron 1.11 a ray cast before
any step sees the body at a stale position. The standard
acron.fixed_loop ordering (_physics_process then do_physics)
gets this right; a bespoke loop must also step the world each fixed step. The
movement sweep uses collide_mask, which must NOT include the presence body’s
own layer (body_mask) or the capsule would collide with itself – the default
collide_mask is everything except body_mask.
Godot fidelity notes:
Defaults mirror Godot:
floor_max_angle45 deg,max_slides6,floor_snap_length0.1.Floor snap runs ONLY when the body was grounded LAST step, is not on the floor now, and is not moving upward – an unconditional snap yanks the body back down the instant it leaves the ground, cancelling every jump, and a snap without the was-grounded gate teleports the tail of every free fall. Godot gates on both; this is the single most important correctness detail.
Grounded downward velocity is projected out on floor contact (Godot’s
move_and_slidedoes this implicitly); ported game code should ALSO zerovelocity.zwhenis_on_floor()before applying gravity, as the GDScript pattern assumes – otherwise gravity accumulates forever and eventually punches the capsule through the floor.seam_snap_distanceis an optional bridge for levels whose floor is parsed primitive boxes with hairline seams: if the body was grounded last step, is not deliberately jumping, and a floor is within this drop, snap back onto it. Off (0.0) by default because Godot has no such behaviour – a character stepping off a low ledge would glue down instead of falling. Our TPS port shipped with 1.5.
Godot API mirrored: velocity, move_and_slide(), is_on_floor(),
is_on_wall(), is_on_ceiling(), get_floor_normal(),
get_wall_normal(), set_up_direction(), get_gravity(). The
algorithm itself lives in acron.slide, shared with the 2D mover;
snap_extra_reach extends the ground-glue probe beyond
floor_snap_length for steps/slopes (it does NOT climb steps).
|
Godot's kinematic character mover. |