【问题标题】:Vectors, calculate movement forces with max speed向量,以最大速度计算运动力
【发布时间】:2023-04-07 23:08:01
【问题描述】:

我正在制作一款小型太空射击游戏。当涉及到空间物理学时,我曾经对数学问题感到困惑。

用文字描述如下: 有一个最大速度。 因此,如果您全速行驶,您的飞船将像在旧的小行星游戏中一样,一遍又一遍地在屏幕上移动。 如果随后释放火箭助推器,您的飞船应该会继续以该速度在屏幕上移动。

然后是我现在卡住的棘手部分。

如果您将船旋转任意角度并再次提供助力,船应该尝试到达这个方向,并且在移动速度方面永远不要超过最大速度。所以我的问题是。有人有这个问题的好主意公式吗?如果您知道要寻找什么,就感觉以前已经完成了。 :)

我将添加这个小图像来说明尝试通过一些矢量计算完成的工作。

红环:最大速度

绿线:当前船舶方向。

黑线:方向以及船在 x 和 y 方向上的移动速度。

黑环:运动的起源。

可以说明,但很难找到一个好的数学解决方案。 :)

编辑

这是我现在在每一帧中使用的代码。它为飞船提供运动,但不提供用户必须用火箭助推器反作用以使飞船停止或减速的移动力。有了这个,它会在你释放飞船加速的瞬间停止。

    //Calculates ship movement rules
var shipVelocityVec = GetVectorPosByAngle(shipMoveSpeed, shipRotationAngle);
var shipUnitVec =$V([Math.cos(shipRotationAngle),Math.sin(shipRotationAngle),0]);
var rawAccel = shipAccelSpeed / shipMass;
var scale = (shipUnitVec.dot(shipVelocityVec))/(shipTopSpeed * shipTopSpeed);
var v1 = shipUnitVec.subtract(shipVelocityVec.multiply(scale));
var finalAccelVec = v1.multiply(rawAccel);
console.log(finalAccelVec);

//move ship according to rules
var shipPosVector = $V([shipxPos, shipyPos, 0]);
var movementVector =  shipPosVector.add(finalAccelVec);
shipxPos = movementVector.elements[0];
shipyPos = movementVector.elements[1];

要获得加速速度,用户必须按住按钮。当用户松开按钮时,加速度设置为零,必须再次加速以提供最大加速度油门。

找到了解决方案!在这里发布了它是如何完成的。

【问题讨论】:

  • 我认为这是一个二维的东西?保留单独的 x 和 y 速度指示器。如果您以某个角度推进,则将该角度推力分解为 x 和 y 分量,从而允许您分别调整船的 x/y 速度分量。每次调整速度时,检查船速,如果达到最大值则停止调整。
  • 请纠正我的误解,但在图像 #3 中,速度的组合矢量不是大于红环允许的速度吗?
  • 不,因为 x 和 y 加在一起等于 circels 最大运动。绿线可能更长。在 #3 中,绿线应该是圆直径的全长。
  • 分离 X 和 Y 运动不是一个坏主意!
  • +1 用您的问题制作图表

标签: javascript math vector game-physics


【解决方案1】:

您似乎有些困惑 - 如果您正确使用矢量,将速度限制在最大速度是没有问题的,即使加速度处于不同的角度。

您的设置应如下所示:

  1. 您的船应该有一个位置、一个速度和一个加速度。每一个都可以表示为一个二维向量(具有单独的 xy 分量)。
  2. 每一帧,将速度添加到位置,将加速度添加到速度。
  3. 每一帧,检查speed 不超过某个最大值。如果是这样,请将速度限制为 normalizing 速度矢量并将其乘以最大速度。

就是这样!无需考虑特殊情况 - 这就是向量代数的魔力!

【讨论】:

  • 添加一个量proportional到速度到位置,proportional到加速度到速度。
  • @Michael:这取决于单位(像素/秒与像素/帧)。 :)
  • 并非如此。除非您的帧在时间上都是均匀分布的,否则您无法将常数吸收到单位中。这是一个微积分问题 - 它是关于积分,而不是加法。
  • 我想我实际上必须在这里接受迈克尔斯的概念,因为这里应该有一个来自以前行动的力量,必须处理它以获得最终的行进方向和速度。
  • @Jonas:迈克尔正在谈论使用variable-step framerate rather than a fixed-step。可变速率更有利,但固定步长更容易实现,因此更常见于小型游戏。我建议从固定步长开始,因为它易于使用。这与阻力无关(正如您对迈克尔的回答所提到的那样)。
【解决方案2】:

@BlueRaja 的解决方案应该可以工作,尽管当您达到最大速度时,您的行为会突然发生变化。

如果您想要一个没有“接缝”的解决方案,我相信您可以通过为加速度添加正确类型的调整来完成您正在寻找的事情,如下所示:

ship_unit_vec = [cos(ship_angle), sin(ship_angle)]
raw_accel = (engine_thrust / ship_mass)

scale = dot_product(ship_unit_vec, ship_velocity_vec) / max_speed^2

final_accel_vec = raw_accel * (ship_unit_vec - scale * ship_velocity_vec)

注意事项:

  • 如果|ship_velocity_vec|<<max_speedscale * ship_velocity_vec 组件可以忽略不计。
  • 如果|ship_velocity_vec|==max_speedscale * ship_velocity_vec 组件会取消所有在“错误”方向上的额外加速,并帮助在“正确”方向上加速。
  • 我从未尝试过,所以我不知道玩家会有什么感觉...

更一般地说,如果加速源不仅仅是船舶推进器,您可以将它们全部加在一起(例如,raw_accel_vec),然后一次性执行上述操作:

scale_forall = dot_product(raw_accel_vec, ship_velocity_vec) / max_speed^2
final_accel_vec = raw_accel_vec - scale_forall * ship_velocity_vec

【讨论】:

  • 很好的例子!从来没有想过给船一个质量。只考虑此刻施加给它的力量,并将其作为变化的基础。明天早上将对我的代码进行一些修改,看看这样的事情是如何工作的。
  • 这个答案完全按照迈克尔的建议引入了阻力。不过,我不确定你为什么要添加一个质量 (它只会以常数倍数影响加速度,因此可以省略),出于某种原因,你决定将单个漂亮的矢量变成方程转化为多个更复杂的方程。
  • 有一个区别:这里的“阻力”与加速度和速度的平方成正比,并适当缩放以产生给定的max_speed施加的“力”。
  • 我添加了质量(以及推力大小和方向之间的分离)以尝试使演示文稿更具体地适合问题 - 但我会采纳您的建议并添加更简单和更抽象的等式。
【解决方案3】:

您可以使用一些实际的物理原理并施加阻力,而不是仅仅施加特定的最大速度。这将是作用在宇宙飞船上的额外力,方向与速度矢量相反。对于阻力的大小,最简单的方法是将其与速度矢量成正比。

总体效果是,当飞船移动得更快时,阻力会增加,当飞船移动得更快时,它更难在运动方向上加速。当它与运动方向相反时,它也使加速更容易。

这与您的描述不同的一点是,宇宙飞船不会永远以最大速度继续行驶,它会减速。然而,它不会停下来,因为阻力会随着船的减速而下降。这比我对小行星的记忆更符合我对永远保持恒定速度的飞船的记忆,但我已经有一段时间没有玩了。

【讨论】:

  • 是的,没错。阻力也是我追求并打算模拟的。我只是在没有下降阻力的情况下做到了这一点,以便更容易尝试解释我想要开始的内容。
  • 这个阻力必须能够被飞船当前的方向力缓慢地改变。对吗?
  • @Jonas:看来你需要更新你的vector math。这里也没有特殊情况需要考虑 - 向量是独立添加的,因此您可以简单地将拖动加速度添加到每帧的速度,然后根据用户输入立即添加加速度,没有任何问题。
  • @Jonas 阻力不受任何其他力的影响,它是速度的函数。我真的不知道您所说的“船舶当前方向力”是什么意思-推力,也许?无论如何,这只是基本的牛顿力学:物体的加速度与作用在物体上的所有力的总和成正比。因此,您将力相加并以总力向量结束,如果它只是来自宇宙飞船的推力,则其处理方式与总力向量相同。
【解决方案4】:

我做到了!感谢您的帮助。

终于找到了解决办法。问题是我试图在速度方面修改船舶当前的运动,然后计算当用户试图去另一个方向时,该运动产生的“阻力”力。解决方案就像提到的@BlueRaja 和@Comingstorm 一样。当涉及到运动时,所有的力量都应该加在一起。这应该是改变船只位置的原因。不应添加到船舶当前运动中。您可能能够影响当前的运动,但您必须以不同的方式执行此操作。所以我想我会分享我的解决方案。

每次用户加速飞船时都会运行此函数。

function CalcShipMovement() {
//Calculates ship movement rules
shipPosVector = $V([shipxPos, shipyPos, 0]);
var shipVelocityVec = GetVectorPosByAngle(shipAccelSpeed, shipRotationAngle);
var shipUnitVec = $V([Math.cos(shipRotationAngle), Math.sin(shipRotationAngle), 0]);

if(currentShipMoveVector != null && Get2DVectorLength(currentShipMoveVector) > 0) {
    var nextMove = currentShipMoveVector.add(shipVelocityVec);
    var nextSpeed = Get2DVectorLength(nextMove);
    //check if topspeed of movement should be changed
    if(nextSpeed > shipTopSpeed) {
        var scale = nextSpeed / shipTopSpeed;
        currentShipMoveVector = DevideVector(nextSpeed, scale);
    } else {
        currentShipMoveVector = currentShipMoveVector.add(shipVelocityVec);
    }
}
if(currentShipMoveVector != null && Get2DVectorLength(currentShipMoveVector) == 0) {
    currentShipMoveVector = currentShipMoveVector.add(shipVelocityVec);
}}

此代码在生成船舶图形以改变其位置的每一帧中运行。

function SetShipMovement() {
if(currentShipMoveVector != null && Get2DVectorLength(currentShipMoveVector) > 0) {
    shipMoveSpeed = Get2DVectorLength(currentShipMoveVector);
    shipPosVector = shipPosVector.add(currentShipMoveVector);
    shipxPos = shipPosVector.elements[0];
    shipyPos = shipPosVector.elements[1];
    //Makes the ship slow down if no acceleration is done for the ship
    if(shipAccelSpeed == 0) {
        currentShipMoveVector = currentShipMoveVector.subtract(DevideVector(currentShipMoveVector, 50));
    }
} else {
    currentShipMoveVector = $V([0, 0, 0]);
}}

【讨论】:

    猜你喜欢
    • 2014-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-13
    • 2011-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多