Setelah membuat beberapa skrip, tidak butuh waktu lama sebelum Anda ingin menggunakan kembali beberapa kode di antara mereka. Tergantung pada lokasi, ModuleScripts memungkinkan Anda menggunakan kembali kode di antara skrip di sisi yang berbeda dari batasan klien-server atau di sisi yang sama dari batasan tersebut.
Anda dapat menempatkan skrip modul di mana saja Anda menempatkan skrip, tetapi ReplicatedStorage adalah lokasi yang populer; menyimpan skrip modul di sini memungkinkan Anda menggunakan kembali kode di antara server dan klien.
Anatomi skrip modul
Di Roblox Studio, tambahkan sebuah skrip modul ke ReplicatedStorage dan ganti namanya menjadi PickupManager. Setiap ModuleScript dimulai dengan kode berikut:
local module = {}return module
Kode ini membuat sebuah tabel Luau kosong dan mengembalikannya ke skrip mana pun yang memanggil skrip modul tersebut.
Nilai yang dikembalikan dapat berupa jenis data apa pun kecuali nil, tetapi sebagian besar skrip modul mengembalikan sebuah fungsi, sebuah tabel, atau tabel fungsi. Untuk menghasilkan nilai kembalian tersebut, skrip modul dapat tentu saja menjalankan kode sembarangan, termasuk memanggil skrip modul lainnya.
Contoh berikut mengembalikan sebuah tabel dengan satu fungsi bernama getPickupBonus. Tempelkan ke skrip modul baru:
-- ModuleScript in ReplicatedStorage
local PickupManager = {}
local defaultMultiplier = 1.25
local rarityMultipliers = {
common = 10,
uncommon = 20,
rare = 50,
legendary = 100
}
-- Tambahkan fungsi getPickupBonus ke tabel PickupManager
PickupManager.getPickupBonus = function(rarity)
local bonus = rarityMultipliers[rarity] * defaultMultiplier
return bonus
end
return PickupManager
Menambahkan fungsi ke sebuah tabel tidaklah mutlak diperlukan—Anda bisa saja mengembalikan fungsi itu sendiri—tetapi ini adalah pola yang baik untuk diikuti; ini memberi Anda sintaks yang mudah dipahami saat Anda memanggil fungsi dari skrip lain dan memungkinkan Anda menambahkan lebih banyak fungsi ke skrip modul dari waktu ke waktu.
Memanggil skrip modul
Untuk memuat skrip modul, Anda memanggil fungsi require(). Di ReplicatedStorage, tambahkan skrip baru, dan ubah RunContext-nya menjadi Client. Kemudian tambahkan kode berikut untuk memanggil fungsi PickupManager.getPickupBonus:
Client script in ReplicatedStoragelocal ReplicatedStorage = game:GetService("ReplicatedStorage")-- Dapatkan nilai yang dikembalikan oleh ModuleScriptlocal PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))-- Panggil fungsi ModuleScriptlocal bonus = PickupManager.getPickupBonus("legendary")print(bonus) --> 125
Menyimpan skrip modul di ReplicatedStorage memungkinkan Anda berbagi kode antara server dan klien, sehingga Anda dapat menggunakan kode yang sama untuk memanggil skrip dari ServerScriptService:
Script in ServerScriptServicelocal ReplicatedStorage = game:GetService("ReplicatedStorage")local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))
Ketika Anda memanggil require() pada ModuleScript, ia dijalankan sekali dan mengembalikan satu item sebagai referensi. Memanggil require() lagi mengembalikan referensi yang persis sama, yang berarti jika Anda mengubah tabel yang dikembalikan atau Instance, panggilan require() berikutnya akan mengembalikan referensi yang dimodifikasi tersebut. Skrip modul itu sendiri tidak dijalankan beberapa kali.
Jika Anda memanggil ModuleScript dari kedua sisi batas klien-server, seperti pada contoh di atas, ModuleScript mengembalikan referensi unik untuk setiap sisi.
Pola
Skrip modul memiliki beberapa pola umum yang dapat Anda gunakan untuk menyederhanakan kode Anda dan menghindari jebakan saat permainan Anda tumbuh dalam ukuran dan kompleksitas.
Berbagi data
Untuk menggaitkan data dengan objek individual, Anda dapat menetapkan atribut kepada mereka atau membuat folder Configuration dengan objek nilai seperti StringValue atau IntValue. Namun, kedua pendekatan tersebut bermasalah jika Anda ingin menambah atau mengubah puluhan objek atau nilai data. Mereka juga tidak menyimpan tabel atau fungsi.
Jika Anda ingin memodifikasi data yang sama untuk beberapa salinan objek yang sama atau menggunakan kembali data yang sama untuk objek yang berbeda, simpan data tersebut di ModuleScripts. Ini adalah cara yang lebih mudah bagi Anda untuk menggunakan kembali data di skrip lain, dan Anda dapat menyimpan tabel dan fungsi.
Contoh berikut ModuleScript di ReplicatedStorage menyimpan nilai konfigurasi untuk senjata umum:
ModuleScript in ReplicatedStoragelocal GunConfig = {}GunConfig.MagazineSize = 20GunConfig.AmmoCount = 100GunConfig.Firerate = 600GunConfig.Damage = {["Head"] = 50;["Torso"] = 40;["Body"] = 25;}return GunConfig
Peristiwa khusus
Peristiwa khusus memungkinkan skrip untuk berkomunikasi satu sama lain, tetapi harus terus melacak referensi ke objek BindableEvent individual dapat membuat kode Anda berantakan.
Anda dapat menggunakan ModuleScripts untuk menyimpan BindableEvents dan memberikan pengendali peristiwa khusus yang langsung terikat pada metode ModuleScript.
Contoh ModuleScript berikut di ReplicatedStorage memiliki peristiwa khusus yang dipicu saat saklar mengubah status:
ModuleScript in ReplicatedStorage
local Switch = {}
-- Membuat bindable sehingga skrip mana pun dapat mendengarkan saat saklar diubah
local bindableEvent = Instance.new("BindableEvent")
Switch.Changed = bindableEvent.Event
local state = false
function Switch.flip()
state = not state
bindableEvent:Fire(state)
end
return Switch
Contoh skrip klien berikut di ReplicatedStorage menghubungkan fungsi untuk dipanggil saat peristiwa Switch.Changed dipicu.
Script in ReplicatedStorage
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Switch = require(ReplicatedStorage:WaitForChild("Switch"))
Switch.Changed:Connect(function(newState)
print("Status saklar sekarang", newState)
end)
-- Uji saklar beberapa kali
task.wait(1)
Switch.flip()
task.wait(1)
Switch.flip()
Enkapsulasi
Enkapsulasi adalah praktik menciptakan lapisan abstraksi di sekitar objek atau logika skrip untuk menyembunyikan kompleksitas. Anda dapat menggunakan ModuleScripts untuk mengenkapsulasi objek Roblox dengan fungsi Luau khusus untuk menyederhanakan kode.
Misalnya, Anda dapat menggunakan enkapsulasi untuk:
- Menyederhanakan komunikasi lintas jaringan dengan satu objek RemoteEvent.
- Mengelola kode penanganan kesalahan di sekitar layanan sensitif seperti DataStoreService.
- Menetapkan metode khusus untuk mengontrol atau memperluas fitur objek Roblox.
Sulit untuk melacak puluhan objek RemoteEvent individual untuk menerapkan jaringan dalam sebuah permainan. Anda dapat menggunakan ModuleScript untuk mengenkapsulasi satu RemoteEvent untuk membantu menyederhanakan masalah ini. Dengan menyertakan argumen id unik, Anda masih dapat mengirim pesan jaringan yang berbeda sambil hanya menggunakan satu RemoteEvent.
Dalam contoh di bawah ini, ModuleScript bernama NetworkManagerClient mengenkapsulasi metode RemoteEvent:FireServer() untuk menyertakan argumen id tambahan ini. Selain itu, ModuleScript ini merujuk pada objek RemoteEvent itu sendiri sehingga Anda tidak perlu merujuknya di bagian lain dari kode Anda. Anda hanya perlu memerlukan ModuleScript ini untuk mengirim pesan jaringan dan tidak perlu berurusan dengan objek RemoteEvent di seluruh basis kode Anda.
Berikut adalah ModuleScript di ReplicatedFirst yang menyediakan fungsi terenkapsulasi yang dapat Anda panggil pada skrip klien Anda untuk mengirim pesan jaringan:
Network Module
-- ModuleScript in ReplicatedFirst bernama NetworkManagerClient
local NetworkManagerClient = {}
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
-- Mengenkapsulasi fungsi FireServer dari objek remote
function NetworkManagerClient.FireServer(id, ...)
remoteEvent:FireServer(id, ...)
end
return NetworkManagerClient
Berikut adalah ModuleScript di ServerScriptService yang menggunakan BindableEvents untuk setiap skrip agar terhubung ke ID tertentu. Ketika seorang klien mengirim pesan jaringan, setiap BindableEvent yang terkait dengan ID yang ditentukan akan dipicu.
-- ModuleScript in ServerScriptService bernama NetworkManagerServer
local NetworkManagerServer = {}
local networkSignalList = {}
function NetworkManagerServer.GetServerEventSignal(id)
local bindableEvent = Instance.new("BindableEvent")
-- Menghubungkan BindableEvent baru ke id
table.insert(networkSignalList, {
id = id,
bindableEvent = bindableEvent,
})
return bindableEvent.Event
end
-- Menghubungkan ke
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
remoteEvent.OnServerEvent:Connect(function(player, id, ...)
-- Mencari setiap bindable event yang cocok dengan ID dari remote event yang diterima
for _, signal in networkSignalList do
if signal.id == id then
signal.bindableEvent:Fire(player, ...)
end
end
end)
return NetworkManagerServer
Berikut adalah LocalScript yang mengirim pesan dengan ID RequestA dengan argumen opsional Hello.
-- LocalScript in ReplicatedFirstlocal ReplicatedFirst = game:GetService("ReplicatedFirst")local NetworkManagerClient = require(ReplicatedFirst:WaitForChild("NetworkManagerClient"))NetworkManagerClient.FireServer("RequestA", "Hello")
Berikut adalah Script yang terhubung ke ID pesan jaringan RequestA dan mencetak pernyataan dengan parameter tambahan apa pun saat menerima permintaan.
-- Script in ServerScriptService
local ServerScriptService = game:GetService("ServerScriptService")
local NetworkManagerServer = require(ServerScriptService:WaitForChild("NetworkManagerServer"))
NetworkManagerServer.GetServerEventSignal("RequestA"):Connect(function(player, ...)
print("Menerima RequestA dari", player, ...)
end)