Єдність - як реально перемістити корабель до точки в двовимірній грі зверху вниз


14

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

Я був би радий, якщо хтось міг би допомогти мені з цим питанням спасибі рух корабля


1
Як здається, ваше зображення зображує вітрила: Чи варто враховувати вітер? Деякі маневри неможливо виконати з неправильним вітром або його відсутністю.
Ніхто

Більш того, реалістичний вигляд руху парусного судна дійсно вимагає врахування вітру; ігнорування це було б майже як ігнорування сили тяжіння при здійсненні стрибків. Вам не обов'язково потрібна особливо детальна модель вітру, але ви повинні мати на увазі, що ваші кораблі вітром штовхають вітрила (а вода проти їх кіля та керма). Зокрема, кораблі не можуть плисти прямо вітром; їм потрібно буде замість них битись .
Ільмарі Каронен

Зазвичай "точку переходу" можна розділити на фазу обертання та фазу руху вперед. Візьміть той самий заступ, але накладіть на обертання рух вперед. Приклад кожного х раду обертання перемістіть човен вперед на метри
dnk drone.vs.drones

Відповіді:


7

Дивіться цю сторінку

Додавання реалістичних поворотів

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

Для кращого рішення перше, що нам потрібно знати, - це радіус повороту для нашого пристрою. Повернути радіус - досить проста концепція: якщо ви знаходитесь на великій парковці в автомобілі, і поверніть колесо вліво, наскільки воно піде, і продовжуйте рух по колу, радіус цього кола - ваш поворот. радіус. Радіус повороту Volkswagen Beetle буде істотно меншим, ніж у великого позашляховика, а радіус повороту людини буде значно меншим, ніж у великого, що лежить в лісі.

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

На малюнку 5 найкоротшим маршрутом є чітко зелена лінія внизу. Цей шлях виявляється досить простим для обчислення через деякі геометричні відношення, проілюстровані на рисунку 6.

Малюнок 6: Обчислення довжини шляху.

Спочатку обчислюємо розташування точки P, яка є центром нашого поворотного кола і завжди радіусом r від початкової точки. Якщо ми повертаємо направо від нашого початкового напрямку, це означає, що P знаходиться під кутом (початкове_направлення - 90) від початку, так що:

angleToP = initial_direction - 90
P.x = Origin.x + r * cos(angleToP)
P.y = Origin.y + r * sin(angleToP)

Тепер, коли ми знаємо розташування центральної точки P, ми можемо обчислити відстань від P до пункту призначення, показане як h на діаграмі:

dx = Destination.x - P.x
dy = Destination.y - P.y
h = sqrt(dx*dx + dy*dy)

У цей момент ми також хочемо перевірити, чи не місце призначення не в колі, бо якби ми ніколи не могли його дістати:

if (h < r)
    return false

Тепер ми можемо обчислити довжину відрізка d, оскільки ми вже знаємо довжини інших двох сторін правильного трикутника, а саме h і r. Ми також можемо визначити кут за відношенням прямокутного трикутника:

d = sqrt(h*h - r*r)
theta = arccos(r / h)

Нарешті, щоб визначити точку Q, в якій слід залишити коло і почати по прямій, нам потрібно знати загальний кут +, і його легко визначити як кут від P до місця призначення:

phi = arctan(dy / dx) [offset to the correct quadrant]
Q.x = P.x + r * cos(phi + theta)
Q.y = P.y + r * sin(phi + theta)

Наведені вище розрахунки представляють шлях, що повертає праворуч. Лівий шлях можна обчислити точно так само, за винятком того, що ми додаємо 90 до початкового_направлення для обчислення angleToP, а пізніше використовуємо - замість +. Обчисливши обидва, ми просто бачимо, який шлях коротший, і використовуємо той.

Під час реалізації цього алгоритму та подальших алгоритмів ми використовуємо структуру даних, яка зберігає до чотирьох чітких "ліній сегментів", кожен з яких є прямим або кривим. Для описаних тут кривих шляхів використовуються лише два сегменти: дуга, за якою пряма лінія. Структура даних містить члени, які визначають, чи є сегмент дугою чи прямою, довжина сегмента та його вихідне положення. Якщо відрізок є прямою, структура даних також визначає кут; для дуг вказується центр кола, початковий кут на колі та загальний радіан, охоплений дугою.

Після того, як ми обчислили кривий шлях, необхідний для проходження між двома точками, ми можемо легко обчислити наше положення та напрямок у будь-який момент часу, як показано у Лістингу 2.

СПИСОК 2. Обчислення положення та орієнтації в певний час.

distance = unit_speed * elapsed_time
loop i = 0 to 3:
    if (distance < LineSegment[i].length)
        // Unit is somewhere on this line segment
        if LineSegment[i] is an arc
            //determine current angle on arc (theta) by adding or
            //subtracting (distance / r) to the starting angle
            //depending on whether turning to the left or right
            position.x = LineSegment[i].center.x + r*cos(theta)
            position.y = LineSegment[i].center.y + r*sin(theta)
        //determine current direction (direction) by adding or
        //subtracting 90 to theta, depending on left/right
        else
            position.x = LineSegment[i].start.x 
              + distance * cos(LineSegment[i].line_angle)
            position.y = LineSegment[i].start.y
              + distance * sin(LineSegment[i].line_angle)
        direction = theta
        break out of loop
    else
        distance = distance - LineSegment[i].length

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

Востаннє, коли я надав існуючий ресурс, який був вирішенням заданого питання, мене попросили включити вміст посилання на випадок, коли цільовий сайт перестав бути. Тепер мене просять не включати вміст. Складіть свою думку.
Draco18s більше не довіряє SE

3
@ Draco18s: Що ви повинні зробити, це узагальнити основні моменти пов'язаного матеріалу своїми словами. (Або ще краще, дайте відповідь на запитання, виходячи з власного досвіду, і використовуйте лише посилання як допоміжний матеріал або для подальшого читання.) Короткі цитати, як правило, добре, особливо в ситуаціях, коли їх справді неможливо уникнути (наприклад, цитуючи когось точне слова, щоб продемонструвати, що вони дійсно щось сказали), але цитування значної частини статті дійсно виходить за рамки чесного використання .
Ільмарі Каронен

Якщо точка знаходиться в колі, ви можете трохи вийти і повернутися назад.
користувач253751

(Псавт. Також ці два питання на мета.SE.)
Ільмарі Каронен

7

Як просте рішення, як я вже говорив у коментарі, ви можете спробувати цей підхід:

розглянемо фазу, коли ти спрямовуєш корабель у цільовому напрямку, у цій фазі ти застосуєш обертання до ковтка, але й рух вперед. Коли судно вже стикається з ціллю, ви можете застосувати повну швидкість вперед. Я влаштував тест на love2d, тут слідкуйте за способом оновлення корабля.

turnAngSpeed = 0.4 --direction changing speed
ForwordSpeed = 40 -- full forward speed
turnForwordSpeed = ForwordSpeed *0.6 -- forward speed while turning
function ent:update(dt)
            dir = getVec2(self.tx-self.x,self.ty-self.y) -- ship --> target direction (vec2)
            dir = dir.normalize(dir) --normalized                               
            a= dir:angle() - self.forward:angle() --angle between target direction e current forward ship vector
            if (a<0) then
             a=a+math.pi *2 -- some workaround to have all positive values
            end

            if a > 0.05 then -- if angle difference 
                if a < math.pi then
                    --turn right
                    self.forward = vec2.rotate(self.forward,getVec2(0,0),turnAngSpeed * dt)
                else
                    --turn left
                    self.forward = vec2.rotate(self.forward,getVec2(0,0),-turnAngSpeed * dt)
                end             
                --apply turnForwordSpeed
                self.x = self.x+ self.forward.x * turnForwordSpeed * dt
                self.y = self.y+ self.forward.y * turnForwordSpeed * dt
            else 
                --applly ForwordSpeed
                self.x = self.x+ self.forward.x * ForwordSpeed * dt
                self.y = self.y+ self.forward.y * ForwordSpeed * dt
            end
end

введіть тут опис зображення

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


Це хороша відповідь, але це може бути, а може і не бути достатньо реалістичним для ОП. На відміну від, скажімо, автомобілів, кораблі насправді не мають "радіусу повороту": більшість кораблів, що працюють на самому (двигун / людина), по суті можуть увімкнути десятку, в той час як вітрильні кораблі залежать від вітру, і насправді можуть мати негативний ефективний поворот радіус при гальмуванні, в тому сенсі, що поворот ліворуч на вітер може призвести до того, що судно пливе вправо. Те, що у кораблів - це інерція (і перетягування): вони не можуть миттєво повернути або рухатися, і, пересуваючись або повертаючись, знадобиться деякий час і сила, щоб зупинитися. Все-таки мати +1.
Ільмарі Каронен

Дуже дякую за вашу відповідь !!! :) ви, мій герой!
DavidT

@DavidT Потім подумайте, як позначити його / її відповідь прийнятою, якщо вона змогла задовільно вирішити вашу проблему. :)
MAND

-2

Сітчаста система Unity Nav, швидше за все, зробить те, що ви хочете, трохи погравши зі значеннями агента nav.

Морські сітки досить прості у використанні. І лише в налаштуваннях зверху вниз (або принаймні доступні лише для руху x / z)

Сторінка посібника Unity щодо налаштування навігаційної сітки

В основному ви можете використовувати сітку будь-якої форми для випікання області навігації та додавати навігаційні агенти до своїх об'єктів і змушувати їх знаходити свої шляхи навколо навігаційної сітки.


Я вважаю, що відповідь Драко18 також відсутня в цьому плані. Однак ваша не справжня відповідь, а більше коментар.
Ніхто

2
Це гарна пропозиція, але, щоб бути гарною відповіддю, їй потрібна підтримка та інформація щодо впровадження. Будь ласка, додайте інформацію щодо налаштування сіток наві, щоб це було гарною відповіддю. Я думаю, що це намагаються сказати вищезгадані коментарі :)
sirdank
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.