ios7sprite-kitskactionsksceneskview

How to stop a audio SKAction?


Goal: I want to present a new scene:

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

and end the current background music in order to start the new background music (the new background music from level 2).

TheProblem: Upon presenting the new scene the background music of the 1. scene (level1) keeps playing and DOES not stop even when leaving the miniGame since the whole game consists of few mini games.

The music played is an 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;
}

Here does the transition to the next level happen:

-(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];
}

In the comments code lines you can se what I have already tried and what did not work. The :

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

did absolutely nothing. The:

self.scene.view.paused = YES;

line stops only the transition but the music still continues.

I have tried the following: - used a weak or strong property on a :

@property (nonatomic,weak) SKAction *playBackgroundSound;

to secure a pointer to the SKAction so I can access it beside using the "withKey" property since I initialized the SKAction in "initWithSize". Someone wrote that SKAction is a fire-and-forget object which I understood as without having stored a pointer to it accessing it later is not possible (directly). However, it didnt work/help me.

I looked into many other stackoverflow posts and none helped me or at least gave me a clue why this happens:

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

... Thoughts: It seems that the action is created with the creation of the SKScene object. It is "hooked" to it and finished after the audio duration. While I was using repeatForever it would never stop. However there is no way to pause or stop it. I also tried hooking the SKAction to SKSpriteNode. When the SKScene is loaded animals are loaded with it. So I tried hooking the SKAction on the SKSpriteNode and use removeAllActions and alike from the SKSpriteNode but it didnt work aswell.

I checked the documentation on SKAction,SKView,SKScene,SKSpriteNode but in the end it didnt help me much.

It looks like the object exists somewhere running its actions.

What the error is not about:

A temporary solution: I have been using the AVAudioPlayer class from AVFoundation framework. I created a :

//@property (nonatomic) AVAudioPlayer *theBackgroundSong;

This didnt help much since I wanted to change theBackgroundSong when level2 was loaded and I had huge problems accessing the property from a nested SKScene structure.

Any advice,clue,hint or idea would be of great help.


Solution

  • You can't stop audio from playing when run from SKAction. You will need another engine to run your background music.
    Try AVAudioPlayer - it is really easy and straightforward to use. Something like this will work:

    First import header and add new property to your scene or view controller:

    #import <AVFoundation/AVFoundation.h>
    
    @interface AudioPlayerViewController : UIViewController {
    
    @property (strong, nonatomic) AVAudioPlayer *audioPlayer;
    
    }
    

    After this in viewDidLoad or in didMoveToView method of scene add following code:

    - (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];
    
    }
    

    Each time you need your music to stop, just call [self.audioPlayer stop];

    When you need new music to play, put a new player into the property initialized with your new music piece.

    Hope this helps.