问题 用物理学研究飞船的2d轨迹规划
我正在太空船上实施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中实施了它。
编辑2:经过更多谷歌搜索后我也发现了 openSteer。它是在C ++上,但它做了我假装的。对于达到这个问题的人来说,这可能会有所帮助。
4687
2018-04-01 13:52
起源
答案:
它被称为运动规划,并不是微不足道的。
这是获得非最佳轨迹的简单方法:
- 停止。施加与速度方向相反的推力,直到速度为零。
- 计算最后一条腿,它将与第一条腿相反,从站立起点到达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
我们已经完成了。
8
2018-04-01 14:26
在没有额外信息的情况下,我们可以假设有3种力量作用于宇宙飞船并最终决定其轨迹:
- “冲动“:[用户/程序控制]强制。
用户(或程序)似乎可以完全控制它,即它控制脉冲的方向及其推力(可能在0到最大范围内)
- 一些外力称之为引力,不管......
这种力量可以由几个来源驱动,但我们只对所产生的合力产生兴趣:在给定的时间和空间,这种外力以给定的强度和方向作用在船上。用户/程序无法控制这些。
- 惯性:这与船舶的当前速度和方向有关。该力通常使船舶以其当前速度继续沿其当前方向行驶。可能存在控制惯性的其他[太空时代]参数,但通常,它与速度和船体质量成比例(直观地,如果当前速度较小和/或船舶将更容易停泊如果质量较小)
显然,用户/程序仅控制(在限制范围内)第一个力。
从问题来看,尚不清楚手头的问题是:
- [问题A]编写一个程序,发现系统的动态(和/或适应改变这些动态)。
要么..
- [问题B]建议一个模型 - 一个公式 - 可以用来计算最终应用于船舶的合力:用户控制的脉冲和其他两个系统/物理驱动力的“加权”和。
后一个问题,问题B,更容易和简洁地解释,所以让我们建议以下模型:
Constant Parameters:
ExternalForceX = strength of the external force in the X direction
ExternalForceY = id. Y direction
MassOfShip = coeficient controlling
Variable Parameters:
ImpulseAngle = direction of impulse
ImpulseThrust = force of thrust
Formula:
Vx[new] = (cos(ImpulseAngle) * ImpulseThrust) + ExternalForceX + (MassOfShip * Vx[current])
Vy[new] = (sin(ImpulseAngle) * ImpulseThrust) + ExternalForceY + (MassOfShip * Vy[current])
注意,上述模型假设一个恒定的外力(在强度和方向上都是常数);也就是说:类似于相对远离所显示区域的引力场(就像说地球引力,在足球场的范围内考虑)。如果显示区域的比例相对于外力源较大,则应修改上述公式的中间项,以包括:基于源中心与电流之间角度的三角因子基于源中心与当前位置之间的距离的位置和/或[反向]比例因子。
类似地,假设船的质量保持不变,它可能是一个变量,基于空的船的质量,当游戏进行时燃料的重量被移除/添加。
现在...以上所有假设系统的动态由游戏设计师控制:基本上为所提到的参数选择一组值,并可能在公式的数学中增加一点复杂性(并确保适当的缩放)通常将船“保持”在显示区域内)。
相反,如果相反,系统动力学很容易被编程到游戏中(并假设是隐藏/随机),而手头的任务是编写一个程序,该程序将逐步决定冲动的方向和推力值以驱动船到它的目标目的地,其目标的速度尽可能接近getTargetVelocity()?这就是“问题A”。
这种类型的问题可以用a来解决 PID控制器。简而言之,这样一个控制器“决定”哪个动作量(在这个游戏的情况下=哪个脉冲角和施加的推力量),基于三个,称重的因子,松散地定义如下:
- 我们距离“设定点”的当前值有多远:这是PID的P =比例部分
- 我们接近“设定点”的速度有多快:这是PID的D =微分部分
- 我们离开“设定点”多长时间和多少:这是PID的I =整数部分
例如,不太复杂的控制器可以仅使用比例因子。这会导致振荡,有时在设定点的两侧都有很大的振幅(“我距离我应该的位置是X单位:让我拉动方向盘并按下气体”)。这种设定点的超调受到衍生因素的影响(“是的,我仍然不是我应该在的地方,但是自从我上一次检查以来我取得的进步非常大:更好地放慢一点”) 。最后,积分部分考虑到所有事物在比例和导数部分方面相同的事实,根据我们是否已经长时间“偏离轨道”而不是更小或更大的行动是合适的。并且我们一直都在偏离轨道(例如,“最近我们一直在追踪到我们应该去的地方,没有必要做出轻率的动作”)
我们可以讨论实现PID控制器的细节,以满足太空船游戏的特定需求,如果这是有效的需要。这个想法是为了提供可以做的事情。
3
2018-04-01 16:15
要以初始速度从当前位置到达目的地,然后沿最短路径和当前速度之间的归一化差值施加推力。你实际上并不需要角度。
-- 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模块用于处理2D矢量 这个粘贴箱。欢迎您使用它。上面的代码将减少为:
d = destination - position - velocity
d:normalize()
d = d * thrust
self:applyImpulse(d.x, d.y)
1
2018-04-01 14:24
你在榨油吗?如果你是的话,你的质量会随着时间而改变。
推力是一种反作用力。它是质量的变化率,乘以相对于宇宙飞船的排气速度。
你有外力吗?如果这样做,则需要输入您的冲动计算。
让我们假设一个神奇的推力,没有质量被驱逐,没有外力。
冲动有动量单位。随着时间的推移,它是力量的积分。
首先,你需要弄清楚API究竟叫什么“推力”和冲动。如果你用一个标量(数字)加上一个推力,那么applyImpulse必须对你的输入做一些其他事情,以便能够将它用作冲动,因为单位不匹配。
假设你的“推力”是一个力,那么你将该推力乘以时间间隔(1/30秒)来获得冲动,并打破组件。
不知道我是否在回答你的问题,但希望这有助于你理解物理学。
0
2018-04-01 14:40
如果将船的速度分成组件,则更容易考虑, 平行 和 垂直 到目标速度矢量。
沿着垂直轴考虑,船舶希望尽快与目标位置一致,然后停留在那里。
沿着平行轴,它应该在任何方向上加速,使其接近目标速度。 (显然,如果加速采取它 远 从目标点来看,你需要决定做什么。飞过点然后再回来?)
我会分别处理它们中的两个,并且可能首先垂直。一旦它工作,如果这不够好,你可以开始考虑是否有办法让船在垂直和平行之间发射智能角度。
(编辑:另外,我忘了提一下,这将需要一些调整来处理你在垂直方向上偏移很多但在平行方向上偏差很大的情况。这里重要的一课是采取组件,这给出了你有用的数字作为决定的依据。)
0
2018-04-01 14:53
您的角度是相反/相邻的反向切线
所以angle = InvTan(VY / VX)
不确定你在谈论想要漂移?
-1
2018-04-01 14:06