BindableEvent 和 BindableFunction 对象让您在 同一侧 的 客户端-服务器 边界上绑定脚本之间的行为,并传达游戏内行动的特定期望结果。
可绑定事件的最常见用例是用于有回合结构的游戏。例如,您可能有一个“比赛开始”事件,让其他脚本启动计时器并显示排行榜,并有一个对应的“比赛结束”事件,让其他脚本知道何时将玩家带回大厅并显示获胜者。
因为它们协调脚本之间的活动,可绑定事件通常用于服务器,但您也可以在客户端使用它们。
根据您的游戏运作方式,可绑定事件可以帮助使您的代码更模块化,但是 模块脚本 通常是更好的选择,用于需要在脚本之间共享数据的情况。您还可以结合模块脚本使用可绑定事件,以获得更简洁的语法,如 自定义事件 中所述。
可绑定事件
BindableEvent 对象通过脚本之间的异步单向通信启用自定义事件。
当您通过 Fire() 方法触发 BindableEvent 时,触发的脚本 不会 阻塞,而目标函数会接收传递的参数,具有某些 限制。像所有事件一样,BindableEvents 创建了每个连接函数的线程,因此即使其中一个发生错误,其他线程也会继续执行。
要使用 Studio 中的 资源管理器 窗口创建新的 BindableEvent:
- 将鼠标悬停在您要插入 BindableEvent 的容器上。我们建议使用 ServerScriptService 进行服务器脚本之间的通信,使用 ReplicatedStorage 进行客户端脚本之间的通信。
- 点击出现在容器名称右侧的 ⊕ 按钮,并插入一个 BindableEvent 实例。
- 将实例重命名为 TestBindableEvent。
创建 BindableEvent 后,在一个脚本中连接一个函数到它的 Event 事件,然后在另一个脚本中 Fire() 该事件。
事件连接
local ServerScriptService = game:GetService("ServerScriptService")
-- 获取可绑定事件实例的引用
local bindableEvent = ServerScriptService:WaitForChild("TestBindableEvent")
-- 连接匿名函数到事件
bindableEvent.Event:Connect(function(data)
print(data) --> 回合开始!
end)
事件触发local ServerScriptService = game:GetService("ServerScriptService")-- 获取可绑定事件实例的引用local bindableEvent = ServerScriptService:WaitForChild("TestBindableEvent")-- 触发可绑定事件bindableEvent:Fire("回合开始!")
自定义回调
BindableFunction 对象允许脚本之间的同步双向通信。您可以使用它定义自定义回调函数,并通过调用 BindableFunction:Invoke() 手动调用该函数。调用该函数的代码 会阻塞,直到找到对应的回调为止,而回调会接收您传递给 Invoke() 的参数。如果从未设置回调,调用它的脚本将不会恢复执行。
要使用 Studio 中的 资源管理器 窗口创建新的 BindableFunction:
- 将鼠标悬停在您要插入 BindableFunction 的容器上。我们建议使用 ServerScriptService 进行服务器脚本之间的通信,使用 ReplicatedStorage 进行客户端脚本之间的通信。
- 点击出现在容器名称右侧的 ⊕ 按钮,并插入一个 BindableFunction 实例。
- 将实例重命名为 TestBindableFunction。
创建 BindableFunction 后,您可以在一个脚本中连接到它的 OnInvoke 回调,然后从另一个脚本中 Invoke() 回调函数。
回调连接
local ServerScriptService = game:GetService("ServerScriptService")
-- 获取可绑定函数的引用
local bindableFunction = ServerScriptService:WaitForChild("TestBindableFunction")
-- 回调函数
local function addTwoNumbers(a, b)
return a + b
end
-- 将函数设置为可绑定函数的回调
bindableFunction.OnInvoke = addTwoNumbers
事件调用local ServerScriptService = game:GetService("ServerScriptService")-- 获取可绑定函数的引用local bindableFunction = ServerScriptService:WaitForChild("TestBindableFunction")-- 调用回调函数并输出返回值local sum = bindableFunction:Invoke(2, 4)print(sum) --> 6
参数限制
当您触发 BindableEvent 或调用 BindableFunction 时,它会转发您与事件或回调函数一起传递的任何参数。您可以传递任何类型的 Roblox 对象(Enum、Instance 等),以及 Luau 类型,如数字、字符串和布尔值,但您应该仔细考虑以下限制。
非字符串索引
如果传递的表的任何 索引 是非字符串类型,例如 Instance、userdata 或 function,Roblox 会自动将这些索引转换为字符串。
事件连接
local ServerScriptService = game:GetService("ServerScriptService")
local bindableEvent = ServerScriptService:WaitForChild("TestBindableEvent")
local function onEventFire(passedTable)
for k, v in passedTable do
print(typeof(k)) --> string
end
end
-- 将函数连接到事件
bindableEvent.Event:Connect(onEventFire)
事件触发local ServerScriptService = game:GetService("ServerScriptService")local bindableEvent = ServerScriptService:WaitForChild("TestBindableEvent")-- 使用包含工作区实例作为键的表触发事件bindableEvent:Fire({[workspace.Baseplate] = true})
表索引
如果您传递一个数据表,请不要传递一个混合了数字和字符串键的表。这样可能导致传输过程中元素被移除。相反,请传递一个 完全 由键值对(字典)组成的表或 完全 由数字索引(数组)组成的表。
事件连接
local ServerScriptService = game:GetService("ServerScriptService")
local bindableEvent = ServerScriptService:WaitForChild("TestBindableEvent")
local function onEventFire(passedTable)
for k, v in passedTable do
print(k .. " = " .. v)
--> 1 = 剑
--> 2 = 弓
--> CharName = Diva Dragonslayer
--> CharClass = Rogue
end
end
-- 将函数连接到事件
bindableEvent.Event:Connect(onEventFire)
事件触发local ServerScriptService = game:GetService("ServerScriptService")local bindableEvent = ServerScriptService:WaitForChild("TestBindableEvent")-- 数字索引表local inventoryData = {"剑", "弓"}-- 字典表local characterData = {CharName = "Diva Dragonslayer",CharClass = "Rogue"}-- 使用一致索引的表触发事件bindableEvent:Fire(inventoryData)bindableEvent:Fire(characterData)
表身份
作为参数传递给可绑定事件和回调的表是被复制的,这意味着它们不会与在触发事件或调用回调时提供的表完全相同。返回给调用者的表也不会与提供的表完全相同。您可以通过在 BindableFunction 上运行以下脚本并观察表身份的不同来证明这一点。
回调连接
local ServerScriptService = game:GetService("ServerScriptService")
local bindableFunction = ServerScriptService:WaitForChild("TestBindableFunction")
-- 回调函数
local function returnTable(passedTable)
-- 输出调用时的表身份
print(tostring(passedTable)) --> table: 0x48eb7aead27563d9
return passedTable
end
-- 将函数设置为可绑定函数的回调
bindableFunction.OnInvoke = returnTable
事件调用local ServerScriptService = game:GetService("ServerScriptService")local bindableFunction = ServerScriptService:WaitForChild("TestBindableFunction")local inventoryData = {"剑", "弓"}-- 输出原始表身份print(tostring(inventoryData)) --> table: 0x059bcdbb2b576549local invokeReturn = bindableFunction:Invoke(inventoryData)-- 输出返回时的表身份print(tostring(invokeReturn)) --> table: 0x9fcae7919563a0e9
元表
如果一个表有元表,所有的元表信息在传输中都会丢失。在以下代码示例中,NumWheels 属性是 Car 元表的一部分。当服务器接收到以下表时,truck 表具有 Name 属性,但 没有 NumWheels 属性。
事件连接
local ServerScriptService = game:GetService("ServerScriptService")
local bindableEvent = ServerScriptService:WaitForChild("TestBindableEvent")
local function onEvent(param)
print(param) --> {["Name"] = "MyTruck"}
end
-- 将函数连接到事件
bindableEvent.Event:Connect(onEvent)
事件触发local ServerScriptService = game:GetService("ServerScriptService")local bindableEvent = ServerScriptService:WaitForChild("TestBindableEvent")local Car = {}Car.NumWheels = 4Car.__index = Carlocal truck = {}truck.Name = "MyTruck"setmetatable(truck, Car)-- 使用包含元表的表触发事件bindableEvent:Fire(truck)