简体   繁体   English

如何在Swift 2的while循环内创建延迟?

[英]How can I create delay inside while loop in Swift 2?

I would need help with this while loop - what I'm trying to do is slow down the whole process of removing and adding new circles while radius is changing every time this happens. 我需要与此while循环相关的帮助-我想做的是在每次发生半径变化时都减慢了删除和添加新圆的整个过程。 I'm becoming really desperate, I've tried using both dispatch_after and sleep inside the loop (which I found online) but neither of them is suitable, they basically stop the whole app. 我变得非常绝望,我尝试在循环中使用dispatch_after和sleep(我在网上找到了它们),但是它们都不适合,它们基本上停止了整个应用程序。 If I put them in the while loop, nothing happens. 如果我将它们放在while循环中,则不会发生任何事情。 Thanks in advance! 提前致谢!

while radius < 100 {

    self.removeAllChildren()
    addCircle()
    radius++
    print(radius)            
}

Basically you just need to do few simple things: 基本上,您只需要做一些简单的事情:

  • Wait for a certain duration and add a node to the scene 等待一定的时间,然后将一个节点添加到场景中
  • Repeat this step forever ( or certain number of times ) 永久重复此步骤( 或一定次数

Here is the example of how you can do it. 这是如何做到的例子。 The important part is action sequence. 重要的部分是动作顺序。 You create the step above, and repeat it forever. 您创建了上面的步骤,并永久重复。 Each time you check radius value and based on that you stop the action (remove it by the key). 每次检查半径值并以此为基础停止操作(通过键将其删除)。 And that's it. 就是这样。 You can change spawning speed by changing action's duration parameter. 您可以通过更改操作的duration参数来更改生成速度。

Using NSTimer might seem like an easier solution, but NSTimer doesn't respect node's (or scene's or view's) paused state. 使用NSTimer似乎是一个更简单的解决方案,但是NSTimer不考虑节点(或场景或视图)的暂停状态。 So, imagine this situation: 因此,想象一下这种情况:

  • You start spawning of nodes 您开始生成节点
  • User receive phone call and app automatically goes to background 用户接听电话,应用程序自动进入后台

Because NSTimer is not automatically paused, the nodes will continue with spawning. 由于NSTimer不会自动暂停,因此节点将继续产生。 So you have to take an additional step and invalidate/restart timer by your self. 因此,您必须自己采取其他步骤并使计时器无效/重新启动。 When using SKAction, this is done automatically. 使用SKAction时,这是自动完成的。 There are some other flaws of using NSTimer in SpriteKit, search SO about all that, there are some posts which covering all this. 在SpriteKit中使用NSTimer还有一些其他缺陷,请在所有内容中进行搜索,还有一些文章涵盖了所有这些内容。

import SpriteKit

class GameScene: SKScene{

    var radius:UInt32 = 0

    override func didMoveToView(view: SKView) {

        startSpawning()
    }

    func startSpawning(){

        let wait = SKAction.waitForDuration(0.5)

       // let wait = SKAction.waitForDuration(1, withRange: 0.4) // randomize wait duration

        let addNode = SKAction.runBlock({

            [unowned self] in //http://stackoverflow.com/a/24320474/3402095 - read about strong reference cycles here

            if(self.radius >= 30){ 

                if self.actionForKey("spawning") != nil {

                    self.removeActionForKey("spawning")
                }
            }

            self.radius++
            let sprite = self.spawnNode()
            sprite.position = CGPoint(x: Int(arc4random()) % 300,  y: Int(arc4random()) % 300) // change this to randomize sprite's position to suit your needs

            self.addChild(sprite)
        })
        //wait & add node   
        let sequence = SKAction.sequence([wait, addNode])
        //repeat forever
        runAction(SKAction.repeatActionForever(sequence), withKey: "spawning")

    }

    func spawnNode()->SKSpriteNode{
        let sprite = SKSpriteNode(color: SKColor.purpleColor(), size: CGSize(width: 50, height: 50))
        //Do sprite initialization here
        return sprite
    }
}

The sleep stops the whole app because you are running the loop on the main thread. 睡眠会停止整个应用程序,因为您正在主线程上运行循环。

You can solve this problem in one of two ways... 您可以通过以下两种方法之一解决此问题:

1) Use an NSTimer. 1)使用NSTimer。 Set it to the amount of time you want to delay. 将其设置为您要延迟的时间。 Put the body of the loop in the timer's trigger function and disable the timer when it has been called enough times. 将循环的主体放入计时器的触发函数中,并在调用足够多次后禁用计时器。 This is the best solution. 这是最好的解决方案。

2) Wrap the loop in a dispatch async block to a background thread and put a sleep in the loop. 2)将循环在调度异步块中包装到后台线程,并在循环中放入睡眠。 If you do this though, you will have to wrap the UI code in another dispatch async block that comes back to the main thread. 但是,如果这样做,则必须将UI代码包装在另一个返回主线程的调度异步块中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM