Столкновение прямоугольник ответ

10

У меня трудности с получением подвижного прямоугольника, который сталкивается с несколькими прямоугольниками.

Я использую SFML, и у него есть удобная функция, intersectsкоторая вызывает 2 прямоугольника и возвращает пересечения. У меня есть вектор, полный прямоугольников, с которым я хочу, чтобы мой подвижный прямоугольник сталкивался. Я перебираю это, используя следующий код (p - подвижный прямоугольник).

IsCollidingWithвозвращает bool, но также использует SFML intersectsдля определения пересечений.

while(unsigned i = 0; i!= testRects.size(); i++){
   if(p.IsCollidingWith(testRects[i]){
        p.Collide(testRects[i]);
   }
}

и фактический Collide()код:

void gameObj::collide( gameObj collidingObject ){

 printf("%f %f\n", this->colliderResult.width, this->colliderResult.height);

if (this->colliderResult.width < this->colliderResult.height) {
    // collided on X
    if (this->getCollider().left < collidingObject.getCollider().left ) {
        this->move( -this->colliderResult.width , 0);
    }else {
        this->move( this->colliderResult.width, 0 );
    }

}

if(this->colliderResult.width > this->colliderResult.height){
    if (this->getCollider().top < collidingObject.getCollider().top ) {
        this->move( 0, -this->colliderResult.height);
    }else {     
        this->move( 0, this->colliderResult.height );
    }

}

и IsCollidingWith()код:

bool gameObj::isCollidingWith( gameObj testObject ){
if (this->getCollider().intersects( testObject.getCollider(), this->colliderResult )) {
    return true;
}else {
    return false;
}

Это прекрасно работает, когда Rectв сцене только 1 . Однако, когда их несколько, Rectвозникает проблема, возникающая при двух столкновениях одновременно.

Есть идеи, как правильно с этим бороться? Я загрузил видео на YouTube, чтобы показать мою проблему. Консоль справа показывает ширину и высоту пересечений. Вы можете видеть на консоли, что он пытается рассчитать 2 столкновения одновременно, я думаю, что именно здесь возникает проблема.

Наконец, изображение ниже, похоже, хорошо иллюстрирует мою проблему:

прямоугольник сталкивается с несколькими другими прямоугольниками

рехнувшийся
источник
Ссылка на видео не работает.
XiaoChuan Yu
Обновлены ли colliderобъекты, возвращенные ?? this->getCollider()this->move()
XiaoChuan Yu
Не могли бы вы добавить больше информации, пожалуйста? в чем именно проблема?: Кажется, видео на YouTube показывает предсказуемое поведение, и на сцене есть только один другой прямоугольник.
Wackidev

Ответы:

3

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

Простым решением для этого является проверка только для вертикального столкновения, исправьте это, затем проверьте еще раз для горизонтального столкновения. Если вы не падаете и не пытаетесь сползти по стене, в этом случае вы сначала должны проверить горизонтальные столкновения. Как вы знаете, когда проверить, что первым? Вы можете сделать это в зависимости от того, какой компонент вашей скорости больше (если горизонтальное движение больше, сначала проверьте вертикальные столкновения, в противном случае проверьте горизонтальные столкновения).

Что может быть еще проще - и более производительным - вместо этого создать список границ для вашего мира. То есть для ваших боксов, составляющих пол, установите флаг, указывающий, что только их верхний край действительно сталкивается, а затем игнорируйте столкновения с другими краями. Вы не сможете использовать для этого процедуру коллизий SFML, но, честно говоря, простейшие коллизии - это, возможно, самый простой фрагмент кода, который вы когда-либо пишете в игре. Этот метод работает особенно хорошо, если ваш мир выровнен по сетке. Я бы ознакомился с превосходными учебниками по Metanet (http://www.metanetsoftware.com/technique.html/) для этой техники.

Вы столкнетесь со многими другими проблемами, пытаясь создать простую 2D-платформерную игру, как вы. Безусловно, лучший ресурс, который я видел в последнее время, это следующий, который вы должны прочитать, а затем прочитать снова:

http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/

Шон Миддледич
источник
1

Возможно, простым решением было бы проверить наличие столкновений с каждым прямоугольником и двигаться назад, в противоположном направлении движения, пока столкновения не будут обнаружены. Если это решит проблему, реализация должна быть довольно простой.

AREX
источник
+1, я на самом деле написал об этом здесь: gamedev.stackexchange.com/questions/38252/…
Маркус фон Броади
0

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

Надеюсь, это полезно?

james82345
источник
0

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

bool collided = true;
while(collided) {
   collided = false
   while(unsigned i = 0; i!= testRects.size(); i++){
      if(p.IsCollidingWith(testRects[i]){
         collided = true
         p.Collide(testRects[i]);
      }
   }
}

Обратите внимание, что существуют ситуации, когда это приведет к бесконечному циклу (представьте себе ситуацию, когда перемещение рамки из столкновения приводит к другой коллекции, а перемещение рамки из этого столкновения перемещает ее обратно в ту же позицию столкновения, что и раньше)

Мэтью Р
источник