如何有效地计算将在盒子中移动并在其墙壁上弹跳(2D)的点的未来位置?
How to efficiently compute the future position of a point that will move in a box and bounce on its walls (2D)?
我这里有一个简单的 maths/physics 问题:在笛卡尔坐标系中,我有一个以已知速度随时间移动的点。该点位于一个盒子内,并在其壁上正交反弹。
这是我在绘画上做的一个简单示例:
我们所知道的:红点位置,以及由角度 θ 和速度定义的速度。我们当然知道绿盒子的尺寸。
在例子中,我用黄色画出了它的大概轨迹,假设经过一段已知的确定时间后,红点在蓝点上。计算蓝点位置的最有效方法是什么?
我一直在努力用三角函数和矢量投影计算每个“反弹点”,但我觉得这是一种资源浪费,因为三角函数通常非常耗费处理器资源。我将有超过一千个点需要这样计算,所以我真的需要找到一种更有效的方法。
如果有人有任何想法,我将不胜感激。
你不需要一直使用三角函数。取而代之的是将归一化方向向量作为 (dx, dy) = (cos(θ), sin(θ))
从垂直墙反弹后,x 分量改变了它的符号 dx = -dx
,从水平墙反弹后,y 分量改变了它的符号 dy = -dy
。你可以看到计算非常简单。
如果您(出于奇怪的原因)更喜欢使用角度,请使用角度变换(对于非零半径的球)
if ((ball.x + ball.radius) >= window.width || (ball.x - ball.radius) <= 0)
ball.theta = M_PI - ball.theta;
else
if ((ball.y + ball.radius) >= window.height || (ball.y - ball.radius) <= 0)
ball.theta = - ball.theta;
获得弹跳点:
Starting point (X0, Y0)
Ray angle Theta, c = Cos(Theta), s = Sin(Theta);
Rectangle coordinates: bottom left (X1,Y1), top right (X2,Y2)
if c >= 0 then //up
XX = X2
else
XX = X1
if s >= 0 then //right
YY = Y2
else
YY = Y1
if c = 0 then //vertical ray
return Intersection = (X0, YY)
if s = 0 then //horizontal ray
return Intersection = (XX, Y0)
tx = (XX - X0) / c //parameter when vertical edge is met
ty = (YY - Y0) / s //parameter when horizontal edge is met
if tx <= ty then //vertical first
return Intersection = (XX, Y0 + tx * s)
else //horizontal first
return Intersection = (X0 + ty * c, YY)
除了编程方面的考虑,从几何角度来看,它还有一个有趣的解决方案。可以在不考虑0<t<T
期间的时间轨迹的情况下,找到特定时间T
的点的位置
一分钟,忘记盒子的大小和边界;并假设该点可以永远沿直线移动。然后该点具有恒定速度分量 vx = v*cos(θ), vy = v*sin(θ)
并且在时间 T
其 虚拟 部分将是 x' = x0 + vx * T, y' = y0 + vy * T
现在您需要映射虚拟位置(x',y')
到实际位置(x,y)
。见下图
您可以递归地反映虚拟点 w.r.t 边界,直到该点返回到参考(初始)框中。这才是重点。现在的问题是如何做这些数学?以及如何找到 (x,y)
知道 (x',y')
?
用 a
和 b
分别表示框沿 x
和 y
的大小。然后 nx = floor(x'/a)
和 ny = floor(y'/b)
表示该点与参考框的距离以框数表示。另外dx = x'-nx*a
和dy = y'-ny*b
介绍了虚拟点在其虚拟框内的相对位置。
现在你可以找到真正的位置(x,y)
:如果nx
是偶数,那么x = dx
else x = a-dx
;同样,如果 ny
是偶数,则 y = dy
否则 y = b-dy
。换句话说,在x轴和y轴上的偶数次反射,使真实点和虚拟点处于相同的相对位置,而奇数次反射使它们不同且互补。
我这里有一个简单的 maths/physics 问题:在笛卡尔坐标系中,我有一个以已知速度随时间移动的点。该点位于一个盒子内,并在其壁上正交反弹。
这是我在绘画上做的一个简单示例:
我们所知道的:红点位置,以及由角度 θ 和速度定义的速度。我们当然知道绿盒子的尺寸。
在例子中,我用黄色画出了它的大概轨迹,假设经过一段已知的确定时间后,红点在蓝点上。计算蓝点位置的最有效方法是什么?
我一直在努力用三角函数和矢量投影计算每个“反弹点”,但我觉得这是一种资源浪费,因为三角函数通常非常耗费处理器资源。我将有超过一千个点需要这样计算,所以我真的需要找到一种更有效的方法。
如果有人有任何想法,我将不胜感激。
你不需要一直使用三角函数。取而代之的是将归一化方向向量作为 (dx, dy) = (cos(θ), sin(θ))
从垂直墙反弹后,x 分量改变了它的符号 dx = -dx
,从水平墙反弹后,y 分量改变了它的符号 dy = -dy
。你可以看到计算非常简单。
如果您(出于奇怪的原因)更喜欢使用角度,请使用角度变换
if ((ball.x + ball.radius) >= window.width || (ball.x - ball.radius) <= 0)
ball.theta = M_PI - ball.theta;
else
if ((ball.y + ball.radius) >= window.height || (ball.y - ball.radius) <= 0)
ball.theta = - ball.theta;
获得弹跳点:
Starting point (X0, Y0)
Ray angle Theta, c = Cos(Theta), s = Sin(Theta);
Rectangle coordinates: bottom left (X1,Y1), top right (X2,Y2)
if c >= 0 then //up
XX = X2
else
XX = X1
if s >= 0 then //right
YY = Y2
else
YY = Y1
if c = 0 then //vertical ray
return Intersection = (X0, YY)
if s = 0 then //horizontal ray
return Intersection = (XX, Y0)
tx = (XX - X0) / c //parameter when vertical edge is met
ty = (YY - Y0) / s //parameter when horizontal edge is met
if tx <= ty then //vertical first
return Intersection = (XX, Y0 + tx * s)
else //horizontal first
return Intersection = (X0 + ty * c, YY)
除了编程方面的考虑,从几何角度来看,它还有一个有趣的解决方案。可以在不考虑0<t<T
T
的点的位置
一分钟,忘记盒子的大小和边界;并假设该点可以永远沿直线移动。然后该点具有恒定速度分量 vx = v*cos(θ), vy = v*sin(θ)
并且在时间 T
其 虚拟 部分将是 x' = x0 + vx * T, y' = y0 + vy * T
现在您需要映射虚拟位置(x',y')
到实际位置(x,y)
。见下图
您可以递归地反映虚拟点 w.r.t 边界,直到该点返回到参考(初始)框中。这才是重点。现在的问题是如何做这些数学?以及如何找到 (x,y)
知道 (x',y')
?
用 a
和 b
分别表示框沿 x
和 y
的大小。然后 nx = floor(x'/a)
和 ny = floor(y'/b)
表示该点与参考框的距离以框数表示。另外dx = x'-nx*a
和dy = y'-ny*b
介绍了虚拟点在其虚拟框内的相对位置。
现在你可以找到真正的位置(x,y)
:如果nx
是偶数,那么x = dx
else x = a-dx
;同样,如果 ny
是偶数,则 y = dy
否则 y = b-dy
。换句话说,在x轴和y轴上的偶数次反射,使真实点和虚拟点处于相同的相对位置,而奇数次反射使它们不同且互补。