TexturePacker 小图打包大图必备。
为什么要把小图打包成大图?
减少内存消耗,提高绘制效率。与openGL的纹理加载特性和绘制特性有关系。具体可以自行百度,网上介绍的很多。
TexturePacker 工具下载链接 http://www.codeandweb.com/texturepacker
注意 TexturePacker 不是免费的 如果你也有自己的技术博客,可以在官网页面申请一个免费的key
我申请到了一个免费的key,作为回报就有了这篇博客。
欢迎转载 请注明出处 http://blog.csdn.net/yangjie314/article/details/23709243
废话不多,简单介绍一下工具的使用,重点实现异步加载纹理。
具体参数不需要过多设置,如图中所示。直接拖拽多个图片或者装有多个图片的文件夹到图中标记区域
like this: 然后点击Publish
选择路径,然后就生成完毕了。
注意:生成两个文件 一个是合成的大图.png 一个是用来描述大图中小图位置大小的参数配置文件.plist
下面介绍 如何在游戏中加载大图纹理并将大图纹理解析到CCSpriteFrameCache(精灵帧缓存),然后使用小图 --》helloWorld场景
如何在游戏中使用loading界面异步加载多个大图纹理并解析到CCSpriteFrameCache(精灵帧缓存) 同时更新loading进度条 --》AsyncLoadingScene场景
游戏中的资源 如图
demo 环境为cocos2d-x 2.2.2 嗯嗯..3个2
demo代码 共三个场景 HelloWorldScene AsyncLoadingSceneGameScene对应 logo-》loading-》game
HelloWorldScene.h
- #ifndef __HELLOWORLD_SCENE_H__
- #define __HELLOWORLD_SCENE_H__
- #include "cocos2d.h"
- USING_NS_CC;
- //要加载的大图纹理 png 图片的文件名
- const static char fileName[] = "texturePacker_%d.png";
- //解释要加载的大图纹理 png 图片的 plist文件名
- const static char plistName[] = "texturePacker_%d.plist";
- //helloWorld 里使用的大图文件名 index
- const static int testfileNameIndex = 0;
- //整个需要加载的大图的数量
- const static int fileNum = 3;
- class HelloWorld : public cocos2d::CCLayer
- {
- public:
- virtual bool init();
- static cocos2d::CCScene* scene();
- // a selector callback
- void menuCloseCallback(CCObject* pSender);
- CREATE_FUNC(HelloWorld);
- //跳转到loadingScene的回调函数
- void toLoadingScene(float dt);
- //这里释放纹理
- virtual void onExit();
- };
- #endif // __HELLOWORLD_SCENE_H__
- #include "HelloWorldScene.h"
- #include "AsyncLoadingScene.h"
- CCScene* HelloWorld::scene()
- {
- // 'scene' is an autorelease object
- CCScene *scene = CCScene::create();
- // 'layer' is an autorelease object
- HelloWorld *layer = HelloWorld::create();
- // add layer as a child to scene
- scene->addChild(layer);
- // return the scene
- return scene;
- }
- // on "init" you need to initialize your instance
- bool HelloWorld::init()
- {
- //
- // 1. super init first
- if ( !CCLayer::init() )
- {
- return false;
- }
- CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
- CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
- CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
- "CloseNormal.png",
- "CloseSelected.png",
- this,
- menu_selector(HelloWorld::menuCloseCallback));
- pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,
- origin.y + pCloseItem->getContentSize().height/2));
- CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
- pMenu->setPosition(CCPointZero);
- this->addChild(pMenu, 1);
- CCLabelTTF* pLabel = CCLabelTTF::create("TexturePacker Test", "Arial", 30);
- pLabel->setPosition(ccp(origin.x + visibleSize.width/2,
- origin.y + visibleSize.height - pLabel->getContentSize().height));
- this->addChild(pLabel, 1);
- //加载纹理 使用纹理缓存单例 加载
- CCTexture2D* texture =
- CCTextureCache::sharedTextureCache()->addImage(
- CCString::createWithFormat(fileName,testfileNameIndex)->getCString()
- );
- //将纹理分解为原始小图 缓存到精灵帧缓存
- CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile(
- CCString::createWithFormat(plistName,testfileNameIndex)->getCString(),texture
- );
- //跳转到loading页面
- scheduleOnce(schedule_selector(HelloWorld::toLoadingScene),2.0f);
- //可以使用两种方式来生成精灵 都是通过加载到精灵帧缓存中的纹理获得的
- //直接使用图片文件名
- CCSprite* girl_6 = CCSprite::createWithSpriteFrameName("girl_6.jpg");
- //使用精灵帧生成精灵
- //获得精灵帧
- CCSpriteFrame* frame_3 = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("girl_3.jpg");
- CCSprite* girl_3 = CCSprite::createWithSpriteFrame(frame_3);
- girl_3->setPosition(ccp(300,visibleSize.height/2));
- girl_6->setPosition(ccp(600,visibleSize.height/2));
- this->addChild(girl_3);
- this->addChild(girl_6);
- return true;
- }
- void HelloWorld::toLoadingScene(float dt){
- CCScene* scene = AsyncLoadingScene::scene();
- CCDirector::sharedDirector()->replaceScene(scene);
- }
- void HelloWorld::onExit(){
- CCLog("HelloWorld::onExit");
- CCLayer::onExit();
- //释放注意顺序 先释放精灵帧缓存 再释放纹理
- //释放精灵帧缓存
- CCSpriteFrameCache::sharedSpriteFrameCache()->removeSpriteFramesFromFile(
- CCString::createWithFormat(plistName,testfileNameIndex)->getCString()
- );
- //释放纹理缓存
- CCTextureCache::sharedTextureCache()->removeTextureForKey(
- CCString::createWithFormat(fileName,testfileNameIndex)->getCString()
- );
- }
- void HelloWorld::menuCloseCallback(CCObject* pSender)
- {
- #if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
- CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
- #else
- CCDirector::sharedDirector()->end();
- #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
- exit(0);
- #endif
- #endif
- }
- #ifndef _ASYNC_LOADING_SCENE_H_
- #define _ASYNC_LOADING_SCENE_H_
- #include "cocos2d.h"
- USING_NS_CC;
- /**
- 加载多张texturePacker生成的大图,可能会造成卡顿,所以使用异步加载纹理
- cocos2d-x 自己维护一个线程来加载资源 无需过多操作 方便 省事!
- 加载到内存的纹理在不使用的情况下注意释放!
- */
- //进度条每次移动的时间
- const static float s_progressAddTime = 2.0f;
- class AsyncLoadingScene : public CCLayer
- {
- public:
- virtual bool init();
- virtual void onEnter();
- static CCScene* scene();
- CREATE_FUNC(AsyncLoadingScene);
- //异步加载完一张纹理的回调函数
- void AsyncLoadingCallback(CCObject* pSender);
- //进度条
- CCProgressTimer* progress;
- //当前加载的第几个纹理
- int loadingIndex;
- //加载进度
- int i_progress;
- //加载一个纹理进度的增加值
- int i_progressAddValue;
- //加载结束的回调 控制跳转
- void loadingOverCallback();
- };
- #endif//_ASYNC_LOADING_SCENE_H_
AsyncLoadingScene.cpp
- #include "AsyncLoadingScene.h"
- #include "HelloWorldScene.h"
- #include "GameScene.h"
- CCScene* AsyncLoadingScene::scene(){
- CCScene* scene = CCScene::create();
- AsyncLoadingScene* layer = AsyncLoadingScene::create();
- scene->addChild(layer);
- return scene;
- }
- bool AsyncLoadingScene::init(){
- if (!CCLayer::init())
- {
- return false;
- }
- CCLog("AsyncLoadingScene::init");
- CCSize size = CCDirector::sharedDirector()->getWinSize();
- //进度条背景图片
- CCSprite* progressBgd = CCSprite::create("progress.png");
- //设置成灰色
- progressBgd->setColor(ccGRAY);
- //设置统一的坐标
- CCPoint progressPosition = ccp(size.width/2,size.height/4);
- progressBgd->setPosition(progressPosition);
- this->addChild(progressBgd);
- //进度条
- //通过精灵生成
- progress = CCProgressTimer::create(CCSprite::createWithTexture(progressBgd->getTexture()));
- //设置纵向
- progress->setType(kCCProgressTimerTypeBar);
- //设置从左边开始还是从右边开始
- progress->setMidpoint(ccp(0,0));
- //不懂是干嘛的
- progress->setBarChangeRate(ccp(1,0));//
- progress->setPosition(progressPosition);
- //progress->setPercentage(0);//设置初始进度
- this->addChild(progress,1);
- //进度条的更新 放到异步加载资源回调中
- //加载回调中 控制解析plist
- i_progress= 0;
- loadingIndex = 0;
- i_progressAddValue = 100/fileNum;
- //为了验证异步加载不会对游戏主线程造成卡顿 弄30个精灵让他们执行无限循环上下抽搐动作
- for (int i = 0; i < 30; i++)
- {
- CCSprite* sp = CCSprite::create("sp9.png");
- CCPoint spPos = ccp(30*i+30,size.height/2+i*5);
- sp->setPosition(spPos);
- this->addChild(sp);
- CCMoveBy* moveBy1 = CCMoveBy::create(0.1f,ccp(0,100));
- //CCReverseTime 反动作,谨慎使用 多适用于 XXXBy 而不是 XXXTo
- //CCReverseTime* reverse = CCReverseTime::create(moveBy1);
- CCMoveBy* moveBy2 = CCMoveBy::create(0.1f,ccp(0,-100));
- CCSequence* seq = CCSequence::create(moveBy1,moveBy2,NULL);
- CCRepeatForever* forever = CCRepeatForever::create(seq);
- sp->runAction(forever);
- }
- return true;
- }
- void AsyncLoadingScene::onEnter(){
- CCLog("AsyncLoadingScene::onEnter");
- CCLayer::onEnter();
- for (int i = 0; i < fileNum; i++)
- {
- //异步加载 最后参数为 异步加载完成后回调的函数 传递的CCObjcet 为加载完成后的纹理
- CCTextureCache::sharedTextureCache()->addImageAsync(
- CCString::createWithFormat(fileName,i)->getCString(),
- this,
- callfuncO_selector(AsyncLoadingScene::AsyncLoadingCallback)
- );
- }
- }
- //异步加载回调函数
- void AsyncLoadingScene::AsyncLoadingCallback(CCObject* pSender){
- //传递的CCObjcet 为加载完成后的纹理
- CCTexture2D* texture = dynamic_cast<CCTexture2D*>(pSender);
- //解析加载的纹理到 精灵帧缓存
- CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile(
- CCString::createWithFormat(plistName,loadingIndex)->getCString(),
- texture
- );
- //加载完最后一个 loading 结束 进度条绘制完毕后 跳转到切屏
- if (loadingIndex == fileNum-1)
- {
- //停止动作
- progress->stopAllActions();
- //进度直接设置为100
- i_progress = 100;
- //进度条增加动作
- CCProgressTo* to = CCProgressTo::create(s_progressAddTime, i_progress);
- CCSequence* seq = CCSequence::create(
- to,
- //纹理加载完毕->纹理解析完毕->进度条动作执行完毕->跳转到游戏页面
- CCCallFunc::create(this,callfunc_selector(AsyncLoadingScene::loadingOverCallback)),
- NULL);
- progress->runAction(seq);
- //progress->setPercentage(i_progress);
- //loadingOverCallback();
- }else
- {
- //停止动作
- progress->stopAllActions();
- //增加进度条进度
- i_progress += i_progressAddValue;
- //进度条增加动作
- CCProgressTo* to = CCProgressTo::create(s_progressAddTime, i_progress);
- progress->runAction(to);
- //progress->setPercentage(i_progress);
- //尼玛写注释好累啊.. 这是干嘛来着..
- loadingIndex++;
- }
- }
- void AsyncLoadingScene::loadingOverCallback(){
- CCLog("AsyncLoadingScene::loadingOverCallback");
- CCScene* scene = GameScene::scene();
- CCDirector::sharedDirector()->replaceScene(scene);
- }
GameScene.h
- #ifndef _GAME_SCENE_H_
- #define _GAME_SCENE_H_
- #include "cocos2d.h"
- USING_NS_CC;
- class GameScene:public CCLayer
- {
- public:
- virtual bool init();
- static CCScene* scene();
- CREATE_FUNC(GameScene);
- };
- #endif //_GAME_SCENE_H_
GameScene.cpp
- #include "GameScene.h"
- CCScene* GameScene::scene(){
- CCScene* scene = CCScene::create();
- GameScene* layer = GameScene::create();
- scene->addChild(layer);
- return scene;
- }
- bool GameScene::init(){
- if (!CCLayer::init())
- {
- return false;
- }
- const static char imageName[] = "neck_%d.jpg";
- int index = 1;
- for (int i = 1; i <= 2; i++)
- {
- for (int j = 1; j <= 5; j++)
- {
- CCSprite* temp = CCSprite::createWithSpriteFrameName(CCString::createWithFormat(imageName,index)->getCString());
- temp->setPosition(ccp(200*j-50,200*i+150));
- this->addChild(temp);
- index++;
- }
- }
- return true;
- }
大概就是这个样子..嗯
最后在GameScene读取纹理 绘制出来 下面这个样子
大家发现有什么不对的地方 欢迎留言