cocos2d-x 源码剖析(19)

这节开始讲CCNode,之前讲过一部分,却是介绍cocos2d-x的其他的内容。毕竟CCNode太过基础,而且大范围使用,不一点一点讲也不太现实。在cocos2d-x的开发中,没有特殊的情况,我很少继承CCNode之外的类。很多情况下,我先选择继承CCSprite来添加一些逻辑,但是在几次尝试之后发现太过愚蠢。所以我总是选择使用CCNode来作为容器,包含一个CCSprite做显示,其他的代码来做逻辑。还有时候会直接使用一个新的class,连CCNode都不用继承,但是到后来要使用回调或者Action的时候又发现当初还是太过天真。说真的,cocos2d-x为了和cocos2d保持一致连起码的原则都丢失了。换来的不过是看起来很easy的甜点。伴随移动游戏开发的成熟,游戏引擎的开源,cocos2d-x还能走多久呢?最近微博上有cocos2d-x和Unity3D口水,不忍多说了几句。

先从CCNodeRGBA开始讲起,他是实现了CCRGBAProtocol的Node。这个类主要做为继承使用。


virtual void setColor(const ccColor3B& color) = 0;
virtual void setOpacity(GLubyte opacity) = 0;
virtual void setCascadeColorEnabled(bool cascadeColorEnabled) = 0;

上面就是这个类的核心内容。第三个函数设置是否是级联处理。我们知道CCNode本身是没有绘制内容的,所以显示的逻辑做它的子类当中,这里仅仅是做一些get和set函数,我们之后再讲。
下面我们来看看CCAtlasNode,CCAtlasNode是实现了CCTextureProtocol的CCNodeRGBA。
而CCTextureProtocol就是一个简单的seter和geter。

class CC_DLL CCAtlasNode : public CCNodeRGBA, public CCTextureProtocol
virtual CCTexture2D* getTexture(void) = 0;
virtual void setTexture(CCTexture2D *texture) = 0;

有意思的是CCTextureProtocol继承之CCBlendProtocol,而它也是一个seter和geter。

class CC_DLL CCTextureProtocol : public CCBlendProtocol
virtual void setBlendFunc(ccBlendFunc blendFunc) = 0;
virtual ccBlendFunc getBlendFunc(void) = 0;

在CCNodeRGBA中使用两个下面的方法设置成员变量:

CC_PROPERTY(CCTextureAtlas*, m_pTextureAtlas, TextureAtlas);
CC_PROPERTY(ccBlendFunc, m_tBlendFunc, BlendFunc);

其定义如下,说实话很不习惯。

#define CC_PROPERTY(varType, varName, funName)\
protected: varType varName;\
public: virtual varType get##funName(void);\
public: virtual void set##funName(varType var);

这个类是个很重要的类,如果你用到了,说明你进入了cocos2d-x高手范畴。他是优化游戏的一个重要手段。在普通的CCNode体系中,一个draw函数要做很多重复的事情,对于一个通用且灵活的解决方案来说这是必要的。但是很多cpu被白白消耗了。CCAtlasNode体系提供了一个优化的解决方案,来提高绘制效率。效果是明显的,当然使用上就有限制了。应为普通的CCNode的draw函数交给子类去实现了,所以我们之后讲解,但是现在我们来看看CCAtlasNode的draw函数:

void CCAtlasNode::draw(void)
{
    CC_NODE_DRAW_SETUP();
 
    ccGLBlendFunc( m_tBlendFunc.src, m_tBlendFunc.dst );
 
    GLfloat colors[4] = {_displayedColor.r / 255.0f, _displayedColor.g / 255.0f, _displayedColor.b / 255.0f, _displayedOpacity / 255.0f};
    getShaderProgram()->setUniformLocationWith4fv(m_nUniformColor, colors, 1);
 
    m_pTextureAtlas->drawNumberOfQuads(m_uQuadsToDraw, 0);
}


和普通的CCTexture不同这里用到了CCTextureAtlas。那么这是怎么加快绘制效率的呢?还记得CCTexture的那个draw函数吗?他用到了一个最简单的draw函数所必须的步骤,也就是不能再少了。但是CCTextureAtlas的绘制就不一样。

void CCTextureAtlas::drawNumberOfQuads(unsigned int n, unsigned int start)
{    
    if (0 == n) 
    {
        return;
    }
    ccGLBindTexture2D(m_pTexture->getName());
 
    glBindBuffer(GL_ARRAY_BUFFER, m_pBuffersVBO[0]);
#define kQuadSize sizeof(m_pQuads[0].bl)
    // XXX: update is done in draw... perhaps it should be done in a timer
    if (m_bDirty) 
    {
        glBufferSubData(GL_ARRAY_BUFFER, sizeof(m_pQuads[0])*start, sizeof(m_pQuads[0]) * n , &m_pQuads[start] );
        m_bDirty = false;
    }
 
    ccGLEnableVertexAttribs(kCCVertexAttribFlag_PosColorTex);
 
    // vertices
    glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof(ccV3F_C4B_T2F, vertices));
 
    // colors
    glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof(ccV3F_C4B_T2F, colors));
 
    // tex coords
    glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof(ccV3F_C4B_T2F, texCoords));
 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_pBuffersVBO[1]);
 
    glDrawElements(GL_TRIANGLES, (GLsizei)n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(m_pIndices[0])));
 
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 
    CC_INCREMENT_GL_DRAWS(1);
    CHECK_GL_ERROR_DEBUG();
}

其关键的不同在与数据来源是一个m_pQuads的结构,而不是一个普通的矩形。也就是说普通的Node一次只绘制了一个矩形出来,而CCNodeAltas一次绘制出了多个矩形。当然这就要求需要显示的图片要在同一张纹理上。实际上如果我们需要做一个显示单元的话,它的资源通常都会合成一张图片。加上使用CCNodeAltas就会极大的提高效率。大家不妨测试下,一百次绘制一个矩形和一次绘制一百个矩形的效率差异到底有多大。这就是CCNodeAltas能提高效率的根源。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值