
做捕鱼项目这些年我最大的感受是决定玩家去留的往往不是炮台多华丽、子弹多花哨而是屏幕里那群鱼“游得对不对、死得爽不爽”。前几篇把捕鱼游戏的整体框架、炮台、子弹、网讲了一遍这一篇集中拆“鱼”本身——鱼种怎么分类、鱼群怎么游、鱼怎么被打死、死了之后系统怎么结算以及刷怪节奏和概率模型怎么配合。这篇内容适合三类人看刚入行的游戏策划、写捕鱼逻辑的客户端/服务端开发以及做数值和运营活动的同学。我会按“从表现到机制、再从机制到数值”的顺序讲尽量把每个决策背后的原因都交代清楚。1. 鱼的定位从“玩家眼中的分值”反推设计1.1 基础鱼种怎么分级小杂鱼、中档鱼和镇场大鱼打开任何一款捕鱼游戏玩家第一眼不会看你的代码也不会关心你的RTP模型他只会问三句话这条鱼值多少分好不好打打死之后爽不爽所以鱼的分类本质上是从“玩家预期”反推出来的。我习惯把基础鱼分成三档。第一档是1~3倍的小杂鱼比如小丑鱼、小鲤鱼体型小、游速快、成群出现作用就是让玩家不断获得“打中了”的正反馈把游戏节奏带起来。第二档是5~20倍的中档鱼比如灯笼鱼、魔鬼鱼、海龟体型明显变大出现频率适中打死一只会有比较强的“赚到了”情绪这一档是玩家长时间在线的主要动力。第三档是50倍以上的大鱼和BOSS比如金鲨、蓝鲸、章鱼王出场频率低、游速慢、血厚但一旦打死屏幕特效和飘分数字能直接刺激整个房间的氛围。这里有个很容易犯的错把倍率当“血量”用。倍率只是奖励倍率真正决定它难打的是捕获概率不是你给它加了多少血。血条是表现层的概率是数值层的两者不要混。定位代表鱼种倍率区间游速行为特征单条产出预算占比小杂鱼小丑鱼、小鲤鱼1~3快有停顿成群结队无规避30%中档鱼灯笼鱼、海龟5~20中等2~3条一小队偶尔变速40%大鱼金鲨、蓝鲸50~200慢稳单条巡游血量厚重20%BOSS/事件鱼章鱼王、远古巨龙300以上极慢带技能需要集火10%我见过有些团队把70%的产出预算都放在大鱼上想着“搏一搏单车变摩托”结果玩家打半小时一条大鱼都打不死负反馈拉满第二天留存直接掉一截。大鱼是用来制造情绪峰值的不是用来承接日常产出的。1.2 特殊鱼技能鱼、彩金鱼和事件鱼怎么加基础鱼负责稳定节奏特殊鱼负责打破节奏。常见做法是三种技能鱼、彩金鱼、事件鱼。技能鱼是指打死之后触发全屏效果比如炸弹鱼、闪电鱼。这类鱼在设计时最重要的是“触发链路要短”鱼的死亡动画播完立刻进入结算特效不要让玩家等待。我之前见过一版闪电鱼死亡后还要等0.8秒的爆开动画才开始劈闪电玩家在等待期间什么都干不了体感非常卡。正确的做法是死亡动画与闪电特效并行播放同时结算。彩金鱼更像一个“移动的运营活动”。它不常驻由后台在特定时间段投放身上挂着一个不断跳动的累计奖金数字玩家打它不是为了它的固定倍率而是为了那个奖金池。奖金池通常由全服玩家消耗的炮值按比例累积比如每消耗1000金币注入3金币。这样设计的好处是把“个人消耗”和“全服共同目标”绑定刺激玩家在大奖池出现时集中在线。事件鱼则是跟节日、版本活动挂钩的比如春节的财神鱼、周年庆的金龙。它一般有自己的独立概率和独立产出池不占用常规鱼种的经济预算。接入方式最好做成配置表驱动运营在后台配好生效时间、出现权重、技能类型客户端拉配置后自动替换不用发版。2. 鱼的行为AI从游动路径到受击反馈的状态机设计2.1 为什么捕鱼游戏不用寻路而是“预置路径随机偏移”很多没做过捕鱼的朋友第一次听到“鱼群AI”第一反应是上A寻路。这是捕鱼项目里最典型的误区。A适合角色需要在复杂地形里绕障碍的场景比如MOBA、RTS。但捕鱼游戏里的鱼几乎不需要智能避障玩家要的是“可预测、有美感、有节奏”的游动。我的做法是预置路径点系统。每条鱼或者每组鱼群在生成时绑定一条路径资源路径由一系列控制点组成可以是直线段、折线、贝塞尔曲线或者闭合环形。鱼沿着路径匀速移动到达终点后按配置决定是消失、折返还是从另一条路径继续。为了不让鱼游得太机械会给每个控制点加一个随机偏移量范围通常在20~80像素2D或0.5~1.5米3D同时让鱼的游动速度在一定区间内波动比如基础速度是3米每秒波动范围±20%。这样视觉上仍然是一条“稳定”的路线但每条鱼的具体轨迹又不一样。3D捕鱼还要额外注意一个问题鱼的转向半径。鱼不像车不会原地转弯尤其是大鱼。转弯半径太小会出现瞬间扭头穿模的“僵尸转”。我一般会给大鱼单独配置一个较大的转向半径并在转向时叠加身体朝向的插值让鱼头先转、身体随后跟上这样才像一条“有质量的鱼”。2.2 鱼的动画状态机受击反馈是捕鱼手感的核心鱼的状态机其实很简单游动Swim→ 受击Hit→ 死亡Dead加上一个待机Idle用作出生和特殊技能前摇。复杂的是这4个状态之间的“衔接手感”。游动状态就是常规的游泳动画循环播放。但当鱼的子弹打到鱼身上时鱼必须立刻响应。这里的关键是“受击反馈要明显但不能打断节奏”。我常用的方案是受击时鱼播放一个极短的“顿挫动画”时间控制在0.1~0.2秒然后回到游泳状态同时鱼身闪现一层白色高光持续0.2秒左右。顿挫动画不是真的做一个新动画而是在游泳动画基础上做时间缩放和位移偏移比如把播放速度降为原来的30%同时朝子弹来的方向偏移几个像素。这样玩家能明确感知“我打中它了”但又不会因为鱼被完全定住而觉得假。死亡状态要注意的是“死亡表现优先级”。普通鱼被网捕住后播放死亡动画、爆金币、飘分这些可以按顺序来但特殊鱼比如炸弹鱼需要打断网的表现优先播放自身技能。所以鱼的状态机里最好加一个“触发优先级”字段比如炸弹鱼死亡时技能触发优先级高于一切表现。动画状态机这块还有一个隐藏雷区客户端表现和服务器状态不同步。比如玩家炮台打出的子弹在客户端已经碰撞了鱼但服务器还没返回结果这时鱼不能提前播死亡动画反过来如果服务器已经判定死亡但客户端还在播游泳动画就会出现“鱼已经死了还在游”的穿帮。解决办法是在客户端做一个“表现缓冲队列”收到服务器的击杀结果后再按一个极短的延迟通常50~120毫秒播放死亡表现尽量对齐其他玩家的视角。3. 鱼群生成器刷怪节奏是捕鱼的隐形关卡设计3.1 出鱼结构决定了“玩家一网能兜到什么”鱼群生成在很多项目里被简单做成“每隔几秒刷几条鱼”这就浪费了刷怪节奏对玩家情绪的调控作用。我的理解是鱼群生成器相当于一个自动运行的关卡脚本它决定玩家在任何时间点面对的屏幕内容。先定义一个“鱼群配置表”每一项包含鱼种ID、数量范围、路径ID、生成间隔、同屏数量上限、权重。系统按权重随机选取下一波刷什么。比如普通波里小杂鱼权重60%中档鱼30%大鱼10%每一波的生命周期由“鱼走完全程消失”或“到达目标点后自动消散”来控制。我还会再加一个“同屏鱼数量上限”的硬约束。2D捕鱼通常是60~100条3D因为镜头和空间更大可以到120~150条。超过上限时不再生成新的鱼群直到部分鱼离开屏幕或被捕捉。这一步很关键因为鱼太多一方面性能扛不住另一方面玩家会“眼花到不知道打哪条”反而降低爽快感。鱼群的编队方式也要设计。小杂鱼适合6~10条排成一排或者一簇让一网下去能捞到好几条制造“赚了”的感觉中档鱼2~3条一队让玩家有瞄准的过程大鱼和BOSS必须单独行动给它们一种“很难靠近”的压迫感。编队的移动方式建议统一用“以队长路径为主队员沿法线方向偏移”这样整个鱼群能保持松散的整体感而不是完全同步的生硬队列。3.2 波次节奏用“高潮波”和“喘息波”交替控制玩家情绪光有随机刷怪还不够需要有一个波次脚本在背景运行。我一般把波次分为三种普通波、小高潮波、大鱼波。普通波持续20~30秒以小鱼加少量中档鱼为主让玩家持续有收获。小高潮波通常持续5~8秒会一口气刷出3~5条中档鱼和1条大鱼让玩家有“换大炮打一波”的冲动。大鱼波是全屏事件每90秒左右触发一次刷出1条BOSS级鱼同时搭配一圈中档鱼当作“护卫”。三种波次的交替要遵循“强弱强弱”的节奏不要让大鱼波连着出也不要把普通波拖到1分钟以上。运营活动期间可以通过后台配置临时调整波次权重比如“鱼潮活动”把大鱼波间隔从90秒缩短到40秒但代价是每发炮弹的期望返还率要相应调低否则经济系统会失控。4. 碰撞、捕捉与结算一颗子弹和一网鱼是怎么对上的4.1 碰撞模型选型球形、胶囊体还是多子碰撞体客户端物理这块我和很多人一样最早用精确的像素级碰撞鱼身体每个像素都参与检测结果性能惨不忍睹。后来换成简化几何体效果立刻好了一个量级。2D捕鱼最常用的是圆形碰撞体和胶囊体碰撞体。小杂鱼用圆半径大约是身体宽度的40%中档鱼和大鱼用胶囊体就是两个圆中间夹一个矩形和鱼身的长条形状贴合度很好。3D捕鱼则统一用球体和胶囊体配合一个“碰撞权重”字段控制同一颗子弹能穿透几条鱼、最多穿透多深。更关键的是“子弹和鱼谁检测谁”。不做性能优化的话常见做法是每颗子弹和每条鱼两两检测复杂度是O(子弹数×鱼数)同屏100条鱼、同时飞30颗子弹一帧就是3000次检测勉强能跑但Plus版本总要为手机性能留余量。我建议反过来每颗子弹在飞行时按帧采样记录其轨迹经过的碰撞体。因为子弹是直线飞行的就算有弹道弧线也是分段直线可以用射线检测或者连续扫描的方式拿到途经的鱼列表。这样检测次数从“子弹数×鱼数”降为“子弹数×穿越鱼数”同屏鱼再多也不怕。4.2 一网鱼的捕捉顺序碰撞列表、上限截断与后端结算子弹碰撞鱼之后会发生两件事子弹可能继续飞行去碰撞下一条鱼同时网在这个点展开。网展开后会根据网的半径捕捉范围内的所有鱼。这里有一个所有新手都会踩的坑一张网拉起来把半径内80条鱼全包进去了按照概率逐条判定最后全屏都是死亡动画产出瞬间爆表。解决方法是给每张网加上两个限制最大捕捉数和判定顺序。最大捕捉数一般设置在8~16之间超过部分即使视觉上在网内也不参与结算。判定顺序推荐“优先判定网中心附近的鱼再按距离向外扩展”这样至少保证玩家瞄准的那条鱼一定会被处理而边缘的鱼只是视觉效果。捕获的最终判定还得分“前端表现”和“后端逻辑”。一句话总结表现看前端结果看后端。客户端负责播动画、飘分、抖动服务器负责真正决定这条鱼死不死。服务器在收到子弹请求后生成随机数并与鱼的捕获率比对一旦命中就扣减产出、广播击杀结果。这样玩家离线、断线、重连都不会出现“打死鱼没给钱”的黑账。5. 数值模型与概率控制让“运气”稳定在目标范围里5.1 从目标RTP到单鱼捕获概率的计算过程捕鱼游戏的数值核心是RTPReturn To Player玩家返还率也就是玩家消耗的金币中有多少比例会以奖励形式返还。它不是固定的是一个期望值。举个例子假设我们设定某房间目标RTP70%玩家这个小时共消耗了10万金币那么系统期望返还7万。这7万不能均匀撒而要按鱼种分配。按前面表里的预算占比小杂鱼分30%即2.1万中档鱼分40%即2.8万大鱼分20%即1.4万BOSS分10%即0.7万。然后计算概率。某档鱼的目标产出O、玩家在该档鱼的命中次数N、该档鱼的平均倍率M那么单发命中后击杀概率p的期望公式是p O / (N × M)假设中档鱼平均倍率10倍玩家这个小时命中了4000发中档鱼目标是产出2.8万那么p 28000 / (4000 × 10) 0.7也就是中档鱼单发捕获率期望70%。大鱼如果平均倍率100倍目标产出1.4万命中200发则p 14000 / (200 × 100) 0.7。这里你会注意到只要倍率和命中次数安排好概率可以保持在一个视觉上“不算太坑”的水平。小鱼为什么感觉好打不是给它设了高概率而是它倍率低、命中次数高每次命中都接近必中。实战中我还会给小鱼单独加一个“保底机制”连续3发命中同一只小杂鱼未死后第4发强制死亡。这能避免极端情况下玩家对小鱼连续miss导致暴躁。5.2 动态概率调节反作弊与体验保护的后台手段纯静态概率有个硬伤如果某个玩家运气特别好在短时间内打出超出预期的产出经济就会崩。所以线上捕鱼一定会做动态调节。我的做法是给每个玩家维护一个“实时RTP窗口”比如最近1小时的实际返还率。当它明显高于目标RTP时下调大鱼和BOSS的捕获概率但保持小鱼和中档鱼的概率不动当它低于目标RTP时适度上调中档鱼概率给玩家一个“回血期”。调幅通常控制在±15%以内否则玩家会明显感觉鱼“变难打”或者“太好打了”都是负面体验。还要防一种作弊场景玩家用加速挂或脚本瞬间打出大量子弹。正常玩家一分钟最多打30~40发脚本能打上百发。服务器端要加频率限制和消耗校准一旦发现单发时间间隔异常直接拒绝请求。这个属于安全模块但需要在数值设计阶段就预留接口否则后期加上去会很痛苦。6. 捕鱼实战踩坑实录卡墙、超算、并发与性能排查6.1 鱼卡地形与路径死区3D捕鱼最烦的问题就是鱼游着游着插进了海底山体里。原因百分之八十是路径点离障碍物太近鱼在转向时由于转向半径的存在船身或尾部被挤进了地形。排查思路分三步第一步在路径编辑器里把鱼的碰撞半径可视化显示出来第二步对每条路径做一次自动检测凡是路径点与最近障碍物的距离小于鱼的碰撞半径加转向余量就报警第三步运行时加一个“卡死检测”鱼连续性移动距离低于阈值超过3秒自动把鱼拉回最近的有效路径点。上线后还要在后台统计卡死重置次数超过设定值就说明该路径配置有问题需要人工调整。6.2 一网捞出50条鱼判定顺序与上限的坑我见过线上事故炸弹鱼爆炸后结算逻辑把全屏300条鱼全部遍历了一遍明明给每条鱼单独判概率最后一条没死但结算数量过大导致客户端卡顿后台入账延迟玩家投诉“打到鱼不给钱”。问题出在“判定顺序”和“结算限流”上。炸弹鱼这类全屏结算也必须遵守单次结算存活上限比如最多只处理40条鱼的死亡表现剩余鱼统一走“沉默结算”——后端入账但客户端只播放常见的死亡特效不再逐个播飘分。另外并发击杀同一批鱼时每条鱼的结算状态要用一个全局自增ID做幂等避免同一条鱼既被炸弹结算又被另一颗子弹结算造成重复发放。6.3 性能优化对象池、视野剔除与合批捕鱼游戏的性能瓶颈几乎都在客户端渲染上。鱼多了、粒子特效多了、飘分多了低端机立刻掉帧。我常用的三板斧是对象池、视野剔除、动画合批。对象池是必须的。鱼、子弹、网、飘分数字、死亡特效全部用池化不Instantiate不Destroy。鱼池建议预热50~100个子弹池50个特效池30个。池化之后GC压力和耗时都大幅下降。视野剔除分两层2D用屏幕矩形裁剪跑到屏幕外的鱼直接休眠3D用视锥剔除加距离剔除镜头拉远时默认不渲染鱼身上的高模细节换成低模或直接取消失。动画合批则要求美术资源规范统一同一种鱼的骨骼动画尽量共用同一张图集、同一套材质这样合批率才上得去。最后说一个我自己的习惯上线前用自动化脚本连续模拟了一个小时高密度射击同时把客户端帧率、内存、服务器入账延迟全部打点统计生成一条“单位时间实际奖励/理论奖励”的曲线。如果这条曲线离配置值偏差超过5%我基本不会让版本出门。捕鱼游戏拼到最后比的就是这种细节上的稳定性。