2017-01-30 62 views
1

我正在製作一個玩家(球)和敵人(球)互相碰撞的遊戲。有時候會有didBegin func保存關於兩個相撞機體的信息,有時候不會導致崩潰並拋出exc_bad_instruction的錯誤,然後我用斷點檢查玩家和敵人,我發現它們是nil。這種情況如何發生,有時會起作用,有時不起作用。請幫忙。爲什麼didBegin沒有關於聯繫人的數據?

我的代碼:

private var player: Player! 

private func drawPlayer(color: SKColor, radius: CGFloat, cn: String) { 
     player = Player.factory.createPlayer(color: color, radius: radius) 
     player.position = CGPoint(x: self.frame.midX, y: self.frame.midY) 
     player.name = cn 
     world.addChild(player) 
    } 

if (contact.bodyA.categoryBitMask == bodyType.enemy.rawValue) && (contact.bodyB.categoryBitMask == bodyType.player.rawValue) { 
     print(contact.bodyA.node?.name) 
     print(contact.bodyB.node?.name) 
     let player = contact.bodyB.node as? Player 
     let hitter = contact.bodyA.node as? Enemy 
} 

我使用的打印得到的名字有時給我兩個名字,有時它給了我兩個nil。剩下的代碼我沒有把它放在這裏,因爲它不是必需的。

的解::

如史蒂夫在他的回答中提到的問題是,有時didBegin方法被調用於同一碰撞物體的兩倍。所以它崩潰了,因爲在第一次調用時我刪除了對象,所以它第二次發現nil。所以史蒂夫提到你應該用if包圍邏輯並檢查兩個物體是否爲nil然後這是didBegin的第二個調用,並且對象已經被刪除,所以你不應該運行邏輯,否則它將在沒有運行時崩潰。如果他們不是nil,你可以運行代碼,它的工作原理。

回答

3

如果bodyA是玩家和bodyB是敵人會發生什麼?我懷疑這種情況是你的「有時不會導致崩潰」問題的原因。

didBegin()您是否從場景中刪除了任何節點(使用removeFromParent)?這可能會導致行爲,因爲SK有時會針對單次碰撞產生多次致電didBegin。如果在第一次調用didBegin時刪除其中一個或兩個參與衝突的節點,則第二次調用它(這是在同一個遊戲循環中),您的某些節點和/或它們的屬性可能是nil

請記住,在SKMPhysicsContact對象中傳遞給didBegin的對象是物理實體,而不是節點本身。即使您自己刪除了節點(在之前的didBegin中),物理實體仍可能存在。這意味着除非您訪問didBegin中的實際節點,否則您可能不會崩潰,並且如果您正在進行一些簡單的檢查,例如如果玩家已經打了一個硬幣或敵人,那麼你可能會增加一個得分兩次或刪除兩批衛生等

有許多方法來處理這個 - 包括,但不限於:

  • 在做任何事情之前,檢查身體是否爲零。 (如果它是零,那麼假設你已經處理它的碰撞並將其刪除)。
  • 在集添加節點被移除以一組,然後除去所有節點 在didFinishUpdate,所有didBegin 的呼籲已作出後。您可能需要在節點userData屬性中設置一個標誌來停止它的兩次處理。

加上一些其他技術。搜索精靈套件多重碰撞。

爲了應付「這是bodyA並且是bodyB」的問題,我喜歡寫代碼didBegin:是這樣的:

func didBeginContact(contact: SKPhysicsContact) { 
     let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask 

     switch contactMask { 

     case categoryBitMask.player | categoryBitMask.enemy: 
      print("Collision between player and enemy") 
      let enemy = contact.bodyA.categoryBitMask == categoryBitMask.thisMine ? contact.bodyA.node! : contact.bodyB.node! 
      enemy.explode() 

     default : 
      //Some other contact has occurred 
      print("Some other contact") 
    } 
} 

這是真的只有安全的,如果您的節點只屬於一個類別在時間,這取決於你自己決定。

+0

是的,我使用刪除父母的敵人和玩家,然後我再次在同一個地方,以便遊戲繼續,但它適用於它的前3或2次,然後崩潰在後來崩潰 –

+0

我懷疑你需要指出這個碰撞已經被處理了。你可以在userData中設置一個標誌,然後在update()中清除該標誌,因爲到那時你將在一個新的遊戲循環中,並且玩家和敵人之間的衝突將是新的。 –

+0

你的意思是我在他們開始碰撞後添加變量'collided = true'? –

相關問題