Математические векторы и вращения (Java-игра Topdown - проблема физики) - PullRequest
4 голосов
/ 06 сентября 2011

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

У меня проблема с моим текущим вращением, которое не обрабатывается должным образом.Я знаю, что проблема заключается в том, что моя величина равна 0 при умножении ее на направление Math.cos / sin, но я просто не знаю, как это исправить.

Это текущий базовый код.

private void move(int deltaTime) {

double secondsElapsed = (deltaTime / 1000.0);// seconds since last update
double speed = velocity.magnitude();
double magnitude = 0;

if (up)
    magnitude = 100.0;
if (down)
    magnitude = -100.0;
if (right)
    direction += rotationSpeed * (speed/topspeed);// * secondsElapsed;
if (left)
    direction -= rotationSpeed * (speed/topspeed);// * secondsElapsed;

double dir = Math.toRadians(direction - 90);
acceleration = new Vector2D(magnitude * Math.cos(dir), magnitude * Math.sin(dir));

Vector2D deltaA = acceleration.scale(secondsElapsed); 
velocity = velocity.add(deltaA); 

if (speed < 1.5 && speed != 0)
    velocity.setLength(0);

Vector2D deltaP = velocity.scale(secondsElapsed); 
position = position.add(deltaP);

...
}

Мой векторный класс эмулирует векторные основы - в том числе вычитание сложения, умножение на скаляры ... и т. Д.

Для повторения основной проблемы - это величина * Math.cos (dir)= 0, когда величина равна 0, таким образом, когда игрок нажимает только клавиши со стрелками вправо или влево без направления «ускорения», не меняется.

Если кому-то нужна дополнительная информация, вы можете найти ее по адресу

http://www.java -gaming.org / index.php / тема, 23930.0.html

Ответы [ 2 ]

6 голосов
/ 06 сентября 2011

Да, все эти физические расчеты перепутаны.Основная проблема в том, что, как вы уже поняли, умножение ускорения на направление неверно.Это потому, что ваше «направление» - это не только направление ускорения автомобиля;это направление движения автомобиля.

Самый простой способ это исправить - начать с рассмотрения ускорения и рулевого управления отдельно.Во-первых, ускорение: для этого у вас есть скорость и клавиши «вверх» и «вниз».Для этого код выглядит следующим образом (включая ваш пороговый код для уменьшения почти нулевой скорости до нуля):

if (up)
    acceleration = 100.0;
if (down)
    acceleration = -100.0;

speed += acceleration * secondsElapsed;

if (abs(speed) < 1.5) speed = 0;

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

if (right)
    rotationRate = maxRotationSpeed * (speed/topspeed);
if (left)
    rotationRate = maxRotationSpeed * (speed/topspeed);

direction += rotationRate * secondsElapsed;

double dir = Math.toRadians(direction - 90);
velocity = new Vector2D(speed * Math.cos(dir), speed * Math.sin(dir));

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

1 голос
/ 11 сентября 2011

Поскольку вы спрашивали об ускорении как векторе, здесь есть альтернативное решение, которое будет вычислять вещи таким образом.

Сначала, учитывая скорость (значение Vector2D), давайте предположим, что вы можете вычислить направление из нее. Я не знаю ваш синтаксис, поэтому вот набросок того, что это может быть:

double forwardDirection = Math.toDegrees(velocity.direction()) + 90;

Это направление, куда указывает машина. (Автомобили всегда указывают в направлении своей скорости.)

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

double forwardAcceleration = 0;
if (up)
    forwardAcceleration = 100;
if (down)
    forwardAcceleration = -100;

Ускорение из-за рулевого управления немного сложнее. Если вы движетесь по кругу, величина ускорения к центру этого круга равна квадрату скорости, деленному на радиус круга. И, если вы поворачиваете налево, ускорение влево; если вы поворачиваете направо, то это направо. Итак:

double speed = velocity.magnitude();
double leftAcceleration = 0;
if (right)
    leftAcceleration = ((speed * speed) / turningRadius);
if (left)
    leftAcceleration = -((speed * speed) / turningRadius);

Теперь у вас есть значение forwardAcceleration, которое содержит ускорение в прямом направлении (отрицательное для обратного), и значение leftAcceleration, которое содержит ускорение в левом направлении (отрицательное для правого). Давайте преобразуем это в вектор ускорения.

Во-первых, некоторые дополнительные переменные направления, которые мы используем для создания единичных векторов (в первую очередь для упрощения объяснения кода):

double leftDirection = forwardDirection + 90;

double fDir = Math.toRadians(forwardDirection - 90);
double ldir = Math.toRadians(leftDirection - 90);

Vector2D forwardUnitVector = new Vector2D(Math.cos(fDir), Math.sin(fDir));
Vector2D leftUnitVector = new Vector2D(Math.cos(lDir), Math.sin(lDir));

Затем вы можете создать вектор ускорения, собрав переднюю и левую части, например:

Vector2D acceleration = forwardUnitVector.scale(forwardAcceleration);
acceleration = acceleration.add(leftUnitVector.scale(leftAcceleration));

Хорошо, это ваше ускорение. Вы конвертируете это в изменение скорости следующим образом (обратите внимание, что правильный термин для этого deltaV, а не deltaA):

Vector2D deltaV = acceleration.scale(secondsElapsed);
velocity = velocity.add(deltaV).

Наконец, вы, вероятно, хотите узнать, в каком направлении движется автомобиль (для того, чтобы нарисовать его на экране), поэтому вы вычисляете это по новой скорости:

double forwardDirection = Math.toDegrees(velocity.direction()) + 90;

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

(Эта версия ближе к тому, что вы изначально пытались сделать, поэтому позвольте мне немного проанализировать, в чем вы пошли не так. Часть ускорения, которая идет вверх / вниз, всегда в направлении, указанном автомобиль заострен, он не поворачивается вместе с рулевым механизмом до тех пор, пока автомобиль не поворачивает. Между тем, часть ускорения от рулевого управления всегда направлена ​​только влево или вправо, и ее величина не имеет ничего общего с ускорением вперед / назад - и, в частности, его величина может быть ненулевой, даже если переднее / заднее ускорение равно нулю. Чтобы получить общий вектор ускорения, вам нужно вычислить эти две части отдельно и сложить их вместе как векторы.)

Ни одно из этих вычислений не является абсолютно точным. В этом примере вы вычисляете направления «вперед» и «влево» от того места, где началась машина, но автомобиль вращается, поэтому эти направления меняются с течением времени. Таким образом, уравнение deltaV = acceleration * time является только оценочным и даст немного неправильный ответ. Другое решение имеет аналогичные неточности, но одна из причин того, что другое решение лучше, заключается в том, что в этом случае небольшие ошибки означают, что скорость будет увеличиваться, если вы будете управлять автомобилем влево и вправо, даже если вы этого не сделаете прикоснитесь к клавише «вверх» - тогда как в другой такой кросс-ошибки не происходит, потому что мы держим скорость и рулевое управление отдельно.

...