You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

2D Elastic Collision:y方向momentum不守恒及垂直碰撞问题求助

2D弹性碰撞模型垂直碰撞失效问题修复

问题描述

我是一名高中生,正在构建两个台球的2D弹性碰撞模型,采用向量旋转方法实现,但遇到了问题:当两球x值相同(垂直碰撞)时,碰撞逻辑失效。排查发现碰撞向量越趋近于垂直,y方向动量变化量就越大,而理论上该变化量应为0,x方向动量则无此问题。

问题根源

代码中旋转回原坐标系时的计算顺序错误:在计算v1y时,已经修改了v1x的值,导致v1y使用了更新后的v1x而非原始旋转后的v1x,垂直碰撞时这个误差被放大,直接导致动量不守恒。

修复方案

  • 修正旋转回原坐标系的计算逻辑
    在旋转回原坐标系时,先保存原始的旋转后速度值,避免计算过程中变量被覆盖:

    # 替换原旋转回代码
    # 先保存旋转后的原始值
    rot_v1x = v1x
    rot_v1y = v1y
    rot_v2x = v2x
    rot_v2y = v2y
    
    # 重新计算旋转回后的速度
    v1x = rot_v1x * cos(angle) - rot_v1y * sin(angle)
    v1y = rot_v1y * cos(angle) + rot_v1x * sin(angle)
    v2x = rot_v2x * cos(angle) - rot_v2y * sin(angle)
    v2y = rot_v2y * cos(angle) + rot_v2x * sin(angle)
    
  • 优化碰撞检测与位置修正
    原位置修正逻辑可能导致球重叠或位置偏移,建议改为基于碰撞方向的分离:

    # 替换原位置修正代码
    # 计算碰撞方向单位向量
    dist = ((b2.x - b1.x)**2 + (b2.y - b1.y)**2)**0.5
    overlap = 2*r - dist
    dir_x = (b2.x - b1.x)/dist
    dir_y = (b2.y - b1.y)/dist
    
    # 分离两球,避免持续触发碰撞
    b1.x -= dir_x * overlap/2
    b1.y -= dir_y * overlap/2
    b2.x += dir_x * overlap/2
    b2.y += dir_y * overlap/2
    
  • 完整修正后的BallCollision函数

    def BallCollision(b1, b2, u1, u2):
        deltaX = b2.x - b1.x
        deltaY = b2.y - b1.y
    
        angle = atan2(deltaY, deltaX)
    
        # 旋转速度到碰撞坐标系
        u1x = b1.vx * cos(angle) + b1.vy * sin(angle)
        u1y = b1.vy * cos(angle) - b1.vx * sin(angle)
        u2x = b2.vx * cos(angle) + b2.vy * sin(angle)
        u2y = b2.vy * cos(angle) - b2.vx * sin(angle)
    
        # 计算弹性碰撞后的速度(碰撞坐标系)
        v1x = ((b1.m - b2.m) / (b1.m + b2.m)) * u1x + ((2 * b2.m) / (b1.m + b2.m)) * u2x
        v1y = u1y
        v2x = ((2 * b1.m) / (b1.m + b2.m)) * u1x + ((b2.m - b1.m) / (b1.m + b2.m)) * u2x
        v2y = u2y
    
        # 分离重叠的球
        dist = ((b2.x - b1.x)**2 + (b2.y - b1.y)**2)**0.5
        overlap = 2*r - dist
        if overlap > 0:
            dir_x = (b2.x - b1.x)/dist
            dir_y = (b2.y - b1.y)/dist
            b1.x -= dir_x * overlap/2
            b1.y -= dir_y * overlap/2
            b2.x += dir_x * overlap/2
            b2.y += dir_y * overlap/2
    
        # 旋转回原坐标系(使用临时变量避免覆盖)
        rot_v1x, rot_v1y = v1x, v1y
        rot_v2x, rot_v2y = v2x, v2y
        v1x = rot_v1x * cos(angle) - rot_v1y * sin(angle)
        v1y = rot_v1y * cos(angle) + rot_v1x * sin(angle)
        v2x = rot_v2x * cos(angle) - rot_v2y * sin(angle)
        v2y = rot_v2y * cos(angle) + rot_v2x * sin(angle)
    
        # 验证动量守恒
        print("x方向动量变化: ", b1.m*b1.vx + b2.m*b2.vx - b1.m*v1x - b2.m*v2x)
        print("y方向动量变化: ", b1.m*b1.vy + b2.m*b2.vy - b1.m*v1y - b2.m*v2y)
    
        b1.vx, b1.vy = v1x, v1y
        b2.vx, b2.vy = v2x, v2y
    

额外建议

  • 动量计算时要乘以质量,原代码未考虑质量,导致验证结果不准确
  • 避免在motion函数中每次都调用checkCollision,建议在主循环中统一检测碰撞,减少重复计算
  • 可以添加边界碰撞检测,让球在窗口内反弹,增强模拟真实性

内容的提问来源于stack exchange,提问作者Thomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 16:30:47