Отображение анимации по кадрам? - PullRequest
14 голосов
/ 20 февраля 2012

У меня есть анимация, состоящая из 100 изображений. Я хочу иметь возможность отображать анимацию через последовательность кадров. Например, вместо отображения анимации от 0:00 до 0:32 секунд, я бы предпочел использовать кадры от 0 до 32. Мне нужно сделать это, потому что мне нужно МНОГО контроля над анимацией (даже разница в один кадр будет создавать неправильный результат). Я нарисовал каждый кадр лично, поэтому знаю изображение каждого кадра.

В любом случае я могу сделать это в Какао, используя Objective-C? Как бы я это сделал? Все, что у меня есть, это 100 изображений, и я понятия не имею, как действовать дальше. А также, будет ли это "запаздывать" по сравнению с указанием по времени?

Я бы предпочел подробный ответ, потому что я не мог найти какие-либо ресурсы в Интернете и совершенно новичок в этом.

Обратите внимание, что я использую OS X, а не iOS, поэтому, пожалуйста, не предоставляйте ответы, связанные с iOS. Я работаю с Xcode 3.2.6 на Snow Leopard.

Ответы [ 7 ]

7 голосов
/ 08 мая 2012

Способ получить максимальный контроль - хранить все ваши изображения в массиве.Если вы назвали свои изображения как-то как «frame.png» (то есть «frame1.png»), то вы можете быстро загрузить все ваши изображения следующим образом:

frames = [[NSMutableArray alloc] init]; // In header: NSMutableArray *frames;
for (int i = 1; i < 100; i++) // 100 can be replaced for any number of frames.
{
    NSString *filename = [NSString stringWithFormat:@"frame%i.png", i];
    [frames addObject:[NSImage imageNamed:filename]];
}

Это создает массив и заполняетэто с NSImage s, названным в честь ваших файлов.%i подставляется в строку для текущего значения i.

Теперь вам понадобится другая переменная для отслеживания текущего кадра.Что-то вроде unsigned int currentFrame;.Это можно увеличивать при каждом цикле обновления или устанавливать на определенное значение, предоставляя вам полный контроль над отображаемым фреймом.

Затем в цикле рендеринга вы можете рендерить любой сохраненный в данный момент фрейм следующим образом:

[(NSImage *)[frames objectAtIndex:currentFrame - 1] drawAtPoint:animPos fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0f];

где animPos - точка NSP, содержащая позицию, в которой вы хотите нарисовать.- 1 есть в индексе, поэтому вы можете ссылаться на ваши кадры, начиная с 1, а не с 0. Этот код вытягивает изображение в кадре currentFrame и отображает его на экране.

Поскольку вы используете массив, также убедитесь, что currentFrame никогда не равно значению, превышающему максимальное количество кадров, что-то вроде: if (currentFrame > 100) currentFrame = 1;.Это может привести к зацикливанию анимации, поскольку, когда она достигает последнего кадра, currentFrame будет возвращаться к начальному индексу массива.

Для получения дополнительной информации о рисовании вы должны посмотреть: Руководство по рисованию какао и Справочник по классу NSImage .Кроме того, если вам нужна дополнительная информация о том, как обновлять фрейм с каждым шагом времени, посмотрите NSTimer Class Reference .

2 голосов
/ 08 марта 2012

Вы можете использовать этот код для покадровой анимации. Надеюсь, это поможет вам.

 // create the view that will execute our animation
 UIImageView* imageListView = [[UIImageView alloc] initWithFrame:self.view.frame];

 // load all the frames of our animation
 imageListView.animationImages = [NSArray arrayWithObjects:    
                             [UIImage imageNamed:@"campFire01.gif"],
                             [UIImage imageNamed:@"campFire02.gif"],
                             [UIImage imageNamed:@"campFire03.gif"],
                             [UIImage imageNamed:@"campFire04.gif"],
                             [UIImage imageNamed:@"campFire05.gif"],
                             [UIImage imageNamed:@"campFire06.gif"],
                             [UIImage imageNamed:@"campFire07.gif"],
                             [UIImage imageNamed:@"campFire08.gif"],
                             [UIImage imageNamed:@"campFire09.gif"],
                             [UIImage imageNamed:@"campFire10.gif"],
                             [UIImage imageNamed:@"campFire11.gif"],
                             [UIImage imageNamed:@"campFire12.gif"],
                             [UIImage imageNamed:@"campFire13.gif"],
                             [UIImage imageNamed:@"campFire14.gif"],
                             [UIImage imageNamed:@"campFire15.gif"],
                             [UIImage imageNamed:@"campFire16.gif"],
                             [UIImage imageNamed:@"campFire17.gif"], 
                              //all your 100 images// , nil];

 // all frames will execute in 1.75 seconds
 imageListView.animationDuration = 1.75;
 // repeat the annimation forever
 imageListView.animationRepeatCount = 0;
 // start animating
 [imageListView startAnimating];
 // add the animation view to the main window 
 [self.view addSubview:imageListView];
1 голос
/ 11 мая 2012

Чтобы повторить ответ @ wquist: -

frames = [[NSMutableArray alloc] init]; // In header: NSMutableArray *frames;
for (int i = 1; i < 100; i++) // 100 can be replaced for any number of frames.
{
    NSString *filename = [NSString stringWithFormat:@"frame%i.png", i];
    [frames addObject:[NSImage imageNamed:filename]];
}

В прошлом у меня было несколько анимаций с именами файлов, таких как image_00000.png, image_00001.png, и чтобы позаботиться о них, я использовал что-то вродеэто: -

NSString *filename = [NSString stringWithFormat:@"frame%05d.png", i];
1 голос
/ 10 мая 2012

Вы можете рассмотреть возможность использования CADisplayLink .Вот пример того, как его использовать:

В вашем методе инициализации настройте ссылку для отображения:

CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(playAnimation:)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];    

Затем добавьте метод:

- (void)playAnimation:(CADisplayLink*)displayLink
{
    // Set the right image to display
    self.imageToDisplay = TheRightImageBasedOnYourAnimationSequence

    [self setNeedsDisplay];
}

И, наконец,, в drawRect: метод, отобразить изображение.Класс CADisplayLink имеет атрибуты для контроля длительности кадра и т. Д. *

0 голосов
/ 02 марта 2012

Я сделал простой проект, который вы можете использовать: Вы можете найти проект здесь

Надеюсь, это то, что вам нужно

0 голосов
/ 25 февраля 2012

Вы пробовали создавать подклассы NSAnimation и заставляли ли они менять изображение, отображаемое каждый тик?

EDIT:

Сначала вы создаете подкласс NSAnimation. Затем переопределите setCurrentProgress:, вызвав его реализацию суперкласса и заставив его изменить представление в зависимости от currentValue. Более подробные инструкции см. В следующем руководстве: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/AnimationGuide/Articles/TimingAnimations.html#//apple_ref/doc/uid/TP40003581-SW1

0 голосов
/ 20 февраля 2012

Слайд-шоу этого примера кода, вероятно, может помочь вам.

https://developer.apple.com/library/mac/#samplecode/CocoaSlides/Introduction/Intro.html#//apple_ref/doc/uid/DTS10004072

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...