Как я могу предотвратить перезапуск последовательности SKAction после декодирования?

Мое приложение - игра SpriteKit с сохранением и восстановлением состояния приложения. Когда состояние приложения сохраняется, большинство узлов в моем текущем SKScene закодированы.

Когда узел работает SKAction закодирован и декодирован, действие возобновится с самого начала. Это кажется стандартным SpriteKit поведение.

Для меня это поведение наиболее заметно для SKAction sequence, При декодировании последовательность перезапускается независимо от того, сколько действий компонента уже выполнено. Например, скажем, код для запуска последовательности выглядит следующим образом:

[self runAction:[SKAction sequence:@[ [SKAction fadeOutWithDuration:1.0],
                                      [SKAction fadeInWithDuration:1.0],
                                      [SKAction waitForDuration:10.0],
                                      [SKAction removeFromParent] ]]];

Если состояние приложения сохраняется в течение 10-секундного ожидания, а затем восстанавливается, SKAction последовательность начнется снова с начала, со вторым видимым постепенным исчезновением.

Это имеет смысл, что SKAction sequence должно показывать поведение декодирования в соответствии с другими действиями. Однако было бы полезно сделать исключение, чтобы любые уже выполненные действия не выполнялись снова. Как я могу предотвратить перезапуск последовательности после декодирования?

2 ответа

Решение

SKAction последовательность может быть разложена на несколько подпоследовательностей, так что после завершения определенной подпоследовательности она больше не будет работать и не будет перезапущена при декодировании.

Код

Создайте легкий, кодируемый объект, который может управлять последовательностью, разбивая ее на подпоследовательности и запоминая (при кодировании), что уже выполнено. Я написал реализацию в библиотеке на GitHub. Вот текущее состояние кода в сущности.

И вот пример (с использованием той же последовательности, что и ниже):

HLSequence *xyzSequence = [[HLSequence alloc] initWithNode:self actions:@[
                                      [SKAction waitForDuration:10.0],
                                      [SKAction performSelector:@selector(doY) onTarget:self],
                                      [SKAction waitForDuration:1.0],
                                      [SKAction performSelector:@selector(doZ) onTarget:self] ]];
[self runAction:xyzSequence.action];

Концепт

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

[self runAction:[SKAction sequence:@[ [SKAction performSelector:@selector(doX) onTarget:self],
                                      [SKAction waitForDuration:10.0],
                                      [SKAction performSelector:@selector(doY) onTarget:self],
                                      [SKAction waitForDuration:1.0],
                                      [SKAction performSelector:@selector(doZ) onTarget:self] ]]];

можно разделить так:

[self runAction:[SKAction sequence:@[ [SKAction performSelector:@selector(doX) onTarget:self] ]]];

[self runAction:[SKAction sequence:@[ [SKAction waitForDuration:10.0],
                                      [SKAction performSelector:@selector(doY) onTarget:self] ]]];

[self runAction:[SKAction sequence:@[ [SKAction waitForDuration:11.0],
                                      [SKAction performSelector:@selector(doZ) onTarget:self] ]]];

Независимо от того, когда узел закодирован, методы doX, doY, а также doZ будет запущен только один раз.

В зависимости от анимации продолжительность ожидания может показаться странной. Например, допустим, приложение сохраняется после doX а также doY запустить, в течение 1 секунды до doZ, Тогда после восстановления приложение не запустится doX или же doY еще раз, но он будет ждать 11 секунд, прежде чем запустить doZ,

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

- (void)doX
{
  // do X...
  [self runAction:[SKAction sequence:@[ [SKAction waitForDuration:10.0],
                                        [SKAction performSelector:@selector(doY) onTarget:self] ]]];
}

- (void)doY
{
  // do Y...
  [self runAction:[SKAction sequence:@[ [SKAction waitForDuration:1.0],
                                        [SKAction performSelector:@selector(doZ) onTarget:self] ]]];
}

- (void)doZ
{
  // do Z...
}

- (void)runAnimationSequence
{
  [self runAction:[SKAction performSelector:@selector(doX) onTarget:self]];
}

При такой реализации, если последовательность сохраняется после doX а также doY затем, после восстановления, задержка до doZ будет только 1 секунда. Конечно, это полная секунда (даже если она была наполовину истекла до кодирования), но результат вполне понятен: какое бы действие в последовательности не выполнялось во время кодирования, оно будет перезапущено, но после его завершения это будет сделано.

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

Единственный способ, которым я могу думать о достижении того, чего вы хотите достичь, - это следующее.

  1. При запуске действия сохраняйте время в переменной. Имейте в виду, что вы захотите использовать значение currentTime, переданное в функцию обновления.
  2. Когда вам нужно кодировать, подсчитайте, сколько времени прошло с момента создания действия до момента кодирования.

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

Я не думаю, что SKActions действительно были предназначены для такого использования, но это может быть обходной путь, по крайней мере. Я думаю, что разработчики чаще сохраняют "состояние" своей игры на постоянство, а не пытаются сохранить реальные спрайты и действия. Это было бы то же самое с материалом UIKit. Вы не будете хранить UIViews для постоянства, у вас вместо этого будет какой-то другой объект, который будет содержать информацию для воссоздания, основанную на прогрессе пользователя. Надеюсь, что-то из этого было хоть немного полезным. Удачи.

редактировать

Чтобы дать больше информации о том, как "в теории" я бы пошел об этом, и вы правы, это хлопот.

  1. Подкласс SKSpriteNode
  2. Создайте новый метод для запуска действий на этом Sprite (например, -(void)startAction:withKey:duration:), который в конечном счете вызовет действие run с ключом.
  3. Когда вызывается startAction, вы сохраняете его в некоторый вид MutableArray со словарем, в котором хранится это действие, его ключ, продолжительность и startTime (по умолчанию 0). Возможно, вам даже не придется хранить это действие, только ключ, продолжительность и время начала.
  4. Добавьте update: метод к этому подклассу SKSpriteNode. Каждый цикл обновления вы вызываете его обновлением и проверяете, есть ли у 1 какие-либо действия время начала и 2, если эти действия все еще выполняются. Если время начала отсутствует, вы добавляете текущее время в качестве времени начала, а если оно не запущено, вы удаляете его из массива.
  5. Когда вы собираетесь кодировать / сохранять этот спрайт, вы используете информацию в этом массиве для определения состояния этих SKAction.

Суть этого в том, что каждый SKSpriteNode удерживает и отслеживает свой собственный SKAction в этом примере. Извините, у меня нет времени, чтобы пройти и написать код в Objective-C. Кроме того, я ни в коем случае не утверждаю или не пытаюсь предположить, что это лучше или хуже, чем ваш ответ, а скорее обращаюсь к тому, как я справлюсь с этим, если я был полон решимости сохранить состояние SKActions в соответствии с вашим вопросом. знак равно

Другие вопросы по тегам