Classe di collisione top-down riutilizzabile


8

Recentemente ho preso il monogame e sto lavorando a un semplice gioco top down per farmi iniziare e imparare le basi.
Ho il movimento e la rotazione per seguire il mouse risolto, ma sono bloccato con le collisioni.
Quello che voglio sapere, in sostanza, sono due cose:

  1. Quale sarebbe il modo migliore per gestire le collisioni? So che Rectangle.Intersects(Rectangle1, Rectangle2)restituisce il rettangolo sovrapposto, ma, poiché il movimento in alto verso il basso è sull'asse x / y, vorrei sapere dove si sta verificando la collisione in modo da poter creare una sorta di "scorrimento a parete" dove il giocatore non ottiene bloccato al muro.
    Controllare le coordinate del giocatore x / y rispetto alle coordinate degli oggetti solidi, quindi lanciare il giocatore nella sua posizione precedente se entra nei limiti di un oggetto solido è davvero l'approccio migliore? Che cosa suggeriresti?
  2. Quale sarebbe il modo migliore per applicare le collisioni a tutti i solidi, agli npc ecc.? Attualmente sto pensando di creare una gameObjectclasse da cui tutti gli oggetti erediteranno e gestiranno semplicemente le collisioni lì.

Grazie per aver letto e spero che qualcuno possa darmi qualche consiglio.


Per alcune riflessioni sulla tua seconda domanda, dai un'occhiata a questa risposta sull'architettura di gioco .
Andrew Russell,

Risposte:


9

Generalmente il modo in cui la maggior parte dei motori di fisica gestisce questo problema è separando gli oggetti che si intersecano .


Quindi, se i tuoi oggetti sono rappresentati da rettangoli (noti anche come "Scatole di confine allineate sull'asse"), e si scontrano su una determinata cornice in questo modo:

Collisione


Quindi misurare la quantità di compenetrazione su ciascun asse. Quindi selezionare l'asse con la minima quantità di compenetrazione e separare gli oggetti lungo quell'asse.

Separato


Dovresti quindi registrarlo come "collisione" e applicare le dinamiche appropriate.

Ad esempio, se si desidera scorrere lungo il muro, è sufficiente azzerare la velocità sull'asse su cui si è separati (l'asse X, nell'illustrazione sopra), lasciando la velocità sull'altro asse da solo.

Ma potresti anche applicare attrito o far rimbalzare gli oggetti.


Ecco un eccellente tutorial interattivo che mostra come farlo in modo molto più dettagliato.

Tuttavia, se hai intenzione di percorrere questa strada (qualcosa di più che semplici collisioni AABB), potresti prendere in considerazione l' idea di utilizzare un motore esistente come Farseer Physics .


Infine, una nota sull'implementazione (se non segui il percorso Farseer): Rectangleutilizza intvalori, che nella maggior parte dei casi non sono realmente appropriati per fare fisica. Valuta invece di creare la tua AABBclasse che usi floatinvece.

La tua seconda domanda ha una risposta abbastanza buona dalla mia vecchia risposta sull'architettura di gioco qui , quindi non la ripeterò qui.


Forse c'è qualcosa che non capisco, ma questo approccio non è imperfetto? Ho illustrato il problema qui: jmp.sh/jEW2lvR A volte comporterebbe un comportamento strano.
BjarkeCK,

@BjarkeCK: Sì, devi fare un lavoro extra per gestire casi del genere. Non sono abbastanza esperto per spiegare appieno come gestirli correttamente (uso solo Farseer e lo chiamo un giorno). Forse dai un'occhiata alla "Sezione 5" di questo link .
Andrew Russell,

1

1: Ho lavorato anche su un gioco d'azione top-down relativamente semplice, e dopo una settimana (-s?) Di lotta, ho finito per usare una sorta di approccio passo-passo al rilevamento e alla risposta delle collisioni. Il motivo principale è che l'uso della minor quantità di compenetrazione in alcuni casi comporterebbe un "teletrasporto" in una nuova posizione in cui l'oggetto in movimento non si trovava in precedenza.

quindi, quando un oggetto vuole muoversi,

  1. Creo un boundingbox dell'oggetto nella posizione dell'oggetto + moveAmount vector, creando una sorta di bounding box target
  2. quindi controllo questa finestra di delimitazione target per eventuali incroci con gli oggetti di gioco, le tessere, ecc. se ce ne sono, le aggiungo a un nuovo elenco, che contiene tutte le potenziali collisioni per il frame corrente
  3. se non ci sono intersezioni, l'oggetto si sposta. ma se c'è un incrocio,
  4. Ho diviso il movimento desiderato in "passi". quindi eseguo un ciclo per il numero di passaggi che ho. ogni passaggio sposta l'oggetto solo di 1 pixel nelle direzioni xey.
  5. per ogni passaggio controllo ogni nuova posizione proiettata per le collisioni, se non altro, aggiungo il vettore di spostamento del passo al vettore di spostamento finale.
  6. se c'è una collisione (si interseca restituisce vero), confronto la posizione precedente (posizione nel passaggio precedente) dell'oggetto in movimento con la cosa con cui si sta scontrando.
  7. a seconda di questa posizione precedente, interrompo il movimento lungo l'asse in conflitto (ad esempio, se l'oggetto in movimento arriva dall'alto in collisione, imposto il valore di vettore di spostamento su 0, ecc.).
  8. Lo ripeto per ogni passaggio consecutivo, aggiungendo i vettori di passo regolati insieme per eseguire un movimento di regolazione finale che è possibile utilizzare in modo sicuro per spostare l'oggetto senza che si verifichino collisioni.

questo approccio assicura che l'oggetto "rimbalzi" nella posizione precedente corretta e consente di scivolare contro le pareti, gli oggetti, qualunque cosa.

2: Io stesso uso una classe di collisione statica che può essere utilizzata da qualsiasi cosa. contiene metodi di rilevamento delle collisioni e regolazione dei vettori, che possono essere chiamati praticamente da qualsiasi cosa. se questi metodi sono chiamati da una classe di gioco "master" o da una sottoclasse di oggetti non ha importanza nel mio caso, perché la classe di collisione crea un nuovo elenco ogni frame per tutti i rettangoli con cui si interseca l'oggetto in movimento. questi rettangoli potrebbero provenire da piastrelle, decorazioni, NPC, qualunque cosa abbia dei confini ed è fondamentalmente collezionabile. questo significa che la nuda necessità per tutti gli oggetti di gioco che sono collezionabili è di avere dei rettangoli di confine. se ce l'hanno, la classe di collisione gestirà il resto.

spero che questo fosse comprensibile.


0

1: Ho usato con successo una tecnica per risolvere questo problema: usando la velocità e la posizione puoi scoprire la collisione e tornare indietro fino a quando la posizione è molto vicina al punto esatto di collisione.

Non fa parte della risposta per la tua prima domanda, ma se hai molti oggetti che possono scontrarsi tra loro, dovresti usare i quadricipiti per migliorare le prestazioni. C'è un ottimo tutorial con molti esempi qui .

2: lo consiglio sempre Entity-Systems .

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.