[英]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.