Как сохранить iOS-анимацию плавной с множеством подпредставлений - PullRequest
4 голосов
/ 30 декабря 2011

Я пробую разные варианты маленькой игры, которую я пишу, чтобы поиграть с анимацией на iOS.

Моя цель - создать сетку плиток, которая в зависимости от игрового процесса меняет отображение каждой плитки наодин из набора изображений.Мне бы хотелось, чтобы каждая плитка (до 24x24) переворачивалась, когда ее лицо менялось.По ходу игры все больше и больше плиток нужно переворачивать одновременно.В первой реализации, где я пытался перевернуть их одновременно, анимация стала очень резкой.

Я изменил свой подход, чтобы не переворачивать их все сразу, а только по несколько за раз, планируя анимацию для каждой плитки.с немного увеличивающейся задержкой на плитку, так что, когда, скажем, 10-ая плитка начинает анимацию, первая уже сделанаВесь процесс занимает немного больше времени, но также приводит к хорошему визуальному волновому эффекту.

Screen shot from the simulator

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

Этоэто код (в моем подклассе игровой сетки UIView), который запускает переключение соответствующих плиток.(Я удалил оптимизацию, которая пропускает плитки, потому что это имеет значение только на ранних стадиях игры).

float delay = 0.0f;
for (NSUInteger row=0; row<numRows; row++) {
    for (NSUInteger col=0; col<numCols; col++) {
        delay += 0.03f;
        [self updateFlippingImageAtRow:row col:col delay:delay animated:YES];
    }
}

Представление игровой сетки имеет NSArray подпредставлений плитки, которые адресуются с помощью row и col переменные в цикле выше.

updateFlippingImageAtRow:col:delay:animated - это метод в моем FlippingImageView (также подкласс UIView) сводится к этому (игровая логика опущена):

-(void)animateToShow:(UIImage*)image 
            duration:(NSTimeInterval)time 
               delay:(float)delay 
          completion:(void (^)(BOOL finished))completion 
{
    [UIView animateWithDuration:time
                          delay:delay
                        options:UIViewAnimationOptionTransitionFlipFromLeft 
                     animations:^{
                         [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft
                                                forView:self
                                                  cache:YES];
                         self.frontImage = image;
                     }
                     completion:completion
    ];
}

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

Instruments screen shot of a few flip operations

Любые предложения о том, как повысить производительностьэтого?Точное время анимации не очень важно.

Ответы [ 2 ]

3 голосов
/ 30 декабря 2011

Вы можете подумать об этом с помощью CoreAnimation и CALayers вместо UIViews.Это невероятно мощный и оптимизированный фреймворк.

Это непросто, вам придется перекодировать хотя бы некоторые из ваших классов (иерархия просмотра и тесты попаданий - это первое, что приходит мне в голову), ноэто стоит попробовать, и это довольно безболезненный процесс, потому что CALayer очень похож на UIView.

Следующий шаг - OpenGL.Он определенно может управлять несколькими сотнями объектов в режиме реального времени, но для этого требуется гораздо больше работы.

1 голос
/ 30 декабря 2011

Вместо этого вы можете попробовать использовать CoreAnimation.Один из способов сделать анимацию сальто:

  • Создать CABasicAnimation, который анимирует первую половину сальто (вращение вдоль оси y).
  • В методе делегата animationDidStop:finished: вы устанавливаете новое изображение, а затем создаете новую анимацию, которая оживляет вторую половину.
  • Вы просто применяете анимацию к свойству layerваш взгляд.
  • Обратите внимание, что вы можете использовать setValue:forKey:, чтобы "аннотировать" анимацию (помните, о каком объекте анимация).Когда вы добавляете анимацию к слою, она копируется, а не сохраняется, поэтому вы не можете идентифицировать ее, просто сравнивая значения указателя.
...