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