2015-01-15 13 views
5
func didBeginContact(contact: SKPhysicsContact) { 
    if (contact.bodyA.categoryBitMask & BodyType.shield.rawValue) == BodyType.shield.rawValue { 
     contact.bodyB.node?.removeFromParent() 
     counter++ 
     println(counter) 


    } else if (contact.bodyB.categoryBitMask & BodyType.shield.rawValue) == BodyType.shield.rawValue { 
     contact.bodyA.node?.removeFromParent() 
     counter++ 
     println(counter) 
    } 
} 

Un corpo fisica è da una trama shield.physicsBody = SKPhysicsBody(texture: shieldTexture, size: shieldTexture.size()) didBeginContact viene chiamato più volte per lo stesso SKPhysicsBody

l'altro da un cerchio sand.physicsBody = SKPhysicsBody(circleOfRadius: sand.size.width/2)

Quando il rimorchio oggetti contatto tra loro talvolta sand.physicsBody = SKPhysicsBody(circleOfRadius: sand.size.width/2) viene chiamato più volte. Come faccio a ottenere di essere chiamato solo una volta per ogni oggetto, anche se lo rimuovo dal genitore non appena entra in contatto.

+2

Credo che questo funzioni come previsto poiché il corpo dalla trama può generare più forme internamente, ciascuna può causare un evento di contatto. La rimozione del nodo non rimuove il corpo fino a quando la fase di simulazione fisica non è terminata. È necessario "contrassegnare" manualmente il nodo o il corpo come elaborati in questo evento di contatto in modo da poter saltare eventuali eventi di contatto successivi degli stessi corpi. – LearnCocos2D

+0

Vorrei che ci fosse un'opzione per SKPhysicsBody dalla texture per impostarlo tramite parametro, quindi si comporta esattamente come ad es. SKPhysicsBody da circleOfRadius quindi conta SOLO 1 colpo/contatto in alcuni casi che sarebbe molto desiderato rispetto alla creazione di qualsiasi logica aggiuntiva, inclusa la risposta di seguito. Inoltre, potrebbe risparmiare risorse per non rilevare più contatti se non sono necessari. –

risposta

2

Ho capito come ottenere func didBeginContact(contact: SKPhysicsContact) in modo che venga chiamato una sola volta. Ciò consente ai corpi fisici con una trama SKPhysicsBody(texture: size:) di contare le collisioni una volta anche se in realtà (a causa della natura del corpo fisico della trama) questa funzione sarà chiamata più volte.

Fase 1:

creare una proprietà nome per lo SKSpriteNode (useremo palla per questo esempio) e impostarlo uguale a un nome univoco. Possiamo farlo con la creazione di un int

var number = 0 

ball.name = "ball \(number)" 

Questo permette un nome univoco evertime si crea l'oggetto.

Fase 2:

Creare un array per contenere questi, aggiungere la palla a matrice, incrementare il numero

var array: [String] = [] 
    var number = 0 

ball.name = "ball \(number)" 
array.append(ball.name!) 
number ++ 

Fase 3: Ora, nel func didBeginContact(contact: SKPhysicsContact) scoprire se il nome è nella array. Se è incrementare il punteggio, rimuovere il nodo e rimuovere il nome dall'array. Se il nome non è nell'array non fare nulla.

La rimozione del nome dall'array ci consente ora di contare solo la chiamata di funzione una volta.

func didBeginContact(contact: SKPhysicsContact) { 
    if (contact.bodyA.categoryBitMask & BodyType.shield.rawValue) == BodyType.shield.rawValue { 
     var name = contact.bodyB.node?.name! 
     let index = find(array, name!) 

     if contains(array, name!) { 
      score++ 
      contact.bodyB.node?.removeFromParent() 
      array.removeAtIndex(index!) 
     } 
    } 
} 
+1

Non puoi semplicemente aggiungere SKSpriteNode all'array? È passato per riferimento in modo da poterli confrontare, non vedo perché dobbiamo assegnare nomi univoci. – 3366784

0

LearnCocos2D ragione, SKPhysicsbody didBeginContact chiamerà continuamente finchè SKphysicsbody dei due oggetti sono in contatto in quanto la forma abbiamo permesso in SKPhysicsBody(texture:xxx, size:xx) può venire in molteplici forme e forme.

Per coloro che ne hanno bisogno per rilevare una sola volta, abbiamo solo bisogno di usare un booleano come flag per verificare se il rilevamento è finito e finito.

Ecco come lo faccio:

  1. dichiarare un var booleano:

    var contactDone = Bool() 
    
  2. inizializzare all'inizio del programma (ad esempiosotto didMoveToView)

    contactDone = false 
    
  3. fare la verifica in didBeginContact:

    func didBeginContact(contact:SKPhysicsBody){ 
    
    if((contact.bodyA.categoryBitMask) == scoreCategory ||  (contact.bodyB.categoryBitMask) == scoreCategory){ 
    
         if (contactDone == false){ 
    
         // Increment score   
         score++ 
    
         // Set flag to disable multiple calls by checking in didEndContact 
         contactDone = true 
    
         } 
    } 
    } 
    
  4. Cancella la bandiera per farlo controllare di nuovo in didEndContact:

    func didEndContact(contact: SKPhysicsContact) { 
    
    if((contact.bodyA.categoryBitMask) == scoreCategory || (contact.bodyB.categoryBitMask) == scoreCategory){ 
    
          if(contactDone == true){ 
    
           contactDone = false 
    
          } 
    
    } 
    
    } 
    

ha funzionato proprio come lo ha fatto quando ho usato SKPhysicBody(circleOfRadius: object.size.height/2).

+0

Non funziona quando uso 'SKPhysicsBody (texture: ghostTexture, size: Obj.size)' – Danny182

0

In questo caso è possibile farlo funzionare senza array. Invece di questo:

contact.bodyA.node?.removeFromParent() 
counter++ 

usare qualcosa di simile a questo:

if let node = contact.bodyA.node as? SKSpriteNode { 
    if node.parent != nil { 
     node.removeFromParent() 
     counter++ 
    } 
} 

Al primo contatto si rimuove il nodo dal genitore, sulle chiamate successive il codice if verrà saltato.

1

c'è una soluzione molto semplice se si utilizza contactbitmask per determinare quali collisioni da catturare.

aggiornare semplicemente lo categoryBitMask dell'oggetto che non si desidera venga rilevato ripetutamente su un nuovo valore che non viene utilizzato in modo che il sistema non consideri più le chiamate di funzione successive rilevanti.

Problemi correlati