Cómo hacer un cofre que dé objetos aleatorios

Claim Your Loot

·

Portada del artículo «Un cofre que da objetos aleatorios», de la sección Sistemas de botín

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

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 compartidoCofre por jugador
Quién se lo llevaEl primero que llegueCada uno el suyo
Qué siente el que llega tardeQue ha perdido el tiempoNada, lo abre igual
Para qué sirveCompetir, carreras, PvPExplorar, progresar
El problemaEl que madruga se lleva todoMenos 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.

El mismo cofre compartido y por jugador, con lo que le pasa a cada uno de los tres jugadores

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.

Mantén E · Abrir
Cofre compartido · disponible

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

Claim Your Loot

Explora otras secciones

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *