我的Lua笔记(总结的坑)

3 篇文章 0 订阅

6.lua 数组是从1开始,这也是许多习惯吃第0碗饭的童鞋,感到不自在,有一种情况还是比较苦恼,比如:

t[0] = 1 t[1] = 2 print(#t) 长度为多少,动手试试

答案:1

LUA编程建议:

1 引用管理

1.1基本原则

C/C++内管管理的一个基本原则是,"谁分配,谁释放"。虽然C#和Lua语言本身都是基于引用的自动垃圾回收,这一原则对于引用的管理、资源的申请和释放同样适用。
正确管理引用的关键就是要满足"谁分配,谁释放"、"有分配,就有释放",做到以下几个方面在一个模块中(ViewComponet、MonoBehavior、LuaComponetContainer、自己写的功能模块等)成对出现:

    1. 通知的监听与反监听
    2. 资源Resource的Retain()与Release
    3. 定时器的注册于反注册
    4. UI事件的监听与反监听

1.2 ViewComponent

aounity框架中ViewComponet指明了对于UI系统这些逻辑应该写在什么地方,以方便清晰的管理引用以及检查。

    • buildUI

在界面构建时执行。
这个函数里主要获取UI组件引用。

    • destroyUI

在界面销毁时执行。
与buildUI中一一对应取消UI组件引用。

    • bindEvents

在界面构建时执行。
在这个函数里面可以:
1) 监听一些界面显示、不显示时都需要监听的通知
2) 监听界面中UI组件的点击等事件

    • unbindEvents

在界面销毁时执行。
此函数中应当与bindEvents中一一对应反注册监听。

    • onEnter/onEnterFinished

在界面打开时执行。
在此函数中可以:
1)执行界面打开的一些逻辑处理
2)监听界面显示时才需要监听的通知
3)注册定时函数

    • onExit/onExitFinished

在界面关闭时执行。
在此函数中应当与onEnter/onEnterFinished中一一对应反注册监听。

1.3 UI界面

UI界面占用的内存主要是:

    • 对象本身占用的堆内存,很小
    • 引用的本界面特有图集
    • 引用的公共图集
    • 大的背景图

UI界面引用的公共图集常驻内存不用考虑释放,用到的大的背景图采用动态加载的方式,在界面打开时加载,在界面关闭时释放。 
下面主要讨论下UI界面对象以及特有图集的释放。这两方面的内存如果要释放,销毁UI界面对象,再执行一次堆内存和Unity资源的垃圾回收即可。对于UI系统开发者来说只需要配置:setting_view.lua中的对应界面的autoDestroyTime字段。 
autoDestroyTime表示界面关闭后,多久自动销毁,每次重新打开会重置倒计时,界面打开中间不会发生销毁。

    • 不配置或者配置0,表示常驻内存,不析构。
    • 配置成负数,界面关闭后,立即销毁。
    • 配置成正数,界面关闭后,对应时间的倒计时结束后销毁。


常用界面
       对于常用界面(主界面上的一级按钮入口进入的、经常使用的等)可以不用配置销毁UI界面对象。只需要界面关闭时,清除动态加载的资源。
非常用界面
       对于非常用界面,根据使用频率进行配置。

执行堆内存和Unity资源的垃圾回收时,需要注意UI界面配置的关闭后一定时间内销毁的销毁延时性。

1.4 GameObject

创建UnityEngine.Object子类的对象,销毁时一定要:
        UnityEngine.GameObject.Destroy(o);o=nil 
注意GameObject.Destroy并不是代码调用之后立即销毁对象的。真正销毁的执行时机,是在所有Update执行之后,绘制之前。因此挂在gameobject上的脚本对属性的引用、OnDetroy中释放的引用,也都不是立即执行的。如果想在销毁GameObject之后,想手动调用GC函数,应该做个延迟。

1.5 MonoBehavior

Lua组件
Aounity框架中提供了LuaComponentContainer来将lua代码绑定在gameobject上,实现像Monobehavior一样的功能。 
当不需要此组件的时候,调用Remove 方法移除。更多的情况下,是不需要移除组件的,而是整个gameobject都需要销毁。LuaComponentContainer 中OnDestroy 中已经有清理添加到gameobject上的lua组件。因此只需要按销毁gameobject的方法销毁gameobject即可,不用再移除组件了。 
C#组件 
经常会需要继承MonoBehavior类,给Lua层提供注册、反注册回调,处理UI组件事件等。
会出问题的一个方面是,在lua中只注册了回调,忘记了反注册。首先写代码时要按照引用管理的基本原则来做到"有注册就要有反注册"外,可以在OnDestroy中做一次最后的清理。 
OnDetroy 
C#组件以及Lua组件,本身的OnDetroy方法都多提供了一个当gameobject销毁时,额外清理自己引用的外部资源的方法,建议每个组件都覆写此方法,以多一层防护。

2 Lua与C#交互

  • 缓存常访问的C#对象的属性

   go.transform => self._trs = go.transform

  • 尽量只传最基本类型的参数如int、float、double,尽量不要传递bool、string、System.Object。

   Chapter 7 - Improving Interop Performance | Microsoft Docs

  • 函数类型是C# 结构体时,尽量使用结构体成员作为参数传递,C#函数中缓存结构体。

  self._trs.position = pos => TransformUtil.SetPos(self._trs,x,y,z)
  TransformUtil.cs: private static Vector3 tempVec3;

  • 函数返回值是C#结构体时,使用多个out参数返回结构体成员。

   public static void GetPos(this Transform trs,out float x,out float y,out float z) 
   TransformUtil.GetPos(self._trs,0,0,0)

  • 实用方法尽量实现成静态类的静态方法
  • 对象池缓存可复用的C#对象,避免频繁创建销毁
  • 创建UnityEngine.Object子类的对象,销毁时一定要UnityEngine.GameObject.Destroy(o)以及o=nil。
  • 尽量减少Lua与C#的交互,如果一段lua代码,多行都会与C#交互,采用这段逻辑用C#封装成一个函数整体给lua调用。

3 Lua编程Tips

  • 尽量不要创建内部匿名function。外部函数多次调用时频繁的创建和释放funciton和upvalue。
  • 字符串连接会产生新的拷贝,避免在循环内不断的连接字符串。
  • 避免lua函数参数是表类型时,每次函数调用都构造一个table对象。注意不定参数被调用时,如果有不定参数在,每次都会定义一个table存放不定参数。

setWayPoint({x,y}) => setWayPoint(x,y)
foo(a,…)

  • 注意Lua逻辑运算中的短路效应。我们经常用 a = a or "default",但如果缺省值是true时,a = a or true会将false也会变成true。
  • 对于容量固定的table数组,可以在创建时就指定大小。

        local t = {nil,nil,nil}

  • Table遍历过程中,可以将key赋为nil,但不要插入新的key。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kerven_HKW

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值