Cocos2d-x SpriteBatchNode
声明:本文分析的是cocos2d-x-3.12的代码
SpriteBatchNode本身不会显示内容,但SpriteBatchNode可以添加使用同一个纹理的Sprite子节点,当绘制SpriteBatchNode节点时,会绘制出所有的子节点。之所以要把节点捆绑在SpriteBatchNode上,是因为SpriteBatchNode可以把相同纹理的节点在一个GL CALL里面绘制,GL CALL是一个非常耗时的操作,这样捆绑后可以大大的提高渲染速度。
直接显示以下两张图片(1.png、2.png)
autosp1 = Sprite::create();
sp1->initWithFile("1.png");
sp1->setPosition(150, 200);
autosp2 = Sprite::create();
sp2->initWithFile("2.png");
sp2->setPosition(250, 200);
this->addChild(sp1);
this->addChild(sp2);
会有两个GL Call
SpriteBatchNode举例
将两张图片合成一张大图12.png (大小201*184)
autosp1 = Sprite::create();
sp1->initWithFile("12.png", Rect(0,0,100,180));
sp1->setPosition(50, 100);
autosp2 = Sprite::create();
sp2->initWithFile("12.png", Rect(101, 0, 100,180));
sp2->setPosition(150, 100);
autobs = SpriteBatchNode::create("12.png");
bs->setPosition(200, 100);
bs->addChild(sp1);
bs->addChild(sp2);
this->addChild(bs);
两个节点只用了一个GL CALL。
说明
1、 SpriteBatchNode的子节点的GlobalZOrder将会失效,因为GlobalZOrder是用于对绘制命令排序的,SpriteBatchNode会将所有要绘制的节点捆绑成一个GL CALL,所以子节点的GlobalZOrder将会失效。子节点的LocalZOrder依然有效可以对SpriteBatchNode的子节点进行排序。SpriteBatchNode本身也有一个GlobalZOrder,这个可以用于对所有节点的层级排序。
2、 在Cocos2d-x3.12中,Cocos在绘制时有优化,当两个连续的绘制命令使用的是同一张纹理时,Cocos会将两个绘制命令合并成一个GL Call。所以以上SpriteBatchNode举例不使用SpriteBatchNode也只有一个GL CALL。因此我们应该尽量把会同时绘制的小图片合成一张大图,这样可以加快渲染速度。
SpriteFrameCache使用大图
为了更好的使用将小图打包成的大图,Cocos提供SpriteFrameCache类。我们可以使用Texturepacker软件将小纹理图片打包成一个大的纹理图片。打包好后会有一个plist配置文件和一张大图。如下:
Plist文件实际是一个XML文件,内部记录各个小图的位置大小等信息。
当使用void SpriteFrameCache::addSpriteFramesWithFile(const std::string& plist)
函数加载plist文件时,SpriteFrameCache会加载大图纹理,解析plist文件,将每个小图封装成一个SpriteFrame类。在创建Sprite时,可以使用SpriteFrame类当作纹理初始化。
SpriteFrameCache、SpriteFrame、Texture类图关系大致如下:
SpriteFrameCache采用单利模式实现,内部有一个Map变量 Map<std::string,SpriteFrame*> _spriteFrames,key是小图的文件名,value是小图对应生成的spriteFrame。这个Map存放了所有的加载后的SpriteFrame。
SpriteFrame中会记录使用的是哪张大图纹理,并记录纹理的位置,旋转角度等等信息。
使用例子如下:
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("friend-zombie.plist");
auto sp1 = Sprite::createWithSpriteFrameName("friend-zombie-01-0000.png");
sp1->setPosition(150, 200);
this->addChild(sp1);