LightGame 完成 Windows
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
"""Validate default spawn candidates per 3x3 room of LevelTotal.
|
||||
|
||||
Reads tiles[] from src/Apps/LightGame/src/levels/LevelTotalData.h, then for each
|
||||
candidate (col,row,tile_x,tile_y) checks:
|
||||
- tile at (tx,ty) and (tx,ty+1)/(tx,ty-1) per collider (8,0)->(24,32) is non-solid
|
||||
- tile at (tx, ty+1) (the tile directly under feet at world_y=tile_y*32+32) is solid
|
||||
|
||||
Player position used by spawn check (LightGameApp.cpp:181):
|
||||
pos = (tile_x*32, tile_y*32) -- collider min=(8,0), max=(24,32)
|
||||
world_box = pos + collider = (tx*32+8, ty*32) -> (tx*32+24, ty*32+32)
|
||||
is_grounded checks tiles below feet; collider rows tile_top..tile_bottom-1 must be non-solid.
|
||||
|
||||
Solid ids: 5,6,7,8,9,10,11.
|
||||
Deadly: 12, 22.
|
||||
"""
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SRC = ROOT / "src/Apps/LightGame/src/levels/LevelTotalData.h"
|
||||
|
||||
text = SRC.read_text(encoding="utf-8")
|
||||
|
||||
# Parse tiles array
|
||||
m = re.search(r"static const uint16_t tiles\[\]\s*=\s*\{([^}]*)\};", text, re.DOTALL)
|
||||
nums = [int(x) for x in re.findall(r"-?\d+", m.group(1))]
|
||||
W, H = 96, 54
|
||||
assert len(nums) == W * H, len(nums)
|
||||
tiles = [nums[y * W:(y + 1) * W] for y in range(H)]
|
||||
|
||||
SOLID = {5, 6, 7, 8, 9, 10, 11}
|
||||
DEADLY = {12, 22}
|
||||
|
||||
def at(tx, ty):
|
||||
if tx < 0 or tx >= W or ty < 0 or ty >= H:
|
||||
return -1
|
||||
return tiles[ty][tx]
|
||||
|
||||
def collider_overlaps_solid(tx, ty):
|
||||
# world_box = (tx*32+8, ty*32) -> (tx*32+24, ty*32+32)
|
||||
# tile rows: ty .. (ty*32+32-1)//32 = ty (since 32+32-1=63, //32=1, so rows ty..ty+1-1 = ty)
|
||||
# Actually max.y - 1 = ty*32 + 31, //32 = ty. So only row ty.
|
||||
# tile cols: (tx*32+8)//32 = tx, (tx*32+24-1)//32 = tx. Only col tx.
|
||||
return at(tx, ty) in SOLID or at(tx, ty) in DEADLY
|
||||
|
||||
def has_solid_below(tx, ty):
|
||||
# Player feet at world_y = ty*32 + 32. is_grounded probes 1px below = ty*32+33.
|
||||
# Tile row = (ty*32+32)//32 = ty+1.
|
||||
return at(tx, ty + 1) in SOLID
|
||||
|
||||
def safe_above_head(tx, ty):
|
||||
# don't have ceiling spike just touching
|
||||
return at(tx, ty - 1) not in DEADLY
|
||||
|
||||
def candidate_score(tx, ty):
|
||||
if collider_overlaps_solid(tx, ty):
|
||||
return None, "overlap solid/deadly at body row"
|
||||
if not has_solid_below(tx, ty):
|
||||
return None, "not grounded"
|
||||
if not safe_above_head(tx, ty):
|
||||
return None, "deadly above head"
|
||||
return True, "ok"
|
||||
|
||||
# Room grid: cols 0/32/64, rows 0/18/36; size 32x18
|
||||
def find_safe_in_room(rcol, rrow, prefer=None):
|
||||
tx0, ty0 = rcol * 32, rrow * 18
|
||||
tx1, ty1 = tx0 + 32, ty0 + 18
|
||||
candidates = []
|
||||
if prefer:
|
||||
ptx, pty = prefer
|
||||
ok, why = candidate_score(ptx, pty)
|
||||
if ok:
|
||||
return (ptx, pty, "preferred")
|
||||
else:
|
||||
print(f" preferred {(ptx,pty)} rejected: {why}")
|
||||
# Scan center outward
|
||||
cx, cy = (tx0 + tx1) // 2, (ty0 + ty1) // 2
|
||||
for ty in range(ty0, ty1):
|
||||
for tx in range(tx0, tx1):
|
||||
ok, why = candidate_score(tx, ty)
|
||||
if ok:
|
||||
d = (tx - cx) ** 2 + (ty - cy) ** 2
|
||||
candidates.append((d, tx, ty))
|
||||
if not candidates:
|
||||
return None
|
||||
candidates.sort()
|
||||
_, tx, ty = candidates[0]
|
||||
return (tx, ty, "auto")
|
||||
|
||||
# Center room must reuse current spawn (1184, 928) = tile (37, 29)
|
||||
preferences = {
|
||||
(1, 1): (37, 29),
|
||||
}
|
||||
|
||||
print(f"{'Room':<8} {'tile':<10} {'pixel':<14} note")
|
||||
print("-" * 50)
|
||||
for rrow in range(3):
|
||||
for rcol in range(3):
|
||||
prefer = preferences.get((rcol, rrow))
|
||||
result = find_safe_in_room(rcol, rrow, prefer=prefer)
|
||||
if result is None:
|
||||
print(f"({rcol},{rrow}) NO SAFE SPAWN FOUND")
|
||||
continue
|
||||
tx, ty, kind = result
|
||||
# Spawn pos in pixels = (tx*32, ty*32). Verify under feet:
|
||||
below = at(tx, ty + 1)
|
||||
print(f"({rcol},{rrow}) ({tx:3d},{ty:3d}) ({tx*32:5d},{ty*32:4d}) below={below} ({kind})")
|
||||
Reference in New Issue
Block a user