开始一个节点暂停的场景

Posted

技术标签:

【中文标题】开始一个节点暂停的场景【英文标题】:starting a scene with a node paused 【发布时间】:2017-01-09 16:35:18 【问题描述】:

我正在开发一款基于 SpriteKitSwift 的情侣的 ios 游戏。从 iOS 7.1 定位

我在游戏中实现短音效的方式是使用SKAction.playSoundFileNamed 方法运行动作,该方法在专门为此目的添加的普通层节点上执行:

let SoundsLayerNode = SKNode()

self.addChild(SoundsLayerNode)

SoundsLayerNode.runAction(soundXXX)

通过暂停整个节点 (SoundsLayerNode.paused = true) 可以很容易地使 FX 声音静音,然后再次打开声音,取消暂停节点 (SoundsLayerNode.paused = false)

当我尝试在节点暂停的情况下启动场景时出现问题。在 func didMoveToView 方法中我设置了 SoundsLayerNode.paused = true 但在第一个 Spritekit 循环开始后,节点会自动取消暂停

看来,SpriteKitdidmovetoview 完成后强制场景(自身)取消暂停,因此它的所有后代都取消暂停,从而触发了声音层节点上令人不快的副作用

你知道怎么解决吗?

谢谢

【问题讨论】:

尝试将此runAction (SKAction.runBlockself.SoundsLayerNode.paused = true) 添加到didMoveToView 恐怕它不起作用,因为问题发生在第一个渲染循环结束(或第二个循环开始)之后。如果我在 didMoveToView 中运行一个动作,它会在触发“取消暂停”效果之前的第一个 -didEvaluateAction 方法中执行 【参考方案1】:

一种解决方案是在节点上运行一个 SKAction 以在一定时间(例如 0.1 秒)后暂停它。

var pauseAction = SKAction.sequence([SKAction.wait(forDuration: 0.1), SKAction.pause()])
node.run(pauseAction)

您可以尝试使用 0.1,看看您可以将其设置到多低才能使其仍能正常工作。

如果这不起作用,你可以在你的 GameScene 中做一个这样的解决方法:

var pauseToggle = true

override func didFinishUpdate() 
   
        if(pauseToggle)
          SoundsLayerNode.paused = true
          pauseToggle = false
        
   

这是一种很垃圾的做法,但应该也可以。

【讨论】:

第二个选项仍然失败。我不知道为什么在第一个渲染循环中我不能暂停节点。似乎有必要跳过第二个循环。也许我可以尝试类似计数器的方法,并在计数器 ==2 时设置 SoundsLayerNode.paused = true。但是我不太喜欢这个选项 @Codediver 失败,因为节点中的仍然未暂停?是的,我同意即使使用布尔值也是一种令人讨厌的方式。也许在其他地方您正在取消暂停节点而不知道它。您的 GameScene 代码是否足够短,可以放入您的帖子中? MarshallD,您有机会阅读我的新帖子吗?我运行了一个简单的测试并检查了 testNode 在第一个循环结束时是否自动取消暂停。我有点困惑。【参考方案2】:

代码很长,但我尝试了一个简单的 GameScene 测试,所以如果我运行该应用一段时间,您可以查看控制台中显示的结果:

在 didMoveToView 内部 testNode 已暂停:true 场景(自身)已暂停:false

循环更新:0 testNode 已暂停:true 场景(自身)已暂停:false

Loop_didEvaluateActions:0 testNode 已暂停:true 场景(自身)已暂停:false

Loop_didFinishUpdate: 0 testNode 已暂停:true 场景(自身)已暂停:false

循环更新:1 testNode 已暂停:假 场景(自身)已暂停:false

Loop_didEvaluateActions:1 testNode 已暂停:假 场景(自身)已暂停:false

Loop_didFinishUpdate: 1 testNode 已暂停:假 场景(自身)已暂停:false

spritekit 是否强制场景在第一次渲染循环后自行取消暂停?

//
//  Test on paused Nodes
//

import SpriteKit


class GameScene: SKScene 

    let testNode = SKNode()
    var loopCounter:Int = 0


    override func didMoveToView(view: SKView) 

    self.addChild(testNode)
    testNode.paused = true

    print ("Inside didMoveToView")
    print("testNode is paused:",testNode.paused)
    print("scene(self) is paused:",scene!.paused)
    print("")



override func update(currentTime: CFTimeInterval) 

    print ("Loop_Update:",loopCounter)
    print("testNode is paused:",testNode.paused)
    print("scene(self) is paused:",scene!.paused)
    print("")



override func didEvaluateActions() 

    print ("Loop_didEvaluateActions:",loopCounter)
    print("testNode is paused:",testNode.paused)
    print("scene(self) is paused:",scene!.paused)
    print("")



override func didFinishUpdate() 

    // This is the last chance to make changes to the scene

    print ("Loop_didFinishUpdate:",loopCounter)
    print("testNode is paused:",testNode.paused)
    print("scene(self) is paused:",scene!.paused)
    print("")

    loopCounter=loopCounter+1



// After didFinishUpdate SKView renders the scene. 
// Does spritekit force the scene to unpause itself here?

【讨论】:

根据您在此处所拥有的内容,您似乎是正确的,该节点最终不会暂停。如果在 didMoveToView 之后调用了一个方法,那么我不知道它。最好的解决方案是解决它 - 我有一个想法涉及一个 SKAction,它在大约 0.5 秒后被调用一次 - 你想让我把它添加到我的答案中吗? 是的,它确实发生在第一个渲染循环的末尾。我希望有人可以知道原因。请添加您的代码,这听起来很有趣,我想评价您的帮助 谢谢。您找到了问题的解决方案。您的代码给了我错误,但我根据您的解决方案重写了它: runAction (SKAction.sequence([SKAction.waitForDuration(0.1), SKAction.runBlockself.SoundsLayerNode.paused = true])) 在第一个 SKAction 中等待 0.1 秒已经足够短了,我认为每个渲染循环持续 0.0166 秒(60fps 时为 1/60 秒),所以 0.02 秒也应该足够短,0.1 可以正常工作: )

以上是关于开始一个节点暂停的场景的主要内容,如果未能解决你的问题,请参考以下文章

WSFC 状态操作指南

Cassandra:将新节点引导到集群时,Long Par New GC 暂停

SpriteKit Swift 2.0 游戏:跨多个场景的按钮和节点

WSFC 维护模式操作粒度控制

从另一层重新启动游戏/场景

Redis学习 —— 主从同步