如何反弹两个移动的物体
How to bounce two moving objects
我正在 Bully 的街机上制作 ConSumo 游戏。基本上有一个直线移动的敌方摔跤手,如果发生碰撞会弹回玩家。我似乎无法弄清楚在与敌方摔跤手发生碰撞时弹起玩家的角度逻辑。
我尝试使用 (player.centerY - enemy.centerY)/(player.centerX - player.centerY) 的反正切值计算碰撞角度,然后加上 180 度来镜像角度。
double angle = Math.atan(((player.getCenterY() - enemies[i].getCenterY())/ (player.getCenterX() - enemies[i].getCenterX())));
angle = Math.toDegrees(angle);
angle += 180;
angle = Math.toRadians(angle);
player.addX(Math.cos(Angle) * strength);
plyaer.addY(-(Math.sin(angle) * strength));
我试图让玩家以相同的角度反弹(我知道这不是理想的结果,但我想至少先掌握它的窍门,如果你能提出更好的方法,我会很感激)但它只对碰撞的一侧或两侧有效,而另一侧似乎将玩家拉过敌人而不是将其弹回。
也许你可以试试考虑冲量守恒和能量守恒的物理方法。
基本上,质量为 mp
的玩家的速度为 [vp; 0]
,而质量为 me
的敌人的速度为 [ve; 0]
。所以没有 y 分量,因为它们只水平移动。现在在碰撞时 t = t_col
假设玩家的质心坐标为 [xp, yp]
并且敌人的质心坐标为 [xe, ye]
(您可以随时调整它们以确保有更大的 bouncing-off 效果,如果您愿意,可以使 y 坐标更加不同)。
动量守恒告诉我们碰撞后两个物体的速度,称为[Vp, Wp]
和[Ve, We]
,计算如下
[Vp; Wp] = [vp; 0] + (1/mp)*[I1; I2];
[Ve; We] = [ve; 0] - (1/me)*[I1; I2];
其中,通常假设撞击垂直于物体表面,矢量 [I1; I2]
可以与连接两个中心的矢量对齐:[xp - xe; yp - ye]
。将此信息与能量守恒相结合,可以计算出所述矢量的大小并发现
k = (mp*me/(mp+me)) * (vp - ve)*(xp - xe) / ((xp - xe)^2 + (yp - ye)^2);
I1 = k*(xp - xe);
I2 = k*(yp - ye);
所以基本上,在碰撞时你有作为输入:
- 玩家的位置和速度:
[xp; yp], [vp; 0]
- 敌人的位置和速度:
[xe; ye], [ve; 0]
- 玩家的质量
mp
和敌人的质量me
然后计算
k = (mp*me/(mp+me)) * (vp - ve)*(xp - xe) / ((xp - xe)^2 + (yp - ye)^2);
I1 = k*(xp - xe);
I2 = k*(yp - ye);
Vp = vp + (1/mp)*I1;
Wp = (1/mp)*abs(I2);
Ve = ve - (1/me)*I1;
We = (1/me)*abs(I2);
请注意,我使用了 abs(I2)
,这是 I2
的绝对值。这是因为对于两个物体之一,碰撞后速度的 y-component 将为正(因此没有差异),但对于另一个物体将为负。对于消极的,我们还可以添加一个事实,即物体在碰撞后可能会立即弹离地面(因此与物体碰撞然后与地面碰撞)。所以我们使用反射定律,有点像光被镜子反射的方式。
碰撞后,在时间 t = t_col
两个玩家的抛物线轨迹(在他们回到地面之前)将是
xp(t) = xp + Vp * (t - t_col);
yp(t) = yp + Wp * (t - t_col) - (g/2) * (t - t_col)^2;
xe(t) = xe + Ve * (t - t_col);
ye(t) = ye + We * (t - t_col) - (g/2) * (t - t_col)^2;
如果你想要角度:
cos(angle_p) = Vp / (Vp^2 + Wp^2);
sin(angle_p) = Wp / (Vp^2 + Wp^2);
cos(angle_e) = Ve / (Ve^2 + We^2);
sin(angle_e) = We / (Ve^2 + We^2);
其中angle_p
是玩家的角度,angle_e
是敌人的角度。
我正在 Bully 的街机上制作 ConSumo 游戏。基本上有一个直线移动的敌方摔跤手,如果发生碰撞会弹回玩家。我似乎无法弄清楚在与敌方摔跤手发生碰撞时弹起玩家的角度逻辑。
我尝试使用 (player.centerY - enemy.centerY)/(player.centerX - player.centerY) 的反正切值计算碰撞角度,然后加上 180 度来镜像角度。
double angle = Math.atan(((player.getCenterY() - enemies[i].getCenterY())/ (player.getCenterX() - enemies[i].getCenterX())));
angle = Math.toDegrees(angle);
angle += 180;
angle = Math.toRadians(angle);
player.addX(Math.cos(Angle) * strength);
plyaer.addY(-(Math.sin(angle) * strength));
我试图让玩家以相同的角度反弹(我知道这不是理想的结果,但我想至少先掌握它的窍门,如果你能提出更好的方法,我会很感激)但它只对碰撞的一侧或两侧有效,而另一侧似乎将玩家拉过敌人而不是将其弹回。
也许你可以试试考虑冲量守恒和能量守恒的物理方法。
基本上,质量为 mp
的玩家的速度为 [vp; 0]
,而质量为 me
的敌人的速度为 [ve; 0]
。所以没有 y 分量,因为它们只水平移动。现在在碰撞时 t = t_col
假设玩家的质心坐标为 [xp, yp]
并且敌人的质心坐标为 [xe, ye]
(您可以随时调整它们以确保有更大的 bouncing-off 效果,如果您愿意,可以使 y 坐标更加不同)。
动量守恒告诉我们碰撞后两个物体的速度,称为[Vp, Wp]
和[Ve, We]
,计算如下
[Vp; Wp] = [vp; 0] + (1/mp)*[I1; I2];
[Ve; We] = [ve; 0] - (1/me)*[I1; I2];
其中,通常假设撞击垂直于物体表面,矢量 [I1; I2]
可以与连接两个中心的矢量对齐:[xp - xe; yp - ye]
。将此信息与能量守恒相结合,可以计算出所述矢量的大小并发现
k = (mp*me/(mp+me)) * (vp - ve)*(xp - xe) / ((xp - xe)^2 + (yp - ye)^2);
I1 = k*(xp - xe);
I2 = k*(yp - ye);
所以基本上,在碰撞时你有作为输入:
- 玩家的位置和速度:
[xp; yp], [vp; 0]
- 敌人的位置和速度:
[xe; ye], [ve; 0]
- 玩家的质量
mp
和敌人的质量me
然后计算
k = (mp*me/(mp+me)) * (vp - ve)*(xp - xe) / ((xp - xe)^2 + (yp - ye)^2);
I1 = k*(xp - xe);
I2 = k*(yp - ye);
Vp = vp + (1/mp)*I1;
Wp = (1/mp)*abs(I2);
Ve = ve - (1/me)*I1;
We = (1/me)*abs(I2);
请注意,我使用了 abs(I2)
,这是 I2
的绝对值。这是因为对于两个物体之一,碰撞后速度的 y-component 将为正(因此没有差异),但对于另一个物体将为负。对于消极的,我们还可以添加一个事实,即物体在碰撞后可能会立即弹离地面(因此与物体碰撞然后与地面碰撞)。所以我们使用反射定律,有点像光被镜子反射的方式。
碰撞后,在时间 t = t_col
两个玩家的抛物线轨迹(在他们回到地面之前)将是
xp(t) = xp + Vp * (t - t_col);
yp(t) = yp + Wp * (t - t_col) - (g/2) * (t - t_col)^2;
xe(t) = xe + Ve * (t - t_col);
ye(t) = ye + We * (t - t_col) - (g/2) * (t - t_col)^2;
如果你想要角度:
cos(angle_p) = Vp / (Vp^2 + Wp^2);
sin(angle_p) = Wp / (Vp^2 + Wp^2);
cos(angle_e) = Ve / (Ve^2 + We^2);
sin(angle_e) = We / (Ve^2 + We^2);
其中angle_p
是玩家的角度,angle_e
是敌人的角度。