当射弹击中两个 "monsters" 时,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 为零。
经过深入研究,我找到了原因:
当射弹同时与其他两个节点碰撞时 - 此方法 运行s 两次。在第一个 运行 之后 - 如果将 bodyA 作为射弹,将 bodyB 作为怪物 - 将它们传递给 projectileDidCollideWithMonster
并将它们都移除。然后它又立即 运行s 但在那一刻抛射物不再存在并且它崩溃无法分配它的节点。
我不知道如何克服这个问题:(请问有什么建议吗?
解决方案:感谢以下想法,我做了一些更改。
在 class:
的顶部添加了数组和触发器
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)
}
所以我从教程中得到了这段代码:
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 为零。
经过深入研究,我找到了原因:
当射弹同时与其他两个节点碰撞时 - 此方法 运行s 两次。在第一个 运行 之后 - 如果将 bodyA 作为射弹,将 bodyB 作为怪物 - 将它们传递给 projectileDidCollideWithMonster
并将它们都移除。然后它又立即 运行s 但在那一刻抛射物不再存在并且它崩溃无法分配它的节点。
我不知道如何克服这个问题:(请问有什么建议吗?
解决方案:感谢以下想法,我做了一些更改。
在 class:
的顶部添加了数组和触发器 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)
}