Cocos2d-X研究之v3.x纹理缓存详解



概述

在游戏中需要加载大量的纹理图片,这些操作都是很耗内存和资源的。

当游戏中有个界面用到的图片非常多,第一次点进这界面时速度非常慢(因为要加载绘制很多图片)出现卡顿,我们可以使用TextureCache提前异步加载纹理,等加载结束,进入到这个界面再使用这些图片速度就会非常快。对精灵缓存不清楚的看Cocos2d-X研究之v3.x精灵帧缓存

Texture2D: 纹理,即图片加载入内存后供CPU和GPU操作的贴图对象。

TextureCache(纹理缓存),用于加载和管理纹理。一旦纹理加载完成,下次使用时可使用它返回之前加载的纹理,从而减少对GPU和CPU内存的占用。

常用的方法

当你创建一个精灵,你一般会使用Sprite::create(pszFileName)。假如你去看Sprite::create(pszFileName)的实现方式,你将看到它将这个图片增加到纹理缓存中去了,

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

Sprite*
Sprite::create(const
std::string&
filename)

{

Sprite *sprite
= new
Sprite();

if
(sprite
&& sprite->initWithFile(filename))

{

sprite->autorelease();

return
sprite;

}

_SAFE_DELETE(sprite);

return
nullptr;

}

bool
Sprite::initWithFile(const
std::string&
filename)

{

ASSERT(filename.size()>0,
"Invalid filename for sprite");

Texture2D *texture
= Director::getInstance()->getTextureCache()->addImage(filename);

if
(texture)

{

Rect rect
= Rect::ZERO;

rect.size
= texture->getContentSize();

return
initWithTexture(texture,
rect);

}

// don‘t release here.

// when load texture failed, it‘s better to get a "transparent" sprite then a crashed program

// this->release();

return
false;

}

上面代码显示在控制加载纹理。一旦这个纹理被加载了,在下一时刻就会返回之前加载的纹理引用,并且减少加载的时候瞬间增加的内存。(详细API请看TextureCache API)

获取TextureCache

在3.0版本中,TextureCache不再作为单例模式使用。作为Director的成员变量,通过以下方式获取

Director::getInstance()->getTextureCache();

1

Director::getInstance()->getTextureCache();

获取纹理

如果文件名以前没有被加载时,它会创建一个新的Texture2D 对象,它会返回它。它将使用文件名作为key否则,它会返回一个引用先前加载的图像。

TextureCache屏蔽了加载纹理的许多细节;

addImage函数会返回一个纹理Texture2D的引用,可能是新加载到内存的,也可能是之前已经存在的;

Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(filename);

1

Texture2D *texture
= Director::getInstance()->getTextureCache()->addImage(filename);

也可以通过getTextureForKey方法来获得这个key所对应的纹理缓存,如果这个Key对应的纹理不存在,那么就返回NULL

Texture2D *texture = Director::getInstance()->getTextureCache()->getTextureForKey(textureKeyName);

1

Texture2D *texture
= Director::getInstance()->getTextureCache()->getTextureForKey(textureKeyName);

异步加载纹理

TextureCache类还支持异步加载资源的功能,利用addImageAsync方法。你可以很方面地给addImageAsync方法添加一个回调方法,这样,当纹理异步加载结束的时候,可以得到通知。

你可以选择异步加载方式,这样你就可以为loading场景增加一个进度条。关键代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

TextureCacheTest::TextureCacheTest()

: _numberOfSprites(20)

,
_numberOfLoadedSprites(0)

{

auto
size =
Director::getInstance()->getWinSize();

_labelLoading
= Label::createWithTTF("loading...",
"fonts/arial.ttf",
15);

_labelPercent
= Label::createWithTTF("%0",
"fonts/arial.ttf",
15);

_labelLoading->setPosition(Point(size.width
/ 2,
size.height
/ 2
- 20));

_labelPercent->setPosition(Point(size.width
/ 2,
size.height
/ 2
+ 20));

this->addChild(_labelLoading);

this->addChild(_labelPercent);

// load textrues

Director::getInstance()->getTextureCache()->addImageAsync("Images/HelloWorld.png",
_CALLBACK_1(TextureCacheTest::loadingCallBack,
this));

Director::getInstance()->getTextureCache()->addImageAsync("Images/grossini.png",
_CALLBACK_1(TextureCacheTest::loadingCallBack,
this));

Director::getInstance()->getTextureCache()->addImageAsync("Images/grossini_dance_01.png",
_CALLBACK_1(TextureCacheTest::loadingCallBack,
this));

....

}

void TextureCacheTest::loadingCallBack(cocos2d::Texture2D
*texture)

{

++_numberOfLoadedSprites;

char
tmp[10];

sprintf(tmp,"%%%d",
(int)(((float)_numberOfLoadedSprites
/ _numberOfSprites)
* 100));

_labelPercent->setString(tmp);

if
(_numberOfLoadedSprites
== _numberOfSprites)

{

this->removeChild(_labelLoading,
true);

this->removeChild(_labelPercent,
true);

addSprite();

}

}

清理缓存

removeUnusedTextures则会释放当前所有引用计数为1的纹理,即目前没有被使用的纹理。比如新场景创建好后,使用此方法释放没有使用的纹理非常方便。

1

Director::getInstance()->getTextureCache()->removeUnusedTextures();

当没有其它对象(比如sprite)持有纹理的引用的时候,纹理仍然会存在内存之间。基于这一点,我们可以立马从缓存中移除出去,这样,当纹理不存需要的时候,马上就会从内存中释放掉。如下代码所示:

1

Director::getInstance()->getTextureCache()->removeTextureForKey("Images/grossinis_sister2.png");

当收到”Memory Warning”时,可以调用removeAllTextures()方法。在短期内: 它还将释放一些资源,防止您的应用程序被杀害; 中期: 它将分配更多的资源;从长远来看:它会是相同的。

1

Director::getInstance()->getTextureCache()->removeAllTextures();

Cocos2d-X研究之v3.x纹理缓存详解

时间: 2024-10-08 07:05:34

Cocos2d-X研究之v3.x纹理缓存详解的相关文章

Cocos2d-X研究之v3.x瓦片地图详解

在游戏开发过程中,我们会遇到超过屏幕大小的地图,例如即时战略游戏,使得玩家可以在地图中滚动游戏画面.这类游戏通常会有丰富的背景元素,如果直接使用背景图切换的方式,需要为每个不同的场景准备一张背景图,而且每个背景图都不小,这样会造成资源浪费. 瓦片地图就是为了解决这问题而产生的.一张大的世界地图或者背景图可以由几种地形来表示,每种地形对应一张小的的图片,我们称这些小的地形图片为瓦片.把这些瓦片拼接在一起,一个完整的地图就组合出来了,这就是瓦片地图的原理. TileMap方案 在Cocos2d-x中

Android研究之动态创建UI界面详解

 Android的基本UI界面一般都是在xml文件中定义好,然后通过activity的setContentView来显示在界面上,这是Android UI的最简单的构建方式.其实,为了实现更加复杂和更加灵活的UI界面,往往需要动态生成UI界面,甚至根据用户的点击或者配置,动态地改变UI,本文即介绍该技巧.对事件和进程的可能安卓设备实现触摸事件的监听,跨进程 假设Android工程的一个xml文件名为activity_main.xml,定义如下: 1 2 3 4 5 6 7 8 9 10 11

Java研究之文件路径的读取详解

 记得在操作系统中了解到文件读取有两种方式,当然这在各编程语言中也是通用的,所以java路径也分,相对和绝对路径.上章我们分享了Java研究之学习设计模式-组合模式详解有兴趣的朋友可以去看下. 绝对路径 绝对路径URI ,听着和URL很相似,那我们就来看看吧. URI(Uniformresource Identifier)统一资源标示符.URL统一资源定位符,是一个定位器,还说明了具体如何找到资源.所以他们就有一种抽象和继承的关系.URI抽象的说明了统一资源表示符号,而URL是具体的标识符的

Android研究之手势交互实例实现详解

 先来几张效果图: 一.没有抛掷: 二.向右抛掷一次 三.向右再抛掷一次 接下来说说Android开发中对于手势动作的识别参考资料... 首先,在Android系统中,每一次手势交互都会依照以下顺序执行. 1. 接触接触屏一刹那,触发一个MotionEvent事件. 2. 该事件被OnTouchListener监听,在其onTouch()方法里获得该MotionEvent对象. 3. 通过GestureDetector(手势识别器)转发次MotionEvent对象至OnGestureList

【转载】浏览器缓存详解:expires cache-control last-modified

最近在对CDN进行优化,对浏览器缓存深入研究了一下,记录一下,方便后来者 画了一个草图: 每个状态的详细说明如下: 1.Last-Modified 在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified的属性标记(HttpReponse Header)此文件在服务期端最后被修改的时间,格式类似这样: Last-Modified:Tue, 24 Feb 2009 08:01:04 GMT 客户端第二次请求此URL时,根据HTTP协议

Hibernate之缓存详解

hibernate中提供了两级缓存,一级缓存是Session级别的缓存,它属于事务范围的缓存,该级缓存由hibernate管理,应用程序无需干预:二级缓存是SessionFactory级别的缓存,该级缓存可以进行配置和更改,并且可以动态加载和卸载,hibernate还为查询结果提供了一个查询缓存,它依赖于二级缓存: 一,缓存的概念 缓存是位于应用程序和永久性数据存储源之间用于临时存放复制数据的内存区域,缓存可以降低应用程序之间读写永久性数据存储源的次数,从而提高应用程序的运行性能: hibern

HTML5 离线缓存详解(转)

离线缓存是html5新特性之一,简单理解就是第一次加载后将数据缓存,在没有清除缓存前提下,下一次没有网络也可以加载,用在静态数据的网页或游戏比较好用.当然,Html5新的特性都不是所有浏览器都能支持的,离线缓存也一样.反正IE9(包括)及IE9以下的浏览器目前是不支持的.如果用在移动端,应该都能支持.检测是否支持离线缓存也是比较简单的. if(window.applicationCache){ alert("支持离线缓存"); } else{ alert("不支持离线缓存&q

Yii2页面缓存详解

class TestController extends Controller{ // 该方法会在其他方法之前执行 public function behaviors() { // 声明缓存配置 return [ // 需要注意的这里是二维数组 [ 'class' => 'yii\filters\PageCache', // 设置需要加载的缓存文件 'only' => ['index'], // 设置需要缓存的控制器 'duration' => 100, // 设置过期时间 'depen

Yii2片段缓存详解

片段缓存 1 // ..../view/site/index.php页面 2 <?php 3 if($this->beginCache('cache')) { 4 echo "<p class='cache'>这里待会会被缓存</p>"; 5 $this->endCache(); 6 } 7 echo "<p class='no_cache'>这里不会被缓存</p>"; 8 ?> 片段缓存--过