Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Форум / Правильный расчет будущих позиций движущегося тела.

Правильный расчет будущих позиций движущегося тела.

Поделиться

Страницы: 1 2 Следующая

ПлотникНовичокwww30 окт. 201723:02#0
Здравствуйте. Треугольник движется под действием притяжения круга. Рассчитываются будущие позиции и рисуются. На рисунке треугольник вращается по почти круговой орбите, но траектория уходит вдаль и вращается вместе с ним. Число "500" это количество будущих позиций. Как правильно рассчитать?
        ...........
        planet1.draw(canvas);
        
        ship.draw(canvas, mouseX, mouseY);
        for(int i = 0; i <= 500; i++)
        {
            double dx = planet1.pos.x - ship.pos.x;
            double dy = planet1.pos.y - ship.pos.y;
            double d2 = (dx*dx)+(dy*dy);
            double d = (double) ((float) Math.sqrt(d2));
            double F = (0.02 * planet1.mass * ship.mass) / d2;
            double Fx = (F * dx) / d;
            double Fy = (F * dy) / d;
            double aX = Fx/ship.mass;
            double aY = Fy/ship.mass;
            vX = aX * (deltaTime*i)/1000;
            vY = aY * (deltaTime*i)/1000;
            pX = ship.pos.x + (vX+ship.vel.x) * (deltaTime*i)/1000;
            pY = ship.pos.y + (vY+ship.vel.y) * (deltaTime*i)/1000;
            
            paint.setColor(Color.YELLOW);
            canvas.drawPoint((float)pX, (float)pY, paint);
        }
        .................

т1 | Правильный расчет будущих позиций движущегося тела.

Правка: 30 окт. 2017 23:05

FordPerfectПостоялецwww30 окт. 201723:48#1
Плотник
Вплоть до
double aY = Fy/ship.mass;
более-менее ок, а дальше фиг пойми что.

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

Откуда взят коэффициент 1000, и что он значит?

        ...........
        planet1.draw(canvas);
        
        ship.draw(canvas, mouseX, mouseY);
        double sx=ship.pos.x;
        double sy=ship.pos.y;
        double vx=ship.vel.x;
        double vy=ship.vel.y;
        for(int i = 0; i <= 500; i++)
        {
            double dx = planet1.pos.x - sx;
            double dy = planet1.pos.y - sy;
            double d2 = (dx*dx)+(dy*dy);
            double d = (double) ((float) Math.sqrt(d2));
            double F = (0.02 * planet1.mass * ship.mass) / d2;
            double Fx = (F * dx) / d;
            double Fy = (F * dy) / d;
            double aX = Fx/ship.mass;
            double aY = Fy/ship.mass;
            vx+=aX*deltaTime;
            vy+=aY*deltaTime;
            sx+=vx*deltaTime;
            sy+=vy*deltaTime;
            paint.setColor(Color.YELLOW);
            canvas.drawPoint((float)sx, (float)sy, paint);
        }
        .................
метод отвратный с т. з. точности и надёжности, но для начала надеюсь сойдёт.
ПлотникНовичокwww31 окт. 20179:51#2
FordPerfect, Спасибо за ответ. Число 1000 это для уменьшения deltaTime (deltaTime/1000).
В вашем случае рисуется прямая линия, показывающая направление и величину скорости. А необходимо что бы эта линия загибалась под действием притяжения планеты, т.е. указывало бы, где в будущем пройдет корабль.
SuslikМодераторwww31 окт. 201714:39#3
Плотник
> В вашем случае рисуется прямая линия, показывающая направление и величину
> скорости. А необходимо что бы эта линия загибалась под действием притяжения
> планеты, т.е. указывало бы, где в будущем пройдет корабль.
ну так если у тебя коэффициенты какие попало выставлены, то, разумеется, линия может выродиться в прямую. он всё правильно написал. выбирай нормальую массу для взаимодествующих тел, если тебе нужно варьировать кривизну траектории.

> Число 1000 это для уменьшения deltaTime (deltaTime/1000)
well, duh. вопрос в том, откуда это "уменьшение" взялось. при любом моделировании физики необходимо понимать, какие параметры определяются физическими законами, а какие — фактически, пользователем. так вот время — это один из тех параметров, ход которого за исключением особых случаев неизменен. вид используемых формул — тоже. а вот варьировать массы, взаимные расположения, скорости, можно сколько влезет.

Правка: 31 окт. 2017 14:41

ПлотникНовичокwww31 окт. 201719:04#4
Неправильно выразился, это не уменьшение, а перевод deltaTime в секунду. deltaTime инициализуется в миллисекундах - deltaTime = 5. Поэтому она делится на 1000. Можно сразу в секундах deltaTime = 0.005. Скорость в пикселях в секунду.
Ускорение корабля насчитывается по: а = F/m, F = (g * M * m)/(d*d). Где М = 125000000(масса планеты), m = 1000(масса корабля), g = 0.02(экспериментально подобран для эти масс и скоростей).
Имеются:
class Planet
{
    ........
}
class Ship
{
    .....
    void update()
    {
        pos.x += vel.x*deltaTime;
        pos.y += vel.y*deltaTime;
    }
    void addForseAcceleratoin(Planet p, double g, long deltaTime)
    {
        double dx = p.pos.x - pos.x;
        double dy = p.pos.y - pos.y;
        double d2 = (dx*dx)+(dy*dy);
        double d = (double) ((float) Math.sqrt(d2));
        double F = (g * p.mass * mass) / d2;
        double Fx = (F * dx) / d;
        double Fy = (F * dy) / d;
        acc.x = Fx/mass;
        acc.y = Fy/mass;
        vel.x += acc.x * deltaTime;
        vel.y += acc.y * deltaTime;
    }
}
void main()
{
    ......
    void draw()
    {
        planet.draw();
        ship.draw();
    }

    void update()
    {
        ....
        ship.update();
        .....
    }
    ....
}

Все нормально работает. Все коэффициенты для этой системы подобраны правильно: корабль движется под притяжением планеты. Можно выйти на орбиту вокруг планеты, сесть на нее, и стартовать с нее.
Но если после ship.update() добавить for(int i = 0; i < 500; i++) {.........}, всё остаётся без изменений: корабль летает вокруг планеты, можно сесть на нее и т.д. Просто точки рисуются не там, где должны быть будущие позиции корабля. То есть будущие позиции рассчитываются неправильно. Формула та же, F=(g*M*m)/(d*d), но нужно рассчитать для будущих позиций.
Необходимо реализовать что то примерно как в коде ниже, используя "i", т.к "i" это будущая позиция. И корабль не должен использовать данные из это функции for(){}, у него уже есть свои update() и addForseAcceleratoin().

    for(int i = 0; i < 500; i++)
    {
        double dx = planet.pos.x - ship.pos[i].x;
        ship.acc[i].x = F[i]/ship.mass;
        ship.vel[i].x += ship.acc[i].x * delaTime;
        ship.pos[i].x += v[i].x * deltaTime;
        ....
    }
deltaTime не изменяется с течением времени, что в настоящем, что в будущем равен 0.005.
i - это количество позиций "наперед" во времени.
Вот в этом месте у меня и загвостка.
Для прямолинейного равномерного движения я могу рассчитать и нарисовать траекторию, так как вектор вектор скорости неизменен. А в данном случае сила действующая от планеты, следовательно и скорость изменяются от каждого "i" к "i+1".

Пробовал так:

        index = 500;
        Vector futurePos[] = new Vector[index];
        Vector futureVel[] = new Vector[index];
        Vector futureAcc[] = new Vector[index];
        double sx = ship.pos.x;
        double sy = ship.pos.y;
        for(index = 0; index < index; index++)
        {
            //newPos[i].x = ship.pos.x;
            //newPos[i].y = ship.pos.y;
            double dx = planet1.pos.x - sx;
            double dy = planet1.pos.y - sy;
            double d2 = (dx*dx)+(dy*dy);
            double d = (double) ((float) Math.sqrt(d2));
            double F = (0.02 * planet1.mass * ship.mass) / d2;
            double Fx = (F * dx) / d;
            double Fy = (F * dy) / d;
            futureAcc[index].x = Fx/ship.mass;
            futureAcc[index].y = Fy/ship.mass;
            futureVel[index].x += futureAcc[index].x * deltaTime;
            futureVel[index].y += futureAcc[index].y * deltaTime;
            sx += futureVel[index].x * deltaTime;
            sy += futureVel[index].y * deltaTime;
            deltaTime += deltaTime;
            
            this.paint.setColor(Color.YELLOW);
            canvas.drawPoint((float)sx, (float)sy, this.paint);
        }
тоже ничего.

Правка: 31 окт. 2017 20:16

SuslikМодераторwww1 ноя. 20172:52#5
Плотник
> Неправильно выразился, это не уменьшение, а перевод deltaTime в секунду.
> deltaTime инициализуется в миллисекундах - deltaTime = 5. Поэтому она делится
> на 1000. Можно сразу в секундах deltaTime = 0.005. Скорость в пикселях в
> секунду.
> Ускорение корабля насчитывается по: а = F/m, F = (g * M * m)/(d*d). Где М =
> 125000000(масса планеты), m = 1000(масса корабля), g = 0.02(экспериментально
> подобран для эти масс и скоростей).
> Имеются:
окей, это уже здравые рассуждения.

> for(index = 0; index < index; index++)
а это — нет. вообще цикл — ерунда какая-то. для того, чтобы отрисовать будущую траекторию, проще всего сделать копию своей системы и для неё смоделировать нужный интервал времени, отрисовывая на ходу.

MANABПостоялецwww1 ноя. 201714:34#6
        ...........
        planet1.draw(canvas);
        
        ship.draw(canvas, mouseX, mouseY);

        pX = ship.pos.x; //текущее значение
        pY = ship.pos.y; //текущее значение
        vX = ship.vel.x; //текущее значение 
        vY = ship.vel.y; //текущее значение 

        for(int i = 0; i <= 500; i++)
        {
            double dx = planet1.pos.x - ship.pos.x;
            double dy = planet1.pos.y - ship.pos.y;
            double d2 = (dx*dx)+(dy*dy);
            double d = Math.sqrt(d2);
            double A = (0.02 * planet1.mass) / d2; //сразу ускорение считаем
            double aX = (A * dx) / d;
            double aY = (A * dy) / d;
            double dvX = aX * (deltaTime)/1000; // дельта
            double dvY = aY * (deltaTime)/1000; // дельта
            double dpX = (vX + dvX/2) * (deltaTime)/1000; // дельта, dvX/2 - средняя скорость на отрезке, т.к. от 0 до dvX прирост скорости
            double dpY = (vY + dvY/2) * (deltaTime)/1000; // дельта, dvY/2 - средняя скорость на отрезке, т.к. от 0 до dvY прирост скорости
            vX += dvX; // прибавление к прошлым значениям
            vY += dvY; // прибавление к прошлым значениям
            pX += dpX; // прибавление к прошлым значениям
            pY += dpY; // прибавление к прошлым значениям
            
            paint.setColor(Color.YELLOW);
            canvas.drawPoint((float)pX, (float)pY, paint);
        }
        .................
ИМХО, как то так должно быть

Правка: 1 ноя. 2017 14:35

ПлотникНовичокwww1 ноя. 201718:38#7
Похоже в самом движении корабля ошибка...хотя где там может быть ошибка в функции addForseAcceleratoin(Planet p, double g, long deltaTime).
Вот видео, корабль вывел на круговую орбиту. Если дать газу дуга из точек выпрямляется, если уменьшить скорость - дуга больше загибается. Ну, явно видно, что, что то не так)
http://www.gamedev.ru/files/?id=129013
Все как на картинке выше.

Правка: 1 ноя. 2017 18:42

ПлотникНовичокwww1 ноя. 201719:23#8
Всем спасибо, к каждому прислушивался. Окончательный вариант выглядит так:
        double px = ship.pos.x;
        double py = ship.pos.y;
        double vx = ship.vel.x;
        double vy = ship.vel.y;
        double ax = ship.acc.x;
        double ay = ship.acc.y;
        for(int i=0; i<500; i++)
        {
            double dx = planet1.pos.x - px;
            double dy = planet1.pos.y - py;
            double d2 = (dx*dx)+(dy*dy);
            double d = Math.sqrt(d2);
            double A = (0.02 * planet1.mass) / d2;
            
            ax = (A * dx) / d;
            ay = (A * dy) / d;
            vx += ax * deltaTime/1000;
            vy += ay * deltaTime/1000;
            px += vx * deltaTime/1000;
            py += vy * deltaTime/1000;
            
            paint.setColor(Color.YELLOW);
            canvas.drawPoint((float)px, (float)py, paint);
        }
Надо было скопировать текущие значения позиции, скорости и Ускорения.
Screenshot_2017-11-01-20-47-36~01 | Правильный расчет будущих позиций движущегося тела.

Правка: 1 ноя. 2017 20:52

MANABПостоялецwww2 ноя. 201710:23#9
            vx += ax * deltaTime/1000;
            vy += ay * deltaTime/1000;
            px += vx * deltaTime/1000;
            py += vy * deltaTime/1000;
Я уже указывал, что px и py так считать не совсем корректно, т.к. за deltaTime/1000 у тебя скорость изменится от vx до vx + ax * deltaTime/1000 => т.к. скорость изменяется равномерно надо брать для вычисления позиции среднюю скорость на участке, т.е. vx + (ax / 2) * deltaTime/1000 и тоже самое для y.
SuslikМодераторwww2 ноя. 201710:28#10
MANAB
всё прекрасно так можно считать, до величины первого порядка малости вообще в любом порядке результат будет правильный. для величин второго порядка малости всё несколько хитрее, потому что если правильным образом трактовать величины, например, считать, что у тебя скорость считается для полуцелых интервалов времени, а позиции — для целых, то формулы могут оказаться правильными и для второго порядка, даже без учёта дополнительных членов при постоянном шаге по времени.

например, вот эти три формулы математически эквивалентны, в чём нетрудно убедиться, сдвинув время на 1/2 шага:
1)
Изображение
2)
Изображение
3)
Изображение

таким образом, несмотря на то, что вторая формула выглядит самой умной, она даёт результат, тождественно равный первой формуле, если просто переобозначить величины. подробнее: https://en.wikipedia.org/wiki/Leapfrog_integration

Правка: 2 ноя. 2017 10:53

MANABПостоялецwww2 ноя. 201710:51#11
Спасибо, почитаю. Всегда приятно послушать умного человека)
FordPerfectПостоялецwww2 ноя. 201717:50#12
>для полуцелых интервалов времени
Для полуцелых моментов.
kiparПостоялецwww2 ноя. 201718:11#13
Если планета только одна, то можно ничего не интегрировать, а сразу считать параметры орбиты. Траектория всегда будет коническим сечением.
FordPerfectПостоялецwww3 ноя. 20170:53#14
kipar
Если параметризовать временем (показать следующую секунду пути) - коническое сечение не обязательно сильно поможет. Докуда дугу рисовать?

Страницы: 1 2 Следующая

/ Форум / Программирование игр / Физика

2001—2017 © GameDev.ru — Разработка игр