Po stworzeniu kilku skryptów, szybko pojawia się potrzeba ponownego wykorzystania niektórych fragmentów kodu między nimi. W zależności od lokalizacji, ModuleScripts pozwala na ponowne wykorzystanie kodu między skryptami po różnych stronach granicy klient-serwer lub po tej samej stronie granicy.
Możesz umieścić skrypty modułowe wszędzie tam, gdzie umieszczasz skrypty, ale ReplicatedStorage jest popularnym miejscem; przechowywanie tam skryptów modułowych pozwala Ci ponownie wykorzystywać kod między serwerem a klientami.
Budowa skryptu modułowego
W Roblox Studio dodaj skrypt modułowy do ReplicatedStorage i zmień jego nazwę na PickupManager. Każdy ModuleScript zaczyna się od następującego kodu:
local module = {}return module
Ten kod tworzy pustą tabelę Luau table i zwraca ją do każdego skryptu, który wymaga skryptu modułowego.
Wartość zwracana może być dowolnym typem danych oprócz nil, ale większość skryptów modułowych zwraca funkcję, tabelę lub tabelę funkcji. Aby wygenerować swoją wartość zwracaną, skrypty modułowe mogą oczywiście uruchamiać dowolny kod, co obejmuje wymaganie innych skryptów modułowych.
Poniższy przykład zwraca tabelę z jedną funkcją o nazwie getPickupBonus. Wklej ją do nowego skryptu modułowego:
-- ModuleScript in ReplicatedStorage
local PickupManager = {}
local defaultMultiplier = 1.25
local rarityMultipliers = {
common = 10,
uncommon = 20,
rare = 50,
legendary = 100
}
-- Dodaj funkcję getPickupBonus do tabeli PickupManager
PickupManager.getPickupBonus = function(rarity)
local bonus = rarityMultipliers[rarity] * defaultMultiplier
return bonus
end
return PickupManager
Dodanie funkcji do tabeli nie jest ściśle konieczne — możesz po prostu zwrócić samą funkcję — ale jest to dobry wzorzec do naśladowania; zapewnia to łatwy do zrozumienia składnik składni, gdy wywołujesz funkcję z innego skryptu i pozwala łatwo dodawać więcej funkcji do skryptu modułowego w miarę upływu czasu.
Wymaganie skryptów modułowych
Aby załadować skrypt modułowy, wywołujesz funkcję require(). W ReplicatedStorage dodaj nowy skrypt i zmień jego RunContext na Client. Następnie dodaj poniższy kod, aby wywołać funkcję PickupManager.getPickupBonus:
Skrypt klienta w ReplicatedStoragelocal ReplicatedStorage = game:GetService("ReplicatedStorage")-- Pobierz wartość zwróconą przez ModuleScriptlocal PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))-- Wywołaj funkcję ModuleScriptlocal bonus = PickupManager.getPickupBonus("legendary")print(bonus) --> 125
Przechowywanie skryptów modułowych w ReplicatedStorage pozwala na dzielenie kodu między serwerem a klientem, więc możesz używać tego samego kodu do wymagania skryptu z ServerScriptService:
Skrypt w ServerScriptServicelocal ReplicatedStorage = game:GetService("ReplicatedStorage")local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))
Kiedy wywołujesz require() na ModuleScript, uruchamia się to raz i zwraca pojedynczy element jako referencję. Ponowne wywołanie require() zwraca dokładnie tę samą referencję, co oznacza, że jeśli zmodyfikujesz zwróconą tabelę lub Instance, kolejne wywołania require() zwracają tę zmodyfikowaną referencję. Sam moduł nie uruchamia się wielokrotnie.
Jeśli wymagasz ModuleScript z obu stron granicy klient-serwer, jak w powyższym przykładzie, ModuleScript zwraca unikalną referencję dla każdej strony.
Wzorce
Skrypty modułowe mają kilka wspólnych wzorców, które możesz wykorzystać do uproszczenia swojego kodu i uniknięcia pułapek, gdy Twoja gra rośnie w rozmiarze i złożoności.
Udostępnianie danych
Aby skojarzyć dane z pojedynczymi obiektami, możesz przypisać im atrybuty lub stworzyć foldery Configuration z obiektami wartości takimi jak StringValue lub IntValue. Jednak oba podejścia są problematyczne, jeśli chcesz dodać lub zmodyfikować dziesiątki obiektów lub wartości danych. Nie przechowują także tabel ani funkcji.
Jeśli chcesz zmodyfikować te same dane dla wielu kopii tego samego obiektu lub ponownie wykorzystać te same dane dla różnych obiektów, przechowuj dane w ModuleScripts. To łatwiejszy sposób na ponowne wykorzystanie danych w innych skryptach, a możesz przechowywać tabele i funkcje.
Poniższy przykład ModuleScript w ReplicatedStorage przechowuje wartości konfiguracyjne dla uniwersalnego pistoletu:
ModuleScript w ReplicatedStoragelocal GunConfig = {}GunConfig.MagazineSize = 20GunConfig.AmmoCount = 100GunConfig.Firerate = 600GunConfig.Damage = {["Head"] = 50;["Torso"] = 40;["Body"] = 25;}return GunConfig
Zdarzenia niestandardowe
Zdarzenia niestandardowe umożliwiają skryptom komunikację ze sobą, ale konieczność śledzenia referencji do poszczególnych obiektów BindableEvent może zagracać Twój kod.
Możesz użyć ModuleScripts, aby przechować BindableEvents i zapewnić niestandardowe obsługi zdarzeń, które są bezpośrednio związane z metodami ModuleScript.
Poniższy ModuleScript w ReplicatedStorage ma niestandardowe zdarzenie, które wywołuje się, gdy przełącznik zmienia stan:
ModuleScript w ReplicatedStorage
local Switch = {}
-- Tworzenie bindable, aby każdy skrypt mógł nasłuchiwać zmiany stanu przełącznika
local bindableEvent = Instance.new("BindableEvent")
Switch.Changed = bindableEvent.Event
local state = false
function Switch.flip()
state = not state
bindableEvent:Fire(state)
end
return Switch
Poniższy skrypt klienta w ReplicatedStorage łączy funkcję do wywołania, gdy zdarzenie Switch.Changed zostanie wywołane.
Skrypt w ReplicatedStorage
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Switch = require(ReplicatedStorage:WaitForChild("Switch"))
Switch.Changed:Connect(function(newState)
print("Stan przełącznika to teraz", newState)
end)
-- Testowanie przełączania kilka razy
task.wait(1)
Switch.flip()
task.wait(1)
Switch.flip()
Kapsułkowanie
Kapsułkowanie to praktyka tworzenia warstwy abstrakcji wokół obiektów lub logiki skryptowej, aby ukryć złożoność. Możesz użyć ModuleScripts do kapsułkowania obiektów Roblox za pomocą niestandardowych funkcji Luau w celu uproszczenia kodu.
Na przykład, możesz użyć kapsułkowania, aby:
- Uprościć komunikację między sieciami za pomocą jednego obiektu RemoteEvent.
- Owinąć kod obsługi błędów wokół wrażliwych usług, takich jak DataStoreService.
- Zdefiniować niestandardowe metody do kontrolowania lub rozszerzania funkcji obiektów Roblox.
Trudno jest śledzić dziesiątki pojedynczych obiektów RemoteEvent, aby wdrożyć sieć w grze. Możesz użyć ModuleScript, aby kapsułkować pojedynczy RemoteEvent, aby uprościć ten problem. Poprzez dodanie unikalnego argumentu id, możesz nadal wysyłać różne wiadomości sieciowe, korzystając tylko z jednego RemoteEvent.
W poniższym przykładzie ModuleScript o nazwie NetworkManagerClient kapsułkuje metodę RemoteEvent:FireServer(), aby uwzględnić ten dodatkowy argument id. Dodatkowo, ten ModuleScript odwołuje się do obiektu RemoteEvent, dzięki czemu nie musisz odwoływać się do niego w innych częściach swojego kodu. Musisz tylko wymagać tego ModuleScript, aby wysyłać wiadomości sieciowe i nie musisz zajmować się obiektami RemoteEvent w reszcie swojej bazy kodu.
Poniższy ModuleScript w ReplicatedFirst zapewnia funkcję kapsułkującą, którą możesz wywołać w swoich skryptach klienta, aby wysłać wiadomość sieciową:
Moduł sieciowy
-- ModuleScript w ReplicatedFirst o nazwie NetworkManagerClient
local NetworkManagerClient = {}
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
-- Kapsułkowanie funkcji FireServer obiektu zdalnego
function NetworkManagerClient.FireServer(id, ...)
remoteEvent:FireServer(id, ...)
end
return NetworkManagerClient
Poniższy ModuleScript w ServerScriptService używa BindableEvents dla każdego skryptu, aby połączyć go z określonym ID. Gdy klient wysyła wiadomość sieciową, każde BindableEvent powiązane z określonym ID zostaje wywołane.
-- ModuleScript w ServerScriptService o nazwie NetworkManagerServer
local NetworkManagerServer = {}
local networkSignalList = {}
function NetworkManagerServer.GetServerEventSignal(id)
local bindableEvent = Instance.new("BindableEvent")
-- Łączenie nowego BindableEvent z id
table.insert(networkSignalList, {
id = id,
bindableEvent = bindableEvent,
})
return bindableEvent.Event
end
-- Łączenie z
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
remoteEvent.OnServerEvent:Connect(function(player, id, ...)
-- Szuka każdej bindable event, która odpowiada ID odebranego zdalnego zdarzenia
for _, signal in networkSignalList do
if signal.id == id then
signal.bindableEvent:Fire(player, ...)
end
end
end)
return NetworkManagerServer
Poniższy LocalScript wysyła wiadomość z ID RequestA z opcjonalnym argumentem Hello.
-- LocalScript w ReplicatedFirstlocal ReplicatedFirst = game:GetService("ReplicatedFirst")local NetworkManagerClient = require(ReplicatedFirst:WaitForChild("NetworkManagerClient"))NetworkManagerClient.FireServer("RequestA", "Hello")
Poniższy Script łączy się z wiadomością sieciową ID RequestA i wypisuje komunikat z dodatkowymi parametrami, gdy otrzyma żądanie.
-- Skrypt w ServerScriptService
local ServerScriptService = game:GetService("ServerScriptService")
local NetworkManagerServer = require(ServerScriptService:WaitForChild("NetworkManagerServer"))
NetworkManagerServer.GetServerEventSignal("RequestA"):Connect(function(player, ...)
print("Odebrano RequestA od", player, ...)
end)