Cocos2d-x 中的帧动画

Cocos2d-x 中的帧动画

在 Cocos2d-x 中可以通过 CCAnimcation 来实现一个帧动画。在这种动画中,根据时间的流逝显示不同的纹理,形成动画。这就是我们平常所说的 逐帧动画

本文将讨论这种动画的使用方法,以及如何利用现有的工具来简化使用和提高开发效率。

本文基于 Cocos2d-x 2.2.1

1. 直接使用代码实现动画

当纹理作为单独的图像文件出现的时候,动画是这样实现的:

 1//建立一个帧动画,填充14个纹理
 2CCAnimation* animation = CCAnimation::create();
 3for( int i=1;i<15;i++)
 4{
 5	char szName[100] = {0};
 6	sprintf(szName, "Images/grossini_dance_%02d.png", i);
 7	animation->addSpriteFrameWithFileName(szName);
 8}
 9//在2.8秒中显示14帧,计算延迟
10animation->setDelayPerUnit(2.8f / 14.0f);
11animation->setRestoreOriginalFrame(true);
12
13CCAnimate* action = CCAnimate::create(animation);
14
15// grossini 是一个CCSprite,使用它播放一个自动回绕的动画
16grossini->runAction(CCSequence::create(action, action->reverse(), NULL));

如果纹理处于plist文件中,则可以这样实现:

 1//将纹理提前加入精灵帧缓存
 2CCSpriteFrameCache *frameCache = CCSpriteFrameCache::sharedSpriteFrameCache();
 3frameCache->addSpriteFramesWithFile("animations/grossini.plist");
 4
 5//建立15个元素的精灵帧数组
 6CCArray* animFrames = CCArray::createWithCapacity(15);
 7char str[100] = {0};
 8for(int i = 1; i < 15; i++)
 9{
10	sprintf(str, "grossini_dance_%02d.png",i);
11	CCSpriteFrame *frame = frameCache->spriteFrameByName(str);
12	animFrames->addObject(frame);
13}
14
15CCAnimation *animation = CCAnimation::createWithSpriteFrames(animFrames, 0.2f);
16CCAnimate *anim = CCAnimate::create(animation);
17
18//创建一个精灵用于显示动画
19CCSprite *grossini = CCSprite::create();
20CCSpriteFrame *frame = frameCache->spriteFrameByName("grossini_dance_01.png");
21grossini->setDisplayFrame(frame);
22
23//播放一个永久循环的动画
24grossini->runAction(CCRepeatForever::create(anim))

2. 使用帧动画定义文件播放动画

使用代码实现动画的缺点是必须将动画的纹理名称硬编码到源码中,这样在修改纹理的时候必须重编编译程序。

如果使用帧动画定义文件,就可以避免这个问题,并得到更多的便利。

这种文件有2种格式:

  • format 1,定义了一个动画包含哪些帧以及帧纹理的名称,但是却并不能指定这些纹理从哪里加载。因此,我们必须提前加载将这些帧纹理使用的文件加载到缓存中。它可以为一个动画指定平均的帧延迟。
  • format 2,可以直接指定需要的纹理文件的名称,也可以定义每帧的延迟。

CCAnimationCache::addAnimationsWithDictionary 负责解析这两种格式,并将它们转换成 CCAnimation ,同时保存在缓存中。

2.1 format 1 动画格式的播放

这是 format 1 格式的内容,文件名为 armatures.plist 。它定义了 dance_1/dance_2/dance_3 这3个动画,每个动画的帧延迟为0.2秒。

这个格式一看就懂,不需要详细介绍。

 1<?xml version="1.0" encoding="UTF-8"?>
 2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3<plist version="1.0">
 4<dict>
 5	<key>animations</key>
 6	<dict>
 7		<key>dance_1</key>
 8		<dict>
 9			<key>delay</key>
10			<real>0.2</real>
11			<key>frames</key>
12			<array>
13				<string>grossini_dance_01.png</string>
14				<string>grossini_dance_02.png</string>
15				<string>grossini_dance_03.png</string>
16				<string>grossini_dance_04.png</string>
17				<string>grossini_dance_05.png</string>
18				<string>grossini_dance_06.png</string>
19				<string>grossini_dance_07.png</string>
20				<string>grossini_dance_08.png</string>
21				<string>grossini_dance_09.png</string>
22				<string>grossini_dance_10.png</string>
23				<string>grossini_dance_11.png</string>
24				<string>grossini_dance_12.png</string>
25				<string>grossini_dance_13.png</string>
26				<string>grossini_dance_14.png</string>
27			</array>
28		</dict>
29		<key>dance_2</key>
30		<dict>
31			<key>delay</key>
32			<real>0.2</real>
33			<key>frames</key>
34			<array>
35				<string>grossini_dance_gray_01.png</string>
36				<string>grossini_dance_gray_02.png</string>
37				<string>grossini_dance_gray_03.png</string>
38				<string>grossini_dance_gray_04.png</string>
39				<string>grossini_dance_gray_05.png</string>
40				<string>grossini_dance_gray_06.png</string>
41				<string>grossini_dance_gray_07.png</string>
42				<string>grossini_dance_gray_08.png</string>
43				<string>grossini_dance_gray_09.png</string>
44				<string>grossini_dance_gray_10.png</string>
45				<string>grossini_dance_gray_11.png</string>
46				<string>grossini_dance_gray_12.png</string>
47				<string>grossini_dance_gray_13.png</string>
48				<string>grossini_dance_gray_14.png</string>
49			</array>
50		</dict>
51		<key>dance_3</key>
52		<dict>
53			<key>delay</key>
54			<real>0.2</real>
55			<key>frames</key>
56			<array>
57				<string>grossini_blue_01.png</string>
58				<string>grossini_blue_02.png</string>
59				<string>grossini_blue_03.png</string>
60				<string>grossini_blue_04.png</string>
61			</array>
62		</dict>
63	</dict>
64</dict>
65</plist>

使用下面的代码将这3个动画串起来并连续播放:

 1CAnimationCache *animCache = CCAnimationCache::sharedAnimationCache();
 2
 3//把动画定义文件载入缓存中
 4animCache->addAnimationsWithFile("animations/animations.plist");
 5
 6//根据动画定义文件中的名称获取3个动画
 7CCAnimation *normal = animCache->animationByName("dance_1");
 8normal->setRestoreOriginalFrame(true);
 9CCAnimation *dance_grey = animCache->animationByName("dance_2");
10dance_grey->setRestoreOriginalFrame(true);
11CCAnimation *dance_blue = animCache->animationByName("dance_3");
12dance_blue->setRestoreOriginalFrame(true);
13
14//创建Action进行播放
15CCAnimate *animN = CCAnimate::create(normal);
16CCAnimate *animG = CCAnimate::create(dance_grey);
17CCAnimate *animB = CCAnimate::create(dance_blue);
18CCSequence *seq = CCSequence::create(animN, animG, animB, NULL);
19
20//创建一个不带纹理的精灵
21CCSprite *grossini = CCSprite::create();
22//获取一个精灵帧,设置成精灵的第1帧
23CCSpriteFrame *frame = frameCache->spriteFrameByName("grossini_dance_01.png");
24grossini->setDisplayFrame(frame);
25addChild(grossini);
26
27//播放动画
28grossini->runAction(seq);

2.2 format 2 动画格式plist文件内容

这是 format 2 格式的内容,文件名为 armatures-2.plist 。它定义了 dance_1 这个动画。其中:

  • delayPerUnit 定义的就是每帧之间的间隔,是 0.2 秒。
  • delayUnits 定义了每帧的延迟值,它会覆盖 delayPerUnit 的定义。实际上,动画持续的时间,就是 所有帧的 delayUnits 的和乘以 delayPerUnit
  • notification 中定义的值会保存在 CCAnimationFrame 中。这些值的本意是在动画播放到设置值的帧时,触发一些事件。但是在 Cocos2d-x 2.2.1 中,这个事件触发并没有实现。
  • properties 定义了动画格式的版本以及这个动画中使用的帧来自于哪些纹理。
  1<?xml version="1.0" encoding="UTF-8"?>
  2<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3<plist version="1.0">
  4<dict>
  5	<key>animations</key>
  6	<dict>
  7		<key>dance_1</key>
  8		<dict>
  9			<key>delayPerUnit</key>
 10			<real>0.2</real>
 11			<key>restoreOriginalFrame</key>
 12			<true/>
 13			<key>loops</key>
 14			<integer>2</integer>
 15			<key>frames</key>
 16			<array>
 17				<dict>
 18					<key>spriteframe</key>
 19					<string>grossini_dance_01.png</string>
 20					<key>delayUnits</key>
 21					<integer>1</integer>
 22					<key>notification</key>
 23					<dict>
 24						<key>firstframe</key>
 25						<true/>
 26					</dict>
 27				</dict>
 28				<dict>
 29					<key>spriteframe</key>
 30					<string>grossini_dance_02.png</string>
 31					<key>delayUnits</key>
 32					<integer>1</integer>
 33				</dict>
 34				<dict>
 35					<key>spriteframe</key>
 36					<string>grossini_dance_03.png</string>
 37					<key>delayUnits</key>
 38					<real>0.5</real>
 39				</dict>
 40				<dict>
 41					<key>spriteframe</key>
 42					<string>grossini_dance_04.png</string>
 43					<key>delayUnits</key>
 44					<integer>1</integer>
 45				</dict>
 46				<dict>
 47					<key>spriteframe</key>
 48					<string>grossini_dance_05.png</string>
 49					<key>delayUnits</key>
 50					<integer>1</integer>
 51				</dict>
 52				<dict>
 53					<key>spriteframe</key>
 54					<string>grossini_dance_06.png</string>
 55					<key>delayUnits</key>
 56					<integer>1</integer>
 57					<key>notification</key>
 58					<dict>
 59						<key>key1</key>
 60						<integer>1234</integer>
 61						<key>key2</key>
 62						<false/>
 63					</dict>
 64				</dict>
 65				<dict>
 66					<key>spriteframe</key>
 67					<string>grossini_dance_07.png</string>
 68					<key>delayUnits</key>
 69					<integer>1</integer>
 70				</dict>
 71				<dict>
 72					<key>spriteframe</key>
 73					<string>grossini_dance_08.png</string>
 74					<key>delayUnits</key>
 75					<integer>2</integer>
 76				</dict>
 77				<dict>
 78					<key>spriteframe</key>
 79					<string>grossini_dance_09.png</string>
 80					<key>delayUnits</key>
 81					<real>0.5</real>
 82				</dict>
 83				<dict>
 84					<key>spriteframe</key>
 85					<string>grossini_dance_10.png</string>
 86					<key>delayUnits</key>
 87					<integer>1</integer>
 88				</dict>
 89				<dict>
 90					<key>spriteframe</key>
 91					<string>grossini_dance_11.png</string>
 92					<key>delayUnits</key>
 93					<integer>1</integer>
 94				</dict>
 95				<dict>
 96					<key>spriteframe</key>
 97					<string>grossini_dance_12.png</string>
 98					<key>delayUnits</key>
 99					<integer>1</integer>
100				</dict>
101				<dict>
102					<key>spriteframe</key>
103					<string>grossini_dance_13.png</string>
104					<key>delayUnits</key>
105					<integer>1</integer>
106				</dict>
107				<dict>
108					<key>spriteframe</key>
109					<string>grossini_dance_14.png</string>
110					<key>delayUnits</key>
111					<integer>1</integer>
112					<key>notification</key>
113					<dict>
114						<key>lastframe</key>
115						<true/>
116					</dict>
117				</dict>
118			</array>
119		</dict>
120	</dict>
121	<key>properties</key>
122	<dict>
123		<key>spritesheets</key>
124		<array>
125			<string>animations/grossini.plist</string>
126			<string>animations/grossini_blue.plist</string>
127			<string>animations/grossini_family.plist</string>
128		</array>
129		<key>format</key>
130		<integer>2</integer>
131	</dict>
132</dict>
133</plist>

使用下面的代码播放这个动画:

 1//解析动画定义文件,将动画载入缓存
 2CCAnimationCache *cache = CCAnimationCache::sharedAnimationCache();
 3cache->addAnimationsWithFile("animations/animations-2.plist");
 4
 5//创建动画
 6CCAnimation *animation = cache->animationByName("dance_1");
 7CCAnimate* action = CCAnimate::create(animation);
 8
 9//播放一个回绕的动画,grossini是一个已存在的精灵
10grossini->runAction(CCSequence::create(action, action->reverse(), NULL));

(全文完)