Después de crear algunos scripts, nunca pasa mucho tiempo antes de que quieras reutilizar algo de código entre ellos.Dependiendo de ubicación, ModuleScripts te permite reutilizar código entre scripts en diferentes lados del límite cliente-servidor o del mismo lado del límite.
Puedes poner los scripts de módulo en cualquier lugar donde pongas scripts, pero ReplicatedStorage es una ubicación popular; almacenar los scripts de módulo aquí te permite reutilizar el código entre el servidor y los clientes.
Anatomía de un script de módulo
En Roblox Studio, agregue un script de módulo a ReplicatedStorage y renómbrelo a PickupManager . Cada ModuleScript comienza con el siguiente código:
local module = {}return module
Este código crea una tabla Luau vacía y la devuelve a cualquier script que requiera el script del módulo.
El valor de devolución puede ser cualquier tipo de dato excepto nil, pero la mayoría de los scripts de módulo devuelven una función, una tabla o una tabla de funciones.Para generar su valor de devolución, los scripts de módulo pueden, por supuesto, ejecutar código arbitrario, que incluye requerir otros scripts de módulo.
El siguiente ejemplo devuelve una tabla con una sola función llamada getPickupBonus. Pégalo en el nuevo guión de script:
-- ModuleScript en Almacenamiento replicado
local PickupManager = {}
local defaultMultiplier = 1.25
local rarityMultipliers = {
common = 10,
uncommon = 20,
rare = 50,
legendary = 100
}
-- Añade la función getPickupBonus a la tabla PickupManager
PickupManager.getPickupBonus = function(rarity)
local bonus = rarityMultipliers[rarity] * defaultMultiplier
return bonus
end
return PickupManager
Añadir la función a una tabla no es estrictamente necesario—podrías simplemente devolver la propia función—pero es un buen patrón a seguir; te da una sintaxis fácil de entender cuando llamas a la función desde otro script y te permite agregar fácilmente más funciones al script del módulo con el tiempo.
Requerir scripts de módulo
Para cargar un guión de módulo, llamas a la función require().En ReplicatedStorage , agregue un nuevo script y cambie su RunContext a Client .Luego agregue el siguiente código para llamar la función PickupManager.getPickupBonus:
Script de cliente en ReplicatedStorage
local ReplicatedStorage = game:GetService("ReplicatedStorage")-- Obtener el valor devuelto por el ModuleScriptlocal PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))-- Llamar una función de ModuleScriptlocal bonus = PickupManager.getPickupBonus("legendary")print(bonus) --> 125
Almacenar scripts de módulo en ReplicatedStorage te permite compartir código entre el servidor y el cliente, por lo que puedes usar el mismo código para requerir el script de ServerScriptService :
Script en ServerScriptService
local ReplicatedStorage = game:GetService("ReplicatedStorage")local PickupManager = require(ReplicatedStorage:WaitForChild("PickupManager"))
Cuando llamas a require() en un ModuleScript, se ejecuta una vez y devuelve un solo artículo como referencia.Llamar de nuevo devuelve exactamente la misma referencia, lo que significa que si modificas una tabla devuelta o , las siguientes llamadas devuelven esa referencia modificada.El propio módulo no se ejecuta varias veces.
Si requiere un ModuleScript de ambos lados del límite cliente-servidor, como en el ejemplo anterior, el ModuleScript devuelve una referencia única para cada lado.
Patrones
Los scripts de módulo tienen algunos patrones comunes que puedes usar para simplificar tu código y evitar trampas a medida que tu experiencia crece en tamaño y complejidad.
Compartir datos
Para asociar datos con objetos individuales, puedes asignarles atributos o crear carpetas Configuration con objetos de valor como StringValue o IntValue .Sin embargo, ambos enfoques son problemáticos si desea agregar o modificar docenas de objetos o valores de datos.Tampoco almacenan tablas o funciones.
Si desea modificar los mismos datos para múltiples copias del mismo objeto o reutilizar los mismos datos para diferentes objetos, almacene los datos en ModuleScripts .Es una forma más fácil de reutilizar los datos en otros scripts y puedes almacenar tablas y funciones.
El siguiente ejemplo ModuleScript en ReplicatedStorage almacena los valores de configuración para una arma genérica:
ModuleScript en Almacenamiento replicado
local GunConfig = {}GunConfig.MagazineSize = 20GunConfig.AmmoCount = 100GunConfig.Firerate = 600GunConfig.Damage = {["Head"] = 50;["Torso"] = 40;["Body"] = 25;}return GunConfig
Eventos personalizados
Los eventos personalizados permiten que los scripts se comuniquen entre sí, pero tener que realizar un seguimiento de las referencias a objetos individuales BindableEvent puede desordenar tu código.
Puedes usar ModuleScripts para almacenar BindableEvents y proporcionar manejadores de eventos personalizados que estén directamente vinculados a los métodos de ModuleScript .
El siguiente ModuleScript en ReplicatedStorage tiene un evento personalizado que se activa cuando el interruptor cambia de estado:
ModuleScript en Almacenamiento replicado
local Switch = {}
-- Crear vinculable para que cualquier script pueda escuchar cuando se cambió el interruptor
local bindableEvent = Instance.new("BindableEvent")
Switch.Changed = bindableEvent.Event
local state = false
function Switch.flip()
state = not state
bindableEvent:Fire(state)
end
return Switch
El siguiente script de cliente en ReplicatedStorage conecta una función para llamar cuando se activa el evento Switch.Changed.
Guión en ReplicatedStorage
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Switch = require(ReplicatedStorage:WaitForChild("Switch"))
Switch.Changed:Connect(function(newState)
print("Switch state is now", newState)
end
-- Prueba voltear varias veces
task.wait(1)
Switch.flip()
task.wait(1)
Switch.flip()
Encapsulación
La encapsulación es la práctica de crear una capa de abstracción alrededor de objetos o lógica de scripting para ocultar la complejidad.Puedes usar ModuleScripts para encapsular objetos de Roblox con funciones Luau personalizadas para simplificar el código.
Por ejemplo, puedes usar la encapsulación para:
- Simplifica la comunicación entre redes con un solo objeto RemoteEvent .
- Envuelve el código de manejo de errores alrededor de servicios sensibles como DataStoreService .
- Define métodos personalizados para controlar o extender las funciones de los objetos de Roblox.
Es difícil mantener un seguimiento de docenas de objetos individuales RemoteEvent para implementar la red en tu juego.Puedes usar un ModuleScript para encapsular un solo RemoteEvent para ayudar a simplificar este problema.Al incluir un argumento único id , aún puedes enviar diferentes mensajes de red mientras solo usas un solo RemoteEvent .
En el ejemplo a continuación, el ModuleScript llamado NetworkManagerClient encapsula el método RemoteEvent:FireServer() para incluir este argumento adicional id.Además, esta ModuleScript se refiere al objeto RemoteEvent en sí mismo para que no tengas que referenciarlo en otras partes de tu código.Solo necesitas requerir esto ModuleScript para enviar mensajes de red y no necesitas lidiar con RemoteEvent objetos en el resto de tu base de código.
El siguiente ModuleScript en ReplicatedFirst proporciona una función encapsulada que puedes llamar a tus scripts de cliente para enviar un mensaje de red:
Módulo de red
-- ModuleScript en ReplicatedFirst llamado NetworkManagerClient
local NetworkManagerClient = {}
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
-- Encapsular la función FireServer del objeto remoto
function NetworkManagerClient.FireServer(id, ...)
remoteEvent:FireServer(id, ...)
end
return NetworkManagerClient
El siguiente ModuleScript en ServerScriptService utiliza BindableEvents para que cada script se conecte a un ID específico.Cuando un cliente envía un mensaje de red, cada BindableEvent asociado con el ID especificado se activa.
-- ModuleScript en ServerScriptService llamado NetworkManagerServer
local NetworkManagerServer = {}
local networkSignalList = {}
function NetworkManagerServer.GetServerEventSignal(id)
local bindableEvent = Instance.new("BindableEvent")
-- Enlazar el nuevo evento vinculable al ID
table.insert(networkSignalList, {
id = id,
bindableEvent = bindableEvent,
})
return bindableEvent.Event
end
-- Conectando a
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("RemoteEvent")
remoteEvent.OnServerEvent:Connect(function(player, id, ...)
-- Encontrar cada evento vinculable que coincida con el ID del evento remoto recibido
for _, signal in networkSignalList do
if signal.id == id then
signal.bindableEvent:Fire(player, ...)
end
end
end)
return NetworkManagerServer
El siguiente LocalScript envía un mensaje con el ID RequestA con un argumento opcional Hello.
-- Guión local en ReplicatedFirstlocal ReplicatedFirst = game:GetService("ReplicatedFirst")local NetworkManagerClient = require(ReplicatedFirst:WaitForChild("NetworkManagerClient"))NetworkManagerClient.FireServer("RequestA", "Hello")
El siguiente Script se conecta al ID de mensaje de red RequestA y imprime una declaración con cualquier parámetro adicional cuando recibe la solicitud.
-- Script en ServerScriptService
local ServerScriptService = game:GetService("ServerScriptService")
local NetworkManagerServer = require(ServerScriptService:WaitForChild("NetworkManagerServer"))
NetworkManagerServer.GetServerEventSignal("RequestA"):Connect(function(player, ...)
print("Received RequestA from", player, ...)
end)