From 51b1e392aa2bd638bef58fbfc94e25a67776c174 Mon Sep 17 00:00:00 2001 From: Karlcarlo Date: Sun, 4 Oct 2026 01:07:03 +0000 Subject: [PATCH] =?UTF-8?q?feat(=E9=A6=96=E9=A1=B5=E5=BD=A9=E8=9B=8B):=20?= =?UTF-8?q?=E8=83=8E=E5=8A=A8=E5=B8=A6=E8=8A=82=E5=A5=8F=E3=80=81=E5=8F=AF?= =?UTF-8?q?=E8=BF=9E=E7=BB=AD=E8=B8=A2=20(v26100406)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 原地连踢:脚/拳/膝按节奏型连顶 3~4 拍(26~33 周 40%,34 周起 22% 且放慢) - 连续踢:踢完不歇,0.2~0.55 秒后在旁边再踢 1~2 下,每下缩短到 1.1~1.7 秒(30% / 15%) Co-Authored-By: Claude Opus 5.5 --- index.html | 2 +- js/app.js | 2 +- js/bump.js | 40 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 92fa9d7..db285a3 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ 兜爸心选 · 孕育陪伴 - + diff --git a/js/app.js b/js/app.js index 2c0c39a..64b0c44 100644 --- a/js/app.js +++ b/js/app.js @@ -3,7 +3,7 @@ (function () { 'use strict'; /* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */ - var VER = '26100405'; + var VER = '26100406'; const $ = (s, c) => (c || document).querySelector(s); const $$ = (s, c) => Array.from((c || document).querySelectorAll(s)); diff --git a/js/bump.js b/js/bump.js index 7b01f40..9eb953f 100644 --- a/js/bump.js +++ b/js/bump.js @@ -26,6 +26,7 @@ · 26~33 周「拳打脚踢」:完整版——小脚丫 / 小拳头 / 膝盖 / 小屁股,最勤(隔 4~8 秒),中途还会再顶一下 · 34 周起「地方小了」:很少猛踢,多是一大片慢慢拱过去(翻身、屁股),节奏放慢(隔 7~12 秒),次数不减 孕周来自 app.js 的 mb-preg 事件(syncPregnancy 跑完后广播)。调试:URL 带 bumpweek=24 可强制按 24 周演示。 + · 节奏(26 周起):有时原地「哒哒哒」带节奏连踢几拍;有时踢完不歇,旁边紧接着再踢 1~2 下 开关:「我的 → 隐私权限 → 宝宝在肚皮下动」,存 localStorage 'mb_bump'('0' = 关);系统开了「减弱动态效果」也不出来。 */ (function () { 'use strict'; @@ -78,10 +79,13 @@ /* ---------- 孕周 → 阶段 ---------- */ const STAGES = { - flutter: { order: ['flick', 'flick', 'tap', 'flick'], gap: [10, 18], kick: false, again: 0, double: .45, follow: false }, - active: { order: ORDER, gap: [4, 8], kick: true, again: .34, double: 0, follow: true }, - late: { order: ['roll', 'butt', 'foot', 'roll', 'knee'], gap: [7, 12], kick: false, again: .15, double: 0, follow: true, slow: true } + // drum:原地带节奏连踢的概率;chain:踢完不歇、旁边紧接着再踢的概率,最多连 chainMax 下(2026-10-04 用户:「有时会带点节奏、可以连续踢」) + flutter: { order: ['flick', 'flick', 'tap', 'flick'], gap: [10, 18], kick: false, again: 0, double: .45, follow: false, drum: 0, chain: 0 }, + active: { order: ORDER, gap: [4, 8], kick: true, again: .34, double: 0, follow: true, drum: .4, chain: .3, chainMax: 3 }, + late: { order: ['roll', 'butt', 'foot', 'roll', 'knee'], gap: [7, 12], kick: false, again: .15, double: 0, follow: true, slow: true, drum: .22, chain: .15, chainMax: 2 } }; + // 原地连踢的节奏型(每拍间隔,秒):匀速「哒哒哒」、「哒哒—哒」、「哒—哒哒」、两下一组 + const RHYTHMS = [[.42, .42, .42], [.3, .3, .75, .3], [.6, .28, .28], [.32, .9, .32], [.38, .38, .38, .38]]; const dbgWeek = (location.href.match(/bumpweek=(\d+)/) || [])[1]; let week = dbgWeek ? +dbgWeek : (window.__mbPreg ? window.__mbPreg.week : null); const stageOf = w => w == null || w < 20 ? null : w < 26 ? STAGES.flutter : w < 34 ? STAGES.active : STAGES.late; @@ -212,6 +216,20 @@ ft.h.vel += P.roll ? 30 : slow ? 45 : P.soft ? 50 : 120; ft.life = 0; ft.dur = P.dur[0] + Math.random() * (P.dur[1] - P.dur[0]); ft.kicked = false; ft.chained = !!ft.chainNext; ft.chainNext = false; + ft.chainN = ft.chained ? (ft.chainN || 0) + 1 : 0; + // 连续踢:第一下就定好后面还跟几下;连踢的每一下都短促(1 秒出头),不像单独那一下要停好几秒 + if (ft.chained) ft.chainLeft--; + else ft.chainLeft = stage && stage.chain && !P.soft && !P.roll && P !== PARTS.kick && Math.random() < stage.chain + ? 1 + (Math.random() * (stage.chainMax - 1) | 0) : 0; + const inChain = ft.chained || ft.chainLeft > 0; + if (inChain && !P.roll) ft.dur = (1.1 + Math.random() * .6) * (stage && stage.slow ? 1.3 : 1); + // 原地连踢:脚丫 / 拳头 / 膝盖才有;晚期节奏放慢 1.4 倍。拍子排在第一下顶起来之后,整段时长跟着拉长 + ft.beats = null; ft.beat = 0; ft.pop = 0; + if (!inChain && stage && stage.drum && !P.roll && !P.soft && P !== PARTS.kick && Math.random() < stage.drum) { + const r = RHYTHMS[Math.random() * RHYTHMS.length | 0], m = stage.slow ? 1.4 : 1; + let t = .7; ft.beats = r.map(d => (t += d * m)); + ft.dur = Math.max(ft.dur, t + .9); ft.kicked = true; // 有节奏就不再「中途再顶一下」 + } ft.catchable = P !== PARTS.kick; if (!skin) skin = findSkin(ft.x, ft.y); gather(ft.x, ft.y, Math.max(P.rx, P.ry) * 1.25 + 20); @@ -322,11 +340,25 @@ } else { ft.wob = Math.sin(u * 2.1) * .12; if (u > ft.dur * .4 && !ft.kicked && P !== PARTS.kick && !P.soft && stage && stage.kick) { ft.kicked = true; ft.h.vel += 70; } // 中途再顶一下 + // 一拍:先往回缩一下(鼓包塌一点),0.12 秒后再顶上来,位置跟着微微挪(脚尖 / 脚跟轮流使劲) + if (ft.beats && ft.beat < ft.beats.length && u >= ft.beats[ft.beat]) { + ft.beat++; ft.h.vel -= 85; ft.pop = .12; + ft.ox += (Math.random() - .5) * 10; ft.oy += (Math.random() - .5) * 10; + } + if (ft.pop > 0 && (ft.pop -= dt) <= 0) ft.h.vel += stage && stage.slow ? 95 : 150; + } + if (u > ft.dur) { + // 连续踢:这一下收得快一点,旁边紧接着再来,不等下一个间隔 + ft.chainNext = ft.chainLeft > 0; + if (ft.chainNext) { ft.h.to = 0; ft.h.k = 200; ft.h.c = 24; mode = 'hide'; } else hide(false); } - if (u > ft.dur) hide(false); } else if (mode === 'hide') { if (ft.h.v < .3) { mode = 'wait'; wait = gap(); + if (ft.chainNext) { + const a = Math.random() * Math.PI * 2, d = 50 + Math.random() * 40; + near = { x: ft.x + ft.ox + Math.cos(a) * d, y: ft.y + ft.oy + Math.sin(a) * d }; wait = .2 + Math.random() * .35; + } // 小鱼吐泡泡常常是连着的:一闪没了,旁边紧跟着又一下 if (stage && stage.double && ft.part.soft && !ft.chained && Math.random() < stage.double) { const a = Math.random() * Math.PI * 2;