经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 游戏设计 » 查看文章
Unity3D开发入门教程(二)—— Lua入门
来源:cnblogs  作者:五邑隐侠  时间:2022/1/17 10:46:33  对本文有异议

五邑隐侠,本名关健昌,12年游戏生涯。 本教程以 Unity 3D + VS Code + C# + tolua 为例。

 

如果你还没有编程基础,建议你先学习一些编程基础。本文不是完全菜鸟教程,主要针对有其他语言经验的开发者,如果想看菜鸟教程,建议看菜鸟教程的 Lua教程

先看一个简单类的代码

  1. 1 ---@class BsnsPack @Base class of business pack
  2. 2 local BsnsPack = {
  3. 3 -- class fields
  4. 4 maxSerialNo = 0,
  5. 5 }
  6. 6
  7. 7 BsnsPack.__index = BsnsPack
  8. 8
  9. 9 --- new()
  10. 10 ---@return BsnsPack
  11. 11 function BsnsPack.new()
  12. 12 local o = {}
  13. 13
  14. 14 -- member fields
  15. 15 o.serialNo = 0
  16. 16 o.mod = 0
  17. 17 o.cmd = 0
  18. 18 o.payload = nil
  19. 19
  20. 20 -- bind BsnsPack methods
  21. 21 setmetatable(o, BsnsPack)
  22. 22 return o
  23. 23 end
  24. 24
  25. 25 --- set serial No.
  26. 26 ---@param serialNo number
  27. 27 function BsnsPack:setSerialNo(serialNo)
  28. 28 self.serialNo = serialNo
  29. 29 end
  30. 30
  31. 31 --- get serial No.
  32. 32 ---@return number
  33. 33 function BsnsPack:getSerialNo()
  34. 34 return self.serialNo
  35. 35 end
  36. 36
  37. 37 --- set mod
  38. 38 ---@param mod number
  39. 39 function BsnsPack:setMod(mod)
  40. 40 self.mod = mod
  41. 41 end
  42. 42
  43. 43 --- get mod
  44. 44 ---@return number
  45. 45 function BsnsPack:getMod()
  46. 46 return self.mod
  47. 47 end
  48. 48
  49. 49 --- set cmd
  50. 50 ---@param cmd number
  51. 51 function BsnsPack:setCmd(cmd)
  52. 52 self.cmd = cmd
  53. 53 end
  54. 54
  55. 55 --- get cmd
  56. 56 ---@return number
  57. 57 function BsnsPack:getCmd()
  58. 58 return self.cmd
  59. 59 end
  60. 60
  61. 61 --- set payload
  62. 62 ---@param payload any
  63. 63 function BsnsPack:setPayload(payload)
  64. 64 self.payload = payload
  65. 65 end
  66. 66
  67. 67 --- get payload
  68. 68 ---@return any
  69. 69 function BsnsPack:getPayload()
  70. 70 return self.payload
  71. 71 end
  72. 72
  73. 73 function BsnsPack.test()
  74. 74 print(BsnsPack.serialNo)
  75. 75 end
  76. 76
  77. 77 --- testPrivate
  78. 78 ---@param self BsnsPack
  79. 79 local function testPrivate(self)
  80. 80 print(self.serialNo)
  81. 81 end
  82. 82
  83. 83 ---@alias Request BsnsPack @Request is BsnsPack
  84. 84 local Request = BsnsPack
  85. 85
  86. 86 ---@class Response : BsnsPack @Response class
  87. 87 local Response = {}
  88. 88 setmetatable(Response, BsnsPack) -- bind super methods
  89. 89 Response.__index = Response
  90. 90
  91. 91 --- new()
  92. 92 ---@return Response
  93. 93 function Response.new()
  94. 94 local o = BsnsPack.new()
  95. 95
  96. 96 -- member fields
  97. 97 o.code = 0
  98. 98
  99. 99 setmetatable(o, nil) -- remove original metatable
  100. 100 setmetatable(o, Response) -- bind Response methods
  101. 101 return o
  102. 102 end
  103. 103
  104. 104 --- get result code
  105. 105 ---@return number
  106. 106 function Response:getCode()
  107. 107 return self.code
  108. 108 end
  109. 109
  110. 110 local bsnsPack = {}
  111. 111 bsnsPack.BsnsPack = BsnsPack
  112. 112 bsnsPack.Request = Request
  113. 113 bsnsPack.Response = Response
  114. 114
  115. 115 return bsnsPack

 

 

1、第1行:这是一行注释

Lua的行注释以两个减号 -- 开头,

class注解:---@class TYPE[: PARENT_TYPE {, PARENT_TYPE}]  [@comment]

这样有利于 VS Code 代码提示,例如将鼠标放到代码中出现 BsnsPack 的地方上,会有小弹窗提示这个table的key,以及key的类型。

用得比较多的注解有 ---@class,---@return,---@param

 

2、第2行,定义一个叫 BsnsPack 的class(通过table模拟)。

Lua里没有类,Lua的结构化数据类型叫table,基于key-value结构。相对于其他语言的 map / dictionary。访问一个table的key对应的值,可以用点 . 来访问,也可以用中括号[]来访问

Lua里没有单独的数组结构,也是基于table,数组下标是key,数组元素是value,要注意的是,Lua里数组下标是从1开始的。

创建table的最简单方式就是花括号 {},创建一个空table。

Lua是脚本语言,变量不需要指定类型,只需要给它赋值。所以 BsnsPack = {maxSerialNo = 0,} 相当于定义了个变量 BsnsPack,它的值是一个table。

Lua的变量默认是全局的,加载到内存的Lua代码都可以访问这个变量。为了避免命名冲突和意外修改,一般建议变量定义为局部变量,限制它的作用域。在变量前面加个 local定义局部变量。

这里定义的 BsnsPack ,作用域只在这个文件里。其他文件不能访问。也可以在函数、代码块里用 local 定义局部变量。

 

3、第7行,给 BsnsPack一个叫 __index 的 key 赋值为 BsnsPack 自己

Lua 的 table 里,__index 是个特殊的key,这是 Lua实现类和继承的关键。
Lua里有个概念叫做元表。Lua定义了一些语言默认key,这些key一般跟 +、-、*、/等操作符、key的访问、值更新关联,这些key叫做元方法(Lua里的函数/方法也可以作为值),这些元方法合起来叫元表。

Lua里设置元表的方法是代码第 21 行的 function setmetatable(t, metatable),调用这个方法会让参数 metatable 成为 参数 t 的元表。

设置元表后,在代码里访问参数 t 的一个key时会发生以下情况:

1)Lua先在 t 里找,看有没有这个key,如果有,就返回这个key的值。否则,执行2)

2)Lua看参数 metatable 有没有 __index 这个key,如果有,就在 __index 对应的值里查找(__index的值如果是表,在这个表里查找;如果是函数,执行这个函数)

BsnsPack.__index = BsnsPack,如果其他的table设置 BsnsPack 为元表,就可以访问 BsnsPack 所有的key。 这些key的值如果是方法,就可以调用这些方法。
所以 BsnsPack 可以定义方法的模板,这就跟class类似。BsnsPack定义的数据key,相当于静态字段class field。BsnsPack定义的方法key,可以是成员方法member method,也可以是class method,后面介绍
 

4、第11~23行,定义BsnsPack的一个叫new的key,它的值是一个方法

Lua里一个代码块不用花括号{},通过end作为结束标记。

定义方法用 function 开头,用点.或者冒号:分割talbe名和方法名,

用冒号:定义的方法,会有个默认参数self,相当于调用者,如果外部用 BsnsPack:new() 这样调用,则self == BsnsPack,如果用a:new()这样调用,self==a。

用点.定义的方法,没有默认参数,只能显式写参数self。

一般地,用冒号:定义成员方法member method(例如第23行的 function BsnsPack:setSerialNo(serialNo) )

1)调用 o:setSerialNo(serialNo) 时,这里的self是对象o,只改对象o的serialNo,其他对象的serialNo不受影响。

用点.定义构造对象的方法(例如第11行的 function BsnsPack.new()),以及静态方法class method(例如第69行的 function BsnsPack.test() )

1)在其他地方通过 BsnsPack.new()构造BsnsPack对象

1)在其他地方通过 BsnsPack.test()调用类方法

建议,方法定义的时候是冒号:,调用的时候用冒号:,定义的时候是点.,调用的时候也用点.

构造方法不一定叫new,只是为了统一,建议都用new,与其他语言一致。

方法new里面的 local o = {},定义的key都是成员字段member field(每次调用方法 BsnsPack.new() 都创建一个新的 table并对其字段初始化后返回)

Lua没有私有的成员方法,可以定义文件的 local 方法,把对象作为参数self显式的传进去(例如第79行 local function testPrivate(self)

 

5、第84行,给类BsnsPack定义一个别名 Request,其实就是把一个table赋值给另外一个变量

 

6、第87~102行,定义一个类Response,继承基类BsnsPack

第87行,定义子类Response

第88行,设置元表,使得Response可以访问BsnsPack所有的key(继承BsnsPack所有的方法)

第89行,所有对象可以访问Response所有的key(通过递归,包括BsnsPack所有的key)

第94行,通过调用BsnsPack构造方法初始化o,o是BsnsPack的对象,拥有基类所有的member field

第97行,定义Response相对于基类新增的字段code

第99、100行,修改o的元表为Response,这样o可以访问Response所有的成员方法 member method(通过递归,包括BsnsPack所有的成员方法)

Response可以重写BsnsPack的方法

  1. 1 function Response:getPayload()
  2. 2 return self.payload
  3. 3 end

由于Lua里访问key,先在table本身查找,如果没有才在元表查找,所以会调用重写的方法,实现多态。

 

7、第110~115行,导出本文件定义的类。

由于class的定义都是以 local 方式定义的局部变量,外部不能访问,所以要把它当作文件的返回值 return

如果该文件只导出一个class,直接return这个局部变量就可以,(例如,如果只导出BsnsPack,return BsnsPack 就可以)

由于本文件需要导出3个class,这里把他们放到一个table里导出

其他文件需要访问这个文件的class,需要调用require方法导入进来,该方法的参数是路径(不含后缀.lua),返回值是这个lua文件的return值

  1. 1 local bsnsPack = require("Assets.Lua.bsns.bsns_pack")
  2. 2 local Request = bsnsPack.Request
  3. 3 local Response = bsnsPack.Response

 

8、如果想模块化管理,把一个模块所有的类通过一个文件暴露给其他模块,可以在这个文件定义一个局部变量,把这个模块所有的文件的类,都通过require导入进来,并赋值给跟类同名的key,最后返回这个局部变量

文件bsns.lua

  1. 1 local bsns = {}
  2. 2
  3. 3 local bsnsPack = require("Assets.Lua.bsns.bsns_pack")
  4. 4 bsns.Request = bsnsPack.Request
  5. 5 bsns.Response = bsnsPack.Response
  6. 6
  7. 7 bsns.BsnsMod = require("Assets.Lua.bsns.bsns_mod")
  8. 8 bsns.BsnsCenter = require("Assets.Lua.bsns.bsns_center")
  9. 9
  10. 10 return bsns

 

5、简单语法介绍

1)Lua里的语句不需要分号;结尾

2)Lua常用的基本数据类型有nil、boolean、number、string、function、table

3)获取数组长度用 #数组变量,例如

  1. 1 local array = {"Lua", "Tutorial"}
  2. 2 local len = #array
  3. 3 print(len)

4)遍历数组用 

  1. 1 for i, v in ipairs(table) do
  2. 2
  3. 3 end

5)遍历对象用

  1. 1 for k, v in pairs(obj) do
  2. 2
  3. 3 end

6)其他语法请查阅菜鸟教程

 

6、Lua代码规范可参考 https://lua.ren/topic/172/

 

原文链接:http://www.cnblogs.com/niudanshui/p/15774984.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号