2015-06-29 17 views
14

Per quanto ne so, l'impostazione predefinita per i corpi fisici è quella di rimbalzarsi l'un l'altro quando si colpiscono a vicenda finché non si imposta il loro collisionBitMask su un numero uguale.Come funziona collisionBitMask? Swift/SpriteKit

Tuttavia, sto riscontrando un grosso problema nel realizzare ciò che sembra dovrebbe essere molto semplice a causa di collisionBitmasks, credo.

let RedBallCategory : UInt32 = 0x1 << 1 
    let GreenBallCategory: UInt32 = 0x1 << 2 
    let RedBarCategory : UInt32 = 0x1 << 3 
    let GreenBarCategory : UInt32 = 0x1 << 4 
    let WallCategory : UInt32 = 0x1 << 5 


     greenBall.physicsBody?.categoryBitMask = GreenBallCategory 
     greenBall.physicsBody?.contactTestBitMask = RedBarCategory 
     greenBall.physicsBody?.collisionBitMask = GreenHealthCategory 

redBall.physicsBody?.categoryBitMask = RedBallCategory 
     redBall.physicsBody?.contactTestBitMask = GreenBarCategory 
     redBall.physicsBody?.collisionBitMask = RedHealthCategory 

    let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame) 
    self.physicsBody = borderBody 
    self.physicsBody?.friction = 0 
    borderBody.contactTestBitMask = RedBallCategory | GreenBallCategory 
    borderBody.categoryBitMask = WallCategory 

Così qui ho i miei 2 palle e il mio corpo di frontiera. Posso ottenere il rilevamento delle collisioni che voglio, ma quando aggiungo la maschera bit di categoria del corpo del bordo, permette alle palle di passare e fuori dallo schermo, cosa che non voglio.

Voglio anche che le palline rimbalzino l'una contro l'altra, ma solo quando commento una categoria della palla dei BitsMasks rimbalzano. Altrimenti passano attraverso l'altro.

Questo non ha assolutamente senso per me perché ognuno di questi elementi ha una maschera di collisione diversa. A volte ho anche avuto il problema di impostare tutti i numeri uguali a 5 per consentire a tutti di passare attraverso l'altro, ma impostando il tutto su 6 si consentirebbe a tutto di colpire l'un l'altro.

Come funzionano esattamente le maschere di bit di collisione e c'è un modo corretto per gestire un sacco di regole di collisione incrociate?

risposta

37

Non è possibile ottenere il comportamento desiderato perché non è stata impostata correttamente la categoria, il contatto e le maschere di bit di collisione. Ecco un esempio di come è possibile impostare questo lavoro:

greenBall.physicsBody?.categoryBitMask = GreenBallCategory //Category is GreenBall 
greenBall.physicsBody?.contactTestBitMask = RedBarCategory | WallCategory //Contact will be detected when GreenBall make a contact with RedBar or a Wall (assuming that redBar's masks are already properly set) 
greenBall.physicsBody?.collisionBitMask = GreenBallCategory | RedBallCategory | WallCategory //Collision will occur when GreenBall hits GreenBall, RedBall or hits a Wall 

redBall.physicsBody?.categoryBitMask = RedBallCategory //Category is RedBall 
redBall.physicsBody?.contactTestBitMask = GreenBarCategory | GreenBallCategory | WallCategory //Contact will be detected when RedBall make a contact with GreenBar , GreenBall or a Wall 
redBall.physicsBody?.collisionBitMask = RedBallCategory | GreenBallCategory | WallCategory //Collision will occur when RedBall meets RedBall, GreenBall or hits a Wall 

let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame) 
self.physicsBody = borderBody 
self.physicsBody?.friction = 0 
borderBody.contactTestBitMask = RedBallCategory | GreenBallCategory //Contact will be detected when red or green ball hit the wall 
borderBody.categoryBitMask = WallCategory 
borderBody.collisionBitMask = RedBallCategory | GreenBallCategory // Collisions between RedBall GreenBall and a Wall will be detected 

ti consiglierei di leggere documenti su categoryBitMask che è una maschera che definisce le categorie di un corpo di fisica appartiene a:

Ogni il corpo della fisica in una scena può essere assegnato a un massimo di 32 diverse categorie , ciascuna corrispondente ad un bit nella maschera bit. Tu definisci i valori della maschera usati nel tuo gioco. In concomitanza con le proprietà collisionBitMask e contactTestBitMask , è possibile definire quali corpi fisici di interagiscono tra loro e quando viene notificato al gioco di queste interazioni.

contactTestBitMask - Una maschera che definisce quali categorie di corpi causano notifiche di intersezione con un corpo fisico corrente.

Quando due corpi condividono lo stesso spazio, maschera categoria di ciascun organismo è testati contro maschera contatti dell'altro corpo eseguendo una logica AND. Se uno dei due risultati risulta in un valore diverso da zero, viene creato un oggetto SKPhysicsContact e inviato al delegato del mondo fisico . Per ottenere prestazioni ottimali, i bit solo impostati nei contatti maschera per interazioni siete interessati a

collisionBitmask -. Una maschera che definisce le categorie di enti di fisica possono collidere con questo corpo fisico.

Quando due corpi fisici si contattano, è possibile che si verifichi una collisione. La maschera di collisione di questo corpo viene confrontata con la maschera di altro corpo della categoria eseguendo un'operazione AND logica. Se il risultato è un valore diverso da zero , questo corpo è interessato dalla collisione. Ogni corpo indipendente sceglie se vuole essere influenzato dall'altro corpo. Per esempio , è possibile utilizzarlo per evitare calcoli di collisione che farebbero modifiche trascurabili alla velocità di un corpo.

Quindi, fondamentalmente, per impostare tutti questi, si dovrebbe chiedere il vostro sé qualcosa di simile:

Va bene, ho una palla verde, e una palla rossa, e gli oggetti a muro sulla scena. Tra quali corpi voglio che si verifichino collisioni o quando voglio registrare i contatti? Voglio che una palla verde e una rossa si scontrino tra loro e scontrino contro i muri. Non è un problema. Io innanzitutto impostare categorie correttamente, e poi mi metterò bit maschere di collisione in questo modo:

greenBall.collisionBitMask = GreenBallCategory | RedBallCategory | WallCategory; //greenBall will collide with greenBall, redBall and a wall 
redBall.collisionBitMask = GreenBallCategory | RedBallCategory | WallCategory 

wall.collisionBitMask = GreenBall | RedBall 

Ora, voglio rilevare quando si verificano alcuni contatti (in didBeginContact: metodo) ... Ma non fare vuoi essere avvisato di tutti i possibili contatti, ma piuttosto di essere informato solo sui contatti tra le sfere (i contatti tra le palle e un muro saranno ignorati). Quindi, consente di impostare contactTestBitMasks per raggiungere questo obiettivo:

greenBall.contactTestBitMask = GreenBallCategory | RedBallCategory; 
redBall.contactTestBitMask = GreenBallCategory | RedBallCategory; 

E questo è tutto. L'importante è che quando non si utilizza il rilevamento dei contatti, non si deve impostare contactTestBitMask. Questo è dovuto a motivi di prestazioni. Se non è necessario il rilevamento delle collisioni e si è interessati solo a rilevare i contatti, è possibile impostare collisionBitMask = 0.

Importante:

Assicurarsi di aver impostato delegato contatto del mondo della fisica, al fine di utilizzare didBeginContact e didEndContact metodi:

self.physicsWorld.contactDelegate = self; //where self is a current scene 

Spero che questo aiuti un po '.

+0

Incredibile risposta, grazie mille per aver dedicato del tempo a scrivere tutto questo. Funziona perfettamente. La parte "chiedi a te stesso" ha sicuramente chiarito su cosa mi ero confuso. Grazie mille, così tanto! – Noowoo

+0

Che dire se ne hai più di 32? – cnzac

+0

@Abcdefg Come si può rilevare la fine della collisione nella funzione didEnd? – Marin