2016-05-23 57 views
0

我想让我的节点在屏幕上移动并在定时器上无限生成。我希望一次在屏幕上有多个节点。这是我迄今为止的稳定代码。我尝试了多种冻结或崩溃的方法。swift繁殖节点infinietly

let bunnyTexture = SKTexture(imageNamed: "oval 1.png") 
    bunny = SKSpriteNode(texture: bunnyTexture) 
    bunny.position = CGPoint(x: (size.width/3), y: 750 + bunny.frame.height) 
    self.addChild(bunny) 
    bunny.physicsBody = SKPhysicsBody(circleOfRadius: bunnyTexture.size().height/2) 
    bunny.physicsBody!.dynamic = true 
    let spawnBunny = SKAction.moveByX(0, y: -self.frame.size.height, duration: 4) 
    let despawnBunny = SKAction.removeFromParent() 
    let spawnNdespawn2 = SKAction.sequence([spawnBunny, despawnBunny]) 
    bunny.runAction(spawnNdespawn2) 

    let gobblinTexture = SKTexture(imageNamed: "oval 2.png") 
    gobblin = SKSpriteNode(texture: gobblinTexture) 
    gobblin.position = CGPoint(x: 150 + gobblin.frame.width, y: (size.height/3)) 
    self.addChild(gobblin) 
    let randomGob = arc4random() % UInt32(self.frame.size.height/2) 
    let spawnGob = SKAction.moveByX(+self.frame.size.width, y: 0, duration: 4) 
    let despawnGob = SKAction.removeFromParent() 
    let spawnNdespawn = SKAction.sequence([spawnGob, despawnGob]) 
    gobblin.runAction(spawnNdespawn) 

    let ground = SKNode() 
    ground.position = CGPointMake(0, 0) 
    ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, -50)) 
    ground.physicsBody!.dynamic = false 
    self.addChild(ground) 

回答

0

您可以使用SKAction.waitForDuration(interval)创建循环定时器。

用新功能loopAction扩展SKNode。这需要SKActionNSTimeInterval() -> Bool函数。

SKAction是将在每个时间间隔执行的功能。 () -> Bool函数将用于停止否则无限循环。

请记住,这会捕获SKNodeSKAction。在循环停止之前,它们都不会释放。

它可能创建一个标志对象(Bool)来保存所有这些信息,并设置标志为false时,它需要停止。我只是喜欢这种方式。

​​是如何实施loopAction的示例。 您需要一个SKNodeSKAction。您可以调用loopAction并调用区间和控制何时停止的函数,而不是在SKNode上调用runAction您可以将此代码放置在有权访问相关节点的某个位置。

功能停止,也可以实现为trailing closure

将代码粘贴到操场,看看它是如何工作的。

import UIKit 
import SpriteKit 
import XCPlayground 



extension SKNode { 

    func loopAction(action:SKAction,interval:NSTimeInterval,continueLoop:() -> Bool) { 

     guard continueLoop() else { return } 

     runAction(SKAction.waitForDuration(interval)) { 

      if continueLoop() { 
       self.runAction(action) 
       self.loopAction(action, interval: interval, continueLoop: continueLoop) 
      } 
     } 
    } 
} 

// example 
class LoopActionManager { 

    let node = SKSpriteNode(color: UIColor.whiteColor(), size: CGSize(width: 20, height: 20)) 
    let action = SKAction.moveBy(CGVector(dx: 10,dy: 0), duration: 0.5) 

    func continueMoveLoop() -> Bool { 
     return (node.position.x + node.size.width) < node.scene?.size.width 
    } 

    func start() { 
     node.loopAction(action, interval: 1, continueLoop: continueMoveLoop) 
    } 

} 

let view = SKView(frame: CGRect(x: 0, y: 0, width: 200, height: 200)) 
let scene = SKScene(size: view.frame.size) 
view.presentScene(scene) 

let example = LoopActionManager() 
scene.addChild(example.node) 
example.start() 



XCPlaygroundPage.currentPage.liveView = view 

由于在它下面的注释中规定,也可以使用repeatAction。 您可以使用static func扩展SKAction以基于重复动作和间隔生成repeatAction。 与第一种解决方案相比,这更简单,更符合SDK。您确实会丢失每个间隔的完成处理程序。

import UIKit 
import SpriteKit 
import XCPlayground 


extension SKAction { 

    static func repeatAction(action:SKAction,interval:NSTimeInterval) -> SKAction { 

     // diff between interval and action.duration will be the wait time. This makes interval the interval between action starts. Max of 0 and diff to make sure it isn't smaller than 0 
     let waitAction = SKAction.waitForDuration(max(0,interval - action.duration)) 
     let sequenceAction = SKAction.sequence([waitAction,action]) 
     let repeatAction = SKAction.repeatActionForever(sequenceAction) 

     return repeatAction 

    } 
} 


let view = SKView(frame: CGRect(x: 0, y: 0, width: 200, height: 200)) 
let scene = SKScene(size: view.frame.size) 
view.presentScene(scene) 

let node = SKSpriteNode(color: UIColor.whiteColor(), size: CGSize(width: 20, height: 20)) 
let action = SKAction.moveBy(CGVector(dx: 10,dy: 0), duration: 0.5) 

scene.addChild(node) 
node.runAction(SKAction.repeatAction(action, interval: 1.0)) 



XCPlaygroundPage.currentPage.liveView = view 
+0

这是为什么如此复杂?将2个动作(等待和移动)放在一个序列中,然后使用重复动作不会更容易吗?同样,如果继续循环为假,为什么还要等待 – Knight0fDragon

+0

@ Knight0fDragon'continueLoop()'可以/应该尽可能多次评估,在wait之前和之后都是有意义的。我之所以选择“等待”是因为它会在最后一个动作运行后进行评估。如果时机不同,这将不再是事实。看着'repeatAction' ... –

+0

@ Knight0fDragon你说得对,'repeatAction'确实提供了一个更清洁的解决方案。我将它添加到我的答案中。好决定! –