TexturePacker 小图打包大图必备。
为什么要把小图打包成大图?
减少内存消耗,提高绘制效率。与openGL的纹理加载特性和绘制特性有关系。具体可以自行百度,网上介绍的很多。
TexturePacker 工具下载链接 http://www.codeandweb.com/texturepacker
注意 TexturePacker 不是免费的 如果你也有自己的技术博客,可以在官网页面申请一个免费的key
我申请到了一个免费的key,作为回报就有了这篇博客。
欢迎转载 请注明出处 http://blog.youkuaiyun.com/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__
HelloWorldScene.cpp
#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
}
AsyncLoadingScene.h
#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读取纹理 绘制出来 下面这个样子
大家发现有什么不对的地方 欢迎留言
欢迎转载 请注明出处 http://blog.youkuaiyun.com/yangjie314/article/details/23709243