Обновление: выяснилось, что я использовал радиус в качестве диаметра, поэтому mtd сверхкомпенсировал.
Другое обновление: причина, по которой мои шары перекрываются, по-видимому, в том, что для каждого столкновения существует только одна проверка. После некоторых исследований некоторые говорят, что одним из способов предотвращения наложения на накопление объектов является рекурсивное выполнение проверки столкновения. Это работает до некоторой степени, и я подозреваю, что это работало бы еще лучше, если бы физика была намного более точной. Я обновлю еще раз, если найду больше решений. Кроме того, я использую код коррекции столкновений Симукала.
Привет, StackOverflow. Я недавно написал программу обработки, имитирующую физику мяча. В принципе, у меня есть большое количество шаров (1000) с включенной гравитацией. Обнаружение работает отлично, но моя проблема в том, что они начинают вести себя странно, когда они отскакивают от других шаров во всех направлениях.
Я уверен, что это связано с обработкой. По большей части я использую код Джея Конрода. Одна часть, которая отличается, это
if (distance > 1.0)
return;
который я изменил на
if (distance < 1.0)
return;
поскольку коллизия даже не была выполнена с первым битом кода, я предполагаю, что это опечатка.
Шары перекрываются, когда я использую его код, а это не то, что я искал. Моя попытка исправить это состояла в том, чтобы переместить шары к краю друг друга:
float angle = atan2(y - collider.y, x - collider.x);
float distance = dist(x,y, balls[ID2].x,balls[ID2].y);
x = collider.x + radius * cos(angle);
y = collider.y + radius * sin(angle);
Это не правильно, я почти уверен в этом.
Я попробовал алгоритм коррекции в предыдущей теме «шарик к шарику»:
// get the mtd
Vector2d delta = (position.subtract(ball.position));
float d = delta.getLength();
// minimum translation distance to push balls apart after intersecting
Vector2d mtd = delta.multiply(((getRadius() + ball.getRadius())-d)/d);
// resolve intersection --
// inverse mass quantities
float im1 = 1 / getMass();
float im2 = 1 / ball.getMass();
// push-pull them apart based off their mass
position = position.add(mtd.multiply(im1 / (im1 + im2)));
ball.position = ball.position.subtract(mtd.multiply(im2 / (im1 + im2)));
за исключением того, что моя версия не использует векторы, и вес каждого шара равен 1. Полученный код, который я получаю, таков:
PVector delta = new PVector(collider.x - x, collider.y - y);
float d = delta.mag();
PVector mtd = new PVector(delta.x * ((radius + collider.radius - d) / d), delta.y * ((radius + collider.radius - d) / d));
// push-pull apart based on mass
x -= mtd.x * 0.5;
y -= mtd.y * 0.5;
collider.x += mtd.x * 0.5;
collider.y += mtd.y * 0.5;
Кажется, этот код слишком корректирует коллизии. Что не имеет смысла для меня, потому что никоим образом я не изменяю значения x и y каждого шара, кроме этого.
Какая-то другая часть моего кода может быть неправильной, но я не знаю. Вот фрагмент всей обработки столкновения шара с шаром, которую я использую:
if (alreadyCollided.contains(new Integer(ID2))) // if the ball has already collided with this, then we don't need to reperform the collision algorithm
return;
Ball collider = (Ball) objects.get(ID2);
PVector collision = new PVector(x - collider.x, y - collider.y);
float distance = collision.mag();
if (distance == 0) {
collision = new PVector(1,0);
distance = 1;
}
if (distance < 1)
return;
PVector velocity = new PVector(vx,vy);
PVector velocity2 = new PVector(collider.vx, collider.vy);
collision.div(distance); // normalize the distance
float aci = velocity.dot(collision);
float bci = velocity2.dot(collision);
float acf = bci;
float bcf = aci;
vx += (acf - aci) * collision.x;
vy += (acf - aci) * collision.y;
collider.vx += (bcf - bci) * collision.x;
collider.vy += (bcf - bci) * collision.y;
alreadyCollided.add(new Integer(ID2));
collider.alreadyCollided.add(new Integer(ID));
PVector delta = new PVector(collider.x - x, collider.y - y);
float d = delta.mag();
PVector mtd = new PVector(delta.x * ((radius + collider.radius - d) / d), delta.y * ((radius + collider.radius - d) / d));
// push-pull apart based on mass
x -= mtd.x * 0.2;
y -= mtd.y * 0.2;
collider.x += mtd.x * 0.2;
collider.y += mtd.y * 0.2;