OpenAL vs AVAudioPlayer vs 其他播放声音的技术



我知道 OpenAL 是快速库,但它不支持任何压缩音频格式,而且使用起来并不容易......

AVAudioPlayer不是那么快,但支持广泛的文件格式,以及mp3等压缩格式。

还有一个SKAction类可以播放声音,以及SystemSoundID...

我有几个问题:

  1. 什么是首选的玩法/玩家/技术:

    • 音效(当时多个)?
    • 声音效果,有时会在小时间延迟后重复
    • 循环播放的背景音乐
  2. 另外,使用未压缩的音频进行音效是否明智之举?我想这没关系,因为这些文件无论如何都很小?

我个人正在使用ObjectAL。 这很好,因为它利用了OpenAL和AVAudioPlayer,但从你那里抽象出了很多复杂的部分。 我的游戏有背景音乐,同时播放大量声音,以及根据精灵速度增加音量、音高等的可循环声音。 ObjectAL可以做到这一切。

ObjectAL可用于使用其OALSimpleAudio类播放简单的声音和音乐循环。 或者你可以更深入地研究它,做更复杂的事情。

我专门为我的游戏创建了一个围绕 ObjectAL 的简单包装器,因此它进一步从我身上抽象出来。

从我所读到的内容来看,未压缩的音频更好。 您只需要确保预加载声音,这样您的游戏就不会在每次播放声音时都尝试拉取文件。

这个非常简单的类为我完美地为多个项目提供服务,同时运行许多声音。我发现这比对OpenAL大惊小怪要简单得多。它具有您要求的一切,预先设置的声音,多个并发播放,延迟后,背景循环。

是否使用压缩文件并不重要,因为您首先设置了它。

斯库迪奥·

#import <Foundation/Foundation.h>
@import AVFoundation;
@interface SKAudio : NSObject
+(AVAudioPlayer*)setupRepeatingSound:(NSString*)file volume:(float)volume;
+(AVAudioPlayer*)setupSound:(NSString*)file volume:(float)volume;
+(void)playSound:(AVAudioPlayer*)player;
+(void)playSound:(AVAudioPlayer*)player afterDelay:(float)delaySeconds;
+(void)pauseSound:(AVAudioPlayer*)player;
@end

斯库迪奥

#import "SKAudio.h"
@implementation SKAudio
#pragma mark -
#pragma mark setup sound
// get a repeating sound
+(AVAudioPlayer*)setupRepeatingSound:(NSString*)file volume:(float)volume {
    AVAudioPlayer *s = [self setupSound:file volume:volume];
    s.numberOfLoops = -1;
    return s;
}
// setup a sound
+(AVAudioPlayer*)setupSound:(NSString*)file volume:(float)volume{
    NSError *error;
    NSURL *url = [[NSBundle mainBundle] URLForResource:file withExtension:nil];
    AVAudioPlayer *s = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
    s.numberOfLoops = 0;
    s.volume = volume;
    [s prepareToPlay];
    return s;
}
#pragma mark sound controls
// play a sound now through GCD
+(void)playSound:(AVAudioPlayer*)player {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [player play];
    });
}
// play a sound later through GCD
+(void)playSound:(AVAudioPlayer*)player afterDelay:(float)delaySeconds {
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delaySeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        [player play];
    });
}
// pause a currently running sound (mostly for background music)
+(void)pauseSound:(AVAudioPlayer*)player {
    [player pause];
}
@end

要在游戏中使用:

设置一个类变量并用您的声音预加载它:

static AVAudioPlayer *whooshHit;
static AVAudioPlayer *bgMusic;
+(void)preloadShared {
    // cache all the sounds in this class 
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
       whooshHit = [SKAudio setupSound:@"whoosh-hit-chime-1.mp3" volume:1.0];
       // setup background sound with a lower volume
       bgMusic = [SKAudio setupRepeatingSound:@"background.mp3" volume:0.3];
    });
}
...

// whoosh with delay
[SKAudio playSound:whooshHit afterDelay:1.0];
...
// whoosh and shrink SKAction
SKAction *whooshAndShrink = [SKAction group:@[
             [SKAction runBlock:^{ [SKAudio playStarSound:whooshHit afterDelay:1.0]; }],
             [SKAction scaleTo:0 duration:1.0]]];
...
[SKAudio playSound:bgMusic];
... 
[SKAudio pauseSound:bgMusic];

这是 @patrick 对 Swift 3 的解决方案的移植。

import AVFoundation
// MARK -
// MARK setup sound
// get a repeating sound
func setupRepeatingSound(file: String, volume: Float) -> AVAudioPlayer? {
    let sound: AVAudioPlayer? = setupSound(file: file, volume: volume)
    sound?.numberOfLoops = -1
    return sound
}
// setup a sound
func setupSound(file: String, volume: Float) -> AVAudioPlayer? {
    var sound: AVAudioPlayer?
    if let path = Bundle.main.path(forResource: file, ofType:nil) {
        let url = NSURL(fileURLWithPath: path)
        do {
            sound = try AVAudioPlayer(contentsOf: url as URL)
        } catch {
            // couldn't load file :(
        }
    }
    sound?.numberOfLoops = 0
    sound?.volume = volume
    sound?.prepareToPlay()
    return sound
}
// MARK sound controls
// play a sound now through GCD
func playSound(_ sound: AVAudioPlayer?) {
    if sound != nil {
        DispatchQueue.global(qos: .default).async {
            sound!.play()
        }
    }
}
// play a sound later through GCD
func playSound(_ sound: AVAudioPlayer?, afterDelay: Float) {
    if sound != nil {
        DispatchQueue.main.asyncAfter(deadline: .now() + Double(afterDelay)) {
            sound!.play()
        }
    }
}
// pause a currently running sound (mostly for background music)
func pauseSound(_ sound: AVAudioPlayer?) {
    sound?.pause()
}

最新更新