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_angle 45 deg, max_slides 6, floor_snap_length 0.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_slide does this implicitly); ported game code should ALSO zero velocity.z when is_on_floor() before applying gravity, as the GDScript pattern assumes – otherwise gravity accumulates forever and eventually punches the capsule through the floor.

  • seam_snap_distance is 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).

CharacterBody3D(physics_world[, radius, ...])

Godot's kinematic character mover.