重复使用代验证码

*此内容使用人工智能(Beta)翻译,可能包含错误。若要查看英文页面,请点按 此处

创建了几个脚本后,在你想要重复使用它们之间的代码之前,从来没有那么久。根据 位置ModuleScripts 让你在客户端-服务器边界的不同侧或同一侧之间重复使用代码。

你可以将模块脚本放在任何你放置脚本的地方,但 ReplicatedStorage 是一个受欢迎的位置;将模块脚本放在这里可以让你在服务器和客户端之间重复使用代码。

模块脚本的解剖学

在 Roblox Studio 中,将模块脚本添加到 ReplicatedStorage 并重命名为 PickupManager 。每个 ModuleScript 以下验证码开始:


local module = {}
return module

这段代码创建一个空的 Luau 并将其返回到任何需要模块脚本的脚本。

返回值可以是任何 数据类型 除了 nil 之外,但大多数模块脚本返回一个函数、表或表的函数。为了生成其返回值,模块脚本当然可以运行任意验证码,其中包括需要其他模块脚本。

以下示例返回一个带有单个函数 getPickupBonus 的表。将其粘贴到新模块脚本中:


-- 复制存储中的模块脚本
local PickupManager = {}
local defaultMultiplier = 1.25
local rarityMultipliers = {
common = 10,
uncommon = 20,
rare = 50,
legendary = 100
}
-- 将获取拾取奖励函数添加到 PickupManager 表
PickupManager.getPickupBonus = function(rarity)
local bonus = rarityMultipliers[rarity] * defaultMultiplier
return bonus
end
return PickupManager

将函数添加到表并不总是必要的——你只需要返回函数本身——但这是一个很好的关注式;当你从另一个脚本调用函数时,你可以轻松理解语法;随着时间的推移,你可以轻松地添加更多函数到模块脚本。

需要模块脚本

要加载模块脚本,您调用 require() 函数。在 ReplicatedStorage 中,添加新脚本,并将其 RunContext 更改为 Client 。然后添加以下代码来调用 PickupManager.getPickupBonus 函数:

复制存储中的客户端脚本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- 获取模块脚本返回的值
local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))
-- 调用模块脚本函数
local bonus = PickupManager.getPickupBonus("legendary")
print(bonus) --> 125

将模块脚本存储在 ReplicatedStorage 中,可让您在服务器和客户端之间共享代码,因此您可以使用相同的代码要求脚本从 ServerScriptService :

服务器脚本服务中的脚本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))

当你在 require() 上调用 ModuleScript 时,它会运行一次并返回一个单个项目作为参考。再次调用 将返回相同的引用,这意味着如果您修改返回的 表 或 》,后续的 》 调用将返回该修改的引用。模块本身不会多次运行。

如果您需要从客户端-服务器边界的两侧获得 ModuleScript,例如上面的示例,那么 ModuleScript 将为每一侧返回独特的引用。

模式

模块脚本具有一些常见模式,您可以使用它们来简化代码并避免随着体验规模和复杂性的增长而出现的陷阱。

数据共享

要将数据与个体对象关联,您可以为其分配属性或创建 Configuration 值对象文件夹,例如 StringValueIntValue 。然而,如果您想添加或修改数十个对象或数据值,那么两种方法都很麻烦。它们也不存储表或函数。

如果您想为同一对象的多个副本修改相同的数据或为不同对象重用相同的数据,请将数据存储在 ModuleScripts 中。这是你更容易重用其他脚本中的数据的方法,你可以存储表和函数。

以下示例 ModuleScriptReplicatedStorage 中存储了通用枪的配置值:

复制存储中的模块脚本

local GunConfig = {}
GunConfig.MagazineSize = 20
GunConfig.AmmoCount = 100
GunConfig.Firerate = 600
GunConfig.Damage = {
["Head"] = 50;
["Torso"] = 40;
["Body"] = 25;
}
return GunConfig

自定义事件

自定义事件使脚本能够相互通信,但必须跟踪对单个 BindableEvent 对象的引用可能会使您的代验证码杂乱。

您可以使用 ModuleScripts 来存储 BindableEvents 并提供与 ModuleScript 方法直接相关的自定义事件处理程序。

以下 ModuleScriptReplicatedStorage 中有一个自定义事件,当开关更改状态时触发:

复制存储中的模块脚本

local Switch = {}
-- 创建可绑定的方式,任何脚本都可以在切换更改时收听
local bindableEvent = Instance.new("BindableEvent")
Switch.Changed = bindableEvent.Event
local state = false
function Switch.flip()
state = not state
bindableEvent:Fire(state)
end
return Switch

以下客户端脚本在 ReplicatedStorage 连接一个函数,在 Switch.Changed 事件触发时调用。

复制存储中的脚本

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Switch = require(ReplicatedStorage:WaitForChild("Switch"))
Switch.Changed:Connect(function(newState)
print("Switch state is now", newState)
end
-- 测试翻转几次
task.wait(1)
Switch.flip()
task.wait(1)
Switch.flip()

封装

封装是创建一个抽象层围绕对象或脚本逻辑来隐藏复杂性的实践。您可以使用 ModuleScripts 将 Roblox 对象用自定义 Luau 函数封装,以简化代验证码。

例如,你可以使用封装来:

  • 使用单个 RemoteEvent 对象简化跨网络通信。
  • 将错误处理代码包围敏感服务,例如 DataStoreService
  • 定义自定义方法来控制或扩展 Roblox 对象功能。

跟踪数十个单独的 RemoteEvent 对象来实现游戏中的网络很难。您可以使用 ModuleScript 来封装单个 RemoteEvent 来帮助简化此问题。通过包含独特的 id 参数,您仍然可以使用单个 RemoteEvent 发送不同的网络消息,而不使用任何其他参数。

在下面的例子中,命名为 ModuleScriptNetworkManagerClient 封装了 RemoteEvent:FireServer() 方法,包含这个额外的 id 参数。此外,这 ModuleScript 引用了 RemoteEvent 对象本身,因此您不需要在代验证码的其他部分中引用它。您只需要要求此 ModuleScript 发送网络消息,而不需要处理代码库中剩余的 RemoteEvent 对象。

以下 ModuleScriptReplicatedFirst 提供了一个封装的函数,您可以调用客户端脚本发送网络消信息:

网络模块

-- 复制的第一个名为 NetworkManagerClient 的模块脚本
local NetworkManagerClient = {}
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
-- 封装远程对象的 FireServer 函数
function NetworkManagerClient.FireServer(id, ...)
remoteEvent:FireServer(id, ...)
end
return NetworkManagerClient

下面的 ModuleScriptServerScriptService 使用 BindableEvents 为每个脚本连接到特定ID。当客户端发送网络消信息时,每个 BindableEvent 与指定的ID关联。


-- 名为 NetworkManagerServer 的 ServerScript 服务中的模块脚本
local NetworkManagerServer = {}
local networkSignalList = {}
function NetworkManagerServer.GetServerEventSignal(id)
local bindableEvent = Instance.new("BindableEvent")
-- 将新的可绑定事件链接到 id
table.insert(networkSignalList, {
id = id,
bindableEvent = bindableEvent,
})
return bindableEvent.Event
end
-- 连接到
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
remoteEvent.OnServerEvent:Connect(function(player, id, ...)
-- 找到与收到的远程事件ID匹配的可绑定事件
for _, signal in networkSignalList do
if signal.id == id then
signal.bindableEvent:Fire(player, ...)
end
end
end)
return NetworkManagerServer

以下 LocalScript 发送了一个带有 ID RequestA 的消息,并带有可选的 Hello 参数。


-- 复制的第一个本地脚本在 ReplicatedFirst
local ReplicatedFirst = game:GetService("ReplicatedFirst")
local NetworkManagerClient = require(ReplicatedFirst:WaitForChild("NetworkManagerClient"))
NetworkManagerClient.FireServer("RequestA", "Hello")

以下 Script 连接到网络消息 ID RequestA 并在收到请求时打印带有任何附加参数的语句。


-- 服务器脚本服务中的脚本
local ServerScriptService = game:GetService("ServerScriptService")
local NetworkManagerServer = require(ServerScriptService:WaitForChild("NetworkManagerServer"))
NetworkManagerServer.GetServerEventSignal("RequestA"):Connect(function(player, ...)
print("Received RequestA from", player, ...)
end)