Sprite(精灵)全解
精灵是游戏中十分重要的组成部分,随处可见,如:游戏背景、NPC、人物、道具等。在cocos2d-x引擎中,只要是用图片展示的,基本上需要使用精灵类。
1. 首先来了解一下跟精灵相关的几个类:
(1) Texture2D
可以把它看成一个纹理,它是cocos2d-x渲染图形的重要参数,用来贴图,因为cocos2d-x使用openglES绘制2d图形的,它的尺寸是2的n次方。一般通过以下方式获得:
//cocos2d-x3.0beta的用法
Texture2D * texture
= Director::getInstance()->getTextureCache()->addImage("hero.png");
(2) Sprite
这个就是精灵类,是Node的子类,它的内部封装了Texture2D(纹理),可以通过下面几种方式初始化精灵对象。
static Sprite* create();
static Sprite* create(const std::string& filename);
//Rect表示图片的指定范围,即从图片的指定矩形区域裁剪
static Sprite* create(const std::string& filename, const Rect& rect);
//Texture2D表示精灵包含的图片,范围是整张图片
static Sprite* createWithTexture(Texture2D *texture);
//SpriteFrame表示精灵的某一帧,大多数情况下精灵本身的图片有多帧。它内部封装了Texture2D和Rect,可以从一个大图片取出一部分作为一帧。
static Sprite* createWithSpriteFrame(SpriteFrame *pSpriteFrame);
//SpriteFrameName表示帧的名字,根据帧名从内存中取出SpriteFrame
static Sprite* createWithSpriteFrameName(const std::string& spriteFrameName);
(3) TextureCache
它相当于Texture2D的容器,是内存池,用来缓存Texture2D对象的。当调用它的addImage函数添加图片时,会先根据图片名称去内存中查找是否已存在,是则直接取出返回。
如果需要一次加载多张图片的时候,可以先把图片加载到TextureCache中,这样使用图片的时候速度就会很快了。
(4) SpriteFrameCache
它是管理SpriteFrame的内存池,跟TextureCache功能一样,不过跟TextureCache不同的是,如果内存池中不存在要查找的帧,它会提示找不到,而不会去本地加载图片。SpriteFrameCache一般用来处理plist文件(这个文件指定了每个独立的精灵在这张“大图”里面的位置和大小),该文件对应一张包含多个精灵的大图,plist文件可以使用TexturePacker制作。如下图所示:
创建精灵方法:利用帧缓存中的一帧的名称声称一个对象,适合于plist打包好的文件:
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("animations/grossini.plist", "animations/grossini.png");
sprite* hero = sprite::createWithSpriteFrameName("grossini_dance_01.png");
只要plist文件跟对应的png图片在同一目录下,且名字相同,则addSpriteFramesWithFile(“animations/ grossini.plist”, “animations / grossini.png”);
可以改成addSpriteFramesWithFile(“animations/grossini.plist”);
创建精灵方法:利用另外一帧生成一个精灵对象,适合于做帧动画使用。
SpriteFrame* frame = SpriteFrame::create("icon.png", Rect(0, 0, 40, 30));
Sprite* sprite = Sprite::createWithSpriteFrame(frame);
它是批处理绘制精灵,主要是用来提高精灵的绘制效率的,需要绘制的精灵数量越多,效果越明显。因为cocos2d-x采用opengl es绘制图片的,opengl es绘制每个精灵都会执行:open-draw-close流程。而SpriteBatchNode是把多个精灵放到一个纹理上,绘制的时候直接统一绘制该texture,不需要单独绘制子节点,这样opengles绘制的时候变成了:open-draw()-draw()…-draw()-close(),节省了多次open-close的时间。注意:因为绘制的时候只open-close一次,所以SpriteBatchNode对象的所有子节点都必须和它是用同一个texture(同一张图片),类似下面这样的图片,4个贝壳都在同一纹理上:
1. 直接使用Layer进行添加精灵,Layer上有几个精灵,那么底层就会绘制几次精灵;
简单可以理解成底层绘制方式如下:
for(int i= 0;i<100;i++){open-draw-close;}
但是使用集合的话,Layer只需要对精灵集合进行一次渲染,
简单可以理解成底层绘制方式如下:
open-draw(100次绘制)-close
从以上两种方式可以看出两者的区别了,第二种使用精灵集合省去了99次open和close的过程,从而达到优化作用;
2.使用SpriteBathNode虽然能达到优化,但是要注意一点:
初始化精灵集合SpriteBatchNode的时候会加载一张图片资源(或者pvr文件等),那么限制其精灵集合的子精灵都必须使用集合加载的这张图才行,否则会给出警告;
3.使用SpriteBatchNode还要注意一点,因为精灵都存放在集合中,那么这个集合SpriteBatchNode中的节点(精灵)都将在同一个z轴上,同一深度上;
一般使用TexturePacker工具都会将很多精灵图片或者动作帧放在一起打包成“.pvr.z”、”.plist”、“-hd.pvr.z”和”-hd.plist”的四个文件,其中两个-hd的是使用工具生成的打包资源的高清版本(940*480)使用的,这个不再强调了;
那么肯定会有童鞋说,那么如果把这资源文件与SpriteBathNode结合使用岂不是更嗨皮,没错,可以的,加载的时候只需要将如下创建集合即可:
创建精灵方法:SpriteBathNode与SpriteFrameCache结合使用。
//加载图片资源
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("xx.plist");
SpriteBatchNode aParenet = SpriteBatchNode::create("xx.pvr.z");
this->addChild(aParenet);
Sprite *pFather = Sprite::spriteWithSpriteFrameName("father.gif");
pFather->setPosition(p(s.width / 2, s.height / 2));
aParenet->addChild(pFather);