Lua是由标准C实现的解释型语言,它的执行效率比较高,通常作为脚本嵌入到应用程序中。
由于支持热更新,Lua在游戏开发领域应用普遍。作为从业人员,不得不来填这个大坑。
本文是Lua入门学习笔记,来源是泰课的一个Lua教程。这里主要记录Lua的语法,以及实现
简单的OOP。
Lua 快速入门(一)——基础语法
Lua 快速入门(二)——函数(Function)
Lua 快速入门(三)——表(Table)
Lua 快速入门(四)——多脚本执行
Lua 快速入门(五)——协程(thread)
Lua 快速入门(六)——基础OOP
在 Lua table 中我们可以访问对应的 key 来得到 value 值,但是却无法对两个 table 进行操作(比如相加)。
因此 Lua 提供了元表(Metatable),允许我们改变 table 的行为,每个行为关联了对应的元方法。
查找一个表元素时,遵循以下规则:
1.在表中查找,如果找到,返回该元素,找不到则继续
2.判断该表是否有元表,如果没有元表,返回 nil,有元表则继续。
3.判断元表有没有 __index 方法,如果 __index 方法为 nil,则返回 nil;如果 __index 方法是一个表,则重复 1、2、3;如果 __index 方法是一个函数,则返回该函数的返回值。
任何表变量都可以作为另一个表变量的元表,任何表变量都可以有自己的元表。
可以通过getmetatable获取某一个表的元表。
print("**********设置元表************")
meta = {}
myTable = {}
--设置元表函数
--第一个参数 子表,第二个参数 元表
setmetatable(myTable, meta)
--得到元表的方法
meta1 = getmetatable(myTable)
print(meta1)
当我们在子表中进行一些特定操作时,会执行元表中的内容。
print("**********特定操作-__tostring************")
meta2 = {
--当子表要被当做字符串使用时 会默认调用这个元表中的tostring方法
__tostring = function(t)
return t.name
end
}
myTable2 = {
name = "Canon"
}
setmetatable(myTable2, meta2)
print(myTable2) --Canon
print("**********特定操作-__call************")
meta3 = {
--当子表要被当做字符串使用时 会默认调用这个元表中的tostring方法
__tostring = function(t)
return t.name
end,
--当子表被当做一个函数来使用时 会默认调用这个__call中的内容
--当希望传参数时 一定要记住 默认第一个参数 是调用者自己
__call = function(a, b)
print(a)
print(b)
print("test call")
end
}
myTable3 = {
name = "Canon2"
}
setmetatable(myTable3, meta3)
--把子表当做函数使用 就会调用元表的 __call方法
--依次打印 Canon2 1 test 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 1
end,
--运算符/
__div = function(t1, t2)
return 2
end,
--运算符%
__mod = function(t1, t2)
return 3
end,
--运算符^
__pow = function(t1, t2)
return 4
end,
--运算符==
__eq = function(t1, t2)
return true
end,
--运算符<
__lt = function(t1, t2)
return true
end,
--运算符<=
__le = function(t1, t2)
return false
end,
--运算符..
__concat = function(t1, t2)
return "567"
end
}
--如果要用条件运算符 来比较两个对象
--这两个对象的元表一定要一致 才能准确调用方法
myTable4 = {age = 1}
setmetatable(myTable4, meta4)
myTable5 = {age = 2}
setmetatable(myTable5, meta4)
print(myTable4 + myTable5)
print(myTable4 - myTable5)
print(myTable4 * myTable5)
print(myTable4 / myTable5)
print(myTable4 % myTable5)
print(myTable4 ^ myTable5)
print(myTable4 == myTable5)
print(myTable4 > myTable5)
print(myTable4 <= myTable5)
print(myTable4 .. myTable5)
这是 metatable 最常用的键。
当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 指定的表中去查找。
meta6Father = {
age = 18
}
meta6Father.__index = meta6Father
meta6 = {
--age = 18
}
--__index的赋值 写在表外面来初始化
meta6.__index = meta6
--meta6.__index = {age = 2}
myTable6 = {}
setmetatable(meta6, meta6Father)
setmetatable(myTable6, meta6)
print(myTable6.age) -- 18
--rawget 当我们使用它时 只会去找自己身上有没有这个变量
--myTable6.age = 1
print(rawget(myTable6, "age")) --nil
__index用来对表访问,__newindex 元方法则用来对表更新 。
当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则不进行赋值操作。
--newIndex 当赋值时,如果赋值一个不存在的索引
--那么会把这个值赋值到newindex所指的表中 不会修改自己
meta7 = {}
meta7.__newindex = {}
myTable7 = {}
setmetatable(myTable7, meta7)
myTable7.age = 1
print(myTable7.age)
--rawset 该方法 会忽略newindex的设置 只会该自己的变量
rawset(myTable7, "age", 2)
print(myTable7.age)
利用表和元表的特性,我们可以实现基础的面向对象。
--面向对象实现
--万物之父 所有对象的基类 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)
obj:Move()
print(obj.posX)
local obj2 = GameObject:new()
print(obj2.posX)
obj2:Move()
print(obj2.posX)
--申明一个新的类 Player 继承 GameObject
GameObject:subClass("Player")
--多态 重写了 GameObject的Move方法
function Player:Move()
--注意!!如果用:调用base的Move方法,改变的是元表GameObject中
--的变量,所以需要用 .调用传入自己作为第一个参数
self.base.Move(self)
end
print("****************************")
--实例化Player对象
local p1 = Player:new()
print(p1.posX)
p1:Move()
print(p1.posX)
local p2 = Player:new()
print(p2.posX)
p2:Move()
print(p2.posX)