wip(0.S3): the runtime migrated - ludic migrate state --runtime <every program>: 331 vars into 25 states (RtInputState, RtGlState, ...), 2 lets; its states are made before it boots; no module-level var is let through outside --globals
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
7b17b4a1b9
commit
02448e176c
38 changed files with 53877 additions and 53251 deletions
|
|
@ -60,35 +60,37 @@
|
|||
const PHYS_ONE: int = 65536 # Q16.16 one whole pixel
|
||||
|
||||
# ---- per-frame config + reflected ids (filled at the top of esys_move) -------
|
||||
var pm_pos: int = -1 # Position prop id
|
||||
var pm_pos_x: int = -1
|
||||
var pm_pos_y: int = -1
|
||||
var pm_col: int = -1 # Collider prop id
|
||||
var pm_c_w: int = -1
|
||||
var pm_c_h: int = -1
|
||||
var pm_c_offx: int = -1
|
||||
var pm_c_offy: int = -1
|
||||
var pm_c_trig: int = -1
|
||||
var pm_c_oneway: int = -1
|
||||
var pm_c_layer: int = -1
|
||||
var pm_c_mask: int = -1
|
||||
var phys_ts: int = 0 # tile size px (0 = grid off)
|
||||
var phys_wall: int = 0 # solid glyph
|
||||
var phys_wall2: int = 0 # optional second solid glyph (Solids.solid2), e.g. a closed door
|
||||
var phys_oneway: int = 0 # one-way platform glyph (0 = none)
|
||||
export state RtSystemsMoveState {
|
||||
pm_pos: int = -1 # Position prop id
|
||||
pm_pos_x: int = -1
|
||||
pm_pos_y: int = -1
|
||||
pm_col: int = -1 # Collider prop id
|
||||
pm_c_w: int = -1
|
||||
pm_c_h: int = -1
|
||||
pm_c_offx: int = -1
|
||||
pm_c_offy: int = -1
|
||||
pm_c_trig: int = -1
|
||||
pm_c_oneway: int = -1
|
||||
pm_c_layer: int = -1
|
||||
pm_c_mask: int = -1
|
||||
phys_ts: int = 0 # tile size px (0 = grid off)
|
||||
phys_wall: int = 0 # solid glyph
|
||||
phys_wall2: int = 0 # optional second solid glyph (Solids.solid2), e.g. a closed door
|
||||
phys_oneway: int = 0 # one-way platform glyph (0 = none)
|
||||
phys_cur_layer: int = 0
|
||||
phys_cur_mask: int = 0
|
||||
phys_hit_x: int = 0 # X sweep blocked
|
||||
phys_hit_up: int = 0 # Y sweep blocked moving up
|
||||
phys_hit_down: int = 0 # Y sweep blocked moving down
|
||||
phys_trig_prev: words = null
|
||||
}
|
||||
|
||||
# the moving body's own layer/mask, so the solid scan can filter by them
|
||||
var phys_cur_layer: int = 0
|
||||
var phys_cur_mask: int = 0
|
||||
|
||||
# sweep outputs (Ludic returns one value, so axis clampers report contact here)
|
||||
var phys_hit_x: int = 0 # X sweep blocked
|
||||
var phys_hit_up: int = 0 # Y sweep blocked moving up
|
||||
var phys_hit_down: int = 0 # Y sweep blocked moving down
|
||||
|
||||
# trigger edge tracking: the body a trigger overlapped last frame, stored as
|
||||
# (entity id + 1) so a zero-filled slot reads as "none" (entity 0 is valid).
|
||||
var phys_trig_prev: words = null
|
||||
|
||||
# ---- small integer helpers --------------------------------------------------
|
||||
# floor division toward negative infinity (positions can go slightly negative);
|
||||
|
|
@ -102,42 +104,42 @@ function phys_floordiv(a: int, b: int) -> int {
|
|||
|
||||
# a solid (fully blocking) tile: out of bounds counts as a wall, so the map edge
|
||||
# is a free arena boundary; otherwise the glyph equals the configured wall.
|
||||
function phys_tile_solid(c: int, r: int) -> bool {
|
||||
function phys_tile_solid(rt_core_st: RtCoreState, rt_systems_move_st: RtSystemsMoveState, c: int, r: int) -> bool {
|
||||
if c < 0 { return true }
|
||||
if r < 0 { return true }
|
||||
if c >= rt_mapw { return true }
|
||||
if r >= rt_maph { return true }
|
||||
let g = rt_tile(c, r)
|
||||
if g == phys_wall { return true }
|
||||
return (phys_wall2 != 0) and (g == phys_wall2)
|
||||
if c >= rt_core_st.rt_mapw { return true }
|
||||
if r >= rt_core_st.rt_maph { return true }
|
||||
let g = rt_tile(rt_core_st, c, r)
|
||||
if g == rt_systems_move_st.phys_wall { return true }
|
||||
return (rt_systems_move_st.phys_wall2 != 0) and (g == rt_systems_move_st.phys_wall2)
|
||||
}
|
||||
# a one-way platform tile (in bounds only — the arena edge is a full wall above).
|
||||
function phys_tile_oneway(c: int, r: int) -> bool {
|
||||
if phys_oneway == 0 { return false }
|
||||
function phys_tile_oneway(rt_core_st: RtCoreState, rt_systems_move_st: RtSystemsMoveState, c: int, r: int) -> bool {
|
||||
if rt_systems_move_st.phys_oneway == 0 { return false }
|
||||
if c < 0 { return false }
|
||||
if r < 0 { return false }
|
||||
if c >= rt_mapw { return false }
|
||||
if r >= rt_maph { return false }
|
||||
return rt_tile(c, r) == phys_oneway
|
||||
if c >= rt_core_st.rt_mapw { return false }
|
||||
if r >= rt_core_st.rt_maph { return false }
|
||||
return rt_tile(rt_core_st, c, r) == rt_systems_move_st.phys_oneway
|
||||
}
|
||||
# is any full-solid tile present in column c over the row span [r0, r1]?
|
||||
function phys_col_solid(c: int, r0: int, r1: int) -> bool {
|
||||
function phys_col_solid(rt_core_st: RtCoreState, rt_systems_move_st: RtSystemsMoveState, c: int, r0: int, r1: int) -> bool {
|
||||
var r = r0
|
||||
while r <= r1 { if phys_tile_solid(c, r) { return true }; r += 1 }
|
||||
while r <= r1 { if phys_tile_solid(rt_core_st, rt_systems_move_st, c, r) { return true }; r += 1 }
|
||||
return false
|
||||
}
|
||||
# is any full-solid tile present in row r over the column span [c0, c1]?
|
||||
function phys_row_solid(r: int, c0: int, c1: int) -> bool {
|
||||
function phys_row_solid(rt_core_st: RtCoreState, rt_systems_move_st: RtSystemsMoveState, r: int, c0: int, c1: int) -> bool {
|
||||
var c = c0
|
||||
while c <= c1 { if phys_tile_solid(c, r) { return true }; c += 1 }
|
||||
while c <= c1 { if phys_tile_solid(rt_core_st, rt_systems_move_st, c, r) { return true }; c += 1 }
|
||||
return false
|
||||
}
|
||||
# is any full-OR-one-way tile present in row r over [c0, c1]? (downward landings)
|
||||
function phys_row_land(r: int, c0: int, c1: int) -> bool {
|
||||
function phys_row_land(rt_core_st: RtCoreState, rt_systems_move_st: RtSystemsMoveState, r: int, c0: int, c1: int) -> bool {
|
||||
var c = c0
|
||||
while c <= c1 {
|
||||
if phys_tile_solid(c, r) { return true }
|
||||
if phys_tile_oneway(c, r) { return true }
|
||||
if phys_tile_solid(rt_core_st, rt_systems_move_st, c, r) { return true }
|
||||
if phys_tile_oneway(rt_core_st, rt_systems_move_st, c, r) { return true }
|
||||
c += 1
|
||||
}
|
||||
return false
|
||||
|
|
@ -157,37 +159,37 @@ function phys_match(la: int, ma: int, lb: int, mb: int) -> bool {
|
|||
}
|
||||
|
||||
# ---- reflected accessors ----------------------------------------------------
|
||||
function phys_pos_x(e: int) -> int { return World.get(e, pm_pos, pm_pos_x) }
|
||||
function phys_pos_y(e: int) -> int { return World.get(e, pm_pos, pm_pos_y) }
|
||||
function phys_set_x(e: int, v: int) -> void { World.set(e, pm_pos, pm_pos_x, v) }
|
||||
function phys_set_y(e: int, v: int) -> void { World.set(e, pm_pos, pm_pos_y, v) }
|
||||
function phys_pos_x(rt_systems_move_st: RtSystemsMoveState, e: int) -> int { return World.get(e, rt_systems_move_st.pm_pos, rt_systems_move_st.pm_pos_x) }
|
||||
function phys_pos_y(rt_systems_move_st: RtSystemsMoveState, e: int) -> int { return World.get(e, rt_systems_move_st.pm_pos, rt_systems_move_st.pm_pos_y) }
|
||||
function phys_set_x(rt_systems_move_st: RtSystemsMoveState, e: int, v: int) -> void { World.set(e, rt_systems_move_st.pm_pos, rt_systems_move_st.pm_pos_x, v) }
|
||||
function phys_set_y(rt_systems_move_st: RtSystemsMoveState, e: int, v: int) -> void { World.set(e, rt_systems_move_st.pm_pos, rt_systems_move_st.pm_pos_y, v) }
|
||||
|
||||
function phys_c_int(e: int, f: int) -> int {
|
||||
function phys_c_int(rt_systems_move_st: RtSystemsMoveState, e: int, f: int) -> int {
|
||||
if f < 0 { return 0 }
|
||||
return World.get(e, pm_col, f)
|
||||
return World.get(e, rt_systems_move_st.pm_col, f)
|
||||
}
|
||||
# a collider's AABB left / top edge (Position anchor + offset).
|
||||
function phys_aabb_x(e: int) -> int { return phys_pos_x(e) + phys_c_int(e, pm_c_offx) }
|
||||
function phys_aabb_y(e: int) -> int { return phys_pos_y(e) + phys_c_int(e, pm_c_offy) }
|
||||
function phys_aabb_x(rt_systems_move_st: RtSystemsMoveState, e: int) -> int { return phys_pos_x(rt_systems_move_st, e) + phys_c_int(rt_systems_move_st, e, rt_systems_move_st.pm_c_offx) }
|
||||
function phys_aabb_y(rt_systems_move_st: RtSystemsMoveState, e: int) -> int { return phys_pos_y(rt_systems_move_st, e) + phys_c_int(rt_systems_move_st, e, rt_systems_move_st.pm_c_offy) }
|
||||
|
||||
# ---- X sweep ----------------------------------------------------------------
|
||||
# Clamp a body's tentative dx so its AABB (px,py,w,h) stops at the first solid it
|
||||
# would cross this frame — entity colliders and (optionally) the tile grid — and
|
||||
# flag phys_hit_x on contact. One-way platforms never block horizontal motion.
|
||||
function phys_clamp_x(self_e: int, px: int, py: int, w: int, h: int, dx: int) -> int {
|
||||
function phys_clamp_x(rt_core_st: RtCoreState, rt_systems_move_st: mut RtSystemsMoveState, self_e: int, px: int, py: int, w: int, h: int, dx: int) -> int {
|
||||
if dx == 0 { return 0 }
|
||||
var best = dx
|
||||
|
||||
# --- entity solids: every other non-trigger collider we match against
|
||||
if pm_col >= 0 {
|
||||
var s = World.query_next(pm_col, 0)
|
||||
if rt_systems_move_st.pm_col >= 0 {
|
||||
var s = World.query_next(rt_systems_move_st.pm_col, 0)
|
||||
while s >= 0 {
|
||||
if s != self_e {
|
||||
if phys_c_int(s, pm_c_trig) == 0 {
|
||||
if phys_match(phys_cur_layer, phys_cur_mask, phys_c_int(s, pm_c_layer), phys_c_int(s, pm_c_mask)) {
|
||||
if phys_c_int(s, pm_c_oneway) == 0 { # one-way: pass horizontally
|
||||
let sx = phys_aabb_x(s); let sy = phys_aabb_y(s)
|
||||
let sw = phys_c_int(s, pm_c_w); let sh = phys_c_int(s, pm_c_h)
|
||||
if phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_trig) == 0 {
|
||||
if phys_match(rt_systems_move_st.phys_cur_layer, rt_systems_move_st.phys_cur_mask, phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_layer), phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_mask)) {
|
||||
if phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_oneway) == 0 { # one-way: pass horizontally
|
||||
let sx = phys_aabb_x(rt_systems_move_st, s); let sy = phys_aabb_y(rt_systems_move_st, s)
|
||||
let sw = phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_w); let sh = phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_h)
|
||||
if (py < sy + sh) and (sy < py + h) { # vertical spans overlap
|
||||
if dx > 0 {
|
||||
if px + w <= sx { # currently left of s
|
||||
|
|
@ -205,13 +207,13 @@ function phys_clamp_x(self_e: int, px: int, py: int, w: int, h: int, dx: int) ->
|
|||
}
|
||||
}
|
||||
}
|
||||
s = World.query_next(pm_col, s + 1)
|
||||
s = World.query_next(rt_systems_move_st.pm_col, s + 1)
|
||||
}
|
||||
}
|
||||
|
||||
# --- tile grid: nearest solid column in the swept path over the row span
|
||||
if phys_ts > 0 {
|
||||
let ts = phys_ts
|
||||
if rt_systems_move_st.phys_ts > 0 {
|
||||
let ts = rt_systems_move_st.phys_ts
|
||||
let r0 = phys_floordiv(py, ts)
|
||||
let r1 = phys_floordiv(py + h - 1, ts)
|
||||
if dx > 0 {
|
||||
|
|
@ -219,7 +221,7 @@ function phys_clamp_x(self_e: int, px: int, py: int, w: int, h: int, dx: int) ->
|
|||
let endc = phys_floordiv(px + w - 1 + best, ts)
|
||||
var c = startc + 1
|
||||
while c <= endc {
|
||||
if phys_col_solid(c, r0, r1) {
|
||||
if phys_col_solid(rt_core_st, rt_systems_move_st, c, r0, r1) {
|
||||
let allow = c * ts - (px + w)
|
||||
if allow < best { best = allow }
|
||||
c = endc + 1 # nearest wins; stop
|
||||
|
|
@ -230,7 +232,7 @@ function phys_clamp_x(self_e: int, px: int, py: int, w: int, h: int, dx: int) ->
|
|||
let endc = phys_floordiv(px + best, ts)
|
||||
var c = startc - 1
|
||||
while c >= endc {
|
||||
if phys_col_solid(c, r0, r1) {
|
||||
if phys_col_solid(rt_core_st, rt_systems_move_st, c, r0, r1) {
|
||||
let allow = (c + 1) * ts - px
|
||||
if allow > best { best = allow }
|
||||
c = endc - 1 # nearest wins; stop
|
||||
|
|
@ -239,7 +241,7 @@ function phys_clamp_x(self_e: int, px: int, py: int, w: int, h: int, dx: int) ->
|
|||
}
|
||||
}
|
||||
|
||||
if best != dx { phys_hit_x = 1 }
|
||||
if best != dx { rt_systems_move_st.phys_hit_x = 1 }
|
||||
return best
|
||||
}
|
||||
|
||||
|
|
@ -247,19 +249,19 @@ function phys_clamp_x(self_e: int, px: int, py: int, w: int, h: int, dx: int) ->
|
|||
# Clamp a body's tentative dy against solids (and one-way platforms on a downward
|
||||
# landing), flagging phys_hit_down / phys_hit_up. Must run after the X sweep so
|
||||
# px is already resolved for this frame.
|
||||
function phys_clamp_y(self_e: int, px: int, py: int, w: int, h: int, dy: int) -> int {
|
||||
function phys_clamp_y(rt_core_st: RtCoreState, rt_systems_move_st: mut RtSystemsMoveState, self_e: int, px: int, py: int, w: int, h: int, dy: int) -> int {
|
||||
if dy == 0 { return 0 }
|
||||
var best = dy
|
||||
|
||||
if pm_col >= 0 {
|
||||
var s = World.query_next(pm_col, 0)
|
||||
if rt_systems_move_st.pm_col >= 0 {
|
||||
var s = World.query_next(rt_systems_move_st.pm_col, 0)
|
||||
while s >= 0 {
|
||||
if s != self_e {
|
||||
if phys_c_int(s, pm_c_trig) == 0 {
|
||||
if phys_match(phys_cur_layer, phys_cur_mask, phys_c_int(s, pm_c_layer), phys_c_int(s, pm_c_mask)) {
|
||||
let sx = phys_aabb_x(s); let sy = phys_aabb_y(s)
|
||||
let sw = phys_c_int(s, pm_c_w); let sh = phys_c_int(s, pm_c_h)
|
||||
let oneway = phys_c_int(s, pm_c_oneway)
|
||||
if phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_trig) == 0 {
|
||||
if phys_match(rt_systems_move_st.phys_cur_layer, rt_systems_move_st.phys_cur_mask, phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_layer), phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_mask)) {
|
||||
let sx = phys_aabb_x(rt_systems_move_st, s); let sy = phys_aabb_y(rt_systems_move_st, s)
|
||||
let sw = phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_w); let sh = phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_h)
|
||||
let oneway = phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_oneway)
|
||||
if (px < sx + sw) and (sx < px + w) { # horizontal spans overlap
|
||||
if dy > 0 {
|
||||
# a one-way platform blocks only when the body starts on/above it
|
||||
|
|
@ -283,12 +285,12 @@ function phys_clamp_y(self_e: int, px: int, py: int, w: int, h: int, dy: int) ->
|
|||
}
|
||||
}
|
||||
}
|
||||
s = World.query_next(pm_col, s + 1)
|
||||
s = World.query_next(rt_systems_move_st.pm_col, s + 1)
|
||||
}
|
||||
}
|
||||
|
||||
if phys_ts > 0 {
|
||||
let ts = phys_ts
|
||||
if rt_systems_move_st.phys_ts > 0 {
|
||||
let ts = rt_systems_move_st.phys_ts
|
||||
let c0 = phys_floordiv(px, ts)
|
||||
let c1 = phys_floordiv(px + w - 1, ts)
|
||||
if dy > 0 {
|
||||
|
|
@ -296,10 +298,10 @@ function phys_clamp_y(self_e: int, px: int, py: int, w: int, h: int, dy: int) ->
|
|||
let endr = phys_floordiv(py + h - 1 + best, ts)
|
||||
var r = startr + 1
|
||||
while r <= endr {
|
||||
var block = phys_row_solid(r, c0, c1)
|
||||
var block = phys_row_solid(rt_core_st, rt_systems_move_st, r, c0, c1)
|
||||
# one-way tiles only catch a body whose feet start at/above the tile top
|
||||
if not block {
|
||||
if phys_row_land(r, c0, c1) { if py + h <= r * ts { block = true } }
|
||||
if phys_row_land(rt_core_st, rt_systems_move_st, r, c0, c1) { if py + h <= r * ts { block = true } }
|
||||
}
|
||||
if block {
|
||||
let allow = r * ts - (py + h)
|
||||
|
|
@ -312,7 +314,7 @@ function phys_clamp_y(self_e: int, px: int, py: int, w: int, h: int, dy: int) ->
|
|||
let endr = phys_floordiv(py + best, ts)
|
||||
var r = startr - 1
|
||||
while r >= endr {
|
||||
if phys_row_solid(r, c0, c1) { # one-way never blocks upward
|
||||
if phys_row_solid(rt_core_st, rt_systems_move_st, r, c0, c1) { # one-way never blocks upward
|
||||
let allow = (r + 1) * ts - py
|
||||
if allow > best { best = allow }
|
||||
r = endr - 1
|
||||
|
|
@ -322,7 +324,7 @@ function phys_clamp_y(self_e: int, px: int, py: int, w: int, h: int, dy: int) ->
|
|||
}
|
||||
|
||||
if best != dy {
|
||||
if dy > 0 { phys_hit_down = 1 } else { phys_hit_up = 1 }
|
||||
if dy > 0 { rt_systems_move_st.phys_hit_down = 1 } else { rt_systems_move_st.phys_hit_up = 1 }
|
||||
}
|
||||
return best
|
||||
}
|
||||
|
|
@ -330,40 +332,40 @@ function phys_clamp_y(self_e: int, px: int, py: int, w: int, h: int, dy: int) ->
|
|||
# ---- ground probe -----------------------------------------------------------
|
||||
# on_ground is a 1px downward overlap test, independent of this frame's velocity,
|
||||
# so a body resting under sub-pixel gravity still reads grounded.
|
||||
function phys_grounded(self_e: int, px: int, py: int, w: int, h: int) -> bool {
|
||||
function phys_grounded(rt_core_st: RtCoreState, rt_systems_move_st: RtSystemsMoveState, self_e: int, px: int, py: int, w: int, h: int) -> bool {
|
||||
# entity solids one pixel below
|
||||
if pm_col >= 0 {
|
||||
var s = World.query_next(pm_col, 0)
|
||||
if rt_systems_move_st.pm_col >= 0 {
|
||||
var s = World.query_next(rt_systems_move_st.pm_col, 0)
|
||||
while s >= 0 {
|
||||
if s != self_e {
|
||||
if phys_c_int(s, pm_c_trig) == 0 {
|
||||
if phys_match(phys_cur_layer, phys_cur_mask, phys_c_int(s, pm_c_layer), phys_c_int(s, pm_c_mask)) {
|
||||
let sx = phys_aabb_x(s); let sy = phys_aabb_y(s)
|
||||
let sw = phys_c_int(s, pm_c_w); let sh = phys_c_int(s, pm_c_h)
|
||||
if phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_trig) == 0 {
|
||||
if phys_match(rt_systems_move_st.phys_cur_layer, rt_systems_move_st.phys_cur_mask, phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_layer), phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_mask)) {
|
||||
let sx = phys_aabb_x(rt_systems_move_st, s); let sy = phys_aabb_y(rt_systems_move_st, s)
|
||||
let sw = phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_w); let sh = phys_c_int(rt_systems_move_st, s, rt_systems_move_st.pm_c_h)
|
||||
if (px < sx + sw) and (sx < px + w) {
|
||||
if (py + h <= sy) and (py + h + 1 > sy) { return true }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
s = World.query_next(pm_col, s + 1)
|
||||
s = World.query_next(rt_systems_move_st.pm_col, s + 1)
|
||||
}
|
||||
}
|
||||
if phys_ts > 0 {
|
||||
let ts = phys_ts
|
||||
if rt_systems_move_st.phys_ts > 0 {
|
||||
let ts = rt_systems_move_st.phys_ts
|
||||
let c0 = phys_floordiv(px, ts)
|
||||
let c1 = phys_floordiv(px + w - 1, ts)
|
||||
let footr = phys_floordiv(py + h, ts) # tile row just below the feet
|
||||
if (py + h) == footr * ts { # feet flush on a tile boundary
|
||||
if phys_row_solid(footr, c0, c1) { return true }
|
||||
if phys_row_land(footr, c0, c1) { return true }
|
||||
if phys_row_solid(rt_core_st, rt_systems_move_st, footr, c0, c1) { return true }
|
||||
if phys_row_land(rt_core_st, rt_systems_move_st, footr, c0, c1) { return true }
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
# ---- the system ------------------------------------------------------------
|
||||
function esys_move() -> void {
|
||||
function esys_move(rt_core_st: mut RtCoreState, rt_systems_move_st: mut RtSystemsMoveState) -> void {
|
||||
let pb = World.prop_id("Body")
|
||||
if pb < 0 { return }
|
||||
|
||||
|
|
@ -382,23 +384,23 @@ function esys_move() -> void {
|
|||
let f_ny = World.field_id(pb, "hit_ny")
|
||||
|
||||
# shared / config props (into module globals the helpers read)
|
||||
pm_pos = World.prop_id("Position")
|
||||
if pm_pos >= 0 {
|
||||
pm_pos_x = World.field_id(pm_pos, "x")
|
||||
pm_pos_y = World.field_id(pm_pos, "y")
|
||||
rt_systems_move_st.pm_pos = World.prop_id("Position")
|
||||
if rt_systems_move_st.pm_pos >= 0 {
|
||||
rt_systems_move_st.pm_pos_x = World.field_id(rt_systems_move_st.pm_pos, "x")
|
||||
rt_systems_move_st.pm_pos_y = World.field_id(rt_systems_move_st.pm_pos, "y")
|
||||
}
|
||||
pm_col = World.prop_id("Collider")
|
||||
if pm_col >= 0 {
|
||||
pm_c_w = World.field_id(pm_col, "w")
|
||||
pm_c_h = World.field_id(pm_col, "h")
|
||||
pm_c_offx = World.field_id(pm_col, "offx")
|
||||
pm_c_offy = World.field_id(pm_col, "offy")
|
||||
pm_c_trig = World.field_id(pm_col, "is_trigger")
|
||||
pm_c_oneway = World.field_id(pm_col, "one_way")
|
||||
pm_c_layer = World.field_id(pm_col, "layer")
|
||||
pm_c_mask = World.field_id(pm_col, "mask")
|
||||
rt_systems_move_st.pm_col = World.prop_id("Collider")
|
||||
if rt_systems_move_st.pm_col >= 0 {
|
||||
rt_systems_move_st.pm_c_w = World.field_id(rt_systems_move_st.pm_col, "w")
|
||||
rt_systems_move_st.pm_c_h = World.field_id(rt_systems_move_st.pm_col, "h")
|
||||
rt_systems_move_st.pm_c_offx = World.field_id(rt_systems_move_st.pm_col, "offx")
|
||||
rt_systems_move_st.pm_c_offy = World.field_id(rt_systems_move_st.pm_col, "offy")
|
||||
rt_systems_move_st.pm_c_trig = World.field_id(rt_systems_move_st.pm_col, "is_trigger")
|
||||
rt_systems_move_st.pm_c_oneway = World.field_id(rt_systems_move_st.pm_col, "one_way")
|
||||
rt_systems_move_st.pm_c_layer = World.field_id(rt_systems_move_st.pm_col, "layer")
|
||||
rt_systems_move_st.pm_c_mask = World.field_id(rt_systems_move_st.pm_col, "mask")
|
||||
}
|
||||
phys_ts = 0; phys_wall = 0; phys_wall2 = 0; phys_oneway = 0
|
||||
rt_systems_move_st.phys_ts = 0; rt_systems_move_st.phys_wall = 0; rt_systems_move_st.phys_wall2 = 0; rt_systems_move_st.phys_oneway = 0
|
||||
let ps = World.prop_id("Solids")
|
||||
if ps >= 0 {
|
||||
let se = World.query_next(ps, 0)
|
||||
|
|
@ -406,24 +408,24 @@ function esys_move() -> void {
|
|||
let f_tile = World.field_id(ps, "tile")
|
||||
let f_wall = World.field_id(ps, "wall")
|
||||
let f_ow = World.field_id(ps, "oneway")
|
||||
if f_tile >= 0 { phys_ts = World.get(se, ps, f_tile) }
|
||||
if f_wall >= 0 { phys_wall = World.get(se, ps, f_wall) }
|
||||
if f_ow >= 0 { phys_oneway = World.get(se, ps, f_ow) }
|
||||
if f_tile >= 0 { rt_systems_move_st.phys_ts = World.get(se, ps, f_tile) }
|
||||
if f_wall >= 0 { rt_systems_move_st.phys_wall = World.get(se, ps, f_wall) }
|
||||
if f_ow >= 0 { rt_systems_move_st.phys_oneway = World.get(se, ps, f_ow) }
|
||||
let f_w2 = World.field_id(ps, "solid2")
|
||||
if f_w2 >= 0 { phys_wall2 = World.get(se, ps, f_w2) }
|
||||
rt_map_solid1 = phys_wall; rt_map_solid2 = phys_wall2 # Map.is_solid reads the same config
|
||||
if phys_ts > 0 { rt_map_tile_px = phys_ts }
|
||||
if f_w2 >= 0 { rt_systems_move_st.phys_wall2 = World.get(se, ps, f_w2) }
|
||||
rt_core_st.rt_map_solid1 = rt_systems_move_st.phys_wall; rt_core_st.rt_map_solid2 = rt_systems_move_st.phys_wall2 # Map.is_solid reads the same config
|
||||
if rt_systems_move_st.phys_ts > 0 { rt_core_st.rt_map_tile_px = rt_systems_move_st.phys_ts }
|
||||
}
|
||||
}
|
||||
|
||||
# a Position is required to move a body; a Body with none is inert.
|
||||
if pm_pos < 0 { return }
|
||||
if pm_pos_x < 0 { return }
|
||||
if pm_pos_y < 0 { return }
|
||||
if rt_systems_move_st.pm_pos < 0 { return }
|
||||
if rt_systems_move_st.pm_pos_x < 0 { return }
|
||||
if rt_systems_move_st.pm_pos_y < 0 { return }
|
||||
|
||||
var e = World.query_next(pb, 0)
|
||||
while e >= 0 {
|
||||
if World.has(e, pm_pos) != 0 {
|
||||
if World.has(e, rt_systems_move_st.pm_pos) != 0 {
|
||||
# 1. integrate velocity (+ gravity for a platformer policy)
|
||||
var vx = 0; if f_vx >= 0 { vx = World.get(e, pb, f_vx) }
|
||||
var vy = 0; if f_vy >= 0 { vy = World.get(e, pb, f_vy) }
|
||||
|
|
@ -452,42 +454,42 @@ function esys_move() -> void {
|
|||
|
||||
# 3. does this body have a solid shape? (a trigger-only body moves freely)
|
||||
var has_shape = false
|
||||
if pm_col >= 0 {
|
||||
if World.has(e, pm_col) != 0 { if phys_c_int(e, pm_c_trig) == 0 { has_shape = true } }
|
||||
if rt_systems_move_st.pm_col >= 0 {
|
||||
if World.has(e, rt_systems_move_st.pm_col) != 0 { if phys_c_int(rt_systems_move_st, e, rt_systems_move_st.pm_c_trig) == 0 { has_shape = true } }
|
||||
}
|
||||
|
||||
if has_shape {
|
||||
phys_cur_layer = phys_c_int(e, pm_c_layer)
|
||||
phys_cur_mask = phys_c_int(e, pm_c_mask)
|
||||
let w = phys_c_int(e, pm_c_w)
|
||||
let h = phys_c_int(e, pm_c_h)
|
||||
var px = phys_aabb_x(e)
|
||||
let py0 = phys_aabb_y(e)
|
||||
rt_systems_move_st.phys_cur_layer = phys_c_int(rt_systems_move_st, e, rt_systems_move_st.pm_c_layer)
|
||||
rt_systems_move_st.phys_cur_mask = phys_c_int(rt_systems_move_st, e, rt_systems_move_st.pm_c_mask)
|
||||
let w = phys_c_int(rt_systems_move_st, e, rt_systems_move_st.pm_c_w)
|
||||
let h = phys_c_int(rt_systems_move_st, e, rt_systems_move_st.pm_c_h)
|
||||
var px = phys_aabb_x(rt_systems_move_st, e)
|
||||
let py0 = phys_aabb_y(rt_systems_move_st, e)
|
||||
|
||||
# X sweep, commit, then Y sweep from the resolved x
|
||||
phys_hit_x = 0
|
||||
let cdx = phys_clamp_x(e, px, py0, w, h, dx)
|
||||
phys_set_x(e, phys_pos_x(e) + cdx)
|
||||
px = phys_aabb_x(e)
|
||||
rt_systems_move_st.phys_hit_x = 0
|
||||
let cdx = phys_clamp_x(rt_core_st, rt_systems_move_st, e, px, py0, w, h, dx)
|
||||
phys_set_x(rt_systems_move_st, e, phys_pos_x(rt_systems_move_st, e) + cdx)
|
||||
px = phys_aabb_x(rt_systems_move_st, e)
|
||||
|
||||
phys_hit_up = 0; phys_hit_down = 0
|
||||
let py = phys_aabb_y(e)
|
||||
let cdy = phys_clamp_y(e, px, py, w, h, dy)
|
||||
phys_set_y(e, phys_pos_y(e) + cdy)
|
||||
rt_systems_move_st.phys_hit_up = 0; rt_systems_move_st.phys_hit_down = 0
|
||||
let py = phys_aabb_y(rt_systems_move_st, e)
|
||||
let cdy = phys_clamp_y(rt_core_st, rt_systems_move_st, e, px, py, w, h, dy)
|
||||
phys_set_y(rt_systems_move_st, e, phys_pos_y(rt_systems_move_st, e) + cdy)
|
||||
|
||||
# derived flags + contact normal
|
||||
if phys_hit_x == 1 { hit_wall = 1; vx = 0; if dx > 0 { nx = -1 } else { nx = 1 } }
|
||||
if phys_hit_up == 1 { hit_ceiling = 1; vy = 0; ny = 1 }
|
||||
if phys_hit_down == 1 { vy = 0; ny = -1 }
|
||||
let gy = phys_aabb_y(e)
|
||||
if phys_grounded(e, px, gy, w, h) { on_ground = 1 }
|
||||
if rt_systems_move_st.phys_hit_x == 1 { hit_wall = 1; vx = 0; if dx > 0 { nx = -1 } else { nx = 1 } }
|
||||
if rt_systems_move_st.phys_hit_up == 1 { hit_ceiling = 1; vy = 0; ny = 1 }
|
||||
if rt_systems_move_st.phys_hit_down == 1 { vy = 0; ny = -1 }
|
||||
let gy = phys_aabb_y(rt_systems_move_st, e)
|
||||
if phys_grounded(rt_core_st, rt_systems_move_st, e, px, gy, w, h) { on_ground = 1 }
|
||||
# a body pressed onto the ground carries no downward velocity, whatever
|
||||
# the gravity step was this frame (so on_ground implies a settled vy).
|
||||
if (on_ground == 1) and (vy > 0) { vy = 0 }
|
||||
} else {
|
||||
# free integration: apply the whole-pixel step straight to Position
|
||||
phys_set_x(e, phys_pos_x(e) + dx)
|
||||
phys_set_y(e, phys_pos_y(e) + dy)
|
||||
phys_set_x(rt_systems_move_st, e, phys_pos_x(rt_systems_move_st, e) + dx)
|
||||
phys_set_y(rt_systems_move_st, e, phys_pos_y(rt_systems_move_st, e) + dy)
|
||||
}
|
||||
|
||||
# 4. write velocity + subpixel remainder + derived outputs back
|
||||
|
|
@ -511,35 +513,35 @@ function esys_move() -> void {
|
|||
# 5. triggers/sensors — overlap that reports but never resolves. For each
|
||||
# trigger collider, find the lowest-id body-shaped collider it overlaps and
|
||||
# edge-detect enter/exit against last frame (SpriteAnim.event_fired shape).
|
||||
esys_triggers()
|
||||
esys_triggers(rt_systems_move_st)
|
||||
}
|
||||
|
||||
function esys_triggers() -> void {
|
||||
if pm_col < 0 { return }
|
||||
if pm_c_trig < 0 { return }
|
||||
let f_hit = World.field_id(pm_col, "hit")
|
||||
let f_ent = World.field_id(pm_col, "entered")
|
||||
let f_ext = World.field_id(pm_col, "exited")
|
||||
function esys_triggers(rt_systems_move_st: mut RtSystemsMoveState) -> void {
|
||||
if rt_systems_move_st.pm_col < 0 { return }
|
||||
if rt_systems_move_st.pm_c_trig < 0 { return }
|
||||
let f_hit = World.field_id(rt_systems_move_st.pm_col, "hit")
|
||||
let f_ent = World.field_id(rt_systems_move_st.pm_col, "entered")
|
||||
let f_ext = World.field_id(rt_systems_move_st.pm_col, "exited")
|
||||
if (f_hit < 0) and (f_ent < 0) and (f_ext < 0) { return } # no trigger outputs declared
|
||||
|
||||
if phys_trig_prev == null { phys_trig_prev = words(1024) }
|
||||
if rt_systems_move_st.phys_trig_prev == null { rt_systems_move_st.phys_trig_prev = words(1024) }
|
||||
|
||||
var t = World.query_next(pm_col, 0)
|
||||
var t = World.query_next(rt_systems_move_st.pm_col, 0)
|
||||
while t >= 0 {
|
||||
if phys_c_int(t, pm_c_trig) != 0 {
|
||||
if World.has(t, pm_pos) != 0 {
|
||||
let tx = phys_aabb_x(t); let ty = phys_aabb_y(t)
|
||||
let tw = phys_c_int(t, pm_c_w); let th = phys_c_int(t, pm_c_h)
|
||||
let tl = phys_c_int(t, pm_c_layer); let tm = phys_c_int(t, pm_c_mask)
|
||||
if phys_c_int(rt_systems_move_st, t, rt_systems_move_st.pm_c_trig) != 0 {
|
||||
if World.has(t, rt_systems_move_st.pm_pos) != 0 {
|
||||
let tx = phys_aabb_x(rt_systems_move_st, t); let ty = phys_aabb_y(rt_systems_move_st, t)
|
||||
let tw = phys_c_int(rt_systems_move_st, t, rt_systems_move_st.pm_c_w); let th = phys_c_int(rt_systems_move_st, t, rt_systems_move_st.pm_c_h)
|
||||
let tl = phys_c_int(rt_systems_move_st, t, rt_systems_move_st.pm_c_layer); let tm = phys_c_int(rt_systems_move_st, t, rt_systems_move_st.pm_c_mask)
|
||||
var cur = -1
|
||||
var b = World.query_next(pm_col, 0)
|
||||
var b = World.query_next(rt_systems_move_st.pm_col, 0)
|
||||
while b >= 0 {
|
||||
if b != t {
|
||||
if phys_c_int(b, pm_c_trig) == 0 {
|
||||
if World.has(b, pm_pos) != 0 {
|
||||
if phys_match(tl, tm, phys_c_int(b, pm_c_layer), phys_c_int(b, pm_c_mask)) {
|
||||
let bx = phys_aabb_x(b); let by = phys_aabb_y(b)
|
||||
let bw = phys_c_int(b, pm_c_w); let bh = phys_c_int(b, pm_c_h)
|
||||
if phys_c_int(rt_systems_move_st, b, rt_systems_move_st.pm_c_trig) == 0 {
|
||||
if World.has(b, rt_systems_move_st.pm_pos) != 0 {
|
||||
if phys_match(tl, tm, phys_c_int(rt_systems_move_st, b, rt_systems_move_st.pm_c_layer), phys_c_int(rt_systems_move_st, b, rt_systems_move_st.pm_c_mask)) {
|
||||
let bx = phys_aabb_x(rt_systems_move_st, b); let by = phys_aabb_y(rt_systems_move_st, b)
|
||||
let bw = phys_c_int(rt_systems_move_st, b, rt_systems_move_st.pm_c_w); let bh = phys_c_int(rt_systems_move_st, b, rt_systems_move_st.pm_c_h)
|
||||
if (tx < bx + bw) and (bx < tx + tw) and (ty < by + bh) and (by < ty + th) {
|
||||
if cur < 0 { cur = b } # lowest id wins (deterministic)
|
||||
}
|
||||
|
|
@ -547,19 +549,19 @@ function esys_triggers() -> void {
|
|||
}
|
||||
}
|
||||
}
|
||||
b = World.query_next(pm_col, b + 1)
|
||||
b = World.query_next(rt_systems_move_st.pm_col, b + 1)
|
||||
}
|
||||
let prev = phys_trig_prev[t] - 1 # stored as id+1, 0 = none
|
||||
let prev = rt_systems_move_st.phys_trig_prev[t] - 1 # stored as id+1, 0 = none
|
||||
var entered = 0
|
||||
var exited = 0
|
||||
if (prev < 0) and (cur >= 0) { entered = 1 }
|
||||
if (prev >= 0) and (cur < 0) { exited = 1 }
|
||||
phys_trig_prev[t] = cur + 1
|
||||
if f_hit >= 0 { World.set(t, pm_col, f_hit, cur) }
|
||||
if f_ent >= 0 { World.set(t, pm_col, f_ent, entered) }
|
||||
if f_ext >= 0 { World.set(t, pm_col, f_ext, exited) }
|
||||
rt_systems_move_st.phys_trig_prev[t] = cur + 1
|
||||
if f_hit >= 0 { World.set(t, rt_systems_move_st.pm_col, f_hit, cur) }
|
||||
if f_ent >= 0 { World.set(t, rt_systems_move_st.pm_col, f_ent, entered) }
|
||||
if f_ext >= 0 { World.set(t, rt_systems_move_st.pm_col, f_ext, exited) }
|
||||
}
|
||||
}
|
||||
t = World.query_next(pm_col, t + 1)
|
||||
t = World.query_next(rt_systems_move_st.pm_col, t + 1)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue