Odpowiedź prostokąta zderzenia

10

Mam trudności z uzyskaniem ruchomego prostokąta, który mógłby zderzyć się z więcej niż jednym prostokątem.

Używam SFML i ma przydatną funkcję o nazwie, intersectsktóra bierze 2 prostokąty i zwraca przecięcia. Mam wektor pełen prostokątów, z którym chcę, aby mój ruchomy prostokąt kolidował. Pętlę przez to za pomocą następującego kodu (p jest ruchomym prostokątem).

IsCollidingWithzwraca bool, ale także używa SFML intersectsdo opracowania skrzyżowań.

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

i rzeczywisty Collide()kod:

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 );
    }

}

a IsCollidingWith()kod to:

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

Działa to dobrze, gdy Rectna scenie jest tylko 1 . Jednak, gdy jest ich więcej niż jeden Rect, powoduje to problem podczas opracowywania 2 kolizji jednocześnie.

Masz pomysł, jak sobie z tym poradzić? Przesłałem film na YouTube, aby pokazać mój problem. Konsola po prawej stronie pokazuje szerokość i wysokość skrzyżowań. Na konsoli widać, że próbuje obliczyć 2 kolizje naraz. Myślę, że właśnie tutaj powstaje problem.

Wreszcie poniższy obraz wydaje się dobrze ilustrować mój problem:

prostokąt koliduje z wieloma innymi prostokątami

rozsiany
źródło
Link do filmu jest zepsuty.
XiaoChuan Yu
Czy colliderobiekty są zwracane przez this->getCollider()zaktualizowane przez this->move()?
XiaoChuan Yu
Czy mógłbyś dodać więcej informacji? Na czym dokładnie polega problem? Wygląda na to, że film w YouTube pokazuje przewidywalne zachowanie, a na scenie jest tylko jeden prostokąt.
Wackidev

Odpowiedzi:

3

Twój obraz ilustruje jeden z wielu problemów z próbą użycia wypukłych kształtów - szczególnie prostokątów - do symulacji płaskiej powierzchni, takiej jak podłoga. Algorytm prowadzi do zablokowania postaci na wewnętrznych krawędziach kształtów tworzących podłogę.

Prostym rozwiązaniem jest sprawdzenie tylko kolizji pionowej, popraw to, a następnie ponownie sprawdź kolizję poziomą. Chyba że spadniesz i ześlizgniesz się po ścianie, w takim przypadku najpierw sprawdź, czy nie występują kolizje w poziomie. Skąd wiesz, kiedy sprawdzić, który pierwszy? Możesz to zrobić na podstawie tego, który składnik prędkości jest większy (jeśli ruch poziomy jest większy, najpierw sprawdź zderzenia pionowe, w przeciwnym razie sprawdź zderzenia poziome).

Tym, co może być jeszcze prostsze - i bardziej wydajne - jest wygenerowanie listy krawędzi dla twojego świata. Oznacza to, że dla twoich pudeł tworzących podłogę ustaw flagę wskazującą, że tylko ich górna krawędź jest w rzeczywistości zderzalna, a następnie zignoruj ​​kolizje z innymi krawędziami. Nie będziesz w stanie użyć do tego procedury kolizji SFML, ale szczerze mówiąc, kolizje pudełkowe to prawdopodobnie najłatwiejszy fragment kodu, jaki kiedykolwiek napiszesz w grze. Ta technika działa szczególnie dobrze, jeśli twój świat jest wyrównany do siatki. Sprawdziłbym doskonałe samouczki Metanet (http://www.metanetsoftware.com/technique.html/) dotyczące tej techniki.

Będziesz miał wiele innych problemów, próbując zbudować prostą platformówkę 2D, taką jak ty. Zdecydowanie najlepszy zasób, jaki widziałem w tym kontekście, to następujący, który powinieneś przeczytać, a następnie przeczytać ponownie:

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

Sean Middleditch
źródło
1

Być może prostym rozwiązaniem byłoby sprawdzenie kolizji z każdym prostokątem i cofnięcie się w przeciwnym kierunku, dopóki nie zostaną wykryte kolizje. Jeśli to rozwiąże problem, wdrożenie również powinno być dość proste.

arex
źródło
+1, pisałem o tym tutaj: gamedev.stackexchange.com/questions/38252/...
Markus von Broady,
0

Nie sądzę, że obliczenie 2 kolizji to problem, tylko problem z wydajnością. Aby kolizja została poprawnie obsłużona, konieczne może być jej dwukrotne przetestowanie. Korzystając ze schematu, pomyśl, że jeśli A jest najpierw testowane względem B, to będzie musiało zostać przetestowane również na innych polach i może równie dobrze kolidować z innym.

Mam nadzieję, że to jest pomocne?

james82345
źródło
0

To naprawdę nie jest optymalna metoda, powinieneś próbować ustalić najwcześniejszy moment, kiedy lub pierwszy punkt wzdłuż ścieżki ruchomych obiektów, w których dochodzi do kolizji, i przenieść obiekty do tej pozycji (lub pozycji w obliczonym czasie), próbując poprawne w oparciu o pozycje penetrujące po ruchu jest bardzo problematyczne, ale możesz użyć obecnego procesu z niewielką zmianą. Po prostu sprawdzaj, czy nie ma kolizji.

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]);
      }
   }
}

Zauważ, że zdarzają się sytuacje, w których doprowadzi to do nieskończonej pętli (pomyśl o sytuacji, w której przeniesienie pudełka z kolizji skutkuje inną kolekcją, a przeniesienie pudełka z tej kolizji powoduje przeniesienie go z powrotem do tej samej pozycji zderzenia, co poprzednio)

Matthew R.
źródło