fix(client): bottom-wall scan pierces 2-thick walls + corner diagonal; whole-box quantized cuts (T-1088)
Live-session findings, three in one: (1) Gauntlet walls are 2 tiles thick — the outer row's camera-far neighbor is the inner WALL, so its flag stayed 0 and it stood full-height behind the collapsed inner stub; the flag now scans up to 3 tiles through consecutive KNOWN walls (unknown stops the scan — no assumptions past the info boundary), and any newly-learned tile refreshes the wall chain behind it. (2) Corner pillars at the screen-bottom junction never collapsed — their interior floor sits DIAGONALLY behind, which no straight scan line reaches; the combined diagonal joins the scan set. (3) Per-fragment smoothstep falloff carved organic notches (the 'sphere' read) — the cut now computes per-instance in the vertex shader from the box's tile center and quantizes at 0.5: every wall box is either full or stub, X2-crisp. Verified via locomotion_cutaway autopilot capture: south runs read as clean stub rows, corners collapse, camera-far walls stand. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -155,6 +155,10 @@ var _free_slots: Array = [[], []]
|
||||
var _state_colors: Array[Color] = []
|
||||
var _last_tick: int = -1
|
||||
var _capacity_warned := false
|
||||
## Bottom-wall scan depth (tiles) along each camera-far direction — covers the
|
||||
## Gauntlet's 2-thick walls plus door trim.
|
||||
const BOTTOM_SCAN_DEPTH := 3
|
||||
|
||||
## Cutaway mode: 0 = sightline corridor, 1 = bottom walls low, 2 = both.
|
||||
var cutaway_mode: int = 0
|
||||
## Camera-far sim-neighbor deltas for the bottom-wall rule (see
|
||||
@@ -284,10 +288,13 @@ func _paint_new(key: Vector3i) -> void:
|
||||
_slots[key] = Vector2i(kind, slot)
|
||||
if kind == Store.Kind.WALL:
|
||||
_refresh_bottom_flag(key)
|
||||
else:
|
||||
# A newly-learned floor can promote camera-ward walls to bottom walls.
|
||||
for d in _behind_dirs:
|
||||
_refresh_bottom_flag(key - d)
|
||||
# Any newly-learned tile can promote camera-ward walls up the scan chain:
|
||||
# a floor is the promotion itself; a wall can EXTEND a chain that previously
|
||||
# stopped at unknown (Gauntlet walls are 2 tiles thick — the outer row sees
|
||||
# floor only THROUGH the inner row).
|
||||
for d in _behind_dirs:
|
||||
for step in range(1, BOTTOM_SCAN_DEPTH + 1):
|
||||
_refresh_bottom_flag(key - d * step)
|
||||
|
||||
|
||||
## Cutaway mode (design amendment, live session 2026-07-06): 0 = sightline
|
||||
@@ -322,6 +329,11 @@ func _compute_behind_dirs() -> void:
|
||||
# hides lies OPPOSITE that face -> behind_dir = -d for camera-ward d.
|
||||
if world_dir.z > 0.01:
|
||||
_behind_dirs.append(-d)
|
||||
# Corner pillars: at a wall-run junction the interior floor sits DIAGONALLY
|
||||
# behind (neither straight scan line reaches it) — include the combined
|
||||
# diagonal in the scan set.
|
||||
if _behind_dirs.size() == 2:
|
||||
_behind_dirs.append(_behind_dirs[0] + _behind_dirs[1])
|
||||
# Repaint flags for walls painted before the deferred computation ran.
|
||||
for key: Vector3i in _slots:
|
||||
if (_slots[key] as Vector2i).x == Store.Kind.WALL:
|
||||
@@ -332,11 +344,20 @@ func _refresh_bottom_flag(key: Vector3i) -> void:
|
||||
var slot: Vector2i = _slots.get(key, Vector2i(-1, -1))
|
||||
if slot.y < 0 or slot.x != Store.Kind.WALL:
|
||||
return
|
||||
# Scan up to BOTTOM_SCAN_DEPTH tiles along each camera-far direction,
|
||||
# walking THROUGH consecutive known walls (Gauntlet walls are 2 thick):
|
||||
# a known non-wall tile behind the wall run marks the whole run "bottom".
|
||||
# Unknown tiles stop the scan — no assumptions past the info boundary.
|
||||
var flag := 0.0
|
||||
for d in _behind_dirs:
|
||||
var n: Vector3i = key + d
|
||||
if store.has_tile(n) and store.kind_of(n) != Store.Kind.WALL:
|
||||
flag = 1.0
|
||||
for step in range(1, BOTTOM_SCAN_DEPTH + 1):
|
||||
var n: Vector3i = key + d * step
|
||||
if not store.has_tile(n):
|
||||
break
|
||||
if store.kind_of(n) != Store.Kind.WALL:
|
||||
flag = 1.0
|
||||
break
|
||||
if flag > 0.0:
|
||||
break
|
||||
_wall_mm.multimesh.set_instance_custom_data(slot.y, Color(flag, 0.0, 0.0, 0.0))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user