Lua游戏逻辑开发中的优化思路

来源:互联网 发布:广州淘宝服装加工厂 编辑:程序博客网 时间:2024/06/04 17:59

本篇中,我们主要讲到一些Lua游戏逻辑开发中的优化思路,以及我们项目中的一部分应用。
开始之前,我们先说个题外话。编者认为,对于个人而言,程序高效可能会高于维护性。但对于团队合作来说,往往易懂、易维护、易扩展,稳定是基本要求,再去追求极致。
这里的高效都是相对的,作为一名程序员来说,我觉得高效应该是一种习惯和追求。


扯了一下,回归正题,这节里我们先从7个点来介绍。

1. 接口统一、抽象化
避免代码过多的Ctrl+C、Ctrl+V,把通用部分抽象化或者统一管理,让代码易读性更强,维护起来也更加方便。

大家看下一下这段代码。

    if vo.cd_time == 0 then        self.cdTimeTxt:setVisible(false)        UITools.loadTexturesFromPilst(self.upBtn, "ui/commonUI/btnBG10.png", "ui/commonUI/commonUI")        self.tipsTxt:setVisible(false)        if vo.goods_num >= vo.cost_coin then            self:setButtonEffect(true)        else            self:setButtonEffect(false)        end        if vo.is_tupo == 1 then            self.panel1:setVisible(false)            self.panel2:setVisible(true)            self.istopo = true            self.upBtn:setTitleText(AwakeWords[3])            self.light = ActionTimeLineUtils.getAnimate(resPth3, "action", nil, true)            local x1,y1 = self.Image_2:getPosition()            self.light:setPosition(x1,y1)            self.light:setScale(2)            self.root:addChild(self.light)        else            removeLight()            self.istopo = false            self.panel1:setVisible(true)            self.panel2:setVisible(false)            self.upBtn:setTitleText(AwakeWords[4])            local roleLv = RoleController:getInstance().model.mainRoleVo.lv            local roleVip = RoleController:getInstance().model.mainRoleVo.vip            if vo.need_lv > roleLv then                self.suoImg:setVisible(true)                self.lvTxt:setVisible(true)                self.autoTxt:setVisible(false)                self.checkBox:setVisible(false)                self.lvTxt:setString(string.format(AwakeWords[18],vo.need_lv))            elseif vo.need_vip > roleVip then                self.suoImg:setVisible(true)                self.lvTxt:setVisible(true)                self.autoTxt:setVisible(false)                self.checkBox:setVisible(false)                self.lvTxt:setString(string.format(AwakeWords[22],vo.need_vip))            else                self.autoTxt:setVisible(true)                self.checkBox:setVisible(true)                self.suoImg:setVisible(false)                self.lvTxt:setVisible(false)            end            if vo.leave_times > 0 then                self.qipao:setVisible(true)                self.vip:setSpriteFrame(UITools.getSpriteFrameFromPlist(string.format("ui/commonUIip/V%s.png",vo.vip_lv)))                self.banjiaNum:setString(string.format(AwakeWords[19],vo.leave_times,vo.max_times))            else                self.qipao:setVisible(false)            end        end    else        self:setButtonEffect(false)        UITools.loadTexturesFromPilst(self.upBtn, "ui/commonUI/btnGray1.png", "ui/commonUI/commonUI")        self.tipsTxt:setVisible(true)        self.panel1:setVisible(false)        self.panel2:setVisible(false)        self.cdTimeTxt:setVisible(true)        self.upBtn:setTitleText("")        self:showDownTime(vo.cd_time)    end

看完这段代码,心里只有一个字:累!
代码质量不高,维护也容易遗漏,并且在同个UI中,多处存在这种代码,这种情形大家就要注意统一下接口。

2. 模块解耦
1)在常用的游戏框架里常用MVC来使业务逻辑、数据、界面显示分离。
2)在模块中,我们常用的设计模式就是观察者,通常都会使用事件机制来降低耦合性。
3)去除相关依赖,在数据缺失的情况下界面并不会报错卡住。

3. 异步加载、分帧加载
对于大贴图以及一些解析慢的文件,尽量不要在主线程加载,采用异步加载来保证游戏的流畅性。
而分帧加载我们经常用在一些节点个数非常多的界面里,例如背包界面,通常都会策略加载或者分帧加载来确保打开时跳帧;还有MMO中的场景元素,也经常会通过分帧处理,降低单帧内创建压力。

4. 空间、时间的平衡
空间复杂度,时间复杂度通常调优就是内存与CPU占用的平衡(这里不排出两种都可以调到极致)。
在for循环使用过程中,要注意嵌套多深,n有多大,可以适当牺牲一些空间,设计出效率更优的解决方案。有时Hash表的运用也可以大程度的降低遍历的时间复杂度。

5. 缓存的应用
创建、释放频繁的对象,我们在游戏中往往也会通过一些缓存机制来处理,提高加载速度,同时也降低内存申请释放的次数,减少一些内存碎片。
举个简单的例子,对于一些通用的游戏UI贴图,我们就可以采用缓存来保证每次用到时无需加载,当然也得把握好当前内存,内存峰值。

6. table的消耗
在我们游戏中经常会用到table.insert/ table.remove,一般都不会有什么问题,但是当表里元素非常多的时候,从中间插入和移除就会有一定的性能损耗,遇到类似情况可考虑一些优化方案(第7中也是一种替代方案)。

7. 双链表
下面分享一下我们项目中常用的双链表,相信很多人的项目也都有用到。

list = {}function list.new(num)    if not num then        return {first = 0, last = -1}    else        return {first = num, last = num - 1}    endendfunction list.size(list)    if list.first > list.last then        return 0    else        return list.last + 1 - list.first    endendfunction list.empty(list)    return list.first > list.lastendfunction list.get(list, index)    local index = list.first + index    return list[index]  endfunction list.pushFront(list, value)    local first = list.first - 1    list.first = first    list[first] = valueendfunction list.pushBack(list, value)    local last = list.last + 1    list.last = last    list[last] = valueendfunction list.popFront(list)    local first = list.first    if first > list.last then error("list is empty") end    local value = list[first]    list[first] = nil       -- to allow garbage collection    list.first = first + 1    return valueendfunction list.popBack(list)    local last = list.last    if list.first > last then error("list is empty") end    local value = list[last]    list[last] = nil        -- to allow garbage collection    list.last = last - 1    return valueend

最后在分享两个Lua源码中的技巧。

1.使用readonly表,保证一些数据不会被串改

 setmetatable(g,{__index=G,__newindex=f})

2.Lua中next关键字,通过next来清空table

--遍历表元素while true do    local k = next(t)    if not k then break end    t[k] = nilend--判断(任意)表是否为空if next(t) == nil then     -- 表为空    -- ...end

东西太多,未完待续- -~

1 0
原创粉丝点击