Векторы, вычисляют силы движения с максимальной скоростью

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

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

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

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

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

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

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

Черная линия: направление (направления) и скорость перемещения судна по x и y.

Черное кольцо: происхождение движения.

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

ИЗМЕНИТЬ

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

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

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

Решение найдено! Отправлено здесь, как это было сделано.

7
задан Jonas Lindahl 15 февр. '12 в 17:20
источник поделиться
4 ответов

Решение @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
ответ дан comingstorm 15 февр. '12 в 22:25
источник поделиться

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

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

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

Что это! Нет особых случаев, чтобы рассмотреть - что волшебство векторной алгебры!

3
ответ дан BlueRaja - Danny Pflughoeft 15 февр. '12 в 18:04
источник поделиться

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

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

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

1
ответ дан Michael J. Barber 15 февр. '12 в 19:07
источник поделиться

Я сделал это! Благодарим вас за помощь.

Наконец нашел решение. проблема заключалась в том, что я пытался изменить текущее движение кораблей, когда дело доходило до скорости, а затем вычислить силы "перетаскивания", которые будут результатом этого движения, когда пользователь попытается перейти в другое направление. Решение было похоже на @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]);
}}
0
ответ дан Jonas Lindahl 17 февр. '12 в 10:28
источник поделиться

Другие вопросы по меткам