Фазирование объектов внутри друг друга при столкновении с более чем одним объектом в пользовательском движке 2d физики - PullRequest
2 голосов
/ 17 января 2020

Хорошо, для начала, первое сообщение (с большой проблемой, которую я не знаю, почему это происходит, или какая часть кода запуталась), поэтому, если я делаю что-то не так, пожалуйста, дайте мне знать, что и как это исправить на будущее. Кроме того, я довольно новичок в C ++ и FLTK, поэтому мой код определенно не самый лучший.

Код написан на C++ и использует FLTK для его рендеринга.

Теперь я пытаюсь создать физическую симуляцию между многими кругами, пытаясь имитировать нечто вроде жидкого веселья, где оно действует как вода (или для меня, когда сталкивается solid кругов). на полпути правильно. Физика иногда выглядит хорошо, но в конечном итоге происходит несколько вещей, когда много кругов сидят друг на друге (я не имею в виду, что они занимают одно и то же пространство, больше похоже на бросание шариков в коробка и они сидят друг на друге), им это не очень нравится.

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

2) Они не любят стены. Я не думаю (особенно в углах, где, как кажется, возникает большинство проблем), что, по крайней мере, в углах, заставляет весь слой испугаться (если у меня один слой с толстыми кругами внизу, и один толкается слишком далеко в угол, это волнуется, затем остальные сходят с ума, и внезапно они все ДЕЙСТВИТЕЛЬНО быстро движутся из стороны в сторону).

3) Они никогда не прекращают двигаться, если их сложить поверх одного Во-вторых, они постоянно дрожат или движутся. Я попробовал несколько разных кодов пересечения окружностей из Интернета, и тот, который я сейчас использую, кажется, является наиболее надежным для того, чтобы убедиться, что окружности обычно не пытаются занимать одно и то же пространство, но круги кружатся, когда у них нет выбора (по какой-то причине те, кто над ними, не уходят с дороги, они просто продолжают давить на те, что ниже).

В этот момент Я не знаю, что я делаю правильно, и что я делаю так неправильно, что привело меня к этой точке, и это просто расстраивает меня

* 1 016 * Примечание для кода: я использую многомерный массив для хранения всех данных для кругов, называемых cd[8][C], где C - это круг, данные которого я специально хочу знать; cd[0][C] - радиус окружности C; cd[1][C] - масса круга C; cd[2][C] - это координата X круга C, а cd[3][C] - это координата Y; cd[4][C] и cd[5][C] - скорости круга X и Y C; cd[6][C] и cd[7][C] не используются на данный момент

Теперь из-за беспорядка кода, и мне очень жаль, что это действительно беспорядок, даже после того, как я потратил около часа на то, чтобы привести его в порядок и привести в порядок up Если кто-нибудь может подсказать мне хорошие советы, как сделать это лучше и красивее на будущее, дайте мне знать!

Сначала я включу основную часть сценария; эта часть вызывается из основного прогона l oop и выполняет почти все:

void math() {
collcount = 0;
    for (int i = 0; i < C; ++i) {
        addx1 = 0;
        addy1 = 0;
    //if circle is not registered as fixed
    if (cd[6][i] != 1) {
        for (int i2 = 0; i2 < C; ++i2) {
        //if circle i2 is not the same as the circle i
        if (i2 != i) {
        //check for collisions between circle i and i2
        collide_check(i,i2);
        //if collision detected between circles i and i2
            if (coltf == 1) {
                    //add collision pairs to list to calculate moving them out of eachother later
                    coll[0][collcount] = i;
                    coll[1][collcount] = i2;
                    //run collision maths
                    collide_calc(i,i2);
                    collcount = collcount + 1;      
                    }
                }
            }
        }
    //set temp velocities to new velocity if object collided ever, or keep it the same if it didnt
    if (addx1 == 0 && addy1 == 0) {
        vx[i]=cd[4][i];
        vy[i]=cd[5][i];
    }else {
        vx[i] = addx1;
        vy[i] = addy1;
    }
}
//calculate and move colliding points so they are no longer colliding
for (int i = 0; i < collcount; ++i) {
if (cd[6][coll[0][i]] != 1) {
                        addx1 = 0;
                        addy1 = 0;
                        collide_check(coll[0][i],coll[1][i]);
                        cd[2][coll[0][i]] = cd[2][coll[1][i]]+(cd[0][coll[0][i]]+cd[0][coll[1][i]]+1)*(ccxdis/cdis);
                        cd[3][coll[0][i]] = cd[3][coll[1][i]]+(cd[0][coll[0][i]]+cd[0][coll[1][i]]+1)*(ccydis/cdis);
                    }
}
//apply new velocities
for (int i = 0; i < C; ++i) {
    cd[4][i] = vx[i];
    cd[5][i] = vy[i];
}
//wall collision calculator
for (int i = 0; i < C; ++i) {
if (cd[2][i] > btx+bw) {
                cd[4][i] = -0.9*cd[4][i];
                cd[2][i] = btx+bw;
            }else if (cd[2][i] < btx) {
                cd[4][i] = -0.9*cd[4][i];
                cd[2][i] = btx;
            }
            if (cd[3][i] > bty+bh) {
                cd[5][i] = -0.9*cd[5][i];
                cd[3][i] = bty+bh;
            }else if (cd[3][i] < bty) {
                cd[5][i] = -0.9*cd[5][i];
                cd[3][i] = bty;
            }
        }
//end of math(); function
}

next, здесь часть, которая вычисляет, происходит ли столкновение между кругами i и i2:

void collide_check(int c1, int c2) {
ccxdis = cd[2][c1]-cd[2][c2];
ccydis = cd[3][c1]-cd[3][c2];
cdis = sqrt(ccxdis*ccxdis+ccydis*ccydis);
movdis = (cd[0][c1]+cd[0][c1])-cdis;
//calculate if collide is true
if (cdis < cd[0][c2]+cd[0][c1]) {
    coltf = 1;
} else {coltf = 0;}
}

Затем, наконец, часть, которая вычисляет конечные скорости столкновений:

void collide_calc(int c1, int c2) {
//current collision math script
addx1 = addx1+1*(cd[4][c1]*(cd[1][c1]-cd[1][c2])+(2*cd[1][c2]*cd[4][c2]))/(cd[1][c1]+cd[1][c2]);
addy1 = addy1+1*(cd[5][c1]*(cd[1][c1]-cd[1][c2])+(2*cd[1][c2]*cd[5][c2]))/(cd[1][c1]+cd[1][c2]);
}

Вот полный код, и я сжал его столько, сколько мог, переходя от 400 строк до примерно 160; Если я сделал это неправильно, или я должен поделиться своим полным кодом для других, чтобы проверить по-другому, пожалуйста, дайте мне знать! Спасибо!

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/fl_draw.H>
#include <math.h>
using namespace std;
//number of circles spawned
const int C = 19;
//data defining all circles
float cd[8][C] = {
{10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10},
{5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5},
{100,110,120,130,140,150,160,170,180,120,140,160,180,425,450,475,430,455,480},
{600,590,600,590,600,590,600,590,600,580,580,580,580,600,600,600,570,570,570},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
//replace above data with below data to see problem 2
/*
{10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10},
{5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5},
{100,125,150,175,200,225,250,275,300,325,350,375,400,425,450,475,500,525,550},
{600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600},
{-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5,-5},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
*/
int coll[2][100];
float vx[C];
float vy[C];
int btx = 50;
int bty = btx;
int bw = 800;
int bh = 600;
int coltf, test1, collcount;
float addx1, addy1, cdis, movdis, ccydis, ccxdis, ccxvel, ccyvel;

void collide_check(int c1, int c2) {
ccxdis = cd[2][c1]-cd[2][c2];
ccydis = cd[3][c1]-cd[3][c2];
cdis = sqrt(ccxdis*ccxdis+ccydis*ccydis);
movdis = (cd[0][c1]+cd[0][c1])-cdis;
//calculate if collide is true
if (cdis < cd[0][c2]+cd[0][c1]) {
    coltf = 1;
} else {coltf = 0;}
}

void collide_calc(int c1, int c2) {
//current collision math script
addx1 = addx1+1*(cd[4][c1]*(cd[1][c1]-cd[1][c2])+(2*cd[1][c2]*cd[4][c2]))/(cd[1][c1]+cd[1][c2]);
addy1 = addy1+1*(cd[5][c1]*(cd[1][c1]-cd[1][c2])+(2*cd[1][c2]*cd[5][c2]))/(cd[1][c1]+cd[1][c2]);
}

void math() {
collcount = 0;
    for (int i = 0; i < C; ++i) {
        addx1 = 0;
        addy1 = 0;
    //if circle is not registered as fixed
    if (cd[6][i] != 1) {
        for (int i2 = 0; i2 < C; ++i2) {
        //if circle i2 is not the same as the circle i
        if (i2 != i) {
        //check for collisions between circle i and i2
        collide_check(i,i2);
        //if collision detected between circles i and i2
            if (coltf == 1) {
                    //add collision pairs to list to calculate moving them out of eachother later
                    coll[0][collcount] = i;
                    coll[1][collcount] = i2;
                    //run collision maths
                    collide_calc(i,i2);
                    collcount = collcount + 1;      
                    }
                }
            }
        }
    //set temp velocities to new velocity if object collided ever, or keep it the same if it didnt
    if (addx1 == 0 && addy1 == 0) {
        vx[i]=cd[4][i];
        vy[i]=cd[5][i];
    }else {
        vx[i] = addx1;
        vy[i] = addy1;
    }
}
//calculate and move colliding points so they are no longer colliding
for (int i = 0; i < collcount; ++i) {
if (cd[6][coll[0][i]] != 1) {
                        addx1 = 0;
                        addy1 = 0;
                        collide_check(coll[0][i],coll[1][i]);
                        cd[2][coll[0][i]] = cd[2][coll[1][i]]+(cd[0][coll[0][i]]+cd[0][coll[1][i]]+1)*(ccxdis/cdis);
                        cd[3][coll[0][i]] = cd[3][coll[1][i]]+(cd[0][coll[0][i]]+cd[0][coll[1][i]]+1)*(ccydis/cdis);
                    }
}
//apply new velocities
for (int i = 0; i < C; ++i) {
    cd[4][i] = vx[i];
    cd[5][i] = vy[i];
}
//wall collision calculator
for (int i = 0; i < C; ++i) {
if (cd[2][i] > btx+bw) {
                cd[4][i] = -0.9*cd[4][i];
                cd[2][i] = btx+bw;
            }else if (cd[2][i] < btx) {
                cd[4][i] = -0.9*cd[4][i];
                cd[2][i] = btx;
            }
            if (cd[3][i] > bty+bh) {
                cd[5][i] = -0.9*cd[5][i];
                cd[3][i] = bty+bh;
            }else if (cd[3][i] < bty) {
                cd[5][i] = -0.9*cd[5][i];
                cd[3][i] = bty;
            }
        }
//end of math(); function
}

class Drawing : public Fl_Widget {
  public:
    Drawing(int X,int Y,int W,int H) : Fl_Widget(X,Y,W,H) {}
  private:
    void draw() {
        fl_color(FL_RED);
        fl_line_style(0,5); 
            //draw circles and velocity vectors 
            for (int i = 0; i < C; ++i)
            {
                fl_color(FL_RED);
            fl_circle(cd[2][i],cd[3][i],cd[0][i]);  
            }
            //draw boundaries
            fl_line(btx,bty,btx,bty+bh);
            fl_line(btx,bty+bh,btx+bw,bty+bh);
            fl_line(btx+bw,bty+bh,btx+bw,bty);
            fl_line(btx+bw,bty,btx,bty);
        fl_line_style(0);
    }
};
//main updating/time step portion
void upda(void*) {
    for (int i = 0; i < C; ++i) {
    cd[5][i] = cd[5][i]+1;
    cd[2][i] = cd[4][i]+cd[2][i];
    cd[3][i] = cd[5][i]+cd[3][i];
    }
    math();
    Fl::redraw();
    Fl::repeat_timeout(0.01, upda);
}
int main() {
    Fl_Window *window = new Fl_Window(1000,1000,"FLTK drawing example");
    Drawing canvas(10,10,1000,1000);
 Fl::add_timeout(0.01,upda);
    window->end();
    window->show();  
    return Fl::run();
}
...