如何反弹两个运动物体

时间:2019-05-25 00:48:46

标签: android game-physics

我正在使用Bully的街机制作ConSumo游戏。基本上,有一个敌人摔跤手成一直线,如果相撞就会反弹玩家。当与敌方摔跤手相撞时,我似乎无法弄清楚弹跳玩家的角度。

我尝试使用(player.centerY-敌人.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));

我试图让玩家以相同的角度弹回(我知道这不是理想的结果,但是我至少想先抓住它,如果您可以提出更好的方法,我将不胜感激),但它仅在碰撞的一侧或两侧起作用,而另一侧似乎将玩家拉过敌人,而不是将其弹跳回来。

1 个答案:

答案 0 :(得分:0)

也许您可以尝试考虑脉冲守恒和能量守恒的物理方法。

基本上,质量为mp的玩家的速度为[vp; 0],质量为me的敌人的速度为[ve; 0]。因此,没有y组件,因为它们仅水平移动。现在,在发生冲突时t = t_col,假设玩家的质心具有坐标[xp, yp],而敌人的质心具有坐标[xe, ye](您可以随时对其进行调整以确保存在如果需要,可以通过使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分量将为正(因此没有差异),而对于另一个对象将为负。对于负数,我们还可以添加一个事实,即物体在碰撞后可能会立即从地面反弹(因此先与物体碰撞然后与地面碰撞)。因此,我们使用反射定律,有点像镜子反射光的方式。

碰撞后,在时间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是敌人的角度。