cocos2d-x精灵动画帧

原文地址http://blog.csdn.net/musicvs/article/details/8105611

1.    会动的精灵

第一篇教程教我们的是创建一个精灵,但是它不会动,现在终于可以创建会动的精灵了,看代码先:

  1. /* 加载图片帧*/ 
  2. CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteFrameCache(); 
  3. cache->addSpriteFramesWithFile("images.plist", "images.png"); 
  4.  
  5. /* 创建一个精灵*/ 
  6. CCSprite* girlSprite = CCSprite::createWithSpriteFrameName("girl1.png"); 
  7. CCSize size = CCDirector::sharedDirector()->getWinSize(); 
  8. girlSprite->setPosition(ccp(size.width / 2, size.height / 2)); 
  9.  
  10. /*  让精灵执行一个动画,
  11. animation是名称,animate是动词,
  12.     所以要动起来就要用CCAnimate创建一个会动的动画,我是这么记忆的,嘿嘿
  13. */ 
  14. girlSprite->runAction(CCAnimate::create(animation)); 
  15.  
  16. this->addChild(girlSprite); 
/* 加载图片帧*/
CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteFrameCache();
cache->addSpriteFramesWithFile("images.plist", "images.png");

/* 创建一个精灵*/
CCSprite* girlSprite = CCSprite::createWithSpriteFrameName("girl1.png");
CCSize size = CCDirector::sharedDirector()->getWinSize();
girlSprite->setPosition(ccp(size.width / 2, size.height / 2));

/*  让精灵执行一个动画,
animation是名称,animate是动词,
    所以要动起来就要用CCAnimate创建一个会动的动画,我是这么记忆的,嘿嘿
*/
girlSprite->runAction(CCAnimate::create(animation));

this->addChild(girlSprite);

首先加载图片(SpriteFrame),这是上一篇教程教过我们的。

然后我先省略了中间的重要步骤,直接创建了一个精灵,最后有一句话:

girlSprite->runAction(CCAnimate::create(animation));

这就是让精灵动起来的方法——runAction

要让精灵动起来,我们需要一个动画对象,这个对象其实就是由若干个图片帧组合的:

  1. /* 数组对象,和Java的集合差不多?*/ 
  2. CCArray* framesArray = CCArray::create(); 
  3.  
  4. /* 把动画所需的所有图片帧添加到数组里*/ 
  5. CCSpriteFrame* frame = cache->spriteFrameByName("girl1.png"); 
  6. framesArray->addObject(frame); 
  7.  
  8. frame = cache->spriteFrameByName("girl2.png"); 
  9. framesArray->addObject(frame); 
  10.  
  11. frame = cache->spriteFrameByName("girl3.png"); 
  12. framesArray->addObject(frame); 
  13.  
  14. frame = cache->spriteFrameByName("girl4.png"); 
  15. framesArray->addObject(frame); 
  16.  
  17. /* 使用图片帧生成动画对象,每隔500毫秒播放一帧*/ 
  18. CCAnimation* animation = CCAnimation::createWithSpriteFrames(framesArray, 0.5f); 
  19. animation->setLoops(-1);    // 设置循环播放 
  20. animation->setRestoreOriginalFrame(true);   // 设置播放完毕后恢复精灵原始帧 
/* 数组对象,和Java的集合差不多?*/
CCArray* framesArray = CCArray::create();

/* 把动画所需的所有图片帧添加到数组里*/
CCSpriteFrame* frame = cache->spriteFrameByName("girl1.png");
framesArray->addObject(frame);

frame = cache->spriteFrameByName("girl2.png");
framesArray->addObject(frame);

frame = cache->spriteFrameByName("girl3.png");
framesArray->addObject(frame);

frame = cache->spriteFrameByName("girl4.png");
framesArray->addObject(frame);

/* 使用图片帧生成动画对象,每隔500毫秒播放一帧*/
CCAnimation* animation = CCAnimation::createWithSpriteFrames(framesArray, 0.5f);
animation->setLoops(-1);    // 设置循环播放
animation->setRestoreOriginalFrame(true);   // 设置播放完毕后恢复精灵原始帧


好像没有什么能解释的,CCAnimation对象需要一组图片帧(SpriteFrame)来创建,而

这组SpriteFrame对象用一个CCArray来存放。

CCArray应该就是和JavaList类似?但是coco2d-x2.x版本里把CCArray的泛型去掉

了,有点不习惯(不知道是不是我弄错了?噗)。

对了,1.x版本和2.x版本创建CCAnimation是有点不一样的(我就不说了哈,我只研究2.x版本~)。

2.    工具类

每次要一个精灵动起来就要写这么多行代码,虽然简单,但是看着就很繁琐,所以教程里面就教我们写一个工具类。

把前面生成CCAnimation的步骤抽离出来,写成一个函数:

  1. cocos2d::CCAnimation* SpriteHelper::createAnimWithSingleFrameN( const char* name, int count, float delay ) 
  2.     CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteFrameCache(); 
  3.  
  4.     CCArray* framesArray = CCArray::createWithCapacity(count); 
  5.  
  6.     char str[80]; 
  7.     for(int i = 1; i <= count; i++) 
  8.     { 
  9.         sprintf(str, "%s%d.png", name, i); 
  10.         framesArray->addObject(cache->spriteFrameByName(str)); 
  11.     } 
  12.  
  13.     CCAnimation* animation = CCAnimation::createWithSpriteFrames(framesArray); 
  14.     animation->setLoops(-1); 
  15.     animation->setRestoreOriginalFrame(true); 
  16.     animation->setDelayPerUnit(delay); 
  17.  
  18.     return animation; 
cocos2d::CCAnimation* SpriteHelper::createAnimWithSingleFrameN( const char* name, int count, float delay )
{
    CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteFrameCache();

    CCArray* framesArray = CCArray::createWithCapacity(count);

    char str[80];
    for(int i = 1; i <= count; i++)
    {
        sprintf(str, "%s%d.png", name, i);
        framesArray->addObject(cache->spriteFrameByName(str));
    }

    CCAnimation* animation = CCAnimation::createWithSpriteFrames(framesArray);
    animation->setLoops(-1);
    animation->setRestoreOriginalFrame(true);
    animation->setDelayPerUnit(delay);

    return animation;
}

没有什么新的知识,噗,当然了,用了一个sprintf函数,用来连接字符串的。我到现在还不懂怎么用C++里面的String对象,Java里用String用习惯了,现在用char*很不习惯,嘻嘻。

3.    如果精灵图片是连在一起的

我们常常会看到这样连在一起的图片:

而刚刚写的那个工具类的函数是针对一张一张分开的图片的,于是,我们要修改一下:

  1. /************************************************************************/ 
  2. /* 根据图片列数,自动切割图片,生成CCAnimation对象                                                                    */ 
  3. /************************************************************************/ 
  4. cocos2d::CCAnimation* SpriteHelper::createAnimByLineFrameN( const char* name, int col, float delay ) 
  5.     CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteFrameCache(); 
  6.     CCSpriteFrame* frame = cache->spriteFrameByName(name); 
  7.  
  8.     CCTexture2D* texture = frame->getTexture(); 
  9.     CCSize frameSize = frame->getOriginalSizeInPixels(); 
  10.     CCRect frameRect = frame->getRect(); 
  11.  
  12.     float w = frameSize.width / col; 
  13.     float h = frameSize.height; 
  14.     float x = frameRect.origin.x; 
  15.     float y = frameRect.origin.y; 
  16.  
  17.     CCArray* framesArray = CCArray::createWithCapacity(col); 
  18.     for(int i = 0; i < col; i++) 
  19.     { 
  20.         framesArray->addObject(CCSpriteFrame::createWithTexture(texture, CCRectMake(x, y, w, h))); 
  21.         x += w; 
  22.     } 
  23.  
  24.     CCAnimation* animation = CCAnimation::createWithSpriteFrames(framesArray); 
  25.     animation->setLoops(-1); 
  26.     animation->setRestoreOriginalFrame(true); 
  27.     animation->setDelayPerUnit(delay); 
  28.  
  29.     return animation; 
/************************************************************************/
/* 根据图片列数,自动切割图片,生成CCAnimation对象                                                                    */
/************************************************************************/
cocos2d::CCAnimation* SpriteHelper::createAnimByLineFrameN( const char* name, int col, float delay )
{
    CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteFrameCache();
    CCSpriteFrame* frame = cache->spriteFrameByName(name);

    CCTexture2D* texture = frame->getTexture();
    CCSize frameSize = frame->getOriginalSizeInPixels();
    CCRect frameRect = frame->getRect();

    float w = frameSize.width / col;
    float h = frameSize.height;
    float x = frameRect.origin.x;
    float y = frameRect.origin.y;

    CCArray* framesArray = CCArray::createWithCapacity(col);
    for(int i = 0; i < col; i++)
    {
        framesArray->addObject(CCSpriteFrame::createWithTexture(texture, CCRectMake(x, y, w, h)));
        x += w;
    }

    CCAnimation* animation = CCAnimation::createWithSpriteFrames(framesArray);
    animation->setLoops(-1);
    animation->setRestoreOriginalFrame(true);
    animation->setDelayPerUnit(delay);

    return animation;
}


因为怕大家看到代码太长会厌烦,所以我把注释都去掉了,大家先扫一眼,看懂了就好,如果还有疑问的话,请看下面这段加上详细注释之后的代码:

  1. /************************************************************************/ 
  2. /* 根据图片列数,自动切割图片,生成CCAnimation对象                                                                    */ 
  3. /************************************************************************/ 
  4. cocos2d::CCAnimation* SpriteHelper::createAnimByLineFrameN( const char* name, int col, float delay ) 
  5.     CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteFrameCache(); 
  6.  
  7.     CCSpriteFrame* frame = cache->spriteFrameByName(name); 
  8.  
  9.     /*
  10.         SpriteFrame的纹理对象(CCTexture2D),
  11.         我的理解就是那张TexturePacker打包的大图
  12.         并且,同一张大图生成的SpriteFrame对象的getTexture的结果是一致的。
  13.         换句话说,SpriteFrame其实保存了一份图片纹理的引用。
  14.     */ 
  15.     CCTexture2D* texture = frame->getTexture(); 
  16.  
  17.     /*
  18.         我很好奇,getOriginalSize和getOriginalSizeInPixels倒底有什么区别?
  19.         稍微我研究一下,再和大家分享
  20.     */ 
  21.     CCSize frameSize = frame->getOriginalSizeInPixels(); 
  22.  
  23.     /*
  24.         SpriteFrame是否没有坐标的概念的,
  25.         只有矩阵范围这个概念,所以要获得它的位置,
  26.         必须通过它的矩阵范围来取得
  27.     */ 
  28.     CCRect frameRect = frame->getRect(); 
  29.  
  30.     float w = frameSize.width / col;    /* 每帧图片的宽*/ 
  31.     float h = frameSize.height; 
  32.  
  33.     float x = frameRect.origin.x; 
  34.     float y = frameRect.origin.y; 
  35.  
  36.     CCArray* framesArray = CCArray::createWithCapacity(col); 
  37.     for(int i = 0; i < col; i++) 
  38.     { 
  39.         /*
  40.             我一直都很担心,createWithTexture是不是就生成了新的纹理对象?
  41.             不过,我再仔细想想,SpriteFrame本来就只是引用了纹理对象,而不是新建一份小纹理。
  42.             我的理解是,SpriteFrame其实只是其记录数据的作用,记录了某个图片帧在整张大图片的位置,以及截取范围等。
  43.             所以,createWithTexture只不过是把SpriteFrame的范围改变了一下而已。
  44.         */ 
  45.         framesArray->addObject(CCSpriteFrame::createWithTexture(texture, CCRectMake(x, y, w, h))); 
  46.  
  47.         x += w; 
  48.     } 
  49.  
  50.     CCAnimation* animation = CCAnimation::createWithSpriteFrames(framesArray); 
  51.     animation->setLoops(-1); 
  52.     animation->setRestoreOriginalFrame(true); 
  53.     animation->setDelayPerUnit(delay); 
  54.  
  55.     return animation; 
/************************************************************************/
/* 根据图片列数,自动切割图片,生成CCAnimation对象                                                                    */
/************************************************************************/
cocos2d::CCAnimation* SpriteHelper::createAnimByLineFrameN( const char* name, int col, float delay )
{
    CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteFrameCache();

    CCSpriteFrame* frame = cache->spriteFrameByName(name);

    /* 
        SpriteFrame的纹理对象(CCTexture2D),
        我的理解就是那张TexturePacker打包的大图
        并且,同一张大图生成的SpriteFrame对象的getTexture的结果是一致的。
        换句话说,SpriteFrame其实保存了一份图片纹理的引用。
    */
    CCTexture2D* texture = frame->getTexture();

    /*
        我很好奇,getOriginalSize和getOriginalSizeInPixels倒底有什么区别?
        稍微我研究一下,再和大家分享
    */
    CCSize frameSize = frame->getOriginalSizeInPixels();

    /* 
        SpriteFrame是否没有坐标的概念的,
        只有矩阵范围这个概念,所以要获得它的位置,
        必须通过它的矩阵范围来取得
    */
    CCRect frameRect = frame->getRect();

    float w = frameSize.width / col;    /* 每帧图片的宽*/
    float h = frameSize.height;

    float x = frameRect.origin.x;
    float y = frameRect.origin.y;

    CCArray* framesArray = CCArray::createWithCapacity(col);
    for(int i = 0; i < col; i++)
    {
        /* 
            我一直都很担心,createWithTexture是不是就生成了新的纹理对象?
            不过,我再仔细想想,SpriteFrame本来就只是引用了纹理对象,而不是新建一份小纹理。
            我的理解是,SpriteFrame其实只是其记录数据的作用,记录了某个图片帧在整张大图片的位置,以及截取范围等。
            所以,createWithTexture只不过是把SpriteFrame的范围改变了一下而已。
        */
        framesArray->addObject(CCSpriteFrame::createWithTexture(texture, CCRectMake(x, y, w, h)));

        x += w;
    }

    CCAnimation* animation = CCAnimation::createWithSpriteFrames(framesArray);
    animation->setLoops(-1);
    animation->setRestoreOriginalFrame(true);
    animation->setDelayPerUnit(delay);

    return animation;
}


4.    如果精灵图片是堆在一起并且被旋转了

哇,这种图片要我们来切的话,还是要花点心思的,教程里作者已经给出了算法了,有兴趣的朋友可以研究一下。

我在这里只说两点:

1.       CCSpriteFrame记录的是图片帧在整张大图片里的位置信息,而不管图片帧在大图片里是否旋转过,它所记录的图片宽高是不会变的。图片帧被旋转之后,CCSpriteFrame会使用isRotate来记录。

2.       仔细研究教程作者的算法,我们应该会发现,截取被旋转后的图片帧的方式有点奇怪,并且,当使用CCSpriteFramesetRotate方法后,CCSpriteFrame对象的纹理对象会以CCSpriteFrame所记录的位置为基准去旋转。有点难逻辑,要自己仔细看看算法才能体会到呢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值