Как приостановить сцену SpriteKit, когда приложение становится активным?

Есть ли способ предотвратить автоматическую отмену паузы сцены SpriteKit при выходе на передний план/становлении активным?

Я установил paused = true и хочу, чтобы он оставался таким, даже когда приложение снова становится активным после того, как оно было отправлено в фоновый режим.

Я должен добавить, что я делаю это быстро, хотя я не ожидал, что поведение будет другим в этом отношении.


person Pinxaton    schedule 17.08.2014    source источник
comment
Я не знаком с фреймворками, но не мог бы я paused = false включить паузу сцены?   -  person BergQuester    schedule 17.08.2014
comment
Я имел в виду пауза = истина - исправлено   -  person Pinxaton    schedule 17.08.2014
comment
Если вы приостановите свой SKView с помощью self.scene.view.paused = YES до входа в фоновый режим, он останется приостановленным, когда ваше приложение станет активным. Вы уверены, что правильно делаете паузу?   -  person 0x141E    schedule 17.08.2014
comment
Я вполне уверен, что делаю это правильно. В функции applicationWillResignActive() AppDelegate я просто делаю 'scene.view.paused = true' (быстро). Если я ничего не делаю после того, как приложение становится активным, я вижу, что все SKActions, которые были приостановлены, возобновляются, а функция update() все еще вызывается и выполняет свою работу. Я ожидал, что в отсутствие моей явной установки для scene.view.paused значения «false» возврат приложения на передний план будет держать сцену в состоянии паузы, но это явно не то, что происходит.   -  person Pinxaton    schedule 18.08.2014


Ответы (5)


Не уверен, что это то же самое в задаче C, но в Swift мне пришлось «переопределить» функцию обратного вызова, которую SKView вызывает за кулисами,

func CBApplicationDidBecomeActive()
{

}

Эта функция вызывала сброс паузы.

(обратите внимание, что ключевое слово переопределения не должно применяться)

В некоторых случаях, когда вы хотите просто сохранить состояние паузы, вместо этого создайте новую переменную и переопределите метод isPaused.

class GameScene:SKScene
{
  var realPaused = false
  {
     didSet
     {
         isPaused = realPaused
     }
  }
  override var isPaused : Bool
  {
    get
    {
       return realPaused
    }
    set
    {
      //we do not want to use newValue because it is being set without our knowledge
      paused = realPaused
    }
  }
}
person Knight0fDragon    schedule 30.03.2015
comment
Как именно вы пришли к этой секретной функции? И как вы это реализовали? - person mogelbuster; 28.10.2016
comment
Я нашел это, просмотрев трассировку стека, просто вставьте функцию в свой класс GameScene точно так, как она есть у меня. Это переопределит функцию, вызываемую из SKScene. Причина, по которой вы не используете переопределение, заключается в том, что у нас нет доступа к этой функции через файлы заголовков, поэтому мы не знаем, что она существует. - person Knight0fDragon; 28.10.2016
comment
Он не вызывался в GameScene, но вызывался в расширении SKView и в подклассе SKView. Это работает так же, как вы сказали, но это кажется опасным. Я имею в виду, что еще делает эта функция, кроме установки isPaused? Я хотел бы вызвать реализацию super, а затем сбросить isPaused, но я не мог понять, как использовать super, поскольку технически мы не переопределили его. - person mogelbuster; 28.10.2016
comment
понятия не имею, что еще он может делать, но технически он ничего не должен делать. Да, вы правы SKView lol Я даже сказал это в своем ответе, не знаю, почему мой мозг сказал GameScene. Другой вариант, который вы можете сделать, это переопределить переменную isPaused в GameScene и сохранить другую переменную с именем isRealPaused, которая отслеживает ее, когда вы хотите ее отслеживать. - person Knight0fDragon; 28.10.2016
comment
извините, @mogelbuster забыл отметить вас, не уверен, что вы получите уведомление о том, что вы последний отправитель - person Knight0fDragon; 28.10.2016

Я внес некоторые изменения в решение от Knight0fDragon, чтобы оно работало на меня. Это делает так, что isPaused всегда будет равен realPaused. Чтобы приостановить игру, необходимо изменить только переменную «realPaused», которая автоматически изменяет также переменную isPaused.

var realPaused: Bool = false {
    didSet {
        self.isPaused = realPaused
    }
}
override var isPaused: Bool {
    didSet {
        if (self.isPaused != self.realPaused) {
            self.isPaused = self.realPaused
        }
    }
}

К сожалению, это предотвратит паузу сцены, когда приложение работает в фоновом режиме. Чтобы предотвратить это, я изменил условие на: «self.isPaused != self.realPaused && self.isPaused == false», чтобы сцена по-прежнему автоматически приостанавливалась, когда приложение переводилось в фоновый режим, но только повторно. активировать, если realPaused также истинно:

var realPaused: Bool = false {
    didSet {
        self.isPaused = realPaused
    }
}
override var isPaused: Bool {
    didSet {
        if (self.isPaused == false && self.realPaused == true) {
            self.isPaused = true
        }
    }
}
person Remus Rain    schedule 17.08.2018
comment
Я применил это к своим подклассам для SKNodes, потому что они содержали некоторые SKActions, которые я не хотел запускать с помощью isPaused==true, и сцена оставалась без паузы. - person Nick Greg; 20.03.2021

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

В AppDelegate я делаю следующее:

- (void)applicationDidBecomeActive:(UIApplication *)application 
{
    SKView *view = (SKView *)self.window.rootViewController.view;

    if ([view.scene isKindOfClass:[GameScene class]]) 
    {
        XGGameScene *scene = (GameScene *)view.scene;
        [scene resumeGame];
    }
}

А затем в самом классе GameScene я обновляю BOOL, чтобы отразить, что приложение только что возобновило работу в фоновом режиме:

- (void)resumeGame
{
    //  Do whatever is necessary

    self.justResumedFromBackground = YES;
}

И, наконец, в цикле update: я запускаю следующее:

- (void)update:(NSTimeInterval)currentTime
{
    // Other codes go here...

    // Check if just resumed from background.
    if (self.justResumedFromBackground) 
    {
        self.world.paused = YES;
        self.justResumedFromBackground = NO;
    }

    // Other codes go here...
}

Надеюсь это поможет!

person Kum Chun Wai    schedule 28.01.2015

Pinxaton вы правы, но вы можете приостановить приложение, добавив небольшую задержку

 (void)theAppIsActive:(NSNotification *)note 
{
    self.view.paused = YES;
       SKAction *pauseTimer= [SKAction sequence:@[
                                                [SKAction waitForDuration:0.1],
                                                [SKAction performSelector:@selector(pauseTimerfun)
                                                                 onTarget:self]

                                                ]];
    [self runAction:pauseTimer withKey:@"pauseTimer"];
}

-(void) pauseTimerfun
{
     self.view.paused = YES;


}
person dragoneye    schedule 18.08.2014

Вы должны использовать свой делегат приложения, в частности, метод applicationDidBecomeActive. В этом методе отправьте уведомление, которое прослушивает ваше представление SpriteKit.

Таким образом, в методе applicationDidBecomeActive ваш код должен выглядеть примерно так:

// Post a notification when the app becomes active
[[NSNotificationCenter defaultCenter] postNotificationName:@"appIsActive" object:nil];    

Теперь в вашем методе didMoveToView в вашем файле SKScene поместите следующее:

// Add a listener that will respond to the notification sent from the above method
 [[NSNotificationCenter defaultCenter] addObserver:self 
                                          selector:@selector(theAppIsActive:) 
                                              name:@"appIsActive" object:nil];

Затем просто добавьте этот метод в свой файл SKScene:

//The method called when the notification arrives
(void)theAppIsActive:(NSNotification *)note 
{
    self.view.paused = YES;
}
person Scooter    schedule 17.08.2014
comment
Спасибо за предложение. Я попробовал это, но, похоже, это не дало желаемого эффекта. Когда приложение становится активным, сцена приостанавливается на долю секунды, а затем снова возобновляется. Я думаю, что SpriteKit должен возобновить работу после получения и обработки уведомления, возможно, в другом потоке? - person Pinxaton; 17.08.2014
comment
Попробуйте изменить self.view.paused на self.scene.view.paused. Вы также можете просто установить для bool значение true в приведенном выше методе. Затем в вашем методе обновления, который срабатывает один раз за кадр, просто проверьте это логическое значение, чтобы увидеть, следует ли вам приостанавливаться или нет. - person Scooter; 17.08.2014
comment
Кстати, UIApplicationDidBecomeActiveNotification уже есть, так что не нужно публиковать свои собственные. - person bio; 20.01.2016