Рух снаряда - стрілка


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 = g / (2s²) · x + 1

Ви можете безпечно використовувати Arctanзараз, якщо хочете.

Деякі додаткові відомості про фізику:

Орієнтовна траєкторія, яку ви моделюєте, стосується центру маси вашої стрілки. Коли ви говорите "позиція" (x, y), ви говорите про положення центру маси ". Центр маси стріли трохи вперед від середини, і ви повинні це врахувати, якщо ви збираєтеся намалювати стрілку.

Майте на увазі, що ви не враховуєте інерційний імпульс стріли (який може сильно відрізнятися, якщо ви стріляєте з гігантського баліста), і ви не розглядаєте динаміку рідини стріли: політ лукової стріли не піде параболічним шляхом!


Дякую Fxlll. Будь-яка ідея, де я можу взяти формули, які стосуються фізики стрілки?
Мартін

Я думаю, ви маєте на увазі:! [& Part; y / & part; x = g / (2s & sup2;) & middot; x + 1] [2], але в будь-якому випадку, я думаю, я рекомендував кращий підхід нижче. По-перше, ви не пояснили розділення компонентів x та y, тому це жорстко закодовано до довільного кута 45 градусів, при цьому startVelocity не є справді запуском швидкості, а складовою обох x та y
Dov

Можна обчислити моменти інерції легко. Це два для стержнів, один для обертання навколо його центру маси, а другий для обертання навколо осі стрижня. Принцип суперпозиції застосовується для інерційних моментів, тому стрілку можна розділити на три частини: пір’я, тіло та кінчик.
FxIII

1
Проблема полягає в тому, що єдиний імпульс легко обчислити - той, що обумовлений варіацією кута (ви можете бачити, що для отримання двічі параболи залишається лише постійний член). Інша викликана прядіння через заднє перо. Тут затягування пір'я та тертя беруть участь як у перетворенні кінетичної енергії у спінінг, уповільнення стрілки, але додаючи гіроскопічного ефекту. Це впливає на траєкторію і досить складно її моделювати
FxIII

У будь-якому випадку, якщо ви можете пов'язати імпульс зі швидкістю, що задається перовою установкою, все можна обчислити ретельною інтеграцією, але я не впевнений, що ви можете мати закриту форму для рівнянь руху (тобто ви можете отримати алгоритм інтеграції, але не параметричний рівняння).
FxIII

4

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

  1. Те, що ви хочете, - дельта y / дельта 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 * г, але наведений вище код приведе вас до 90% шляху, не роблячи нічого надто шаленого. Benchmark робить це 10 мільйонів разів, якщо вам подобається, це, мабуть, не величезна кількість часу, але відсотково-розумно це досить велика - бібліотеки на Java дуже повільні

Отже, якщо ви хотіли кут, під яким стрілка повинна йти, те, що ви хочете

atan(dy/dx)

І в цьому випадку це буде працювати, тому що dx - це константа. Але загалом dx може бути нульовим, тому зазвичай ви хочете використовувати:

atan2(dy, dx)

що є функцією, спеціально розробленою для цієї роботи.

Але, як я вже говорив, функції бібліотеки на Яві жахливо повільні, і в цьому випадку є кращий спосіб зробити це без того, як нагадав @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" або щось інше; схоже, сильно відрізняється між різними математичними бібліотеками)


Ні, ви не хочете нічого гіперболічного
Dov

Га, ти абсолютно прав. Я одразу зрозумів помилку "використання основної тригонометрії", і пропустив, що функція, яку він використовував, була абсолютно неправильною для решти його підходу.
Тревор Пауелл

Тан () приймає кут. Атан приймає співвідношення сторони трикутника (sin / cos).
3Dave
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.