且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在spritekit swift中触摸节点时声音未播放

更新时间:2023-02-01 20:05:33

为什么在按钮上运行声音操作不起作用?

这来自文档:

SKAction对象是由节点中的节点执行的操作 场景(SKScene)...当场景处理其节点时,将评估与这些节点关联的动作.

An SKAction object is an action that is executed by a node in the scene (SKScene)...When the scene processes its nodes, actions associated with those nodes are evaluated.

表示仅当将节点添加到场景时,该节点的操作才会运行 .所以这没有效果:

Means the actions for a node will run only if the node is added to the scene. So this has no effect :

playButton.runAction(sndButtonClick)
playButton.removeFromParent()

因为您已经从场景中删除了按钮,并且在应该执行操作时下一帧中将不显示该按钮.这就是runAction方法的工作原理:

because you have removed the button from the scene and it will not be present in the next frame when actions should be executed. That is how runAction method works:

在节点执行的动作列表中添加一个动作...下一次处理场景的动画循环时,将处理新动作.

Adds an action to the list of actions executed by the node...The new action is processed the next time the scene’s animation loop is processed.

此外,由于您将立即调用presentScene,因此无论如何都不会再有下一帧,因此即使删除removeFromParent语句,声音也不会起作用,因为没有下一帧.

Also, because you are immediately calling presentScene there will be no next frame anyways, so even if you delete removeFromParent statement, sound will not work, because there is no next frame.

为什么在场景上运行声音操作不起作用?

self.runAction(sndButtonClick)将不起作用,因为您要立即进行过渡,而无需等待将要执行排队操作的下一帧(如上所述).

self.runAction(sndButtonClick) won't work because you are making a transition immediately without waiting for a next frame where the queued actions will be executed (like described above).

问题解决方案

要在过渡之前播放声音,您必须等待下一帧,然后可以执行以下操作:

To play the sound before transition, you have to wait for a next frame, and you can do something like:

runAction(sndButtonClick, completion: {
   self.view?.presentScene(nextScene)
})

let block = SKAction.runBlock({
   self.view?.presentScene(nextScene)
})

runAction(SKAction.sequence([sndButtonClick, block]))

防止泄漏:

考虑在捕获自身的块中使用捕获列表,以在需要时避免可能的强引用循环,如下所示:

Consider using capture list inside of a block which captures self to avoid possible strong reference cycles when needed, like this:

let block = SKAction.runBlock({
   [unowned self] in
   //use self here
})

在您的特定情况下,没有场景列表应该很安全,因为场景没有对块的强烈引用.只有块具有对场景的强引用,但是执行该块后,由于没有保留任何内容(无强引用),因此将其释放,因此可以正确释放场景.但是,如果将该块声明为属性,或者执行该块的动作无限运行(使用repeateActionForever方法重复某个序列),则肯定会泄漏.

In this particular case of yours, it should be safe to go without capture list because scene doesn't have a strong reference to the block. Only block has strong reference to the scene, but after the block is executed, because nothing retains it (no strong references to it), it will be released, thus the scene can be released correctly. But, if the block was declared as a property, or the action which executes the block was running infinitely (using repeateActionForever method to repeat a certain sequence), then you will have a leak for sure.

您应该始终重写场景的deinit来查看发生了什么(如果未调用,则保留场景并导致泄漏的东西).

You should always override scene's deinit to see what is going on (if it is not called, something retaining the scene and causing the leak).