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>
No files matched your search
|
After Width: | Height: | Size: 351 KiB |
|
After Width: | Height: | Size: 363 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||