Векторы, рассчитать силы движения с максимальной скоростью - PullRequest
7 голосов
/ 15 февраля 2012

Я строю небольшой космический шутер. Я когда-либо сталкивался с математической проблемой, когда дело доходит до космической физики.

Описать это словами можно следующим образом: Максимальная скорость есть. Поэтому, если вы дадите полную скорость, ваш корабль будет перемещаться по экрану снова и снова, как в старых играх с астероидами. Если затем отпустите ускорение ракеты, то ваш корабль должен продолжать двигаться с этой скоростью по экрану.

Тогда сложная часть, где я застрял прямо сейчас.

Если вы поворачиваете корабль на ЛЮБОЙ угол и снова разгоняетесь, корабль должен попытаться добраться в этом направлении, и НИКОГДА не превышать максимальную скорость, когда дело касается скорости его движения. так что мой вопрос У кого-нибудь есть хорошая идея формулы для этого вопроса? кажется, что это было сделано раньше, если вы знаете, что искать. :)

Я добавлю это маленькое изображение, чтобы проиллюстрировать, что пытаются сделать с помощью некоторых векторных расчетов. Max speed movement with force

Красное кольцо: максимальная скорость

Зеленая линия: текущее направление корабля.

Черная линия: направление (я) и как быстро корабль движется в х и у.

Черное кольцо: начало движения.

Могу проиллюстрировать это, но трудно найти хорошее математическое решение для этого. :)

EDIT

Это код, который я сейчас использую в каждом кадре. Он дает движение кораблю, но не дает силы движения, которую пользователь должен противопоставить своим ракетным ускорителям, чтобы корабль остановился или замедлился. При этом он останавливается, как только вы отпускаете ускоряющую скорость для корабля.

    //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 ]

3 голосов
/ 15 февраля 2012

Вы, кажется, что-то путаете - там означает без проблем, ограничивая скорость до максимальной скорости, даже если ускорение находится под другим углом, если вы правильно используете векторы.

Ваша установка должна выглядеть примерно так:

  1. У вашего корабля должна быть позиция, скорость и ускорение.Каждый из них может быть представлен в виде 2D вектора (с отдельными x и y компонентами).
  2. В каждом кадре добавьте скорость к позиции и ускорение к скорости.
  3. В каждом кадре убедитесь, что скорость не превышает некоторого максимума.Если это так, ограничьте скорость на , нормализуя вектор скорости и умножив его на максимальную скорость.

Вот и все!Особых случаев рассматривать не нужно - это магия векторной алгебры!

1 голос
/ 15 февраля 2012

@ Решение 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_speed, компонент scale * ship_velocity_vec пренебрежимо мал.
  • Если |ship_velocity_vec|==max_speed, компонент scale * 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
1 голос
/ 15 февраля 2012

Вместо того, чтобы просто вводить максимальную скорость ad hoc, вы можете использовать некоторую физику и применить силу сопротивления.Это была бы дополнительная сила, действующая на космический корабль, направленная противоположно вектору скорости.Для величины силы сопротивления проще всего взять ее пропорциональной вектору скорости.

Общий эффект состоит в том, что сила сопротивления увеличивается по мере того, как космический корабль движется быстрее, что затрудняет ускорение в направлении движения, когда корабль движется быстрее.Это также облегчает ускорение, когда оно противоположно направлению движения.

Один момент, который отличается от вашего описания, заключается в том, что космический корабль не будет продолжать работать на максимальной скорости вечно, он будет замедляться.Однако он не остановится, поскольку сила торможения падает по мере замедления корабля.Это соответствует моей памяти об астероидах лучше, чем корабль, продолжающий вечно с постоянной скоростью, но я играл довольно давно.

0 голосов
/ 17 февраля 2012

Я сделал это!Спасибо за вашу помощь.

Наконец-то нашли решение.проблема заключалась в том, что я пытался изменить текущее движение кораблей, когда дело доходит до скорости, и затем из этого вычислить силы «сопротивления», которые были бы продуктом этого движения, когда пользователь попытался пойти в другом направлении.Решение было похоже на @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]);
}}
...