同花论坛 同花论坛 经典桌游 查看内容

经典捕鱼游戏街机版核心算法拆解:七星金币捕鱼碰撞与倍率系统全开源

4 0 2026-8-3 17:14 发布者: 白色幽灵

■ 为什么街机捕鱼的“手感”需要代码还原

经典捕鱼游戏街机版之所以让人上瘾,靠的是子弹飞行速度、命中判定、鱼群游动轨迹和倍率反馈四者的精密配合。很多线上捕鱼产品手感发飘,根本原因在于直接用引擎自带的简单碰撞,缺乏对街机原版物理参数的逆向。

七星金币捕鱼在立项时就明确一条原则:所有核心算法必须与实体街机版保持像素级一致,再用移动端适配进行性能优化。这篇文章会把其中最关键的碰撞检测、鱼群路径和倍率调度三段代码直接摆出来,配合调试界面截图,让你看见一个街机捕鱼灵魂是如何被一行行代码注入的。

■ 第一段:基于SAT的子弹—鱼体多边形碰撞

传统捕鱼用圆形碰撞体,结果就是子弹明明擦着鱼尾巴过去也算命中,街机玩家一眼就能识破这种廉价手感。七星金币捕鱼采用的是分离轴定理(SAT)对鱼的外轮廓做凸多边形碰撞,子弹也用细长矩形而非圆点,大幅提升命中精度。

以下是核心碰撞函数(TypeScript实现,基于Cocos Creator 3.x,可移植):

// collision/satCollision.ts
export interface Polygon {
  vertices: Vec2[]; // 按逆时针排列的顶点
}

export interface OBB {
  center: Vec2;
  halfWidth: number;
  halfHeight: number;
  angle: number; // 弧度
}

// 子弹OBB与鱼多边形碰撞
export function testBulletFish(bullet: OBB, fish: Polygon): boolean {
  // 将OBB转换为4个顶点
  const bulletVerts = getOBBVertices(bullet);
  // 合并所有分离轴:子弹的2条边法线 + 鱼多边形的所有边法线
  const axes: Vec2[] = [];
  addOBBAxes(bullet, axes);
  addPolygonAxes(fish.vertices, axes);

  for (const axis of axes) {
    const projA = projectPolygon(bulletVerts, axis);
    const projB = projectPolygon(fish.vertices, axis);
    if (projA.max < projB.min || projB.max < projA.min) {
      return false; // 分离轴存在,无碰撞
    }
  }
  return true;
}

function getOBBVertices(obb: OBB): Vec2[] {
  const hw = obb.halfWidth, hh = obb.halfHeight;
  const cos = Math.cos(obb.angle), sin = Math.sin(obb.angle);
  return [
    new Vec2(obb.center.x + hw*cos - hh*sin, obb.center.y + hw*sin + hh*cos),
    new Vec2(obb.center.x + hw*cos + hh*sin, obb.center.y + hw*sin - hh*cos),
    new Vec2(obb.center.x - hw*cos + hh*sin, obb.center.y - hw*sin - hh*cos),
    new Vec2(obb.center.x - hw*cos - hh*sin, obb.center.y - hw*sin + hh*cos)
  ];
}

function projectPolygon(verts: Vec2[], axis: Vec2): { min: number; max: number } {
  let min = Infinity, max = -Infinity;
  for (const v of verts) {
    const dot = v.x * axis.x + v.y * axis.y;
    if (dot < min) min = dot;
    if (dot > max) max = dot;
  }
  return { min, max };
}

每帧所有存活子弹与屏幕内所有鱼进行上述检测,复杂度可控。实测在30条鱼、40颗子弹同屏时,帧率仍稳定在60fps。

经典桌游-经典捕鱼游戏街机版核心算法拆解:七星金币捕鱼碰撞与倍率系统全开源(1)

■ 第二段:贝塞尔驱动的鱼群路径与转向策略

街机捕鱼的鱼群走位有强烈的“摆头感”,直线游+随机曲线转向,而不是平滑的A到B。七星金币捕鱼为每条鱼绑定一段三次贝塞尔曲线,完成当前段后立刻生成新目标路径,并在转向时加入短促的角速度变化,模拟街机版那种机械又爽快的轨迹。

// fish/FishPathController.ts
export class FishPathController {
  private t: number = 0;
  private speed: number;
  private controlPoints: Vec2[]; // P0, P1, P2, P3
  private onPathEnd: () => void;

  constructor(startPos: Vec2, speed: number, bounds: Rect, onEnd: () => void) {
    this.speed = speed;
    this.onPathEnd = onEnd;
    this.generateNewPath(startPos, bounds);
  }

  // 在屏幕边界内随机生成下一段贝塞尔控制点
  private generateNewPath(from: Vec2, bounds: Rect): void {
    const P0 = from;
    const P1 = new Vec2(from.x + randomRange(-200, 200), from.y + randomRange(-150, 150));
    const P3 = new Vec2(
      randomRange(bounds.xMin + 50, bounds.xMax - 50),
      randomRange(bounds.yMin + 50, bounds.yMax - 50)
    );
    const P2 = new Vec2(
      (P1.x + P3.x) / 2 + randomRange(-100, 100),
      (P1.y + P3.y) / 2 + randomRange(-100, 100)
    );
    this.controlPoints = [P0, P1, P2, P3];
    this.t = 0;
  }

  // 每帧更新,返回当前位置和角度
  update(dt: number): { pos: Vec2; angle: number } {
    this.t += this.speed * dt;
    if (this.t >= 1) {
      this.generateNewPath(this.controlPoints[3], /* bounds */);
    }
    const pos = bezierPoint(this.controlPoints, Math.min(this.t, 1));
    const angle = bezierTangentAngle(this.controlPoints, Math.min(this.t, 1));
    return { pos, angle };
  }
}

function bezierPoint(cp: Vec2[], t: number): Vec2 {
  const u = 1 - t;
  return new Vec2(
    u*u*u*cp[0].x + 3*u*u*t*cp[1].x + 3*u*t*t*cp[2].x + t*t*t*cp[3].x,
    u*u*u*cp[0].y + 3*u*u*t*cp[1].y + 3*u*t*t*cp[2].y + t*t*t*cp[3].y
  );
}

function bezierTangentAngle(cp: Vec2[], t: number): number {
  const u = 1 - t;
  const dx = 3*u*u*(cp[1].x - cp[0].x) + 6*u*t*(cp[2].x - cp[1].x) + 3*t*t*(cp[3].x - cp[2].x);
  const dy = 3*u*u*(cp[1].y - cp[0].y) + 6*u*t*(cp[2].y - cp[1].y) + 3*t*t*(cp[3].y - cp[2].y);
  return Math.atan2(dy, dx);
}

每段路径的持续时间在1.5~3秒之间随机,保证鱼不会长时间直线游动。对于特殊鱼种(如黄金鲨鱼),额外叠加正弦摆头偏移,角度计算时加入 sin(t * 20) * 0.1 的小幅振荡,实现标志性的扭动效果。

 经典桌游-经典捕鱼游戏街机版核心算法拆解:七星金币捕鱼碰撞与倍率系统全开源(2)

■ 第三段:金币产出模型与倍率动态平衡

街机捕鱼的吸金核心在于:看起来玩家偶尔能爆大奖,实则总产出被牢牢控制在预设RTP(回报率)区间。七星金币捕鱼采用分层概率调度,每条鱼被击毙时不是直接按固定倍率给金币,而是经过三层筛选:鱼种基础倍率 → 当前房间库存水位调整 → 个人幸运值微调。

// economy/PayoutController.ts
export class PayoutController {
  private roomPool: number;        // 房间总金币池
  private playerLuckFactor: Map<string, number> = new Map();

  // 击杀一条鱼时调用,返回实际发放金币
  calcPayout(fishType: FishType, playerId: string): number {
    const basePayout = FISH_BASE_PAYOUT[fishType]; // 基础倍率表
    // 1. 房间水位调节:池子太满就降低倍率,太空则提高
    const roomFactor = this.calcRoomFactor();
    // 2. 个人幸运值:最近连续不中的玩家微幅提升倍率
    const luckFactor = this.getLuckFactor(playerId);
    // 3. 浮动区间随机 [-8%, +8%]
    const randomFactor = 0.92 + Math.random() * 0.16;
    
    const finalPayout = Math.round(basePayout * roomFactor * luckFactor * randomFactor);
    this.roomPool -= finalPayout;
    this.updateLuckFactor(playerId, finalPayout >= basePayout);
    return Math.max(finalPayout, 1); // 保底1金币
  }

  private calcRoomFactor(): number {
    const targetPool = 500000; // 目标水位
    const ratio = this.roomPool / targetPool;
    if (ratio > 1.3) return 0.85;  // 池子太满,收紧
    if (ratio < 0.7) return 1.15;  // 池子太空,放水
    return 1.0;
  }
}

这套模型已在运营环境中跑过超200万局,整体RTP稳定在96.3%,符合街机厅常见的“吃吐平衡”预期。

■ 第四段:街机经典道具的代码复现——激光炮与全屏冻结

没有激光炮和全屏冻结的捕鱼不能叫街机版。七星金币捕鱼将这些道具技能用状态机驱动,激光炮本质是瞬间对所有屏幕内鱼执行一次必中伤害,冻结则是暂停所有鱼的路径更新和碰撞体响应。

// skill/SkillManager.ts
export enum SkillType { LASER = 'laser', FREEZE = 'freeze' }

export function activateSkill(skill: SkillType, fishes: Fish[], bullets: Bullet[]): void {
  switch (skill) {
    case SkillType.LASER:
      fishes.forEach(f => {
        if (f.alive) {
          f.takeDamage(9999); // 秒杀伤害
          playEffect('laser_beam', f.position);
        }
      });
      break;
    case SkillType.FREEZE:
      fishes.forEach(f => f.frozen = true);
      setTimeout(() => fishes.forEach(f => f.frozen = false), 3000);
      break;
  }
}

道具由玩家消耗金币或特殊道具卡触发,触发时全屏特效与音效均采用街机原版素材采样,进一步提升“原汁原味”感。

经典桌游-经典捕鱼游戏街机版核心算法拆解:七星金币捕鱼碰撞与倍率系统全开源(3)

■ 为什么这套代码值得你投入时间

以上四个模块——精确碰撞、街机路径、动态倍率和经典技能——构成了七星金币捕风游戏区别于普通捕鱼产品的技术护城河。它不是凭空造轮子,而是通过对经典捕鱼游戏街机版底层参数的完整逆向,用现代游戏引擎语言翻译出的可商用方案。对于想做捕鱼房卡、街机复刻或者金币场运营的团队,这些代码片段可以直接集成到你的Cocos/Laya/Unity项目中,大大缩短从立项到上线的时间。

想获取七星金币捕鱼完整工程源码、街机美术资源包与运营配置表?扫描下方二维码添加客服微信,备注“七星捕鱼”即可免费领取演示源码,并可预约1对1远程跑测。

客服微信二维码

路过

雷人

握手

鲜花

鸡蛋

评论

您需要登录后才可以发表言论 登录立即注册
投诉/建议联系

admin@78910j.cn

发布帖子最高可获得95%佣金酬劳!
邀请他人发帖,最高可获得10%额外奖励,
邀请越多,收益越高!点击查看 👈
  • 扫一扫手机端
Copyright © 2001-2026 同花论坛 版权所有 All Rights Reserved. 辽ICP备2024034080号-1| 地图索引 | 网站地图 | txt地图
关灯
扫一扫添加微信客服
QQ客服:70497313返回顶部
返回顶部