Ya sabes tirar una tabla de pesos. Lo que falta es el cofre: el objeto que está ahí en el mapa, que alguien abre, que suelta algo y que —y esto es lo que menos se piensa— tiene que decidir quién puede abrirlo y cuándo vuelve a estar disponible.
Porque un cofre mal planteado tiene un problema muy concreto: el primero que llega se lo lleva todo y los demás se encuentran una caja vacía. Eso, multiplicado por un servidor de veinte personas, es un juego que aburre en cinco minutos.
En la demo tienes tres jugadores y el mismo cofre montado de las dos maneras: compartido y por jugador. Prueba a abrirlo con los tres.
Respuesta rápida
Un ProximityPrompt para abrirlo, la tirada en el servidor, y una decisión de diseño: cofre compartido (se vacía y reaparece a los X segundos) o cofre por jugador (cada uno lo abre una vez). Para casi todos los juegos, por jugador con reaparición.
Lo que necesitas antes de empezar
- La tabla de pesos: rarezas con probabilidades reales.
- Un sitio donde meter lo que salga: el inventario.
- Unos 35 minutos.
Paso 1: el cofre en el mundo
Un Model con la base, la tapa y un ProximityPrompt:
-- Script dentro del Model del cofre
local cofre = script.Parent
local base = cofre:WaitForChild("Base")
local prompt = Instance.new("ProximityPrompt")
prompt.ActionText = "Abrir"
prompt.ObjectText = "Cofre"
prompt.HoldDuration = 0.6 -- que haya que mantener: evita abrirlo sin querer
prompt.MaxActivationDistance = 10
prompt.RequiresLineOfSight = false
prompt.Parent = base
Ese HoldDuration de medio segundo hace más de lo que parece: sin él, pasar por delante pulsando E abre cofres sin querer, y luego la gente jura que «no le ha dado nada».
Paso 2: quién puede abrirlo
Aquí está la decisión de diseño. Las dos opciones:
| Cofre compartido | Cofre por jugador | |
|---|---|---|
| Quién se lo lleva | El primero que llegue | Cada uno el suyo |
| Qué siente el que llega tarde | Que ha perdido el tiempo | Nada, lo abre igual |
| Para qué sirve | Competir, carreras, PvP | Explorar, progresar |
| El problema | El que madruga se lleva todo | Menos motivo para correr |
Para un juego de exploración o de progresión, por jugador. Para uno de competición, compartido y con reaparición corta, para que haya carrera.

Paso 3: el cofre por jugador
local Jugadores = game:GetService("Players")
local ESPERA = 300 -- 5 minutos hasta que ese jugador pueda volver a abrirlo
local abiertoPor = {} -- abiertoPor[jugador] = momento
local function puedeAbrir(jugador)
local ultimo = abiertoPor[jugador]
if not ultimo then return true end
return os.clock() - ultimo >= ESPERA
end
prompt.Triggered:Connect(function(jugador)
if not puedeAbrir(jugador) then
avisar(jugador, "Este cofre todavía no")
return
end
abiertoPor[jugador] = os.clock()
local objeto = tirarBotin()
entregar(jugador, objeto)
anunciar(jugador, objeto)
end)
Jugadores.PlayerRemoving:Connect(function(jugador)
abiertoPor[jugador] = nil
end)
Es el mismo patrón que el de los cooldowns: una marca de tiempo por jugador, y limpieza al salir.
Un matiz importante: ese cooldown vive en la memoria del servidor. Si el jugador se cambia de servidor, el cofre vuelve a estar disponible. Para un cofre normal da igual; para uno que da algo valioso, guárdalo en el DataStore.
Paso 4: el cofre compartido, con reaparición
local disponible = true
local REAPARECE = 45
prompt.Triggered:Connect(function(jugador)
if not disponible then return end
disponible = false
prompt.Enabled = false
abrirTapa() -- animación
local objeto = tirarBotin()
entregar(jugador, objeto)
task.delay(REAPARECE, function()
cerrarTapa()
disponible = true
prompt.Enabled = true
end)
end)
prompt.Enabled = false es importante: además de la bandera, quita el cartel de la pantalla de todo el mundo. Si el cartel sigue ahí y no pasa nada al pulsarlo, parece que el juego está roto.
Paso 5: que el cofre cuente algo
Un cofre que suelta un objeto sin más está bien. Uno que además cambia de aspecto engancha:
local COLORES = {
comun = Color3.fromRGB(150, 150, 160),
raro = Color3.fromRGB(80, 150, 220),
epico = Color3.fromRGB(160, 100, 230),
legendario = Color3.fromRGB(240, 170, 60),
}
local function brillar(rareza)
local luz = base:FindFirstChildOfClass("PointLight")
if not luz then return end
luz.Color = COLORES[rareza] or COLORES.comun
luz.Brightness = 6
game:GetService("TweenService"):Create(luz,
TweenInfo.new(1.5), {Brightness = 0}):Play()
end
Y si lo que sale es muy raro, anúncialo a todo el servidor. Que otro vea «Fulano ha sacado una espada legendaria» es la mejor publicidad que tiene tu cofre. La animación completa de apertura está en la caja de botín con animación.
Paso 6: muchos cofres sin repetir código
No dupliques el script en cada cofre. Uno solo que los recorra todos:
-- ServerScriptService
local cofres = workspace:WaitForChild("Cofres")
for _, cofre in ipairs(cofres:GetChildren()) do
montarCofre(cofre)
end
cofres.ChildAdded:Connect(montarCofre)
Con eso, añadir un cofre al mapa es arrastrar un modelo a la carpeta. Y si mañana cambias cómo funcionan, lo cambias en un sitio.
Para colocar cofres por el mapa de forma aleatoria:
local PUNTOS = workspace.PuntosDeCofre:GetChildren()
local CUANTOS = 8
local elegidos = {}
for i = 1, math.min(CUANTOS, #PUNTOS) do
local n = math.random(i, #PUNTOS)
PUNTOS[i], PUNTOS[n] = PUNTOS[n], PUNTOS[i] -- barajado
table.insert(elegidos, PUNTOS[i])
end
for _, punto in ipairs(elegidos) do
local cofre = plantilla:Clone()
cofre:PivotTo(punto.CFrame)
cofre.Parent = cofres
end
Ese barajado (Fisher-Yates) es la forma correcta de elegir ocho puntos distintos de veinte. Sacar números al azar y comprobar si ya salió funciona, pero se atasca cuando quedan pocos libres.
Pruébalo aquí
El mismo cofre, montado de dos maneras
Tres jugadores llegan al cofre. Ábrelo con cada uno y mira quién se queda con cara de tonto.
Errores habituales
El primero que llega vacía el mapa
Es el cofre compartido sin reaparición. Decide: o reaparece, o es por jugador.
El cartel sigue ahí pero no pasa nada
Falta prompt.Enabled = false mientras el cofre está vacío.
Dos jugadores abren el mismo cofre a la vez y salen dos objetos
Triggered puede entrar dos veces antes de que pongas la bandera. Ponla en la primera línea, antes de cualquier task.wait.
Al abrirlo se le da el objeto a todo el mundo
Triggered te da el jugador que lo activó: úsalo. Si entregas con un bucle sobre GetPlayers, se lo das a todos.
El cofre reaparece pero la tapa se queda abierta
La animación de cierre no se ejecuta si cancelaste el tween o si el modelo se movió. Coloca el estado final a mano al reaparecer.
En Studio funciona y en el juego no
Comprueba que el script es del servidor y que el cofre no está dentro de algo que el cliente pueda borrar.
Preguntas frecuentes
¿Cada cuánto debería reaparecer un cofre?
Lo bastante como para que dé tiempo a dar una vuelta por el mapa, no tanto como para que la gente se plante a esperar. Entre treinta segundos y dos minutos suele funcionar; míralo con gente jugando.
¿Puedo hacer que haga falta una llave?
Sí, y es una buena forma de que el botín signifique algo: la llave se compra en la tienda o cae de los enemigos. Comprueba y gasta la llave antes de tirar.
¿Cómo hago un cofre que solo aparezca de vez en cuando?
Un bucle en el servidor que cada cierto tiempo lo coloque en un punto aleatorio y lo quite pasado un rato. Anuncia en el chat cuando aparezca: es de lo que más junta a la gente.
¿Y si quiero que el cofre sea de un solo uso para siempre?
Entonces la marca va al DataStore, con el identificador del cofre: cofresAbiertos = {cofre_cueva_1 = true}. Es lo que hacen los juegos de exploración con cofres escondidos.
Última revisión: 2 de septiembre de 2026





Deja una respuesta