代码改变世界

cocos2d-x for android:士兵听我的命令移动

2012-11-11 20:49 by Terry_龙, ... 阅读, ... 评论, 收藏, 编辑

上一篇文章讲述了利用cocos2d-x构建精灵的动画效果,今天打算以此为引子,创建一个在移动时同时指挥角色到我手指触摸的移动地点,那么就开始吧。

开始

本篇要点

  1. 角色(Sprite)缓存
  2. 动画(Animation)缓存
  3. 触摸(Touch)精灵到我指定的移动地点
  4. 动作(Action)移动和切换

角色缓存

角色缓存使用CCSpriteFrameCache ,配合CCSpriteBatchNode将图片*.plist和*.png 加载进内存,方便以后调用。

 

以上为动作序列图,图片名称为:sg.png.图片来源于博客园:nowpaper.

角色缓存代码如下:

CCSpriteFrameCache* cache=CCSpriteFrameCache::sharedSpriteFrameCache();
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文件,代码如下

 

 

CCAnimationCache *animCache = CCAnimationCache::sharedAnimationCache();

    animCache->addAnimationsWithFile("sg.plist");

 在将plist文件添加完后,即可以通过动画Animation将每一个动画的Animation添加进CCAnimationCache了,这里我写了一个函数,代码见下方

 

CCAction* HelloWorld::createAction(int begin,int end,char* cacheActionName,CCPoint point){
    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>0true:false),
        ani->copy()->autorelease(),
        NULL
    ));
    return CCRepeatForever::create(plistSeq);//创建动画并返回Action
}

 

触摸精灵到我指定的移动地点

设定好让程序允许Touch之后,在回调函数ccTouchesEnded 里面通过捕获触摸位置指定精灵移动,代码见下方

 

CCTouch* touch=(CCTouch*)(touches->anyObject());  
     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的动作,代码如下:

sprite->stopAllActions();  //因为Touch是无时无刻的,所以每当touch一次即停止当前的action
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);
}

 

全部代码如下:

View Code 
  1 using namespace cocos2d;
  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>0true: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); 与
CCAnimation *attackAnimation =CCAnimation::createWithSpriteFrames(attackArray);因为站立action才一帧,所以我不打算指定时间,但是如果不指定时间,它无法成功切换action,这个目前还不清楚是为什么。

 

 

 

 

 最后实现的效果如下:

 

由于是在ubuntu下开发,好像没有什么抓取屏幕gif 图片的软件可用,简单截一屏!!!

代码没有做任何的处理,很多多余的代码,做个DEMO可以看看就行!!!

代码下载:https://github.com/terryyhl/SpriteAnimation.git