【问题标题】:Calculate angle change after hitting a tilted wall计算撞到倾斜的墙壁后的角度变化
【发布时间】:2017-07-17 21:47:25
【问题描述】:

我正在用 javascript 制作一个游戏,其中一个对象应该从墙上反弹。我真的试图让它自己工作,但它永远无法正常工作。

假设有一个球在这个笼子里弹跳(蓝色 = 30°,棕色 = 60°);

球的坐标是已知的。运动的角度是已知的。碰撞点 (P) 坐标是已知的。墙的角度是已知的。球的位置正在使用这个函数在 setInterval 函数中更新它的坐标:

function findNewPoint(x, y, angle, distance) {
var result = {};

result.x =(Math.cos(angle * Math.PI / 180) * distance + x);
result.y = (Math.sin(angle * Math.PI / 180) * distance + y);

return result;

因此,在碰撞时,应该有一个函数可以正确改变球的角度。这似乎是一个非常复杂的问题,因为即使我知道墙壁是 30°,但知道球从哪一侧撞到墙壁上也很重要。我尝试使用“平面中的一条线的反射”公式以及一些向量,但它从未对我有用。我不期待代码的完整答案,如果有人可以建议应该以何种方式编程,它也会有所帮助。

编辑: 感谢您的提示,我意识到造成最大困惑的是什么;如果我用鼠标在画布上选择一个角度,则起始坐标(0,0)在左下角。但是由于画布的起始坐标在左上角,所以必须要考虑到这一点。

基本上使用这个公式来计算角度:

function angle(cx, cy, ex, ey) {
var dy = ey - cy;
var dx = ex - cx;
var theta = Math.atan2(dy, dx);
theta *= 180 / Math.PI; 
return theta;

}

如果球从 (50,50) 移动到 (100,100),则角度将为 -45。

现在,这个角度在撞墙时会发生以下变化:

老实说,我是通过反复试验得到的,我不太明白为什么正好是 60 和 120。

【问题讨论】:

  • 我知道您并没有要求这个,但是您是否考虑过使用 javascript 物理引擎?他们中有很多人会做这种事情。如果您有兴趣,有一个名为 (Phaser)[phaser.io/] 的游戏引擎非常简单,并且内置了物理引擎。如果您不想要这个,请随意忽略它:)
  • 谢谢,但这确实是我游戏中唯一的“物理”部分,我希望自己能够解决它,现在我已经用 node.js 做了太多了 :(。
  • 你能描述一下什么地方不能正常工作吗?此外,尝试简化您的问题,并从垂直墙或水平墙开始。反射角总是入射角。或者正如 Cyber​​chase 所说,入角 = 出角。这适用于 90 度和 0 度的墙壁。但是其他角度呢?想想如果你把整个图像旋转起来,让 30 度的墙变成 90 度的墙(垂直)会发生什么。球的角度会如何变化?
  • 我认为可能令人困惑的一件事是您说“蓝色是 30 度,棕色是 60 度”等等。如果您查看所有蓝色墙壁,法线(即球的角度会反映出来)是不同的。有些可能称为 30 度,有些可能称为 -30 度,具体取决于您测量的位置。弄清楚你是如何记录你的球角度的,并在墙上也小心地使用这个标准。
  • 有没有可能把它变成一个函数?目前,我只是在遇到不同的角落时将 if 语句用于不同的功能(如果您查看我编辑的帖子)。

标签: javascript math


【解决方案1】:

使用角度来移动球并一次又一次地计算Cos/Sin是不明智的。而是使用带有vx, vy 分量的单位速度方向向量,如下所示:

new_x = old_x + vx * Velocity_Magnitude * Time_Interval

请注意vx = Cos(angle), vy = Sin(angle),但使用方向方法,您很少需要使用三角函数。

角度为 Fi 的倾斜墙具有法线

nx = -Sin(Fi)
ny = Cos(Fi)

要找到反射,需要计算速度和法线的点积

dot = vx * nx + vy * ny

反射变换后的速度:

vnewx = v.x - 2 * dot * n.x 
vnewy = v.y - 2 * dot * n.y 

使用这些值进一步移动

(注意你可以同时使用内部和外部法线方向,因为方向翻转改变了两个分量,2 * dot * n.x 的符号保持不变)

例子:

horizontal moving right
vx=1, vy=0   
30 degrees wall has normal 
nx=-1/2, ny=Sqrt(3)/2  
dot = -1/2
vnewx = 1 - 2 * (-1/2) * (-1/2) = 1/2
vnewy = 0 - 2 * (-1/2) * Sqrt(3)/2 = Sqrt(3)/2
(velocity direction angle becomes 60 degrees)

horizontal moving left
vx=-1, vy=0   
330 degrees wall (left bottom corner) has normal 
nx=1/2, ny=Sqrt(3)/2  
dot = -1/2
vnewx = -1 - 2 * (-1/2) * (1/2) = -1/2
vnewy = 0 - 2 * (-1/2) * (Sqrt(3)/2) = Sqrt(3)/2
(velocity direction angle becomes 120 degrees)

【讨论】:

  • 谢谢,这正是我所需要的。虽然,对于左下角,我必须将其视为 30 度墙(不是 330),与右上角相同,而右下角 + 左上角是 330。我猜这是因为画布坐标系开始在左上角。
  • 好的。我删除了关于内部正常的句子 - 没有区别
【解决方案2】:

这是一个函数,它返回给定入射角和表面角(以度为单位)的反射角。它还确保返回的角度在 0 到 359 度之间。

function angleReflect(incidenceAngle, surfaceAngle){
  var a = surfaceAngle * 2 - incidenceAngle;
  return a >= 360 ? a - 360 : a < 0 ? a + 360 : a;
}

Here's a demonstration,其中蓝线是入射角,紫线是反射角,黑线是表面。

【讨论】:

    【解决方案3】:

    如果您假设球的行为就像从镜子反射的光,那么入射角等于反射角。

    因此,您的电路板与 0° 成 30°(笔直向上)。表示法线(在球击中点垂直于板)为 300°。假设球从 280° 到达,它必须在 320° 离开,因为入射角和法线之间的差值和反射角和法线之间的差必须相等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-30
      • 1970-01-01
      • 2015-08-03
      • 2012-07-19
      • 1970-01-01
      相关资源
      最近更新 更多