Los almacenes de datos son un servicio que puedes utilizar para guardar y cargar datos persistentes del jugador a través de diferentes sesiones de jugador. Almacenan información importante, como el progreso o inventario de un jugador, y permiten recuperarla para el jugador la próxima vez que se una a tu juego. Sin almacenes de datos, un jugador perdería todo su progreso cada vez que saliera del juego.
Hay dos tipos de almacenes de datos: estándar y ordenados. Este tutorial utiliza almacenes de datos estándar, que almacenan datos como números, cadenas y tablas que no necesitan ser clasificados ni ordenados.
Usando el archivo del tutorial de almacén de datos Gold Rush - Inicio .rbxl como punto de partida y el archivo del tutorial de almacén de datos Gold Rush - Completo .rbxl como referencia, este tutorial te brinda la base que necesitas para guardar el progreso del jugador y crear juegos más consistentes, incluyendo orientación sobre:
- Guardar y cargar la cantidad de oro que un jugador ha recogido.
- Actualizar la interfaz de usuario para mostrar el inventario de oro del jugador.
- Guardar automáticamente el inventario de oro del jugador cada 30 segundos.
- Guardar la posición del jugador cuando deja el juego.
- Restaurar la posición del jugador cuando vuelve a unirse al juego.
Al final de este tutorial, deberías tener dos scripts con almacenes de datos bajo ServerScriptService:
- Un script actualizado de GoldManager que rastrea, carga y guarda automáticamente el oro del jugador.
- Un script actualizado de PositionManager que guarda la posición del jugador cuando deja el juego y restaura su posición cuando vuelve al juego.

Habilitar el acceso de Studio a los servicios de API
Los almacenes de datos no se almacenan localmente en tu dispositivo, por lo que tu juego depende de la comunicación servidor a servidor con el backend de Roblox para utilizarlos. Por defecto, Studio restringe esta comunicación para prevenir abusos o usos accidentales. El acceso a los servicios de API en Studio está deshabilitado hasta que lo habilites explícitamente para asegurarte de que solo los juegos de confianza pueden leer y escribir en los servidores de backend de Roblox.
Para habilitar el acceso de Studio a los servicios de API para que puedas usar almacenes de datos:
- Abre el archivo de tutorial de almacén de datos Gold Rush - Inicio .rbxl en Studio y crea una copia local.
- De vuelta en Studio, ve a Archivo ⟩ Configuración de Experiencia ⟩ Seguridad.
- Activa Habilitar acceso de Studio a los servicios de API.
- Guarda tus cambios.
Crear un almacén de datos estándar
Al crear un almacén de datos, siempre debes llamar al DataStoreService desde un Script del lado del servidor. Hacer esto es importante porque:
- Roblox bloquea todo acceso al almacén de datos desde el cliente, de modo que solo el servidor tiene permiso para acceder y modificar datos persistentes del jugador.
- Los scripts del lado del servidor se ejecutan en un entorno centralizado, asegurando que los datos que se leen y escriben en tu almacén de datos sean precisos y válidos.
- Dado que los scripts del lado del cliente se ejecutan en el dispositivo del jugador, cualquier jugador podría potencialmente explotar el juego y robar o sobrescribir los datos de otros jugadores si el cliente tuviera acceso a tus almacenes de datos.
También debes darle a tu almacén de datos un nombre único para mantener tus datos organizados y prevenir que se superpongan o entren en conflicto con otros almacenes de datos. En este tutorial, el almacén de datos que guarda y almacena el inventario de oro del jugador se llama PlayerGold.
Para crear el almacén de datos PlayerGold:
Abre el script existente de GoldManager bajo ServerScriptService.

En la parte superior del script, inicializa el DataStoreService y llama a GetDataStore con la cadena "PlayerGold".
local DataStoreService = game:GetService("DataStoreService")local goldStore = DataStoreService:GetDataStore("PlayerGold")
Guardar y cargar datos del jugador
Los almacenes de datos están compuestos por claves, que identifican los datos, y valores, que almacenan datos.
| Clave | Valor | |
|---|---|---|
| Descripción | Una clave es un identificador único que puedes usar para acceder a un pieza específica de datos. Las claves te permiten organizar tus datos para que puedas gestionarlos y depurarlos fácilmente. | Un valor es el dato real que deseas guardar o cargar, como el inventario de un jugador o sus configuraciones. Los valores te permiten almacenar progreso entre sesiones y recuperar datos del jugador la próxima vez que se unan a tu juego. |
| Formatos permitidos | Solo pueden ser cadenas. | Pueden ser números, cadenas, booleanos o tablas. |
| Ejemplos | "Player_A", "TopScore", "GameSetting" | 100, "Level_5", true, {gold = 100, level = 5} |
En este tutorial, la clave es el userId del jugador y el valor es la cantidad de oro que ha recogido. Para utilizar esta clave y valor para guardar y cargar datos del jugador:
En el script de GoldManager, agrega una función auxiliar llamada saveGold para guardar el oro del jugador en el almacén de datos PlayerGold.
local function saveGold(userId, value)local success, err = pcall(function()-- `userId` es la ID única del jugador-- `value` es la cantidad de oro que se va a guardar para ese jugadorgoldStore:SetAsync(userId, value)end)end- OPCIONALAgrega una advertencia a saveGold que imprima la ID del jugador y un mensaje de error. Aunque no es obligatorio, este paso es una buena práctica para una depuración más fácil en caso de que tu función falle.local function saveGold(userId, value)local success, err = pcall(function()-- `userId` es la ID única del jugador-- `value` es la cantidad de oro que se va a guardar para ese jugadorgoldStore:SetAsync(userId, value)end)if not success thenwarn("[ERROR DE GUARDADO] No se pudo guardar el oro para", userId, ":", err)endend
Modifica el evento onPlayerAdded para cargar el oro del jugador cuando se una al juego por primera vez. La función onPlayerAdded actualizada:
- Intenta cargar el contenido dentro del almacén de datos PlayerGold. Retorna ya sea el oro guardado del jugador o un valor de 0 si el jugador no tiene oro o no ha jugado el juego antes.
- Proporciona un registro de depuración para ayudarte a depurar tu código más fácilmente. Este registro de depuración incluye el oro guardado del jugador que se une, o un mensaje de error si onPlayerAdded no puede acceder al almacén de datos.
- Actualiza la interfaz de usuario para mostrar el oro guardado del jugador en su pantalla.
local function onPlayerAdded(player)local userId = player.UserIdlocal success, storedGold = pcall(function()return goldStore:GetAsync(userId)end)if success thenlocal currentGold = storedGold or 0playerGold[userId] = currentGolduiEvent:FireClient(player, {gold = currentGold,doTween = false,showAlert = not success})elseuiEvent:FireClient(player, { showAlert = true })warn("No se pudo cargar el oro para", player.Name)endendModifica el evento onPlayerRemoving para llamar a la función saveGold que creaste anteriormente y guardar el oro del jugador cuando deja el juego.
local function onPlayerRemoving(player)local userId = player.UserIdif playerGold[userId] thensaveGold(userId, playerGold[userId])endend
Guardar datos del jugador automáticamente
Guardar automáticamente los datos de un jugador es una buena práctica porque protege al jugador de perder sus datos. Si solo guardas los datos del jugador cuando dejan el juego con onPlayerRemoving, podrías perder su último progreso si se desconectan inesperadamente del servidor.
Para guardar automáticamente los datos del jugador:
Crea una nueva constante para determinar con qué frecuencia quieres que tu juego guarde automáticamente los datos del jugador. Una constante es una variable cuyo valor no cambia mientras el juego está en ejecución. Puedes usar esta constante para referenciar el intervalo de guardado automático en todo tu script y ajustar fácilmente la frecuencia de guardado automático.
-- Este número está en segundoslocal AUTOSAVE_INTERVAL = 30Agrega una coroutine de guardado automático a la función existente onPlayerAdded para crear un bucle de fondo que se ejecute mientras el jugador esté dentro del juego. Una coroutine es una función que se ejecuta de manera asíncrona; puede pausarse en ciertos puntos, reanudarse donde lo dejó y ejecutarse en paralelo con otras partes de tu script sin bloquearlas.
En este script, el bucle de fondo de la coroutine de guardado automático espera el número de segundos de tu constante AUTOSAVE_INTERVAL, luego llama a la función saveGold que creaste anteriormente.
coroutine.wrap(function()while player.Parent dotask.wait(AUTOSAVE_INTERVAL)if playerGold[userId] thenprint("[AUTOSAVE] Guardando", playerGold[userId], "oro para", player.Name)saveGold(userId, playerGold[userId])endendend)()
Guardar y cargar la posición del jugador
Para guardar la posición de un jugador, trabaja con su Character en lugar del objeto Player en sí. El Character de un jugador representa su modelo físico en el mundo 3D y tiene las coordenadas para su posición y orientación actuales, mientras que el objeto Player solo representa la cuenta de usuario.
Debido a que los almacenes de datos solo pueden guardar tipos de datos básicos como números, cadenas y tablas, no puedes almacenar directamente objetos complejos como valores Vector3 o CFrame. Para guardar la posición de un jugador, necesitas dividirla en tres números separados (las coordenadas X, Y y Z) y guardarlas individualmente. Al cargar la posición más tarde, puedes reconstruir el Vector3 usando las coordenadas guardadas.
Para guardar y cargar la posición del personaje:
Abre el script existente de PositionManager bajo ServerScriptService.
En la parte superior del script, inicializa el DataStoreService y llama a GetDataStore con la cadena "PlayerPosition".
local DataStoreService = game:GetService("DataStoreService")local positionStore = DataStoreService:GetDataStore("PlayerPosition")Agrega una función auxiliar llamada savePosition que toma el userId de un jugador y una posición Vector3. Dado que no puedes guardar valores Vector3 directamente, convierte la posición en una tabla de números X, Y, Z.
local function savePosition(player, position)local userId = player.UserIdlocal success, err = pcall(function()positionStore:SetAsync(userId, {position.X, position.Y, position.Z})end)end- OPCIONALAgrega una advertencia a savePosition que imprima un mensaje de error y el nombre del jugador cuyo posición no pudiste guardar. Aunque no es obligatorio, este paso es una buena práctica para una depuración más fácil en caso de que tu función falle.local function savePosition(player, position)local userId = player.UserIdlocal success, err = pcall(function()positionStore:SetAsync(userId, {position.X, position.Y, position.Z})end)if not success thenwarn("No se pudo guardar la posición para", player.Name, ":", err)endend
Agrega otra función auxiliar llamada loadPosition para cargar las coordenadas guardadas de un jugador en el almacén de datos PlayerPosition. Usa PivotTo para restaurar la posición del personaje en el mundo. Ya que la posición guardada del jugador se devuelve como una tabla, debes reconstruir un Vector3 y luego convertirlo a un CFrame para mover al personaje.
local function loadPosition(userId, character)local userId = player.UserIdlocal success, savedCoords = pcall(function()return positionStore:GetAsync(userId)end)if success and savedCoords thenlocal pos = Vector3.new(savedCoords[1], savedCoords[2], savedCoords[3])print("Restaurada la posición para", player.Name)character:PivotTo(CFrame.new(pos))elseif not success thenwarn("No se pudo cargar la posición para", player.Name)endendModifica el evento onPlayerAdded para configurar la lógica de posición para cada jugador que se une a tu juego. Dentro de la función onPlayerAdded actualizada:
- CharacterAdded llama a loadPosition para restaurar la última ubicación conocida del personaje cuando el personaje de un jugador aparece.
- CharacterRemoving llama a savePosition para guardar la posición actual del personaje del jugador si es eliminado del juego.
- GetPivot obtiene la ubicación exacta del personaje en el mundo en el momento en que son eliminados.
local function onPlayerAdded(player)local userId = player.UserIdplayer.CharacterAdded:Connect(function(character)loadPosition(player, character)end)player.CharacterRemoving:Connect(function(character)local pos = character:GetPivot().PositionsavePosition(player, pos)end)endPlayer.PlayerAdded:Connect(onPlayerAdded)
Código final
Consulta los siguientes fragmentos de código para los scripts completos de GoldManager y PositionManager. Puedes copiarlos y ejecutarlos directamente en el archivo del tutorial sobre guardar datos de Gold Rush - Inicio .rbxl en Studio.
GoldManager
-- Obtener servicios
-- Obtener servicios
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local DataStoreService = game:GetService("DataStoreService")
-- Evento remoto para actualizar la interfaz de usuario
local uiEvent = ReplicatedStorage:WaitForChild("UIEvent")
-- Almacén de datos para guardar los trozos de oro del jugador
local goldStore = DataStoreService:GetDataStore("PlayerGold")
-- Tabla para almacenar los trozos de oro del jugador para una única sesión
local playerGold = {}
-- Constantes
local GOLD_VALUE = 10 -- Cuánto vale cada trozo de oro
local GOLD_REGEN_DELAY = 2 -- El retraso antes de que un trozo reaparezca (en segundos)
local AUTOSAVE_INTERVAL = 30 -- Con qué frecuencia se guardan los trozos del jugador (en segundos)
-- Función para manejar la recolección de un trozo de oro por el jugador
local function processGoldTouch(chunk, player)
-- Ocultar el trozo cuando el jugador lo recoge
chunk.Parent = nil
-- Agregar el trozo al puntaje de oro de sesión del jugador
local userId = player.UserId
playerGold[userId] = (playerGold[userId] or 0) + GOLD_VALUE
print(player.Name, "ahora tiene", playerGold[userId], "oro")
-- Actualizar la interfaz de usuario para reflejar el nuevo puntaje de oro para esta sesión
uiEvent:FireClient(player, {
gold = playerGold[userId],
doTween = true,
showAlert = false
})
-- Esperar un poco y luego reaparecer el trozo de oro que se acaba de recoger
task.delay(GOLD_REGEN_DELAY, function()
chunk.Parent = workspace.GoldChunks
end)
end
-- Recorrer todas las partes etiquetadas con "Gold" y conectarlas a la detección de toque
for _, chunk in ipairs(CollectionService:GetTagged("Gold")) do
chunk.Touched:Connect(function(otherPart)
local player = Players:GetPlayerFromCharacter(otherPart.Parent)
if player then
processGoldTouch(chunk, player)
end
end)
end
-- Función para guardar el oro del jugador en el almacén de datos
local function saveGold(player, value)
local userId = player.UserId
local success, err = pcall(function()
goldStore:SetAsync(userId, value)
end)
if not success then
warn("No se pudo guardar el oro para", player.Name, ":", err)
end
end
-- Función para manejar la unión del jugador al juego
local function onPlayerAdded(player)
local userId = player.UserId
print(player.Name, "se ha unido al juego")
-- Intentar cargar el oro del jugador desde el almacén de datos
local success, storedGold = pcall(function()
return goldStore:GetAsync(userId)
end)
if success then
-- Establecer el puntaje de oro de sesión actual usando el valor del almacén de datos para el jugador
local currentGold = storedGold or 0
playerGold[userId] = currentGold
-- Actualizar la interfaz de usuario con el valor del almacén de datos para el jugador
uiEvent:FireClient(player, {
gold = currentGold,
doTween = false,
showAlert = false
})
print("Cargado", currentGold, "oro para", player.Name)
else
-- Notificar al jugador que su oro no pudo ser cargado
uiEvent:FireClient(player, { showAlert = true })
warn("No se pudo cargar el oro para", player.Name)
end
-- Iniciar la coroutine de autosave para guardar el oro del jugador cada 30 segundos
coroutine.wrap(function()
while player.Parent do
task.wait(AUTOSAVE_INTERVAL)
if playerGold[userId] then
saveGold(player, playerGold[userId])
print("Guardando automáticamente", playerGold[userId], "oro para", player.Name)
end
end
end)()
end
-- Función para manejar la salida del jugador del juego
local function onPlayerRemoving(player)
local userId = player.UserId
print(player.Name, "ha salido del juego")
-- Comprobar si se ha rastreado el oro del jugador
if playerGold[userId] then
-- Guardar el oro del jugador en el almacén de datos antes de que se vaya
saveGold(player, playerGold[userId])
end
end
-- Conectar los eventos de unión y salida del jugador
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)
PositionManager
-- Obtener servicios
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
-- Almacén de datos para guardar la posición del jugador
local positionStore = DataStoreService:GetDataStore("PlayerPosition")
-- Función para guardar la posición del jugador como una tabla de {X, Y, Z}
local function savePosition(player, position)
local userId = player.UserId
local success, err = pcall(function()
positionStore:SetAsync(userId, {position.X, position.Y, position.Z})
end)
if not success then
warn("No se pudo guardar la posición para", player.Name, ":", err)
end
end
-- Función para cargar la última posición guardada del jugador y mover su personaje
local function loadPosition(player, character)
local userId = player.UserId
local success, savedCoords = pcall(function()
return positionStore:GetAsync(userId)
end)
if success and savedCoords then
local pos = Vector3.new(savedCoords[1], savedCoords[2], savedCoords[3])
print("Restaurada la posición para", player.Name)
character:PivotTo(CFrame.new(pos))
elseif not success then
warn("No se pudo cargar la posición para", player.Name)
end
end
-- Función para manejar la unión del jugador al juego
local function onPlayerAdded(player)
local userId = player.UserId
-- Intentar cargar la posición del jugador cuando su personaje aparece
player.CharacterAdded:Connect(function(character)
loadPosition(player, character)
end)
-- Guardar la posición del jugador cuando su personaje es eliminado
player.CharacterRemoving:Connect(function(character)
local pos = character:GetPivot().Position
savePosition(player, pos)
end)
end
Players.PlayerAdded:Connect(onPlayerAdded)