怎么玩
四条轨道,三首曲子,声音全部当场算出来。音符从画面上方落到判定线,在重合的那一刻按下对应的键。判定不看画面画到第几帧,看的是声音时钟:每个音符带着一个目标时间,命中时拿当前歌曲时间减去它,差多少就给什么评价。
生命 100 起步,Perfect 回 1.2、Good 回 0.5、Miss 扣 6;归零判失败但曲子会放完。准确率是 (Perfect×1 + Good×0.6) 除以总音符数,全 Perfect 正好 100%。想打高,先把 ±45 ms 的窗口按稳,再把连击续到 100。
- 曲目
- 3 首
- 轨道
- 4 条
- 音符
- 48 / 72 / 104
- BPM
- 96 / 120 / 144
- 单曲时长
- 均为 40 秒
- 判定窗口
- ±45 / ±100 ms
- 连击加成
- 每 10 连击 +5%,上限 +50%
- 生命
- 100 / Perfect +1.2 / Good +0.5 / Miss −6
操作
这是什么
《听雨》是一款四轨下落式节奏游戏,打开网页就能玩,不用下载、不用注册。四条轨道对应键盘上的 D、F、J、K,音符从画面上方落到判定线,你在它和判定线重合的那一刻按下对应键就算击中。手机上没有键盘,画面底部画出四个触摸区,手指按哪一列就打哪条轨,支持多指同时按。判定和画面是分开算的,掉帧不会把节奏带偏。
游戏一共三首曲子:「檐下」96 BPM、64 拍、48 个音符,「涨潮」120 BPM、80 拍、72 个音符,「骤雨」144 BPM、96 拍、104 个音符。时长都按拍数除以 BPM 换算,三首都是 40 秒。谱面用固定种子生成,同一首曲子每次打开的音符位置、轨道和数量都一样,成绩才有可比性。
它的主时钟是 AudioContext 的 currentTime,不是帧数。每个音符、每一声 bass、每一层雨声都提前排到未来的时间点上,命中时就拿当前的歌曲时间和音符目标时间作差。±45 ms 以内是 Perfect,±100 ms 以内是 Good,超过 100 ms 没打中就是 Miss。哪怕某一帧卡了半个刷新周期,判定窗口也不会跟着漂。
三首曲子是怎么来的
三首曲子都没有音频文件。低频正弦负责 bass,三角波加快速衰减做木琴式的短音,再叠一层经过高通和低通滤波的噪声当雨声底噪。它们在浏览器里由 WebAudio 实时合成,每个事件按 currentTime 提前排程到未来的时间点,声音和判定共用同一把尺子。三首用各自的音阶和音色,从柔和到紧绷,难度也跟着往上走。
谱面不是手写死的,是用固定种子生成的。生成时把曲子的拍子切成八分音符网格,按权重挑出若干格放音符,难度越高密度越大,还会在部分格子放两条轨同时命中的和音。挑完再数一遍,确保「檐下」正好 48 个、「涨潮」72 个、「骤雨」104 个,一个不多一个不少;运行时也能数出来,不会随刷新变化。
- 「檐下」:96 BPM、64 拍、40 秒,柔和的小调五声音阶,正弦主音,48 个音符,和音最少,适合先熟悉键位和 ±45 ms 的手感。
- 「涨潮」:120 BPM、80 拍、40 秒,换成明亮的大调五声音阶,木琴质感更明显,72 个音符,八分音符的连续段落变多。
- 「骤雨」:144 BPM、96 拍、40 秒,音阶更紧、音色更锐,104 个音符,和音与跨轨切换最多,是三首里最累的一首。
判定与计分
生命从 100 开始。Perfect 回 1.2、Good 回 0.5、Miss 扣 6,生命夹在 0 到 100 之间。归零会判失败,但曲子仍会放完,结算里明确标出未通关,不会中途把你踢出去,也不会停止伴奏。连击在 Perfect 和 Good 上累加,Miss 清零。
连击每到 10 的整数倍,之后每个音符的得分就加 5%,一直加到上限 50% 封顶,也就是连到 100 之后不再涨。基础分 Perfect 最高,Good 约为它的六成。准确率按 (Perfect×1 + Good×0.6) 除以总音符数算,分母是整首曲子的音符数,所以全 Perfect 是 100%,全 Good 是 60%,全程 Miss 是 0%。结算再给出评级 S / A / B / C。
- Perfect:与目标时间相差不超过 45 ms,基础分最高,生命 +1.2,连击 +1。
- Good:相差不超过 100 ms,基础分约 Perfect 的六成,生命 +0.5,连击 +1。
- Miss:超过 100 ms 没击中,或一直没按,生命 −6、连击清零,准确率不计分。
- 分数、连击、准确率、生命四项实时显示在画面上方的 HUD;结算再补上 Perfect / Good / Miss 数量、最大连击、准确率和评级。
为什么用浏览器合成声音
不加载音频文件,主要是为了让节奏和判定严格对齐。下载来的音频在浏览器里要解码、进缓冲,开始播放的时刻和画面首帧常常差几十毫秒,而且不同设备差得还不一样;这个游戏把每个音符、每一声 bass、每一层雨声都按 currentTime 提前排程,判定用的也是同一个时钟,音画之间是同一把尺子,不用再猜偏移。
做法是把未来一小段时间内的事件先排好:每帧把未来约 0.15 秒内该响的音符和伴奏交给 WebAudio,剩下的等下一帧再排。这样既不卡帧,也不会因为一次性排满整首而在切后台回来后抢拍。暂停时把 AudioContext 挂起、currentTime 停走,恢复后从同一位置接着走,不会多响或漏响一个音。
代价是声音没法做得像录音那样厚,换来的是体积和确定性:页面里没有 mp3、没有 ogg,断网也能玩,三首曲子各用各的音阶与音色。雨声是叠了滤波的噪声,木琴是三角波配快速衰减,低频是正弦,全部现场算,没有一个采样文件要等。
键位、判定线和落速
电脑用 D、F、J、K 打四条轨,P 暂停,R 重开本曲,Esc 回标题,M 和页面上的按钮管声音。音符的落速是固定的,单位是像素每秒,判定线的位置跟着画布高度走,窗口拉高拉低都不会让音符提前或迟到;变的是它出现在画面里的时长,不是它该被击中的时间。
手机在画面底部画了四个触摸区,和四条轨道一一对应,按 x 坐标判断落在哪一轨,多指同时按也能分别判定。触摸区上标着键位字母,横屏竖屏都能用。四条发光轨道从紫色渐变到薄荷绿,命中时会在判定线炸开涟漪和粒子,连击数字弹出来,按下的那条轨会亮一下。背景雨丝分了几层视差,远处细而慢,近处粗而快。
成绩记在哪
每首曲子的最高分和最高准确率分开保存在这台设备的浏览器 localStorage 里,按曲目分别记录,选曲界面和结算界面会读出来,破纪录时结算会提示。数据不上传、不跨设备同步,也没有账号;清掉站点数据或换一台设备,纪录就从零开始。页面会加载广告脚本来覆盖运营成本,但游戏本身没有服务端、没有表单、没有自建统计。我们不知道你是谁,也不知道你打了多少局。
常见问题
下面是几个和判定、声音、成绩有关的实际问题,答案都对应到具体实现,而不是笼统的说法。
- 判定准不准,会不会因为我屏幕刷新率不同而变?
- 不会。判定用的是 AudioContext 的 currentTime 与音符目标时间的差值,和帧率、刷新率无关。画面掉帧最多让音符看起来跳一下,±45 ms 和 ±100 ms 的窗口不变。
- 暂停之后声音会不会错位?
- 暂停会把 AudioContext 挂起,currentTime 停走,已经提前排程的音符一起冻结;恢复后从冻结的位置继续,歌曲时间不变,所以不会多响、漏响或抢拍。
- 音符数量真的固定吗?
- 是。谱面由固定种子生成,生成后会数一遍,「檐下」48、「涨潮」72、「骤雨」104,严格等于标注值,每次打开都一样,运行时可数。
- 手机上怎么按四条轨?
- 画面底部有四个触摸区,按 x 坐标分轨,支持多指。不需要真的找四个按键,手指落在哪一列就打哪一轨。
- 生命扣到零会怎样?
- 生命归零判失败,但曲子会放完,结算明确标出未通关并照常给评级和成绩,不会中途结束。