Draw the frames instead of faking them

Two of the same mistake, both called out.

The wounded feet still did not move because a mirror cannot move them: flipping
the legs swaps WHICH leg leads but keeps the two feet in the same two places, so
the spacing never changes and the body still slides. Measured it — mirrored feet
sat at -35/59 against the original's -34.5/60.5. What a walk actually needs is
the PASSING pose, feet together under the body, so the gap opens and closes.
Drawn now for all three wounded skins: 75->65, 95->68, 79->69 px between the
feet. (The mirror also clipped the steward's hanging arm into a floating
fragment, which is what Oliver spotted. Gone with it.)

The death was one sprite scaled down, which miniaturises a man rather than
killing him. It is five drawn frames now — arched back, knees, hands, face down
in the pool, a flat heap — each genuinely shorter than the last (100/84/60/47/20%
of standing height, common-scaled off one sheet) and each drawn at its own
height. No scaling anywhere in the sequence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-07-31 20:52:52 +02:00
1 parent 0a7633b671
commit 17ae73682b
12 files changed
+14 -11

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 21 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 20 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 23 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 27 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

+1 -1
View File
@@ -97,6 +97,6 @@
<p id="build"></p>
</div>
</div>
<script type="module" src="main.js?v=65"></script>
<script type="module" src="main.js?v=66"></script>
</body>
</html>
+13 -10
View File
@@ -155,9 +155,9 @@ export function proj(x, y, z) {
// ---------------------------------------------------------------- sprites ----
// assets/<name>.png; game falls back to code-drawn figures until sprites load.
const SPRV = 59; // asset cache-buster — bump with main.js?v=N (see the img.src note below)
const SPRV = 60; // asset cache-buster — bump with main.js?v=N (see the img.src note below)
const SPR = {};
for (const n of ['p_idle1','p_idle2','p_bounce','p_bounce2','p_toss','p_smash','p_run1','p_run2','p_run3','p_run4','p_swing1','p_swing2','p_die1','p_die2',
for (const n of ['p_idle1','p_idle2','p_bounce','p_bounce2','p_toss','p_smash','p_run1','p_run2','p_run3','p_run4','p_swing1','p_swing2','p_die1','p_die2','p_die3','p_die4','p_die5',
'o_idle1','o_idle2','o_bounce','o_bounce2','o_toss','o_smash','o_run1','o_run2','o_swing1','o_swing2',
'x_ump','x_boyrun1','x_boyrun2','x_boyrun3','x_boyrun4','x_crowd','x_crowd2','x_ads',
'x_boymop1','x_boymop2','x_boymop3','x_boymop4', // the push cycle, used only while he is stopped and working
@@ -506,23 +506,26 @@ function drawChar(ch) {
// alternating), then pulled flat and pressed DOWN into the ground as the ring of bodies closes over
// him — he is drawn inside the crowd's own z order (see render()), so the ones between him and the
// camera hide him exactly as they arrive. What is left when he is gone is the mound.
// Five DRAWN frames, arched back -> knees -> hands -> flat -> a heap, each one genuinely shorter
// than the last (100/84/60/47/20% of standing height, common-scaled off one sheet). The first pass
// faked the collapse by scaling one sprite down, which is miniaturising a man, not killing him.
// Nothing here is scaled: each frame is drawn at ITS OWN height, the same rule the walk cycles use.
const DIE_AT = [0, 0.15, 0.35, 0.6, 0.8]; // fraction of the way to EATEN_BURST each frame takes over
function drawDying() {
const at = G.eatenAt || P, t = G.eatenT;
if (t >= EATEN_BURST) return; // he is the pile now
const struggling = t < EATEN_GRAB;
const name = struggling ? (Math.floor(t * 11) % 2 ? 'p_die1' : 'p_die2') : 'p_die2';
const img = SPR[name];
const k = t / EATEN_BURST;
let i = 0; while (i + 1 < DIE_AT.length && k >= DIE_AT[i + 1]) i++;
const img = SPR['p_die' + (i + 1)];
const p = proj(at.x, 0, at.z);
const sink = struggling ? 0 : Math.min(1, (t - EATEN_GRAB) / (EATEN_BURST - EATEN_GRAB)); // 0..1 going under
const j = struggling ? 1.6 : 0.6; // he stops fighting as he goes down
const j = i < 2 ? 1.6 : i < 4 ? 0.7 : 0; // he stops fighting on the way down
ctx.save();
ctx.translate((Math.random() * 2 - 1) * j, (Math.random() * 2 - 1) * j * 0.6);
if (img) {
const h = PLAYER_H * p.s * (img.height / SPRITE_H) * (1 - 0.8 * sink); // pressed into the ground
const w = h * img.width / img.height;
const h = PLAYER_H * p.s * (img.height / SPRITE_H), w = h * img.width / img.height;
drawShadow(p.x, p.y, w * 0.42, h * 0.06, 0.3);
ctx.drawImage(img, p.x - w / 2, p.y - h, w, h);
} else drawFallbackChar(P, p, PLAYER_H * p.s * (1 - 0.8 * sink)); // sprites not loaded: still dies
} else drawFallbackChar(P, p, PLAYER_H * p.s); // sprites not loaded: he still dies
ctx.restore();
}