Как я могу анимировать вручную на iPhone? - PullRequest
1 голос
/ 28 января 2009

У меня на iPhone настроена очень упрощенная «игра». Все движется, вращается, вы можете взаимодействовать с ними и т. Д. В симуляторе он работает нормально, но на устройстве он набирает около 0,25 FPS, и он настолько медленный, что, по-видимому, не успевает распознать касания.

Первоначально это было просто использование UIView с массивом Item s, каждый из которых имел функции Tick и Draw. В начале приложения я запустил таймер, который срабатывает со скоростью 60 FPS, который вызывает Tick, а в конце Tick - [self setNeedsDisplay];

Это работало так ужасно медленно, что я превратил класс Item в подкласс класса CALayer, перемещая слой, а не перерисовывая элементы. Однако я перемещал CALayer вручную, кадр за кадром, и это, по-видимому, бесполезно. Это было все еще слишком медленно. Поэтому я сказал ему переместиться к конечному пункту назначения и дал ему длину, равную количеству тиков, которые потребуются, чтобы добраться туда.

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

Работает нормально, но возникает новая проблема: если я хочу что-то анимировать, мне все равно придется использовать [self setNeedsDisplay] каждый тик, который вызывает drawInContext:, и это, похоже, major slow нерешенный вопрос.

Разве нет способа нарисовать все вручную, как я делал раньше? Я просто делал вызовы CGContext *, и в симуляторе все работало нормально! Было бы хорошо работать, если бы я реализовал нечто подобное на J2ME или во встроенном C ++. Что мне не хватает? Мне действительно нужно учить OpenGL, чтобы делать какую-нибудь интересную ручную анимацию?

Ответы [ 4 ]

2 голосов
/ 28 января 2009

Не уверен насчет слоя анимации CG, но OpenGLES - это ответ iPhone на высокопроизводительную графику. В конце дня вы получите лучшую производительность таким образом. Работать с openGLES может быть непросто, но если вы начнете с рабочего кода (см. Разбивку текстур и классы представления приложения, вызывающего сбои), вы сможете абстрагироваться от того, что вам нужно, вокруг него или вокруг него.

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

1 голос
/ 29 января 2009

Если все, что вам нужно сделать, это анимировать что-то, перемещающееся из точки А в точку Б, UIView и CALayer более чем способны справиться с этим. Вы действительно, действительно, не хотите вручную изменять положение спрайтов со скоростью 60 кадров в секунду, используя Core Graphics, UIViews или Core Animation на iPhone.

Для простого перемещения с использованием CALayer вы должны сделать следующее:

[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:0.5f] forKey:kCATransactionAnimationDuration];

CGSize spriteSize = currentSprite.frame.size;
currentSprite.frame = CGRectMake(newPosition.x, newPosition.y, spriteSize.width, spriteSize.height);

[CATransaction commit];

с currentSprite, являющимся вашим CALayer, и newPosition, являющимся конечной точкой всего линейного перемещения. Это будет плавно анимировать от текущего местоположения до нового положения, используя постоянную скорость.

В Core Animation вы просто хотите указать конечное местоположение вашего слоя и позволить ему выполнять интерполяцию промежуточных кадров. Если вы прервете эту анимацию, предоставив ей другую анимацию для выполнения на том же слое, она даже будет плавно переходить от перемещения в одно местоположение к перемещению в другое. Более сложные анимации могут быть разработаны с использованием CAKeyframeAnimations. Опять же, просто задайте Core Animation начальное и конечное состояния и позвольте ему оптимизировать остальные.

С UIViews, которые являются легкими обертками вокруг CALayers, я получаю по крайней мере 30 FPS на устройстве с десятками прозрачных слоев, перемещающихся одновременно.

0 голосов
/ 30 января 2009

Я узнал, что настоящей проблемой была необходимость позвонить [self setNeedsDisplay]. Перерисовка на покадровой основе - плохой моджо. Поэтому я использую изображения по большей части, и я все еще могу обойтись без установки позиции за кадром, установив действия на CALayer равными нулю. В частности:

NSMutableDictionary *customActions=[NSMutableDictionary dictionaryWithDictionary:[self actions]];
[customActions setObject:[NSNull null] forKey:@"position"];
[customActions setObject:[NSNull null] forKey:@"transform"];
[customActions setObject:[NSNull null] forKey:@"opacity"];
self.actions=customActions;

После этого вызова все происходит намного быстрее при покадровом вычислении.

0 голосов
/ 28 января 2009

Похоже, это будет немного переписать, к сожалению, но вы смотрели на движок Cocos2d? Если все, что вы хотите сделать, это анимировать серию спрайтов по всему экрану, тогда они накрывают вас симпатичными оболочками Objective-C для всех вызовов OpenGL.

http://code.google.com/p/cocos2d-iphone/

...