2013-09-25 3 views
14

Я попытался найти везде в коде: объяснил документальный фильм, что он делает при переходе на задний план, или если он когда-нибудь был приостановлен, но никоим образом не может кто-то направить меня на пути что рекомендуется делать при переходе на задний план в игре с комплектом спрайтов?SpriteKit - правильный способ многозадачности

Должен ли я просто позвонить scene.paused = YES, или как я могу подтвердить, что в фоновом режиме не происходит рисования, поэтому я могу избежать завершения iOS, что не позволит мне это?

Спасибо!

ответ

14

here Как сказал по 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.

+1

Нужна ли вторая? –

+0

Это исправление. По-видимому, SpriteKit все еще не обрабатывает звук. –

+0

Эта проблема исправлена ​​в iOS8. iOS7 и ниже, он падает. – rjm226

-4

Sprite Kit автоматически останавливает свои таймеры анимации при переходе на задний план - вам не нужно беспокоиться о том, что ваше приложение будет убито за это.

+0

Тем не менее, по-видимому IOS прекращено мое приложение, что-то из-за EXC_BAD_ACCESS, но также показывает gpus_ReturnNotAllowedKillClient? –

+0

Sprite Kit _says_, что он автоматически приостанавливает свои таймеры анимации, но с этим есть определенные проблемы. – Kardasis

+0

Я тоже получал ошибку 'EXEC_BAD_ACCESS' при создании фона - код в моем ответе _seems_, чтобы зафиксировать его, хотя мое приложение действительно не так сложно на данный момент ... – MassivePenguin

39

SpriteKit действительно не документирован так хорошо, вероятно, потому, что он настолько новый, что относительно немногие разработчики его внедрили. SpriteKit должен приостанавливать анимацию в фоновом режиме, но по моему опыту (и harrym17's) это приведет к ошибкам доступа к памяти и полностью прекратит работу приложения, а не создает его.

В соответствии с форумами разработчиков Apple, похоже, это известная ошибка в SpriteKit (она не всегда приостанавливает анимацию при фоновой настройке, так как она должна) вызывать memory access errors as per harrym17's comment. Вот краткое исправление, которое сработало для меня - мое приложение постоянно сбой при создании фона, и с момента добавления этого кода все работает нормально.

(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, по-видимому; Обходное решение упоминается in this thread.

+0

Это не мешает краху (для меня по крайней мере) –

+0

Отлично. Я могу подтвердить, что это работает! Это необходимо добавить по умолчанию в AppDelegate для любого приложения Sprite Kit, если вы спросите меня. Кроме того, если вы используете звуки в своем приложении, объедините его с исправлением AVAudioSession в этой же теме. Спасибо – stvn

+0

Я не пробовал в этом контексте, но вы можете использовать NSTimer (см. Http://stackoverflow.com/questions/1449035/how-do-i-use-nstimer). Я * использовал * NSTimer для установки другой переменной, когда приложение становится активным, поэтому оно должно работать на вас. – MassivePenguin

0

iPad, похоже, хорошо, но iPhone определенно сбой при создании спрайта. Вы должны сделать это вручную, автоматическая часть не такая автоматическая.

10

Мне было интересно, почему в мире это, казалось бы, простое решение привело к сбоям при запуске приложения, но это было из-за того, что у меня был запуск iAd. Итак, нужно иметь в виду: @ Ответ MassivePenguin работает, но , если у вас есть iAd, идущий, вам нужно будет захватить 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; 
    } 

} 
+0

Ваше решение действительно сработало для меня, спасибо! – user3033437

+0

хорошо сделано, очень легко и прямо. спасибо и плюс 1 –

1

Для меня не сработало. Я нашел другой способ, как это сделать.

// 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; 
    } 
} 
Смежные вопросы