繁体   English   中英

当弹丸击中两个“怪物”时,didBeginContact方法崩溃。 我知道为什么,但我不知道如何避免

[英]When projectile hits two “monsters” the didBeginContact method crashes. I know why but i don't know how to avoid it

因此,我从教程中获得了以下代码:

func didBeginContact(contact: SKPhysicsContact) {

    // 1
    var firstBody: SKPhysicsBody?
    var secondBody: SKPhysicsBody?
    var body: SKPhysicsBody

    //contact.bodyB.node!.physicsBody!.allContactedBodies().count


        if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
            firstBody = contact.bodyA
            secondBody = contact.bodyB
            println("1 = A, 2 = B")
        } else {
            firstBody = contact.bodyB
            secondBody = contact.bodyA
            println("2 = A, 1 = B")
        }



        // 2
        if ((firstBody!.categoryBitMask & PhysicsCategory.Monster != 0) &&
            (secondBody!.categoryBitMask & PhysicsCategory.Projectile != 0)) {

                for var c = 1; c <= contact.bodyB.node!.physicsBody!.allContactedBodies().count; c++ {
                    projectileDidCollideWithMonster(firstBody!.node as! SKSpriteNode, monster: secondBody!.node as! SKSpriteNode)

                }
                secondBody!.node?.removeFromParent()
        }
}

func projectileDidCollideWithMonster(projectile:SKSpriteNode, monster:SKSpriteNode) {
    println("Hit")
    changeScore(1)
    changeAmo(true)
    projectile.removeFromParent()
    monster.removeFromParent()
}

然后发生的事情是,一枚抛射物有时会同时击中两个怪物。

发生这种情况时-didBeginContact方法崩溃,表示secondBody为nil。

经过深入研究,我发现了原因:

当弹丸一次与其他两个节点碰撞时,此方法将运行两次。 第一次运行后-如果将bodyA作为射弹,将bodyB作为怪物-将它们传递给projectileDidCollideWithMonster ,并将它们都删除。 然后它立即再次运行,但在那一刻,弹丸不再存在,并且崩溃了,无法分配其节点。

我不知道如何克服这个问题:(有什么建议吗?

解决方案:由于下面的想法,我做了一些更改。

在类的顶部添加了array和一个触发器:

    var bodiesToBeRemoved = [SKSpriteNode]()
    var shouldRemoveBodies = false

并进行了以下修改:

 func projectileDidCollideWithMonster(projectile:SKSpriteNode, monster:SKSpriteNode) {
 /* Called when collisions is detected and collided nodes are passed to it */
    //score and stuff
    println("Hit")
    changeScore(1)
    changeAmo(true)

    //collect the nodes to be removed
    bodiesToBeRemoved.append(projectile)
    bodiesToBeRemoved.append(monster)

    //change the trigger to remove collected nodes later on
    shouldRemoveBodies=true

}

override func update(currentTime: CFTimeInterval) {
    /* Called before each frame is rendered */

    //check the trigger
    if shouldRemoveBodies == true {
        println("\(bodiesToBeRemoved.count)")
        //remove collected nodes
        for var i = 0; i<bodiesToBeRemoved.count; i++ {
            bodiesToBeRemoved[i].removeFromParent()
        }

        //reset array
        bodiesToBeRemoved.removeAll(keepCapacity: false)

        //reset the trigger
        shouldRemoveBodies = false
    } else {
        //do nothing:)
    }

}

与其立即移除弹丸,不如将其标记为要移除(例如,通过设置布尔标志或将其添加到某个集合中(如果尚未在集合中))。 然后,在下一次物理检查之前(例如,在此帧末尾),检查并清除所有标记为要移除的射弹。

只需检查它是否为零或比检查每个节点的标记更好。

func removeNodeFromPhysicsBody(ps: SKPhysicsBody){
    if (ps.node != nil){
        ps.node?.removeFromParent()
    }
}

func wallDidCollideWithMeteor(wall:SKPhysicsBody, meteor:SKPhysicsBody) {
    removeNodeFromPhysicsBody(wall)
    removeNodeFromPhysicsBody(meteor)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM