feat(engine): 2D collision / physics-lite — Body + Collider + esys_move (#65)
Phase 0 of the gameplay-controller work (#57): turn the static Collision.* overlap tests into a real physics-lite moving-body-with-collision layer that the platformer / shooter / NPC-AI / RPG families build on. New engine-owned system esys_move (runtime/native/systems_move.ludic), spliced and Update-phase-registered when a game declares `Body` (parse.ludic), standing entirely on the reflection ABI like the SpriteAnim / Motion / Light2D systems: - Body { vx, vy, gravity, max_fall, rx, ry, policy, on_ground, hit_wall, hit_ceiling } — Q16.16 velocity + engine-owned sub-pixel accumulators. - Collider { w, h, offx, offy, is_trigger, one_way, layer, mask, hit, entered, exited } — AABB shape off Position, layer/mask filtering, one-way + triggers. - Solids { tile, wall, oneway } — optional config entity enabling the tile-grid broadphase over the Map.* tilemap. esys_move integrates velocity + gravity, then resolves per-axis swept AABB against both solid Collider entities and the tile grid (no tunneling), handles one-way platforms (block only a downward landing), reports trigger/sensor overlaps without resolving, and sets on_ground / hit_wall / hit_ceiling for a controller to poll. No float, no hidden singletons, no runtime dispatch — integer + deterministic, so replay / lockstep / world_save hold. Contact is surfaced as polled flags (the SpriteAnim.event_fired shape), so a game raises its own CollisionResolved / TriggerEntered events with no engine coupling. Two self-asserting examples (entity + tile broadphase) wired into `x test`; docs added to the collision section. A build with no Body compiles byte-for-byte the same (bootstrap fixpoint + all golden renders unchanged). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
6c6dfae235
commit
0b149a6876
7 changed files with 17645 additions and 16763 deletions
|
|
@ -776,6 +776,13 @@ function maybe_splice_runtime() -> void {
|
|||
if (find_comp("SpriteAnim") != null) or (find_comp("Motion") != null) {
|
||||
do_import("runtime/native/systems.ludic")
|
||||
}
|
||||
# Body -> the movement + collision system (#65). It reads the tilemap
|
||||
# (rt_tile / rt_mapw / rt_maph) for the tile-grid broadphase, so it links
|
||||
# against core.ludic; do_import dedupes when a game already pulled core in.
|
||||
if find_comp("Body") != null {
|
||||
do_import("runtime/native/core.ludic")
|
||||
do_import("runtime/native/systems_move.ludic")
|
||||
}
|
||||
# Light2D / Occluder -> the lighting render system, which links against the
|
||||
# 2D light pass (light.ludic). do_import dedupes, so this is a no-op when the
|
||||
# game also uses Light.* directly (g_uses_light already pulled it in).
|
||||
|
|
@ -824,6 +831,7 @@ function parse_program() -> void {
|
|||
g_esys_comp = new []pointer; g_esys_fn = new []pointer; g_esys_phase = new []pointer
|
||||
push(g_esys_comp, "SpriteAnim"); push(g_esys_fn, "esys_spriteanim"); push(g_esys_phase, "Update")
|
||||
push(g_esys_comp, "Motion"); push(g_esys_fn, "esys_motion"); push(g_esys_phase, "Update")
|
||||
push(g_esys_comp, "Body"); push(g_esys_fn, "esys_move"); push(g_esys_phase, "Update")
|
||||
push(g_esys_comp, "Light2D"); push(g_esys_fn, "esys_light2d"); push(g_esys_phase, "Render")
|
||||
g_namespaces = new []pointer
|
||||
loaded_paths = new []pointer
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue