我正在太空船上实施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++上,但它做了我假装的.达到这个问题的任何人都可能会有所帮助.
它被称为运动规划,并不是微不足道的.
这是获得非最佳轨迹的简单方法:
停止.施加与速度方向相反的推力,直到速度为零.
计算最后一条腿,它将与第一条腿相反,从站立起点到达x0和v0的稳定推力.起点将是距离x0 | v0 | ^ 2 /(2*推力)的距离.
到达那个起点(然后做最后一站).从一个站点到另一个站点很容易:向前推进直到你到达那里,然后向后推,直到你停下来.
如果您想要快速而肮脏的方法来获得最佳轨迹,您可以使用迭代方法:从上面的非最优方法开始; 这只是一个推力角的时间序列.现在尝试对该序列进行少量变化,保持接近目标的序列群.拒绝最糟糕的,最好的实验 - 如果你感觉大胆,你可以把它变成遗传算法 - 幸运的是它会开始绕过角落.
如果您想要确切的答案,请使用变量计算.我会对此有所了解,如果我成功了,我会在这里发布答案.
编辑:这是一个更简单的问题的确切解决方案.
假设我们有四个固定的推进器指向{+ 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
我们已经完成了.