我有一个由100张图片组成的动画。我希望能够通过一系列帧显示动画。例如,我宁愿使用第0帧到第32帧,而不是在0:00秒到0:32秒之间显示动画。我需要这样做,因为我需要对动画进行大量控制(即使是差异框架会产生错误的结果)。我亲自绘制了每一帧,所以我知道每帧的图像。
无论如何,我可以使用Objective-C在Cocoa中执行此操作吗?我该怎么做?我只有100张图片,我不知道如何从这里开始。而且,与按时间指定相比,这是否会“滞后”?
我更喜欢详细的答案,因为我在网上找不到任何资源,而且对此我是全新的。
请注意,我使用的是OS X,而不是iOS,因此请不要提供与iOS相关的答案。我在Snow Leopard上使用Xcode 3.2.6。
答案 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 Guide和NSImage 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
我希望这是你需要的