Cover

Cover

Studio 简介

Roblox 基本上所有的资源都存储在云端,也就是说如果你想使用 Studio , 就需要你的计算机保持联网状态,这一点与大多数软件开发 IDE 都不同。打开 Roblox Studio 首先会进行自动更新,和登录操作,更新和登录完成后才可以正常使用 Roblox Studio。关于中国版 Roblox 卡在登录界面的问题,在 这篇博客里给出了解决方案。

image-20211114193025061Roblox Studio 的主界面

我这里 Studio 的语言为中文,主题为暗色主题,其他相关配置项都可以在 Studio 的设置中进行更改。

image-20211114193901652Alt + s 进入设置界面

接下来我们打开 Studio 的 Village 模板,来介绍 Studio 的相关界面。

image-20211114195213020主界面的组成部分

游戏主界面 中点击一个对象后,项目管理器中就会高亮显示这个对象,并且在项目管理器下面的对象属性中会展示这个对象的属性。

image-20211114195517027

如果你的界面上没有显示某些窗口,可以在菜单栏中的 视图 对相应窗口进行开关。其中高亮的部分是已经显示的窗口,点击即可取消该窗口的显示。相应的,点击没有高亮的选项,可以显示相应的窗口。

image-20211114200242451

下面介绍相机的基本操作:

  1. 按住鼠标右键可以左右移动视角,对应键盘的 ,.

    zuoyou

  2. 使用鼠标滚轮可以前后移动相机,对应键盘的或者ws 使用鼠标滚轮移动时,会朝着鼠标指针的位置移动。

    qianhou

  3. 按住鼠标滚轮拖动可以上下左右平移相机,对应键盘快捷键是QEAD

    pingyi

  4. 按住 shift + QWEASD 会降低镜头移动速度。

  5. 点击一个目标对象,按f可以聚焦到这个对象(镜头中心是这个对象),这个时候进行右键旋转和鼠标滚轮滚动,都会以这个目标为中心,如果上下移动或者左右移动,则会自动退出聚焦模式。

    jujiao

关于对象的创建,缩放,和旋转操作,在这篇博客里已经有过了相应介绍,此处不再举例。

Studio Introduction

Almost all of Roblox’s resources are stored in the cloud, which means if you want to use Studio, your computer needs to stay connected to the internet. This is different from most software development IDEs. When you open Roblox Studio, it will first perform an automatic update and then a login; only after both are complete can you use Roblox Studio normally. For the issue of the Chinese version of Roblox being stuck on the login screen, this blog post provides a solution.

image-20211114193025061The main interface of Roblox Studio

My Studio’s language is set to Chinese and the theme is dark; other related settings can be changed in Studio’s settings.

image-20211114193901652Press Alt + s to open the settings

Next, let’s open the Village template in Studio to introduce the relevant interface elements.

image-20211114195213020Components of the main interface

After clicking an object in the game main interface, the Explorer will highlight that object, and the object’s properties will be shown in the Properties panel below the Explorer.

image-20211114195517027

If some windows are not shown on your interface, you can toggle them via View in the menu bar. The highlighted entries are windows that are currently shown; click them to hide them. Conversely, click an unhighlighted entry to show the corresponding window.

image-20211114200242451

Here are the basic camera operations:

  1. Hold the right mouse button to rotate the view left and right, corresponding to the , and . keys.

    zuoyou

  2. Use the mouse wheel to move the camera forward and backward, corresponding to the and keys or w and s. When moving with the mouse wheel, the camera moves toward the position of the mouse pointer.

    qianhou

  3. Hold and drag the middle mouse button to pan the camera up, down, left, and right, with the keyboard shortcuts QEAD.

    pingyi

  4. Holding shift + QWEASD reduces the camera movement speed.

  5. Click a target object and press f to focus on it (the object becomes the center of the camera). Rotating with the right button or scrolling the mouse wheel will then center on that target; if you move up/down or left/right, focus mode is automatically exited.

    jujiao

The creation, scaling, and rotation of objects have already been covered in this blog post, so no examples will be repeated here.

部件属性

由于在 Studio 的编辑模式下,物理运算的有些内容是不更新的,部件的某些属性需要在程序运行时才能体现出来。所以在介绍部件属性之前,先介绍一下运行游戏测试的相关按钮和功能。

Roblox 游戏采用 客户端/服务器 模式,通常许多客户端连接到同一个服务器。每一名玩家对应一个客户端。在 Studio 的 测试 选项卡中可以选择玩家的数量。

image-20211114234712236

当选择 2 名玩家时,点击启动后就会额外启动 3 个 Roblox Studio,其中一个是服务器,两个客户端。服务器与客户端的区别是服务器可以使用自由相机来观察世界,而在客户端这里相机是与玩家绑定的。

image-20211114235007294

image-20211114235026005服务器视角

image-20211114235137222玩家1视角

image-20211114235216891玩家2视角

开始游戏按钮会启动一个客户端和一个服务器,默认为客户端视角,玩家会在重生点的任意位置随机出现。

image-20211114235519399启动一个客户端

image-20211114235620374点击可以切换到服务器视角

重生点就是一个特殊的部件,类型名是SpawnLocation

我们可以在模型中点击 重生点 来插入部件,当然,插入部件的方式有很多,具体可以看这篇博客

image-20211115000229660

接下来介绍部件的常用属性。官方文档会有更详细的介绍。

插入部件时可以选择部件的形状,包括方块、球体、楔形和圆柱。

image-20211117140603903

其对应的是部件的 Shape 属性。楔形部件和其他形状部件有所不同,楔形部件有其独立的属性。新插入的部件会默认插入在屏幕中央,所以,在你决定要插入部件的时候,请调整相机使其对准地面,如果相机对着天空插入部件的话,部件会被插入在很远的地方。

image-20211117140801786

接下来我们介绍部件的属性列表。

首先时颜色,颜色的属性包含 BrickColor 和 Color,这两个属性都可以修改部件的颜色,为什么会有两个属性呢,这里面包含一个 Roblox 的历史原因,几年前,Roblox 还只有一个 BrickColor 属性,只可以从弹出的选项中选择颜色。

image-20211117141329438

后来,想要加入更多颜色选项,实现可以自定义颜色数值,但是已经有许多脚本使用了 BrickColor 属性,就只能新增加一个 Color 属性。现在这两个属性几乎没有区别了。

Material 材质属性,里面包含 10 几个内置的材质可供选择,在使用不同的材质后,不仅可以改变部件的外观,还会修改部件的物理属性,比如表面摩擦力和弹性之类的。如果要修改默认的物理属性,需要勾选下面的 CustomPhysicalProperties,然后修改出现的子属性。

image-20211117142439526

Reflectance 反射,调高之后会混合天空的颜色,这个属性只对 塑料 、光滑塑料和玻璃生效。不推荐大家用这个属性,因为效果比较假,以后很可能被弃用。

image-20211117142814913

Transparency 透明度。其中 0 表示不透明 1表示全透明。

ClassName 类型名,如果想使用脚本创建一个对象,就需要知道它的类型名。

Part Properties

Because some physics calculations are not updated in Studio’s edit mode, certain part properties only take effect when the game is running. So before introducing part properties, let’s first introduce the buttons and functions for testing the game.

Roblox games use a client/server model, where usually many clients connect to the same server. Each player corresponds to one client. The number of players can be selected in the Test tab of Studio.

image-20211114234712236

When 2 players are selected, clicking start will launch 3 additional Roblox Studio instances: one server and two clients. The difference between the server and the clients is that the server can use a free camera to view the world, while on a client the camera is bound to the player.

image-20211114235007294

image-20211114235026005Server view

image-20211114235137222Player 1 view

image-20211114235216891Player 2 view

The Play button starts one client and one server, with the client view by default; players spawn at a random location at the spawn point.

image-20211114235519399Starting one client

image-20211114235620374Click to switch to the server view

A spawn point is a special part with the ClassName SpawnLocation

We can insert parts by clicking SpawnLocation in the model; of course, there are many ways to insert parts — see this blog post for details.

image-20211115000229660

Next, let’s introduce the commonly used properties of parts. The official documentation has more detailed information.

When inserting a part, you can choose its shape, including Block, Ball, Wedge, and Cylinder.

image-20211117140603903

This corresponds to the part’s Shape property. Wedge parts are different from other shapes and have their own independent properties. Newly inserted parts are placed at the center of the screen by default, so before inserting a part, adjust the camera to aim at the ground — if you insert while the camera faces the sky, the part will be inserted very far away.

image-20211117140801786

Now let’s introduce the list of part properties.

First, color. The color properties include BrickColor and Color; both can change a part’s color. Why are there two properties? There’s a historical reason in Roblox: several years ago, Roblox only had the BrickColor property, which only allowed choosing colors from a popup list.

image-20211117141329438

Later, they wanted to add more color options and allow custom color values, but many scripts already used the BrickColor property, so a new Color property was added. Nowadays there is almost no difference between the two.

The Material property contains more than 10 built-in materials to choose from. Using different materials not only changes the appearance of the part but also its physical properties, such as surface friction and elasticity. To modify the default physical properties, check CustomPhysicalProperties below and edit the sub-properties that appear.

image-20211117142439526

Reflectance reflects the sky color when increased; this property only affects Plastic, Smooth Plastic, and Glass. It’s not recommended to use this property because the effect looks fake and it will likely be deprecated in the future.

image-20211117142814913

Transparency: 0 means fully opaque and 1 means fully transparent.

ClassName is the type name. If you want to create an object with a script, you need to know its type name.

1
Instance.new("Part")

Name 是当前对象的名字,也是资源管理器中显示的名字,可以修改 Name 属性为部件重命名。

Parent 是当前对象的父对象。

Transform 属性列表下包含的是属性的位置及大小属性。

Anchored 这个属性需要在运行游戏时才能看出区别,勾选了 Anchored 属性后,部件可以悬停在半空中,取消勾选后,部件会由于重力的原因落到地上。

maozhu

CanCollide 是否可以与其它物体发生碰撞,true 表示可以 ,false 表示不可以。当我们的部件既没有勾选 CanCollide 属性 也没有勾选 Anchored 属性时,开始游戏后部件就会消失,准确的说时落到地面上由于不可碰撞又会继续下落。

pengzhuang

CollisionGroupId 碰撞组。我们可以给每个部件设置不同的分组,然后设定哪些组之间可以发生碰撞。这个属性只是设置 Id ,具体实现哪些组可以发生碰撞需要在脚本中实现。

Locked ,勾选后我们无法用鼠标在场景中选中部件,但是我们依然可以在资源管理器中选中部件。

Name is the name of the current object and also the name shown in the Explorer; you can rename a part by modifying the Name property.

Parent is the parent object of the current object.

Under the Transform property are the position and size properties.

The Anchored property only shows a difference when the game is running. With Anchored checked, the part can hover in mid-air; unchecked, the part falls to the ground due to gravity.

maozhu

CanCollide determines whether it can collide with other objects: true means yes, false means no. When our part has neither CanCollide nor Anchored checked, the part will disappear after the game starts — to be precise, it falls to the ground and, being non-collidable, keeps falling.

pengzhuang

CollisionGroupId is the collision group. We can assign different groups to each part, then set which groups can collide with each other. This property only sets the Id; implementing which groups can collide requires scripting.

Locked: when checked, we cannot select the part with the mouse in the scene, but we can still select it in the Explorer.

脚本基础

要使用 Roblox 脚本需要创建脚本对象,Roblox 有三种脚本对象,Script、LocalScript 和 ModuleScript ,我们使用 Script 来演示脚本的编写,其他两种脚本对象与 Script 的语法都是相同的,只是运行的位置不同。Roblox 使用的时 Lua 脚本的语法。

我们在 WorkSpace 下新建一个 Script 对象,Studio 会自动写上第一行代码。当我们运行游戏就会在输出栏打印相关内容。

image-20211117150434713

服务器脚本需要放在 WorkSpace 或者 ServerScriptService 目录下才会被自动执行,放在其他位置是不会自动执行的。

如果不想脚本立即运行,可以把写好的脚本放在 ServerStorage 下,这里是专门用来存放预先制作好的对象的。

所有语言的基础内容都大致相似,这里重点介绍一下 Lua 和 Python 语法上的一些区别。

Scripting Basics

To use Roblox scripts, you need to create a script object. Roblox has three types of script objects: Script, LocalScript, and ModuleScript. We’ll use Script to demonstrate script writing; the syntax of the other two is the same as Script’s, only the place they run differs. Roblox uses the Lua scripting language.

When we create a new Script object under WorkSpace, Studio automatically writes the first line of code. When we run the game, the relevant output is printed in the Output panel.

image-20211117150434713

Server scripts are only executed automatically when placed under WorkSpace or ServerScriptService; placing them elsewhere means they won’t run automatically.

If you don’t want a script to run immediately, you can place the finished script under ServerStorage, which is specially used to store pre-made objects.

The fundamentals of all languages are roughly similar; here we focus on some syntax differences between Lua and Python.

字符串连接

Lua 中使用 .. 来连接字符串。

String Concatenation

In Lua, .. is used to concatenate strings.

1
a = "Hello " .. 'Lua'

Table 类型

Table 类型是一种表结构,是一种键值对的类型,类似于 Python 中字典和列表的整合。

Table 类型的初始化使用一对大括号 {}

Table 中可以保存很多变量,每个变量使用一个 key 来索引,key 可以是数字,也可以是字符串。索引方式可以使用中括号的方式,但是需要注意,中括号中的数字 1 和字符 1 是不相等的两个数值。当 key 是合法的变量名的时候,也可以使用 . 来进行索引。

Table 类型变量中不仅可以存放普通的变量,还可以存放函数。

Table Type

The Table type is a table structure, a key-value type similar to a combination of Python dictionaries and lists.

A Table is initialized with a pair of curly braces {}.

A Table can store many variables, each indexed by a key; a key can be a number or a string. Indexing can be done with square brackets, but note that the number 1 and the character 1 in brackets are two different values. When the key is a valid variable name, . can also be used for indexing.

Table type variables can store not only ordinary variables, but also functions.

1
2
3
4
5
6
t = {}
t[1] = 123
t["1"] = 222
t["Name"] = "lua"
print(t)
print(t[1],t['1'],t.Name) -- T.Name 和 t["Name"] 是等价的

image-20211117151924341

Roblox 中所有的对象都是 Table 类型,当我们想获得某个对象的引用时,可以通过Table 索引的方式来获得对象的引用。例如

image-20211117151924341

All objects in Roblox are of the Table type. When we want to get a reference to an object, we can do so through Table indexing. For example

1
2
3
4
5
6
7
8
p = game.Workspace.Baseplate.Position
print(p)
-- 也可以使用 [] 的方式进行索引
pp = game["Workspace"]["Baseplate"]["Position"]
print(pp)
-- 混合使用两种方式
ppp = game.Workspace["Baseplate"].Position
print(ppp)

image-20211117153017767

函数

函数定义的两种方式

  1. [作用域] 函数名 = function(参数列表)
  2. [作用域] function 函数名(参数列表)

image-20211117153017767

Functions

Two ways to define a function

  1. [Scope] FunctionName = function(parameter list)
  2. [Scope] function FunctionName(parameter list)
1
2
3
4
5
6
7
8
9
10
11
12
13
a = 10
b = '15'

local add = function(a,b)
return a + b -- 当字符串与数字相加减时 Lua 会首先尝试把字 符串转 换为 数值类型
end

local function sub(a,b)
return b - a
end

print(add(a,b))
print(sub(a,b))

image-20211117153810726

当 Table 类型变量进行函数参数传递时,会发生 地址传递

image-20211117153810726

When a Table type variable is passed as a function argument, pass by reference occurs

看示例代码:

Look at the example code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
local a = 10 -- 定义局部数值类型变量
local t = {} -- 定义局部 Table 类型变量
t.Name = "lua" -- 修改 Table 类型变量的内容
t["Friend"] = "C"

local function test(a,t)
-- 函数接收两个参数 第一个参数赋值为一百,修改第二个参数的值
a = 100
t.Name = "lualualua"
t.Friend = "C++"
end

test(a,t) -- 调用 test 函数

print(a) -- test 函数没有修改当前作用域下 a 的值
print(t.Name) -- test 函数修改了 t 的内容
print(t.Friend)

image-20211117184334988

在函数执行过程中,形参的 a 和 实参的 a 不是相同的内存空间,因此修改实参的 a 不会改变实参 a 的值。此过程类似于 C++ 中的值传递,在调用函数时,系统会再声明一个变量用来接收 a 。但是由于 Table 类型的变量有可能很大,当 Table 类型的变量作为参数传递时,不会重新声明一个变量来进行值的拷贝,而是直接修改该变量的值,类似于 C++ 中的地址传递。

在 Roblox 中,函数很大的一个作用是用来连接部件的事件。例如,如果我们想实现对部件的点击操作。我们首先应该在部件下新建一个 ClickDetector 对象,在 ClickDetector 对象下新建一个脚本,用来实现点击事件。

image-20211117191123273

ClickDetector官方文档中,可以找到鼠标点击事件,我们在脚本中将鼠标点击事件与我们的函数绑定起来。

image-20211117191630628

image-20211117184334988

During function execution, the formal parameter a and the actual argument a do not share the same memory space, so modifying the formal parameter a does not change the value of the actual argument a. This process is similar to pass-by-value in C++: when calling a function, the system declares another variable to receive a. However, because Table type variables can be very large, when a Table type variable is passed as an argument, no new variable is declared to copy the value; instead the variable’s value is modified directly, similar to pass-by-reference in C++.

In Roblox, one major use of functions is to connect part events. For example, if we want to implement a click operation on a part, we should first create a ClickDetector object under the part, and then create a script under the ClickDetector object to implement the click event.

image-20211117191123273

In the ClickDetector official documentation, we can find the mouse click event, and in the script we bind the mouse click event to our function.

image-20211117191630628

1
2
3
4
5
function onclick(player)
print("You clicked")
end

script.Parent.MouseClick:Connect(onclick) --MouseClick 使用冒号的方式调用 Connect 函数

click

连接事件也可以使用匿名函数,像下面这样,也可以实现相同的功能。

click

Events can also be connected using anonymous functions, like below, achieving the same result.

1
2
3
script.Parent.MouseClick:Connect(function onclick(player)
print("You clicked")
end)

使用冒号和点的区别。

The difference between using the colon and the dot.

在上面的例子中,我们使用冒号来调用 Connect 函数,冒号的点的区别在于:使用冒号调用函数默认传入函数的第一个变量是 函数调用者本身。

In the example above, we used the colon to call the Connect function. The difference between the colon and the dot is that calling a function with a colon passes the function caller itself as the first argument by default.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
local t = {}

t.Name = "Lua"
t.Value = 1
t.add_func = function(tab) -- 在 Table 类型变量中加入函数
tab.Value += 1
end

t.add_func(t) -- 使用点的方式调用函数,函数的参数需要传入自身

print(t.Value) -- 2

t:add_func() -- 使用冒号的方式调用函数

print(t.Value) -- 3

image-20211117193736265

于是,上面例子中的鼠标点击事件就可以重写成如下代码。

image-20211117193736265

So the mouse click event in the example above can be rewritten as the following code.

1
2
3
4
5
6
7
8
function onclick(player)
print("You clicked")
end

-- script.Parent.MouseClick:Connect(onclick)

script.Parent.MouseClick.Connect(script.Parent.MouseClick,onclick)
-- 代码更长了,所以还是使用冒号的方式更加方便。

我们除了在调用函数时可以使用冒号,在写函数体的时候也可以使用冒号。

Besides using the colon when calling functions, we can also use it when writing function bodies.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
local t = {}

t.Name = "Lua"
t.Value = 1

--t:add_func = function() -- 这种方式是错误的
-- self.Value += 1
--end

function t:add_func() -- 使用冒号来实现函数体,此时函数默认传入的第一个参数为 self
self.Value += 1
end

t.add_func(t) -- 使用点的方式调用函数,函数的参数需要传入自身

print(t.Value) -- 2

t:add_func() -- 使用冒号的方式调用函数

print(t.Value) -- 3

基本上所有 Roblox 对象上的函数都需要使用冒号来调用,因为这些函数都需要获取对象本身的一些参数。

Basically, all functions on Roblox objects need to be called with a colon, because these functions need to access some parameters of the object itself.

全局变量和局部变量

在变量声明时,不加 local 关键字则默认声明为全局变量,全局变量在整个程序运行时任何一个地方都可以使用,局部变量则只可以在当前代码块中使用。最大的代码块就是脚本文件本身,其次,你每看见一个 end 关键字就标志着一个代码块的结束,比如一个函数就是一个代码块。

使用局部变量的好处:

  1. 避免命名冲突
  2. 存取速度块
  3. 方便阅读代码,当你读到一个 local 关键字的变量时,你可以马上意识到,这个变量只在当前代码块有用。

下面的例子来展示全局变量和局部变量在使用上的区别。

Global and Local Variables

When declaring a variable, if you don’t add the local keyword, it is declared as a global variable by default. Global variables can be used anywhere during the whole program run, while local variables can only be used in the current code block. The largest code block is the script file itself; moreover, every end keyword you see marks the end of a code block, for example a function is a code block.

Benefits of using local variables:

  1. Avoid name conflicts
  2. Faster access
  3. Easier to read code: when you see a variable with the local keyword, you immediately know that this variable is only useful in the current code block.

The following example shows the difference between global and local variables in use.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
local a = 10

local f = function(param) -- 函数的实参是局部变量
print(a,param)

c = function() -- 此处的 c 是全局变量,因此可以在当前代码块外继续使用
end
local d = 1000
end

local b = 100

f(b)

print(param,c) -- nil function: 0x48b06e735faff19b
-- param 是函数实参,属于局部变量,在作用域外部无法使用。或者说当前代码块中没有 param 这个变量

print(d) -- nil
-- 同理 d 是被声明在函数内部的局部变量,在函数外部无法使用

使用 do … end 可以生成代码块,防止命名冲突。

Using do … end creates a code block and prevents name conflicts.

1
2
3
4
5
6
7
do
local a = 10
end

do
local a = 100
end

Roblox 中的全局变量和正统的 Lua 中的全局变量有所不同,即使变量声明为全局变量,在其他脚本文件中依然无法使用。

Global variables in Roblox differ from those in vanilla Lua: even if a variable is declared as global, it still cannot be used in other script files.

循环语句

循环语句有三种基本形式。

Loop Statements

There are three basic forms of loop statements.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
local a = 0

-- while 循环
while a < 10 do
print(a)
a += 1
end

-- repeat until
repeat
a = a + 1
until a >= 10


for i = 1,10,1 do -- 1,10,1 从 1 开始 到 10 结束 步长 是 1
print(i)
end

使用 for 循环遍历 table。

Using a for loop to iterate over a table.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
local arr = {"WANG","GUANG","XIN"} -- 数组类型
local dic = {WANG = 1,GUANG = 2,XIN = 3} -- 字典类型
-- 虽然一个表里可以同时有这两种方式进行索引,但是不推荐大家这么做,因为很多内置函数是假设你的 Table 是数组或者字典的。

-- 针对数组的 for 循环
for i = 1,#arr do -- 数组索引从1开始,#数组名 可以获得数组的长度
print(arr[i])
end

for index,value in ipairs(arr) do -- ipairs 每次返回数组索引和值
print(arr[index],index,value)
end

-- 针对字典的 for 循环
for key,value in pairs(dic) do
print(dic[key],value)
-- dic.key 这样是不对的,使用点的方式,点后面不能是变量 如果索引是变量 只能dic[key]
end

image-20211117204150188

不同脚本间的数据共享

前面提到过 Roblox 的脚本中全局变量也无法被其他脚本文件使用,这里介绍不同脚本间数据共享的几种方法。

image-20211117204150188

Data Sharing Between Scripts

As mentioned earlier, even global variables in Roblox scripts cannot be used by other script files. Here we introduce several ways to share data between different scripts.

  1. 存储在 Roblox 的对象里

这种方法适用于一个简单的数据,比如一个数值、字符串之类的。

首先点击 Workspace 创建一个 value 对象。

搜索 value 可以出现以下几种对象。

image-20211117204557282

我们创建一个 IntValue 对象,顾名思义这个对象就是用来存储整数数据的,比如 Boss 的血量等等。

image-20211117204803251

我们可以在不同脚本中修改这个 Value 对象的 Value 属性,可以修改这个对象的 Name 属性方便理解这个值的作用,比如修改成 HP 等等。

接下来我们可以在其他脚本文件中对这个 Value 对象进行操作。

  1. Store in a Roblox object

This method is suitable for a simple piece of data, such as a number or a string.

First, click Workspace and create a value object.

Searching for “value” gives the following objects.

image-20211117204557282

We create an IntValue object, which, as its name implies, is used to store integer data, such as a Boss’s HP.

image-20211117204803251

We can modify the Value property of this Value object in different scripts, and modify its Name property to make the purpose of the value clear, e.g., rename it to HP.

Next, we can operate on this Value object in other script files.

1
2
3
4
5
6
7
8
9
10
11
local HP = game.Workspace:WaitForChild("HP") 
-- 这里我们使用 WaitForChild 是为了防止脚本执行时 Value 对象还没有被创建导致的程序出错。
-- local HP = game.Workspace.HP 这种方式 需要先创建了 HP 对象,再执行脚本对象才不会出错。


-- 每隔 1 秒钟打印以下 HP 的值 并且使其减一
for i = 1,100 do
print(HP.Value)
HP.Value -= 1
wait(1)
end
  1. 使用全局表

在 Lua 里有个特殊的表,名字是 _G 。这个表里存了一些对 Lua 比较重要的东西,比如一些内置函数。

我们可以把需要共享的变量存储在这个表里,这样所有脚本之间都可以使用这个变量。为了避免与 _G 表内已经存在的内容出现冲突,我们可以在 _G 表下创建一个表,用来专门存储我们自己声明的变量。

  1. Use a global table

In Lua, there is a special table named _G. It stores some things important to Lua, such as built-in functions.

We can store the variables we need to share in this table, so that they can be used across all scripts. To avoid conflicts with existing content in the _G table, we can create a table under _G specifically for variables we declare ourselves.

1
2
3
4
_G.MyValues = {}
_G.MyValues.HP = 1000

print(_G.MyValues.HP)

使用这种方法共享数据可能出现一个问题,由于脚本之间的执行顺序是不确定的,比如你想实现第一个脚本写入数据,第二个脚本读取数据,但实际上脚本的执行顺序是相反的,可能会读到一个不存在的数据。因此,使用这种方式共享数据还需要编写其他的逻辑来加以控制。

另外,Roblox 客户端和服务器的全局表是不同的,这种方法不能在客户端和服务器之间共享数据。

  1. 使用 ModuleScript 对象

Sharing data this way may have a problem: the execution order of scripts is nondeterministic. For example, you want the first script to write data and the second to read it, but the actual execution order may be reversed, and a nonexistent value may be read. Therefore, using this method requires additional logic to control the flow.

In addition, the global tables of the Roblox client and server are different, so this method cannot share data between client and server.

  1. Use a ModuleScript object

ModuleScript 自己单独存在的时候并不会运行,你需要在别的脚本中调用它,他才会执行。在 ServerScriptService 中新建一个 ModuleScript 对象。

image-20211117223039180

Studio 会为我们自动生成两行代码。

image-20211117223152478

我们把 Boss 的信息存在这个文件的表内。

A ModuleScript does not run by itself; it only executes when you require it from another script. Create a ModuleScript object in ServerScriptService.

image-20211117223039180

Studio automatically generates two lines of code for us.

image-20211117223152478

We store the Boss’s information in a table in this file.

1
2
3
4
5
6
7
8
9
10
local Boss = {}

Boss.HP = 1000
Boss.Name = "Lua"

Boss.shou_shang = function(Boss)
Boss.HP -= 1
end

return Boss

然后在用到的地方先执行 require 函数,然后就可以操作这个表了。

Then, wherever you need it, call the require function first, after which you can operate on the table.

1
2
3
4
5
6
7
local Boss = require(game.ServerScriptService:WaitForChild("ModuleScript"))

while Boss.HP > 0 do
print(Boss.HP)
Boss:shou_shang()
wait(0.5)
end

以上就是我关于 Roblox 所了解的全部内容了🚩

更多精彩内容请自行查阅官方文档

如果你足够细心的话,你会发现下面有个按钮在闪光😉

i-am-not-interested-in-money

That’s everything I know about Roblox 🚩

For more great content, please check the official documentation

If you’re observant enough, you’ll notice there’s a button flashing below 😉

i-am-not-interested-in-money