取消分配playSoundFileNamed操作时防止SpriteKit游戏崩溃

时间:2019-07-13 10:30:05

标签: ios swift sprite-kit

我有一个使用SpriteKit制作的基于物理的2D游戏。 越来越多的小球与许多块碰撞。 每当球碰到一个障碍物时,我都想发出声音。

目前,我使用playSoundFileNamed(_:waitForCompletion:)并将其waitForCompletion参数始终设置为false来播放声音(这样它可以快速播放多种声音)。

这在性能和帧速率方面非常有效,但是我收到越来越多的关于失败的重新分配的崩溃报告。

仅当在游戏本身从不取消分配GameScene时,才会发生这种情况。

我尝试用SKAudioNode代替SKAction,但是不能连续快速播放多种声音,因此游戏感觉不对。

我尝试加入GameAudioPlayer,但是在播放大量声音时帧频会大大降低。

这是我现在播放声音的方式:

class GameScene: SKScene {
    private var popSound = SKAction.playSoundFileNamed("Pop.wav", waitForCompletion: false)
    private var starSound = SKAction.playSoundFileNamed("Star.wav", waitForCompletion: false)
    private var whooshSound = SKAction.playSoundFileNamed("Whoosh.wav", waitForCompletion: false)

    // ...

    func didEnd(_ contact: SKPhysicsContact) {
        // ball-to-block collision
        self.run(popSound)
    }
}

这是来自Crashlytics的堆栈跟踪

Fatal Exception: NSRangeException
0  CoreFoundation                 0x1ec81527c __exceptionPreprocess
1  libobjc.A.dylib                0x1eb9ef9f8 objc_exception_throw
2  CoreFoundation                 0x1ec78ece8 _CFArgv
3  CoreFoundation                 0x1ec700298 -[__NSArrayM removeObjectsInRange:]
4  SpriteKit                      0x20354ee3c -[SKSoundSource purgeCompletedBuffers]
5  SpriteKit                      0x20354f0d4 -[SKSoundSource dealloc]
6  SpriteKit                      0x203523b14 -[SKPlaySound .cxx_destruct]
7  libobjc.A.dylib                0x1eb9ee7cc object_cxxDestructFromClass(objc_object*, objc_class*)
8  libobjc.A.dylib                0x1eb9fe6b8 objc_destructInstance
9  libobjc.A.dylib                0x1eb9fe720 object_dispose
10 SpriteKit                      0x203485c08 -[SKAction dealloc]
11 SpriteShot                     0x1005f8418 @objc GameScene.__ivar_destroyer (GameScene.swift)
12 libobjc.A.dylib                0x1eb9ee7cc object_cxxDestructFromClass(objc_object*, objc_class*)
13 libobjc.A.dylib                0x1eb9fe6b8 objc_destructInstance
14 libobjc.A.dylib                0x1eb9fe720 object_dispose
15 UIKitCore                      0x219145b28 -[UIResponder dealloc]
16 SpriteKit                      0x203504be4 -[SKNode dealloc]
17 SpriteKit                      0x2034bade0 -[SKScene dealloc]
18 SpriteShot                     0x1005f83d4 @objc GameScene.__deallocating_deinit (<compiler-generated>)
19 SpriteKit                      0x2034e2004 -[SKView _update:]
20 SpriteKit                      0x2034dd7f4 __51-[SKView _vsyncRenderForTime:preRender:postRender:]_block_invoke.351
21 SpriteKit                      0x2034dcbf8 -[SKView _vsyncRenderForTime:preRender:postRender:]
22 SpriteKit                      0x2034dfc54 __29-[SKView setUpRenderCallback]_block_invoke
23 SpriteKit                      0x203522c18 -[SKDisplayLink _callbackForNextFrame:]
24 QuartzCore                     0x1f0b9cf90 CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long)
25 QuartzCore                     0x1f0c66b10 display_timer_callback(__CFMachPort*, void*, long, void*)
26 CoreFoundation                 0x1ec780a8c __CFMachPortPerform
27 CoreFoundation                 0x1ec7a7690 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
28 CoreFoundation                 0x1ec7a6ddc __CFRunLoopDoSource1
29 CoreFoundation                 0x1ec7a1c00 __CFRunLoopRun
30 CoreFoundation                 0x1ec7a10b0 CFRunLoopRunSpecific
31 GraphicsServices               0x1ee9a179c GSEventRunModal
32 UIKitCore                      0x21911b978 UIApplicationMain
33 SpriteShot                     0x1005f1910 main + 16 (Ball.swift:16)
34 libdyld.dylib                  0x1ec2668e0 start

1 个答案:

答案 0 :(得分:1)

强烈建议您在此处阅读我的答案:https://stackoverflow.com/a/56615200/5277976

我的最终结论是对所有内容都使用AVAudioPlayer:音乐和声音。创建AVAudioPlayer实例,使每种声音的最大数量最适合您的情况。此处给出一个示例:https://www.oreilly.com/library/view/ios-swift-game/9781491920794/ch04.html

请注意,O'Reilly所做的不完全是我所说的或最终要做的:在他们的情况下,它们允许您生成更多的AVAudioPlayers,但鉴于我们将有多少重叠的声音,我发现这对性能产生了很大影响一次-如果您有很多相同类型的重叠声音,在某个时候就应该调用它,但是我让您自己决定。

在我们的案例中,如果我们有经常播放且重叠的声音,我们将保留几个播放器(但不是无限播放器,例如在O'Reilly的例子中)。请注意,重叠播放的声音越多,演奏的效果就越差。据我所知,这是没有办法的。保持尽可能多的声音给1个播放器。为此,我们有一个单独的枚举。

PlaySoundFileNamed重量更轻,性能似乎更好;不幸的是,它实际上已经损坏了–在IAP购买过程中它使我们的应用程序崩溃了,那是不对的。考虑到它已经损坏了多长时间,我怀疑它是否会修复。 SKAudioNode具有您所描述的局限性,我将方钉插入圆孔的尝试由于各种原因而失败。

正如我在那儿解释的那样,拥有许多AVAudioPlayer实例并不是理想的解决方案,但是当涉及到它时,这是最坏的情况中最好的。

我还要指出,像这样的问题使我们完全脱离了SpriteKit,现在我们使用Unity。