Risposta al rettangolo di collisione


10

Ho difficoltà a far scontrare un rettangolo mobile con più di un rettangolo.

Sto usando SFML e ha una pratica funzione chiamata intersectsche prende 2 rettangoli e restituisce le intersezioni. Ho un vettore pieno di rettangoli con i quali voglio che il mio rettangolo mobile si scontrasse. Sto facendo un giro di questo usando il seguente codice (p è il rettangolo mobile).

IsCollidingWithrestituisce un bool ma usa anche gli SFML per calcolare intersectsle intersezioni.

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

e il Collide()codice attuale :

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

}

e il IsCollidingWith()codice è:

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

Funziona bene quando c'è solo 1 Rectnella scena. Tuttavia, quando ce n'è più di uno, Rectsi crea un problema quando si risolvono 2 collisioni contemporaneamente.

Qualche idea su come gestirlo correttamente? Ho caricato un video su YouTube per mostrare il mio problema. La console all'estrema destra mostra la larghezza e l'altezza delle intersezioni. Puoi vedere sulla console che sta provando a calcolare 2 collisioni contemporaneamente, penso che sia qui che si sta causando il problema.

Infine, l'immagine qui sotto sembra illustrare bene il mio problema:

rettangolo in collisione con più altri rettangoli


Il collegamento video è interrotto.
XiaoChuan Yu,

Gli collideroggetti vengono restituiti this->getCollider()aggiornati da this->move()??
XiaoChuan Yu,

Potresti aggiungere qualche informazione in più per favore? Qual è esattamente il problema? Il video di YouTube sembra mostrare un comportamento prevedibile e nella scena c'è solo un altro rettangolo.
Wackidev,

Risposte:


3

La tua immagine illustra uno dei tanti problemi con il tentativo di usare forme convesse - in particolare rettangoli - per simulare una superficie piana come un pavimento. L'algoritmo porta i personaggi a rimanere bloccati sui bordi interni delle forme che compongono il pavimento.

Una semplice soluzione è quella di verificare solo la collisione verticale, correggerla, quindi verificare di nuovo la collisione orizzontale. A meno che tu non stia cadendo e non provi a scivolare giù da un muro, nel qual caso vuoi prima verificare le collisioni orizzontali. Come fai a sapere quando verificare quale? Potresti farlo in base a quale componente della tua velocità è più grande (se il movimento orizzontale è maggiore, controlla prima le collisioni verticali, altrimenti controlla le collisioni orizzontali).

Ciò che può essere ancora più semplice - e più performante - è invece generare un elenco di spigoli per il tuo mondo. Cioè, per le tue scatole che compongono il pavimento, imposta una bandiera che indica che solo il loro bordo superiore è effettivamente raccoglibile, quindi ignora le collisioni con gli altri bordi. Non sarai in grado di utilizzare la routine di collisione di SFML per questo, ma onestamente semplicemente le collisioni a scatola sono probabilmente il pezzo di codice più semplice che tu abbia mai scritto in un gioco. Questa tecnica funziona particolarmente bene se il tuo mondo è allineato a una griglia. Vorrei dare un'occhiata agli eccellenti tutorial di Metanet (http://www.metanetsoftware.com/technique.html/) per quella tecnica.

Incontrerai molti altri problemi nel tentativo di creare un semplice gioco platform in 2D come te. Di gran lunga, la miglior risorsa per cui ho visto il latino è la seguente, che dovresti leggere e poi rileggere:

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


1

Forse una soluzione semplice sarebbe quella di verificare le collisioni con ogni rettangolo e tornare indietro, nella direzione opposta del movimento, fino a quando non vengono rilevate collisioni. Se ciò risolve il problema, anche l'implementazione dovrebbe essere abbastanza semplice.



0

Non credo che calcolare 2 collisioni sia un problema, ma solo un problema di prestazioni. Affinché la collisione possa essere gestita correttamente, potrebbe essere necessario testarla due volte. Usando il tuo diagramma, pensa se A è stato testato prima contro B, quindi dovrà essere testato anche contro le altre caselle e potrebbe anche scontrarsi con un altro.

Spero che sia utile?


0

Questo non è davvero un metodo ottimale, dovresti provare a determinare lì prima o quando il primo punto lungo il percorso degli oggetti in movimento in cui si verificano le collisioni e spostare gli oggetti in quella posizione (o la posizione al momento calcolato), tentando di corretto in base alle posizioni penetranti dopo il movimento è molto problematico, ma è possibile utilizzare il processo corrente con una piccola modifica. Continua a controllare le collisioni fino a quando non ce ne sono.

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

Si noti che ci sono situazioni in cui ciò comporterà un ciclo infinito (si pensi a una situazione in cui lo spostamento della scatola da una collisione provoca un'altra raccolta e lo spostamento della scatola da quella collisione la riporta nella stessa posizione di collisione di prima)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.