我正在制作一个玩家(球)和敌人(球)相互击中的游戏。有时候didBegin
func会保存有关两个碰撞体的信息,有时候没有,导致崩溃并抛出exc_bad_instruction
的错误,然后我用断点检查玩家和敌人,我发现它们{{1 }}。如何发生,有时它工作,有时不做。请帮忙。
我的代码:
nil
我使用打印来获取名称,有时它会给我两个名字,有时它会给我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
,您可以运行代码并且它可以运行。
答案 0 :(得分:3)
如果bodyA
是玩家且bodyB
是敌人,会发生什么?我怀疑这种情况是你的“有时没有,导致崩溃”问题的原因。
在didBegin()
中,您是否从场景中删除了任何节点(使用removeFromParent
)?这可能会导致行为,因为SK有时会针对单个碰撞生成多次调用didBegin
。如果在第一次调用didBegin
时删除了碰撞中涉及的一个或两个节点,那么第二次调用它(这是在同一个游戏循环中),你的一些节点和/或它们的属性可以是nil
。
请记住,传递给didBegin
对象中SKMPhysicsContact
的对象是物理实体,而不是节点本身。即使你已经删除了节点本身(在之前的didBegin中),物理实体仍然可能存在。这意味着除非你访问didBegin中的实际节点,否则你可能不会崩溃,如果你正在做一些简单的检查,例如如果玩家击中了硬币或敌人,那么你可以增加两次得分,或者去除两次健康等。
有很多方法可以解决这个问题 - 包括但不限于:
didFinishUpdate
的调用后,在didBegin
的集合中
已经成了。您可能需要在节点userData
属性中设置一个标志,以阻止它被处理两次。还有其他一些技巧。搜索sprite-kit多次碰撞。
要处理'哪个是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")
}
}
如果您的节点一次只属于一个类别,这实际上是安全的,由您决定。