Unity3d热更新之Lua热更新

Unity3d热更新之Lua热更新
黄雨涵此文章部分内容和思维导图来源于唐老狮相关Lua课程,通过Vistual Studio Code语法测试,如有问题,请在以下留言
由于全部为本工作室二级网站–学习格整理而成,故本网站对本文章拥有相关创作权,因此在搬运或者转载二次改变前请与本人联系,禁止一切未经允许的搬运行为,若出现或发现侵权行为,本人有权对相关侵权行为进行举报,维护本人和合法权益。
因本人知识储备有限,可能存在错误,如有错误,可在评论处进行评论(评论回复将通过qq邮箱进行回复),一起探讨进步
Sublime Text
Visual Studio Code(安装lua)
Typora
一.Lua相关注释
这里需要注意的是在C#中单行注释是使用”//“,多行注释是”/%内容%/“,在lua中的单行注释和多行注释相关格式如下图
1 | --单行注释 |
1 | --[[ |
二.数据类型
写在最前面
在lua中
无需定义数据 的类型,在使用中会自动识别lua当中的基本数据类型:
(1)nil(类似于c#中null)
(2)number(所有的数值都是number==>number包括int float double)
(3)string (lua中没有char,字符串的声明使用单引号或者双引号包裹)
(4)boolean(返回的是true或false)
lua当中的复杂数据类型:
(1)函数(function)
(2)表(table)【表需要特别学习,特别的重要】
(3)数据结构(userdata)
(4)协同程序(thread(线程))
lua中带
所有的变量申明,都不需要申明变量类型 ,同理可以随便赋值,可以自动判断类型==>类似c#中的varlua中使用
没有声明过的变量并不会报错,默认返回的是nil lua
默认是没有 面向对象的 ,需要自己实现 在lua中的”数组”
起始位置与c#不同,从1开始 ;当对变量多赋值时,会将后面多赋的值自动省略 ;当对变量少赋值时,会将后面不够的值直接自动赋为空值 多返回值时,用几个变量接就会有多少个值 如果
变量数大于方法返回的值数量,则会进行补空处理 如果
变量数小于方法返回的值数量,则会根据变量数量进行接取
1.基本数据类型
nil的使用
1 | a=nil --定义a这个变量的值为nil |
number(数值类型)
- 这里需要注意一点:在上面赋过值得变量,可以重复使用,在下面依然可以重新赋值,也同样会根据相关赋值的类型转化为相对应的类型
1 | a=1 b=1.25 |
string(字符串类型)
在lua中是没有字符的,在定义字符串时可以使用以下三种方式:
(1)单引号 ‘SeveneStudio’
(2)双引号 “SeveneStudio”
(3)中括号 [[SeveneStudio]]
1 | a="SeveneStudio_Logo" |
boolean(Boolean类型)
- 在lua中只有true和false代表真与假,这个与c#有着区别
1 | a=true |
2.type()的使用和字符串扩展
type() 获取变量类型
- 通过type()可以获取变量类型==>返回值是变量的数据类型,属于string类型
1 | a=123 |
3.字符串的相关使用
第一小节
相关方法:print(#变量名)
注意点 |
---|
1.一个汉字占3个长度 |
2.英文字符占1个长度 |
1 | s="aBcDEfG字符串" |
说明:字符串的换行/字符串多行打印在lua中是与c#一样,是支持转义字符的
相关格式:可以使用\n或者[[字符串]]
1 | print("123\n123") |
相关格式:
(1)在lua中字符串的拼接通过..实现,字符串..字符串
1 | print("HaXinXi".."XueYuan") -- HaXinXiXueYuan |
(2)string.format()
注意点 |
---|
%d 与数字进行拼接 |
%a 与任何字符拼接 |
%s 与字符配对 |
1 | print(string.format("我是哈信息%d级学生",18)) --我是哈信息18级学生 |
格式:string.upper(字符串)
注意点 |
---|
string.upper(argument): 字符串全部转为大写字母, |
**string.lower(argument):**字符串全部转为小写字母 |
1 | s="SeveneStudio" |
第二小节
格式:string.reverse(arg)了解即可,用途不是很大
1 | print(string.reverse(s)) --oidutSeneveS |
格式:string.find (str, substr, [init, [plain]])
init 指定了搜索的起始位置,默认为 1,可以一个负数,表示从后往前数的字符个数。
plain 表示是否以正则表达式匹配。
注意点 |
---|
(1)lua的起始位置与c#不同,从1开始; |
(2)string.find ()会返回起始位置和结束位置 |
1 | s="SeveneStudio" |
格式:string.sub(s, i [, j])
s:要截取的字符串;
i:截取开始位置;
j:截取结束位置,默认为 -1,最后一个字符。
1 | string.sub(s, i [, j]) |
格式:string.rep(string, n)
注意点 |
---|
返回字符串String的n个拷贝,即将字符串复制n个返回 |
1 | s="SeveneStudio" |
第三小节
格式:string.gsub(mainString,findString,replaceString,num)
mainString 为要操作的字符串;
replaceString 要替换的字符;
findString 为被替换的字符;
num 替换次数(可以忽略,则全部替换);
这里会返回两个:1.替换后的字符串,2.替换次数
1 | s="SeveneStudio" |
格式:字符转ASCII码:string.byte(string,int)
ASCII码转字符:string.char(int)
注意点 |
---|
string.byte(string,int) 字符转ASCII码 ==>string是指字符串,int是需要转换的位置 |
string.char(int) ASCII码转字符==>int指需要ASCII码转化为字符 |
1 | print("字符转ASCII码") |
4.复杂数据类型
函数(function)
表(table)【表需要特别学习,特别的重要】
数据结构(userdata)
协同程序(thread(线程))
注意:
(1)lua函数的使用与c#不同,需要在函数创建后调用
(2)在lua中当你传入的参数和函数中的参数个数不匹配时,并不会报错,而是少于参数个数补空或者多余参数个数丢失
(3)多返回值时,在前面申明多个变量来接取即可,如果变量不够,不会影响结果,值会根据实际接取对应位置的返回值
(4)在lua中并不支持函数的重载,如果函数名相同,参数不同时,则会执行最后声明的函数
基本语法
1 | function 函数名() |
1.无参数无返回值的函数
1 | print("**********无参数无返回值**********") |
2.有参数无返回值
1 | print("**********有参数无返回值**********") |
1 | **********有参数无返回值********** |
3.有参数有返回值
1 | temp=F4("1") |
相关的测试结果
1 | 只有一个变量: 1 |
4.变长参数
1 | print("**********变长参数**********") |
5.嵌套函数
1 | print("**********嵌套函数**********") |
在嵌套函数中引入了一个新的词:闭包【面试常问】
闭包:通过调用含有一个内部函数加上该外部函数持有的外部局部变量(upvalue)的外部函数(就是工厂)产生的一个实例函数
闭包组成:外部函数+外部函数创建的upvalue+内部函数(闭包函数)
1 | function F9(x) |
相关的测试结果
这里最后执行的结果为15==>F9(10)执行的x=10,f(10)执行的是y=5
这里需要注意一个知识点:所有复杂类型本质都是table表
注意:
1.在lua中索引是从1开始的
2.通常在获取长度的时候关键字是#
3.打印长度时,nil(空)在末尾是被忽略的,但是不在末尾而是在某一位置,则会影响获取长度,由于底层的不同,有时转而打印在nil(空)之前的长度,有时会出现计算长度包括nil
1.数组的定义与长度获取
1 | a={1,2,3,"SeveneStudio",true,nil} |
相关的测试结果
1 | 打印数组第一个值 1 |
2.数组的遍历
1 | print("*********数组遍历*********") |
相关的测试结果
1 | *********数组遍历********* |
3.二维数组的定义
1 | print("*********二维数组*********") |
相关的测试结果
1 | *********二维数组********* |
4.二维数组的遍历
1 | print("*********二维数组遍历*********") |
相关的测试结果
1 | *********二维数组遍历********* |
5.自定义索引
注意:
1.计算长度时会忽略小于等于0的索引
2.当对自定义索引进行跳跃性设置时,若只跳跃一个值并不会断掉,长度受最大的索引影响
【迭代器遍历主要是用于遍历表】
- ipairs遍历
pairs遍历是从1开始往后遍历的,小于等于是不会获取到的
智能找到连续索引的键值,若中间断序,无法遍历后面的内容
1 | a={[0]=1,2,[-1]=3,4,5,[5]=6} |
相关的测试结果
1 | ***********ipairs迭代器遍历 |
- pairs【推荐使用pairs遍历不规则数组】
能够把所有的键都可以找到,通过键可以得到值
1 | a={[0]=1,2,[-1]=3,4,5,[5]=6} |
相关的测试结果
1 | ***********pairs迭代器遍历 |
lua字典的使用与C#相似
1.字典的声明与访问使用
1 | print("****************字典的声明和使用****************") |
相关的测试结果
1 | ****************字典的声明和使用**************** |
2.字典的遍历
1 | print("****************字典的遍历****************") |
相关的测试结果
1 | ****************字典的遍历**************** |
在开始的时候已经说过了lua没有面向对象的,所以这里通过表类实现类
下面给大家说明一下相关知识逻辑
TODO:这里到时候叙说
1 | Student={ |
三.运算符
(1)在lua中是没有自增自减和复合运算的
(2)字符串可以进行算数运算符操作,可自动转化成number
加法(+)减法(-)乘法(*)除法(/)取余(%) 幂(^) 整除(//)
大于(>) 小于(<) 大于等于(>=) 小于等于(<=) 等于等于(==) 不等于(~=)
- 在lua中逻辑与==>and
- 在lua中逻辑或==>or
- 在lua中逻辑否==>not
- 在lua中同样遵守逻辑运算的“短路”规则
1 | print(true and false) |
*特殊知识记录
and 逻辑与 or 逻辑或 |
---|
and or 他们不仅可以连接boolean ,任何东西都可以连接 |
在lua中只有nil和false才会认为是假 |
“短路”===>对于and 是有假则假,对于 or 则是有真则真 |
所以只需要判断第一个是否满足就会停止计算 |
对于运算符and来说,假设它的第一个操作数为假,就返回第一个操作数;不然返回第二个操作数 |
对于运算符or来说,假设它的第一个操作数为真。就返回第一个操作数,不然返回第二个操作数 |
在lua中不支持位运算(& |),需要自己去实现
在lua中不支持三目运算符(?:),需要自身根据需要实现
模拟三目运算符
说明:这里x=3,y=2,所以很明显的说明x>y返回时true,然后继续看便是 true and x ,由于and是有假则假,所以true and x肯定是true了,对于or来说,true or y这个已经有一个真的了,所以直接返回3
1 | x=3 |
说明:(1)这里x=1,y=3,所以x>y返回的是false,所以现在变化成了false and y,在前面逻辑运算符中说到过and的逻辑,当第一个值为假,则返回第一个值,所以r是false
(2)根据上一个所知转化为 false or y,根据or的逻辑,第一个为假,则会返回第二个值,所以res是3
1 | x=1 |
四.Lua循环和条件分支
注意:lua中是没有Switch语句的1.条件分支语句
Lua 提供了以下条件分支语句:
语句 | 描述 |
---|---|
[if 语句] | if 语句 由一个布尔表达式作为条件判断,其后紧跟其他语句组成。 |
[if…else 语句] | if 语句 可以与 else 语句搭配使用, 在 if 条件表达式为 false 时执行 else 语句代码。 |
[if 嵌套语句] | 你可以在if 或 else if中使用一个或多个 if 或 else if 语句 。 |
基本语法:
if 条件 then ……end
1 | a=8 |
基本语法
if 条件 then ……else ……end
1 | a=22 |
if 条件 then ……elseif 条件 then ……end
1 | a=5 |
2.循环语句
Lua 语言提供了以下几种循环处理方式:
循环类型 | 描述 |
---|---|
[while 循环] | 在条件为 true 时,让程序重复地执行某些语句。执行语句前会先检查条件是否为 true。 |
[for 循环] | 重复执行指定语句,重复次数可在 for 语句中控制。 |
[repeat…until] | 重复执行循环,直到 指定的条件为真时为止 |
[循环嵌套] | 可以在循环内嵌套一个或多个循环语句(while do … end;for … do … end;repeat … until;) |
基本语法:
while 条件 do……end
1 | num=0 |
基本语法
repeat ……until 条件(条件事结束条件)
1 | num=0 |
for 初始值,结束值,递增值
注意:lua中默认递增,i会默认+1,若保持默认递增值可以省略,若递减则需将递增值改为负数
1 | print("****默认递增for循环****") |
五.多脚本执行
在实际的开发过程中,无论是Java还是C#都需要多脚本的调用
1.全局变量和本地变量
这里全局变量直接就可以定义。例如
1 | a=123 --number类型 |
在c#中的本地变量(亦可以说局部变量)是可以用private【私有】protected(保护,只有子类可以访问),在lua中就比较简易了,直接用local 来表示,例如
1 | local d="HaXinXi" --局部字符串类型 |
2.全局方法和本地方法
前面已经说明了全局变量和本地变量,其实全局方法和本地方法是和其相差不多的
1 | -- 全局方法 |
3.脚本的调用
前面两个标题已经说明了一大部分知识点了,下面就是脚本的调用
这里先写一个Test.lua文件作为后面使用
1 | print("Test这里加载了这个lua文件测试") |
在lua中如果想用其他脚本,需要使用一个关键字:require(‘脚本名’)/ require(“脚本名”)这两种格式都是可以的,例如:
1 | require("Test") -- 调用同路径中的Test脚本 |
这里需要说明重要的点
相关说明 |
---|
只要require执行完的脚本,任何全局变量,包括表,方法是可以直接拿来用的 |
这里需要注意若调用相同路径的文件可以直接使用文件名,而不同路径需要写入路径名 |
require不会重复加载同一个lua |
4.脚本的卸载/移除
前面已经说完了脚本的声明调用,当这个脚本不需要了,该如何呢
先说明如何判断脚本是否声明过了
1 | package.loaded["Test"] |
当知道了判断脚本是否被调用了,在后面不需要了直接将其判断为空或者将判断是否调用过直接定义为false也是也是可以的
1 | package.loaded["Test"]=nil -- 将判断包是否加载过为nil |
5.局部变量使用
对于局部变量的使用可以在lua文件的最后一行返回一个局部参数,然后在需要的地方来用local 参数接收即可
1 | local a=require("Test") --这里调用Test.lua文件,用local a来接收,其实收到的也就是Test.lua中的testLocalA |
6.大G表
_G是一个总表,本质是table,他将我们申明的所有全局变量都存储在其中
声明的local本地/局部变量是不会存到_G表中的
1 | a=1 |
相关参考信息
1 | string table: 0000021B456413D0 |
六.协同程序
前言:协程其实可以看作是一个线程对象,前面已经说了方法的定义与使用,这里就直接写一个方法
首先是一个比较简单的方法,打印的是SeriousWission这个字符串
1 | fun=function () |
协同程序的创建
这里需要说明的便是这两种方式的使用和运行是不一样的
第一种方式-coroutine.create
1 | co=coroutine.create(fun) |
第二种方式-coroutine.warp
1 | co2=coroutine.wrap(fun) |
这样看的还是不太明显,使用type()看看这两个协程程序的类型
1 | -- 创建协程的第一种方式 |
这样就能看出来这两种创建协程的方式类型是不同的,第一种方式本质是线程,但是第二种则本质是方法
协同程序的运行
这里运行协程程序因为前面用到的方式不同,使用也是不同的
1 | --运行通过coroutine.create()创建的协程 |
协同程序的挂起
这里需要注意一个点,c#的协程在启动后会按照一定时间不停的执行,但是lua只会执行一次
首先我们重新在定义一个方法并在里面放上协程的挂起函数
1 | fun2 =function () |
使用上面说到的运行协同程序的方式看看效果
1 | --coroutine.create()创建 |
即使while是一个死循环,这两种方式都只会执行一次,只有再创建相应的开始程序才会执行
协同程序的挂(加返回值)
协程的挂起说完了,其实协程是可以有返回值的
定义一个function()【为了方便直接使用fun2的】
1 | fun3 =function () |
执行这两个程序
1 |
|
七.元表
首先先对元表是什么来一个大白话的解释
元表可以解释为一个表的父亲,也就是父表,
任何表变量都可以作为另一个表变量的元表
任何表变量都可以有自己的元表(父亲)
当我们子表中进行一些特定操作时,会执行元表的内容(其中包括__tostring(),__index()等)
- 设置元表
设置元表就相比较简单了==>setmetatable(子表,元表【可以看做是父表】),下面举个例子看看
1 | mytable = {} -- 普通表 |
- 特定操作
❶__tostring():当子表要被当做字符串使用时,会默认调用这个元表中的tostring方法
1 | mytable2={ |
同样里面function里面也是可以带参数的,那就再写一个
1 | mytable3={ |
❷__call :在 Lua 调用一个值时调用:简单来说就是当做函数来用时调用
这里需要注意一点:只有元表里有__call元方法,才可以使用方法调用,不然会报错误
1 | meta4={ |
这时 传入一个参数 会出现什么效果呢?
1 | meta5={ |
- 元表中运算符
其实元表也是支持 运算符 的,下面就直接用程序做解释吧(以下罗列了常用的运算符)
翻阅Lua官网API可知:需要注意元表中的运算符只有小于或者小于等于,如果想实现大于或者大于等于可以选择取反实现
模式 | 描述 |
---|---|
__add | 对应的运算符 ‘+’. |
__sub | 对应的运算符 ‘-‘. |
__mul | 对应的运算符 ‘*’. |
__div | 对应的运算符 ‘/‘. |
__mod | 对应的运算符 ‘%’. |
__unm | 对应的运算符 ‘-‘. |
__concat | 对应的运算符 ‘..’. |
__eq | 对应的运算符 ‘==’. |
__lt | 对应的运算符 ‘<’. |
__pow | 对应的运算符‘^’ |
__le | 对应的运算符 ‘<=’. |
这里罗列了代码实现效果与输出结果,可能有些乱,但是看上去还是比较容易看明白的
1 | meta5={ |
❸__index:当子表中,找不到某一个属性时,会到元表中的 _index中指定的表 去找索引;
__index遵循向上查找原则
这里其实有一个坑,举个例子阐述一下
1 | meta7={ |
这里很有可能会认为输出的是1,因为age=1,但是他的结果为nil,也就是意味着为空;在使用_index时需要用 _index指定表,如下代码:
这里有一个小小的坑:__index的赋值需要放到表外面赋值
1 | meta7={ |
其实到这里就基本上够用了,但是再上升一个高度[层层查找]
1 | meta7={ |
这里很显然,myTable7中没有age这个字段,然后到其元表的meta7中查找,但是meta7的age被注释上了,刚刚我们设置了meta7的元表是meta7Father,这个时候便会到meta7Father中查找,如果没有便无法在找了,便会返回nil,但是meta7Father中有age字段,便会返回1
❹__newindex:当赋值时,如果赋值一个不存在的索引,会把这个值赋值到newindex所指的表中,不会修改自己
__newindex同样遵循向上查找原则
1 | meta8={} |
- 得到元表
getmetatable(table): 返回对象的元表(metatable
1 | meta9={} |
- 查找参数/设置参数
rawget():绕过__index,在自身身上查找有没有这个变量
1 | meta10={} |
rawset():绕过__newindex,在自身身上设置变量
1 | meta11={} |
八.面向对象
这里复习一下c#知识,在c#中面向对象的三大特性:继承,封装,多态;
- 封装:指能够把一个实体的信息、功能、响应都装入一个单独的对象中的特性。
- 继承:继承的方法允许在不改动原程序的基础上对其进行扩充,这样使得原功能得以保存,而新功能也得以扩展。这有利于减少重复编码,提高软件的开发效率。
- 多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。
在lua中的对象便是由属性 和方法 组成,lua中最基本的结构 是table,所以需要用table来描述对象的属性
封装
1 | Object ={} |
这还是只是一个表,还有一个参数是id等于1,想要实现c#的实例化,就要有一个实例化方法
1 | -- 冒号是会自动将调用这个函数的对象作为第一个参数传入的写法 |
这时我们即可调用这个方法来完成实例化
1 | local myObj=Object:new() |
此时你想要得到id的值,你会发现print(myObj.id)的值为nil,这是因为你获取的是Object:new()里面的obj,这是没有id的,而且又没指定元表,当然id是nil(空)咯,所以想要获取id的值,你需要指定其元表
1 | -- 冒号是会自动将调用这个函数的对象作为第一个参数传入的写法 |
这是在通过print(myOj.id)时,obj中没有id,然后到其元表,这里使用self是因为冒号是会自动将调用这个函数的对象作为第一个参数,也就是Object了,这样就可以获取Object里的id的值了,所以打印结果为:1
上面说完了参数的使用,当然少不了在c#中的方法的调用,那我们就设置一个无参的方法和一个有参的方法
1 | Object.name="爱吃大饼的小虎" |
这个时候我们就可以调用这个Test()方法和Test(age)的方法了
1 | myObj:Test() --因为获取的Object.name的值,所以为:爱吃大饼的小虎 |
那当name的值赋值是什么结果呢?
1 | myObj.name="七鳄学习格" |
继承
在c#中的继承是 class 类名:需要继承的类(父类),在lua是需要自己写来实现,首先我们先复用上面的Object代码
1 | Object ={} |
这里需要复习一下_G(大G表)的相关知识,我们知道_ _G是一个总表,本质是table,他将我们申明的所有全局变量都存储在其中
1 | --这里相当于将a和b的值传入到_G表中,方可通过_G.a和_G.b获取值 |
其实到这里就比较容易说通了,我们可以通过结合_G表来实现继承,示例代码如下
1 | --className表示一个新的类的名称 |
1 | (1)p1:Person:new()===>function Object:new() |
然后说一下赋值
1 | Object:subClass("Person") |
多态
首先主要明白什么是多态
(1)相同行为 不同表象 就是多态
(2)相同方法 不同执行逻辑 就是多态
而需要实现多态需要拥有三个条件:继承,重写,父类引用指向子类对象:Parent p = new Child();
因为需要用到上面的代码,复用一下
1 | Object ={} |
实现所谓的继承,重写,父类引用指向子类对象
1 | --相当于创建一个GameObject类 |
这样基本的多态就ok了,但是当我们在创建一个p2
1 | --实例化p2 |
所以这里就需要用self.base.Move(self)这样调用方可解决这个问题(Bug)
九.自带库
时间库
- os.time ([table])
按table的内容返回一个时间值(数字),若不带参数则返回当前时间.(在许多系统中该数值是当前距离某个特定时间的秒数。),按照这种方式写即可
1 | print(os.time()) |
1 | --自己传入参数,得到时间 |
- os.date ([format [, time]])
功能:返回一个按format格式化日期、时间的字串或表
*t”:将返一个带year(4位),month(1-12), day (1–31), hour (0-23), min (0-59), sec (0-61), wday (星期几, 星期天为1), yday (年内天数), and isdst (是否为日光节约时间true/false)的带键名的表;
若没有”*t”则返回一个按C的strftime函数格式化的字符串;
若不带参数,则按当前系统的设置返回格式化的字符串 os.date() <=> os.date(“%c”)
1 | local nowTime=os.date("*t") |
如果使用带标记(见下表)的特殊字符串,os.data函数会将相应的标记位以时间信息进行填充,得到一个包含时间的字符串。
特殊字符串 | 说明 |
---|---|
%a | 一星期中天数的简称(Wed) |
%A | 一星期中天数的全称(Wednesday) |
%b | 月份的简称(Sep) |
%B | 月份的全称(September) |
%c | 日期和时间(11/11/11 11:11:11) |
%d | 一个月中的第几天(0-31) |
%H | 24小时制中的小时数 |
%I | 12小时制中的小时数 |
%j | 一年中的第几天(259) |
%M | 分钟数 |
%m | 月份数 |
%P | 上午(am)或者下午(pm) |
%S | 秒数(00-59) |
%w | 一星期的第几天(3) |
%W | 一年中的第几个星期(0-52) |
%x | 日期(01/01/01) |
%X | 时间(00:00:00) |
%y | 两位数的年份(00-99) |
%Y | 完整的年份(2001) |
%% | 字符串”%” |
例如:
1 | print(os.date("today is %A, in %B")) --运行结果: today is Tuesday, in February |
数学库
比较常用的
1 | print("绝对值:"..math.abs(-11)) |
这里按照实际需求来用咯
库/方法 | 功能 |
---|---|
math.abs (x) | 返回 x 的绝对值 |
math.acos (x) | 返回 x 的反余弦值(以弧度为单位) |
math.asin (x) | 返回 x 的反正弦(以弧度为单位) |
math.atan (x) | 返回 x 的反正切(以弧度为单位) |
math.atan2 (y, x) | 返回 y/x 的反正切(以弧度为单位),但使用两个参数的符号来查找结果的象限。 (它还可以正确处理 x 为零的情况。) |
math.ceil (x) | 返回大于或等于 x 的最小整数。 |
math.cos (x) | 返回 x 的余弦(假定为弧度)。 |
math.cosh (x) | 返回 x 的双曲余弦值。 |
math.deg (x) | 返回以度为单位的角度 x(以弧度为单位)。 |
math.exp (x) | 返回值 e 幂 x。 |
math.floor (x) | 返回小于或等于 x 的最大整数。 |
math.fmod (x, y) | 返回 x 除以 y 的余数,该余数将商向零舍入。 |
math.frexp (x) | 返回 m 和 e 使得 x = m2e, e 是一个整数并且 m 的绝对值在 [0.5, 1) 范围内(或者当 x 为零时为零)。 |
math.huge | 值 HUGE_VAL,大于或等于任何其他数值的值。 |
math.ldexp (m, e) | 返回 m2e(e 应该是一个整数)。 |
math.log (x) | 返回 x 的自然对数。 |
math.log10 (x) | 返回 x 的以 10 为底的对数。 |
math.max (x, …) | 返回其参数中的最大值。 |
math.min (x, …) | 返回其参数中的最小值。 |
math.modf (x) | 返回两个数字,x 的整数部分和 x 的小数部分。 |
math.pi | pi 的值。 |
math.pow (x, y) | 返回 xy。 (您也可以使用表达式 x^y 来计算此值。) |
math.rad (x) | 返回以弧度为单位的角度 x(以度为单位)。 |
math.random ([m [, n]]) | 此函数是 ANSI C 提供的简单伪随机生成器函数 rand 的接口。当不带参数调用时,返回范围 [0,1) 内的统一伪随机实数。 当使用整数 m 调用时,math.random 返回范围 [1, m] 内的统一伪随机整数。 当使用两个整数 m 和 n 调用时,math.random 返回范围 [m, n] 内的统一伪随机整数。 |
math.randomseed (x) | 将 x 设置为伪随机生成器的”种子”:相等的种子产生相等的数字序列。 |
math.sin (x) | 返回 x 的正弦值(假定为弧度)。 |
math.sinh (x) | 返回 x 的双曲正弦值。 |
math.sqrt (x) | 返回 x 的平方根。 (您也可以使用表达式 x^0.5 来计算此值。) |
math.tan (x) | 返回 x 的正切(假定为弧度)。 |
math.tanh (x) | 返回 x 的双曲正切。 |
文件路径
1 | print(package.path) |
十.I/O
Lua I/O 库用于读取和处理文件。分为简单模式(和C一样)、完全模式
- 简单模式
1 | file = io.open("test.lua", "r") -- 以只读方式打开文件 |
模式 | 描述 |
---|---|
r | 以只读方式打开文件,该文件必须存在。 |
w | 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。 |
a | 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留) |
r+ | 以可读写方式打开文件,该文件必须存在。 |
w+ | 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 |
a+ | 与a类似,但此文件可读可写 |
b | 二进制模式,如果文件是二进制文件,可以加上b |
+ | 号表示对文件既可以读也可以写 |
1 | io.input(file) -- 设置默认输入文件为 test.lua |
这里io.read()是可以添加参数的,具体如下:
“*n” | 读取一个数字并返回它。例:file.read(“*n”) |
---|---|
“*a” | 从当前位置读取整个文件。例:file.read(“*a”) |
“*l”(默认) | 读取下一行,在文件尾 (EOF) 处返回 nil。例:file.read(“*l”) |
number | 返回一个指定字符个数的字符串,或在 EOF 时返回 nil。例:file.read(5) |
1 | io.close(file) -- 关闭打开的文件 |
十一.垃圾回收
在lua中垃圾回收的关键字是collectgaabage,其中加入不同的参数实现不同的功能,其实比较常用的基本就count和collect两个;
collectgarbage(“count”)
以 K 字节数为单位返回 Lua 使用的总内存数。 这个值有小数部分,所以只需要乘上 1024 就能得到 Lua 使用的准确字节数(除非溢出)。
1 | --使用就比较简单了 |
collectgarbage(“collect”)
做一次完整的垃圾收集循环,即垃圾回收,这里lua中的机制和C#中垃圾回收机制很类似 解除羁绊 就是变垃圾,所以如下代码会发现
1 | --复用一下上面的代码 |
做个最后的结语咯
其实lua中 有自动定时进行GC的方法,采用了自动内存管理。 这意味着你不用操心新创建的对象需要的内存如何分配出来, 也不用考虑在对象不再被使用后怎样释放它们所占用的内存。这也就可以说:Unity中热更新开发,尽量不要去用自动垃圾回收
对所有代码都严格审核规范
数据类型知识点
多脚本执行
面向对象
对每一个知识点都做细节
lua知识点覆盖,并能够应用于学习和工作当中