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)
            })

        }
    }
    }