acron.world

Bullet physics world with Godot’s conventions, plus query helpers.

PhysicsWorld extends BulletWorld (rather than wrapping it): everything Acron’s BulletWorld does – attach/remove, debug node, contact tests – is available directly, and this subclass adds only what Godot ports need on top:

  • the exact-fixed-step convention: do_physics() always steps (dt, 0, dt) – one step, no Bullet substeps – because ported logic assumes Godot’s constant-tick cadence (Bullet substepping breaks velocity-from-position tricks and can make stiff systems vibrate more). The stepping cadence itself lives in acron.fixed_loop.

  • Godot-style spatial queries: ray_test() (intersect_ray) and sweep_closest() (the move_and_collide core), returning a flattened RayHit.

Layer convention: Godot’s editor collision layers are 1-indexed (set_collision_layer_value(n, ...) sets 1 << (n-1)); Acron’s BitMask32.bit(i) is 0-indexed. layer_bit() does the off-by-one once. Game-specific layer names (from project.godot [layer_names]) stay in the game – define them there as LAYER_LEVEL = layer_bit(1) etc.

Owner protocol: Bullet query results hand back the body node, not your game object. tag_owner() stashes the owning Python object on a NodePath via set_python_tag; owner_of() (and RayHit.collider) recover it. Character bodies tag themselves automatically.

PhysicsWorld([gravity, fixed_dt])

A BulletWorld with Godot's stepping and query conventions built in.

RayHit(bullet_node, position, normal[, fraction])

Result of a ray/sweep query -- Godot's collision dictionary, flattened.

Global Functions

layer_bit(godot_layer: int) → BitMask_uint32_t_32

The Acron BitMask32 for Godot editor collision layer godot_layer.

Godot layers are 1-indexed in the editor: layer 1 -> bit(0) (value 1).

layer_mask(*godot_layers: int) → BitMask_uint32_t_32

OR together several Godot editor layer indices into one mask.

owner_of(node_or_np)

The Python owner tagged on a node (or NodePath), else None.

static_box(world, parent, name: str, half_extents, pos, *, hpr=None, mask: BitMask_uint32_t_32 = 1111 1111 1111 1111 1111 1111 1111 1111)

A static (mass-0) box body: attached to world, parented, masked.

The five lines every constructed level and physics test rolls by hand — shape, node, parent, mask, attach — as one call. hpr tilts it (a rotated box is how a ramp is made). Returns the body’s NodePath; tag an owner on it with tag_owner() if queries should resolve to a game object.

tag_owner(np, owner) → None

Stash owner on np so physics queries can resolve back to it.