zoukankan      html  css  js  c++  java
  • 深入分析Cocos2d-x 2.0中的“纹理”

    对CCImage的绘制是通过CCTexture2D来实现的(OPENGL es)通过纹理绘制到某个面。



    (本文中所提到的方法在cocos2d2.0中部分有调整,请应用时候具体察看源码)
    1. 首先来了解一下跟精灵相关的几个类:
    (1) CCTexture2D
    可以把它看成一个纹理,它是cocos2d-x渲染图形的重要参数,用来贴图,因为cocos2d-x使用opengl es绘制2d图形的,它的尺寸是2的n次方。一般通过以下方式获得:
    CCTexture2D* cache = CCTextureCache::sharedTextureCache()->addImage("hero.png"); 
    (2) CCSprite
    这个就是精灵类,是CCNode的子类,可以直接添加到CCLayer或CCScene,它的内部封装了CCTexture2D(纹理),可以通过下面几种方式初始化精灵对象。
    static CCSprite* spriteWithTexture(CCTexture2D pTexture); //CCTexture2D表示精灵包含的图片,范围是整张图片 
    static CCSprite
     spriteWithTexture(CCTexture2D pTexture, const CCRect& rect); //CCRect表示图片的指定范围,即从图片的指定矩形区域
    static CCSprite
     spriteWithSpriteFrame(CCSpriteFrame pSpriteFrame); ////CCSpriteFrame表示精灵的某一帧,内部封装了CCTexture2D和CCRect,CCRect表示图片的指定范围,即从图片的指定矩形区域裁剪 
    static CCSprite
     spriteWithSpriteFrameName(const char pszSpriteFrameName);

    static CCSprite
     spriteWithFile(const char pszFileName); 
    static CCSprite
     spriteWithFile(const char pszFileName, const CCRect& rect); 
    static CCSprite
     spriteWithBatchNode(CCSpriteBatchNode batchNode, const CCRect& rect); 
    下面是两种比较常用的初始化精灵的方式:
    CCSprite
     sprite = CCSprite::spriteWithFile("hero.png"); 
    /** 或者 **/ 
    CCTexture2D* cache = CCTextureCache::sharedTextureCache()->addImage("hero.png"); 
    CCSprite* sprite = CCSprite::spriteWithTexture(cache); 
    (3) CCTextureCache
    它相当于CCTexture2D的容器,是内存池,用来缓存CCTexture2D对象的,它内部有一个字典CCMutableDictionary m_pTextures,key为图片的名称,值是CCTexture2D。当调用它的addImage函数添加图片时,会先根据图片名称去内存中查找是否已存在,是则直接取出返回。下面是addImage部分源码:
    [cpp] 
    CCTexture2D * CCTextureCache::addImage(const char * path) 

    CCTexture2D * texture = NULL; 
    std::string pathKey = path; 
    CCFileUtils::ccRemoveHDSuffixFromFile(pathKey);



    pathKey = CCFileUtils::fullPathFromRelativePath(pathKey.c_str()); 
    texture = m_pTextures->objectForKey(pathKey); 

    std::string fullpath = pathKey; // (CCFileUtils::fullPathFromRelativePath(path)); 
    if( ! texture ) 

    /** .... */ 


    return texture;




    如果需要一次加载多张图片的时候,可以先把图片加载到CCTextureCache中,这样使用图片的时候速度就会很快了。



    (4) CCSpriteBatchNode



    它是批处理绘制精灵,主要是用来提高精灵的绘制效率的,需要绘制的精灵数量越多,效果越明显。因为cocos2d-x采用opengl es绘制图片的,opengl es绘制每个精灵都会执行:open-draw-close流程。而CCSpriteBatchNode是把多个精灵放到一个纹理上,绘制的时候直接统一绘制该texture,不需要单独绘制子节点,这样opengl es绘制的时候变成了:open-draw()-draw()…-draw()-close(),节省了多次open-close的时间。CCSpriteBatchNode内部封装了一个CCTextureAtlas(纹理图集,它内部封装了一个CCTexture2D)和一个CCArray(用来存储CCSpriteBatchNode的子节点:单个精灵)。注意:因为绘制的时候只open-close一次,所以CCSpriteBatchNode对象的所有子节点都必须和它是用同一个texture(同一张图片):



    在addChild的时候会检查子节点纹理的名称跟CCSpriteBatchNode的是不是一样,如果不一样就会出错,源码:



    [cpp] Child(CCNode *child, int zOrder, int tag) 

    /** ... */ 
    // check CCSprite is using the same texture id 
    CCAssert(pSprite->getTexture()->getName() == m_pobTextureAtlas->getTexture()->getName(), "");



    /** ... */ 
    }



    下面是使用CCSpriteBatchNode的使用代码示例:
    [cpp] 
    CCSpriteBatchNode* BatchNode1 = CCSpriteBatchNode::batchNodeWithFile("Images/grossinidanceatlas.png", 50); 
    addChild(BatchNode1, 0, kTagSpriteBatchNode);



    CCSpriteBatchNode* BatchNode = (CCSpriteBatchNode*) getChildByTag( kTagSpriteBatchNode ); 
    int idx = CCRANDOM_0_1() * 1400 / 100; 
    int x = (idx%5) * 85; 
    int y = (idx/5) * 121;



    CCSprite* sprite = CCSprite::spriteWithTexture(BatchNode->getTexture(), CCRectMake(x,y,85,121)); 
    BatchNode->addChild(sprite);



    sprite->setPosition( ccp( p.x, p.y) ); 
    (5) CCSpriteFrameCache
    它是管理CCSpriteFrame的内存池,跟CCTextureCache功能一样,不过跟CCTextureCache不同的是,如果内存池中不存在要查找的帧,它会提示找不到,而不会去本地加载图片。它的内部封装了一个字典:CCDictionary *m_pSpriteFrames,key为帧的名称。CCSpriteFrameCache一般用来处理plist文件(这个文件指定了每个独立的精灵在这张“大图”里面的位置和大小),该文件对应一张包含多个精灵的大图,plist文件可以使用TexturePacker制作。



    下面是使用CCSpriteFrameCache的使用代码示例:



    [cpp] 
    CCSpriteFrameCache* cache = CCSpriteFrameCache::sharedSpriteFrameCache(); 
    cache->addSpriteFramesWithFile("animations/grossini.plist", "animations/grossini.png");
    mpSprite1 = CCSprite::spriteWithSpriteFrameName("grossinidance01.png"); 
    m
    pSprite1->setPosition( ccp( s.width/2-80, s.height/2) ); 
    只要plist文件跟对应的png图片在同一目录下,且名字相同,则addSpriteFramesWithFile(“animations/grossini.plist”, “animations/grossini.png”)可以改成addSpriteFramesWithFile(“animations/grossini.plist”);




      1. CCSpriteBatchNode和CCSpriteFrameCache结合使用
        必须保证CCSpriteFrameCache和CCSpriteBatchNode加载的是同一纹理贴图。




    [cpp] 
    CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("animations/ghosts.plist", "animations/ghosts.png"); 
    CCSpriteBatchNode *aParent = CCSpriteBatchNode::batchNodeWithFile("animations/ghosts.png"); 
    addChild(aParent, 0, kTagSprite1);



    CCSprite *pFather = CCSprite::spriteWithSpriteFrameName("father.gif"); 
    pFather->setPosition(ccp( s.width/2, s.height/2)); 
    aParent->addChild(pFather, 0, kTagSprite2);



    //////////////////////////////////////////////////////////////////////



    voidCCTextureCache的异步加载



    voidCCTextureCache::addImageAsync(constchar *path, CCObject *target, SEL_CallFuncO selector)



    {



    CCAssert(path != NULL, "TextureCache: fileimage MUST not be NULL");



    CCTexture2D *texture = NULL;

    std::string pathKey = path;



    CCFileUtils::ccRemoveHDSuffixFromFile(pathKey);



    pathKey = CCFileUtils::fullPathFromRelativePath(pathKey.c_str());



    texture = m_pTextures->objectForKey(pathKey); //根据pathkey查看是否纹理已经加载过,如果已经有了,则不重复加载



    std::string fullpath = pathKey;



    if (texture != NULL)



    {



    if (target && selector)



    {



    (target->*selector)(texture);



    }



    return;



    }



    if (target)



    {



    target->retain();



    }



    // lazy init



    static bool firstRun = true;



    if (firstRun)



    {



    s_pAsyncStructQueue = new queue<AsyncStruct*>();

    s_pImageQueue = new queue<ImageInfo*>();

    pthread_mutex_init(&s_asyncStructQueueMutex, NULL);



    seminit(&ssem, 0, 0);



    pthreadmutexinit(&s_ImageInfoMutex, NULL);



    pthreadcreate(&sloadingThread, NULL, loadImage, NULL); //创建新的线程,用于后台加载图片



    //创建调度队列,用来根据已加载的图片进行纹理转换



    CCScheduler::sharedScheduler()->scheduleSelector(schedule_selector(CCTextureCache::addImageAsyncCallBack), this, 0, false);



    need_quit = false;



    firstRun = false;



    }



    // generate async struct



    AsyncStruct *data = new AsyncStruct();



    data->filename = fullpath.c_str();



    data->target = target;



    data->selector = selector;



    // add async struct into queue



    pthreadmutexlock(&s_asyncStructQueueMutex);



    s_pAsyncStructQueue->push(data); //将需要加载的图片放入队列中



    pthreadmutexunlock(&s_asyncStructQueueMutex);



    sempost(&ssem);



    }



    从上述代码分析可以看出其过程:



    1.创建线程,用于后台加载




      1. 将对于需要加载的图片放入队列中

      1. callback函数设定,用于将加载完成的图片转为纹理,等待使用其调用是由CCTimer::update调用的。

      1. addImageAsyncCallBack函数在处理完纹理转换,还会调用addImageAsync传入的SEL_CallFuncO selector,实现用户加载图片纹理之后的具体处理。




    使用例子:



    CCTextureCache::sharedTextureCache()->addImageAsync("Images/blocks.png", this,callfuncO_selector(TextureCacheTest::loadingCallBack));



    loadingCallBack函数就是使用异步加载完之后的用户可以自处理结果,比如初始化一个sprite,用这个纹理贴出来。



    或创建动画。



    //////////////////////////////////////////////////////////////////////



    红孩儿



    深入分析Cocos2d-x 2.0中的“纹理”一文对CCTexture2D和CCTexturePVR,CCTextureCache的Api做了说明,推荐大家阅读
    http://blog.csdn.net/honghaier/article/details/8068895

  • 相关阅读:
    黄聪:robots.txt一分钟教程
    黄聪:C#获取系统中的所有字体
    黄聪:C#下如何实现服务器+客户端的聊天程序
    黄聪:C#截取DOS命令输出流取得网卡MAC地址
    黄聪:选择适当的关键词
    黄聪:C#的Main(String[] args)参数输入问题
    黄聪:C#正则表达式整理备忘
    黄聪:【强烈推荐】搜索引擎排名决定一切吗!
    黄聪:第2章 并发操作的一致性问题 (2)
    黄聪:VS2008 "LIB 环境变量" 无效解决方案
  • 原文地址:https://www.cnblogs.com/fwycmengsoft/p/3658755.html
Copyright © 2011-2022 走看看