太空船的二维轨迹规划,带物理学。
我正在实现一个带有太空飞船的2D游戏。
为了实现它,我使用LÖVE,它使用Lua实现了Box2D。但我相信我的问题可以被任何比我更了解物理的人回答 - 因此伪代码也可以作为答案接受。
我的问题是我不知道如何在2D物理世界上正确移动我的太空飞船。更具体地说:
质量为m的飞船位于初始位置{x,y}。 它有初始速度向量{vx,vy}(可以是{0,0})。
目标是点{x0,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 ++编写的,但它可以实现我所需要的。 对于达到这个问题的任何人来说,它可能会有所帮助。
原文链接 https://stackoverflow.com/questions/2560817
为了只是从当前位置到目的地以一个初始速度到达,然后沿着最短路径和当前速度之间的归一化差异施加推力。实际上,你不需要角度。
-- 最短路径减去初始速度
dx, dy = x0 - x - vx, y0 - y - vy
-- 归一化方向向量
magnitude = sqrt(dx*dx + dy*dy)
dx, dy = dx/magnitude, dy/mangitude
-- 在我们刚刚计算出的方向上施加推力
self:applyImpulse(thrust*dx, thrust*dy)
注意,这不考虑目标速度,因为那会变得非常复杂。
我有一个很小的用于处理2D向量的Lua模块,在这个Paste Bin中。你可以使用它。上面的代码将简化为:
d = destination - position - velocity
d:normalize()
d = d * thrust
self:applyImpulse(d.x, d.y)
这被称为运动规划,它并不是微不足道的。
以下是一个获得非最优轨迹的简单方法:
停止。应用反向推力直到速度为零。
计算最后一段,即与第一段相反的稳定推力,从静止开始使飞船达到x0和v0。起点将在距离x0 |v0|^2/(2*thrust) 处。
到达该起点(然后进行最后一段)。从一个静止点到另一个静止点很容易:向它推进,直到到达一半,然后向后推直到停止。
如果您想快速而粗略地逼近最佳轨迹,可以使用迭代方法:从上述非最优方法开始;那仅仅是推力角的时间序列。现在尝试对该序列进行微小的变化,并保留能够接近目标的序列群。拒绝最差的,尝试最好的-如果你感到大胆,你可以将其制作成遗传算法-幸运的话会开始平滑路径。
如果您想要精确答案,请使用变分法。我将尝试解决这个问题,如果我成功了,我会在这里发布答案。
编辑:以下是简单问题的确切解决方案。
假设我们没有可以指向任何方向的推力,而是有四个指向{+X,+Y,-X,-Y}方向的固定推力器。在任何给定时间,我们最多会发射+/-X中的一个,以及+/-Y中的一个(同时点燃+ X和-X的作用没有意义)。所以现在X和Y问题是独立的(在原始问题中它们不是因为推力必须在X和Y之间共享)。我们现在必须解决1-D问题-并将其应用两次。
最佳轨迹实际上涉及在一个方向上进行推进,然后在另一个方向上进行推进,不会再回到第一个方向。(仅在其他轴线的解决方案将需要更长时间,以便您有时间击败它时,滑行就有用了。)首先解决速度问题:我们假设(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
完成。
你是否正在排放燃料?如果是的话,你的质量会随着时间变化。
推力是一种反作用力。它是质量变化的速率,乘以相对于宇宙飞船的排气速度。
你是否有外力作用?如果有,这些力需要纳入你的冲量计算中。
假设存在一种神奇的推力,没有物质被排放,也没有外力。
冲量的单位是动量。它是力在时间上的积分。
首先,你需要确定 API 将“推力”和“冲量”定义为什么样的量。如果你输入的是经过标量(数字)乘以的推力,则 applyImpulse 必须对输入进行一些处理才能将其用作冲量,因为其单位不匹配。
假设你的“推力”是一种力,则将该推力乘以时间间隔(1/30 秒)以得到冲量,并分解出各组分。
不确定我是否回答了你的问题,但希望这能帮助你理解一些物理知识。
更容易理解的方法是将船的速度分解成与目标速度向量平行和垂直的两个分量。
沿着垂直轴考虑,船希望尽快与目标位置对齐,然后保持在那里。
沿着平行轴,船应该加速朝着接近目标速度的方向。(显然,如果这种加速会将其带远离目标点,你需要决定该怎么办。是飞过这个点然后回头吗?)
我建议分别处理这两个分量,先考虑垂直的分量。一旦它运作正常,如果这还不足以满足需求,你可以开始考虑如何让船在垂直和平行之间发射智能角度。
(编辑:另外,我忘记提到,这会需要一些调整来处理你在垂直方向上偏移很多但平行方向上不多的情况。重要的教训是使用分量运算,这将给你有用的数字,以便做出决策。)
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
你的角度是反正切量的相反数/临边比。
因此,角度=InvTan(VY/VX)。
我不确定你所说的想漂移是什么意思?