removeFromParent() 不会删除节点,但会使其不可见
removeFromParent() does not remove a node, but makes it invisible
我有一个 restartButton 必须在两个物体碰撞时出现,当它第一次发生时,一切顺利 - 物体碰撞 --> restartButton 出现 --> 我通过触摸重启按钮重启关卡。
这是一个 "good, right restart" 问题开始了...
关卡重新启动后,如果我触摸屏幕中央(调用 restartButton 时必须出现的位置)游戏崩溃,提示如下:
“由于未捕获的异常 'NSInvalidArgumentException',正在终止应用程序,原因:'Attemped to add a SKNode which already has a parent: name:'(null)' particleTexture:'enemyPart.png' (100 x 100) 位置:{721.33929 , 175.39999} accumulatedFrame:{{inf, inf}, {inf, inf}}'
** 首先抛出调用栈:
(0x2a0fa137 等)
libc++abi.dylib:以 NSException 类型的未捕获异常终止
但是 restartButton 是不可见的,它甚至不可能在那里,因为没有物体发生碰撞。
如果在那之后 "good restart" 一些敌人与玩家发生碰撞,重启按钮会出现片刻,玩家、敌人 1、敌人 2、敌人 3 将从场景中淡出。
如果有人能提供帮助,我将不胜感激
这是您可以看到所有内容的代码:
import SpriteKit
import UIKit
let player = SKEmitterNode(fileNamed: "playerPart.sks")
let enemy1 = SKEmitterNode(fileNamed: "ePart.sks")
let enemy2 = SKEmitterNode(fileNamed: "ePart.sks")
let enemy3 = SKEmitterNode(fileNamed: "ePart.sks")
let restartButton = SKSpriteNode(imageNamed: "restartButton")
let playerCat: UInt32 = 0x1 << 0
let enemyCat: UInt32 = 0x1 << 1
class Level2: SKScene, SKPhysicsContactDelegate {
override func didMoveToView(view: SKView) {
physicsWorld.contactDelegate = self
initWorld()
movements()
player.physicsBody = SKPhysicsBody(circleOfRadius: 50)
player.position = CGPointMake(819.2 , 693.8)
player.zPosition = 1
player.physicsBody?.categoryBitMask = playerCat
player.physicsBody?.contactTestBitMask = enemyCat
player.targetNode = self
self.addChild(player)
enemy1.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(102, 102))
enemy1.position = CGPointMake(819.2, 175.4)
enemy1.zPosition = 1
enemy1.physicsBody?.affectedByGravity = false
enemy1.physicsBody?.dynamic = true
enemy1.physicsBody?.allowsRotation = false
enemy1.physicsBody?.categoryBitMask = enemyCat
enemy1.physicsBody?.contactTestBitMask = playerCat
enemy1.physicsBody?.collisionBitMask = 0x0
enemy1.targetNode = self
enemy1.particleBirthRate = 150
enemy1.particleLifetime = 10
enemy1.particleLifetimeRange = 20
enemy1.particlePositionRange = CGVectorMake(50, 60)
enemy1.emissionAngle = 0
enemy1.emissionAngleRange = 0
enemy1.particleSpeed = 0
enemy1.particleSpeedRange = 0
enemy2.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(102, 102))
enemy2.position = CGPointMake(614.4, 386.6)
enemy2.zPosition = 1
enemy2.physicsBody?.affectedByGravity = false
enemy2.physicsBody?.dynamic = true
enemy2.physicsBody?.allowsRotation = false
enemy2.physicsBody?.categoryBitMask = enemyCat
enemy2.physicsBody?.contactTestBitMask = playerCat
enemy2.physicsBody?.collisionBitMask = 0x0
enemy2.targetNode = self
enemy2.particleBirthRate = 150
enemy2.particleLifetime = 10
enemy2.particleLifetimeRange = 20
enemy2.particlePositionRange = CGVectorMake(50, 60)
enemy2.emissionAngle = 0
enemy2.emissionAngleRange = 0
enemy2.particleSpeed = 0
enemy2.particleSpeedRange = 0
enemy3.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(102, 102))
enemy3.position = CGPointMake(409.6, 181.8)
enemy3.zPosition = 1
enemy3.physicsBody?.affectedByGravity = false
enemy3.physicsBody?.dynamic = true
enemy3.physicsBody?.allowsRotation = false
enemy3.physicsBody?.categoryBitMask = enemyCat
enemy3.physicsBody?.contactTestBitMask = playerCat
enemy3.physicsBody?.collisionBitMask = 0x0
enemy3.targetNode = self
enemy3.particleBirthRate = 150
enemy3.particleLifetime = 10
enemy3.particleLifetimeRange = 20
enemy3.particlePositionRange = CGVectorMake(50, 60)
enemy3.emissionAngle = 0
enemy3.emissionAngleRange = 0
enemy3.particleSpeed = 0
enemy3.particleSpeedRange = 0
func initWorld() {
self.addChild(enemy1)
self.addChild(enemy2)
self.addChild(enemy3)
}
func movements() {
let move11 = SKAction.moveTo(CGPointMake(819.2, 386.6), duration: 1.5)
let move12 = SKAction.moveTo(CGPointMake(614.4, 386.6), duration: 1.5)
let move13 = SKAction.moveTo(CGPointMake(614.4, 175.4), duration: 1.5)
let move14 = SKAction.moveTo(CGPointMake(819.2, 175.4), duration: 1.5)
let enemy1m = SKAction.sequence([move11, move12, move13, move14])
let enemy1move = SKAction.repeatActionForever(enemy1m)
let move21 = SKAction.moveTo(CGPointMake(614.4, 591.4), duration: 1.5)
let move22 = SKAction.moveTo(CGPointMake(409.6, 591.4), duration: 1.5)
let move23 = SKAction.moveTo(CGPointMake(409.6, 386.6), duration: 1.5)
let move24 = SKAction.moveTo(CGPointMake(614.4, 386.6), duration: 1.5)
let enemy2m = SKAction.sequence([move21, move22, move23, move24])
let enemy2move = SKAction.repeatActionForever(enemy2m)
let move31 = SKAction.moveTo(CGPointMake(409.6, 386.6), duration: 1.5)
let move32 = SKAction.moveTo(CGPointMake(204.8, 386.6), duration: 1.5)
let move33 = SKAction.moveTo(CGPointMake(204.8, 181.8), duration: 1.5)
let move34 = SKAction.moveTo(CGPointMake(409.6, 181.8), duration: 1.5)
let enemy3m = SKAction.sequence([move31, move32, move33, move34])
let enemy3move = SKAction.repeatActionForever(enemy3m)
enemy1.runAction(enemy1move)
enemy2.runAction(enemy2move)
enemy3.runAction(enemy3move)
}
func didBeginContact(contact: SKPhysicsContact) {
let collision:UInt32 = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask)
if collision == (playerCat | enemyCat) {
self.removeAllActions()
self.runAction(SKAction.waitForDuration(0.1), completion: {
self.runAction(SKAction.waitForDuration(0.2), completion:
{self.removeAllActions()
self.removeChildrenInArray([enemy1, enemy2, enemy3, player])})
restartButton.size = CGSizeMake(200, 200)
restartButton.position = CGPointMake(512, 384)
restartButton.zPosition = 1
self.addChild(restartButton)
})
}
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if (restartButton .containsPoint(location)) {
restartButton.runAction(fadeAway)
restartButton.removeFromParent()
println(1)
self.runAction(SKAction.waitForDuration(1.5), completion: {
let repeatLevel = SKTransition.fadeWithDuration(2)
let level2 = Level2(fileNamed: "Level2")
self.view?.presentScene(level2, transition: repeatLevel)
})
}
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
当你的 playerCat 和 enemyCat 第一次碰撞时,你的 restartButton 第一次设置了它的大小,这很好。
因为 restartButton 现在有一个大小。您可以检查您的触摸是否在重启按钮的范围内。
if (restartButton .containsPoint(location)) {
就像你这样做了,但你没有检查 restartButton 是否被添加到场景中。
快速修复可能是:
if (restartButton.parent != nil && restartButton .containsPoint(location)) {
如果不是特别需要检查它是否与节点的边界。您可以直接使用它进行检查。这将消除检查 parent.
的需要
if (self.nodeAtPoint(location) == restartButton) {
我注意到的另一件事是,在您的碰撞检测中,您从不检查它是否已经发生碰撞。因此,您可能 运行 多次使用相同的代码,只是不断删除所有操作,然后添加新的操作。
您可以添加一个简单的 have 变量来防止冗余
var detectionMade = false
并重置为
override func didMoveToView(view: SKView) {
physicsWorld.contactDelegate = self
initWorld()
movements()
detectionMade = false
...
并在第一次碰撞和检查时设置为真
if collision == (playerCat | enemyCat) && !detectionMade {
detectionMade = true
...
@martinmeincke 我做到了!通过这样做:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if (restartButton .containsPoint(location) && restartButton.parent == nil) {
restartButton.runAction(fadeAway)
println(1)
}
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if (restartButton .containsPoint(location)) {
restartButton.removeFromParent()
self.runAction(SKAction.waitForDuration(1.5), completion: {
let repeatLevel = SKTransition.fadeWithDuration(2)
let level2 = Level2(fileNamed: "Level2")
self.view?.presentScene(level2, transition: repeatLevel)
})
}
}
}
我有一个 restartButton 必须在两个物体碰撞时出现,当它第一次发生时,一切顺利 - 物体碰撞 --> restartButton 出现 --> 我通过触摸重启按钮重启关卡。 这是一个 "good, right restart" 问题开始了...
关卡重新启动后,如果我触摸屏幕中央(调用 restartButton 时必须出现的位置)游戏崩溃,提示如下:
“由于未捕获的异常 'NSInvalidArgumentException',正在终止应用程序,原因:'Attemped to add a SKNode which already has a parent: name:'(null)' particleTexture:'enemyPart.png' (100 x 100) 位置:{721.33929 , 175.39999} accumulatedFrame:{{inf, inf}, {inf, inf}}' ** 首先抛出调用栈: (0x2a0fa137 等) libc++abi.dylib:以 NSException 类型的未捕获异常终止
但是 restartButton 是不可见的,它甚至不可能在那里,因为没有物体发生碰撞。
如果在那之后 "good restart" 一些敌人与玩家发生碰撞,重启按钮会出现片刻,玩家、敌人 1、敌人 2、敌人 3 将从场景中淡出。
如果有人能提供帮助,我将不胜感激
这是您可以看到所有内容的代码:
import SpriteKit
import UIKit
let player = SKEmitterNode(fileNamed: "playerPart.sks")
let enemy1 = SKEmitterNode(fileNamed: "ePart.sks")
let enemy2 = SKEmitterNode(fileNamed: "ePart.sks")
let enemy3 = SKEmitterNode(fileNamed: "ePart.sks")
let restartButton = SKSpriteNode(imageNamed: "restartButton")
let playerCat: UInt32 = 0x1 << 0
let enemyCat: UInt32 = 0x1 << 1
class Level2: SKScene, SKPhysicsContactDelegate {
override func didMoveToView(view: SKView) {
physicsWorld.contactDelegate = self
initWorld()
movements()
player.physicsBody = SKPhysicsBody(circleOfRadius: 50)
player.position = CGPointMake(819.2 , 693.8)
player.zPosition = 1
player.physicsBody?.categoryBitMask = playerCat
player.physicsBody?.contactTestBitMask = enemyCat
player.targetNode = self
self.addChild(player)
enemy1.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(102, 102))
enemy1.position = CGPointMake(819.2, 175.4)
enemy1.zPosition = 1
enemy1.physicsBody?.affectedByGravity = false
enemy1.physicsBody?.dynamic = true
enemy1.physicsBody?.allowsRotation = false
enemy1.physicsBody?.categoryBitMask = enemyCat
enemy1.physicsBody?.contactTestBitMask = playerCat
enemy1.physicsBody?.collisionBitMask = 0x0
enemy1.targetNode = self
enemy1.particleBirthRate = 150
enemy1.particleLifetime = 10
enemy1.particleLifetimeRange = 20
enemy1.particlePositionRange = CGVectorMake(50, 60)
enemy1.emissionAngle = 0
enemy1.emissionAngleRange = 0
enemy1.particleSpeed = 0
enemy1.particleSpeedRange = 0
enemy2.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(102, 102))
enemy2.position = CGPointMake(614.4, 386.6)
enemy2.zPosition = 1
enemy2.physicsBody?.affectedByGravity = false
enemy2.physicsBody?.dynamic = true
enemy2.physicsBody?.allowsRotation = false
enemy2.physicsBody?.categoryBitMask = enemyCat
enemy2.physicsBody?.contactTestBitMask = playerCat
enemy2.physicsBody?.collisionBitMask = 0x0
enemy2.targetNode = self
enemy2.particleBirthRate = 150
enemy2.particleLifetime = 10
enemy2.particleLifetimeRange = 20
enemy2.particlePositionRange = CGVectorMake(50, 60)
enemy2.emissionAngle = 0
enemy2.emissionAngleRange = 0
enemy2.particleSpeed = 0
enemy2.particleSpeedRange = 0
enemy3.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(102, 102))
enemy3.position = CGPointMake(409.6, 181.8)
enemy3.zPosition = 1
enemy3.physicsBody?.affectedByGravity = false
enemy3.physicsBody?.dynamic = true
enemy3.physicsBody?.allowsRotation = false
enemy3.physicsBody?.categoryBitMask = enemyCat
enemy3.physicsBody?.contactTestBitMask = playerCat
enemy3.physicsBody?.collisionBitMask = 0x0
enemy3.targetNode = self
enemy3.particleBirthRate = 150
enemy3.particleLifetime = 10
enemy3.particleLifetimeRange = 20
enemy3.particlePositionRange = CGVectorMake(50, 60)
enemy3.emissionAngle = 0
enemy3.emissionAngleRange = 0
enemy3.particleSpeed = 0
enemy3.particleSpeedRange = 0
func initWorld() {
self.addChild(enemy1)
self.addChild(enemy2)
self.addChild(enemy3)
}
func movements() {
let move11 = SKAction.moveTo(CGPointMake(819.2, 386.6), duration: 1.5)
let move12 = SKAction.moveTo(CGPointMake(614.4, 386.6), duration: 1.5)
let move13 = SKAction.moveTo(CGPointMake(614.4, 175.4), duration: 1.5)
let move14 = SKAction.moveTo(CGPointMake(819.2, 175.4), duration: 1.5)
let enemy1m = SKAction.sequence([move11, move12, move13, move14])
let enemy1move = SKAction.repeatActionForever(enemy1m)
let move21 = SKAction.moveTo(CGPointMake(614.4, 591.4), duration: 1.5)
let move22 = SKAction.moveTo(CGPointMake(409.6, 591.4), duration: 1.5)
let move23 = SKAction.moveTo(CGPointMake(409.6, 386.6), duration: 1.5)
let move24 = SKAction.moveTo(CGPointMake(614.4, 386.6), duration: 1.5)
let enemy2m = SKAction.sequence([move21, move22, move23, move24])
let enemy2move = SKAction.repeatActionForever(enemy2m)
let move31 = SKAction.moveTo(CGPointMake(409.6, 386.6), duration: 1.5)
let move32 = SKAction.moveTo(CGPointMake(204.8, 386.6), duration: 1.5)
let move33 = SKAction.moveTo(CGPointMake(204.8, 181.8), duration: 1.5)
let move34 = SKAction.moveTo(CGPointMake(409.6, 181.8), duration: 1.5)
let enemy3m = SKAction.sequence([move31, move32, move33, move34])
let enemy3move = SKAction.repeatActionForever(enemy3m)
enemy1.runAction(enemy1move)
enemy2.runAction(enemy2move)
enemy3.runAction(enemy3move)
}
func didBeginContact(contact: SKPhysicsContact) {
let collision:UInt32 = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask)
if collision == (playerCat | enemyCat) {
self.removeAllActions()
self.runAction(SKAction.waitForDuration(0.1), completion: {
self.runAction(SKAction.waitForDuration(0.2), completion:
{self.removeAllActions()
self.removeChildrenInArray([enemy1, enemy2, enemy3, player])})
restartButton.size = CGSizeMake(200, 200)
restartButton.position = CGPointMake(512, 384)
restartButton.zPosition = 1
self.addChild(restartButton)
})
}
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if (restartButton .containsPoint(location)) {
restartButton.runAction(fadeAway)
restartButton.removeFromParent()
println(1)
self.runAction(SKAction.waitForDuration(1.5), completion: {
let repeatLevel = SKTransition.fadeWithDuration(2)
let level2 = Level2(fileNamed: "Level2")
self.view?.presentScene(level2, transition: repeatLevel)
})
}
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
当你的 playerCat 和 enemyCat 第一次碰撞时,你的 restartButton 第一次设置了它的大小,这很好。
因为 restartButton 现在有一个大小。您可以检查您的触摸是否在重启按钮的范围内。
if (restartButton .containsPoint(location)) {
就像你这样做了,但你没有检查 restartButton 是否被添加到场景中。 快速修复可能是:
if (restartButton.parent != nil && restartButton .containsPoint(location)) {
如果不是特别需要检查它是否与节点的边界。您可以直接使用它进行检查。这将消除检查 parent.
的需要if (self.nodeAtPoint(location) == restartButton) {
我注意到的另一件事是,在您的碰撞检测中,您从不检查它是否已经发生碰撞。因此,您可能 运行 多次使用相同的代码,只是不断删除所有操作,然后添加新的操作。
您可以添加一个简单的 have 变量来防止冗余
var detectionMade = false
并重置为
override func didMoveToView(view: SKView) {
physicsWorld.contactDelegate = self
initWorld()
movements()
detectionMade = false
...
并在第一次碰撞和检查时设置为真
if collision == (playerCat | enemyCat) && !detectionMade {
detectionMade = true
...
@martinmeincke 我做到了!通过这样做:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if (restartButton .containsPoint(location) && restartButton.parent == nil) {
restartButton.runAction(fadeAway)
println(1)
}
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if (restartButton .containsPoint(location)) {
restartButton.removeFromParent()
self.runAction(SKAction.waitForDuration(1.5), completion: {
let repeatLevel = SKTransition.fadeWithDuration(2)
let level2 = Level2(fileNamed: "Level2")
self.view?.presentScene(level2, transition: repeatLevel)
})
}
}
}