我将假设您的船体运动正确,否则该分析将不成立。您需要强于效率的东西才能正确解决此问题。
每个推进器都会对船的运动产生两种影响:线性和角度。这些可以独立考虑。如果推进器f
在一个方向上产生力dir
,并且从质心偏移一个矢量r
(不是几何中心或子图形的中心!),那么对线性分量的影响为:
t = f * dir // f is a scalar, dir is unit length
对角速度的影响由扭矩给出:
tau = f * <dir.x, dir.y, 0> CROSS <r.x, r.y, 0> // cross product
t
是力矢量(即线性推力)。tau
是一个有符号标量,当除以质量惯性矩时,将给出角加速度。重要的是dir
且r
都在同一坐标空间中,即都在局部坐标中或在世界坐标中。
船舶的整体线性加速度由t
每个推进器的s 之和除以船舶的质量得出。同样,角加速度也就是转矩除以质量惯性矩(这是另一个标量)之和。如果总扭矩为零,则船舶将不会转弯。同样,如果总推力为零,它也不会移动。召回转矩是一个标量,但推力(“和t
”的总和)是一个2D向量。
阐述的重点是,现在我们可以将问题写为 线性程序。首先说我们要我们的船转不动。每个推进器都有一个变量$ x_1,x_2,... $,这是推进器将提供的推进量。一组约束是:
0 <= x_i < fmax_i //for each i
fmax
该推力器的最大力在哪里(这使我们可以更强或更弱)。接下来,我们说两个平等:
0 = Sum_i x_i * dir_i.x
0 = Sum_i x_i * dir_i.y
通过说总推力为零(推力是矢量,所以我们只说每个部分为零),我们就编码了这样的约束:我们将不施加线性加速度。
现在我们要我们的船转弯。大概我们想尽快这样做,所以我们想要:
max (Sum_i x_i * c_i)
where c_i = <dir_i.x, dir_i.y, 0> CROSS <r_i.x, r_i.y, 0>
x_i
在满足上述不等式和等式的同时求解,同时使上述总和最大化,将为我们提供所需的推力。大多数编程语言都有一个可用的LP库。只需将上述问题放入其中,它就会产生您的答案。
一个类似的问题将使我们继续前进。假设我们在一个坐标系中重新编写问题,在该坐标系中我们想沿正x方向移动。那么约束是:
0 <= x_i < fmax_i //for each i
max Sum_i x_i * dir_i.x
0 = Sum_i x_i * dir_i.y
0 = (Sum_i x_i * c_i)
where c_i = <dir_i.x, dir_i.y, 0> CROSS <r_i.x, r_i.y, 0> // as before
由于推进器只能产生单个方向的推力,因此您将能够实现的旋转和线速度的种类将受到限制。这将作为解决方案体现在0 = x_1 = x_2 = ... = x_n
,这意味着您永远都将一事无成。为了减轻这种情况,我建议为每位玩家将一对小的,弱的(例如5%或10%)推进器添加到每侧45度的位置。这将为解决方案提供更大的灵活性,因为它们可以用来抵消主推力器的弱次要影响。
最终,对于多达100个推进器,LP的解决方案足够快,可以在每帧完成。但是,由于解决方案不取决于位置或当前状态,因此只要形状发生变化,您就可以为每种合理的控制器输入组合预先计算解决方案(包括添加非推力器,这些推力器会改变惯性矩或船的质量,因为推进器相对于质心位于不同的位置!)。这是24种可能性(即8个方向乘以{左旋转,不旋转,右旋转})。