Roblox 遊戲預設為多人遊戲,因此所有遊戲本質上都在伺服器與玩家的連接客戶端之間進行通信。在最簡單的情況下,當玩家移動他們的角色時,某些 Humanoid 屬性,例如狀態,會傳送到伺服器,伺服器再將這些資訊傳遞給其他連接的客戶端。
遠端事件和回呼讓您能夠在客戶端和伺服器邊界之間進行 通信:
- RemoteEvents 允許單向通信(發送請求但 不 等待回應)。
- UnreliableRemoteEvents 允許對不斷變化或對遊戲狀態不關鍵的資料進行單向通信。這些事件以改善網路性能為代價,交換了排序與可靠性。
- RemoteFunctions 允許雙向通信(發送請求並等待回應)。
與 可綁定事件 不同,後者的應用場景較為有限,遠端事件和函數的使用案例多得數不勝數:
- 遊戲玩法 - 基本的遊戲玩法,例如玩家到達關卡結尾,可能需要一個遠端事件。客戶端腳本會通知伺服器,伺服器腳本會重置玩家的位置。
- 伺服器驗證 - 如果一名玩家嘗試喝一瓶藥水,他們是否真的 有 那瓶藥水?為了確保公平,伺服器必須是遊戲的真相來源。客戶端腳本可以使用遠端事件來通知伺服器玩家正在喝藥水,然後伺服器腳本可以決定該玩家是否真的擁有那瓶藥水及是否要給予任何好處。
- 用戶界面更新 - 隨著遊戲狀態的變化,伺服器腳本可以使用遠端事件來通知客戶端分數、目標等更改。
- 遊戲內市場所購買商品 - 有關使用遠端函數的範例實作,請參見 提示訂閱購買。
快速參考
以下表格作為 RemoteEvents 和 RemoteFunctions 之間通信的快速參考。
| 客戶端 → 伺服器 | |
|---|---|
| 客戶端 | RemoteEvent:FireServer(args) |
| 伺服器 | RemoteEvent.OnServerEvent:Connect(function(player, args)) |
| 伺服器 → 客戶端 | |
| 伺服器 | RemoteEvent:FireClient(player, args) |
| 客戶端 | RemoteEvent.OnClientEvent:Connect(function(args)) |
| 伺服器 → 所有客戶端 | |
| 伺服器 | RemoteEvent:FireAllClients(args) |
| 客戶端 | RemoteEvent.OnClientEvent:Connect(function(args)) |
遠端事件
RemoteEvent 物件輔助進行非同步的單向通信,穿越客戶端與伺服器邊界,無需等待回應。
要透過 Explorer 視窗在 Studio 中創建新的 RemoteEvent:
- 將鼠標懸停在您想要插入 RemoteEvent 的容器上。為了確保伺服器和客戶端均能訪問,它必須位於雙方都能看到的地方,例如 ReplicatedStorage,雖然在某些情況下將其存儲在 Workspace 或 Tool 內也是合適的。
- 單擊容器名稱右側出現的 ⊕ 按鈕,並插入一個 RemoteEvent 實例。
- 將實例重新命名以描述其目的。
一旦您創建了 RemoteEvent,它可以促進從 客戶端到伺服器、從 伺服器到客戶端 或從 伺服器到所有客戶端 的單向通信。



客戶端 → 伺服器
您可以使用 LocalScript 來觸發 伺服器 上的一個事件,方法是調用 FireServer() 方法。 如果您將參數傳遞給 FireServer(),它們將以某些 限制 通過事件處理程序傳遞到伺服器。注意,伺服器上事件處理程序的第一個參數始終是調用它的客戶端的 Player 物件,後續參數依次跟隨。
| 客戶端 | RemoteEvent:FireServer(args) |
| 伺服器 | RemoteEvent.OnServerEvent:Connect(function(player, args)) |
以下 Script 將一個事件處理程序連接到 OnServerEvent,該事件處理程序在伺服器上創建一個新的 Part。 附帶的 LocalScript 然後在 RemoteEvent 實例上調用 FireServer() 並傳遞所需的 Color 和 Position 參數來創建這個部件。
事件連接 - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- 獲取遠端事件實例的參考
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onCreatePart(player, partColor, partPosition)
print(player.Name .. " 發出了 RemoteEvent")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
end
-- 將函數連接到事件
remoteEvent.OnServerEvent:Connect(onCreatePart)
事件觸發 - LocalScriptlocal ReplicatedStorage = game:GetService("ReplicatedStorage")-- 獲取遠端事件實例的參考local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")-- 觸發遠端事件並傳遞額外參數remoteEvent:FireServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))
伺服器 → 客戶端
您可以使用 Script 來觸發客戶端上的事件,方法是調用 FireClient() 方法。 FireClient() 的第一個參數是您希望對其響應事件的客戶端的 Player 物件,並且通過某些 限制 傳遞額外參數。注意,事件處理程序不需要將 Player 物件作為第一個參數,因為您可以通過 Players.LocalPlayer 在客戶端上確定玩家。
| 伺服器 | RemoteEvent:FireClient(player, args) |
| 客戶端 | RemoteEvent.OnClientEvent:Connect(function(args)) |
以下 LocalScript 將事件處理程序連接到 OnClientEvent 事件。 附帶的 Script 然後監聽進入伺服器的玩家,並為每個玩家調用 FireClient(),傳遞任意資料。
事件連接 - LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- 獲取遠端事件實例的參考
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local player = Players.LocalPlayer
local function onNotifyPlayer(maxPlayers, respawnTime)
print("[客戶端] 玩家接收到事件", player.Name)
print(maxPlayers, respawnTime)
end
-- 將函數連接到事件
remoteEvent.OnClientEvent:Connect(onNotifyPlayer)
事件觸發 - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
-- 獲取遠端事件實例的參考
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- 監聽進入的玩家並為每個玩家發送遠端事件
local function onPlayerAdded(player)
print("[伺服器] 向玩家發送事件", player.Name)
remoteEvent:FireClient(player, Players.MaxPlayers, Players.RespawnTime)
end
Players.PlayerAdded:Connect(onPlayerAdded)
伺服器 → 所有客戶端
您可以使用 Script 觸發所有客戶端的事件,通過調用 FireAllClients() 方法。 與 FireClient() 不同,FireAllClients() 方法不需要 Player 物件,因為它會將 RemoteEvent 發送到所有客戶端。
| 伺服器 | RemoteEvent:FireAllClients(args) |
| 客戶端 | RemoteEvent.OnClientEvent:Connect(function(args)) |
以下 LocalScript 將事件處理程序連接到 OnClientEvent 事件,該事件輸出剩餘的倒計時時間。 附帶的 Script 然後在循環中每秒調用 FireAllClients(),以便為所有客戶端發送 RemoteEvent。
事件連接 - LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- 獲取遠端事件實例的參考
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onTimerUpdate(seconds)
print(seconds)
end
-- 將函數連接到事件
remoteEvent.OnClientEvent:Connect(onTimerUpdate)
事件觸發 - Scriptlocal ReplicatedStorage = game:GetService("ReplicatedStorage")-- 獲取遠端事件實例的參考local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")local countdown = 5-- 每秒觸發一次遠端事件,直到時間結束for timeRemaining = -1, countdown doremoteEvent:FireAllClients(countdown - timeRemaining)task.wait(1)end
遠端回呼
RemoteFunction 物件促進了同步的雙向通信,穿越客戶端與伺服器的邊界。 發送遠端函數的發送者將會在接收到回應之前進入等待狀態。
要透過 Explorer 視窗在 Studio 中創建新的 RemoteFunction:
- 將鼠標懸停在您想要插入 RemoteFunction 的容器上。 為了確保伺服器和客戶端均能訪問,它必須位於雙方都能看到的地方,例如 ReplicatedStorage,雖然在某些情況下將其存儲在 Workspace 或 Tool 內也是合適的。
- 單擊容器名稱右側出現的 ⊕ 按鈕,並插入一個 RemoteFunction 實例。
- 將實例重新命名以描述其目的。
一旦您創建了 RemoteFunction,它可以促進從 客戶端到伺服器 或從 伺服器到客戶端 的雙向通信。


客戶端 → 伺服器 → 客戶端
您可以使用 LocalScript 通過調用 InvokeServer() 方法調用伺服器上的函數。 與 遠端事件 不同,調用 RemoteFunction 的 LocalScript 在回呼返回之前會等待。 您傳遞給 InvokeServer() 的參數將以某些 限制 傳遞到 OnServerInvoke 的回呼中。 注意,如果您為同一 RemoteFunction 定義多個回呼,則僅執行最後的定義。
| 客戶端 | RemoteFunction:InvokeServer(args) |
| 伺服器 | RemoteFunction.OnServerInvoke = function(player, args) |
以下 Script 通過 OnServerInvoke 定義回呼函數並通過其 return 值返回所請求的 Part。 隨後,附帶的 LocalScript 以額外的參數呼叫 InvokeServer(),以定義所請求的部件顏色和位置。
回呼連接 - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- 獲取遠端函數實例的參考
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- 回呼函數
local function createPart(player, partColor, partPosition)
print(player.Name .. " 請求創建一個新部件")
local newPart = Instance.new("Part")
newPart.Color = partColor
newPart.Position = partPosition
newPart.Parent = Workspace
return newPart
end
-- 將函數設置為遠端函數的回呼
remoteFunction.OnServerInvoke = createPart
事件調用 - LocalScriptlocal ReplicatedStorage = game:GetService("ReplicatedStorage")-- 獲取遠端函數實例的參考local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")-- 在調用回呼時傳遞顏色和位置local newPart = remoteFunction:InvokeServer(Color3.fromRGB(255, 0, 0), Vector3.new(0, 25, -20))-- 輸出返回的部件引用print("伺服器創建了請求的部件:", newPart)
伺服器 → 客戶端 → 伺服器
您可以使用 Script 來調用客戶端上的函數,調用 InvokeClient() 方法,但存在嚴重風險如下:
- 如果客戶端拋出錯誤,伺服器也會拋出錯誤。
- 如果客戶端在被調用時斷開連接,InvokeClient() 會拋出錯誤。
- 如果客戶端沒有返回值,伺服器將會無限等待。
對於不需要雙向通信的操作,例如更新 GUI,請使用 RemoteEvent 並從 伺服器到客戶端 進行通信。
參數限制
當您觸發 RemoteEvent 或調用 RemoteFunction 時,它會將您通過事件或回呼函數傳遞的任何參數轉發出去。 可以傳遞任何類型的 Roblox 物件,例如 Enum、Instance 等,還可以傳遞 Luau 類型,例如數字、字串和布林值,但是您應該仔細考慮以下限制。
非字串索引
如果傳遞的表的任何 索引 為非字串類型,例如 Instance、userdata 或 function,Roblox 將自動將這些索引轉換為字串。
事件連接 - LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEventFire(passedTable)
for k, v in passedTable do
print(typeof(k)) --> string
end
end
-- 將函數連接到事件
remoteEvent.OnClientEvent:Connect(onEventFire)
事件觸發 - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- 監聽進入的玩家並將遠端事件發送給每個
local function onPlayerAdded(player)
remoteEvent:FireClient(player,
{
[Workspace.Baseplate] = true
}
)
end
Players.PlayerAdded:Connect(onPlayerAdded)
傳遞的函數
包含作為 RemoteEvent 或 RemoteFunction 參數的函數將 不 在客戶端與伺服器之間複製,因此無法遠端傳遞函數。 相反,接收方的結果參數將為 nil。
事件連接 - LocalScript
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onClientEvent(func)
print(func) --> nil
end
remoteEvent.OnClientEvent:Connect(onClientEvent)
事件觸發 - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function testFunction()
print("Hello world!")
end
-- 觸發遠端事件並將函數作為參數傳遞
remoteEvent:FireAllClients(testFunction)
表索引
如果您傳遞一個資料表,請勿傳遞一個包含數字和字串鍵的混合表。 相反,請傳遞一個完全由鍵值對(字典)或完全由數字索引組成的表。
事件連接 - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEventFire(player, passedTable)
for k, v in passedTable do
print(k .. " = " .. v)
--> 1 = 劍
--> 2 = 弓
--> CharName = Diva Dragonslayer
--> CharClass = Rogue
end
end
-- 將函數連接到事件
remoteEvent.OnServerEvent:Connect(onEventFire)
事件觸發 - LocalScriptlocal ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")-- 數值索引表local inventoryData = {"劍", "弓"}-- 字典表local characterData = {CharName = "Diva Dragonslayer",CharClass = "Rogue"}remoteEvent:FireServer(inventoryData)remoteEvent:FireServer(characterData)
表的身份
傳遞到遠端事件/回呼的表將被複製,這意味著它們將不會完全等同於觸發事件或調用回呼時所提供的表。 同樣,返回給調用者的表將不會完全等同於所提供的表。 您可以通過在 RemoteFunction 上運行以下腳本並觀察表身份的差異來演示這一點。
回呼連接 - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")
-- 回呼函數
local function returnTable(player, passedTable)
-- 在調用時輸出表身份
print(tostring(passedTable)) --> table: 0x48eb7aead27563d9
return passedTable
end
-- 將函數設置為遠端函數的回呼
remoteFunction.OnServerInvoke = returnTable
事件調用 - LocalScriptlocal ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteFunction = ReplicatedStorage:FindFirstChildOfClass("RemoteFunction")local inventoryData = {"劍", "弓"}-- 輸出原始表身份print(tostring(inventoryData)) --> table: 0x059bcdbb2b576549local invokeReturn = remoteFunction:InvokeServer(inventoryData)-- 輸出返回時的表身份print(tostring(invokeReturn)) --> table: 0x9fcae7919563a0e9
元表
如果一個表具有元表,則在傳輸過程中會丟失所有的元表信息。 在以下示例中,NumWheels 屬性是 Car 元表的一部分。 當伺服器接收到以下表時,truck 表中有 Name 屬性但 沒有 NumWheels 屬性。
事件連接 - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onEvent(player, param)
print(param) --> {["Name"] = "MyTruck"}
end
-- 將函數連接到事件
remoteEvent.OnServerEvent:Connect(onEvent)
事件觸發 - LocalScriptlocal ReplicatedStorage = game:GetService("ReplicatedStorage")local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")local Car = {}Car.NumWheels = 4Car.__index = Carlocal truck = {}truck.Name = "MyTruck"setmetatable(truck, Car)-- 觸發包含元表的表的事件remoteEvent:FireServer(truck)
非複製的實例
如果 RemoteEvent 或 RemoteFunction 傳遞一個只有發送者可見的值,Roblox 不會在客戶端-伺服器邊界上複製它,而是傳遞 nil 來代替該值。 例如,如果 Script 傳遞一個 ServerStorage 的後裔,則收聽此事件的客戶端將會接收到 nil,因為該物體無法被客戶端訪問。
事件觸發 - Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- 將接收的部分設置為 "nil",因為客戶端無法訪問 ServerStorage
local storedPart = Instance.new("Part")
storedPart.Parent = ServerStorage
local function onPlayerAdded(player)
remoteEvent:FireClient(player, storedPart)
end
Players.PlayerAdded:Connect(onPlayerAdded)
類似地,如果您在 LocalScript 中創建一個部件並嘗試將其傳遞給 Script,伺服器會看到 nil,因為該部件對伺服器並不可複製。
事件觸發 - LocalScriptlocal ReplicatedStorage = game:GetService("ReplicatedStorage")local Workspace = game:GetService("Workspace")local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")-- 將接收的部分設置為 "nil",因為伺服器不知道該部分local clientPart = Instance.new("Part")clientPart.Parent = WorkspaceremoteEvent:FireServer(clientPart)