The maze performs: doors swing, walls die loudly, homes wear their colors
Entertainment polish for the instant replay, all through one wizard's eyes. Doors now slide open along their own edge — Wolf3D style — when anyone steps through in a reel, hold for the crossing, and swing shut; the raycaster takes a per-edge openness map and doors carry their texture with them, leaving a sliver of jamb at the far post. A wall that dies bursts into stone and shakes the camera, then leaves a mound of rubble at the fallen edge for the rest of the reel (a tenth paintable sprite, drawn opaque — debris, not light). Jammed locks seethe: a rusty pulse across the wood, keyed off the view's own door states. Walking THROUGH a wall shimmers on both faces and washes the walker's own screen stone-gray. And every home base wears its owner's emblem on the flagstones — a near-white paintable overlay tinted by wizard color per cell in the floor cast. Testing surfaced a real ghost: a body standing near a far warp mouth also rendered at its virtual position, which can overlap real corridors — the depth buffer alone cannot clip it. Every column now remembers whether its ray bent, and a sprite draws only where its warp side matches the column's; projectile legs carry the same flag. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
8a27c06b55
commit
cdfae39398
@@ -5,7 +5,7 @@
|
||||
import { humanize } from "./net.svelte";
|
||||
import { scheduleFx, type BoardFx } from "./fx";
|
||||
import { fpFxForEvents, type FpFx } from "./fpv/fx3d";
|
||||
import { castRay } from "./fpv/raycast";
|
||||
import { castRay, edgeMid } from "./fpv/raycast";
|
||||
import { prefs } from "./prefs.svelte";
|
||||
import { stackSightTrace } from "@wizwar/engine";
|
||||
import type { GameEvent, GameView } from "@wizwar/engine";
|
||||
@@ -51,6 +51,24 @@
|
||||
// attack in progress, so a replay-watcher can see how a spell reached them.
|
||||
const sightTrace = $derived(stackSightTrace(step.view));
|
||||
|
||||
/** Every wall destroyed so far in the reel leaves a mound of rubble on
|
||||
* the first-person floor for the rest of it. */
|
||||
const rubbleSpots = $derived.by(() => {
|
||||
const spots: { x: number; y: number }[] = [];
|
||||
const seen = new Set<string>();
|
||||
for (let i = 0; i <= Math.min(idx, steps.length - 1); i++) {
|
||||
for (const e of steps[i]!.events) {
|
||||
if (e.type !== "wallDestroyed" || !("edge" in e)) continue;
|
||||
const edge = (e as { edge: { cell: { x: number; y: number }; side: "N" | "E" | "S" | "W" } }).edge;
|
||||
const key = `${edge.cell.x},${edge.cell.y}:${edge.side}`;
|
||||
if (seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
spots.push(edgeMid(edge.cell, edge.side));
|
||||
}
|
||||
}
|
||||
return spots;
|
||||
});
|
||||
|
||||
/** Each step's spells flare on the reel exactly as they did at the table. */
|
||||
let boardFx = $state<BoardFx[]>([]);
|
||||
$effect(() => {
|
||||
@@ -320,7 +338,7 @@
|
||||
{#if fp}
|
||||
<FirstPerson view={step.view} {povId}
|
||||
x={cam.x} y={cam.y} facing={cam.facing} width={640} height={360}
|
||||
fx={fpFx} posOverride={actorPos} />
|
||||
fx={fpFx} posOverride={actorPos} rubble={rubbleSpots} />
|
||||
{:else}
|
||||
<Board view={step.view} effects={boardFx} {sightTrace} />
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user