前言

  对于内存的优化,网上有很多例子和教程。总体来说,就那么几种解决方案,在最后我会简单提下,这里先说下在quick中,对于图片的处理。

1.查看内存调试信息

  对于quick框架的了解,我们可以参考\docs\文件夹里面的文件,有相关api。学会学习的第一步,就是学会看api。好了,废话不多说,下面是和内存相关的地方。

但是在这里我不说具体再项目中怎么使用了,相信各位大神们一看就明白,有错误的地方,更好的,请大神们分享一下。

在项目的config.lua中有些调试信息的设置,这里简单说下。

在初始化框架之前,可以定义以下常量:

  • DEBUG: 设置框架的调试输出级别

    DEBUG = 0 -- 不输出任何调试信息(默认值) DEBUG = 1 -- 输出基本的调试信息 DEBUG = 2 -- 输出详细的调试信息 
  • DEBUG_FPS: 设置是否在画面中显示渲染帧率等信息

    DEBUG_FPS = false -- 不显示(默认值) DEBUG_FPS = true -- 显示 
  • DEBUG_MEM: 设置是否输出内存占用信息

    DEBUG_MEM = false -- 不输出(默认值) DEBUG_MEM = true -- 每 10 秒输出一次 
  • LOAD_DEPRECATED_API: 是否载入过时的 API 定义,默认为 false

  • disABLE_DEPRECATED_WARNING: 使用过时的 API 时是否显示警告信息,默认为 true

  • USE_DEPRECATED_EVENT_ARGUMENTS: 是否使用过时的 Node 事件参数格式,默认为 false

上面标红的就是我们要用的,可以在调试信息中看到内存的使用情况。

2.SceneEx.lua

  Scene的自动清理更能,实现原理是exit的时候,遍历autoCleanupImages_数组,然后调用

display.removeSpriteFrameByImageName(imageName)进行释放,我们可以把需要在场景切换时释放掉的图片,通过
Scene:markAutoCleanupImage放到scene的autoCleanupImages_中。详细代码如下:
local c = cc
local Scene = c.Scene

function Scene:setAutoCleanupEnabled()
    self:addNodeEventListener(c.NODE_EVENT,function(event)
        if event.name == "exit" then
            if self.autoCleanupImages_ then
                for imageName,v in pairs(self.autoCleanupImages_) do
                    display.removeSpriteFrameByImageName(imageName)
                end
                self.autoCleanupImages_ = nil
            end
        end
    end)
end

function Scene:markAutoCleanupImage(imageName)
    if not self.autoCleanupImages_ then self.autoCleanupImages_ = {} end
    self.autoCleanupImages_[imageName] = true
    return self
end

3.display.lua

  对于图片的批处理、批量加载、合成大图加载、降低图片的质量等,在display中,有方法的封装和介绍。

-- start -- ------------------------------ -- 将指定的 Sprite Sheets 材质文件及其数据文件载入图像帧缓存。 @function [parent=#display] addSpriteFrames @param string plistFilename 数据文件名 @param string image 材质文件名 @see Sprite Sheets --[[-- 将指定的 Sprite Sheets 材质文件及其数据文件载入图像帧缓存。 格式: display.addSpriteFrames(数据文件名,材质文件名) ~~~ lua -- 同步加载纹理 display.addSpriteFrames("Sprites.plist","Sprites.png") -- 异步加载纹理 local cb = function(plist,image) -- do something end display.addSpriteFrames("Sprites.plist","Sprites.png",cb) ~~~ Sprite Sheets 通俗一点解释就是包含多张图片的集合。Sprite Sheets 材质文件由多张图片组成,而数据文件则记录了图片在材质文件中的位置等信息。 ]] end -- function display.addSpriteFrames(plistFilename,image,handler) local async = type(handler) == function" local asyncHandler = nil if async then asyncHandler = function() local texture = sharedTextureCache:getTextureForKey(image) assert(texture,string.format(The texture %s,%s is unavailable.",plistFilename,image)) sharedSpriteFrameCache:addSpriteFrames(plistFilename,texture) handler(plistFilename,image) end if display.TEXTURES_PIXEL_FORMAT[image] then cc.Texture2D:setDefaultAlphaPixelFormat(display.TEXTURES_PIXEL_FORMAT[image]) then sharedTextureCache:addImageAsync(image,asyncHandler) else sharedSpriteFrameCache:addSpriteFrames(plistFilename,255); line-height:1.5!important">end cc.Texture2D:setDefaultAlphaPixelFormat(cc.TEXTURE2D_PIXEL_FORMAT_RGBA8888) else end 从内存中卸载 Sprite Sheets 材质和数据文件 @function [parent=#display] removeSpriteFramesWithFile @param string image 材质文件名 function display.removeSpriteFramesWithFile(plistFilename,imageName) sharedSpriteFrameCache:removeSpriteFramesFromFile(plistFilename) if imageName then display.removeSpriteFrameByImageName(imageName) 设置材质格式。 @function [parent=#display] setTexturePixelFormat @param string filename 材质文件名 @param integer format 材质格式 @see Texture Pixel Format -- 设置材质格式。 为了节约内存,我们会使用一些颜色品质较低的材质格式,例如针对背景图使用 cc.TEXTURE2D_PIXEL_FORMAT_RGB565 格式。 display.setTexturePixelFormat() 可以指定材质文件的材质格式,这样在加载材质文件时就会使用指定的格式。 function display.setTexturePixelFormat(filename,format) display.TEXTURES_PIXEL_FORMAT[filename] = format 从图像帧缓存中删除一个图像。 @function [parent=#display] removeSpriteFrameByImageName @param string imageName 图像文件名 -- 从图像帧缓存中删除一个图像。 有时候,某些图像仅在特定场景中使用,例如背景图。那么在场景退出时,就可以用 display.removeSpriteFrameByImageName() 从缓存里删除不再使用的图像数据。 此外,Scene 提供了 markAutoCleanupImage() 接口,可以指定场景退出时需要自动清理的图像,推荐使用。 function display.removeSpriteFrameByImageName(imageName) sharedSpriteFrameCache:removeSpriteFrameByName(imageName) cc.Director:getInstance():getTextureCache():removeTextureForKey(imageName) 从指定的图像文件创建并返回一个批量渲染对象。 @function [parent=#display] newBatchNode @param string image 图像文件名 @param integer capacity @return SpriteBatchNode#SpriteBatchNode ret (return value: cc.SpriteBatchNode) @see Batch Node -- 从指定的图像文件创建并返回一个批量渲染对象。 ~~~ lua local imageName = "Sprites.png" display.addSpriteFrames("Sprites.plist",imageName) -- 载入图像到帧缓存 -- 下面的代码绘制 100 个图像只用了 1 次 OpenGL draw call local batch = display.newBatchNode(imageName) for i = 1,100 do local sprite = display.newSprite("#Sprite0001.png") batch:addChild(sprite) end -- 下面的代码绘制 100 个图像则要使用 100 次 OpenGL draw call local group = display.newNode() for i = 1,100 do local sprite = display.newSprite("#Sprite0001.png") group:addChild(sprite) end ~~~ function display.newBatchNode(image,capacity) return cc.SpriteBatchNode:create(image,capacity or 100) 创建并返回一个图像帧对象。 @function [parent=#display] newSpriteFrame @param string 图像帧名称 @return SpriteFrameCache#SpriteFrameCache ret (return value: cc.SpriteFrameCache) -- 创建并返回一个图像帧对象。 ~~~ lua display.addSpriteFrames("Sprites.plist","Sprites.png") -- 创建一个 Sprite local sprite = display.newSprite("#Yes.png") -- 创建一个图像帧 local frameNo = display.newSpriteFrame("No.png") -- 在需要时,修改 Sprite 的显示内容 sprite:setSpriteFrame(frameNo) ~~~ function display.newSpriteFrame(frameName) local frame = sharedSpriteFrameCache:getSpriteFrame(frameName) not frame then printError(display.newSpriteFrame() - invalid frameName %s",255); line-height:1.5!important">tostring(frameName)) return frame 以特定模式创建一个包含多个图像帧对象的数组。 @function [parent=#display] newFrames @param string pattern 模式字符串 @param integer begin 起始索引 @param integer length 长度 @param boolean isReversed 是否是递减索引 @return table#table ret (return value: table) 图像帧数组 -- 以特定模式创建一个包含多个图像帧对象的数组。 ~~~ lua -- 创建一个数组,包含 Walk0001.png 到 Walk0008.png 的 8 个图像帧对象 local frames = display.newFrames("Walk%04d.png",1,8) -- 创建一个数组,包含 Walk0008.png 到 Walk0001.png 的 8 个图像帧对象 local frames = display.newFrames("Walk%04d.png",8,true) ~~~ function display.newFrames(pattern,begin,length,isReversed) local frames = {} local step = 1 local last = begin + length - if isReversed then last,begin = begin,last step = -for index = begin,last,step do local frameName = string.format(pattern,index) local frame = sharedSpriteFrameCache:getSpriteFrame(frameName) then printError(display.newFrames() - invalid frame,name %stostring(frameName)) return end frames[#frames + 1] = frame return frames 以包含图像帧的数组创建一个动画对象。 @function [parent=#display] newAnimation @param table frames 图像帧的数组 @param number time 每一桢动画之间的间隔时间 @return Animation#Animation ret (return value: cc.Animation) Animation对象 -- 以包含图像帧的数组创建一个动画对象。 ~~~ lua local frames = display.newFrames("Walk%04d.png",8) local animation = display.newAnimation(frames,0.5 / 8) -- 0.5 秒播放 8 桢 sprite:playAnimationOnce(animation) -- 播放一次动画 ~~~ function display.newAnimation(frames,time) local count = #frames local array = Array:create() for i = 1,count do array:addobject(frames[i]) end time = time 1.0 / count return cc.Animation:createWithSpriteFrames(frames,time) 以指定名字缓存创建好的动画对象,以便后续反复使用。 @function [parent=#display] setAnimationCache @param string name 名字 @param Animation animation 动画对象 -- 以指定名字缓存创建好的动画对象,以便后续反复使用。 ~~~ lua local frames = display.newFrames("Walk%04d.png",0.5 / 8) -- 0.5 秒播放 8 桢 display.setAnimationCache("Walk",animation) -- 在需要使用 Walk 动画的地方 sprite:playAnimationOnce(display.getAnimationCache("Walk")) -- 播放一次动画 ~~~ function display.setAnimationCache(name,animation) sharedAnimationCache:addAnimation(animation,name) 取得以指定名字缓存的动画对象,如果不存在则返回 nil。 @function [parent=#display] getAnimationCache @param string name @return Animation#Animation ret (return value: cc.Animation) function display.getAnimationCache(name) return sharedAnimationCache:getAnimation(name) 删除指定名字缓存的动画对象。 @function [parent=#display] removeAnimationCache @param string name function display.removeAnimationCache(name) sharedAnimationCache:removeAnimation(name) 从内存中卸载没有使用 Sprite Sheets 材质 @function [parent=#display] removeUnusedSpriteFrames function display.removeUnusedSpriteFrames() sharedSpriteFrameCache:removeUnusedSpriteFrames() sharedTextureCache:removeUnusedTextures() 创建一个进度条的节点 @function [parent=#display] newProgresstimer @param mixed image @param number progresstype -- 创建一个进度条的节点 进度条类型有: - display.PROGRESS_TIMER_BAR - display.PROGRESS_TIMER_RADIAL 环形 ]] end --

3.项目内存优化

  对于整个项目的内存优化,我们可以在下面几个方面。cocos2dx一直在更新和优化,所以,不要仅局限于下面的解决方案,只是其中的一部分,

也许有的版本已经不再适应,请根据你所使用的版本和项目的具体需求,做出优化方案。

(1)纹理优化

上面我们讲到了quick中的优化,下面还有其他几个解决办法

为了优化纹理内存的使用,我们必须知道什么因素影响了内存的使用情况。

有三个因素影响了纹理的内存使用。纹理格式(压缩的还是非压缩的),颜色,大小。

我们可以使用PVR格式的纹理来减少内存使用。最被建议的纹理格式是pvr.ccz,每色的bit值越高,画面质量就约好。但是也会消费很多内存。

那么我们使用颜色深度是RGBA4444的纹理来代替RBGA8888,这将会消费一半内存。

我们也会发现大纹理也会导致内存相关的问题。那么你最好使用适度的大小。

(2)音频

有三个因素影响文件内存使用。是音频文件格式,比特率,和样本率

我们最希望音频文件时mp3格式。因为它被Android和iOS都支持。并且它也被压缩并且硬件加速了。

你应该保证你的背景音乐文件大小在800KB一下。最简单的方式就是减少背景音乐播放时间并且重复调用。

你应该保持你的音频文件样本率在96-128kbps之间,并且比特率在44kHz就足够了。

(3)字体和粒子系统优化

这里我们有两个建议:当使用BM字体显示游戏分数,在你的图片文件中选择最小的数字字符,例如:

如果你想只显示数字,你可以移除所有的字符。

粒子系统中,我们可以减少粒子数量来减少内存使用。

(4)语言代码

  无内存泄露的代码。

  lua 注意全局变量的使用 ,局部变量不要忘记 local

最后一些建议:

1、一帧帧的加载游戏资源。

2、减少绘制调用

3、按照最大到最小的顺序的加载纹理

4、避开内存使用高峰、

5、使用加载界面来预加载游戏资源。

6、当不需要的时候释放无用的资源

7、当有内存警告的时候释放缓存的资源

8、使用texturePacker来优化纹理尺寸,格式,色彩深度值等等。

9、小心使用JPG文件

10、使用16位RBGA4444色彩深度的纹理(看具体的机型,Android和IOS有点却别)

11、使用NPOT纹理代替POT纹理

12、避开加载大尺寸图片

13、使用1024*1024 NPOT pvr.ccz纹理图集而不是原生图片

有些的不对的地方和需要完善的地方,希望大神指教。

Cocos2d-LuaQuick-Cocos2d-x内存释放的更多相关文章

  1. CSS中实现动画效果-附案例

    这篇文章主要介绍了 CSS中实现动画效果并附上案例代码及实现效果,就是CSS动画样式处理,动画声明需要使用@keyframes name,后面的name是人为定义的动画名称,下面我们来看看文章的具体实现内容吧,需要的小伙伴可以参考一下

  2. ios – 围绕其中心点旋转UIImageView?

    我在UIImageView中有一个透明的png,我想围绕它的中心点旋转.代码应该非常简单:图像以正确的速度/时间和直角旋转,但其位置会发生偏移.这是一个正在发生的事情的例子:灰色方块只是为了在屏幕上显示位置.透明的png是另一个图.白色虚线显示UIImageView的中心.图像的左侧显示图像的原始位置,右侧显示使用上述代码旋转后的图像.黑色和白色圆圈位于图像文件的中心.有什么东西我不见了吗?

  3. ios – 将UIView的框架和角半径合在一起

    码:此代码是UIView的扩展.解决方法我像这样调整我的圈子视图:

  4. ios – 如何在Cocos2D 3.x中为CCSprite制作动画?

    你知道如何在新的Cocos2Dv3.x中动画CCSprite吗?许多类都被改变了,旧的方法似乎不起作用.任何的想法?谢谢.额外信息解决方法这是它的工作原理:

  5. ios5 – UIPageViewController转换速度/持续时间?

    有没有办法改变页面卷曲过渡的默认持续时间?这是快速的方式然后我希望它会是?谢谢沙尼解决方法Hy,这是使用默认转换来卷曲页面和指定卷曲速度的方法.祝你工作顺利.

  6. ios – 重用UICollectionView中的单元格时,会短暂显示重用的UICollectionViewCell的旧内容

    我正在使用UICollectionView来显示从URL异步加载的图片网格.我的集合视图使用可重用单元格来显示UICollectionViewCells.当不重复使用单元格时,所有内容都会正确显示,但是当我滚动一下时,重用的单元格会在它们开始正常行为之前短暂闪烁旧内容.以下是自定义UICollectionViewController的实现:这是自定义UICollectionViewCell的实现.

  7. 在iOS中移动UICollectionView的单元格?

    我有一个UICollectionView.I我试图给它作为SpringBoard的功能.我有能力给每个单元格摇动动画.但是我想当图标摇动时,我应该能够移动他们.为了摇动单元格,我已经在每个单元格上添加了UILongPressGesture.当手势结束时,我已经添加了一个自定义动画.还在左上角添加了一个删除按钮.长按手势代码:添加手势到集合视图回调方法单元格在inde路径项在这里工作正常为了移动单元

  8. iOS:CAShapeLayer绘制非直视图像并为其形状设置动画

    我一直在阅读有关CAShapeLayer的文档,但我仍然不太明白.根据我的理解,Layer始终是扁平的,其大小始终是矩形.另一方面,CAShapeLayer允许您定义不仅仅是矩形的图层.它可以是圆形,三角形等,只要您将它与UIBezierPaths一起使用即可.我的理解是在这里吗?

  9. ios – CGContextSaveGState:应用启动时的无效上下文0x0

    FWW我的应用程序大多是用Swift2.0编写的,在iOS9上使用Xcode7b6.解决方法我遇到同样的问题,其原因是,我正在为不同的屏幕设置不同的状态栏样式.因此,我需要在plist中添加“查看基于控制器的状态栏外观”键.如果我删除此键,警告消失.

  10. ios – 可以将视图放在彼此之上

    我正在构建一个Watch应用程序,其中我要覆盖WKInterfaceImage与一组WKInterfaceLabel对象.在StoryBoard编辑器中似乎无法做到这一点.有没有人能够为WatchApp设计出相互之间的观点?

随机推荐

  1. 【cocos2d-x 3.x 学习笔记】对象内存管理

    Cocos2d-x的内存管理cocos2d-x中使用的是上面的引用计数来管理内存,但是又增加了一些自己的特色。cocos2d-x中通过Ref类来实现引用计数,所有需要实现内存自动回收的类都应该继承自Ref类。下面是Ref类的定义:在cocos2d-x中创建对象通常有两种方式:这两中方式的差异可以参见我另一篇博文“对象创建方式讨论”。在cocos2d-x中提倡使用第二种方式,为了避免误用第一种方式,一般将构造函数设为protected或private。参考资料:[1]cocos2d-x高级开发教程2.3节[

  2. 利用cocos2dx 3.2开发消灭星星六如何在cocos2dx中显示中文

    由于编码的不同,在cocos2dx中的Label控件中如果放入中文字,往往会出现乱码。为了方便使用,我把这个从文档中获取中文字的方法放在一个头文件里面Chinese.h这里的tex_vec是cocos2dx提供的一个保存文档内容的一个容器。这里给出ChineseWords,xml的格式再看看ChineseWord的实现Chinese.cpp就这样,以后在需要用到中文字的地方,就先include这个头文件然后调用ChineseWord函数,获取一串中文字符串。

  3. 利用cocos2dx 3.2开发消灭星星七关于星星的算法

    在前面,我们已经在GameLayer中利用随机数初始化了一个StarMatrix,如果还不知道怎么创建星星矩阵请回去看看而且我们也讲了整个游戏的触摸事件的派发了。

  4. cocos2dx3.x 新手打包APK注意事项!

    这个在编译的时候就可以发现了比较好弄这只是我遇到的,其他的以后遇到再补充吧。。。以前被这两个问题坑了好久

  5. 利用cocos2dx 3.2开发消灭星星八游戏的结束判断与数据控制

    如果你看完之前的,那么你基本已经拥有一个消灭星星游戏的雏形。开始把剩下的两两互不相连的星星消去。那么如何判断是GameOver还是进入下一关呢。。其实游戏数据贯穿整个游戏,包括星星消除的时候要加到获得分数上,消去剩下两两不相连的星星的时候的加分政策等,因此如果前面没有做这一块的,最好回去搞一搞。

  6. 利用cocos2dx 3.2开发消灭星星九为游戏添加一些特效

    needClear是一个flag,当游戏判断不能再继续后,这个flag变为true,开始消除剩下的星星clearSumTime是一个累加器ONE_CLEAR_TIME就是每颗星星消除的时间2.连击加分信息一般消除一次星星都会有连击信息和加多少分的信息。其实这些combo标签就是一张图片,也是通过控制其属性或者runAction来实现。源码ComboEffect.hComboEffect.cpp4.消除星星粒子效果消除星星时,为了实现星星爆裂散落的效果,使用了cocos2d提供的粒子特效引擎对于粒子特效不了

  7. 02 Cocos2D-x引擎win7环境搭建及创建项目

    官网有搭建的文章,直接转载记录。环境搭建:本文介绍如何搭建Cocos2d-x3.2版本的开发环境。项目创建:一、通过命令创建项目前面搭建好环境后,怎样创建自己的Cocos2d-x项目呢?先来看看Cocos2d-x3.2的目录吧这就是Cocos2d-x3.2的目录。输入cocosnew项目名–p包名–lcpp–d路径回车就创建成功了例如:成功后,找到这个项目打开proj.win32目录下的Hello.slnF5成功了。

  8. 利用cocos2dx 3.2开发消灭星星十为游戏添加音效项目源码分享

    一个游戏,声音也是非常的重要,其实cocos2dx里面的简单音效引擎的使用是非常简单的。我这里只不过是用一个类对所有的音效进行管理罢了。Audio.hAudio.cpp好了,本系列教程到此结束,第一次写教程如有不对请见谅或指教,谢谢大家。最后附上整个项目的源代码点击打开链接

  9. 03 Helloworld

    程序都有一个入口点,在C++就是main函数了,打开main.cpp,代码如下:123456789101112131415161718#include"main.h"#include"AppDelegate.h"#include"cocos2d.h"USING_NS_CC;intAPIENTRY_tWinMain{UNREFERENCED_ParaMETER;UNREFERENCED_ParaMETER;//createtheapplicationinstanceAppDelegateapp;return

  10. MenuItemImage*图标菜单创建注意事项

    学习cocos2dx,看的是cocos2d-x3.x手游开发实例详解,这本书错误一大把,本着探索求知勇于发现错误改正错误的精神,我跟着书上的例子一起调试,当学习到场景切换这个小节的时候,出了个错误,卡了我好几个小时。

返回
顶部