对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

转载于:https://www.cnblogs.com/lancidie/archive/2013/03/19/2968504.html

深入分析Cocos2d-x 2.0中的“纹理”和精灵-沈大海cocos2d-x教程20相关推荐

  1. 深入分析Cocos2d-x 2.0中的“纹理”

    [Cocos2d-x相关教程来源于红孩儿的游戏编程之路CSDN博客地址:http://blog.csdn.net/honghaier] 红孩儿Cocos2d-X学习园地QQ群:249941957 加群 ...

  2. cocos2d-x3.0中数据类型vector,map、value

    在3.0中,已经不再使用以前的ccarray,ccdictionary,ccint等从以前的oc继承过来的数据类型,转而加入了自己的数据结构,更加符合c++的开发习惯和思考模式,其中就包括了vecto ...

  3. .NET Core 3.0 中的新变化

    译者:楚人Leo 译文:http://www.cnblogs.com/leolion/p/10585834.html 原文:https://msdn.microsoft.com/en-us/magaz ...

  4. TensorFlow 2.0中的tf.keras和Keras有何区别?为什么以后一定要用tf.keras?

    选自pyimagesearch 作者:Adrian Rosebrock 参与:王子嘉.张倩 本文经机器之心授权转载,禁止二次转载 随着 TensorFlow 2.0 的发布,不少开发者产生了一些疑惑: ...

  5. .NET(C#) Internals: 以一个数组填充的例子初步了解.NET 4.0中的并行(二)

    引言 随着CPU多核的普及,编程时充分利用这个特性越显重要.上篇首先用传统的嵌套循环进行数组填充,然后用.NET 4.0中的System.Threading.Tasks提供的Parallel Clas ...

  6. KlayGE 4.0中Deferred Rendering的改进(五)完结篇:Post process

    转载请注明出处为KlayGE游戏引擎 上一篇分析了KlayGE中实现实时全动态GI的方法,本篇是这个系列的完结篇,主要讲流水线的最后一段:Post process. Post process 在Kla ...

  7. OpenCV3.0中的离散傅里叶变换

    图像中的离散傅里叶变换的相关理论较为简单,频域里面,对于一幅图像,高频部分代表了图像的细节.纹理信息:低频部分代表了图像的轮廓信息. 这里我们直接讲解OpenCV3.0中的离散傅里叶变换 1.dft( ...

  8. OpenGL ES 3.0之Texturing纹理详解(二)

    Texture Filtering and Mipmapping 纹理过滤与多级纹理 前面我们已经讲了单个2D图像的2D纹理的介绍,这篇文章主要讲解多级纹理.纹理坐标是用于生成一个2D索引,当放大和缩 ...

  9. 【cocos2d-js官方文档】二十五、Cocos2d-JS v3.0中的单例对象

    为何将单例模式移除 在Cocos2d-JS v3.0之前.全部API差点儿都是从Cocos2d-x中移植过来的,这是Cocos2d生态圈统一性的重要一环.可惜的是,这样的统一性也在非常大程度上限制了C ...

最新文章

  1. PHP7.3中fileinfo怎么安装与开启
  2. PHP explode() 函数
  3. markdown 笔记
  4. mybatis-generator自动生成mapper
  5. php封装webservice_PHP实现WebService的简单示例和实现步骤
  6. 计算机辅助设计受力分析,假肢接受腔的受力分析和计算机辅助设计
  7. linux脚本监控某一进程,linux监控某个进程的运行shell脚本
  8. Win10调试ssd_tensorflow的目标检测
  9. django-解决-修改过的模型类不能被正常迁移的解决办法
  10. 【Spark】Spark调优 JVM调优
  11. BZOJ3123[Sdoi2013]森林——主席树+LCA+启发式合并
  12. 协程 c语言,协程-C语言实现
  13. 安卓Notification通知栏全解
  14. Html5实现二维码扫描并解析-web前端教程
  15. thymeleaf 默认选中下拉框(select option)
  16. java中输出日历_Java:输入年份和月份打印出相应的日历表
  17. centos 7 拉黑IP
  18. 【UI界面开发】基本组件——滑杆
  19. 斜面怎么计算机械效率,初中物理斜面的机械效率学习方法
  20. Java实现第九届蓝桥杯螺旋折线

热门文章

  1. 中国移动锁定数据业务新战略
  2. Web应用中避免Form重复提交的三种方案
  3. 丹麦为NSA开绿灯 通过通信中心监控欧洲政客
  4. 老哥,帮我看下这个 0day exploit:安全研究员遭疑似国家黑客社工,有人不幸中招...
  5. 安全界“圣经”DBIR 报告推翻了哪些“你以为的”数据泄漏情况?
  6. GitHub 2019年漏洞奖励计划最值得回顾的2个精彩 bug
  7. 《UNIX环境高级编程》笔记--read函数,write函数,lseek函数
  8. AC自动机——多个kmp匹配
  9. 取消xp开机默认登陆账户
  10. Redis集群安装及配置步骤