2017-01-30 58 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'? –

相关问题