← 返回首页目录
# Roblox Lua脚本入门指南

**作者:吉祥法师**

## 引言:编程世界的起点

如果你曾经玩过电子游戏,你很可能好奇过这些游戏是如何被创造出来的。一把剑如何在短短几秒内从收鞘状态变为挥舞动作?为什么?流媒体应用如何能够即时播放你选择的电影?我们现在浏览的网站又是如何运作的?答案很简单——代码。

计算机编程是现代生活中不可或缺的一部分,它决定并驱动着我们日常使用的众多技术。然而,并非所有代码都采用相同的书写方式,事实上,存在多种不同的编程语言,即编写代码的不同语法体系。你可能已经熟悉一些编程语言的名称,例如JavaScript或Python。在本教程中,我们将重点介绍Lua——Roblox的官方编程语言,它可用于创建各种不同类型的游戏供玩家体验。

学习编程就像学习任何其他爱好一样——无论是艺术、音乐、体育还是摄影——但对于初学者来说,尤其是对于那些在此之前从未接触过编程的人,知道从何处开始可能是一个巨大的挑战。当我年轻时,找到针对完全没有经验的年轻受众的教程非常困难。尽管网上有大量内容可供学习,但我仍然难以理解这些材料,或者干脆淹没在信息海洋中迷失方向。现在,虽然YouTube和互联网的其他角落仍然有许多适合初学者的学习资源,但我特别整理了这份指南,当你感到困惑或不知道在搜索教程后该往哪里走时,你可以参考这个简洁有序的页面。

从零开始成为一名有经验的程序员绝非易事,这需要大量的努力,更重要的是,需要时间去成为专家。我这样说是因为我个人认识的许多开发者,无论是新手还是专业人士,都倾向于在半途放弃他们的项目或目标。当事物发展不像你预期的那样迅速时,不要失去希望,耐心至关重要。区分优秀学生和普通学生的关键并不一定是智力,而是他们投入工作的意愿以及不断寻求提升自我的方法。

请将本文视为Lua的图例,类似于一本大书中用来突出显示读者可能不认识的特定术语或角色的说明书页。当你完成本指南时,你的编程能力可能仍然有限,但你应该能更容易地理解更高级主题的教程。最终,我希望这篇文章能帮助你起步,或者至少引导你走完编程之旅。

## 基础概念:理解格式与脚本

### 工作区设置

在本教程中,我们将使用特定的格式来编写、输入和接收脚本的结果。要使用与我相同的格式,请点击屏幕左上角的“查看”,然后确保你已经选择并开启了以下设置:属性、资源管理器、命令栏和输出。你的屏幕应该看起来类似于附带的参考图片。

### 创建脚本

脚本几乎可以插入到任何地方。为了保持本教程简洁,请转到顶部面板的“模型”选项,然后浏览到最左侧并点击“脚本”,这将生成一个可用于本教程的脚本。

### 打印(Print)功能详解

Print是一个内置函数,用于打印出你决定提供的任何语句。这可以是数字或字符串,我们将在本节中介绍这些概念。你会注意到,一旦启动脚本,就已经有一个print函数自动为你输入好了。这段代码总是伴随你的脚本出现,因此我们将删除它以继续下一步。

### 字符串(Strings)的使用

以小写字母输入print。如果print输入错误或包含任何大写字母,程序将无法识别该命令并且不会运行它。然后添加一对括号,Studio应该会自动添加第二个括号。确保print和括号之间没有空格,否则Lua将无法读取它。

```lua
print()
```

接下来,我们需要在括号之间添加一个字符串,这样我们就不会打印空白的空间。字符串是指引号内的任何字符或单词,例如“Hello World!”在本教程中,我们将添加字符串“YellowNoobs!”供程序打印。

```lua
print("YellowNoobs!")
```

你可以用任何其他文本替换“YellowNoobs”,只要它在括号内的引号中即可。如果你想在引号中包含引号本身,你也可以使用一对单引号('')并放入双引号,反之亦然。

### 数字与算术运算符(Arithmetic Operators)

Print同样适用于数字和方程式,它会在输出中自动简化结果。但在写出我们的问题之前,我们需要找到正确的符号来得到答案。算术运算符基本上是我们用来表示数字之间关系的工具。这听起来很复杂,但实际上只是我们用来加减乘除数字的符号。

Lua中使用的算术运算符包括:
- **加法**:`+`
- **减法**:`-`
- **乘法**:`*`
- **除法**:`/`
- **指数**:`^`
- **取模(求余数)**:`%`

现在,我们将方程式写在括号内,准备好后将其粘贴到命令栏中以获取输出。你可以随意尝试这些运算符来掌握它们。

```lua
print(1 + 5 * 10^2 / 5 - 20)
```

如果我们把这段代码放入命令栏,我们将得到81。这是方程式的简化版本或答案。Lua之所以这样做,是因为它遵循运算顺序(Order of Operations),即先进行指数运算,然后是除法和乘法,最后是加法和减法。以这段代码为例:

```lua
print(1 + 5 * 2)
```

虽然你可能会倾向于说是12,因为你先把1加5得到6,然后乘以2,但这是错误的。相反,你应该先乘5和2得到10,然后加1得到11。这是数学和编程的共同规则,所以请练习这个概念直到你能够避免打印出错误的数字。

### 连接(Concatenation)

为了将两个或多个单独的值组合在一起,你可以在print函数中使用连接。我们仍然使用相同的格式,但在每个字符串后面添加两个句点或点号。不要将其放在字符串内部,否则Lua会将其解释为字符串的一部分并产生错误。

```lua
print("现在是" .. " 晚上7点")
```

如果我们将其粘贴到命令栏中,输出将显示一个完整的语句,就像它是一个单独的字符串一样,这意味着连接成功了。

## 变量:命名与存储数据

### 变量的本质

既然你已经学会了如何创建脚本,你将要学习什么是变量以及如何创建你自己的变量。变量之所以至关重要,是因为它们可以节省大量时间,使你的脚本更易于审查。变量可以是布尔值、数字、字符串,或者实际上任何你想为其分配名称的东西。如果你难以理解变量这个概念,你可以把它比作你给某个名字过于冗长的人起的绰号。虽然这并非他们的本名,但用绰号称呼他们仍然会引起他们的注意,因为他们已经被这样称呼过。

下面,我给出了一个变量的例子。当我们使用变量时,术语“变量”将与字符串“YellowNoobs!”互换使用。如果我们将变量放在print命令中,它将打印分配给它的文本。由于变量等同于我们分配给它的字符串,我们不需要在变量名周围加引号。如果你在变量名周围放置引号,Lua会将其解释为字符串,并打印实际的名称而不是其值。

```lua
variable = "YellowNoobs!"
print(variable)
```

如果我们复制并粘贴这段代码到输入中,输出将打印我们的语句。

### 全局变量与局部变量

在使用变量之前,你需要先定义它们。由于Lua是从上到下读取代码的,当它执行print函数时,如果变量尚未定义,它将不知道变量代表什么。如果我们把代码粘贴到命令栏,我们会得到输出nil,这意味着没有内容或没有数据。

当我们定义变量时,其作用域覆盖脚本中所有下方的代码。变量作用域只是指变量在脚本中可以访问的时间范围。有两种类型的变量你会经常听到:全局变量和局部变量。到目前为止,我们在本教程中制作的变量都是全局变量,这意味着它们可以在脚本内部的所有下方代码中访问。局部变量将在本教程后面介绍,但简单来说,它们的作用域要有限得多。

### 变量命名规则

变量不一定只能命名为"variable"来分配给特定的代码块。实际上,为了让程序识别脚本中要使用哪个变量,你的变量必须具有不同的名称。虽然你几乎可以自由地命名变量,但在Lua中存在一些限制。

你可以使用:
- 字母
- 数字
- 下划线

你不能使用:
- 大写字母作为变量的第一个字符(虽然不是必需的,但这是常见做法)
- 数字作为变量的第一个字符
- 空格
- Lua保留关键字

保留关键字列表包括:and, break, do, else, elseif, end, false, for, function, if, in, local, nil, not, or, repeat, return, then, true, until, while

## 注释(Comments)

注释是一种简单的绿色文本,用于组织和解释你的代码行,如果你打算分享代码,这对你自己或他人来说非常有用。创建注释非常简单:添加`--`,然后输入你的文本。它应该看起来像这样。如果你希望注释覆盖多行,请在文本前后插入方括号。

任何附加到注释的文本都不会被程序执行,并且只能被读者看到。这种绿色文本非常有用,以防你想在脚本中找到特定的代码片段。如果你打算分享你的脚本并希望读者理解某些命令的作用,注释也至关重要。除了提供上下文外,你还可以使用注释为自己脚本署名,或者写出用户可能想看到的说明。

## 属性(Properties)的修改

如果你想更改工作区中对象的设置(例如透明度或可见性),你必须先写清楚具体细节,然后Lua才知道你想要它做什么。因此,如果我们想改变地板的透明度,我们首先需要定义地板位于game.Workspace中,其中game是我们正在处理的游戏,workspace是地板和我们其余部分存储的位置。然后,我们写出要更改的对象(地板)和要更改的设置(其透明度),然后为其分配一个值。如果我们希望它完全隐形,我们将值设置为1,降低这个值将使其半透明。

```lua
game.WorkSpace.Baseplate.Transparency = 1
```

最终,如果我们运行代码或玩游戏,这将使地板完全不可见。请记住,只要你正确定义了代码中的对象,我们可以在Studio中更改对象的属性。

## 函数(Functions)的结构与使用

当需要重复编写一系列代码时,这可能有点繁琐,也会使代码显得杂乱。函数是Lua中的一种工具,我们可以使用它将不同的代码行放入其中,从而更容易地重复和操纵这些代码。本节中的函数不要与Lua的内置函数(如print)混淆。

### 创建函数

要定义函数,我们需要写`function`,然后为其分配一个名称。接着,在函数名之后添加一对括号,中间不要有任何空格,然后按回车键。我将把这个函数命名为printStuff,但你可以根据自己的喜好命名。

```lua
function printStuff()
end
```

现在,我们需要编写代码来实际执行函数。你会注意到,当你写完函数按回车后,会自动出现`end`。这个语句的作用是让你结束或关闭函数,否则Lua会出错。我想打印几个字符串,所以我将把几段代码插入到我的函数中。

```lua
function printStuff()
    print("Hello World!")
    print("外面是个美丽的晴天。")
    print("我喜欢喝黑咖啡,不加糖或奶。")
end
```

现在我们有了函数,但是,因为我们还没有编写执行它的命令,所以什么都不会发生。我们需要在下一行输入函数名,Lua将打印我们的字符串。

```lua
function printStuff()
    print("Hello World!")
    print("外面是个美丽的晴天。")
    print("我喜欢喝黑咖啡,不加糖或奶。")
end

printStuff()
```

现在,Lua将执行我们的代码。如果我们将所有内容粘贴到命令栏中,我们会看到函数成功执行了。需要注意的是,就像变量一样,函数需要在代码中实际执行之前定义,否则我们只会得到nil。

### 局部变量与代码块

之前我们在教程中介绍局部变量时,我提到它的作用域要有限得多。全局变量可以在定义后的脚本中的任何地方访问,而局部变量仅限于一个块。那么什么是代码块呢?一个例子基本上就是我们在函数中看到的缩进代码序列。

```lua
function printStuff()
    local myVariable = "Hello World!" -- 这是代码块的一部分
    print(myVariable) -- 这也是代码块的一部分
end

print(myVariable) -- 这不在代码块内
```

你还可以通过左侧出现的小箭头来判断某物是否属于一个块。如果你仔细观察,function旁边的向下箭头表示正在显示块,而当它朝上时,表示它已关闭。如果我们在块外尝试打印局部变量,我们会得到nil,因为该变量无法被访问。

### 参数(Parameters)与实参(Arguments)

函数的一个便捷功能是能够轻松操纵变量。你可能已经注意到定义函数时的那对括号,以及执行时的另一对括号。这些是我们放置实参和参数的空间。每当我们执行函数时,我们可能想要每次都更改代码的某些部分。

参数用于告诉Lua你想更改函数内部的哪些变量(以及任何相关信息)。它们在首次定义函数时建立,并放置在同一行的第一对括号之间。确保不要在函数内部定义你要更改的变量,否则参数将无法工作。

```lua
function printStuff(myString)
    print(myString)
end
```

既然我们已经定义了参数,我们需要为函数正确执行编写一个实参。实参是在执行代码时分配给参数的值。它出现在我们的下一对括号内,并且每次单独执行函数时都可以更改。我们将打印一个字符串和一个数字,程序应该将实参视为函数中的变量。

```lua
function printStuff(myString)
    print(myString)
end

printStuff("Hello World!")
printStuff(27)
```

现在如果我们将它放入输出中,这两个值应该成功打印出来。参数和实参不仅限于一对,事实上可以有任意多对。要添加另一对,用逗号分隔每个参数和实参,然后放入函数中。

```lua
function printStuff(weather, time)
    print(weather)
    print(time)
end

printStuff("天气寒冷且下雪", "时间是早上6:30")
```

现在如果我们将其粘贴到命令栏中,输出应该按照我们给出的顺序打印两个语句。重要的是,你必须按照相同的顺序放置实参和参数,否则你会将错误的值分配给变量。此外,当你执行函数时,你总是需要定义参数,否则Lua将不知道将什么分配给变量。

## 本地脚本(Local Scripts)

你可能已经注意到,在创建脚本的选项下方,有一个叫做本地脚本的东西。本教程不会深入介绍它们,但会提供一个关于其目的的总括性总结。本地脚本是只影响用户客户端而非服务器的脚本。用户的客户端基本上是他们所看到的内容,而不是整个服务器。因此,你可能看到某种东西,而你的朋友在玩同一个游戏时可能看到完全不同的内容。相比之下,影响服务器的脚本是所有人都能看到的,而不仅仅是个人的客户端。

## 布尔值(Booleans)与关系运算符

你可能在数学课上听说过这个词,它与此相关。脚本中的布尔值是指条件`true`或`false`。在比较值时,你也会得到布尔值,尽管你也可以直接写true或false。

关系运算符是用于相互比较值的运算符。它们包括:
- **等于**(不要与赋值混淆,赋值只是分配东西而不是比较):`==`
- **不等于**(如果值不相等则为真):`~=`
- **大于**:`>`
- **小于**:`<`
- **大于或等于**:`>=`
- **小于或等于**:`<=`

现在,让我们看一些数字,看看它们代表真还是假的布尔值:
- `4 > 4`:假,因为值只能是大于,而不能等于另一个值。
- `2 == 2`:真,因为两个值彼此相等。
- `8 < 2`:假,因为8不小于数字2。

### If语句的使用

If语句使得特定命令只有在满足条件时才会执行。例如,如果`5 > 1`,输出将打印"Congratulations",因为`5 > 1`为真。如果脚本说`5 < 1`,那么脚本将不会在输出中打印"Congratulations"。

```lua
if 5 > 1 then
    print("Congratulations")
end
```

这等价于写true,并且仍然会打印我们的字符串。

```lua
if true then
    print("Congratulations")
end
```

## 循环(Loops):重复执行代码

有时,我们的代码需要被重复才能产生我们想要的结果。循环是允许我们多次重复代码的语句。它们有几种不同的形式,我们将在本教程的这一部分进行介绍。

### While循环

While循环在条件为真时重复执行代码块。然而,当条件为假时,它不会执行代码块。例如,当一个变量小于某个值时,它会继续打印我们决定赋予它的字符串。这只是你可以用while循环做的无数事情之一,所以如果你雄心勃勃,请随意发挥创意。

对于我们的while循环,我们将为变量x分配一个数字。之后,在下一行写`while`。这有助于Lua理解这是一个while循环,这样当条件为真时,它将执行代码块。你看到的布尔值后面的`do`只是告诉Lua在条件为真时执行属于循环的代码块。

```lua
x = 10
while x < 100 do
    print("该值小于100")
    x = x + 10
end
print("该值不小于100")
```

在这段代码中,我将变量定义为10,并设置while循环持续运行直到它不再小于100。每次运行代码时,我都会让变量增加10,这意味着在运行几次后,由于条件变为假,它将不再执行代码。注意循环结束后打印的字符串。这直到循环完成才被执行,因此将字符串附加到循环外可以用来告诉我们循环何时结束。

### For循环

For循环能够按照用户的意愿循环任意多次。首先,我们为循环定义一个变量,并将其分配给一个起始值和结束值。循环将继续重复,直到起始值达到结束值。默认情况下,起始值每次增加1,但你可以通过在结束值后添加逗号和步长值来更改它。下面是一个for循环的例子。

```lua
for x = 1, 25, 5 do
    print(x)
end
```

我们的循环现在将打印1, 6, 11, 16,一直持续到21,在那里它将停止,因为它无法超过25。以下是for循环的格式:

```
for (变量名) = (起始值), (结束值), (值每次增加的量) do
    (语句)
end
```

### Repeat/Until循环

Repeat循环会重复分配给它的语句,直到后面的条件为真。

```lua
x = 10
repeat
    print("该值小于100")
    x = x + 10
until(x > 100)
print("该值大于100")
```

与while循环不同,它先运行语句,然后检查条件是否为真。

### Break语句

在循环结束时编写`break`,如果条件为真,将结束循环。在下面的例子中,break用于跳出无限循环,否则该循环会因为条件始终为真而持续运行。

```lua
x = 10
while true do
    print("该值小于100")
    x = x + 10
    if x == 100 then
        break
    end
end
print("该值不小于100")
```

如果我们将`while true`替换为`while x < 200`,结果将是循环提前结束,在x达到100而不是200时结束。你可能还会听到术语“嵌套循环”,它用于描述内部包含另一个循环的循环。

## 表(Tables):数据存储结构

表用于存储在创建脚本时可能会使用到的大量数据集。通过表,你可以轻松访问和操作数据,这在以后非常有用。在这一部分,你将学习一种类型的表:数组。

### 数组(Arrays)

数组只是编译在表中的值列表。这可以包括字符串、数字、布尔值、函数——几乎任何可以在脚本外部使用的东西。

构建数组时,首先为表分配一个名称:

```lua
randomArray
```

然后,你需要将数据分配给表。通过在中间添加“=”来将表分配给数据,并写一对大括号(第二个括号会自动为你输入)。

```lua
randomArray = {}
```

接下来,你可以将所有值放入数组中。在本教程中,我们将放置几个字符串和数字,但如果你跟随学习,你可以为你的表添加更多种类。确保用逗号分隔每个值。

```lua
randomArray = {"Hello World", 70, "外面的天气很暖和", 23, 4}
```

如果我们想打印数组的特定部分,我们可以使用索引来获取我们想要的内容。数组中的每个值都有一个索引,即分配给它的数字。第一个值是1,第二个值是2,第三个值是3,依此类推。要打印数组的特定部分,我们将表名放在print函数中,然后在括号中跟上值的索引。

```lua
randomArray = {"Hello World", 70, "外面的天气很暖和", 23, 4}
print(randomArray[1])
```

最终,这应该会在输出中打印出我们的第一个字符串"Hello World"。

## 常见问题解答

### 我还能在哪里学习脚本编写?

**网站推荐:**
- Khan Academy(教授JavaScript,而非Lua)
- Stack Overflow
- Roblox开发者中心
- Lua.org
- Google

**YouTuber推荐:**
- AlvinBlox
- TheDevKing
- Roblox官方(脚本播放列表)
- PeasFactory
- SkeleDotLua

还有许多其他地方可以学习,但上面列出的资源对我学习或适应Lua有帮助。

### 输入和输出之间有什么区别?

输入是给引擎的代码,而输出是接收到的/完成后的命令。例如,`print("YellowNoobs!")`是输入,而`YellowNoobs`是输出。

### 如何阻止作弊者?

阻止作弊者不是一个初学者的问题,它比我们目前讨论的内容要更高级一些。在你的脚本编写生涯中,你会意识到作弊的主要原因是由于脚本编写不佳且薄弱,黑客能够绕过这些脚本。Roblox现在自动应用于所有游戏的一个功能是FilteringEnabled,它可以防止黑客干扰服务器本身。

### 为什么Studio会自动缩进?

从技术上讲,缩进不是必需的,但它非常有帮助,可以保持代码的组织性。例如,通过缩进,你可以看到代码块的边界。不仅如此,它看起来也更加整洁。没有正确缩进编写代码会让你和审阅你代码的程序员在阅读时感到头疼。

### 如何变得更好?

练习,熟能生巧,没有例外。学会独立编写独特的程序是你作为开发者应该始终追求的目标。当你无法解决问题时,第一步不应该是寻求帮助。去开发者维基,去Stack Overflow,去开发者论坛,阅读过去的帖子,并尝试自己解决。你可以一次又一次地寻求帮助,做出一个相当不错的游戏,但如果没有这些人在你身边,你将永远无法复制它,你什么也学不到。有时寻求建议并没有错,但这永远不应该是你采取的第一步。

## 结语

到此为止,基础教程终于完成了!希望现在你能更容易地理解新概念,并在感到困惑时将本文作为参考。如果你还有其他问题或反馈,请在评论中回复,祝你好运!