Какой алгоритм подойдет для описания полета насекомого?

Суть задачи. Пишу игру IOS Sprite Kit. Необходимо реализовать хаотичный полёт насекомого. Сейчас получилось вот так:
fb104a7a0a144609969297785d3a5121.jpg
Это не похоже на полёт насекомого
Необходимо чтобы траектория полёта была, примерно, такая:
fa783d5e6de64b1fa5f670ae10f94294.jpg
Я понимаю, что через произвольные точки необходимо строить кривые, но никак не могу сообразить как определять корректно случайные точки, чтобы можно было построить нормальную кривую. Плюс как быть с виражами? Ещё надо контролировать чтобы насекомое не покидало границ экрана. Одновременно их летает несколько. И самое грустное, что насекомое это не абстрактная точка, а она имеет чёткие очертания, т.е. голова должна быть направлена в направлении движения. Спрайт постоянно нужно будет вращать. Подскажите в какую сторону копать? Может быть в swift есть другие какие-то решения подобных задач? Может другим способом её нужно решать? Пока смотрел кривую Безье, и что-то никак не адаптирую её к данной задаче. Вообщем, буду рад любым советам.
  • Вопрос задан
  • 3279 просмотров
Пригласить эксперта
Ответы на вопрос 8
sergiks
@sergiks Куратор тега Алгоритмы
♬♬
Можно сделать цепочку преследования: к случайной точке тянется одна, к ней другая, и т.д., а последняя – муха.

Очередную точку ставить на плоскости случайно, в любом месте внутри допустимой области. Эта точка – цель, к которой стремится следующая, невидимая точка: каждый следующий кадр её координаты изменяются на k * векторИзТекущегоПоложения-в-Цель:
x = x + k * (xTarget - x);
y = y + k * (yTarget - y);

Так «преследователь» замедляется, по мере приближения к цели, никогда её не достигая.

Эта невидимая точка – не одна. К ней, как к цели, стремится следующая. К той ещё одна. Наконец, сама муха по этому закону стремится к хвосту этой цепи - очередной точке.

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

Сделал рабочий пример.

Можно поменять алгоритм и сделать, скажем, линейную скорость постоянной. Или случайно варьировать параметры k и D – от этого поменяется скорость и траектория от плавной ближе к ломаной.
Ответ написан
Комментировать
@BorisKorobkov
Web developer
Существует как минимум десяток типов полета. Вам какой из них нужен?
Ответ написан
@SolidMinus
т.е. голова должна быть направлена в направлении движения


Направление движения будет вектор = касательная к кривой в данной точке * (вектор скорости/ значение скорости)

mathserfer.com/theory/kiselev2/node64.html
Вот тут есть как ее найти.

Производная в точке программно вычисляется через определение производной отношение разницы значений, см. определение частной производной через предел и как через нее найти полную производную.

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


Чтобы траектория была гладкая - надо генерировать больше точек. Чтобы были дуги - использовать тригонометрические функции.

Главное правило, которое поможет:
* нужна цикличность - cos/sin etc
* нужно сглаживание между некоторым границами - sigmoid
* нужен рост - функции высшего порядка

В данном случае - нужна 2d функция, которая будет принимать x, y и возвращать z, подобная картина будет ее проекцией на 2d-плоскость

Берешь функцию:

f(x(t1), y(t1)) = a*cos(x(t1))^k + b * sin(y(t1))^t + O, где a,b,k,t, O - переменные, которые рандомно подбираешь для придания уникального вида, t1 - время, f(x(t1),y(t1)) - высота мухи по z, в зависимости от ее координат по x,y

Я хз как привести практический пример, поэтому приведу в python, некая гипотетическая пьяная муха или обдолбанный раптором комар
Nk9X0Bh.png8935555cc6f04cd8a21a52a0bb294fb6.PNG
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def func(x, y, a, b, t, k, O):
    return a * np.power(np.sin(x), t) + b * np.power(np.cos(y), k) + O

t = 5
k = 5

theta = np.linspace(-4 * np.pi, 4 * np.pi, 1000)
time = np.linspace(0, 5, num=1000)

a = 10
b = 10

x = time * np.sin(theta) + a
y = time * np.cos(theta) + b

z = np.asarray([func(x[i], y[i], a, b * i, t, k, 100) for i in range(len(x))])


plt.plot(x, z, 'r')
plt.show()

fig = plt.figure()
ax = fig.gca(projection='3d')


ax.plot(x, y, z)


Короче вектор в каком направлении двигаться ясен. Тупо перебирай функции генерации x, y и z пока не найдешь нужную красотульку
Ответ написан
Комментировать
@gigi1988 Автор вопроса
Вспомнил, что забыл отписаться по решению данной задачи.
Решил в SWIFT ее следующим образом. Строим N-ое количество точек, строим сплайн через эти точки. Перемещаем объект с помощью SKAction.follow, она позволяет задавать ориентацию по направлению движения, по завершению строим новые точки. Более плавное перемещение можно достичь генерируя точки без резких отклонений от текущего направления движения, чтобы объект не менял резко направления движения в противоположную сторону. Всем спасибо за помощь
func Yellow()
    {
        var object = self.childNode(withName: "//yellow") as! SKSpriteNode
        yellowMove(object: object)
    }

    func yellowMove(object obj: SKSpriteNode)
    {
         var chain = [CGPoint]()
        chain.append(CGPoint(x:obj.position.x,y:obj.position.y))
       // генерируем 6 случайных точек.
        for var i in (1..<6) {
            chain.append(CGPoint(x:getRndX(),y:getRndY()))
        }
         // Строим сплайн через эти точки
        let ground = SKShapeNode(splinePoints: &chain,count: chain.count)
        let anim=SKAction.follow(ground.path!, asOffset: false, orientToPath: true, duration: 10)
        // по завершении перемещения, опять запускаем функцию
        obj.run(anim,completion:{
            self.yellowMove(object: obj)
        })
    }
Ответ написан
Комментировать
x67
@x67
помимо сплайнов, есть еще много других видов фигур. Простейший вариант - задавайте точку назначения рандомно и для плавности движения используйте формулу newpos=K*pos+(1-K)posz, где pos - текущая позиция в векторной форме, posz - заданная позиция. Чем больше К, тем более плавными будут кривые, но без забросов. Можно усложнить для красоты, но тогда придется разбираться в дифф.урах.
Ответ написан
Комментировать
GavriKos
@GavriKos
А по моему намного лучше сделать десяток предопределенных карт траекторий, с точками перехода с одной траектории на другую.
Чистый рандом - достаточно злобная вещь, потому что неконтролируемый.
Ответ написан
@Xeli
Задача очень похожа на алгоритм сглаживания узлов. Я думаю самое простое что вы можете сделать это написать разработчикам Inkscape (открытый векторный редактор), и попросить их указать куда копать, чтобы реализовать подобную фичу (если возьмете их код, то игру придется публиковать под GPL), ради интереса скачайте Inkscape натыкайте прямую с произвольным количеством узлов, а затем сгладьте их. Вы удивитесь как прямые палки превратятся в изящные кривые, причем кривизну можно регулировать "рычагами" (т.е в коде есть переменные отвечающие за это). Так же есть кривая Спиро. Она больше подходит для вашей задачи чем Безье. Вот тут прямая без
сглаживания
d04373919e2c46cb8d0674f4b1bcb100.png

Она же со сглаженными
точками
2638e604ce584a26a757d3387ebaf34f.png
Ответ написан
Комментировать
@AlexSku
не буду отвечать из-за модератора
Ограничения на скорость угла поворота (голова спрайта всегда направлена по вектору скорости).
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы