Dopo aver creato alcuni script, non passa molto tempo prima di voler riutilizzare del codice tra di essi. A seconda della posizione, ModuleScripts ti consente di riutilizzare codice tra script su lati diversi del confine client-server o sullo stesso lato del confine.
Puoi posizionare gli script modulo ovunque tu metta script, ma ReplicatedStorage è una posizione popolare; memorizzare gli script modulo qui ti consente di riutilizzare il codice tra il server e i clienti.
Anatomia di uno script modulo
In Roblox Studio, aggiungi uno script modulo a ReplicatedStorage e rinominalo in PickupManager. Ogni ModuleScript inizia con il seguente codice:
local module = {}return module
Questo codice crea una tabella Luau vuota e la restituisce a qualsiasi script che richiede lo script modulo.
Il valore di ritorno può essere di qualsiasi tipo di dato tranne nil, ma la maggior parte degli script modulo restituisce una funzione, una tabella o una tabella di funzioni. Per generare il suo valore di ritorno, gli script modulo possono ovviamente eseguire codice arbitrario, che include la richiesta di altri script modulo.
Il seguente esempio restituisce una tabella con una singola funzione chiamata getPickupBonus. Incollala nel nuovo script modulo:
-- ModuleScript in ReplicatedStorage
local PickupManager = {}
local defaultMultiplier = 1.25
local rarityMultipliers = {
comune = 10,
uncommon = 20,
rare = 50,
legendary = 100
}
-- Aggiungi la funzione getPickupBonus alla tabella PickupManager
PickupManager.getPickupBonus = function(rarity)
local bonus = rarityMultipliers[rarity] * defaultMultiplier
return bonus
end
return PickupManager
Aggiungere la funzione a una tabella non è strettamente necessario: potresti semplicemente restituire la funzione stessa, ma è un buon modello da seguire; ti offre una sintassi facile da capire quando chiami la funzione da un altro script e ti consente di aggiungere facilmente altre funzioni allo script modulo nel tempo.
Richiedere script modulo
Per caricare uno script modulo, chiami la funzione require(). In ReplicatedStorage, aggiungi un nuovo script e cambia il suo RunContext in Client. Poi aggiungi il seguente codice per chiamare la funzione PickupManager.getPickupBonus:
Script client in ReplicatedStoragelocal ReplicatedStorage = game:GetService("ReplicatedStorage")-- Ottieni il valore restituito dallo ScriptModulolocal PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))-- Chiama una funzione dello ScriptModulolocal bonus = PickupManager.getPickupBonus("legendary")print(bonus) --> 125
Memorizzare gli script modulo in ReplicatedStorage ti consente di condividere codice tra il server e il client, quindi puoi utilizzare lo stesso codice per richiedere lo script da ServerScriptService:
Script in ServerScriptServicelocal ReplicatedStorage = game:GetService("ReplicatedStorage")local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))
Quando chiami require() su un ModuleScript, viene eseguito una volta e restituisce un singolo elemento come riferimento. Chiamare nuovamente require() restituisce esattamente lo stesso riferimento, il che significa che se modifichi una tabella o Instance restituita, le successive chiamate a require() restituiscono quel riferimento modificato. Il modulo stesso non viene eseguito più volte.
Se richiedi un ModuleScript da entrambi i lati del confine client-server, come nell'esempio sopra, il ModuleScript restituisce un riferimento univoco per ciascun lato.
Modelli
Gli script modulo hanno alcuni modelli comuni che puoi utilizzare per semplificare il tuo codice ed evitare insidie man mano che il tuo gioco cresce in dimensioni e complessità.
Condivisione dei dati
Per associare dati a singoli oggetti, puoi assegnare loro attributi o creare cartelle Configuration con oggetti valore come StringValue o IntValue. Tuttavia, entrambi gli approcci sono problematici se desideri aggiungere o modificare dozzine di oggetti o valori di dati. Non memorizzano neanche tabelle o funzioni.
Se desideri modificare gli stessi dati per più copie dello stesso oggetto o riutilizzare gli stessi dati per oggetti diversi, memorizza i dati in ModuleScripts. È un modo più semplice per riutilizzare i dati in altri script e puoi memorizzare tabelle e funzioni.
Il seguente esempio di ModuleScript in ReplicatedStorage memorizza i valori di configurazione per una pistola generica:
ModuleScript in ReplicatedStoragelocal GunConfig = {}GunConfig.MagazineSize = 20GunConfig.AmmoCount = 100GunConfig.Firerate = 600GunConfig.Damage = {["Head"] = 50;["Torso"] = 40;["Body"] = 25;}return GunConfig
Eventi personalizzati
Gli eventi personalizzati consentono agli script di comunicare tra loro, ma dover tenere traccia dei riferimenti agli oggetti BindableEvent individuali può ingombrare il tuo codice.
Puoi utilizzare ModuleScripts per memorizzare BindableEvents e fornire gestori di eventi personalizzati che sono direttamente legati ai metodi di ModuleScript.
Il seguente ModuleScript in ReplicatedStorage ha un evento personalizzato che si attiva quando l'interruttore cambia stato:
ModuleScript in ReplicatedStorage
local Switch = {}
-- Creazione bindable affinché qualsiasi script possa ascoltare quando l'interruttore è cambiato
local bindableEvent = Instance.new("BindableEvent")
Switch.Changed = bindableEvent.Event
local state = false
function Switch.flip()
state = not state
bindableEvent:Fire(state)
end
return Switch
Il seguente script client in ReplicatedStorage collega una funzione da chiamare quando si attiva l'evento Switch.Changed.
Script in ReplicatedStorage
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Switch = require(ReplicatedStorage:WaitForChild("Switch"))
Switch.Changed:Connect(function(newState)
print("Lo stato dell'interruttore è ora", newState)
end)
-- Testa il ribaltamento alcune volte
task.wait(1)
Switch.flip()
task.wait(1)
Switch.flip()
Incapsulamento
L'incapsulamento è la pratica di creare uno strato di astrazione attorno agli oggetti o alla logica di scripting per nascondere la complessità. Puoi utilizzare ModuleScripts per incapsulare oggetti Roblox con funzioni Luau personalizzate per semplificare il codice.
Ad esempio, puoi utilizzare l'incapsulamento per:
- Semplificare la comunicazione attraverso la rete con un singolo oggetto RemoteEvent.
- Racchiudere il codice di gestione degli errori attorno a servizi sensibili come DataStoreService.
- Definire metodi personalizzati per controllare o estendere le funzionalità degli oggetti Roblox.
È difficile tenere traccia di dozzine di oggetti RemoteEvent individuali per implementare la rete in un gioco. Puoi utilizzare un ModuleScript per incapsulare un singolo RemoteEvent per aiutarti a semplificare questo problema. Includendo un argomento id univoco, puoi comunque inviare diversi messaggi di rete utilizzando solo un singolo RemoteEvent.
Nel seguente esempio, il ModuleScript chiamato NetworkManagerClient incapsula il metodo RemoteEvent:FireServer() per includere questo ulteriore argomento id. Inoltre, questo ModuleScript fa riferimento all'oggetto RemoteEvent stesso in modo da non doverlo riferire in altre parti del tuo codice. Devi solo richiedere questo ModuleScript per inviare messaggi di rete e non devi gestire oggetti RemoteEvent nel resto della tua base di codice.
Il seguente ModuleScript in ReplicatedFirst fornisce una funzione incapsulata che puoi chiamare nei tuoi script client per inviare un messaggio di rete:
Network Module
-- ModuleScript in ReplicatedFirst chiamato NetworkManagerClient
local NetworkManagerClient = {}
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
-- Incapsulamento della funzione FireServer dell'oggetto remoto
function NetworkManagerClient.FireServer(id, ...)
remoteEvent:FireServer(id, ...)
end
return NetworkManagerClient
Il seguente ModuleScript in ServerScriptService utilizza BindableEvents per ogni script per collegarsi a un ID specifico. Quando un client invia un messaggio di rete, ogni BindableEvent associato all'ID specificato si attiva.
-- ModuleScript in ServerScriptService chiamato NetworkManagerServer
local NetworkManagerServer = {}
local networkSignalList = {}
function NetworkManagerServer.GetServerEventSignal(id)
local bindableEvent = Instance.new("BindableEvent")
-- Collega il nuovo BindableEvent all'id
table.insert(networkSignalList, {
id = id,
bindableEvent = bindableEvent,
})
return bindableEvent.Event
end
-- Connessione a
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
remoteEvent.OnServerEvent:Connect(function(player, id, ...)
-- Trovare ogni evento bindable che corrisponde all'ID dell'evento remoto ricevuto
for _, signal in networkSignalList do
if signal.id == id then
signal.bindableEvent:Fire(player, ...)
end
end
end)
return NetworkManagerServer
Il seguente LocalScript invia un messaggio con l'ID RequestA con un argomento opzionale Hello.
-- LocalScript in ReplicatedFirstlocal ReplicatedFirst = game:GetService("ReplicatedFirst")local NetworkManagerClient = require(ReplicatedFirst:WaitForChild("NetworkManagerClient"))NetworkManagerClient.FireServer("RequestA", "Hello")
Il seguente Script si connette all'ID del messaggio di rete RequestA e stampa una dichiarazione con eventuali parametri aggiuntivi quando riceve la richiesta.
-- Script in ServerScriptService
local ServerScriptService = game:GetService("ServerScriptService")
local NetworkManagerServer = require(ServerScriptService:WaitForChild("NetworkManagerServer"))
NetworkManagerServer.GetServerEventSignal("RequestA"):Connect(function(player, ...)
print("Ricevuta RequestA da", player, ...)
end)