Я пытаюсь реализовать обнаружение столкновений в своей игре, но то, что казалось легким, сначала превратилось в монстра, с которым я не могу справиться без какой-либо помощи.Обнаружение столкновения 2D-группы
В какой-то момент игра будет RTS, но сейчас это всего лишь куча юнитов, которые можно передать перемещению в определенное место на экране. Но единицы продолжают исчезать только в одном блоке, поэтому я определил ограничивающие поля для каждого блока и испытал на столкновение между единицами после их перемещения в игровом цикле, чтобы отделить их.
Это не сработало, потому что я не реализовал способ узнать, что конкретное устройство, которое я перемещаю, не занимает какое-то другое место (которое я уже повторил).
Я попытался сохранить позиции (или регионы), которые уже заняты, чтобы сдвинуться там, где нет единиц. Но это также не работает в некоторых случаях, например, когда блок перемещается в любом из четырех углов экрана, он не может выходить за пределы экрана и также не может занимать регионы, занятые подразделениями, с которыми он сталкивается.
Я по-прежнему уверен, что я слишком усложняю то, что можно сделать легко с другим подходом.
Каждый блок имеет собственную ограничительную сферу, положение, вектор направления и вектор скорости.
class Unit {
friend class Party;
protected:
float xPos, yPos;
float destX, destY;
float detectionRange;
Vector *vel;
Vector *dest;
int dir;
int offset;
int width, height;
Circle *circle; //Bounding Circle
...
public:
...
};
//Collision Checking
void Party::checkCollisions() {
bool noCol;
float dx, dy;
Circle *mCircle = NULL;
Circle *sCircle = NULL;
do {
noCol = true;
for(int i=0; i<numUnits; i++) {
mCircle = units[i]->getCircle();
for(int j=0; j<numUnits; j++) {
if(j==i) {
continue;
}
sCircle = units[j]->getCircle();
if(mCircle->isColliding(sCircle)) {
noCol = false;
mCircle->getShifts(sCircle, &dx, &dy);
units[i]->shift(dx, dy);
units[j]->shift(-dx, -dy);
}
}
}
} while(noCol == false);
}
//IsColliding. This is overriden for isColliding(Circle *circle), but here
//you see the actual algorithm.
bool Circle::isColliding(float X, float Y, int rad) {
float mag = sqrt((X-x)*(X-x) + (Y-y)*(Y-y));
if(mag <= (radius + rad)){
return true;
}
return false;
}
//Get Shifts
void Circle::getShifts(Circle *c, float *dx, float *dy) {
float x1 = x - c->x;
float y1 = y - c->y;
if(x1 > -1 && x1 < 1) {
x1 = 1;
}
if(y1 > -1 && y1 < 1) {
y1 = 1;
}
*dx = x1/fabs(x1);
*dy = y1/fabs(y1);
}
This video показывает, что у меня до сих пор, но это очевидно, что это крайне сглаженным и имеет излишние движения единицы.
Я хочу, чтобы при соединении двух или более единиц они стекались естественным образом. Но все подразделения не будут формировать одну стаю во все времена. Поскольку каждый блок имеет различный диапазон обнаружения, можно отделить один или несколько единиц от стаи. Я хочу это, чтобы позже я мог выбирать и перемещать разные группы единиц.
Я попробую, спасибо за ваш ответ и ссылку. Есть ли какой-то способ быть уверенным, как только я убедился, что один конкретный блок не участвует в каких-либо столкновениях, что я не нажимаю еще одну единицу на первый блок? Например, я повторяю свой список единиц, рассматривая основной блок, с которым я проверяю столкновения. Я перемещаю основной блок после проверки столкновения с первой итерацией. Я нахожу, что он также сталкивается со вторым блоком в последовательности, и я перемещаю его так, что он снова находится в месте расположения первого блока, который я проверил. Какой метод я использую, чтобы этого избежать? – Rikonator
@Rikonator: Шаг № 3 применяется ко всем устройствам. Вы удаляете все единицы (на ** небольшое ** расстояние) от столкновения на этом шаге, а затем повторяете его, пока никакие единицы не столкнутся ни с чем, или пока не закончите шаги. Если у вас заканчиваются шаги, это означает, что вы пытаетесь заполнить большое количество единиц в очень маленьком пространстве. Было научное название этого метода, но я забыл его. Я думаю, что это было связано с решателями IK - инкрементным решателем или чем-то еще. Другое дело, что вы должны иметь в виду, что использование этих единиц метода может превышать их максимальную скорость (если они есть) при определенных обстоятельствах. – SigTerm
@Rikonator: «Какой метод я использую, чтобы избежать этого?» Этот метод уже справляется с этой проблемой. Просто обработайте ВСЕ устройства на шаге №3, оттолкните их ВСЕ от их непосредственного столкновения на * маленьком * расстоянии, даже если это не сразу устранит столкновение, а затем повторите весь процесс 50 раз или пока не произойдет столкновение. Прекрасно работает, когда ваши подразделения используют ограничивающие сферы для обнаружения столкновений. С коробками результаты могут быть хуже. – SigTerm