插件编写:Lua
阅读
2022-04-17更新
最新编辑:七年mark
阅读:
更新日期:2022-04-17
最新编辑:七年mark
在这一章节中,我们将会学习用Lua写脚本,并且复习一些你可能会发现的实用技巧。
代码编辑器
只需要一个带语法高亮的编辑器就足以使用Lua写脚本。语法高亮根据术语(关键字)类别来显示不同颜色和字体的文字。该功能可以帮助你找到错误。
function ctf.post(team,msg)
if not ctf.team(team) then
return false
end
if not ctf.team(team).log then
ctf.team(team).log = {}
end
table.insert(ctf.team(team).log,1,msg)
ctf.save()
return true
end
例如,上面代码片段中的关键字将突出显示,例如if、then、end和return。默认情况下,table.insert是Lua附带的函数。<br/>
这里有一些常见的适合Lua的常见编辑器。其他编辑器可以。<br/>
以下是个人推荐的编辑器:
- Windows:Atom,VS Code,Sublime Text,notepad++,GVIM
- Linux:Kate,Gedit,Atom,VS Code,Sublime Text,GVIM,notepadqq
- OSX:Atom, VS Code
- Android:Dcoder,Quoda,DroidEdit,QuickEdit
用Lua写代码
程序流
程序是由一行行的命令组成的。我们称这些为“语句”。程序流是这些语句的执行方式。不同类型的流可以让你跳过或跳到命令集。这里有三种类型流:
- 顺序:只需运行一条接一条的语句,不跳过。
- 选择:根据条件跳过序列。
- 迭代(重复):重复,继续运行相同的语句,直到满足条件为止。
让我们来看看Lua的语句长什么样子:
local a = 2 -- Set 'a' to 2
local b = 2 -- Set 'b' to 2
local result = a + b -- Set 'result' to a + b, which is 4
a = a + 10
print("Sum is "..result)
这里发生了什么?
a和b,和result是变量。使用local声明局部变量,并且给他们初始变量。局部将在稍后讨论,因为它是一个非常重要概念的一部分,叫做范围。<br/>
“=”意思是赋值,所以,result = a + b 也就意味着“result”这个变量的值为 a + b。与数学不同的是,变量名可以变得更长(至少一个字母),就像“result”这个变量名一样。另外值得注意的是,Lua是区分大小写的;“A”与“a”是不同的变量。
变量类型
变量只能是以下类型之一,并且可以在赋值后更改类型。这是一个很好的实践,确保一个变量永远是nil(零)或者是一个单一的非nil(零)类型。<br/>
Type | Description | Example |
---|---|---|
Nil(零) | 没有初始化,这是个值是空的 | local A , D = nil
|
Number(数字) | 一个整数或小数 | local A = 4
|
String(字符串) | 一段文字 | local D = "one two three"
|
Boolean(布尔值) | 真或假 | local is_true = false , local E = (1 == 1)
|
Table(列表) | 列表 | 后面会提到的 |
Function(函数) | 可执行,可能需要输入几个值(至少一个)或者输出一个值 | local result = func(1, 2, 3)
|
算术运算符
这不是一个详尽的清单,不包含所有可能的运算符。<br/>
符号 | 意义 | 例子 |
---|---|---|
A + B | 加 | 2 + 2 = 4 |
A - B | 减 | 2 - 10 = -8 |
A * B | 乘 | 2 * 2 = 4 |
A / B | 除 | 100 / 50 = 2 |
A ^ B | 平方 | 2 ^ 2 = 22 = 4 |
A .. B | 拼字符串 | "foo" .. "bar" = "foobar" |
判断
最基本的判断就是if语句。它看起来像这样:
local random_number = math.random(1, 100) -- Between 1 and 100.
if random_number > 50 then
print("Woohoo!")
else
print("No!")
end
这个例子是生成1-100的随机数。如果这个数字大于50,他就会打出“Woohoo!”,否则就会打出“No!”。除了“>”你还能得到什么?
逻辑运算符
它不包含所有可能的运算符,您可以组合如下运算符:
符号 | 意义 | 例子 |
---|---|---|
A == B | 等于 | 1 == 1 (true), 1 == 2 (false) |
A ~= B | 不等于 | 1 ~= 1 (false), 1 ~= 2 (true) |
A > B | 大于 | 5 > 2 (true), 1 > 2 (false), 1 > 1 (false) |
A < B | 小于 | 1 < 3 (true), 3 < 1 (false), 1 < 1 (false) |
A >= B | 大于等于 | 5 >= 5 (true), 5 >= 3 (true), 5 >= 6 (false) |
A <= B | 小于等于 | 3 <= 6 (true), 3 <= 3 (true) |
A and B | 和(两者都必须要符合) | (2 > 1) and (1 == 1) (true), (2 > 3) and (1 == 1) (false) |
A or B | 二选一,只要符合一个条件即可 | (2 > 1) or (1 == 2) (true), (2 > 4) or (1 == 3) (false) |
not A | 相反 | not (1 == 2) (true), not (1 == 1) (false) |
if not A and B then
print("Yay!")
end
当A和B的值为真为时,就会输出“Yay!”<br/>
逻辑运算符和算术运算符的工作原理完全相同;它们都接受输入并返回一个可以存储的值。
local A = 5
local is_equal = (A == 5)
if is_equal then
print("Is equal!")
end
编程
编程是一种处理问题的动作,如对项目列表进行排序,然后将其转换为计算机可以理解的步骤。<br/>
教你编程的逻辑过程超出了本书的范围;但是,以下网站在开发这个过程中非常有用(当然如果你有一定的Lua编程基础,你可以直接看下一部分的内容。当然如果你有其他编程语言的基础,译者本人建议建议也学一下Lua。):
- Codecademy是学习“编码”的最佳资源之一,提供了交互式教程体验。
- Scratch是一个很好的资源,当从绝对的基础开始,学习解决问题所需的编程技巧。
Scratch的目的是教孩子们如何编程,而不是一种严肃的编程语言。
- 菜鸟教程(译者自己补充上去的):个人极力推荐,提供了大量的在线实例。该网站致力于推广各种编程语言技术,所有资源是完全免费的,并且会根据当前互联网的变化实时更新本站内容。
本地和全局范围
变量是局部变量还是全局变量决定了它可以写入或读取的位置。局部变量只能从定义它的位置访问。举个例子:
-- Accessible from within this script file
local one = 1
function myfunc()
-- Accessible from within this function
local two = one + one
if two == one then
-- Accessible from within this if statement
local three = one + two
end
end
而全局变量可以从脚本文件中的任何位置访问,也可以从任何其他模组访问。
my_global_variable = "blah"
function one()
my_global_variable = "three"
end
print(my_global_variable) -- Output: "blah"
one()
print(my_global_variable) -- Output: "three"
尽量使用本地变量
Lua在默认情况下是全局的(与大多数其他编程语言不同)。局部变量必须这样标识。
function one()
foo = "bar"
end
function two()
print(dump(foo)) -- Output: "bar"
end
one()
two()
dump()是一个函数,它可以将任何变量转换为字符串,以便程序员可以看到它是什么。foo变量将被打印为“bar”,包括显示它是字符串的引号。<br/>
这是草率的编码,事实上,Minetest将对此发出警告:
Assignment to undeclared global 'foo' inside function at init.lua:2
要更正此问题,请使用“local”:
function one()
local foo = "bar"
end
function two()
print(dump(foo)) -- Output: nil
end
one()
two()
请记住,nil表示不初始化。变量尚未赋值、不存在或未初始化(即:设置为零)。<br/>
函数也是如此。函数是一种特殊类型的变量,应该设置为局部的,因为其他模组可以有同名的函数
local function foo(bar)
return bar * 2
end
应该使用API表来允许其他mod调用函数,例如:
mymod = {}
function mymod.foo(bar)
return "foo" .. bar
end
-- In another mod, or script:
mymod.foo("foobar")
包含其他Lua脚本
如果要在模组中包含其他Lua脚本,推荐使用dofile。
dofile(minetest.get_modpath("modname") .. "/script.lua")
在脚本文件的任何函数之外声明的“local”变量将是该脚本的本地变量。脚本可以返回一个值,该值对于共享私有局部变量非常有用:
-- script.lua
return "Hello world!"
-- init.lua
local ret = dofile(minetest.get_modpath("modname") .. "/script.lua")
print(ret) -- Hello world!
后面的章节将详细讨论如何分割mod的代码。不过,目前最简单的方法是为不同类型的事物(nodes.lua、crafts.lua、craftitems.lua等)创建不同的文件。