logo

JavaScript台球算法解析:基于通用规则的碰撞模拟实现

作者:carzy2025.12.16 18:26浏览量:0

简介:本文深入探讨如何使用JavaScript实现台球物理模拟算法,结合行业常见的台球规则进行碰撞检测与运动计算。通过矢量运算、物理模型构建及可视化渲染,开发者可掌握台球游戏的核心技术逻辑,适用于网页游戏开发或物理引擎研究场景。

一、台球算法的核心物理模型

台球游戏的物理模拟需解决两个核心问题:球的碰撞检测运动轨迹计算。其物理模型基于经典力学中的动量守恒与能量守恒定律,同时需考虑摩擦力、旋转效应等次要因素。

1.1 碰撞检测的几何基础

台球碰撞分为球-球碰撞球-边界碰撞两类:

  • 球-球碰撞:检测两球中心距离是否小于半径之和。
    1. function checkBallCollision(ball1, ball2) {
    2. const dx = ball2.x - ball1.x;
    3. const dy = ball2.y - ball1.y;
    4. const distance = Math.sqrt(dx * dx + dy * dy);
    5. return distance < (ball1.radius + ball2.radius);
    6. }
  • 球-边界碰撞:检测球心到边界的垂直距离是否小于半径。
    1. function checkBoundaryCollision(ball, tableWidth, tableHeight) {
    2. const { x, y, radius } = ball;
    3. return x - radius < 0 || x + radius > tableWidth ||
    4. y - radius < 0 || y + radius > tableHeight;
    5. }

1.2 动量守恒与能量分配

碰撞后的速度计算需满足动量守恒与动能守恒(弹性碰撞)。简化模型中,假设质量相同且碰撞为正碰:

  • 速度交换:两球碰撞后沿接触面法线方向的速度分量互换。
  • 切向速度不变:沿接触面切线方向的速度分量保持不变。
  1. function resolveCollision(ball1, ball2) {
  2. const dx = ball2.x - ball1.x;
  3. const dy = ball2.y - ball1.y;
  4. const angle = Math.atan2(dy, dx);
  5. // 旋转坐标系到碰撞法线方向
  6. const v1n = ball1.vx * Math.cos(angle) + ball1.vy * Math.sin(angle);
  7. const v1t = -ball1.vx * Math.sin(angle) + ball1.vy * Math.cos(angle);
  8. const v2n = ball2.vx * Math.cos(angle) + ball2.vy * Math.sin(angle);
  9. const v2t = -ball2.vx * Math.sin(angle) + ball2.vy * Math.cos(angle);
  10. // 交换法向速度(弹性碰撞)
  11. [ball1.vx, ball2.vx] = [
  12. v2n * Math.cos(angle) - v1t * Math.sin(angle),
  13. v1n * Math.cos(angle) - v2t * Math.sin(angle)
  14. ];
  15. [ball1.vy, ball2.vy] = [
  16. v2n * Math.sin(angle) + v1t * Math.cos(angle),
  17. v1n * Math.sin(angle) + v2t * Math.cos(angle)
  18. ];
  19. }

二、行业常见台球规则的算法适配

不同台球规则(如8球、9球、斯诺克)对碰撞结果的影响主要体现在得分判定球状态管理上。以下以8球规则为例说明算法适配:

2.1 球组分类与击球顺序

  • 球组划分:1-7号为全色球,9-15号为半色球,8号为黑八。
  • 合法击球:每次击球需先碰撞己方球组,或直接击入黑八(决胜局)。
  1. class Ball {
  2. constructor(id, number, isSolid) {
  3. this.id = id;
  4. this.number = number;
  5. this.isSolid = isSolid; // true为全色,false为半色
  6. this.isPotted = false;
  7. }
  8. }
  9. function isValidShot(currentBall, targetBallGroup) {
  10. return currentBall.isSolid === targetBallGroup ||
  11. (currentBall.number === 8 && isFinalShot());
  12. }

2.2 犯规判定逻辑

常见犯规场景包括:

  • 白球落袋
  • 未碰撞己方球组
  • 击球后无球入袋且无球触边
  1. function checkFoul(whiteBall, touchedBalls, pottedBalls) {
  2. if (whiteBall.isPotted) return true; // 白球落袋
  3. if (touchedBalls.length === 0 && pottedBalls.length === 0) {
  4. return !checkAnyBallTouchedRail(whiteBall); // 无触边且无触球
  5. }
  6. return false;
  7. }

三、性能优化与可视化实现

3.1 空间分区加速碰撞检测

使用网格分区(Spatial Hashing)减少检测次数:

  1. class SpatialGrid {
  2. constructor(cellSize) {
  3. this.cellSize = cellSize;
  4. this.grid = new Map();
  5. }
  6. update(balls) {
  7. this.grid.clear();
  8. balls.forEach(ball => {
  9. const key = `${Math.floor(ball.x / this.cellSize)}_${Math.floor(ball.y / this.cellSize)}`;
  10. if (!this.grid.has(key)) this.grid.set(key, []);
  11. this.grid.get(key).push(ball);
  12. });
  13. }
  14. getNearbyBalls(ball) {
  15. const nearbyCells = [];
  16. const baseX = Math.floor(ball.x / this.cellSize);
  17. const baseY = Math.floor(ball.y / this.cellSize);
  18. for (let dx = -1; dx <= 1; dx++) {
  19. for (let dy = -1; dy <= 1; dy++) {
  20. const key = `${baseX + dx}_${baseY + dy}`;
  21. if (this.grid.has(key)) nearbyCells.push(...this.grid.get(key));
  22. }
  23. }
  24. return nearbyCells.filter(b => b !== ball);
  25. }
  26. }

3.2 Canvas渲染优化

使用离屏Canvas缓存静态元素(如台球桌纹理),减少主线程绘制开销:

  1. const offscreenCanvas = document.createElement('canvas');
  2. offscreenCanvas.width = 800;
  3. offscreenCanvas.height = 400;
  4. const ctx = offscreenCanvas.getContext('2d');
  5. // 预渲染台球桌
  6. function renderTable() {
  7. ctx.fillStyle = '#0a5f0a';
  8. ctx.fillRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
  9. // 绘制边界线、袋口等
  10. }
  11. // 主循环中合并绘制
  12. function render() {
  13. ctx.clearRect(0, 0, canvas.width, canvas.height);
  14. ctx.drawImage(offscreenCanvas, 0, 0);
  15. balls.forEach(ball => {
  16. ctx.beginPath();
  17. ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
  18. ctx.fillStyle = ball.isSolid ? '#000' : '#fff';
  19. ctx.fill();
  20. });
  21. }

四、实际应用中的注意事项

  1. 时间步长控制:固定时间步长(如16ms)避免不同设备上的物理模拟差异。
  2. 浮点数精度:使用整数坐标或定点数运算减少累积误差。
  3. 规则扩展性:通过策略模式实现不同台球规则的快速切换。
  1. class RuleEngine {
  2. constructor(ruleType) {
  3. this.rules = {
  4. '8ball': new EightBallRule(),
  5. '9ball': new NineBallRule()
  6. };
  7. this.currentRule = this.rules[ruleType];
  8. }
  9. checkScore(pottedBall) {
  10. return this.currentRule.checkScore(pottedBall);
  11. }
  12. }

通过结合精确的物理模型与灵活的规则适配,JavaScript可实现高效且符合行业标准的台球算法。开发者可根据实际需求调整碰撞精度、渲染效果或规则细节,适用于网页游戏、教育模拟或物理引擎研究等多种场景。

相关文章推荐

发表评论