用物理学研究飞船的2d轨迹规划

时间:2010-04-01 13:52:12

标签: lua 2d physics box2d

我正在太空船上实施2D游戏。

为了做到这一点,我正在使用LÖVE,它将Box2D与Lua包装在一起。但我相信任何对物理学有更多了解的人都可以回答我的问题 - 所以伪代码被接受作为回应。

我的问题是我不知道如何在启用2D物理的世界中正确地移动我的宇宙飞船。更具体地说:

质量m的船位于初始位置{x, y}。它的初始速度矢量为{vx, vy}(可以是{0,0})。

目标是{xo,yo}中的一个点。该船必须按照最短的轨迹达到速度为{vxo, vyo}(或接近它)的目标。

有一个名为update(dt)的函数经常被调用(即每秒30次)。在此功能上,船舶可以通过对自身施加“冲动”来修改其位置和轨迹。脉冲的大小是二进制的:你可以在给定的方向上应用它,或者根本不应用它。在代码中,它看起来像这样:

function Ship:update(dt)
  m = self:getMass()
  x,y = self:getPosition()
  vx,vy = self:getLinearVelocity()
  xo,yo = self:getTargetPosition()
  vxo,vyo = self:getTargetVelocity()
  thrust = self:getThrust()

  if(???)
    angle = ???
    self:applyImpulse(math.sin(angle)*thrust, math.cos(angle)*thrust))
  end
end

第一个???表示在某些情况下(我猜)最好“不要冲动”并让船“漂移”。第二个???部分包括如何计算给定dt上的脉冲角。

我们在太空中,所以我们可以忽略空气摩擦等事情。

虽然它会非常好,但我并不是在寻找能为我编码的人;我把代码放在那里,所以我的问题清楚地被理解了。

我需要的是一种策略 - 一种攻击方式。我知道一些基本的物理,但我不是专家。例如,这个问题有名字吗?那种事。

非常感谢。

编辑:Beta提供了一个有效的策略,Judge在评论中直接在LÖVE中实施了它。

EDIT2:经过更多的谷歌搜索后,我也找到了openSteer。这是在C ++上,但它做了我假装的。对于达到这个问题的人来说,这可能会有所帮助。

6 个答案:

答案 0 :(得分:9)

它被称为运动规划,并不简单。

这是一种获得非最佳轨迹的简单方法:

  1. 停止。施加与速度方向相反的推力,直到速度为零。
  2. 计算最后一条腿,它与第一条腿相反,是从站立起点到达x0和v0的稳定推力。起点将是距离x0 | v0 | ^ 2 /(2 *推力)的距离。
  3. 到达那个起点(然后做最后一站)。从一个站点到另一个站点很容易:向前推进直到你到达那里,然后向后推,直到你停下来。

如果您想要快速而肮脏的方法来获得最佳轨迹,您可以使用迭代方法:从上面的非最优方法开始;这只是一个推力角的时间序列。现在尝试对该序列进行少量变化,保持接近目标的序列群。拒绝最坏的情况,尝试最好的 - 如果你感觉大胆,你可以把它变成遗传算法 - 幸运的是它会开始绕过角落。

如果您想要准确的答案,请使用变体演算。我会对此有所了解,如果我成功了,我会在这里发布答案。

编辑:以下是解决更简单问题的确切方法。

假设我们有四个固定的推进器指向{+ X,+ Y,-X,-Y}方向,而不是我们可以指向任何方向的推力。在任何给定的时间,我们将最多发射+/- X中的一个和+/- Y中的至多一个(同时发射+ x和-X没有点)。所以现在X和Y问题是独立的(它们不是原始问题,因为必须在X和Y之间共享推力)。我们现在必须解决一维问题 - 并将其应用两次。

事实证明,最好的轨迹包括向一个方向推进,然后向另一个方向推进,而不是再次回到第一个方向。 (只有当其他轴的解决方案比你的解决方案需要更长的时间时才能使用滑行,因此你有时间杀死它。)首先解决速度问题:假设(WLOG)你的目标速度大于你的初始速度。要达到目标速度,您需要一段持续时间(+)的持续时间

T = (Vf - Vi)/a

(我使用Vf:最终速度,Vi:初始速度,a:推力大小。)

我们注意到,如果这就是我们所做的一切,那么这个位置就不会正确。实际的最终位置将是

X = (Vi + Vf)T/2

所以我们必须添加

的更正
D = Xf - X = Xf -(Vi+Vf)T/2

现在为了使位置正确,我们在之前的一个方向上添加一段推力,并且在之后在相反方向上添加相等的时段。这将使最终速度不受干扰,但给我们一些位移。如果第一个周期(和第三个周期)的持续时间是t,那么我们得到的位移是

d = +/-(at^2 + atT)

+/-取决于我们是否推动+然后 - 或 - 然后+。假设它是+。 我们解决了二次方:

t = (-aT + sqrt(a^2 T^2 + 4 a D))/2a

我们已经完成了。

答案 1 :(得分:4)

答案 2 :(得分:1)

要以初始速度从当前位置到达目的地,然后沿最短路径和当前速度之间的归一化差值施加推力。你实际上并不需要角度。

-- shortest path minus initial velocity
dx,dy = x0 - x - vx, y0 - y - vy

-- normalize the direction vector
magnitude = sqrt(dx*dx + dy*dy)
dx,dy = dx/magnitude, dy/mangitude

-- apply the thrust in the direction we just calculated
self:applyImpulse(thrust*dx, thrust*dy)

请注意,这不会考虑目标速度,因为这会非常复杂。

我有一个非常小的Lua模块,用于处理this paste bin中的2D向量。欢迎您使用它。上面的代码将减少为:

d = destination - position - velocity
d:normalize()
d = d * thrust
self:applyImpulse(d.x, d.y)

答案 3 :(得分:0)

你正在驱逐燃料吗?如果你的话,你的质量会随时间而变化。

推力是一种反作用力。它是质量的变化率,乘以相对于宇宙飞船的排气速度。

你有外力吗?如果这样做,则需要进入您的冲动计算。

让我们假设一个神奇的推力,没有质量被驱逐,也没有外力。

冲动有动力单位。随着时间的推移,它是力量的积分。

首先,你需要弄清楚API究竟叫什么“推力”和冲动。如果你用一个标量(数字)加上一个推力,那么applyImpulse必须对你的输入做一些其他事情,以便能够将它用作冲动,因为单位不匹配。

假设你的“推力”是一个力,那么你将该推力乘以时间间隔(1/30秒)以获得冲动,并打破组件。

不知道我是否在回答你的问题,但希望这有助于你理解物理学。

答案 4 :(得分:0)

如果将船舶的速度分为组件,平行垂直与目标速度矢量分开,则更容易考虑。

考虑沿垂直轴,船舶希望尽快与目标位置一致,然后留在那里。

沿着平行轴,它应该在任何方向加速,使其接近目标速度。 (显然,如果加速度从目标点开始离开,你需要决定做什么。飞过点然后再回来?)

我会分别处理它们中的两个,并且可能首先垂直。一旦它工作,如果这不够好,你可以开始考虑是否有办法让船在垂直和平行之间发射智能角度。

(编辑:另外,我忘了提及,这将需要一些调整来处理你在垂直方向上偏移很多但在平行方向上没有多少偏差的情况。这里的重要教训是获取组件,它为您提供有用的数字作为决策依据。)

答案 5 :(得分:-1)

您的角度是相反/相邻的反向切线

所以angle = InvTan(VY / VX)

不确定你在谈论想要漂移的是什么?