今天学了一下cocos2d-x的帧动画,在这里记录一下,如果有什么错误的地方还请大家指出,我及时改正。在这里我创建了一个SpriterLayer的类,他是继承自CClayer的,在这里我先把头文件的定义贴出来:
1 #ifndef SPRITER_LAYER_H 2 #define SPRITER_LAYER_H 3 4 #include "cocos2d.h" 5 6 USING_NS_CC; 7 8 class SpriterLayer : public CCLayer 9 { 10 public: 11 virtual ~SpriterLayer(); 12 virtual bool init(); 13 CREATE_FUNC(SpriterLayer); 14 15 static CCScene *createScene(); 16 17 CCSize size; 18 19 void initSpriteOne(); 20 void initSpriteTwo(); 21 void initSpriteThree(); 22 void initSpriteFourth(); 23 24 void animationEnd(); 25 26 void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent); 27 void update(float delta); 28 29 CCPoint location; 30 }; 31 32 #endif
在这里我们提供了一个静态函数用来创建一个场景,然后定义了四个精灵帧动画,顺便也学习一下android的动画,之后还定义了一个动画结束之后的回调函数,接着我们重新实现了它的ccTouchesBegan函数以此来接收触摸事件,接着我们实现了update函数用来更新精灵的位置,从而实现行走动作,最后定义了一个CCPoint的对象,用来实现触目位置的记录。
接着我把其实现文件贴出来,代码如下:
1 #include "SpriterLayer.h" 2 3 SpriterLayer::~SpriterLayer() 4 { 5 6 } 7 8 bool SpriterLayer::init() 9 { 10 if(!CCLayer::init()) 11 return false; 12 13 location.x = 30; 14 location.y = 100; 15 size = CCDirector::sharedDirector()->getWinSize(); 16 17 CCLayerColor *colorLayer = CCLayerColor::create(ccc4(150, 150, 150, 230),size.width,size.height); 18 addChild(colorLayer); 19 20 CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("role.plist"); 21 22 initSpriteOne(); 23 24 initSpriteTwo(); 25 26 initSpriteThree(); 27 28 initSpriteFourth(); 29 30 31 setTouchEnabled(true); 32 33 scheduleUpdate(); 34 35 36 return true; 37 } 38 39 CCScene *SpriterLayer::createScene() 40 { 41 CCScene *scene = NULL; 42 43 scene = CCScene::create(); 44 45 SpriterLayer *layer= SpriterLayer::create(); 46 47 scene->addChild(layer); 48 49 50 return scene; 51 } 52 53 void SpriterLayer::initSpriteOne() 54 { 55 CCSprite *sprite = CCSprite::createWithSpriteFrameName("Img_ZRun1.png"); 56 addChild(sprite); 57 sprite->setPosition(ccp(100,size.height/2)); 58 59 CCArray *frameArray = CCArray::create(); 60 frameArray->retain(); 61 62 for (int i=1;i<7;i++) 63 { 64 CCSpriteFrame *frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("Img_ZRun%d.png",i)->getCString()); 65 frameArray->addObject(frame); 66 } 67 CCAnimation *animation = CCAnimation::createWithSpriteFrames(frameArray,0.1f); 68 69 CCAnimate *animate = CCAnimate::create(animation); 70 CCAction *action = CCRepeatForever::create(animate); 71 72 sprite->runAction(action); 73 } 74 75 void SpriterLayer::initSpriteTwo() 76 { 77 CCSprite *sprite = CCSprite::createWithSpriteFrameName("Img_Zhici1.png"); 78 addChild(sprite); 79 sprite->setPosition(ccp(300,size.height/2)); 80 81 CCArray *frameArray = CCArray::create(); 82 frameArray->retain(); 83 84 for (int i=1;i<9;i++) 85 { 86 CCSpriteFrame *frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("Img_Zhici%d.png",i)->getCString()); 87 frameArray->addObject(frame); 88 } 89 90 CCAnimation *animation = CCAnimation::createWithSpriteFrames(frameArray,0.1f); 91 CCAnimate *animate = CCAnimate::create(animation); 92 93 //CCAction *action = CCSequence::create(CCSpawn::create(animate,CCMoveTo::create(2.0f,ccp(700,100)),NULL),NULL); 94 95 CCAction *action = CCSequence::create(animate,CCCallFunc::create(this,callfunc_selector(SpriterLayer::animationEnd)),NULL); 96 97 sprite->runAction(action); 98 99 } 100 101 void SpriterLayer::initSpriteThree() 102 { 103 CCSprite *sprite = CCSprite::createWithSpriteFrameName("Img_Zhn1.png"); 104 addChild(sprite); 105 sprite->setPosition(ccp(500,size.height/2)); 106 107 CCArray *frameArray = CCArray::create(); 108 frameArray->retain(); 109 110 for (int i=1;i<17;i++) 111 { 112 CCSpriteFrame *frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("Img_Zhn%d.png",i)->getCString()); 113 frameArray->addObject(frame); 114 } 115 116 CCAnimation *animation = CCAnimation::createWithSpriteFrames(frameArray,0.1f); 117 CCAnimate *animate = CCAnimate::create(animation); 118 119 CCAction *action = CCRepeatForever::create(animate); 120 121 sprite->runAction(action); 122 123 } 124 125 126 void SpriterLayer::initSpriteFourth() 127 { 128 CCSprite *sprite = CCSprite::createWithSpriteFrameName("Img_Zwlak1.png"); 129 addChild(sprite,0,1); 130 131 sprite->setPosition(ccp(30,100)); 132 133 CCArray *frameArray = CCArray::create(); 134 frameArray->retain(); 135 136 for (int i=1;i<7;i++) 137 { 138 CCSpriteFrame *frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("Img_Zwlak%d.png",i)->getCString()); 139 frameArray->addObject(frame); 140 } 141 142 CCAnimation *animation = CCAnimation::createWithSpriteFrames(frameArray,0.1f); 143 animation->setRestoreOriginalFrame(true); //动画完成之后还原为第一帧 144 CCAnimate *animate = CCAnimate::create(animation); 145 146 CCAction *action = CCRepeatForever::create(animate); 147 148 sprite->runAction(action); 149 } 150 151 void SpriterLayer::animationEnd() 152 { 153 CCLog("animation finish"); 154 } 155 156 void SpriterLayer::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) 157 { 158 CCTouch *touch = (CCTouch *)( pTouches->anyObject()); 159 160 #ifdef DEBUG 161 CCPoint point = touch->getLocation(); 162 CCLog("location x=%2.2f\t y=%2.2f\n",point.x,point.y); 163 164 CCPoint viewPoint = touch->getLocationInView(); 165 CCLog("viewLocation x=%2.2f\t y=%2.2f\n",viewPoint.x,viewPoint.y); 166 #endif 167 168 location = touch->getLocationInView(); 169 170 } 171 172 void SpriterLayer::update(float delta) 173 { 174 CCSprite *sprite = (CCSprite *)this->getChildByTag(1); 175 176 if (sprite!=NULL) 177 { 178 if(sprite->getPositionX()>location.x) 179 { 180 sprite->setScaleX(-1); 181 } 182 else 183 { 184 sprite->setScaleX(1); 185 } 186 187 sprite->setPosition(ccp(location.x,100)); 188 } 189 }
接下来从init函数一步一步往下看:
实现我们调用了父对象的init方法,接着我们在添加了一个CCLayerColor层,这个主要是一个背景色,不然背景是黑色的不太好看。接着我们调用
1 CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("role.plist");
这行代码是把我们所需要的资源添加到缓冲池里,这个plist文件是用TexturPackerGUI生成的,具体的大家google一下吧。
接着我们初始化调用initSpriteOne函数初始化我们的第一个精灵,代码如下:
1 void SpriterLayer::initSpriteOne() 2 { 3 CCSprite *sprite = CCSprite::createWithSpriteFrameName("Img_ZRun1.png"); 4 addChild(sprite); 5 sprite->setPosition(ccp(100,size.height/2)); 6 7 CCArray *frameArray = CCArray::create(); 8 frameArray->retain(); 9 10 for (int i=1;i<7;i++) 11 { 12 CCSpriteFrame *frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("Img_ZRun%d.png",i)->getCString()); 13 frameArray->addObject(frame); 14 } 15 CCAnimation *animation = CCAnimation::createWithSpriteFrames(frameArray,0.1f); 16 17 CCAnimate *animate = CCAnimate::create(animation); 18 CCAction *action = CCRepeatForever::create(animate); 19 20 sprite->runAction(action); 21 }
我们首先创建出一个精灵对象,这个地方的图像资源是从我们刚刚加入的缓冲池里取出的。接着我们创建了一个CCArray的数组用来存放我们的frame对象。接着我们通过一个循环把fram对象从缓冲池取出来加入到我们刚刚创建的数组,取出我们所需的frame之后我们就可以开始创建我们的动画了:
1 CCAnimation *animation = CCAnimation::createWithSpriteFrames(frameArray,0.1f);
根据我们取出的序列帧创建一个动画,动画的间隔时间设置为0.1f,接着我们创建CCAnimate对象,创建完成之后调用下面的代码创建action
1 CCAction *action = CCRepeatForever::create(animate);
在这里我们创建了一个重复动画,看这个方法的名字我们就知道这个动画是一只在循环的,接着我们就可以为精灵执行我们的动画了
1 sprite->runAction(action);
不知道在window下怎么生成gif,效果大家自己编译出来看吧
接着我们看看第二个精灵动画,代码如下:
1 void SpriterLayer::initSpriteTwo() 2 { 3 CCSprite *sprite = CCSprite::createWithSpriteFrameName("Img_Zhici1.png"); 4 addChild(sprite); 5 sprite->setPosition(ccp(300,size.height/2)); 6 7 CCArray *frameArray = CCArray::create(); 8 frameArray->retain(); 9 10 for (int i=1;i<9;i++) 11 { 12 CCSpriteFrame *frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("Img_Zhici%d.png",i)->getCString()); 13 frameArray->addObject(frame); 14 } 15 16 CCAnimation *animation = CCAnimation::createWithSpriteFrames(frameArray,0.1f); 17 CCAnimate *animate = CCAnimate::create(animation); 18 19 CCAction *action = CCSequence::create(animate,CCCallFunc::create(this,callfunc_selector(SpriterLayer::animationEnd)),NULL); 20 21 sprite->runAction(action); 22 23 }
这个精灵的大部分代码和第一个精灵的是相同的,唯一不同的是这个帧动画只会执行一次,执行完成动画之后会调用animationEnd函数。
第三个精灵和第一个是一样的就不看了,我们看看碟四个精灵,看看我们如何实现行走:
1 void SpriterLayer::initSpriteFourth() 2 { 3 CCSprite *sprite = CCSprite::createWithSpriteFrameName("Img_Zwlak1.png"); 4 addChild(sprite,0,1); 5 6 sprite->setPosition(ccp(30,100)); 7 8 CCArray *frameArray = CCArray::create(); 9 frameArray->retain(); 10 11 for (int i=1;i<7;i++) 12 { 13 CCSpriteFrame *frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(CCString::createWithFormat("Img_Zwlak%d.png",i)->getCString()); 14 frameArray->addObject(frame); 15 } 16 17 CCAnimation *animation = CCAnimation::createWithSpriteFrames(frameArray,0.1f); 18 animation->setRestoreOriginalFrame(true); //动画完成之后还原为第一帧 19 CCAnimate *animate = CCAnimate::create(animation); 20 21 CCAction *action = CCRepeatForever::create(animate); 22 23 sprite->runAction(action); 24 }
这个动画其实和第一个是一样的,我们要重写CCLayer的ccTouchesBegan函数获取当前触摸的坐标,接着我们看看ccTouchesBegan函数的实现:
1 void SpriterLayer::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) 2 { 3 CCTouch *touch = (CCTouch *)( pTouches->anyObject()); 4 5 #ifdef DEBUG 6 CCPoint point = touch->getLocation(); 7 CCLog("location x=%2.2f\t y=%2.2f\n",point.x,point.y); 8 9 CCPoint viewPoint = touch->getLocationInView(); 10 CCLog("viewLocation x=%2.2f\t y=%2.2f\n",viewPoint.x,viewPoint.y); 11 #endif 12 13 location = touch->getLocationInView(); 14 15 }
在这里我们看到有个debug信息,我们看到有两个函数:getLocation和getLocationInView,这两个函数是用来转换我们所取坐标的,一个取得的是opengl的坐标,另外一个则是cocos2d的坐标,在这里我们要使用的是cocos2d的坐标,所以把该坐标值赋值给location。
接着我们在update函数中实现对第四个精灵对象的移动,updae函数如下:
1 void SpriterLayer::update(float delta) 2 { 3 CCSprite *sprite = (CCSprite *)this->getChildByTag(1); 4 5 if (sprite!=NULL) 6 { 7 if(sprite->getPositionX()>location.x) 8 { 9 sprite->setScaleX(-1); 10 } 11 else 12 { 13 sprite->setScaleX(1); 14 } 15 16 sprite->setPosition(ccp(location.x,100)); 17 } 18 }
这样我们就实现了对精灵位置的移动,看上去就是行走状态了。
声明:该代码所使用的图片来源于网络