Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 精灵套件的AVAudioPlayer_Objective C_Sprite Kit_Avaudioplayer - Fatal编程技术网

Objective c 精灵套件的AVAudioPlayer

Objective c 精灵套件的AVAudioPlayer,objective-c,sprite-kit,avaudioplayer,Objective C,Sprite Kit,Avaudioplayer,我正在MyScene中使用AVAudioPlayer,这是我的精灵套件游戏的主要游戏场景。我还有一个包含2个按钮的OptionScene。其中1个按钮用于打开/关闭音乐 除了按下按钮不能立即打开或关闭音乐外,所有功能都正常。我必须离开应用程序,双击iPhone的Home按钮,然后向上滑动游戏视图以完全关闭它 完成后,我可以打开游戏&之前选择的开/关按钮生效。有没有办法让AVAudioPlayer在“选项”场景中单击按钮后立即关闭 我确实使用自定义类来播放我没有编写的音乐。所以我不完全理解它是如何

我正在MyScene中使用AVAudioPlayer,这是我的精灵套件游戏的主要游戏场景。我还有一个包含2个按钮的OptionScene。其中1个按钮用于打开/关闭音乐

除了按下按钮不能立即打开或关闭音乐外,所有功能都正常。我必须离开应用程序,双击iPhone的Home按钮,然后向上滑动游戏视图以完全关闭它

完成后,我可以打开游戏&之前选择的开/关按钮生效。有没有办法让AVAudioPlayer在“选项”场景中单击按钮后立即关闭

我确实使用自定义类来播放我没有编写的音乐。所以我不完全理解它是如何工作的。以下是我在MyScene中用来激活AVAudioPlayer的方法:

-(void)musicPlayer
{
    defaults = [NSUserDefaults standardUserDefaults]; //"Activate" defaults.
    music = [defaults boolForKey:@"MusicButtonKEY"]; //Then assign that defaults to a BOOL (music in this case).
    if (music == YES) //Check what defaults BOOL key value was set to & act accordingly to that.
    {
        [self.audioController tryPlayMusic]; //tryPlayMusic is a method from AudioController class.
        NSLog(@"Music playing");

    }
    else /*if (music == NO)*/
    {
       [self.audioController stopPlayingMusic]; //stopPlayingMusic is a method from AudioController class.
       NSLog(@"Music not playing");
    }
} 
以下是AudioController类的.h和.m文件: 音频控制器

#import <Foundation/Foundation.h>

@interface AudioController : NSObject

-(instancetype)init;
-(void)tryPlayMusic;
-(void)stopPlayingMusic;

@end

真希望这对细节有所帮助。

停止播放音乐是否有效?当时背景音乐播放==是吗?self.BackgroundMusicLayer当时是否为非零?设置断点并查找。请显示音乐按钮的代码,以及在哪里调用
musicPlayer
方法?我的猜测是,你设置音乐
BOOL
键的方式有问题,或者你没有在正确的位置调用
musicPlayer
方法,因此只有在重新启动应用程序后才会执行该方法,而
music
变量是从
NSUserDefaults
中获取其值的。我编辑了我的帖子,以显示音乐按钮的调用位置。MusicLayer由一个名为“tryPlayMusic”的方法调用,该方法来自MyScene内部名为AudioController的单独类(在线找到它-它解决了我的问题,每次我从MyScene进入OptionScene时都会播放一首歌曲本身的额外曲目)。至于选项屏幕,当您按下按钮时,音乐不会停止,因为该按钮仅将
BOOL
设置为
YES
NO
,但实际上没有停止或启动音乐。根据您的代码,
tryPlayMusic
是由
musicPlayer
调用的,而不是您的评论所建议的那样。在主游戏场景代码中,您称之为musicPlayer的位置?试着把它放到
视图中就会出现
。我真的应该在下班后、深夜停止编码。似乎连基本的逻辑都没有萌芽。我看了看我的代码&那是一些可怜的东西。我现在把它修好了。
#import "AudioController.h"
@import AVFoundation;

@interface AudioController () <AVAudioPlayerDelegate>

@property (strong, nonatomic) AVAudioSession *audioSession;
@property (strong, nonatomic) AVAudioPlayer *backgroundMusicPlayer;
@property (assign) BOOL backgroundMusicPlaying;
@property (assign) BOOL backgroundMusicInterrupted;

@end

@implementation AudioController

#pragma mark - Public

-(instancetype)init
{
    self = [super init];
    if (self)
    {
        [self configureAudioSession];
        [self configureAudioPlayer];
    }
    return self;
}


-(void)tryPlayMusic
{
    //If background music or other music is already playing, nothing more to do here
    if (self.backgroundMusicPlaying || [self.audioSession isOtherAudioPlaying])
    {
        return;
    }

    // Play background music if no other music is playing and we aren't playing already
    //Note: prepareToPlay preloads the music file and can help avoid latency. If you don't
    //call it, then it is called anyway implicitly as a result of [self.backgroundMusicPlayer play];
    //It can be worthwhile to call prepareToPlay as soon as possible so as to avoid needless
    //delay when playing a sound later on.
    [self.backgroundMusicPlayer prepareToPlay];
    [self.backgroundMusicPlayer play];
    self.backgroundMusicPlaying = YES;
}


-(void)stopPlayingMusic
{
    if (self.backgroundMusicPlaying == YES)
    {
        [self.backgroundMusicPlayer stop];
        self.backgroundMusicPlaying = NO;
    }
}


#pragma mark - Private

-(void)configureAudioSession
{
    //Implicit initialization of audio session.
    self.audioSession = [AVAudioSession sharedInstance];

    //Set category of audio session
    //See handy chart on pg. 46 of the Audio Session Programming Guide for what the categories mean
    //Not absolutely required in this example, but good to get into the habit of doing
    //See pg. 10 of Audio Session Programming Guide for "Why a Default Session Usually Isn't What You Want"

    NSError *setCategoryError = nil;
    if ([self.audioSession isOtherAudioPlaying])
    { //Mix sound effects with music already playing
        [self.audioSession setCategory:AVAudioSessionCategorySoloAmbient error:&setCategoryError];
        self.backgroundMusicPlaying = NO;
    }
    else
    {
        [self.audioSession setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
    }
    if (setCategoryError)
    {
        NSLog(@"Error setting category! %ld", (long)[setCategoryError code]);
    }
}


-(void)configureAudioPlayer
{
    //Create audio player with background music.
    NSString *backgroundMusicPath = [[NSBundle mainBundle] pathForResource:@"ThemeA" ofType:@"mp3"];
    NSURL *backgroundMusicURL = [NSURL fileURLWithPath:backgroundMusicPath];
    self.backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:nil];
    self.backgroundMusicPlayer.delegate = self;  //We need this so we can restart after interruptions
    self.backgroundMusicPlayer.numberOfLoops = -1;  //Negative number means loop forever
}


#pragma mark - AVAudioPlayerDelegate methods

-(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
    //It is often not necessary to implement this method since by the time
    //this method is called, the sound has already stopped. You don't need to
    //stop it yourself.
    //In this case the backgroundMusicPlaying flag could be used in any
    //other portion of the code that needs to know if your music is playing.

    self.backgroundMusicInterrupted = YES;
    self.backgroundMusicPlaying = NO;
}


-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flag
{
    //Since this method is only called if music was previously interrupted, you know that the music has stopped playing & can now be resumed.
      [self tryPlayMusic];
      self.backgroundMusicInterrupted = NO;
}

@end
#import "OptionsScene.h"
#import "ViewController.h"


BOOL soundON;
BOOL musicON;

@interface OptionsScene ()

@property (strong, nonatomic) AGSpriteButton *AGSoundButton;
@property (strong, nonatomic) AGSpriteButton *AGMusicButton;

@end


@implementation OptionsScene
{
    NSUserDefaults *defaults;

}


-(id)initWithSize:(CGSize)size
{
    self = [super initWithSize:size];
    {
        defaults = [NSUserDefaults standardUserDefaults];

        [self background]; //Won't show code for this method since it just loads the background.

        //Background music & sound dispatched once to get things going in this scene so to speak.
        static dispatch_once_t onceOS;
        dispatch_once(&onceOS, ^ {
            //Code to run once
            soundON = YES;
            musicON = YES;

            [defaults setBool:YES forKey:@"SoundButtonKEY"];
            [defaults synchronize];
            self.AGSoundButton.texture = [SKTexture textureWithImageNamed:@"checkboxYES"];
            NSLog(@"SOUND switched to ON");

            [defaults setBool:YES forKey:@"MusicButtonKEY"];
            [defaults synchronize];
            self.AGMusicButton.texture = [SKTexture textureWithImageNamed:@"checkboxYES"];
            NSLog(@"MUSIC switched to ON");
        });
    }
    return self;
}


-(void)update:(NSTimeInterval)currentTime
{

}


-(void)didMoveToView:(SKView *)view
{
    //Sound button.
    self.AGSoundButton = [AGSpriteButton buttonWithImageNamed:@"checkboxYES"];
    self.AGSoundButton.position = CGPointMake(self.size.width/2 + 50, self.size.height/2 + 70);
    self.AGSoundButton.zPosition = 2.2;
    [self.AGSoundButton addTarget:self selector:@selector(soundInit) withObject:[NSValue valueWithCGPoint:CGPointMake(self.size.width + 230, self.size.height/2 + 3)] forControlEvent:AGButtonControlEventTouchUpInside];
    [self addChild:self.AGSoundButton];

    //Music button.
    self.AGMusicButton = [AGSpriteButton buttonWithImageNamed:@"checkboxYES"];
    self.AGMusicButton.position = CGPointMake(self.size.width/2 + 50, self.size.height/2 + 10);
    self.AGMusicButton.zPosition = 2.2;
    [self.AGMusicButton addTarget:self selector:@selector(musicInit) withObject:[NSValue valueWithCGPoint:CGPointMake(self.size.width + 230, self.size.height/2 + 3)] forControlEvent:AGButtonControlEventTouchUpInside];
    [self addChild:self.AGMusicButton];


    //Call upon the saved BOOL/Button positions from their respective key's.
    BOOL soundDefaults = [defaults boolForKey:@"SoundButtonKEY"];
    BOOL musicDefaults = [defaults boolForKey:@"MusicButtonKEY"];


    //Sound button retrieval.
    if (soundDefaults == YES)
    {
        self.AGSoundButton.texture = [SKTexture textureWithImageNamed:@"checkboxYES"];
        NSLog(@"Sound is ON");
    }
    if (soundDefaults == NO)
    {
        self.AGSoundButton.texture = [SKTexture textureWithImageNamed:@"checkboxNO"];
        NSLog(@"Sound is OFF");
    }

    //Music button retrieval.
    if (musicDefaults == YES)
    {
        self.AGMusicButton.texture = [SKTexture textureWithImageNamed:@"checkboxYES"];
        NSLog(@"Music is ON");
    }
    if (musicDefaults == NO)
    {
        self.AGMusicButton.texture = [SKTexture textureWithImageNamed:@"checkboxNO"];
        NSLog(@"Music is OFF");
    }
}


//Sound button switch ON/OFF.
-(void)soundInit
{
    if (soundON == YES)
    {
        soundON = NO;
        [defaults setBool:NO forKey:@"SoundButtonKEY"];
        [defaults synchronize];
        self.AGSoundButton.texture = [SKTexture textureWithImageNamed:@"checkboxNO"];
        NSLog(@"SOUND switched to OFF");
    }
    else /*if (soundON == NO)*/
    {
        soundON = YES;
        [defaults setBool:YES forKey:@"SoundButtonKEY"];
        [defaults synchronize];
        self.AGSoundButton.texture = [SKTexture textureWithImageNamed:@"checkboxYES"];
        NSLog(@"SOUND switched to ON");
    }
}


//Music button switch ON/OFF.
-(void)musicInit
{
    if (musicON == YES)
    {
        musicON = NO;
        [defaults setBool:NO forKey:@"MusicButtonKEY"];
        [defaults synchronize];
        self.AGMusicButton.texture = [SKTexture textureWithImageNamed:@"checkboxNO"];
        NSLog(@"MUSIC switched to OFF");
    }
    else /*if (musicON == NO)*/
    {
        musicON = YES;
        [defaults setBool:YES forKey:@"MusicButtonKEY"];
        [defaults synchronize];
        self.AGMusicButton.texture = [SKTexture textureWithImageNamed:@"checkboxYES"];
        NSLog(@"MUSIC switched to ON");
    }
}


//Brings back to GameScene. Called by a 3rd button that I didn't bother including in this code. It doesn't really matter.
-(void)backToGame
{
    NSLog(@"Going back");

    [defaults synchronize]; //Save button states, just in case, before leaving scene.

    //Brings back to game scene.
    MyScene *firstScene = [MyScene sceneWithSize:self.size];
    [self.view presentScene:firstScene];
}

@end