1、首先安装LuaForWindows,官网地址:https://github.com/rjpcomputing/luaforwindows/releases
2、安装Sublime Text,官网地址:https://www.sublimetext.com/download
3、如果大家下载不了的话,可以通过我提供的百度网盘进行下载:
链接:https://pan.baidu.com/s/1ojhEqgUoEtozdS3itTY1_Q
提取码:nw68
1、打印函数
print("hello world")
2、注释
--单行注释
--[[
第一种多行注释
]]
--[[
第二种多行注释
]]--
--[[
第三种多行注释
--]]
print(type(a))
--type的返回值为string类型
--lua中使用没有声明过的变量,不会报错,默认值是nil
6、字符串
s="521一生一世"
print(#s) --获取字符串的长度,一个汉字占3个长度,英文字符占一个长度
--字符串多行打印
print("123\n123")
s=[[
521
1314
]]
print(s)
--字符串拼接
print("123".."456") --通过两个..
print(string.format("小明今年%d岁了",18)
--%d:与数字拼接
--%a:与任何字符拼接
--%s:与字符配对
--别的类型转字符串
a=18
print(tostring(a))
--字符串提供的公共方法
str="aBcDe"
print(string.upper(str)) --小写转大写的方法
print(string.lower(str)) --大写转小写的方法
print(string.reverse(str)) --翻转字符串
print(string.find(str,"cDe")) --字符串索引查找,Lua中索引下标从1开始
print(string.sub(str,3)) --截取字符串
print(string.rep(str,2)) --字符串重复
print(string.gsub(str,"cD","**")) --字符串修改
a=string.byte("Lua",1) --给指定位置的字符转成ASCII码
print(a)
print(striing.char(a)) --ASCII码转字符
7、运算符
--算术运算符
-- + - * / % ^
-- 没有自增自减 ++ --
-- 没有复合运算符 += -= /= *= %=
-- 字符串可以进行算术运算符操作,会自动转成number
print("123"+1) --结果为:124
print("幂运算:"..2^5)
--条件运算符
-- > < >= <= == ~=(不等于)
--逻辑运算符
--and 与
--or 或
--not 非
-- Lua中支持“短路”,只要第一个条件成立,后面的语句就不执行
--位运算符
--Lua中不支持位运算
--三目运算符
--Lua中不支持三目运算符
8、条件分支语句
--单分支
if 条件 then
...
end
--双分支
if 条件 then
...
else
...
end
--多分支
if 条件 then
...
elseif 条件 then --elseif是连着写的,要不然会报错
...
else
...
end
--Lua中没有Switch语法,需要自己实现
9、循环语句
--while语句
while 条件 do
...
end
--do while语句
repeat
...
until 条件 --结束条件,满足条件退出
--for语句
for i=1,5 do --从1开始到5结束,i默认递增+1,如果要自定义增量,要这样写:i=1,5,2
...
end
10、函数
--无参数无返回值,两种方法
function F1() --一个在function后面取名字
...
end
F2 = function() --一个不取名字,用一个变量来存储
...
end
--有参数,如果传入的参数和函数参数个数不匹配,不会报错,只会补空nil或者丢弃
function F3(a)
...
end
--有一个返回值
function F4(a)
return a
end
--有多个返回值,需要申明多个变量来接取,接少接多不影响,少了丢弃,多了为nil
function F5(a)
return a,b,c
end
--函数类型就是function
--不支持函数的重载
--变长参数
function F6(...)
arg = {...}
for i=1,#arg do
print(arg[i])
end
end
F6(1,"123",true,456)
--函数嵌套,函数里面申明函数
function F7()
return function()
print(123)
end
end
F8 = F7()
F8()
--闭包,改变传入参数的生命周期
function F9(x)
return function(y)
return x + y
end
end
F10 = F9(10)
print(F10(5)) --15
11、复杂数据类型table
--所有的复杂类型都是table
--数组的声明和使用
a = {1,2,"123",true,nil,"456"}
print(a[1]) --Lua中索引从1开始
print(#a) --获取数组的长度,#是通用的获取长度的关键字,在打印长度的时候,第一个空后面的内容会被忽略
--数组的遍历
for i=1,#a do
print(a[i])
end
--二维数组
b = {{1,2,3},{4,5,6}}
print(b[1][2])
--二维数组的遍历
for i=1,#b do
c=b[i]
for j=1,#c do
print(c[j])
end
end
--自定义索引
aa={[0]=1,2,3,[-1]=4} --#aa打印结果为2,忽略小于等于0的索引
bb={[1]=1,[2]=2,[4]=4,[6]=6} --有坑,#bb打印的结果为6,索引之间可以跳一个,缺的补nil
cc={[1]=1,[2]=2,[5]=5,[6]=6} --#cc打印结果为2
--迭代器遍历,主要是用来遍历表的,一般不要用#来遍历表
a={[0]=1,2,[-1]=3,4,5,[5]=6}
--ipairs遍历,还是从1开始往后遍历的,小于等于0的值得不到
--只能找到连续索引的键,如果中间断序了,它也无法遍历出后面的内容
for i,k in ipairs(a) do
print(i.."_"..k) --1_2 2_4 3_5
end
--pairs它能够把所有的键都找到,通过键可以得到值
for i,v in pairs(a) do
print(i.."_"..v) --1_2 2_4 3_5 0_1 -1_3 5_6
end
--只遍历键
for i in pairs(a) do
print(i)
end
12、字典
--字典的声明,字典是由键值对构成
a={["name"]="张三",["age"]=18,["sex"]="男"}
print(a["name"]) --访问
print(a.name) --虽然可以通过.成员变量的形式得到值,但是不能是数字
a["name"]="李四" --修改
a["score"]=100 --新增
a["score"]=nil --删除
--字典的遍历
for k,v in pairs(a) do
print(k,v)
end
13、类和结构体
--Lua中默认是没有面向对象的,需要我们自己来实现
--类的声明,成员变量,成员函数
Student = {
age=18,
sex=true,
Up=function()
--这样写 这个age和表中的age没有任何关系 它是一个全局变量
--print(age)
--想要在表的内部函数中 调用表本身的属性或者方法
--一定要指定是谁的 所以要使用 表名.属性 或者 表名.方法
print(Studnet.age)
print("Grow up!");
end
}
print(Student.age) --调用
Student.Up()
--申明表过后,在表外去申明表有的变量和方法
Student.name="张三"
Student.Learn=function(t)
--第二种 能够在函数内部调用自己属性或者方法的 方法
--把自己作为一个参数传进来 在内部 访问
print(t.sex)
print("好好学习,天天向上")
end
Student.Learn(Student)
Student:Learn() --冒号调用方法 会默认把调用者 作为第一个参数传入方法中
function Student:Speak() --冒号声明函数
--Lua中 有一个关键字 self 表示默认传入的第一个参数
print(self.name.."说话")
end
14、表的公共操作
t1={{age=1,name="123"},{age=2,name="345"}}
t2={name="张三",sex=true}
--将t2插入t1
table.insert(t1,t2)
--移除最后一个索引的内容
table.remove(t1)
--移除指定位置的内容
table.remove(t1,1)
t3={4,8,1,3,6,9}
table.sort(t3) --升序排序
table.sort(t3,function(a,b)
if a>b then
return true
end
end) --降序排序
--拼接
tb={"123","456","789"}
table.concat(tb,",")
15、多脚本执行
--全局变量和本地变量
--本地变量就是在变量前加local关键字
--不加local关键字的都是全局变量
--多脚本执行语法:require("脚本名") 或 require('脚本名')
--如果是require加载执行的脚本 加载一次过后不会再被执行
--脚本卸载
--package.loaded["脚本名"] --返回值是boolean 意思是 该脚本是否被执行
package.loaded["脚本名"]=nil --卸载已经执行过的脚本
--大G表:是一个总表 它将我们申明的所有全局的变量都存储在其中
--写法:_G
_G["a"] = 1 --大G表中声明
print(a)
--如果想在另外一个脚本中访问该脚本中的本地变量,可以通过return返回,在另一个脚本中用变量接收即可
16、特殊用法
--多变量赋值,如果后面的值不够,会自动补空;如果后面的值多了,会自动省略
a,b,c=1,2,3
--多返回值
function Test()
return 10,20,30,40
end
a,b,c=Test() --多返回值时 你用几个变量接 就有几个值 如果少了 就少接几个 如果多了 就自动补空
--逻辑与 逻辑或
--and or 他们不仅可以连接boolean 任何东西都可以用来连接
--在Lua中 只有nil和false才认为是假
--“短路” 对于and来说 有假则假 对于or来说 有真则真
--所以他们只需要判断 第一个 是否满足 就会停止计算了
print(1 and 2) --2
print(0 and 1) --1
print(nil and 1) --nil
print(false and 2) --2
print(true or 1) --true
print(nil or 2) --2
--Lua不支持三目运算符,模拟三目运算符
x=3
y=2
res=(x>y) and x or y
--(x>y) and x -> x --x>y为真
--x or y -> x
--(x>y) and x -> (x>y) --x>y为假
--(x>y) or y -> y
17、协同程序
--协程的创建 协程的本质是一个线程对象
--第一种方法:coroutine.create() 常用方式 返回的是一个thread
fun = function()
print(123)
end
co = coroutine.create(fun)
--第二种方法:coroutine.wrap() 返回的是function
co2 = coroutine.wrap(fun)
--协程的运行
coroutine.resume(co) --用第一种方法创建的协程的运行方法
co2() --第二种
--协程的挂起
fun2 = function()
local i=1
while true do
print(i)
i = i + 1
coroutine.yield(i) --协程的挂起函数 可以有返回值
end
end
co3 = coroutine.create(fun2)
coroutinee.resume(co3) --1
coroutinee.resume(co3) --2
isOk,tempI = coroutinee.resume(co3) --默认第一个返回值是协程是否启动成功,第二个是yield里面的返回值
co4 = coroutine.wrap(fun2)
co4() --1
co4() --2
print(co4) --这种方式的协程调用 也可以有返回值 只是没有默认第一个返回值了
--协程的状态:coroutine.status(协程对象)
--有三种状态:dead 结束 suspended 暂停 running 进行中
--得到当前正在运行的协程的线程号
coroutine.running()
18、元表
--元表的概念
--任何表变量都可以作为另一个表变量的元表
--任何表变量都可以有自己的元表(爸爸)
--当我们子表中进行一些特定操作时 会执行元表中的内容
--设置元表
meta={}
myTable={}
--设置元表函数 第一个参数 子表 第二个参数 元表(爸爸)
setmetatable(myTable,meta)
--特定操作 __tostring 当子表要被当做字符串使用时 会默认调用这个元素中的tostring方法
meta2={
__tostring = function(t)
return t.name
end
}
myTable2={
name = "张三"
}
setmetatable(myTable2,meta2)
print(myTable2)
--特定操作 __call
meta3={
__tostring = function(t)
return t.name
end,
--__当子表被当做一个函数来使用时 会默认调这个__call中的内容
__call = function() --当希望传参数时 一定要记住 默认第一个参数 是调用者自己
print("李四")
end
}
myTable3={
name = "张三"
}
setmetatable(myTable3,meta3)
print(myTable3)
myTable3()
--运算符重载
meta4={
--相当于运算符重载 当子表使用+运算符时 会调用该方法
__add = function(t1,t2)
return t1.age + t2.age
end
-- 运算符-:__sub
-- 运算符*:__mul
-- 运算符/:__div
-- 运算符%:__mod
-- 运算符^:__pow
-- 如果要用条件运算符来比较两个对象,这两个对象的元表一定要一致,才能准确调用方法
-- 运算符==:__eq
-- 运算符<:__lt
-- 运算符<=:__le
-- 运算符..:__concat
}
myTable4={age = 1}
setmetatable(myTable4,meta4)
myTable5={age = 2}
print(myTable4+myTable5) --3
--特定操作 __index 和 __newIndex
meta6={
__index = {age = 1}
}
--meta6.__index = {age = 2}
--meta6={
-- age=1
--}
--meta6.__index = meta6
myTable6={}
setmetatable(myTable6,meta6)
--__index 当子表中找不到某一个属性时 会在元表中 __index指定的表去找索引 建议写在外面
print(myTable6.age)
print(getmetatable(myTable6)) --得到元表的方法
print(rawget(myTable6,"age")) --rawget 当我们使用它时 会去找自己身上有没有这个变量
--newindex 当赋值时 如果赋值一个不存在的索引 那么会把这个值赋值到newIndex所指的表中 不会修改自己
meta7={}
meta7.__newindex={}
myTable7={}
setmetatable(myTable7,meta7)
myTable7.age=1
print(myTable7.age) --nil
print(myTable.__newindex.age) --1
rawset(myTable7,"age",2) --该方法 会忽略newindex的设置 只会改自己的变量
print(myTable7.age) --2
19、面向对象
-- 面向对象 类 其实都是基于table来实现的
-- 面向对象之封装
Object = {}
Object.id = 1
function Object:Test()
print(self.id)
end
--冒号 是会自动将调用这个函数的对象 作为第一个参数传入的写法
function Object:new()
--self 代表的是 我们默认传入的第一个参数
local obj = {}
--元表知识 __index 当找自己的变量 找不到时 就会去找元表当中 __index指向的内容
self.__index = self
obj.base = self --子类 定义个base属性 代表父类
setmetatable(obj,self)
return obj
end
local myObj = Object:new()
print(myObj.id) --1
myObj:Test() --1
--对空表中 声明一个新的属性 叫做id
--myObj.id=2
--print(Object.id) --1
myObj.id = 2
myObj:Test() --2
--面向对象之继承
function Object:subClass(className)
-- _G知识点 是总表 所有声明的全局变量 都以键值对的形式存在其中
_G[className]={}
local obj = _G[className]
self.__index = self
setmetatable(obj,self)
end
Object:subClass("Person")
print(Person.id) --1
local p = Person:new()
print(p.id) --1
--面向对象之多态
Object:subClass("GameObject")
GameObject.posX = 0
GameObject.posY = 0
function GameObject:Move()
self.posX = self.posX + 1
self.posY = self.posY + 1
print(self.posX,self.posY)
end
GameObject:subClass("Player")
function Player:Move()
self.base:Move()
--我们如果要执行父类逻辑 就不能直接使用冒号调用 要通过.调用 然后自己传入第一个参数
--self.base.Move(self) --填坑
end
local p1 = Player:new()
p1:Move() --1 1
--目前这种写法 有坑 不同对象使用的成员变量 居然是相同的成员变量 不是自己的
local p2 = Player:new()
p2:Move() --2 2
20、面向对象总结
Object = {}
function Object:new() -- 封装
local obj = {}
--给空对象设置元素 以及 __index
self.__index = self
setmetatable(obj,self)
return obj
end
function Object:subClass(className) -- 继承
--根据大G表的特性 根据名字生成一张表 就是一个类
_G[className] = {}
local obj = _G[className]
obj.base = self --设置自己的“父类” 多态
--给子类设置元表 以及 __index
self.__index = self
setmetatable(obj,self)
end
--多态
Object:subClass("GameObject") --声明一个新的类
GameObject.posX = 0 --成员变量
GameObject.posY = 0
function GameObject:Move() --成员方法
self.posX = self.posX + 1
self.posY = self.posY + 1
print(self.posX,self.posY)
end
GameObject:subClass("Player") --声明一个新的类 Player 继承 GameObject
function Player:Move() --多态 重写了GameObject的Move方法
--self.base.Move(self) --base调用父类方法 用.自己传第一个参数
end
--实例化对象使用
local obj1 = GameObject:new()
print(obj1.posX) --0
obj1:Move()
print(obj1.posX) --1
local obj2 = GameObject:new()
print(obj2.posX) --0
obj2:Move()
print(obj2.posX) --1
local p1 = Player:new()
print(p1.posX) --0
p1:Move()
print(p1.posX) --1
local p2 = Player:new()
print(p2.posX) --0
p2:Move()
print(p2.posX) --1
21、自带库
--时间
print(os.time()) --系统时间
local nowTime = os.date("*t") --详细时间
for k,v in pairs(nowTime) do
print(k,v)
end
print(nowTime.year)
--数学运算
print(math.abs(-1)) --绝对值
print(math.deg(math.pi)) --弧度转角度
print(math.cos(math.pi)) --三角函数
print(math.floor(2.6)) -- 2 向上取整
print(math.ceil(5.2)) -- 6 向下取整
print(math.max(1,2)) -- 2 最大值
print(math.min(4,5)) -- 4 最小值
print(math.modf(1.2)) --小数分离 分成整数部分和小数部分
print(math.pow(2,5)) --幂运算
print(math.sqrt(4)) --开方
--随机数
math.randomseed(os.time) --随机数种子
print(math.random(100))
--路径
print(package.path) --lua脚本加载路径
22、Lua垃圾回收
--垃圾回收关键字:collectgarbage
--获取当前Lua占用内存数 K字节 用返回值*1024 就可以得到具体的内存占用字节数
print(collectgarbage("count"))
--进行垃圾回收
collectgarbage("collect")
--Lua中 有自动定时进行GC的方法
--Unity中热更新开发 尽量不要去用自动垃圾回收