为啥我的 SpriteKit update() 函数会创建多个 NSTimers?

Posted

技术标签:

【中文标题】为啥我的 SpriteKit update() 函数会创建多个 NSTimers?【英文标题】:Why is my SpriteKit update() function creating multiple NSTimers?为什么我的 SpriteKit update() 函数会创建多个 NSTimers? 【发布时间】:2016-02-28 05:04:59 【问题描述】:

我正在创建一个 SpriteKit 游戏,它会根据经过的时间进行更新。游戏使用NSTimer 及其scheduledTimerWithTimeInterval 方法生成敌人,每2.0 秒调用一次spawnEnemy 函数。

当 5 秒过去后,应该有一个非常短暂的中场休息,防止新敌人生成以显示关卡变化动画。

当到达最初的 5 秒时,一切正常,直到条件 self.nextLevelDelayTicker == 100。一旦满足此条件,"YOLO" 字符串只会在控制台中触发一次。但是,我假设NSTimer 的多个实例被创建并存储在self.timer 中,因为在调用self.resumeGame() 以创建新的预定计时器后会产生大量敌人。

关于为什么会发生这种情况的任何想法,即使我在条件中设置了标志,只调用一次 self.resumeGame() 函数?

func resumeGame() 
    // Start game timer
    // Need a way to access ib action of pause button
    self.timer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: "spawnEnemy", userInfo: nil, repeats: true)


override func update(currentTime: CFTimeInterval) 
    /* Called before each frame is rendered */
    if gameTicker.isActive == true 
        gameTicker.increment()
    

    // If gameTicker is equal to 5 seconds, increase enemy amount
    if gameTicker.getTimePassed() % 500 == 0 
        self.enemyAmount += 1
        self.timer?.invalidate()
        levelCount += 1

        gameTicker.isActive = false
    

    // If level has been completed and last ghost has been killed, activate next level scene
    if gameTicker.isActive == false && enemyArray.count == 0 
        self.nextLevelDelayTicker.increment()

        if self.nextLevelDelayTicker.getTimePassed() == 100 
            print("YOLO")
            self.gameTicker.isActive = true
            self.nextLevelDelayTicker.reset()
            self.resumeGame()
        
    

【问题讨论】:

下面的答案值得考虑,但就您的问题而言,您创建了计时器变量并放置在更新中。每次调用 update 时都会创建一个新的计时器,因此尽管下面的答案很好,但我喜欢使用 skaction 并在那里创建我的计时器并在适当的变量中而不是在 update 方法中调用它们。但这只是我。???? 【参考方案1】:

尝试遵循您的代码.. 但我认为您在这里的方法对于 spritekit 来说不是很好。它可能使事情变得比它需要的复杂得多。

您可以直接使用更新方法来跟踪时间。重写这部分代码可能值得。在 spritekit 中会更好地工作,并且不太容易出现错误。

您真正需要的只是增量时间。

场景属性

// time values
var delta = NSTimeInterval(0)
var last_update_time = NSTimeInterval(0)

// some time youre trying to keep track of
var timeLimit = NSTimeInterval(5)
var timeLimitMax = NSTimeInterval(5)

场景的更新方法

 func update(currentTime: NSTimeInterval) 
        if last_update_time == 0.0 
            delta = 0
         else 
            delta = currentTime - last_update_time
        

        last_update_date = currentTime

        // now we can keep track of time
        timeLimit -= self.delta
        if timeLimit <= 0 
            // do something and reset timer
            timeLimit = timeLimitMax
        

现在,如果您要持续每隔几秒生成一些东西,那么我们甚至不需要打扰 update 来执行此操作。只需将其放入您的viewDidLoad

现在我们将永远每两秒运行一次此代码。最好的部分是这将自动暂停和恢复您的游戏。您不必过多地管理 SKAction。 spritekit 为你做的:)

let spawnAction = SKAction.repeatActionForever(
    SKAction.sequence([
        SKAction.waitForDuration(2),
        SKAction.runBlock(
            [unowned self] in
            self.spawnEnemy()   
        )
    ])
)
runAction(spawnAction)

【讨论】:

我赞成你的回答,因为这是 SpriteKit 的做法,但你应该稍微改变 spawnAction。首先,您需要在块内显式地使用 self 才能进行编译。其次,它将创建强引用循环,并且在过渡到下一个场景后,场景永远不会被释放,因为自我被捕获并且动作是无止境的。所以在过渡之前,要么显式删除动作,要么在块内使用捕获列表(无主的自我)将解决问题。 好点..我在没有 xcode 的情况下编写了这段代码,所以我确定它不是 100% 完美的。我会编辑。 关于基于计时器生成敌人的非常好的答案。我摆脱了我所有的NSTimers,并用一个 SKAction 取而代之。暂停/恢复功能现在就像一个魅力。不过有一件事,我需要能够每 15 秒暂停一次spawnAction SKAction 5 秒,以显示动画并防止敌人在此期间生成。一旦 5 秒延迟结束,我需要能够重新激活 SKAction。是否有可用的暂停SKAction 方法? 我是否只需将大约 7 个 SKAction.waitForDuraction(2)s 硬编码到 SKAction.repeatActionForever 中,然后在最后添加一个 SKAction.waitForDuraction(5)?需要注意的是,只有在所有敌人都被杀死/从场景中移除后,才能激活 5 秒的动画延迟。 我读了你写的几遍,并没有真正理解你想要做什么。但是,一旦它变得像这样复杂,我倾向于开始使用 update 和 ditch skaction。当你做一次性的事情时,Skaction 很棒。但是一旦设置好,你就不能修改它。您只能取消它并制作一个新的。如果涉及到逻辑和不断变化的条件,那么此时最好使用更新

以上是关于为啥我的 SpriteKit update() 函数会创建多个 NSTimers?的主要内容,如果未能解决你的问题,请参考以下文章

SpriteKit - 为啥我的游戏会随着新 iOS 版本的发布而出现错误?

为啥我的声音让我的游戏在 Swift Spritekit 中滞后?

如何在 Spritekit 中停止 func update(_ currentTime: TimeInterval)

为啥我的音频会在 Sprite Kit 场景转换之前播放?

为啥这个 UPDATE 查询会杀死我的 CPU?

为啥我的 SELECT 查询不需要我的 UPDATE 查询需要这么长时间?