quick cocos2dx lua 内存释放

前言

  对于内存的优化,网上有很多例子和教程。总体来说,就那么几种解决方案,在最后我会简单提下,这里先说下在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
    end

    if display.TEXTURES_PIXEL_FORMAT[image] then
        cc.Texture2D:setDefaultAlphaPixelFormat(display.TEXTURES_PIXEL_FORMAT[image])
        if async then
            sharedTextureCache:addImageAsync(image, asyncHandler)
        else
            sharedSpriteFrameCache:addSpriteFrames(plistFilename, image)
        end
        cc.Texture2D:setDefaultAlphaPixelFormat(cc.TEXTURE2D_PIXEL_FORMAT_RGBA8888)
    else
        if async then
            sharedTextureCache:addImageAsync(image, asyncHandler)
        else
            sharedSpriteFrameCache:addSpriteFrames(plistFilename, image)
        end
    end
end

-- start --

--------------------------------
-- 从内存中卸载 Sprite Sheets 材质和数据文件
-- @function [parent=#display] removeSpriteFramesWithFile
-- @param string plistFilename 数据文件名
-- @param string image 材质文件名

-- end --

function display.removeSpriteFramesWithFile(plistFilename, imageName)
    sharedSpriteFrameCache:removeSpriteFramesFromFile(plistFilename)
    if imageName then
        display.removeSpriteFrameByImageName(imageName)
    end
end

-- start --

--------------------------------
-- 设置材质格式。
-- @function [parent=#display] setTexturePixelFormat
-- @param string filename 材质文件名
-- @param integer format 材质格式
-- @see Texture Pixel Format

--[[--

设置材质格式。

为了节约内存,我们会使用一些颜色品质较低的材质格式,例如针对背景图使用 cc.TEXTURE2D_PIXEL_FORMAT_RGB565 格式。

display.setTexturePixelFormat() 可以指定材质文件的材质格式,这样在加载材质文件时就会使用指定的格式。

]]
-- end --

function display.setTexturePixelFormat(filename, format)
    display.TEXTURES_PIXEL_FORMAT[filename] = format
end

-- start --

--------------------------------
-- 从图像帧缓存中删除一个图像。
-- @function [parent=#display] removeSpriteFrameByImageName
-- @param string imageName 图像文件名

--[[--

从图像帧缓存中删除一个图像。

有时候,某些图像仅在特定场景中使用,例如背景图。那么在场景退出时,就可以用 display.removeSpriteFrameByImageName() 从缓存里删除不再使用的图像数据。

此外,Scene 提供了 markAutoCleanupImage() 接口,可以指定场景退出时需要自动清理的图像,推荐使用。

]]
-- end --

function display.removeSpriteFrameByImageName(imageName)
    sharedSpriteFrameCache:removeSpriteFrameByName(imageName)
    cc.Director:getInstance():getTextureCache():removeTextureForKey(imageName)
end

-- start --

--------------------------------
-- 从指定的图像文件创建并返回一个批量渲染对象。
-- @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

~~~

]]
-- end --

function display.newBatchNode(image, capacity)
    return cc.SpriteBatchNode:create(image, capacity or 100)
end

-- start --

--------------------------------
-- 创建并返回一个图像帧对象。
-- @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)

~~~

]]
-- end --

function display.newSpriteFrame(frameName)
    local frame = sharedSpriteFrameCache:getSpriteFrame(frameName)
    if not frame then
        printError("display.newSpriteFrame() - invalid frameName %s", tostring(frameName))
    end
    return frame
end

-- start --

--------------------------------
-- 以特定模式创建一个包含多个图像帧对象的数组。
-- @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", 1, 8, true)

~~~

]]
-- end --

function display.newFrames(pattern, begin, length, isReversed)
    local frames = {}
    local step = 1
    local last = begin + length - 1
    if isReversed then
        last, begin = begin, last
        step = -1
    end

    for index = begin, last, step do
        local frameName = string.format(pattern, index)
        local frame = sharedSpriteFrameCache:getSpriteFrame(frameName)
        if not frame then
            printError("display.newFrames() - invalid frame, name %s", tostring(frameName))
            return
        end

        frames[#frames + 1] = frame
    end
    return frames
end

-- start --

--------------------------------
-- 以包含图像帧的数组创建一个动画对象。
-- @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", 1, 8)
local animation = display.newAnimation(frames, 0.5 / 8) -- 0.5 秒播放 8 桢
sprite:playAnimationOnce(animation) -- 播放一次动画

~~~

]]
-- end --

function display.newAnimation(frames, time)
    local count = #frames
    -- local array = Array:create()
    -- for i = 1, count do
    --     array:addObject(frames[i])
    -- end
    time = time or 1.0 / count
    return cc.Animation:createWithSpriteFrames(frames, time)
end

-- start --

--------------------------------
-- 以指定名字缓存创建好的动画对象,以便后续反复使用。
-- @function [parent=#display] setAnimationCache
-- @param string name 名字
-- @param Animation animation 动画对象

--[[--

以指定名字缓存创建好的动画对象,以便后续反复使用。

~~~ lua

local frames = display.newFrames("Walk%04d.png", 1, 8)
local animation = display.newAnimation(frames, 0.5 / 8) -- 0.5 秒播放 8 桢
display.setAnimationCache("Walk", animation)

-- 在需要使用 Walk 动画的地方
sprite:playAnimationOnce(display.getAnimationCache("Walk")) -- 播放一次动画

~~~

]]
-- end --

function display.setAnimationCache(name, animation)
    sharedAnimationCache:addAnimation(animation, name)
end

-- start --

--------------------------------
-- 取得以指定名字缓存的动画对象,如果不存在则返回 nil。
-- @function [parent=#display] getAnimationCache
-- @param string name
-- @return Animation#Animation ret (return value: cc.Animation) 

-- end --

function display.getAnimationCache(name)
    return sharedAnimationCache:getAnimation(name)
end

-- start --

--------------------------------
-- 删除指定名字缓存的动画对象。
-- @function [parent=#display] removeAnimationCache
-- @param string name

-- end --

function display.removeAnimationCache(name)
    sharedAnimationCache:removeAnimation(name)
end

-- start --

--------------------------------
-- 从内存中卸载没有使用 Sprite Sheets 材质
-- @function [parent=#display] removeUnusedSpriteFrames

-- end --

function display.removeUnusedSpriteFrames()
    sharedSpriteFrameCache:removeUnusedSpriteFrames()
    sharedTextureCache:removeUnusedTextures()
end

-- start --

--------------------------------
-- 创建一个进度条的节点
-- @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纹理图集而不是原生图片

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

本文地址:http://www.cnblogs.com/zhangfeitao/p/4562791.html

时间: 2024-10-19 05:19:33

quick cocos2dx lua 内存释放的相关文章

quick cocos2dx lua 网络图片 下载 自己主动更新

转载请注明,原文地址:http://blog.csdn.net/dd135373/article/details/46468505 quick coocs2d-x 网络图片下载,自己主动更新纹理,保存url的md5作为标记.假设本地存在,直接读取本地. NetSprite.new(url):addTo(self):align(display.CENTER,0,0) 版权声明:本文博主原创文章,博客,未经同意不得转载.

quick Cocos2dx lua 接anysdk

quick3.3 的quick\samples\anysdk中有例子,具体用法可以参考官方文档,将的非常详细. 1.框架接口设计 系统介绍 必接入流程简要描述 消息通知 可扩展性 测试模式 添加测试账号 在dev.anysdk.com后台添加测试账号,并且添加相应的测试币. 使用测试账号 生成的测试账号,可用来完成接入AnySDK Framework的登陆.登出.支付功能 其他接口 其他接口AnySDK Framework也提供了简易的界面或者Log 告知接口调用成功 2.anysdk-Lua用

quick cocos2dx 游戏引擎lua调用oc代码实现本地推送

我在博客标题为“ios如何实现本地推送,兼容ios8“http://www.cnblogs.com/laoguigame/p/4522474.html的博文中介绍了通过oc代码实现本地推送的方法.现在介绍在lua中调用咱们之前写的oc方法接口来实现在lua层实现推送的功能,主要基于quick cocos2dx V3.3版本的引擎来实现.在quick中的luaoc.lua文件中实现了luaoc.callStaticMethod(className, methodName, args)接口,可以看出

cocos2dx 之内存管理

 cocos2dx的内存管理移植自Objective-C, 对于没有接触过OC的C++开发人员来说是挺迷惑的.不深入理解内存管理是无法写出好的C++程序的,我用OC和cocos2dx也有一段时间了,在此总结一下,希望对想用cocos2dx开发游戏的朋友有所帮助. C++的动态内存管理一般建议遵循谁申请谁释放的原则,即谁通过new操作符创建了对象,谁就负责通过delete来释放对象.如果对象的生命周期在一个函数内,这很容易做到,在函数返回前delete就行了.但一般我们在函数中new出来的对象

Mac下搭建quick cocos2d-x编译环境

前言 虽然之前已经写过了很多 Cocos2d-x 相关的教程和文档,但本次却是我第一次接触 Quick,第一次接触 Lua,所以此次的教程本人将站在一个初学者的角度(看到这里是不是想白眼我了,哈哈,别切啊!尽管第一次,但我身边可是有很多 Quick 大神的,廖大大也在旁边办公室,没准撒个娇大神就把他知道的全部要点倾囊相授了啦!),全方位的解析 Quick 的学习过程,并同大家一起学习如何利用 Quick-Cocos2d-x 开发一款属于自己的游戏,包教包会的哦. 好了,那么下面我们就开始进入正题

第一个Cocos2d-x Lua游戏

我们的编写的第一个Cocos2d-x Lua程序,命名为HelloLua,从该工程开始学习其它的内容.创建工程我们创建Cocos2d-x Lua工程可以通过Cocos2d-x提供的命令工具cocos实现,但这种方式不能与Cocos Code IDE集成开发工具很好地集成,不便于程序编写和调试.由于Cocos Code IDE工具是Cocos2d-x开发的专门为Cocos2d-JS和Cocos2d-x Lua开发设计的,因此使用Cocos Code IDE工具很方便创建Cocos2d-x Lua工

Quick Cocos2dx 调试问题

最近由于忙了一段时间,忙完了之后又迷茫了这么久,然后终于开始继续Quick-x的学习之路了. 然后遇到了一个比较棘手的问题. 虽然照着官方mvc的例子敲代码,但是还是不停的报错,报错的问题下次集结成一个帖子发出来好了. 今次记录的是对于错误的DEUG方面的问题. 我的首选当然是Eclipse + LDT了,因为从业是自java而始,继而是AS,用得最熟的莫过与FB了. 参考的是官方的文章: 用 Eclipse LDT 调试 quick-cocos2d-x 游戏 但是,进行到配置player的时候

Cocos2dx+lua合适还是Cocos2dx+js合适?

问题: 开发cocos2dx手游Cocos2dx+lua合适还是Cocos2dx+js合适 百牛信息技术bainiu.ltd整理发布于博客园 回答: 作者:廖宇雷链接:https://www.zhihu.com/question/21130385/answer/18485625来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 2014.02更新:请放心选择 Lua 吧.触控已经收购了 quick-cocos2d-x,2014年肯定会大力强化 cocos2d-x 的

quick cocos2dx 3.x 配置win32工程

公司项目主体部分用c++,而ui部分用lua写,所以选择了用quick框架.项目先开发了ios/mac版,这两天试着配置其win32工程,遇到一些问题,记录一下(纯c++版本cocos2dx配置方法应该也是类似的). 先配debug模式: 把c++文件都添到工程中去,并在附加包含目录下配置c++文件的搜索路径.然后编译会遇到一些问题: 一,win32下fullPathForFilename函数与ios/mac下行为不一致的问题. fullPathForFilename当传入的参数是文件夹路径时,