矢量,以最大速度计算运动力

时间:2012-02-15 14:20:58

标签: javascript math vector game-physics

我正在建造一个小型太空射击游戏。当涉及空间物理学时,我对数学问题有过深入探讨。

用文字描述如下: 最高速度。 因此,如果你全速前进,你就会像在旧的小行星游戏中一样,一遍又一遍地在屏幕上移动。 如果然后释放火箭助推器,你应该继续在屏幕上以那个速度移动。

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

如果您将船舶任意角度旋转并再次提升,那么船舶应该尝试朝这个方向前进,并且当它移动速度时,永远不会超过最大速度。所以我的问题是。对于这个问题,谁都有一个好主意公式?如果你知道要找什么,感觉就像以前一样。 :)

我添加这个小图片来说明试图通过一些矢量计算完成的工作。 Max speed movement with force

红圈:最高速度

绿线:当前船舶方向。

黑线:方向(s)以及船舶在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];

为了给出加速度,用户必须按住按钮。用户释放按钮的实例,加速度设置为零,并且必须再次加速以提供最大加速度油门。

找到解决方案!在此处发布它是如何完成的。

4 个答案:

答案 0 :(得分:3)

你好像让人感到困惑 - 如果正确使用矢量,即使加速度处于不同的角度, 也不会将速度限制在最大速度上。

您的设置应如下所示:

  1. 你的船应该有位置,速度和加速度。其中每个都可以表示为2D向量(具有单独的xy组件)。
  2. 每帧,将速度添加到位置,加速度加速到速度。
  3. 每一帧,检查speed是否超过某个最大值。如果是这样,请将速度限制为normalizing速度矢量并将其乘以最大速度。
  4. 就是这样!没有特殊情况需要考虑 - 这是矢量代数的魔力!

答案 1 :(得分:1)

您可以使用一些实际的物理效果并施加阻力,而不仅仅是施加一个临时的最大速度。这将是作用在飞船上的额外力,与速度矢量相反。对于阻力的大小,最简单的方法是将其与速度矢量成比例。

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

与你的描述不同的一点是宇宙飞船不会永远以最大速度继续,它会减速。然而,它不会停止,因为随着船速减慢,阻力下降。这与我对小行星的记忆相比,比船只在恒定的速度下持续更好,但是自从我玩完以来已经有一段时间了。

答案 2 :(得分:1)

@ 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

答案 3 :(得分:0)

我做到了!谢谢你的帮助。

终于找到了解决方案。问题是我试图修改船舶当前的运动速度,然后计算“拖动”力,这将是当用户试图转向另一个方向时此运动的产物。解决方案就像@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]);
}}