十组预制浪,熟练玩家三天就能背下来

很多冲浪游戏的浪是这样做的:美术和动画团队精心制作十组左右的预制浪,每组有固定的高度、破碎位置和剥离速度,比赛时按顺序或随机循环播放。第一天玩家会觉得浪很漂亮;第三天,熟练玩家已经知道“第四道是长长的右手浪,第七道会在中段闭合”,看到浪的开头就知道结尾。

这就是背答案的问题。冲浪比赛的核心决策是选浪和读浪:这道浪会不会破、破在哪里、是等下一道还是现在就划。一旦浪可以被记住,这些决策就退化成记忆测试,高手和新手的差距变成谁玩的次数多,而不是谁判断得好。AI对手也会因此显得别扭:要么它也按记忆抢浪,看起来像作弊;要么它不按记忆,被背熟答案的玩家轻松碾压。

im体育的AI冲浪不使用固定循环的浪组,而是在一个受约束的参数空间里连续生成。下面说明这个空间由什么组成、如何随一天变化、怎样保证不会生成一堆没法冲的浪,以及它在性能上要付出多少代价。

参数空间:把“一道浪”拆成可以组合的变量

一道可冲的浪,大致由这几组变量决定:

  • 涌浪(Swell):周期、方向、离岸浪高、方向离散度。周期长的涌浪到岸后更有力,方向决定它和礁石或沙坝的夹角。
  • 风(Wind):离岸风让浪面平整、推迟破碎;向岸风让浪顶提前倒下、浪面起碎纹;侧岸风会让浪的一侧更好冲。
  • 潮汐(Tide):潮位就是水深,水深决定破浪点的前后位置和破碎的急缓。
  • 地形:冲浪点的水深图和底质,是整个参数空间的“坐标系”。

前三组随世界天气变化,地形则固定或缓慢变化。它们的组合不是简单相乘出几百种浪,而是连续空间:周期13秒和14秒之间有无数中间状态,风速和潮位也是连续的。玩家可以学会规律——“西南涌浪加离岸风,这里会出好浪”——但无法背下具体某一道浪。能学会规律而不能背答案,这是我们想要的状态。

浪组本身也由参数生成。我们把两到三个周期相近的涌浪分量叠加,形成忽大忽小的包络,再施加有限的随机扰动。浪组的平均间隔可以预测,但下一组第几道最大,需要看外海的隆起去判断。更完整的生成链条见海浪生成一文。

潮位的一天:同一个浪点的四张地图

潮汐是最容易被忽视、但对“不重复”贡献最大的变量。以一个设计示例说明:某个沙底与礁石混合的浪点,一天大致两涨两落。

  1. 清晨低潮:礁石边缘的浅区接近水面,浪在外侧提早破碎,陡而短,闭合比例高。
  2. 上午涨潮:水深增加,破浪点内移,剥离变顺,浪壁变长,是最适合比赛的窗口。
  3. 中午高潮:中等浪在礁石上方不破,只有浪组里的大浪能破,出现长时间的等待。
  4. 下午退潮:破浪点重新外移,若叠加午后海风转为向岸,浪面变碎,路线变短。

即使涌浪几天不变,潮汐时刻每天也会推后几十分钟,同一钟点的浪况在滚动变化。玩家每天同一时间登录,看到的浪点状态也不一样。这比在循环列表里多加几组浪更自然,也更贴近真实冲浪者的经验:他们看潮汐表和看浪高一样认真。

可冲性保底:生成不等于完全随机

参数空间的风险是生成出大量没法冲的浪:整排闭合、太小推不动,或者太大只适合职业选手。完全随机和固定循环一样会毁掉比赛。

我们对生成结果做一层可冲性校验,看几项指标:破浪高度是否落在当前赛事等级的区间内;剥离角是否允许一名中等速度的冲浪者追上破碎线;可用浪壁长度是否足以完成至少一次转向;破碎后的水深是否会造成过高的落水代价。

保底的对象是时间窗口,而不是单道浪。一组浪里可以有闭合浪,这本身就是读浪判断的一部分;但一场20分钟左右的比赛窗口里,必须有一定数量的浪达到可冲下限。如果某个天气组合下整个浪点都不达标,赛事系统就不在此时此地安排比赛,而是让世界呈现“今天这里浪不好”,并提示玩家其他浪点的情况。赛事的时间和地点跟着浪走,而不是强行把浪修成能比赛的样子。

性能预算:哪些实时算,哪些提前算

连续生成听起来很贵,但真正需要每帧计算的部分并不多。我们把工作分成三层:

  • 离线预计算:每个浪点的水深图、折射系数,以及不同涌浪方向和潮位下的破浪点分布。这些随地形固定,可以做成查找表。
  • 低频更新:天气系统每隔一段游戏时间更新涌浪、风和潮位,据此从查找表插值出当前浪点状态,并生成接下来几组浪的包络。
  • 实时计算:玩家附近正在破碎的那一两道浪的浪壁形状、浪唇和白水,以及冲浪板与浪面的交互。远处海面继续用FFT海面谱渲染,只负责视觉。

这样实时预算主要花在玩家身边,参数空间的丰富度主要由查找表和低频计算承担。在im体育App的移动端,还可以降低远处海面的分辨率,但不会降低玩家脚下那道浪的物理精度,因为那才是比赛本身。

固定循环省下的是开发与运行成本,付出的是比赛的寿命。在im体育里,我们倾向于把预算留给“下一道浪不可背”这件事:让玩家每次坐在排队区里,都需要重新看一眼海。