按帧显示动画?

时间:2012-02-20 19:04:38

标签: objective-c macos cocoa animation

我有一个由100张图片组成的动画。我希望能够通过一系列帧显示动画。例如,我宁愿使用第0帧到第32帧,而不是在0:00秒到0:32秒之间显示动画。我需要这样做,因为我需要对动画进行大量控制(即使是差异框架会产生错误的结果)。我亲自绘制了每一帧,所以我知道每帧的图像。

无论如何,我可以使用Objective-C在Cocoa中执行此操作吗?我该怎么做?我只有100张图片,我不知道如何从这里开始。而且,与按时间指定相比,这是否会“滞后”?

我更喜欢详细的答案,因为我在网上找不到任何资源,而且对此我是全新的。

请注意,我使用的是OS X,而不是iOS,因此请不要提供与iOS相关的答案。我在Snow Leopard上使用Xcode 3.2.6。

7 个答案:

答案 0 :(得分:7)

获得最多控制权的方法是将所有图像存储在一个数组中。如果你命名你的图像类似“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填充它。 %i在字符串中替换为当前值i

现在,您需要另一个变量来跟踪当前帧。像unsigned int currentFrame;这样的东西。这可以在每个更新循环中递增,也可以设置为特定值,使您可以完全控制显示的帧。

然后,在渲染循环中,您可以渲染当前存储的帧,如下所示:

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

其中animPos是一个NSPoint,包含您希望绘制的位置。的- 1是那里的索引,以便可以参考您的帧从1开始,而不是0。此拉动码在帧的图像currentFrame,并将其呈现在屏幕上。

由于使用的阵列,也一定要检查currentFrame是从未等于比帧的最大数量的值,是这样的:if (currentFrame > 100) currentFrame = 1;。这将导致动画循环,因为当它到达最后一帧,设置currentFrame将被重新设置为阵列的开始索引。

有关绘图的更多信息,请查看:Cocoa Drawing GuideNSImage Class Reference。 此外,如果您需要有关如何每增加一次时间更新帧的更多信息,请查看NSTimer Class Reference

答案 1 :(得分:2)

您可以将此代码用于逐帧动画。希望这会对你有所帮助。

 // 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];

答案 2 :(得分:1)

您可以考虑使用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类具有控制帧持续时间等的属性......

答案 3 :(得分:1)

重申@ 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];

答案 4 :(得分:0)

答案 5 :(得分:0)

您是否尝试过对NSAnimation进行子类化,并让它更改每个滴答时显示的图像?

编辑:

首先,创建NSAnimation的子类。然后,通过调用其超类实现来覆盖setCurrentProgress:,并根据currentValue更改视图。有关更深入的说明,请参阅以下指南:https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/AnimationGuide/Articles/TimingAnimations.html#//apple_ref/doc/uid/TP40003581-SW1

答案 6 :(得分:0)

我制作了一个你可以使用的简单项目:you can find the project here

我希望这是你需要的