作者:慧科集团华东校区-朱家聪老师,转载请注明出处及本链接。
精灵
精灵Sprite类是Node类的派生类,用于描述我们在游戏场景中看到的几乎所有的游戏内容。例如玩家角色,敌方角色,游戏背景等都是用精灵来创建的。围绕着精灵类还有很多概念,如精灵帧缓存,动作,动画等。
创建一个精灵对象
static Sprite* create(); //直接创建一个空的精灵对象
static Sprite* create(const std::string& filename); //使用一个指定的图片文件来创建精灵
static Sprite* create(const std::string& filename, const Rect& rect); //使用图片来创建精灵,并且制定图片的剪裁区域
static Sprite* createWithTexture(Texture2D *texture); //使用指定的纹理来创建精灵
static Sprite* createWithTexture(Texture2D *texture, const Rect& rect, bool rotated=false); //使用指定的纹理和剪裁区域来创建精灵,第三个参数表示是否旋转纹理,默认为不旋转
static Sprite* createWithSpriteFrame(SpriteFrame *spriteFrame); //通过一个精灵帧对象来创建另一个精灵对象
static Sprite* createWithSpriteFrameName(const std::string& spriteFrameName); //通过指定的精灵帧缓存中的精灵帧名来创建精灵对象
使用图片素材来创建一个精灵
现有如下的图片素材,这是一个游戏中出现的紫色小怪兽。要通过这个图片素材来创建一个精灵对象,代码如下所示。
PurpleMonster
//创建一个精灵对象
Sprite *monster = Sprite::create("PurpleMonster.png");
//设置精灵的位置到屏幕正中间
monster->setPosition(Vec2(origin.x+visibleSize.width / 2, origin.y + visibleSize.height / 2));
//设置精灵的大小
monster->setContentSize(Size(22,20));
this->addChild(monster);
运行结果:
MonsterSprite
使用纹理创建一个精灵
在创建精灵时,常常会把多个图片素材放入到同一个png图片文件中去,在使用这样的图片素材时需要对图片进行合理的裁剪。
walkRight
使用Sprete将这个超级玛丽的人物精灵加入到当前的场景中去,并且添加场景的背景精灵。
auto visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
Sprite *bg = Sprite::create("background.jpg");
bg->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2));
bg->setContentSize(Size(512,362));
this->addChild(bg);
Sprite *ground = Sprite::create("ground.png");
ground->setPosition(Vec2(Vec2(origin.x + visibleSize.width / 2, 100)));
ground->setAnchorPoint(Vec2(0.5,1));
ground->setContentSize(Size(512,100));
this->addChild(ground);
Sprite *monster = Sprite::create("PurpleMonster.png");
monster->setAnchorPoint(Vec2(0.5,0));
monster->setContentSize(Size(22,20));
monster->setPosition(Vec2(origin.x + visibleSize.width / 2, 100));
this->addChild(monster);
Sprite *player = Sprite::create("walkRight.png", Rect(0,0,18,32));
player->setAnchorPoint(Vec2(0.5,0));
player->setContentSize(Size(18,32));
player->setPosition(Vec2(origin.x + visibleSize.width / 2 - 100, 100));
this->addChild(player);
运行结果:
玛丽打怪兽
通过在创建精灵对象的create中,添加一个Rect类型的参数,能够对图片素材设置所需要的裁剪范围。但是这种方式创建对象,每次在创建时都需要读取这个图像文件。所以需要手动的将这个图像素材文件添加到系统缓存中去,方便之后的使用。
//将图片添加到纹理缓存中去
Texture2D *cache = Director::getInstance()->getTextureCache()->addImage("walkRight.png");
Sprite *player = Sprite::create();
player->setTexture(cache);
player->setTextureRect(Rect(0,0,18,32));
player->setPosition(Vec2(origin.x + visibleSize.width / 2 - 100, 100));
this->addChild(player);
精灵的性能优化
在游戏的运行过程中,良好的优化能够带来更流畅的用户体验。而在精灵的使用中,使用纹理图集和缓存能够喊好的提高精灵对象的加载速度。
纹理图集
将一个场景中需要使用到的大量的纹理放入到同一个图片文件中去,可以大大的减少读取文件的次数。因为OpenGL绘制图片时的内存管理机制导致这样做也能节省很大空间的内存。纹理图集是由两个文件构成的,一个是纹理图片文件,一个是plist属性列表文件。
SpirteSheetplist文件的内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>frames</key>
<dict>
<key>hero1.png</key>
<dict>
<key>frame</key>
<string>{{2,1706},{391,327}}</string>
<key>offset</key>
<string>{6,0}</string>
<key>rotated</key>
<false/>
<key>sourceColorRect</key>
<string>{{17,0},{391,327}}</string>
<key>sourceSize</key>
<string>{413,327}</string>
</dict>
<key>hero2.png</key>
<dict>
<key>frame</key>
<string>{{2,1313},{391,327}}</string>
<key>offset</key>
<string>{-1,0}</string>
<key>rotated</key>
<true/>
<key>sourceColorRect</key>
<string>{{10,0},{391,327}}</string>
<key>sourceSize</key>
<string>{413,327}</string>
</dict>
<key>hero3.png</key>
<dict>
<key>frame</key>
<string>{{395,984},{391,327}}</string>
<key>offset</key>
<string>{1,0}</string>
<key>rotated</key>
<false/>
<key>sourceColorRect</key>
<string>{{12,0},{391,327}}</string>
<key>sourceSize</key>
<string>{413,327}</string>
</dict>
<key>hero4.png</key>
<dict>
<key>frame</key>
<string>{{2,984},{391,327}}</string>
<key>offset</key>
<string>{-5,0}</string>
<key>rotated</key>
<false/>
<key>sourceColorRect</key>
<string>{{6,0},{391,327}}</string>
<key>sourceSize</key>
<string>{413,327}</string>
</dict>
<key>mountain1.png</key>
<dict>
<key>frame</key>
<string>{{2,391},{934,388}}</string>
<key>offset</key>
<string>{0,-8}</string>
<key>rotated</key>
<false/>
<key>sourceColorRect</key>
<string>{{0,16},{934,388}}</string>
<key>sourceSize</key>
<string>{934,404}</string>
</dict>
<key>mountain2.png</key>
<dict>
<key>frame</key>
<string>{{2,781},{742,201}}</string>
<key>offset</key>
<string>{24,-15}</string>
<key>rotated</key>
<false/>
<key>sourceColorRect</key>
<string>{{48,30},{742,201}}</string>
<key>sourceSize</key>
<string>{790,231}</string>
</dict>
<key>tree1.png</key>
<dict>
<key>frame</key>
<string>{{2,2},{958,387}}</string>
<key>offset</key>
<string>{-14,0}</string>
<key>rotated</key>
<false/>
<key>sourceColorRect</key>
<string>{{0,0},{958,387}}</string>
<key>sourceSize</key>
<string>{986,387}</string>
</dict>
</dict>
<key>metadata</key>
<dict>
<key>format</key>
<integer>2</integer>
<key>realTextureFileName</key>
<string>SpirteSheet.png</string>
<key>size</key>
<string>{1024,2048}</string>
<key>smartupdate</key>
<string>$TexturePacker:SmartUpdate:5f186491d3aea289c50ba9b77716547f:abc353d00773c0ca19d20b55fb028270:755b0266068b8a3b8dd250a2d186c02b$</string>
<key>textureFileName</key>
<string>SpirteSheet.png</string>
</dict>
</dict>
</plist>
使用精灵帧缓存
使用精灵帧缓存能够优化精灵的运行效率。使用到的类有SpriteFrame
和SpriteFrameCache
,主要代码如下:
//创建背景精灵
Sprite *bg = Sprite::create("background.png");
bg->setPosition(Vec2(origin.x+visibleSize.width/2, origin.y+visibleSize.height/2));
bg->setContentSize(visibleSize);
this->addChild(bg, 0);
//获取缓存对象 单例
SpriteFrameCache *frameCache = SpriteFrameCache::getInstance();
//添加纹理集到缓存中
frameCache->addSpriteFramesWithFile("SpirteSheet.plist");
//从精灵帧缓存中,通过帧名来获取精灵对象
Sprite *mountain1 = Sprite::createWithSpriteFrameName("mountain1.png");
mountain1->setAnchorPoint(Vec2::ZERO);
mountain1->setPosition(Vec2(0, 80));
this->addChild(mountain1, 0);
//从精灵帧缓存中,通过帧名来获取一个精灵帧对象
SpriteFrame *heroSpriteFrame = frameCache->getSpriteFrameByName("hero1.png");
//通过精灵帧对象来创建精灵对象
Sprite *hero = Sprite::createWithSpriteFrame(heroSpriteFrame);
hero->setAnchorPoint(Vec2::ZERO);
hero->setPosition(Vec2(300, 80));
this->addChild(hero);
运行结果:
mountain_hero
在使用精灵帧缓存时,需要注意的是,当一个缓存使用完毕之后需要移除这个缓存。否则之后如果有其他的同名的帧就就出现错误。
SpriteFrameCache::getInstance()->removeSpriteFrameByName(<const std::string &name>); //使用帧名来移除一个特定的精灵帧
SpriteFrameCache::getInstance()->removeSpriteFrames(); //移除指定的精灵帧
SpriteFrameCache::getInstance()->removeSpriteFramesFromFile(<const std::string &plist>); //移除指定plist文件的精灵帧
SpriteFrameCache::getInstance()->removeUnusedSpriteFrames(); //移除没有使用的精灵帧
一般来说我们可以直接在当前场景的退出函数里面对精灵帧的缓存进行移除操作。也可以在每一个场景被创建时来移除之前场景所有的精灵帧缓存。
void HelloWorld::onExit(){
SpriteFrameCache::getInstance()->removeSpriteFrames();
}
网友评论