TexturePacker打包图片并使用addImageAsync实现longding界面异步加载图片纹理---cocos2d-x学习之路[3]

本文介绍如何使用TexturePacker工具将小图打包成大图以优化内存消耗和绘制效率,并演示了如何在游戏中实现纹理的异步加载及解析到精灵帧缓存的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值