上一篇文章講述了利用cocos2d-x構建精靈的動畫效果,今天打算以此為引子,創建一個在移動時同時指揮角色到我手指觸摸的移動地點,那么就開始吧。
開始
本篇要點
- 角色(Sprite)緩存
- 動畫(Animation)緩存
- 觸摸(Touch)精靈到我指定的移動地點
- 動作(Action)移動和切換
角色緩存
角色緩存使用CCSpriteFrameCache ,配合CCSpriteBatchNode將圖片*.plist和*.png 加載進內存,方便以后調用。
以上為動作序列圖,圖片名稱為:sg.png.圖片來源於博客園:nowpaper.
角色緩存代碼如下:
cache->addSpriteFramesWithFile( " sg.plist ");
sprite=CCSprite::createWithSpriteFrameName( " A1_6.png ");
sprite->setPosition(ccp(size.width-sprite->getContentSize().width,size.height/ 2));
spriteBatchNode=CCSpriteBatchNode::create( " sg.png ");
spriteBatchNode->addChild(sprite);
addChild(spriteBatchNode);
以上代碼,CCSpriteFrameCache負責加載sg.plist,CCSpriteBatchNode負責加載sg.png,然后創建一個精靈指定初始化位置和精靈紋理,並添加進CCSpriteBatchNode。通過上面的代碼即可以將一個plist序列圖加載進緩存了,你要做的就是將這些緩存的數據拿出來操作它。
動畫緩存
上面己經將數據加載進緩存了,可以使用其中的那些節點來制作動畫緩存了。
緩存動畫使用 CCAnimationCache,該動畫同樣需要使用到plist文件,代碼如下
animCache->addAnimationsWithFile( " sg.plist ");
在將plist文件添加完后,即可以通過動畫Animation將每一個動畫的Animation添加進CCAnimationCache了,這里我寫了一個函數,代碼見下方
CCAnimationCache *animCache = CCAnimationCache::sharedAnimationCache();//得到一個緩存對象
CCArray *array = CCArray::createWithCapacity(end-begin);
char name[ 20];
for( int i = begin ;i<end;i++){
sprintf(name, " A1_%d.png ",i);
CCSpriteFrame* frame =cache->spriteFrameByName(name);
array->addObject(frame);
}//以上創建一個動作序列集合
CCAnimation *plistAnimation = CCAnimation::createWithSpriteFrames(array, 0.2f);//通過動作序列集合創建animation
animCache->addAnimation(plistAnimation, cacheActionName);//添加進緩存並指定緩存名稱
array->removeAllObjects();
CCAnimation *animation = animCache->animationByName(cacheActionName);//通過緩存名稱得到一個動畫
animation->setRestoreOriginalFrame( true);
CCAnimate *ani=CCAnimate::create(animation);
CCActionInterval* plistSeq=(CCActionInterval*)(CCSequence::create(ani,
CCFlipX::create(point.x> 0? true: false),
ani->copy()->autorelease(),
NULL
));
return CCRepeatForever::create(plistSeq);//創建動畫並返回Action
}
觸摸精靈到我指定的移動地點
設定好讓程序允許Touch之后,在回調函數ccTouchesEnded 里面通過捕獲觸摸位置指定精靈移動,代碼見下方
CCPoint location = touch ->getLocation();
float offX=location.x-sprite->getPosition().x;
float offY=location.y-sprite->getPosition().y;
walkAction=createAction( 4, 6, " move ",ccp(offX,offY));
sprite->setFlipX(offX> 0? true: false);
float realX=offY/offX;
CCPoint realDeast =ccp(location.x,location.y);
CCActionInterval *actionTo=CCMoveTo::create( 2.2f,realDeast);
CCAction *moveToAction=CCSequence::create(
actionTo,
CCCallFunc::create( this,callfunc_selector(HelloWorld::moveDone)),
NULL
);
sprite->runAction(moveToAction);
ok了,精靈移動了,但你會發現,你想讓精靈移動的時候不是一整張圖片移動,而是邊移動邊兩只腳在走路的移動,就像是我們人類一樣,是走着過去的,而不是幽靈飄過去的,那么,我們要做些什么呢?
動作移動
其實,很簡單 ,只要記住要精靈移動的時候即:MoveTo時,同時再讓精靈執行一個動作即walk的動作,代碼如下:
walkAction=createAction( 4, 6, " move ",ccp(offX,offY));//構建一個walk的action
sprite->runAction(walkAction);//播放走的action
sprite->runAction(moveToAction);//播放moveTo的action
當到達指定地點時,希望讓角色以站立的姿勢站在屏幕上,這時我們需要在moveTo的callback函數里面調用,讓其停止當前action,並重新執行站立的action,代碼如下:
void HelloWorld::moveDone(){
sprite->stopAllActions();
CCAnimationCache *animCache = CCAnimationCache::sharedAnimationCache();
CCAnimation *standAnimation = animCache->animationByName( " stand ");
standAnimation->setRestoreOriginalFrame( true);
CCAnimate *standAni=CCAnimate::create(standAnimation);
CCActionInterval* s=(CCActionInterval*)(CCSequence::create(standAni,
standAni->copy()->autorelease(),
NULL
));
CCAction *frameAction=CCRepeatForever::create(s);
sprite->runAction(frameAction);
}
全部代碼如下:

2 using namespace CocosDenshion;
3
4 #define LOG_TAG "main" ||- function
5 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
6
7 CCScene* HelloWorld::scene()
8 {
9 // 'scene' is an autorelease object
10 CCScene *scene = CCScene::create();
11
12 // 'layer' is an autorelease object
13 HelloWorld *layer = HelloWorld::create();
14
15 // add layer as a child to scene
16 scene->addChild(layer);
17
18 // return the scene
19 return scene;
20 }
21
22 // on "init" you need to initialize your instance
23 bool HelloWorld::init()
24 {
25 //////////////////////////////
26 // 1. super init first
27 if ( !CCLayer::init() )
28 {
29 return false;
30 }
31
32 this->setTouchEnabled( true);
33
34 CCSize size = CCDirector::sharedDirector()->getWinSize();
35 CCAnimationCache::purgeSharedAnimationCache();
36 CCAnimationCache *animCache = CCAnimationCache::sharedAnimationCache();
37
38 animCache->addAnimationsWithFile( " sg.plist ");
39
40
41
42 cache=CCSpriteFrameCache::sharedSpriteFrameCache();
43 cache->addSpriteFramesWithFile( " sg.plist ");
44
45 sprite=CCSprite::createWithSpriteFrameName( " A1_6.png ");
46 sprite->setPosition(ccp(size.width-sprite->getContentSize().width,size.height/ 2));
47 spriteBatchNode=CCSpriteBatchNode::create( " sg.png ");
48 spriteBatchNode->addChild(sprite);
49 addChild(spriteBatchNode);
50
51 cache->addSpriteFramesWithFile( " hero.plist ");
52 hero=CCSprite::createWithSpriteFrameName( " Hero02_0.png ");
53 hero->setPosition(ccp(hero->getContentSize().width,size.height/ 2));
54 heroBatchNode=CCSpriteBatchNode::create( " hero.png ");
55 heroBatchNode ->addChild(hero);
56 hero->setFlipX( true);
57
58 addChild(heroBatchNode);
59
60
61
62 attackArray =CCArray::createWithCapacity( 4);
63 char attackName[ 20];
64 for( int i= 0;i< 4;i++){
65 sprintf(attackName,
66 " A1_%d.png ",i);
67 CCSpriteFrame* frame =cache->spriteFrameByName(attackName);
68 attackArray->addObject(frame);
69 }
70 CCAnimation *attackAnimation =CCAnimation::createWithSpriteFrames(attackArray, 0.2f);
71 CCAnimationCache::sharedAnimationCache()->addAnimation(attackAnimation, " attack ");
72
73 attackArray->removeAllObjects();
74
75
76
77 standArray= CCArray::createWithCapacity( 1);
78 char standName[ 20];
79 for( int i= 6;i< 7;i++){
80 sprintf(standName,
81 " A1_%d.png ",i);
82 CCSpriteFrame* frame =cache->spriteFrameByName(standName);
83 standArray->addObject(frame);
84 }
85 CCAnimation *standAnimation =CCAnimation::createWithSpriteFrames(standArray, 0.2f);
86 CCAnimationCache::sharedAnimationCache()->addAnimation(standAnimation, " stand ");
87 standArray->removeAllObjects();
88
89
90 return true;
91 }
92
93 void HelloWorld::moveDone(){
94 //
95 sprite->stopAllActions();
96 CCAnimationCache *animCache = CCAnimationCache::sharedAnimationCache();
97
98
99 CCAnimation *standAnimation = animCache->animationByName( " stand ");
100 standAnimation->setRestoreOriginalFrame( true);
101 CCAnimate *standAni=CCAnimate::create(standAnimation);
102 CCActionInterval* s=(CCActionInterval*)(CCSequence::create(standAni,
103 standAni->copy()->autorelease(),
104 NULL
105 ));
106 CCAction *frameAction=CCRepeatForever::create(s);
107
108
109 sprite->runAction(frameAction);
110 }
111
112 CCAction* HelloWorld::createAction( int begin, int end, char* cacheActionName,CCPoint point){
113 CCAnimationCache *animCache = CCAnimationCache::sharedAnimationCache();
114 CCArray *array = CCArray::createWithCapacity(end-begin);
115
116 char name[ 20];
117 for( int i = begin ;i<end;i++){
118 sprintf(name, " A1_%d.png ",i);
119 CCSpriteFrame* frame =cache->spriteFrameByName(name);
120 array->addObject(frame);
121 }
122
123 CCAnimation *plistAnimation = CCAnimation::createWithSpriteFrames(array, 0.2f);
124 CCAnimationCache::sharedAnimationCache()->addAnimation(plistAnimation, cacheActionName);
125
126 array->removeAllObjects();
127
128 CCAnimation *animation = animCache->animationByName(cacheActionName);
129 animation->setRestoreOriginalFrame( true);
130 CCAnimate *ani=CCAnimate::create(animation);
131 CCActionInterval* plistSeq=(CCActionInterval*)(CCSequence::create(ani,
132 CCFlipX::create(point.x> 0? true: false),
133 ani->copy()->autorelease(),
134 NULL
135 ));
136 return CCRepeatForever::create(plistSeq);
137 }
138
139
140 void HelloWorld::registerWithTouchDispatcher(){
141 CCDirector::sharedDirector()->getTouchDispatcher()->addStandardDelegate( this, 0);
142 }
143 void HelloWorld::ccTouchesEnded(cocos2d::CCSet * touches,cocos2d::CCEvent * event){
144
145 sprite->stopAllActions();
146
147
148 CCTouch* touch=(CCTouch*)(touches->anyObject());
149 CCPoint location = touch ->getLocation();
150 float offX=location.x-sprite->getPosition().x;
151 float offY=location.y-sprite->getPosition().y;
152
153 walkAction=createAction( 4, 6, " move ",ccp(offX,offY));
154
155 sprite->setFlipX(offX> 0? true: false);
156
157
158 float realX=offY/offX;
159 CCPoint realDeast =ccp(location.x,location.y);
160 CCActionInterval *actionTo=CCMoveTo::create( 2.2f,realDeast);
161 CCAction *moveToAction=CCSequence::create(
162 actionTo,
163 CCCallFunc::create( this,callfunc_selector(HelloWorld::moveDone)),
164 NULL
165 );
166
167 sprite->runAction(walkAction);
168 sprite->runAction(moveToAction);
169 }
170
171
172 void HelloWorld::menuCloseCallback(CCObject* pSender)
173 {
174 CCDirector::sharedDirector()->end();
175
176 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
177 exit( 0);
178 #endif
179
注意點
CCAnimation *attackAnimation =CCAnimation::createWithSpriteFrames(attackArray,0.2f); 與
最后實現的效果如下:
由於是在ubuntu下開發,好像沒有什么抓取屏幕gif 圖片的軟件可用,簡單截一屏!!!
代碼沒有做任何的處理,很多多余的代碼,做個DEMO可以看看就行!!!
代碼下載:https://github.com/terryyhl/SpriteAnimation.git