diff --git a/assets/_sheet_prun4.png b/assets/_sheet_prun4.png new file mode 100644 index 0000000..987b94c Binary files /dev/null and b/assets/_sheet_prun4.png differ diff --git a/assets/p_run1.png b/assets/p_run1.png index 2014c7e..68a33ca 100644 Binary files a/assets/p_run1.png and b/assets/p_run1.png differ diff --git a/assets/p_run2.png b/assets/p_run2.png index 07ff5dd..c58dfa2 100644 Binary files a/assets/p_run2.png and b/assets/p_run2.png differ diff --git a/assets/p_run3.png b/assets/p_run3.png new file mode 100644 index 0000000..21feee7 Binary files /dev/null and b/assets/p_run3.png differ diff --git a/assets/p_run4.png b/assets/p_run4.png new file mode 100644 index 0000000..a4b0f90 Binary files /dev/null and b/assets/p_run4.png differ diff --git a/index.html b/index.html index facb77b..791c9e9 100644 --- a/index.html +++ b/index.html @@ -97,6 +97,6 @@

- + diff --git a/render.js b/render.js index 6d69c62..0f1a24b 100644 --- a/render.js +++ b/render.js @@ -155,9 +155,9 @@ export function proj(x, y, z) { // ---------------------------------------------------------------- sprites ---- // assets/.png; game falls back to code-drawn figures until sprites load. -const SPRV = 51; // asset cache-buster — bump with main.js?v=N (see the img.src note below) +const SPRV = 52; // 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_swing1','p_swing2', +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', '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 @@ -434,7 +434,11 @@ function drawChar(ch) { const rising = Math.sin(w) * Math.cos(w) > 0; name = pre + (rising ? 'bounce2' : 'bounce'); // hand up while the ball rises, pat down exactly at the apex } - if (ch.pose === 'run') name = pre + (Math.floor(ch.runT * 9) % 2 ? 'run1' : 'run2'); + // Four-frame run where the frames exist (the player), two where they don't (the opponent). Same + // CYCLE rate either way — more frames subdivide the stride, they do not speed it up, exactly as + // ZFRAMES does for the shamblers. + const runN = SPR[pre + 'run4'] ? 4 : 2; + if (ch.pose === 'run') name = pre + 'run' + (Math.floor(ch.runT * 4.5 * runN) % runN + 1); if (receiverWaiting) name = pre + (sway > 0 ? 'run1' : 'run2'); // split-step shuffle if (ch.pose === 'swing') name = pre + (ch.poseT < 0.15 ? 'swing1' : 'swing2'); if (ch.pose === 'serve') name = pre + (G.phase === 'toss' ? 'toss' : 'smash'); @@ -442,7 +446,7 @@ function drawChar(ch) { // Auto-fire: the idle sprite carries a racket at his hip AND drawMgRacket puts one in his hands — // two rackets. The run frames are the racket-less art, so he jogs on the spot instead. if (ch.side === 'P' && ch.pose === 'idle' && G.mode === 'splatter' && (G.horde || G.mgT > 0)) - name = pre + (Math.floor(G.idleT * 6) % 2 ? 'run1' : 'run2'); + name = pre + 'run' + (Math.floor(G.idleT * 3 * runN) % runN + 1); const img = SPR[name]; drawShadow(p.x, p.y, hpx * 0.22, hpx * 0.06); if (img) {