第一个语法
打印
print("你好")
注释
--单行注释
--lua可以省略分号
--[[
多行注释
]]
--[[
第二种多行注释
]]--
--[[
第三种多行注释
--]]
变量
简单变量
print("**********变量**********")
-- 简单变量
-- nil number string boolean
--不用申明变量类型 会自己判断
--类似C#中的var
--lua中的变量可以 随便赋值 ——自动识别类型
--通过type函数可以得到变量类型
--type返回string类型
--lua中没定义的变量
--默认为nil,不会报错
print(b)
-- nil 类似 C#中的null
a = nil
print(a)
print(type(a))
--number 所有数值都是number
a=1
print(a)
print(type(a))
a = 1.2
print(a)
print(type(a))
--string 字符串申明 用单/双引号
--lua 中没有char
a = "12345"
print(a)
print(type(a))
a = '123'
print(a)
print(type(a))
--boolean
a = true
print(a)
print(type(a))
a = false
print(a)
print(type(a))
--type返回string
print(type(type(a)))
Lua总共有8种变量类型
简单变量
number, string, boolean, nil
复杂变量
function 函数 table 表 userdata 数据结构 thread 协同程序
字符串操作
print("*****字符串*****")
str = "双引号字符串"
str2 = '单引号字符串'
--获取字符串的长度
print("***字符串长度***")
s = "1234567字符串"
--一个汉字占3个长度
--英文字符 1个
print(#s)
print("***多行打印***")
--lua也支持转义字符
print("123\n123")
s = [[我是
阿喆
不想学习
]]
print(s)
print("***字符串拼接***")
--字符串拼接 通过..
print("123".."456")
s1 = 111
s2 = 111
--number 拼接后也是 string
print(s1 .. s2)
print(type(s1 .. s2))
print(string.format("我是阿喆不想学习,我今年%d岁了",18))
--%d : 与数字拼接
--%a : 与任何字符拼接 format中用不了,
--%s : 与字符配对
--........
print("***别的类型转字符串***")
a = true
print(tostring(a))
print("***字符串提供的公共方法***")
str = "abCdeFg"
--小写转大写
print(string.upper(str))
print(str) --本体不变
--大写转小写
print(string.lower(str))
--翻转字符串
print(string.reverse(str))
--字符串索引查找 返回开始和结束位置 从1开始
print(string.find(str,"Cde"))
--截取字符串
print(string.sub(str,3)) --截取第3个及之后所有字符
print(string.sub(str,3,4)) --截取第3到第4个字符
--字符串重复
print(string.rep(str,2)) --连续拼接2次
--字符串修改
--返回修改后的,并显示改了几次,若有2个Cd,则会返回2
print(string.gsub(str,"Cd","**"))
print(string.gsub("abcde123","%a","4")) --44444123 5
print(string.gsub("abcde123","a","4")) --4bcde123 1
print(string.gsub("abcde123","%A","4")) --abcde444 3
--字符转 ASCII码
a = string.byte("Lua",1)
--把第一个字符转成了ASCII码
print(a)
--ASCII码 转字符
print(string.char(a))
返回值
print("***运算符***")
print("***算数运算符***")
-- + - * / % ^
-- 没有自增自减 ++ --
-- 没有复合运算符 += -= /= *= %=
--字符串 可以进行 算数运算符操作 会自动转成number
print("加法运算 1 + 2")
--print("加法运算" .. 1 + 2) 会输出"加法运算3"
a = 1
b = 2
print(a + b)
print("123.4" + 1) -- 124.4
--其它运算符一样
--注意除法不会向下取整
print("123.4" / 2) -- 61.7
print("123.4" % 2) -- 1.4
-- lua 中 ^ 为幂运算
print("幂运算" .. 2 ^ 5)
print("123.4" ^ 2) -- 15227.56
print("***条件运算符***")
-- > < >= <= == ~=
--不等于不一样
print("***逻辑运算符***")
-- && || !
-- and or not Lua用这个
-- lua满足“短路” 比如and第一个已经是假 则后面不会执行
print( true and false)
print("***位运算符***")
-- & | 不支持位运算 需要自己实现
print("***三目运算符***")
-- ? : lua中不支持
条件分支语句
print("***条件分支语句***")
a = 9
-- if 条件 then ... end
if a > 5 then
print("123")
end
if a < 5 then
print("123")
else
print("321")
end
--多分支 elseif 连着写
if a < 5 then
print("123")
elseif a == 9 then
print("6")
else
print("321")
end
if a >= 3 and a <= 9 then
print("9")
end
--lua中无 switch语法
循环语句
print("***循环***")
print("***while***")
num = 0
--while 条件 do ... end
while num < 5 do
print(num)
num = num + 1
end
print("***do while***")
num = 0
--repeat ... until 结束条件
repeat
print(num)
num = num + 1
until num > 5 --满足条件跳出
print("***for***")
-- i 从 1 到 5
for i = 1, 5 do --默认递增 i会默认加一
print(i)
end
for i = 1, 5, 2 do --自定义增量 直接逗号后面写
print(i)
end
for i = 5, 1, -1 do --自定义增量 直接逗号后面写
print(i)
end
函数
print("***函数***")
--function 函数名()
--end
--a = function()
--end
print("***无参无返回值***")
-- 要先声明才能调用
function F1()
print("F1函数")
end
F1()
--有点类似C#中的委托和事件
F2 = function()
print("F2函数")
end
F2()
print("***有参数***")
--参数类型不指定,可以任意传参(只要函数体支持该操作)
function F3(a)
print(a)
end
F3(1)
--如果传入参数和函数参数个数不匹配
--不会报错 只会不空nil 或丢弃
F3()
F3(1,2,3)
print("***有返回值***")
function F4(a)
return a
end
temp = F4("123")
print(temp)
function F5(a)
return a,"123",true
end
-- 用对应数量的变量来赋值
-- 变量不够 会丢弃后面两个返回值
-- 变量多了 赋nil
temp = F4("1")
temp1,temp2,temp3 = F5("1")
print(temp1)
print(temp2)
print(temp3)
print("***函数的类型***")
--函数类型就是function
F6 = function()
print("123")
end
print(type(F6))
print("***函数的重载***")
--函数名相同 参数类型不同 或者参数个数不同
--但lua中参数类型没要求
--所以不支持重载
--只会调用最后申明的同名函数
print("***变长参数***")
--变长参数使用 用一个表存起来 再用
function F7( ... )
arg = {...}
for i = 1, #arg do
print(arg[i])
end
end
F7(1,"123",true,4,5,6)
print("***函数嵌套***")
function F8()
return function()
print(123)
end
end
f9 = F8()
f9()
--闭包
function F9(x)
--改变了传入参数的生命周期
--外部的x被传入了内部的函数
return function(y)
return x - y
end
end
f10 = F9(10)
--x被存进去了
print(f10(5)) --5
在lua中闭包的体现在哪里
是函数中返回一个函数,改变函数中变量的生命周期
table
table实现数组
print('***复杂数据类型 table***')
--所有的复杂类型 都是table
print('***数组***')
a = {1,2,nil,3,4,"12345",6,true,nil,7}
--lua中索引从1开始 a[0]是nil
print(a[5])
-- #是通用的获取长度的关键字
--在打印长度的时候 nil会被忽略
--遍历时 碰到 nil 就会断,则返回长度可能不对
print(#a)
print('***数组的遍历***')
for i = 1, #a do
print(a[i])
end
print("***二维数组***")
a = {{1,2,3},
{4,5,6}}
print(a[1][2])
print("***二维数组遍历***")
for i = 1, #a do
b = a[i]
for j = 1, #b do
print(b[j])
end
end
print("***自定义索引***")
aa = {[0] = 1, 2,3, [-1] = 4, 5}
print(aa[0]) -- 1
print(aa[1]) -- 2
print(aa[-1]) -- 4
--不认识[0], [-1]
print(#aa) -- 3
--中间断一个 输出最大
aa = {[1] = 1,[2] = 2,[4] = 3, [5] = 4}
print(#aa) -- 5
--断的多余1个
aa = {[1] = 1,[2] = 2,[5] = 3, [-1] = 4, 5}
print(#aa) -- 2
注意: #a 碰到nil 会不会停要看lua版本,我的lua为5.1.4,碰到nil不停,
迭代器遍历
print("***迭代器遍历***")
--迭代器遍历 主要用来遍历表
--#得到长度 并不准确 一般不用#来遍历表
a = {[0] = 1, 2, [-1] = 3, 4, 5}
print("***ipairs迭代器遍历***")
--ipairs
--ipairs遍历 还是从1开始遍历,小于等于0的值得不到
--只能找连续索引的 键 如果中间断序了 也无法遍历出后面的内容
for i,k in ipairs(a) do
print("ipairs遍历键值"..i.."_"..k)
end
print("***pairs迭代器遍历***")
--能把所有的键都找到
for i,v in pairs(a) do
print("pairs遍历键值"..i.."_"..v)
end
print("***pairs迭代器遍历键***")
--能把所有的键都找到
for i in pairs(a) do
print("pairs遍历键"..i)
end
table实现字典
print('***复杂数据类型 table2***')
print('***字典***')
print('***字典的申明***')
--字典由键值对构成
a = {["name"] = "阿喆", ["age"] = 20, ["1"] = 5}
--访问单个变量 中括号中填键
print(a["name"])
--还可以类似.成员变量的形式得到值,但不能是数字
print(a.name)
-- print(a.1) 会报错
print(a["1"])
--修改
a["name"] = "azhe"
print(a.name)
--新增
a["sex"] = false
print(a.sex)
--删除
a["sex"] = nil
print(a.sex)
--其实没有也会打印出空
print('***字典的遍历***')
--模拟字典 只能用pairs
for k,v in pairs(a) do
--可以传多个参数 一样可以打印
print(k,v)
end
for k in pairs(a) do
print(k)
print(a[k])
end
table实现类
print('***类和结构体***')
--lua中默认没有面向对象的 要我们自己来实现
--成员变量 成员函数
Student = {
age = 1,
sex = true,
Up = function()
--这样写 这个age是全局变量,和表中的age没有任何关系
--print(age)
--要表明是谁的 才能调用表本身的属性或方法
print(Student.age)
print("我成长了")
end,
Learn = function(t)
--第二种 在函数内部调用自己属性或者方法的方法
--把自己作为一个参数传进来 在内部访问
print(t.sex)
print("好好学习")
end
}
--C#要使用类 实例化对象new 静态
--lua中类的表现 更像是一个类中有很多 静态变量和函数
print(Student.age)
Student.Up()
--申明表过后,在表外去申明表的变量和方法
Student.name = "阿喆"
Student.speak = function ()
print("说话")
end
--函数的第三种申明方式
function Student.speak2()
print("说话2")
end
function Student:speak3()
--lua中 有一个关键字self (不是this) 表示 默认传入的第一个参数
print(self.name.."说话3")
end
Student.Learn(Student)
--lua中 . 和 冒号的区别
--冒号调用方法 会默认把调用者 作为第一个参数传入方法中
Student:Learn()
Student:speak3()
Student.speak3(Student)
注意:
当定义冒号调用方法时,如例子Student:Learn(),当定义该方法后,Student表里就会存放该Learn方法。 在后续实现面向对象的过程中,多态就靠这个实现。
表的公共操作
print('***表的公共操作***')
--表中 table提供的一些公共方法的讲解
t1 = {{age = 1, name = "123"}, { age = 2, name = "345"}}
t2 = {name = "唐老狮", sex = true}
--插入
print(#t1)
--插到t1后面
table.insert(t1,t2)
print(#t1)
print(t1[1])
print(t1[2])
print(t1[3])
print(t1[3].sex)
--删除指定元素
-- remove 方法 传1个参数进去 会移除最后一个索引的内容
table.remove(t1)
print(#t1)
print(t1[1].name)
--remove 方法 传2个参数进
--参数2 要移除内容的索引
table.remove(t1,1)
print(t1[1].name)
print(#t1)
print('***排序***')
t2 = {5,2,3,7,1}
table.sort(t2) --从小到大
for _,v in pairs(t2) do
print(v)
end
print('***降序***')
--参数二 排序规则函数
table.sort(t2, function(a,b)
if a > b then
return true
end
end
)
for _,v in pairs(t2) do
print(v)
end
print("***拼接***")
tb = {1,"123", "456","789"}
--数字和字符串可以拼,其它报错 (nil放最后不报错)
--连接函数 用于拼接表中元素 返回值 是一个字符串
str = table.concat(tb,",")
print(str)
多lua脚本执行
全局变量和本地变量
print('***全局变量和本地变量***')
--全局变量
a = 1
b = "123"
for i = 1,2 do
c = "azhe"
end
print(c) -- azhe
--本地(局部) 变量的关键字 local
for i = 1,2 do
local d = "azhe"
print("循环中的d",d)
end
print(d) -- nil
fun = function()
tt = "123123"
end
print(tt) -- nil
fun() --执行后tt赋值了
print(tt) -- 123123
local tt2 = "555"
print(tt2)
多脚本执行
print('***多脚本执行***')
--关键字 require("脚本名") require('脚本名')
require("Test")
print(testA) --123
print(testLocalA) --nil
local testLA = require("Test")
print(testLA) -- 456
Test脚本
print("Test测试")
testA = "123"
local testLocalA = "456"
--其它脚本require的时候会正常输出
print(testLocalA) -- 456
--可以return出去
return testLocalA
脚本卸载
print('***脚本卸载***')
--如果是require加载执行的脚本 加载一次后不会再被执行
require("Test") --没输出Test测试
--package.loaded["脚本名"]
--返回值是boolean 意思是 脚本是否被执行
print(package.loaded["Test"]) -- true
--卸载已经执行过的脚本
package.loaded["Test"] = nil
print(package.loaded["Test"]) --nil
_G表
print('***大G表***')
-- _G表是一个总表(table) 他将我们申明的所有全局的变量都存储在其中
for k,v in pairs(_G) do
print(k,v)
end
--本地变量 加了local的变量不会存到_G表中
特殊用法
print("***特殊用法***")
print("***多变量赋值***")
a,b,c = 1,2,"123"
print(a,b,c) -- 1 2 123
--多变量赋值 如果后面的值不够会补空
a,b,c = 1,2
print(a,b,c) -- 1 2 nil
--后面值多了会省略
a,b,c = 1,2,"123",12
print(a,b,c) -- 1 2 123
print("***多返回值***")
function Test()
return 10,20,30,40
end
--多返回值 你用几个变量接,就有几个值
--少了就少接,多了就补空
a,b,c = Test()
print(a,b,c)
print("***and or***")
--逻辑与 逻辑或
--and or 不仅可以连接 boolean 任何东西都可以用来连接
--在lua中 只有nil 和false 才认为是假
-- "短路" 对于and来说 有假则假 对于or来说 有真则真
--所以第一个满足条件了 就停止计算
print(1 and 2) --2
print(0 and 2) --0
print(nil and 1) --nil
print(false and 2) -- false
print(true and 3) --3
print(true or 1) --true
print(false or 1) -- 1
print(nil or 2) --2
--lua不支持三目运算符
x = 1
y = 2
-- ? :
--但可以通过"短路"特性来模拟
local res = (x > y) and x or y
print(res) -- 2
-- (x > y) and x -> x
-- x or y -> y
x = 2
y = 3
local res = (x > y) and x or y
print(res) -- 3
-- (x > y) and x -> (x>y)
-- (x>y) or y -> y -> y
协同程序
print("***协同程序***")
print("***协程的创建***")
--coroutine.creata()
fun = function()
print(123)
end
co = coroutine.create(fun)
--协程的本质是一个线程对象
print(co) -- thread: 00C9DA48
print(type(co)) -- thread
--coroutine.wrap() 第二种方式
co2 = coroutine.wrap(fun)
print(co2) --function: 00CAE428
print(type(co2)) --function
print("***协程的运行***")
--第一种方式 对应的是 create创建的
coroutine.resume(co)
--第二种方式 调用函数 co2
co2()
print("***协程的挂起***")
fun2 = function()
local i = 1
while true do
print(i)
i = i + 1
--协程的挂起函数
--可以带返回值
--默认第一个是协程是否启动成功
--第二个是yield中的返回值
coroutine.yield(i)
end
end
co3 = coroutine.create(fun2)
--重启协程的函数
isOk,tempI = coroutine.resume(co3) --1
print(isOk,tempI)
--只打印一次
--因为lua中从上到下只执行一次
coroutine.resume(co3) --2
co4 = coroutine.wrap(fun2)
--会先输出co4()中的print(i),然后直接返回返回值,没有默认第一个返回值
print("返回值",co4())
co4() --2
print("***协程的状态***")
--coroutine.status(协程对象)
--dead 结束
--suspended 暂停
--running 进行中
print(coroutine.status(co)) --dead
print(coroutine.status(co3)) --suspend
--在内部运行 得到running
--这个函数可以得到当前 正在运行的协程的线程号
print(coroutine.running())
元表
print("***元表***")
print("***元表概念***")
--任何表变量都可以作为另一个表变量的元表
--任何表变量都可以有自己的元表(爸爸)
--当我们子表中进行一些特定操作时
--会执行元表中的内容
print("***设置元表***")
meta = {}
myTable = {}
--设置元表函数
--参数一 子表
--参数二 元表(爸爸)
setmetatable(myTable,meta)
print("***特定操作***")
print("***特定操作-__tostring***")
meta2 = {
--当子表要被当做字符串使用时,会默认调用这个元表中的tostring方法
__tostring = function()
return "阿喆"
end
}
myTable2 = {name = "阿喆2"}
--设置元表函数
--参数一 子表
--参数二 元表(爸爸)
setmetatable(myTable2,meta2)
print(myTable2)
meta2 = {
--当子表要被当做字符串使用时,会默认调用这个元表中的tostring方法
--会默认传入自己 myTable2
__tostring = function(t)
return t.name
end
}
myTable2 = {name = "阿喆2"}
--设置元表函数
--参数一 子表
--参数二 元表(爸爸)
setmetatable(myTable2,meta2)
print(myTable2)
print("***特定操作-__call***")
meta3 = {
--当子表要被当做字符串使用时,会默认调用这个元表中的tostring方法
--会默认传入自己 myTable2
__tostring = function(t)
return t.name
end,
--当子表被当作一个函数来使用时,会默认调用这个__call的内容
__call = function(a,b)
--a是自己,第一个参数默认是自己
--当需要传参数时,记住默认第一个参数是自己
print(a) -- 阿喆3
print(b) -- 1
print("阿喆好努力")
end
}
myTable3 = {name = "阿喆3"}
setmetatable(myTable3,meta3)
--把子表当函数使用 会调用元表的__call方法
myTable3(1)
print("***特定操作-运算符重载***")
meta4 = {
--运算符+
__add = function(t1,t2)
return t1.age + t2.age
end,
--运算符-
__sub = function(t1,t2)
return t1.age - t2.age
end,
--运算符*
__mul = function(t1,t2)
return t1.age * t2.age
end,
--运算符/
__div = function(t1,t2)
return t1.age / t2.age
end,
--运算符%
__mod = function(t1,t2)
return t1.age % t2.age
end,
--运算符^
__pow = function(t1,t2)
return t1.age ^ t2.age
end,
--运算符==
__eq = function(t1,t2)
return t1.age == t2.age
end,
--运算符< 没有 > >=
__lt = function(t1,t2)
return t1.age < t2.age
end,
--运算符<=
__le = function(t1,t2)
return t1.age <= t2.age
end,
--运算符..
__concat = function(t1,t2)
return t1.age..t2.age
end
}
myTable4 = {age = 2}
setmetatable(myTable4,meta4)
myTable5 = {age = 2}
print(myTable4 + myTable5)
--如果要用条件运算符 来比较两个对象
--这两个对象的元素一定要一致 才能准确调用方法
print(myTable4 == myTable5) -- false
setmetatable(myTable5,meta4)
print(myTable4 == myTable5) -- true
print("***特定操作-__index和__newindex***")
meta6 = {
age = 1
}
myTable6 = {}
setmetatable(myTable6,meta6)
--__index 当子表中 找不到某一个属性时
--会到元表中 __index指定的表去找索引
print(myTable6.age) -- nil
meta6.__index = meta6
print(myTable6.age) -- 1
--或者mata6中没有age,但index指向一个新的表
meta6.__index = {age = 2}
print(myTable6.age) -- 2
--建议__index的赋值 写在表外面来初始化
--__index没有赋值的话是找不到的
--__newindex 当赋值时,如果赋值一个不存在的索引
--那么会把这个值赋到newindex所指的表中 不会修改自己
meta7 ={}
myTable7 = {}
setmetatable(myTable7,meta7)
meta7.__newindex = {}
myTable7.age = 1
--在myTable7中找不到,newindex设置了,则会加到__newindex中
print(myTable7.age) -- nil
print(meta7.__newindex.age) -- 1
--获取元表
--得到元表
print(getmetatable(myTable6)) --table: 00C31290
--rawget 当我们使用他时,会去找自己身上有没有这个变量,不看元表的index了
print(rawget(myTable6,"age")) -- nil
--即使有__newindex,也会忽略,只改自己的变量
rawset(myTable7,"age",2)
print(myTable7.age) -- 2
疑惑与解决
在后续实现面向对象的过程中,p1调用父类的move方法后,发现p1表中也有了posX和posY,且父类GameObject的PosX和posY没有变,而p1的pos值变了,因此有了疑惑做了以下试验
s = {}
function s:fun()
self.A = 10
end
s:fun()
以上操作s中会创建A元素等于10。
s = {}
function s:fun()
self.A = self.A+10
end
s:fun()
这样就会出错,因为s中没有A
因此可以这样写
father = {}
father.__index = father
s = {}
setmetatable(s,father)
father.A = 10
function s:fun()
self.A = self.A+10
end
s:fun()
这样子就可以执行,因为设置元表,找到了father的index中的A,那么输出就会发现,s中有A为20,father中的A仍为10
因此我推测index中的值只是供s参考,因此等号右边的self.A会找到father的index中的值,等号左边的self.A则会在s中创建A。
面向对象
封装
print("***面向对象***")
print("***封装***")
--面向对象 类 其实都是基于表 table 来实现
--元表相关知识点
Object = {}
Object.id = 1
function Object:Test()
print(self.id)
end
--冒号 自动将调用这个函数的对象 作为第一个参数传入的写法
function Object:new()
--self 代表的是我们默认传入的 第一个参数
--对象就是变量 返回一个新的变量
--返回出去的内容 本质上就是表对象
local obj = {}
--元表知识 __index 当找自己的变量 找不到时,会找元表中__index中的内容
self.__index = self
setmetatable(obj,self)
return obj
end
local myObj = Object:new()
print(myObj) --table: 00CB96D0
-- nil 没设置元表以及元表的index时
-- 1 设置元表及其__index后
print(myObj.id)
Object:Test() -- 1
--在空表中 申明一个新的属性
myObj.id = 2
print(Object.id) -- 1
myObj:Test() -- 2
继承
print("***继承***")
--C# class 类名 : 继承类
--写一个用于继承的方法
function Object:subClass(className)
-- _G知识点 总表, 所有声明的全局变量,都以键值对的形式存在其中
_G[className] = {}
--写继承规则
--用到元表
local obj = _G[className]
self.__index = self
setmetatable(obj,self)
end
Object:subClass("Person")
print(Person) --table: 00EA9AE0
print(Person.id) -- 1
local p1 = Person:new()
print(p1.id) -- 1
--p1无id,找person,person的__index也无
--再往上找Object的__index
多态
...
function Object:subClass(className)
-- _G知识点 总表, 所有声明的全局变量,都以键值对的形式存在其中
_G[className] = {}
--写继承规则
--用到元表
local obj = _G[className]
self.__index = self
--子类 定义个base属性 base表示父类
obj.base = self
setmetatable(obj,self)
end
...
print("***多态***")
--相同行为 不同表现 就是多态
--相同方法 不同执行逻辑 就是多态
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)
print(self.posY)
end
GameObject:subClass("Player")
local p1 = Player:new()
p1:Move() -- 1 \n 1
--重写
function Player:Move()
--c#中保留父类方法 base.Move()
--为了实现,要去继承那里定义base属性
--self.base:Move()
--重点
--base指的是 GameObject 表(类)
--这种方式调用 相当于是把基类表 作为第一个参数传入了方法中
--避免把基类表 传入到方法中 这样相当于公用一张表的属性了
--如果要执行父类逻辑 不要直接使用冒号调用
--要通过.调用,然后自己传入第一个参数
self.base.Move(self)
end
p1:Move() -- 2 \n 2
local p2 = Player:new()
p2:Move() -- 改前 2 \n 2
--改后 1 \n 1
--p1 和 p2 共用
--(没有改成重点之后的内容前)以上写法有坑 不同对象使用的成员变量 居然是相同的成员变量
汇总
--面向对象实现
--万物之父 所有对象的基类 Object
--封装
Object = {}
--实例化方法
function Object:new()
local obj = {}
--给空对象设置元表 以及__index
self.__index = self
setmetatable(obj,self)
return obj
end
--继承
function Object:subClass(className)
--根据名字生成一张表 就是一个类
_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
end
--实例化对象使用
local obj = GameObject:new()
print(obj.posX) --0
obj:Move()
print(obj.posX) --1
local obj2 = GameObject:new()
print(obj2.posX) --0
obj2:Move()
print(obj2.posX) --1
--声明一个新的类 Player 继承 GameObject
GameObject:subClass("Player")
--多态 重写了 GameObject中的Move方法
function Player:Move()
--base调用父类方法 用.自己传第一个参数
self.base.Move(self)
end
--实例化Player对象
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
自带库
print("***自带库***")
--string
--table
print("***时间***")
--系统时间
print(os.time()) --1709371947
--自己传入参数 得到事件
print(os.time({year = 2014, month = 8, day = 14})) --1407988800
--os.date("*t")
local nowTime = os.date("*t")
print(nowTime)
for k,v in pairs(nowTime) do
print(k,v)
end
--[[
hour 17
min 35
wday 7
day 2
month 3
year 2024
sec 23
yday 62
isdst false
]]
print(nowTime.hour) --17
print("***数学运算***")
--math
--绝对值
print(math.abs(-11)) --11
--弧度转角度
print(math.deg(math.pi)) --180
--三角函数 传弧度
print(math.cos(math.pi)) -- -1
--向下向上取整
print(math.floor(2.6)) -- 2
print(math.ceil(5.2)) -- 6
--最大最小值
print(math.max(2,6)) -- 6
print(math.min(5,2)) -- 2
--小数分离 分成整数部分和小数
print(math.modf(1.2)) -- 1 0.2
--幂运算
print(math.pow(2,5)) --32
--随机数
--先设置随机数种子
math.randomseed(os.time())
print(math.random(100))
print(math.random(100))
--开方
print(math.sqrt(4)) --2
print("***路径***")
--lua脚本加载路径
print(package.path)
package.path = package.path .. ";C:\\"
print(package.path)
Lua垃圾回收
print("***垃圾回收***")
test = {id = 1, name = "123456"}
--垃圾回收关键字
--collectgarbage
--获取当前lua占用内存值 K字节 用返回值*1024 就可以得到具体的内存占用字节数
print(collectgarbage("count"))
--lua中的机制 和C#中垃圾回收机制很类似 解除羁绊 就是变垃圾
test = nil
--进行垃圾回收 有点像C#的 GC
collectgarbage("collect")
print(collectgarbage("count"))
--lua中 有自动定时进行GC的方法
--Unity中热更新开发 尽量不要去用自动垃圾回收