SpriteKit - правильный способ многозадачности
Я попытался найти везде в коде: объяснил документальный фильм, что он делает при переходе на задний план, или если он когда-нибудь был приостановлен, но никоим образом не может кто-то направить меня на путь того, что рекомендуется делать, когда вы собираетесь к фону в игре с поддержкой спрайтов?
Должен ли я просто вызвать scene.paused = YES
, или как я могу подтвердить, что в фоновом режиме не происходит рисования, поэтому я могу избежать завершения iOS, который не позволит мне это?
Спасибо!
Ответы
Ответ 1
Как сказано здесь на LearnCocos2D
:
Проблема заключается в том, что AVAudioSession не может быть активным, пока приложение переходит в фоновый режим.
Исправление довольно простое, а также применительно к ObjectAL = > отключить AVAudioSession, когда приложение находится в фоновом режиме, и повторно активировать сеанс аудио, когда приложение переходит на передний план.
Упрощенный AppDelegate с этим исправлением выглядит так:
#import <AVFoundation/AVFoundation.h>
...
- (void)applicationWillResignActive:(UIApplication *)application
{
// prevent audio crash
[[AVAudioSession sharedInstance] setActive:NO error:nil];
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// prevent audio crash
[[AVAudioSession sharedInstance] setActive:NO error:nil];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// resume audio
[[AVAudioSession sharedInstance] setActive:YES error:nil];
}
PS: это исправление будет включено в Kobold Kit v7.0.3.
Ответ 2
SpriteKit действительно еще не документирован, но, вероятно, потому, что он настолько новый, что относительно немногие разработчики его реализовали. SpriteKit должен приостанавливать анимацию в фоновом режиме, но по моему опыту (и harrym17's) это приведет к ошибкам доступа к памяти и полностью прекратит приложение, а не поможет в его создании.
Согласно форумам разработчиков Apple, кажется, что это известная ошибка в SpriteKit (она не всегда приостанавливает анимацию при фоновой настройке, так как она должна) вызывать ошибки доступа к памяти в соответствии с комментарий harrym17. Здесь короткое исправление, которое сработало для меня - мое приложение постоянно сбой при фоновой настройке, и с момента добавления этого кода все работает нормально.
(Kudos to Keith Murray для этого кода на форумах Apple, насколько я вижу, он не разместил его на SO).
В AppDelegate.h
убедитесь, что вы импортируете SpriteKit:
#import <SpriteKit/SpriteKit.h>
В AppDelegate.m
отредактируйте свой метод applicationWillResignActive
:
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
// pause sprite kit
SKView *view = (SKView *)self.window.rootViewController.view;
view.paused = YES;
}
И это вашему методу applicationDidBecomeActive
:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
// resume sprite kit
SKView *view = (SKView *)self.window.rootViewController.view;
view.paused = NO;
}
Есть дополнительные проблемы при воспроизведении звука при использовании AVAudioSession
, по-видимому; обходной путь упоминается в этом потоке.
Ответ 3
Мне было интересно, почему в мире это, казалось бы, простое решение привело к сбою при запуске приложения, но это было из-за того, что у меня был запуск iAd.
Итак, нужно иметь в виду: @MassivePenguin отвечает, но , если у вас есть iAd going, вам придется захватить SKView
с помощью subviews
или он (очевидно) сработает.
-(SKView*)getSKViewSubview{
for (UIView* s in self.window.rootViewController.view.subviews) {
if ([s isKindOfClass:[SKView class]]) {
return (SKView*)s;
}
}
return nil;
}
- (void)applicationWillResignActive:(UIApplication *)application {
SKView* view = [self getSKViewSubview];
if (view) {
view.paused = YES;
}
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
SKView* view = [self getSKViewSubview];
if (view) {
view.paused = NO;
}
}
Ответ 4
Для меня не сработало ни одно из решений. Я нашел другой способ, как это сделать.
// In the AppDelegate
- (void)applicationWillResignActive:(UIApplication *)application
{
if ([self.window.rootViewController isKindOfClass:[GameViewController class]]) {
GameViewController *vc = (GameViewController*)self.window.rootViewController;
[vc pauseGame];
[vc.view addObserver:vc
forKeyPath:@"paused"
options:NSKeyValueObservingOptionNew
context:nil];
}
}
// In the GameViewController
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
SKView *skView = (SKView*)self.view;
MainGame *mainGame = (MainGame*)skView.scene;
if ([keyPath isEqualToString:@"paused"] &&
[[change objectForKey:NSKeyValueChangeNewKey] boolValue] == NO &&
[mainGame isGameInProgress]) {
[self.view removeObserver:self forKeyPath:@"paused" context:nil];
skView.paused = YES;
}
}
Ответ 5
iPad, похоже, хорошо работает, но iPhone определенно сбой при создании спрайта. Вы должны сделать это вручную, автоматическая часть не так автоматична.
Ответ 6
Sprite Kit автоматически приостанавливает свои таймеры анимации при переходе на задний план - вам не нужно беспокоиться о том, что ваше приложение будет убито за это.