canvas 踩坑 * 小球弹性碰撞逻辑解析

效果演示在这里插入图片描述

1.重叠检测

在这里插入图片描述
新生成的小球需要与数组中的每个小球进行判断是否重叠
判断依据:圆心距小于等于半径之和

2.碰撞检测

2.1 矢量分析

在这里插入图片描述
假设小球初速度方向为OA
经过碰撞以后它的速度为OA’
由于碰撞平面不是水平线,不方便计算,所以我们将整个球体模型沿碰撞平面旋转α角
旋转过后 OA --> OB OA’---->OB’
设OA = v
根据三角函数可得
x0 = v * cosα
y0 = v * sinβ
x1 = v * cos ( α + β)
= v * cosα * cosβ - v * sinα * sinβ
= x0 * cosα - y0 * sinα
y1 = v * sin ( α + β)
= v * sinα * cosβ + v * cosα + sinβ
= y0 * sinα + x0 * sinα

那么我们就可以获得 碰撞过后的速度
Vx’ = Vx * cosα- Vy * sinα
Vy’ = Vy * sinα+ Vx * sinα

    // 旋转向量
    function rotateVector(v, theta) {
   
        return {
   
            dx: v.dx * Math.cos(theta) - v.dy * Math.sin(theta),
            dy: v.dx * Math.cos(theta) + v.dy * Math.sin(theta)
        }
    }

2.2 旋转角度

现在我们需要计算的是旋转的 α 角度为多少
根据正切函数 tan α = y / x 可得 α = arctan * y /x
在Math函数中用 atan2 来计算,返回弧度,是指x轴距离点(y,x)与圆心连线的夹角
结果为正表示从X 轴逆时针旋转的角度
结果为负表示从X 轴顺时针旋转的角度
因为小球碰撞不外乎就两种情况

1.一低一高

在这里插入图片描述
向量等于终点坐标减去起始坐标
向量AB = (xa - xb,ya - yb)
tan θ = (ya-yb)/(xa-xb)
|θ| = arctan (ya-yb)/(xa-xb)
xa < xb ----> xa - xb <0
ya < yb ----> ya - yb <0
所以(ya-yb)/(xa-xb) > 0
由于碰撞平面是沿着顺指针方向旋转 -θ = atan2(y,x)
为了θ为正 进行取反
θ = -atan2(ya-yb)/(xa-xb)

2.一高一低

在这里插入图片描述
同理
xa < xb ----> xa - xb <0
ya > yb ----> ya - yb >0
所以(ya-yb)/(xa-xb) < 0
由于碰撞平面是沿着逆指针方向旋转 θ = - atan2(y,x)
所以
θ = -atan2(ya-yb)/(xa-xb)

然后我们就可以根据角度进行旋转

  let theta = -Math.atan2(p1.y - p2.y, p1.x - p2.x);

2.3 更新速度

根据动量守恒定律和动能定理我们有两个公式
在这里插入图片描述
将旋转过后的速度带入公式可得到新速度(旋转后)

在这里插入代码片

我们需要将新速度(旋转后)沿逆时针旋转α角,就可以获得小球
碰撞过后真正的速度

        // 完全弹性碰撞计算新的速度(旋转后的坐标)
        let v1RotatedAfterCollision = {
   
            dx: (v1Rotated.dx * (p1.mass - p2.mass) + 2 * p2.mass * v2Rotated.dx) / (p1.mass + p2.mass),
            dy: v1Rotated.dy
           
        };let v2RotatedAfterCollision = {
   
            dx: (v2Rotated.dx * (p2.mass - p1.mass) + 2 * p1.mass * v1Rotated.dx) / (p1.mass + p2.mass),
            dy: v2Rotated.dy
           
        };// 将新速度旋转回原来的角度获得真正的速度
        let v1finalCollision = rotateVector(v1RotatedAfterCollision,-theta);
        let v2finalCollision = rotateVector(v2RotatedAfterCollision,-theta);//更新小球的速度
        p1.dx = v1finalCollision.dx;
        p1.dy = v1finalCollision.dy;
        p2.dx = v2finalCollision.dx;
        p2.dy = v2finalCollision.dy;

2.4 修复漏洞
在这里插入图片描述
最后我们需要解决一个小bug
我们需要对碰撞检测进行一个优化
多个球黏在一起
原因:
两个小球碰撞的时候还没有分开,检测函数就已经执行了很多次,导致速度被更新了很多次
需要判断当两个小球靠近

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值