8 球台球:一杆击球背后的拖拽力度、碰撞物理与回合裁决
拆解这只 8 球台球的确定性设计:拖拽距离如何折叠成 18 档力度、全停统一结算如何保证规则可信、犯规与自由球如何维持回合公平,以及 AI 误差如何制造对局张力。文末附可试玩 demo。
玩法拆解
- 标准 8 球:16 颗球(母球 + 1-15 号),纯色 1-7 与条纹 9-15 两组,8 号球最后收
- 开球后首颗入袋球决定双方球组分配(groupsAssigned 由 null 写入)
- 犯规三态:母球落袋、空杆未碰球、先碰对方球 → 对手获得自由球,手动放置母球
- 清空己方组后合法打进 8 号获胜;提前进 8 或犯规进 8 直接判负
- 母球附近按下 → 拖拽决定方向与力度(拖拽距离映射 0-18 档)→ 松手击球
- 球体逐帧物理:球-球碰撞、库边反弹、入袋检测,全部停稳后统一结算
- 结算判定犯规 / 球组分配 / 入袋归属,决定续杆或换人;AI 思考 1-1.5 秒后自动回杆
- 任一方合法收掉 8 号 → result 弹出胜负,PLAY AGAIN 一键重开
- 8-ball/pool-model 单模块承载物理与规则:球态数组、碰撞/入袋检测、犯规判定、胜负与 AI 击球
- __OV.Games.EightBallPool.Game 场景私有渲染器:PIXI 绘制球台/球/球杆,把指针事件翻译成 shot.aim/drag/release
- 击球链路修过真实竞态:LogicGraph 异步执行,aiming 标志的重置必须让位到宏任务,否则真实拖拽永远打不出杆
- common-ui 管暂停/帮助按钮;状态机 boot → menu → gameplay ⇄ paused → result 由蓝图声明
关键代码
Demo
点击 Play 开局;在母球附近按住拖动瞄准、松手击球,拖拽越远力度越大;先清空己方球组再打进 8 号球获胜,AI 会自动应战。
文章
8 球台球:一杆击球背后的拖拽力度、碰撞物理与回合裁决
一句话本质
8 球台球(8-Ball Pool 重建版)是一个物理母型的完整对战样本:玩家与 AI 在标准球桌上轮流击球,每次击球被压缩成「按下瞄准 → 拖拽定力度 → 松手出杆」一个手势,之后的碰撞、入袋、犯规与胜负全部交给物理模拟和规则结算。它把台球最难做的两件事——手感与规则可信度——拆给了两个模块分别承担。
行为循环
- 开局:菜单点 Play,15 颗目标球三角摆位、母球置于开球线(25% 台宽)后,玩家执开球。
- 瞄准:在母球 4 倍球半径内按下开始瞄准,拖拽方向即击球方向,拖拽距离线性映射力度(150 逻辑像素拖满 18 档)。
- 击球:松手且力度大于 0.5 才出杆,初速度 = 力度 × 180,物理模拟启动。
- 结算:球-球碰撞、库边反弹、入袋检测逐帧进行,全部停稳后统一判定——犯规、球组分配、入袋归属、回合切换。
- 轮转:未分球组时首颗入袋球定组;进球合法则续杆,否则换 AI;AI 思考 1-1.5 秒后带误差回杆。
- 终盘:清空己方组后合法收 8 号获胜;提前进 8 或犯规进 8 判负。result 弹窗给出 🏆 / 😞,PLAY AGAIN 一键重开。
文末的 demo 可以直接试玩这个完整循环。
原语标注
AimStart(x, y)– 母球附近按下开始瞄准(shot.aim)AimDrag(dx, dy)– 拖拽更新角度与力度(shot.drag)Shoot(angle, power)– 松手出杆(shot.release → takeShot)SimulatePhysics()– 逐帧碰撞 / 反弹 / 入袋,直到全停SettleTurn()– 犯规判定、球组分配、回合切换(balls.stopped 触发)PlaceCueBall(x, y)– 自由球状态下手动放置母球(cueball.place)AiShoot()– AI 计算角度与力度自动回杆JudgeWinner()– 8 号球合法性裁决(game.over)
参数速查表
| 参数 | 说明 | 默认值 | 单位 | |------|------|--------|------| | 球台尺寸 | 逻辑台面宽 × 高 | 600 × 300 | 逻辑像素 | | 球半径 | 所有球统一 | 10 | 逻辑像素 | | 袋口数 | 四角袋 + 两中袋 | 6 | 个 | | 球数 | 母球 + 1–15 号 | 16 | 颗 | | 力度范围 | power | 0–18 | 档 | | 满力拖拽距离 | maxDrag | 150 | 逻辑像素 | | 出杆阈值 | 最低有效力度 | 0.5 | 档 | | 初速度映射 | speed = power × 180 | 最高 3240 | 逻辑像素/秒 | | 瞄准触发半径 | 按下点距母球上限 | 40(4 倍球半径) | 逻辑像素 | | 开球线 | 母球初始位置 | 25% 台宽 | – | | AI 思考时间 | 回杆前停顿 | 1–1.5 | 秒 |
设计取舍
- 拖拽方向即击球方向:真实球杆是「往后拉、往前打」,本作简化为「朝目标方向拖」——触屏上省掉一次方向反转的心智转换,代价是牺牲拉杆的拟真感。
- 力度由拖拽距离直接映射:不用蓄力条,短拖轻推、长拖爆杆,出杆没有等待;力度不足 0.5 视为取消,防误触。
- 全停统一结算替代逐球即时结算:所有球停稳后才判犯规、定归属、分胜负,规则只写一遍、顺序确定;代价是玩家必须等球停才能看到本杆评价,节奏上偏向「一杆一景」而非爽快连打。
- AI 带随机误差:AI 不做精确解算,瞄准加误差来模拟水平,让对局有来有回;当前只有单档强度,未暴露难度选择。
- 二级菜单收纳:主界面只留暂停与帮助两个按钮,音量滑块收进暂停菜单,球桌区域保持干净。
实现要点
- 状态机:boot → menu → gameplay ⇄ paused → result,迁移事件为 game.start / game.pause / game.resume / game.over / game.restart,由蓝图 stateMachine 声明。
- 事件流:
shot.aim→shot.drag→shot.release(力度 > 0.5 才发)→ pool-model.takeShot;球全停触发回合结算,currentPlayer = 2时 AI 自动回杆,形成完整轮转。 - 数据模型:balls(16 颗球的位置/速度/入袋态)+ currentPlayer / 双方球组与入袋清单 + foul / ballInHand / placingCueBall + aiming / power / aimAngle,约 20 个键撑起全场。
- 模块分工:8-ball/pool-model 单模块承载物理模拟、8 球规则与 AI 击球;
__OV.Games.EightBallPool.Game是场景私有渲染器——PIXI 画球台、球体与球杆,并把指针事件翻译成瞄准手势;common-ui 管暂停与帮助按钮。 - 一次真实竞态修复:LogicGraph 的事件处理是异步的,渲染模块若在 emit
shot.release后同步重置 aiming,规则的if (aiming == true)会被抢先判否,真实拖拽永远打不出杆;改为宏任务兜底重置后才打通。脚本直发事件的 e2e 测不出这类问题,只有真实指针输入能暴露。 - 运行时:PIXI 渲染 + v2-kernel 驱动 LogicGraph,整包导出为纯静态 demo,离线可玩;文末 iframe 即真实导出产物。
这一版的价值在于把「手感」和「规则」彻底解耦:手势只管产生角度与力度两个参数,物理与规则模块只看数据键——每层都可以单独替换或调参,而一杆击球的因果链始终清晰可验。
你可能也喜欢

拆解拉针解谜的惩罚机制与假难度设计。文章分析顺序错误如何触发直接重开,通过低容错率制造“看似难、实为假”的挑战体验,揭示利用规则逻辑而非复杂操作构建关卡的底层逻辑,为解谜游戏提供高价值策划参考。
拆解这只泡泡龙的确定性设计:角度如何被折叠成列选择、八向连通如何提高消除密度、每 10 发压顶如何把倒计时改成可计算的步数压力,以及悬空 20 分为什么是技巧上限。文末附可试玩 demo。
5 轮点球对决的规则骨架:瞄准角与力度被切成必偏区、风险区、甜区三段判定带,用概率裁决进球、被扑与射偏。文末附可试玩 demo。