Minetest的Mod开发教程:【2-Lua脚本】

介绍

在本章中,我们将讨论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

在这个例子中的关键字高亮显示,包括ifthenend ,和return 。默认情况下,Lua随附的功能(如)table.insert 也会突出显示。

非常适合Lua的常用编辑器包括:

  • VSCode -微软开源的ide!使用 Electron开发,开源插件丰富的ide
  • Notepad++ - 只有window可以使用(开源)
  • Atom -开源

也可以使用其他合适的编辑器。

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)

在这个例子中,ab ,和result变量 。通过使用local 关键字声明局部变量,然后给其一个初始值。本地将在后面讨论,因为它是一个非常重要的概念(称为作用域) 的一部分。

= 标志意味着分配(赋值) ,这样result = a + b 的手段设定的值result ,它的值a + b 。如变量所见,变量名可以长于一个字符result 。同样值得注意的是,与大多数语言一样,Lua区分大小写Aa是不同的变量 。

变量类型(数据类型)

变量将是以下类型之一,并且可以在赋值后更改类型。优良作法是确保变量仅是nil或单个非nil类型。

类型 描述 例子
Nil 尚未初始化。变量为空,没有任何值 local A, D = nil
Number 整数或十进制数。 local A = 4
String 字符串。 local D = one two three
Boolean true或false。 local is_true = false, local E = (1 == 1)
Table 集合。 解释如下。
Function 函数(方法)。可能需要输入并可能返回值。 local result = func(1, 2, 3)

算术运算符

Lua的运运算符包括:

Symbol Purpose Example
A + B 2 + 2 = 4
A - B 2 - 10 = -8
A * B 2 * 2 = 4
A / B 100 / 50 = 2
A ^ B 平方 2 ^ 2 = 2x2 = 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之间的随机数。然后显示“ Woohoo!”。如果该数字大于50,则打印“否!”。

逻辑运算符

Lua中的逻辑运算符包括:

Symbol Purpose Example
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为真。

逻辑和算术运算符的工作方式相同;它们都接受输入并返回可以存储的值。例如:

local A = 5
local is_equal = (A == 5)
if is_equal then
    print("Is equal!")
end

程序设计

编程是解决问题的方法,例如对项目列表进行排序,并将其转变为计算机可以理解的步骤。

教给你编程的逻辑过程超出了本书的范围。但是,以下网站在开发此网站时非常有用:

  • 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

相反,可以从脚本文件中的任何位置以及任何其他mod访问全局变量。

function one()
    foo = "bar"
end

function two()
    print(dump(foo))  -- Output: "bar"
end

one()
two()

尽可能使用局部变量。Mod最多只能创建一个与Mod同名的全局变量。创建其他全局变量是草率的编码,Minetest将对此发出警告:

Assignment to undeclared global 'foo' inside function at init.lua:2

若要更正此问题,请使用“本地”:

function one()
    local foo = "bar"
end

function two()
    print(dump(foo))  -- Output: nil
end

one()
two()

请记住,nil表示未初始化 。该变量尚未分配值,不存在或尚未初始化(意味着设置为nil)。

函数是一种特殊类型的变量,但也应设为局部变量,因为其他模块可能具有相同名称的函数。

local function foo(bar)
    return bar * 2
end

要允许mod调用您的函数,您应该创建一个与mod相同名称的表,然后向其中添加函数。该表通常称为API表或命名空间。

mymod = {}

function mymod.foo(bar)
    return "foo" .. bar
end

-- In another mod, or script:
mymod.foo("foobar")

包括其他Lua脚本

建议在mod中包含其他Lua脚本的方法是使用dofile

dofile(minetest.get_modpath("modname") .. "/script.lua")

脚本可以返回一个值,这对于共享私有本地资源非常有用:

-- script.lua
return "Hello world!"

-- init.lua
local ret = dofile(minetest.get_modpath("modname") .. "/script.lua")
print(ret) -- Hello world!

后面的章节将讨论如何最好地为mod拆分代码。