数行のスクリプトを作成した後、それらの間でコードを再使用したい前には、長くはありません。場所 によって、ModuleScripts は、クライアント-サーバー境界の異なる側や境界の同じ側のスクリプト間でコードを再使用できます。
スクリプトを置く場所はどこでもモジュールスクリプトを置うことができますが、ReplicatedStorage は人気の場所です; モジュールスクリプトをここに保存すると、サーバーとクライアントの間のコードを再使用できます。
モジュールスクリプトのアナトミー
Roblox Studio では、 ReplicatedStorage にモジュールスクリプトを追加し、PickupManager に名前を変更します。それぞれ ModuleScript は次のコードで始まります:
local module = {}return module
このコードは空の Luau テーブル を作成し、モジュールスクリプトが必要なスクリプトに返します。
返却値は、 データタイプ を除き、ほとんどのモジュールスクリプトは関数、テーブル、または関数のテーブルを返します。その返却値を生成するには、モジュールスクリプトはもちろん、他のモジュールスクリプトが必要な任意のコードを実行できます。
次の例では、getPickupBonus という単一の機能を持つテーブルを返します。新しいモジュールスクリプトに貼り付けます:
-- ReplicatedStorage のモジュールスクリプト
local PickupManager = {}
local defaultMultiplier = 1.25
local rarityMultipliers = {
common = 10,
uncommon = 20,
rare = 50,
legendary = 100
}
-- PickupManager テーブルに getPickupBonus 機能を追加する
PickupManager.getPickupBonus = function(rarity)
local bonus = rarityMultipliers[rarity] * defaultMultiplier
return bonus
end
return PickupManager
機能をテーブルに追加することは厳密に必要ではありません—機能自体を返すだけでもよい—しかし、それはフォロー随する良いパターンです;機能を別のスクリプトから呼び出すと簡単に理解できる構文を返し、時間経過でモジュールスクリプトにより多くの機能を簡単に追加できます。
モジュールスクリプトが必要
モジュールスクリプトをロードするには、require() 関数を呼び出します。In ReplicatedStorage , 新しいスクリプトを追加し、その RunContext を Client に変更します。次に、PickupManager.getPickupBonus 関数を呼び出すための次のコードを追加します:
ReplicatedStorage のクライアントスクリプト
local ReplicatedStorage = game:GetService("ReplicatedStorage")-- モジュールスクリプトによって返される値を取得するlocal PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))-- モジュールスクリプト関数を呼び出すlocal bonus = PickupManager.getPickupBonus("legendary")print(bonus) --> 125
ストレージモジュールスクリプトを に保存すると、サーバーとクライアント間でコードを共有でき、同じコードを使用してスクリプトを要求できるようになります:
ServerScriptService のスクリプト
local ReplicatedStorage = game:GetService("ReplicatedStorage")local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))
require() を ModuleScript で呼び出すと、1回実行して参照として単一のアイテムを返します。再び require() を呼び出すと、同じ参照が返され、返された テーブル または Instance を変更すると、後続の require() 呼び出しがその修正された参照を返すことになります。モジュール自体は複数回実行しません。
上記の例のように、クライアント-サーバー境界の両側から ModuleScript が必要な場合、ModuleScript はそれぞれの側に独自の参照を返します。
パターン
モジュールスクリプトには、コードを簡素化し、規模と複雑さが増すにつれて落とし穴を避けるために使用できるいくつかの共通パターンがあります。
データ共有
データを個々のオブジェクトに関連付けるには、属性を割り当てたり、 または のような値オブジェクトのフォルダを作成したりできます。しかし、どちらのアプローチも、数十のオブジェクトまたはデータ値を追加または変更したい場合は面倒です。また、テーブルや機能を保存しません。
同じオブジェクトの複数のコピーで同じデータを変更したり、異なるオブジェクトで同じデータを再使用したい場合は、ModuleScripts にデータを保存します。他のスクリプトでデータを再使用する方法が簡単になり、テーブルと機能を保存できます。
次の例 において、一般的な銃の構成値が保存されています:
ReplicatedStorage のモジュールスクリプト
local GunConfig = {}GunConfig.MagazineSize = 20GunConfig.AmmoCount = 100GunConfig.Firerate = 600GunConfig.Damage = {["Head"] = 50;["Torso"] = 40;["Body"] = 25;}return GunConfig
カスタムイベント
カスタムイベントでは、スクリプトがお互いに通信できますが、個々の BindableEvent オブジェクトへの参照を追跡しなければならないと、コードが混乱する可能性があります。
ModuleScripts を使用して、BindableEvents を保存し、ModuleScript のメソッドに直接結合するカスタムイベントハンドラーを提供できます。
次の ModuleScript に ReplicatedStorage には、スイッチが状態を変更すると発動するカスタムイベントがあります:
ReplicatedStorage のモジュールスクリプト
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
次のクライアントスクリプト in ReplicatedStorage は、Switch.Changed イベントが発動したときに呼び出される関数を接続します。
ReplicatedStorage のスクリプト
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 だけを使用しながら、異なるネットワークメッセージを送信できます。
以下の例では、ModuleScript という名前の NetworkManagerClient が、この追加の RemoteEvent:FireServer() 引数を含む id メソッドをカプセル化します。さらに、この ModuleScript は、RemoteEvent オブジェクト自体を参照しているので、コードの他の部分で参照する必要はありません。ネットワークメッセージを送信するには、この ModuleScript を要求するだけで十分で、コードベースの残りの部分で RemoteEvent オブジェクトに対処する必要はありません。
次の ModuleScript により、ReplicatedFirst にクライアントスクリプトを呼び出してネットワークメッセージを送信できるカプセル化された関数が提供されます:
ネットワークモデル
-- モジュールスクリプトを ReplicatedFirst という名前の NetworkManagerClient
local NetworkManagerClient = {}
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
-- リモートオブジェクトの FireServer 機能をカプセル化する
function NetworkManagerClient.FireServer(id, ...)
remoteEvent:FireServer(id, ...)
end
return NetworkManagerClient
次の ModuleScript における ServerScriptService は、すべてのスクリプトが特定のIDに接続するために BindableEvents を使用します。クライアントがネットワークメッセージを送信すると、指定された ID に関連するそれぞれの BindableEvent が発火します。
-- NetworkManagerServer という名前の ServerScriptService のモジュールスクリプト
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 は、オプションの RequestA 引数で ID Hello のメッセージを送信します。
-- ReplicatedFirst のローカルスクリプトlocal ReplicatedFirst = game:GetService("ReplicatedFirst")local NetworkManagerClient = require(ReplicatedFirst:WaitForChild("NetworkManagerClient"))NetworkManagerClient.FireServer("RequestA", "Hello")
次の Script は、ネットワークメッセージ ID RequestA に接続し、リクエストを受信すると、追加パラメータを含むステートメントを印刷します。
-- ServerScriptService のスクリプト
local ServerScriptService = game:GetService("ServerScriptService")
local NetworkManagerServer = require(ServerScriptService:WaitForChild("NetworkManagerServer"))
NetworkManagerServer.GetServerEventSignal("RequestA"):Connect(function(player, ...)
print("Received RequestA from", player, ...)
end)