Снаряд Движение - Стрелка

13

В 2D игре я просто хочу нарисовать траекторию стрелки в полете. С помощью приведенного ниже кода траектория (парабола) выглядит правильно, а угол (или поворот) или стрелка - нет.

float g = -9.8f;
float x = (launchVelocity * time);
float y = (launchVelocity * time) + (0.5f * g * (float)Math.Pow(time, 2));
float angle = (float)Math.Tanh(y / x);

Что мне не хватает? Благодарю.

Мартин
источник
3
Скриншот может помочь
doppelgreener

Ответы:

10

Arctanhдает вам касательную для гиперболической кривой! Насколько я знаю, ваша парабола не является гиперболой.

Но у нас есть хорошие новости: легче найти касательную для вашей параболы. Уравнение

x = s · t => t = x / s; y = s · t + g / 2 · t² => y = x + g / 2 · x² / s²

Где твой launchVelocity. Теперь наклон вашей стрелы:

∂y / ∂y = г / (2 с²) · x + 1

Вы можете использовать безопасность Arctanсейчас, если хотите.

Некоторая дополнительная информация о физике:

Примерная траектория, которую вы моделируете, относится к центру масс вашей стрелы. Когда вы говорите «положение» (x, y), вы говорите о положении центра масс. Центр масс для стрелки находится немного вперед от средней точки, и вы должны принять это во внимание, если собираетесь рисовать стрелку.

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

FXIII
источник
Спасибо, Fxlll. Любая идея, где я мог бы получить формулы, которые применяются к физике стрелки?
Мартин
Я думаю, что вы имеете в виду:! [& Part; y / & part; x = g / (2s & sup2;) & middot; x + 1] [2], но в любом случае я думаю, что рекомендовал лучший подход ниже. Во-первых, вы не объяснили разделение компонентов x и y, так что это жестко закодировано под произвольным углом 45 градусов, при этом launchVelocity не является по-настоящему launchVelocity, а компонентом как x, так и y
Dov
Можно легко вычислить моменты инерции. Это два стержня, один для вращения вокруг его центра масс, а другой для вращения вокруг оси стержня. Принцип суперпозиции применяется к моментам инерции, поэтому стрелка может быть разделена на три части: перья, тело и кончик.
FxIII
1
Проблема в том, что единственный импульс, который легко вычислить, - это тот, который обусловлен изменением угла (вы можете видеть, что при получении двойной параболы остается только постоянный член). Другое вызвано вращением из-за заднего пера. Здесь задействованы перетаскивание и трение, которые преобразуют кинетическую энергию в вращение, замедляют стрелку, но добавляют гироскопический эффект. Это влияет на траекторию и довольно сложно моделировать
FxIII
В любом случае, если вы можете связать импульс со скоростью, заданной настройкой пера, все можно вычислить путем полной интеграции, но я не уверен, что вы можете иметь закрытую форму для уравнений движения (т.е. вы можете получить алгоритм интегрирования, но не параметрический уравнение).
FxIII
4

Вы хотите угол наклона стрелки в любой момент времени. Вы вспомнили, что для вычисления угла есть касательная. Но вот где ваше мышление начало идти не так:

  1. То, что вы хотите, это дельта y / delta x, потому что наклон - это скорость изменения (упоминается в одном из других ответов). Обратите внимание, что x это просто позиция, в которой вы находитесь в любой момент времени, а не dx.

Итак, если вы пренебрегаете воздушным трением, то x-скорость стрелки постоянна.

Сначала разложим скорость на составляющие x и y. Вы можете снимать под углом 45 или 60 градусов. Так что вам нужна скорость запуска и угол, это не скаляр.

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

В-третьих, не используйте Math.pow, он медленный и не такой точный, как умножение на целые числа. Также вы можете сэкономить много времени, используя форму Хорнера (см. Ниже)

final double DEG2RAD = Math.PI/180;
double ang = launchAngle * DEG2RAD;
double v0x = launchVelocity * cos(ang); // initial velocity in x
double v0y = launchVelocity * sin(ang); // initial velocity in y

double x = (v0x * time);
// double y = (v0y * time) + (0.5 * g * (float)Math.Pow(time, 2));
double y = (0.5 * g * time + v0y) * time

Если вы отчаянно нуждаетесь в производительности, вы можете даже предварительно рассчитать 0,5 * g, но приведенный выше код отнимет у вас 90% пути, не делая ничего слишком сумасшедшего. Если вы хотите, тесты делают это 10 миллионов раз, это, правда, не так уж много времени, но в процентном отношении это довольно много - библиотеки в Java работают очень медленно

Итак, если вы хотите угол, под которым стрелка должна идти, то вы хотите, чтобы

atan(dy/dx)

И в этом случае это будет работать, потому что dx является константой. Но в общем случае dx может быть нулевым, поэтому вы обычно хотите использовать:

atan2(dy, dx)

которая является функцией, специально разработанной для этой работы.

Но, как я уже сказал, библиотечные функции в Java ужасно медленные, и в этом случае есть лучший способ сделать это без упоминания @FxIII выше.

Если горизонтальная скорость всегда v0x, а вертикальная скорость:

double vy = v0y - 0.5 * g * time;

тогда ваша дельта: vx, vy

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

сюжет (x, y, x + vx, y + vy);

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

Не забудьте, если вы используете opengl, чтобы повернуть угол обратно в градусы, потому что ATAN2 возвращает радианы:

final double RAD2DEG = 180 / Math.PI;
double ang = Math.atan2(vy,vx); // don't forget, vy first!!!
double deg = ang * RAD2DEG;
Дов
источник
2

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

Что вы действительно хотите, так это использовать гиперболический арктангенс , который принимает соотношение сторон в качестве параметра и возвращает угол. (Назовите это может быть «atanh», «atanh2», «arctanh» или что-то подобное; похоже, они сильно различаются в разных математических библиотеках)

Тревор Пауэлл
источник
Нет, вы не хотите ничего гиперболического
Дов
Гах, ты абсолютно прав. Я сразу понял ошибку «использование базовой тригонометрии» и пропустил, что функция, которую он использовал, была совершенно неверной для остальной части его подхода.
Тревор Пауэлл
Тан () принимает угол. Атан принимает соотношение сторон треугольника (sin / cos).
3Dave