Javascript 圆/矩形碰撞响应

Javascript 圆/矩形碰撞响应,javascript,math,game-physics,Javascript,Math,Game Physics,所以我不久前构建了一个突破克隆,我想对它进行一点升级,主要是为了碰撞。当我第一次做的时候,我在我的球和砖块之间有一个基本的“碰撞”检测,它实际上将球视为另一个矩形。但这就产生了边碰撞的问题,所以我想我会改变它。问题是,我找到了一些问题的答案: 例如这张图片 这条线索的最后一条评论是:但是我找不到如何计算最终的速度向量 到目前为止,我已经: -在矩形上找到最近的点, -创建法线和切线向量 现在我需要的是“将速度向量分为法向分量和切线分量,求反法向分量,再加上法向分量和切线分量,得到新的速度向量”

所以我不久前构建了一个突破克隆,我想对它进行一点升级,主要是为了碰撞。当我第一次做的时候,我在我的球和砖块之间有一个基本的“碰撞”检测,它实际上将球视为另一个矩形。但这就产生了边碰撞的问题,所以我想我会改变它。问题是,我找到了一些问题的答案:

例如这张图片

这条线索的最后一条评论是:但是我找不到如何计算最终的速度向量

到目前为止,我已经:

-在矩形上找到最近的点
-创建法线和切线向量

现在我需要的是“将速度向量分为法向分量和切线分量,求反法向分量,再加上法向分量和切线分量,得到新的速度向量”如果这看起来非常简单,我很抱歉,但我无法集中注意力。。。 代码:

谢谢


编辑:也找到了,但我不知道它是否适用于矩形的所有点或仅适用于角。

最好用两个图表来解释:

入射角=反射角。称这个值为θ

θ=法向角-入射角

是用于计算向量相对于正x轴的角度的函数

下面的代码紧跟其后:

function collision(rect, circle){
  var NearestX = Max(rect.x, Min(circle.pos.x, rect.x + rect.w));
  var NearestY = Max(rect.y, Min(circle.pos.y, rect.y + rect.h));

  var dist = createVector(circle.pos.x - NearestX, circle.pos.y - NearestY);
  var dnormal = createVector(- dist.y, dist.x);

  var normal_angle = atan2(dnormal.y, dnormal.x);
  var incoming_angle = atan2(circle.vel.y, circle.vel.x);
  var theta = normal_angle - incoming_angle;
  circle.vel = circle.vel.rotate(2*theta);
}
另一种方法是得到沿切线的速度,然后从圆周速度中减去该值的两倍

然后代码变为

function collision(rect, circle){
  var NearestX = Max(rect.x, Min(circle.pos.x, rect.x + rect.w));
  var NearestY = Max(rect.y, Min(circle.pos.y, rect.y + rect.h));

  var dist = createVector(circle.pos.x - NearestX, circle.pos.y - NearestY);
  var tangent_vel = dist.normalize().dot(circle.vel);
  circle.vel = circle.vel.sub(tangent_vel.mult(2));
}
上面的两个代码段在大约相同的时间内(可能)做基本相同的事情。随便挑一个你最懂的

另外,正如@arbuthnott指出的,有一个复制粘贴错误,
NearestY
应该使用
rect.h
而不是
rect.w

编辑:我忘记了位置分辨率。这是将两个物理对象分开的过程,使它们不再相交。在这种情况下,由于块是静态的,我们只需要移动球

function collision(rect, circle){
  var NearestX = Max(rect.x, Min(circle.pos.x, rect.x + rect.w));
  var NearestY = Max(rect.y, Min(circle.pos.y, rect.y + rect.h));    
  var dist = createVector(circle.pos.x - NearestX, circle.pos.y - NearestY);

  if (circle.vel.dot(dist) < 0) { //if circle is moving toward the rect
    //update circle.vel using one of the above methods
  }

  var penetrationDepth = circle.r - dist.mag();
  var penetrationVector = dist.normalise().mult(penetrationDepth);
  circle.pos = circle.pos.sub(penetrationVector);
}

函数冲突(矩形、圆形){
var NearestX=最大值(矩形x,最小值(圆形位置x,矩形x+矩形w));
var NearestY=最大值(矩形y,最小值(圆形位置y,矩形y+矩形h));
var dist=createVector(圆位置x-最接近x,圆位置y-最接近y);
if(circle.vel.dot(dist)<0){//如果圆正在向矩形移动
//使用上述方法之一更新circle.vel
}
变量穿透深度=圆r-距离磁();
var percentrationvector=dist.normalise().mult(穿透深度);
circle.pos=circle.pos.sub(穿透向量);
}
Bat和Ball碰撞 处理球和矩形碰撞的最佳方法是利用系统的对称性

把球当作一分。 首先是球,它有一个半径
r
,该半径定义了距离中心的所有点
r
。但是我们可以把球变成一个点,在矩形上加上半径。球现在只是一个随着时间移动的单点,这是一条线

矩形的所有边都以半径增长。图中显示了这是如何工作的

绿色矩形是原始矩形。球A、B不接触矩形,而球C、D接触矩形。球A,D代表一种特殊情况,但正如您将看到的,很容易解决

所有运动都是直线。 所以现在我们有一个更大的矩形和一个球作为一个点随时间移动(一条线),但矩形也在移动,这意味着随着时间的推移,边缘将扫出对我的大脑来说太复杂的区域,所以我们可以再次使用对称性,这次是相对运动

从球拍的角度看,球移动时它是静止的,从球的角度看,球拍移动时它是静止的。他们都看到对方朝相反的方向移动

由于球现在是一个点,对其运动进行更改只会更改它所沿的直线。所以我们现在可以在空间中固定球棒,并从球中减去它的运动。现在球棒固定了,我们可以把它的中心点移到原点,(0,0),然后把球移到相反的方向

在这一点上,我们做了一个重要的假设。球和球棒始终处于不接触状态,当我们移动球和/或球棒时,它们可能会接触。如果它们确实接触了,我们计算出一条新的轨迹,这样它们就不会接触了

两种可能的碰撞 现在有两种可能的碰撞情况,一种是球撞到球棒侧面,另一种是球撞到球棒角

接下来的图像显示了球棒在原点的位置,以及球在运动和位置上相对于球棒的位置。它沿着红线从A移动到B,然后反弹到C

球击中边缘

球打到角落

因为这里也有对称性,哪边或哪角被击中没有任何区别。事实上,我们可以根据球离球棒中心的大小来反映整个问题。因此,如果球在球棒的左侧,则在x方向镜像其位置和运动,在y方向镜像其位置和运动(您必须通过信号灯跟踪此镜像,以便在找到解决方案后将其反转)

代码 该示例执行上述函数
doBatBall(bat,ball)
中所述的操作。球具有一定的重力,会从画布的侧面反弹。蝙蝠通过鼠标移动。球棒的运动会转移到球上,但球棒不会感觉到来自球的任何力量

function collision(rect, circle){
  var NearestX = Max(rect.x, Min(circle.pos.x, rect.x + rect.w));
  var NearestY = Max(rect.y, Min(circle.pos.y, rect.y + rect.h));    
  var dist = createVector(circle.pos.x - NearestX, circle.pos.y - NearestY);

  if (circle.vel.dot(dist) < 0) { //if circle is moving toward the rect
    //update circle.vel using one of the above methods
  }

  var penetrationDepth = circle.r - dist.mag();
  var penetrationVector = dist.normalise().mult(penetrationDepth);
  circle.pos = circle.pos.sub(penetrationVector);
}
const ctx=canvas.getContext(“2d”);
常量鼠标={x:0,y:0,按钮:false}
功能鼠标事件(e){
mouse.x=e.pageX;
mouse.y=e.pageY;
mouse.button=e.type==“mousedown”?true:e.type==“mouseup”