如何停止一个音频的SKAction?

13

目标:我想呈现一个新的场景:

[self.scene.view presentScene:level2 transition:reveal];

为了开始新的背景音乐(来自第二关),需要结束当前的背景音乐。

问题:呈现新场景时,第一关的背景音乐仍在播放,并且即使离开小游戏,也不会停止播放,因为整个游戏由几个小游戏组成。

所播放的音乐是SKAction类型:

@implementation WBMAnimalMiniGameLvL1

    -(id)initWithSize:(CGSize)size {    
        if (self = [super initWithSize:size])
        {
            /* Setup your scene here */
        self.temporaryScore = 0;
        self.animalSKSprites = [[WBMAnimalsMiniGameModel alloc] init];
        self.backgroundImage = [SKSpriteNode spriteNodeWithImageNamed:@"farmBackground1024x768.png"];
        self.backgroundImage.position = CGPointMake(CGRectGetMidX(self.frame),
                                       CGRectGetMidY(self.frame));
        self.temporaryStartingPointIndex = -1;
        [self addChild:self.backgroundImage];
        self.playBackgroundSound = [SKAction playSoundFileNamed:@"farm.mp3" waitForCompletion:NO];

        //SKAction *repeat = [SKAction repeatActionForever:playSound];
        [self runAction:self.playBackgroundSound withKey:@"play"];

        [self drawAllAnimalsOntoScreen];

    }
    return self;
}

下一级别的转换发生在这里:

-(void)transitionToNextLevel
{
    NSLog(@"transitionToNextLevel");
    SKTransition *reveal = [SKTransition moveInWithDirection:SKTransitionDirectionDown duration:0.5];
    //SKView *skView = (SKView *)self.view;
    SKScene *level2 = [[WBMAnimalMiniGameLvL2 alloc] initWithSize:self.size];

    level2.scaleMode = SKSceneScaleModeAspectFill;

    [self removeAllActions];
    [self removeActionForKey:@"play"];
    //self.scene.view.paused = YES;
    //self.playBackgroundSound = nil;
    [self.scene.view presentScene:level2 transition:reveal];
}
在代码行的注释中,您可以看到我已经尝试过什么以及什么没有起作用。 The :

[self removeAllActions];
    [self removeActionForKey:@"play"];

什么也没做。

self.scene.view.paused = YES;

线路只会停止过渡,但音乐仍将继续。

我尝试了以下方法: - 在冒号上使用了弱或强属性:

@property (nonatomic,weak) SKAction *playBackgroundSound;

为了在"initWithSize"中初始化SKAction后能够安全地获得指向它的指针,以便我可以访问它,而不仅仅是使用"withKey"属性。有人写道SKAction是一种"fire-and-forget"对象,这意味着如果没有存储指针,就无法直接访问它。然而,这对我没有起到帮助。

我查看了许多其他stackoverflow帖子,但没有一个能够帮助我或者至少给我一个线索为什么会出现这种情况:

SKAction playSoundFileNamed stops background music

Stop SKAction that RepeatsForever - Sprite Kit

Is it possible to end an SKAction mid-action?

Pausing a sprite kit scene

... 想法:看起来动作是在创建SKScene对象时创建的。它与其相关联,并在音频持续时间之后完成。当我使用repeatForever时,它将永远不会停止。但是没有办法暂停或停止它。 我还尝试将SKAction挂钩到SKSpriteNode上。当加载SKScene时,动物也随之加载。因此,我尝试将SKAction挂钩到SKSpriteNode上,并从SKSpriteNode中使用removeAllActions等方法,但它也没有起作用。

我查看了SKAction、SKView、SKScene和SKSpriteNode的文档,但最终并没有帮助我多少。

看起来这个对象存在于某个地方运行着它的动作。

错误的原因不在于:

  • 不是模拟器或设备相关的错误 - 我已经在模拟器和设备上进行了测试,结果相同(错误)。

  • 不是项目相关的错误 - 我在一个更小的单独项目中进行了测试,结果也是相同的(错误)。

临时解决方案: 我一直在使用AVFoundation框架中的AVAudioPlayer类。我创建了一个:

//@property (nonatomic) AVAudioPlayer *theBackgroundSong;

由于我想在加载level2时更改背景音乐,但是在嵌套的SKScene结构中很难访问该属性,因此这并没有帮助太多。

任何建议、线索、提示或想法都将非常有帮助。


2
AVAudioPlayer或者像ObjectAL这样的“适当”的音频引擎是正确的选择。我认为playSoundFileNamed:方法只是为了进行一些快速的音频测试,但我不会在任何真实的应用程序中使用它。主要是因为你无法对正在播放的音频进行任何控制,你不能改变它的音调或声道,暂停或恢复它,预加载或释放它。 - CodeSmile
我同意你的看法。看来我需要改变我的方法。我不确定iOS Sprite Kit的音频播放能力是否低,还是我缺乏使用它的知识。 - MB_iOSDeveloper
我认为他们将该操作放在那里是为了方便初学者。没有一个基本的“播放音频”功能,SK似乎就不完整了。 - CodeSmile
1
我用它来播放短暂的声音,例如动物叫声,挂在SKSpriteNodes上。这项工作做得相当不错。然而,如果持续时间超过几秒钟,就会出现问题,因为如果您更快地点击动物,则声音会同时播放。我无法将它们排队或停止它们。我相信苹果公司会慢慢解决这个问题并添加更多功能。对于初学者来说还可以。 - MB_iOSDeveloper
2个回答

14

如果在SKAction中播放音频,无法停止其播放。您需要另一个引擎来运行后台音乐。
尝试使用AVAudioPlayer-它非常易于使用和直观。类似以下的内容将起作用:

首先导入头文件并向您的场景或视图控制器添加新属性:

#import <AVFoundation/AVFoundation.h>

@interface AudioPlayerViewController : UIViewController {

@property (strong, nonatomic) AVAudioPlayer *audioPlayer;

}
هœ¨viewDidLoadوˆ–者sceneçڑ„didMoveToViewو–¹و³•ن¸­و·»هٹ ه¦‚ن¸‹ن»£ç پï¼ڑ
- (void)viewDidLoad {
    [super viewDidLoad];

    NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/audiofile.mp3", [[NSBundle mainBundle] resourcePath]]];

    NSError *error;
    self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
    self.audioPlayer.numberOfLoops = -1;

    if (!self.audioPlayer)
        NSLog([error localizedDescription]);                
    else 
        [self.audioPlayer play];

}

每次需要停止音乐时,只需调用 [self.audioPlayer stop];

当您需要播放新的音乐时,请将一个新的播放器放入使用您的新音乐片段初始化的属性中。

希望这能帮到您。


2
“当使用SKAction运行时,无法停止音频播放” - 你是对的。我之前不确定,但现在我明白了。这很有帮助 :)。 - MB_iOSDeveloper
对我来说没有用,但看起来这是正确的方法。但是,我没有听到任何声音。你知道可能是什么问题吗?错误是:操作无法完成。(OSStatus错误2003334207)。 - Vladimir Despotovic

2

现在,您可以通过为其分配键字符串,然后稍后使用removeActionForKey来停止播放声音操作。

抱歉,这是Swift。但它可以移植到Obj-C。

let action: SKAction = SKAction.playSoundFileNamed("sounds/boom.wav", waitForCompletion: true)
self.runAction(action, withKey:"die-sound")
// later you do:
self.removeActionForKey("die-sound")

我已测试成功。

在 Swift 中,太棒了 ;)。请仅编辑版本(1.2 或 2.0)。 - MB_iOSDeveloper
21
我在这里看到了类似问题的解决方案,但它对我不起作用。我可以看到该操作已成功从节点中移除,但声音仍会一直播放直到结束。 - Darren Black
即使到今天,它在Objective-C中仍然无法工作。对我来说它不起作用。 - Vladimir Despotovic
很不幸,它看起来从未工作过,而且现在也无法正常运行。 - kelin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接