如何将多个相同的节点添加到视图中?

时间:2016-08-20 20:07:21

标签: ios swift sprite-kit

我正在尝试编写一段代码,使用计时器,每秒从三个位置中的一个位置从视图顶部“放下”一个球。当第一个球被释放时,它会工作,但是,在计时器再次调用该函数后,代码崩溃,因为它表示该节点无法再次添加到视图中。

有人可以向我解释一下这项工作的方法吗?

import SpriteKit

class GameScene: SKScene {


    //Creates the three circles
    let circleOne = SKSpriteNode(imageNamed: "Circle")
    let circleTwo = SKSpriteNode(imageNamed: "Circle")
    let circleThree = SKSpriteNode(imageNamed: "Circle")

    //Creates dropping ball
    let droppingBall = SKSpriteNode(imageNamed: "Circle")

    //Creates variables to play game
    var gameStarted = false
    var gameOver = false
    var timeInterval = 1.0
    var droppingBallXPosition = 0
    var livesLeft = 3


    //Creates timer for the balls
    var ballTimer = NSTimer()

    override func didMoveToView(view: SKView) {
        /* Setup your scene here */

        //Set background colour
        backgroundColor = UIColor.whiteColor()

        //Assigns position to circles
        circleOne.position = CGPoint(x: (self.frame.width / 2) - 80, y: self.frame.height / 2)
        circleTwo.position = CGPoint(x: (self.frame.width / 2), y: self.frame.height / 2)
        circleThree.position = CGPoint(x: (self.frame.width / 2) + 80, y: self.frame.height / 2)

        //Assigns size to circles
        circleOne.size = CGSize(width: 35, height: 35)
        circleTwo.size = CGSize(width: 350, height: 350)
        circleThree.size = CGSize(width: 35, height: 35)

        //Set colour to circles
        circleOne.color = UIColor.lightGrayColor()
        circleOne.colorBlendFactor = 1.0
        circleTwo.color = UIColor.lightGrayColor()
        circleTwo.colorBlendFactor = 1.0
        circleThree.color = UIColor.lightGrayColor()
        circleThree.colorBlendFactor = 1.0

        //Add circles to view
        self.addChild(circleOne)
        self.addChild(circleTwo)
        self.addChild(circleThree)

        //set properties for falling ball
        droppingBall.position = CGPoint(x: CGFloat(droppingBallXPosition), y: 0)
        droppingBall.size = CGSize(width: 25, height: 25)
        droppingBall.color = UIColor.redColor()
        droppingBall.colorBlendFactor = 1.0
        droppingBall.physicsBody = SKPhysicsBody(circleOfRadius: 25)
        droppingBall.physicsBody?.dynamic = false
        droppingBall.physicsBody?.affectedByGravity = false


        }
    func releaseBall(){
        var whichColumn = arc4random() % 3

        switch whichColumn {
        case 0:
            droppingBall.position = CGPoint(x: (self.frame.width / 2) - 80, y: self.frame.height)
            droppingBall.physicsBody?.dynamic = true
            droppingBall.physicsBody?.affectedByGravity = true
            droppingBall.physicsBody?.friction = 1.0
            self.addChild(droppingBall)
            break
        case 1:
            droppingBall.position = CGPoint(x: (self.frame.width / 2), y: self.frame.height)
            droppingBall.physicsBody?.dynamic = true
            droppingBall.physicsBody?.affectedByGravity = true
            droppingBall.physicsBody?.friction = 1.0
            self.addChild(droppingBall)

            break
        case 2:
            droppingBall.position = CGPoint(x: (self.frame.width / 2) + 80, y: self.frame.height)
            droppingBall.physicsBody?.dynamic = true
            droppingBall.physicsBody?.affectedByGravity = true
            droppingBall.physicsBody?.friction = 1.0
            self.addChild(droppingBall)

            break
        default:
            break
        }
    }



    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
       /* Called when a touch begins */
        if gameStarted == false {
            let zoomOut = SKAction.scaleTo(0.1, duration: 0.2)
            circleTwo.runAction(zoomOut)
            gameStarted = true
        }
        else if gameStarted == true && gameOver == false {
            //check to see if the game is over
            if livesLeft > 0 {
                //Continue game
                ballTimer = NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: #selector(GameScene.releaseBall), userInfo: nil, repeats: true)

            }
            else {
                //The player has lost
                gameOver = true
                gameStarted = false
            }
        }
        else if gameStarted == true && gameOver == true {
            //The player has lost
            gameOver = true
            gameStarted = false
        }

    }



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

错误:

  

尝试添加已有父级的SKNode

3 个答案:

答案 0 :(得分:0)

每次添加另一个球时,您都可以创建一个复制球来添加到场景中。这将是一个替代解决方案,而不是一个正确的答案,因为正确地做这将涉及为球创建一个类。这样,您需要做的就是在每个开关案例中创建一个新的sprite,如下所示:

let ballCopy = droppingBall.copy() as! SKSpritenode

然后,您只需更改其位置(因为使用copy将有关正在复制的节点的所有内容复制到交换机案例所指的位置)。总而言之,它看起来应该是这样的:

func releaseBall(){

        var whichColumn = arc4random() % 3

        droppingBall.physicsBody?.dynamic = true
        droppingBall.physicsBody?.affectedByGravity = true
        droppingBall.physicsBody?.friction = 1.0

        switch whichColumn {

          case 0:

            let ballCopy1 = droppingBall.copy() as! SKSpritenode

            ballCopy1.position = CGPoint(x: (self.frame.width / 2) - 80, y: self.frame.height)
            self.addChild(ballCopy1)

            break

          case 1:

            let ballCopy2 = droppingBall.copy() as! SKSpritenode

            ballCopy2.position = CGPoint(x: (self.frame.width / 2), y: self.frame.height)
            self.addChild(ballCopy2)

            break

          case 2:

            let ballCopy3 = droppingBall.copy() as! SKSpritenode

            ballCopy3.position = CGPoint(x: (self.frame.width / 2) + 80, y: self.frame.height)

            self.addChild(ballCopy3)

            break

          default:
                break
            }
        }

答案 1 :(得分:0)

屏幕上只有一个球吗?如果是这样,你可以改变你的功能:

func releaseBall(){
self.droppingball.removefromparent()

    var whichColumn = arc4random() % 3
    switch whichColumn {
    case 0:
        droppingBall.position = CGPoint(x: (self.frame.width / 2) - 80, y: self.frame.height)
        droppingBall.physicsBody?.dynamic = true
        droppingBall.physicsBody?.affectedByGravity = true
        droppingBall.physicsBody?.friction = 1.0
        self.addChild(droppingBall)
        break
    case 1:
        droppingBall.position = CGPoint(x: (self.frame.width / 2), y: self.frame.height)
        droppingBall.physicsBody?.dynamic = true
        droppingBall.physicsBody?.affectedByGravity = true
        droppingBall.physicsBody?.friction = 1.0
        self.addChild(droppingBall)

        break
    case 2:
        droppingBall.position = CGPoint(x: (self.frame.width / 2) + 80, y: self.frame.height)
        droppingBall.physicsBody?.dynamic = true
        droppingBall.physicsBody?.affectedByGravity = true
        droppingBall.physicsBody?.friction = 1.0
        self.addChild(droppingBall)

        break
    default:
        break
    }
}

这应该允许您多次运行该功能。 如果系统需要多个球。您可以创建第二个精灵节点和第二个func来释放球并将计时器设置为在不同日期开始。

像这样:

    var droppingball = SKSpriteNode(imageNamed: "Circle")
         var droppingball0 = SKSpriteNode(imageNamed: "Circle")
func releaseBall(){
self.droppingball.removefromparent()
var whichColumn = arc4random() % 3
switch whichColumn {
case 0:
    droppingBall.position = CGPoint(x: (self.frame.width / 2) - 80, y: self.frame.height)
    droppingBall.physicsBody?.dynamic = true
    droppingBall.physicsBody?.affectedByGravity = true
    droppingBall.physicsBody?.friction = 1.0
    self.addChild(droppingBall)
    break
case 1:
    droppingBall.position = CGPoint(x: (self.frame.width / 2), y: self.frame.height)
    droppingBall.physicsBody?.dynamic = true
    droppingBall.physicsBody?.affectedByGravity = true
    droppingBall.physicsBody?.friction = 1.0
    self.addChild(droppingBall)

    break
case 2:
    droppingBall.position = CGPoint(x: (self.frame.width / 2) + 80, y: self.frame.height)
    droppingBall.physicsBody?.dynamic = true
    droppingBall.physicsBody?.affectedByGravity = true
    droppingBall.physicsBody?.friction = 1.0
    self.addChild(droppingBall)

    break
default:
    break
}
}
func releaseBall0(){
self.droppingball.removefromparent()

var whichColumn = arc4random() % 3
switch whichColumn {
case 0:
    droppingBall.position = CGPoint(x: (self.frame.width / 2) - 80, y: self.frame.height)
    droppingBall0.physicsBody?.dynamic = true
    droppingBall0.physicsBody?.affectedByGravity = true
    droppingBall0.physicsBody?.friction = 1.0
    self.addChild(droppingBall)
    break
case 1:
    droppingBall0.position = CGPoint(x: (self.frame.width / 2), y: self.frame.height)
    droppingBall0.physicsBody?.dynamic = true
    droppingBall0.physicsBody?.affectedByGravity = true
    droppingBall0.physicsBody?.friction = 1.0
    self.addChild(droppingBall0)

    break
case 2:
    droppingBall0.position = CGPoint(x: (self.frame.width / 2) + 80, y: self.frame.height)
    droppingBall0.physicsBody?.dynamic = true
    droppingBall0.physicsBody?.affectedByGravity = true
    droppingBall0.physicsBody?.friction = 1.0
    self.addChild(droppingBall0)

    break
default:
    break
}

} 然后,您需要做的就是找出您想要调用此函数的间隔,并将两个定时器添加到该间隔的两倍。例如,如果我想每秒发射一次,你会创建两个定时器间隔为2秒的定时器,并告诉一个定时器在第一个定时器之后开始1秒,然后将其装入:

        dispatch_after(
                dispatch_time(
                    DISPATCH_TIME_NOW,
                    Int64(1 * Double(NSEC_PER_SEC))
                ),
                dispatch_get_main_queue(),
                {
// your timer
 })

答案 2 :(得分:0)

您收到错误的原因是因为Node已经添加到场景中,您只能添加一次。您需要创建一个新的SKSpriteNode实例,然后在每次想要另一个球时将其添加到场景中。您可能希望为球创建自定义类并将其存储在列表中,以便在需要时识别每个类。