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ウィンドウで新しいRemoteEventを作成するには:
- RemoteEventを挿入したいコンテナをホバーオーバーします。サーバーとクライアントの両方からアクセスできるようにするには、ReplicatedStorageのように両側から見ることができる場所に配置する必要がありますが、場合によってはWorkspaceやToolの内部に保存することも適当です。
- コンテナの名前の右側に表示される**⊕**ボタンをクリックし、RemoteEventインスタンスを挿入します。
- インスタンスの名前を、その目的を説明するように変更します。
RemoteEventを作成した後は、クライアントからサーバーへ、サーバーからクライアントへ、またはサーバーからすべてのクライアントへの一方向通信を促進できます。



クライアント → サーバー
LocalScriptを使用して、FireServer()メソッドを呼び出すことでサーバー上でイベントをトリガーできます。FireServer()に引数を渡すと、それらは特定の制限に従ってサーバーのイベントハンドラーに渡されます。サーバーのイベントハンドラーの最初のパラメータは、常にそれを呼び出すクライアントのPlayerオブジェクトであり、追加のパラメータが続きます。
| クライアント | RemoteEvent:FireServer(args) |
| サーバー | RemoteEvent.OnServerEvent:Connect(function(player, args)) |
以下のScriptは、OnServerEventにイベントハンドラーを接続し、新しいPartをサーバーで作成します。対応するLocalScriptは、希望するColorおよびPositionを持つRemoteEventインスタンスに対してFireServer()を呼び出します。
イベント接続 - スクリプト
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
-- リモートイベントインスタンスへの参照を取得
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function onCreatePart(player, partColor, partPosition)
print(player.Name .. " がリモートイベントを発火しました")
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オブジェクトであり、追加の引数は特定の制限に従ってクライアントに渡されます。イベントハンドラーには、Players.LocalPlayerを使用してクライアント上のプレイヤーを特定できるため、最初の引数としてPlayerオブジェクトを含める必要はありません。
| サーバー | 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)
イベント発火 - スクリプト
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)
イベント発火 - スクリプトlocal 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ウィンドウで新しいRemoteFunctionを作成するには:
- RemoteFunctionを挿入したいコンテナをホバーオーバーします。サーバーとクライアントの両方からアクセスできるようにするには、ReplicatedStorageのように両側から見ることができる場所に配置する必要がありますが、場合によってはWorkspaceやToolの内部に保存することも適当です。
- コンテナの名前の右側に表示される**⊕**ボタンをクリックし、RemoteFunctionインスタンスを挿入します。
- インスタンスの名前を、その目的を説明するように変更します。
RemoteFunctionを作成した後は、クライアントとサーバー間またはサーバーとクライアント間の双方向通信を促進できます。


クライアント → サーバー → クライアント
LocalScriptを使用して、InvokeServer()メソッドを呼び出すことでサーバー上の関数を呼び出すことができます。リモートイベントとは異なり、RemoteFunctionを呼び出すLocalScriptは、コールバックが返されるまで待機します。引数として渡すInvokeServer()は、一定の制限に従ってOnServerInvokeコールバックに渡されます。複数のコールバックが同じRemoteFunctionに定義されている場合、最後の定義のみが実行されます。
| クライアント | RemoteFunction:InvokeServer(args) |
| サーバー | RemoteFunction.OnServerInvoke = function(player, args) |
以下のScriptは、OnServerInvokeを介してコールバック関数を定義し、リクエストされたPartをそのreturn値を通じて返します。対応するLocalScriptは、リクエストされたパートの色と位置を定義する追加の引数を持ってInvokeServer()を呼び出します。
コールバック接続 - スクリプト
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を呼び出したりすると、それに渡す引数はイベントまたはコールバック関数に転送されます。Enum、Instanceなどのロブロックスオブジェクトの種類や、数値、文字列、ブール値といったLuaの型を渡すことができますが、次の制限を慎重に確認する必要があります。
非文字列インデックス
渡されたテーブルのインデックスが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)
イベント発火 - スクリプト
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)
イベント発火 - スクリプト
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
local function testFunction()
print("こんにちは世界!")
end
-- 関数を引数として持つリモートイベントを発火
remoteEvent:FireAllClients(testFunction)
テーブルインデックス
データのテーブルを渡す場合、数値インデックスと文字列キーのミックステーブルを渡さないでください。代わりに、完全にキーバリューペア(辞書)から成るテーブルまたは完全に数値インデックスから成るテーブルを渡してください。
イベント接続 - スクリプト
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で以下のスクリプトを実行し、テーブルの同一性が異なることを確認できます。
コールバック接続 - スクリプト
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プロパティはありません。
イベント接続 - スクリプト
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値を受け取ります。
イベント発火 - スクリプト
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local remoteEvent = ReplicatedStorage:FindFirstChildOfClass("RemoteEvent")
-- クライアントがServerStorageにアクセスできないため「nil」として受信される
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)