goo2d_physics_box2d 0.2.0
goo2d_physics_box2d: ^0.2.0 copied to clipboard
2D physics for the good game engine: bodies, colliders, all nine joints, effectors, and raycast and overlap queries, stepped in the game isolate and solved across threads.
0.2.0 #
Breaking #
-
One Box2D world per loaded scene, and the queries name the scene.
raycastandoverlapBoxtake aSceneas their first argument, as do the fourEffectors2Dfunctions (areaEffector,pointEffector,buoyancyEffector,surfaceEffector). Pass the handleloadScenereturned; a game with one scene passes the one it has. There is deliberately no default and no fallback to "the one loaded scene" - that shape works for months and then queries the wrong world the day a HUD scene loads, which is whygetScenebecamesingleScenein the kernel.Before this, every loaded scene shared one world: a dynamic body in one scene came to rest on static geometry in another, one
overlapBoxreturned shapes from two scenes interleaved, andlayerMaskwas the only way to tell them apart - a budget that exists for something else. A scene is this engine's isolation boundary everywhere else, so physics was the subsystem catching up.Two more consequences. A joint between bodies in different scenes is refused with an
ArgumentErrornaming both slots, because they have no solver in common and Box2D has no defined behaviour for it. And unloading a scene destroys its world outright, taking every body and joint in it, so nothing survives an unload that used to.Box2DPhysicsSystem.worldis gone;worldOf(scene)replaces it.awakeBodyCountandcounterssum across loaded scenes, which reads the same as before for a game with one. -
+yis up, followinggoo2d. Gravity defaults to-10, the wheel joint's axis to(0, -1), and buoyancy searches below the waterline. A world that set any of these itself needs the sign checked. -
A polygon collider takes its points, and the eight-vertex cap now lives here — Box2D's solver is what the limit was ever about.
Performance #
-
A static body no longer has its transform read back from the solver. Since the drift fix below, a static body's pulled transform was discarded on arrival, but the read still happened — one per static body per tick, thrown away. The transform pull now runs off its own handle array with the static rows zeroed, and the shim skips those. Velocities still come back for every body, static included, because a body turned static has to report zero.
The cost was about 11 ns per static body per tick, so it scaled with level geometry and was worst on exactly the scenes that notice it least — a mostly-static tilemap. Measured against the raw shim, AOT-compiled, on a scene of 500 dynamic bodies dropped onto a row of statics:
static bodies transform pull, before after saved per tick 1,000 14.2 µs 4.7 µs 9.5 µs 5,000 58.8 µs 5.4 µs 53.4 µs 20,000 243.2 µs 8.9 µs 234.3 µs At 20,000 statics that is 1.4% of a whole 60 Hz frame, and roughly half the native part of a physics tick.
tool/static_pull_bench.dartis the measurement, including the control case that shows what no difference looks like.
Fixed #
- Static and kinematic bodies no longer drift toward multiples of π/4. A
non-dynamic body pushed its transform every tick and read Box2D's reading of
it back, and that round trip has an error that converges there. A floor
authored at 0.3 rad reached 0.785 in ten thousand ticks — 17 degrees to 41 in
sixteen seconds. Static bodies no longer write back at all, and both kinds
push only when gameplay wrote the value. The comparison has a threshold —
1e-4units of position,5e-3radians of angle — so a static body scripted in smaller increments than that now moves in steps instead of continuously. It ends up where you told it.docs/guide/physics.mdsays which body type a moving platform wants and why; the short answer is kinematic, which is driven by velocity and never meets the threshold at all. - Changing
bodyTypeon a live body is applied. It was documented as working and moved only the column, so the solver went on treating the body as whatever it was created as.
0.1.1 #
Documentation only. No code changes.
The README now shows a declared collider and effector. The library docs
described the superseded effector API, where you wrote your own system and a
compareTo to order it before the solver; declaring Effector2D is the
current shape and the physics system handles the ordering.
0.1.0 #
First published release. The ECS-facing 2D physics layer:
- Bodies and colliders, declared as components.
- All nine joints — distance, motor, mouse, prismatic, revolute, weld,
wheel and the rest of Unity's 2D set — with
Jointas a real type, not a raw handle. - Effectors, declared alongside the colliders they act on.
- Raycast and overlap queries.
- The solver runs across worker threads; the thread count is set on the
Game.
0.0.1 #
- Package scaffolded. Never published.