Ya tienes un enemigo al que se puede pegar. Ahora quieres que al morir suelte algo: monedas, un arma, de vez en cuando algo bueno. Es el bucle que engancha en cualquier juego de progresión, y montarlo bien tiene más miga de la que parece.
En la demo puedes darle al enemigo hasta matarlo y ver qué suelta, con las probabilidades a la vista.
Respuesta rápida
Escucha Humanoid.Died, tira la tabla de botín, y crea el objeto en el mundo con un poco de dispersión para que no salgan todos apilados. Y una bandera para que no suelte dos veces, porque Died puede dispararse más de una vez.
Lo que necesitas antes de empezar
- Un Model con un
Humanoidque haga de enemigo. - Saber cómo funciona una tabla de pesos: está en rarezas con probabilidades reales.
- Unos 25 minutos.
Paso 1: detectar la muerte
-- Script dentro del Model del enemigo
local enemigo = script.Parent
local humanoide = enemigo:WaitForChild("Humanoid")
local yaSolto = false
humanoide.Died:Connect(function()
if yaSolto then return end
yaSolto = true
print("el enemigo ha muerto")
end)
Esa bandera no es paranoia: si el enemigo recibe dos golpes en el mismo fotograma, o si algo toca su vida después de morir, Died puede llegar dos veces y te encuentras con el doble de botín.
Paso 2: la tabla de botín
Igual que en las rarezas, con pesos relativos. La diferencia es que aquí conviene separar si suelta algo de qué suelta:
local PROBABILIDAD_DE_SOLTAR = 0.7 -- 70 % de las veces suelta algo
local BOTIN = {
{nombre = "Moneda", peso = 600, color = Color3.fromRGB(240, 200, 80)},
{nombre = "Poción", peso = 250, color = Color3.fromRGB(90, 200, 130)},
{nombre = "Gema azul", peso = 100, color = Color3.fromRGB(80, 150, 220)},
{nombre = "Anillo raro", peso = 40, color = Color3.fromRGB(160, 100, 230)},
{nombre = "Espada legendaria", peso = 10, color = Color3.fromRGB(240, 170, 60)},
}
local function elegirBotin()
local total = 0
for _, o in ipairs(BOTIN) do total = total + o.peso end
local tirada = math.random() * total
local acumulado = 0
for _, o in ipairs(BOTIN) do
acumulado = acumulado + o.peso
if tirada <= acumulado then return o end
end
return BOTIN[1]
end
Separar las dos tiradas te da mucho control. Un enemigo débil puede tener un 30 % de soltar algo con la misma tabla, y un jefe un 100 % y tres objetos. No duplicas tablas: cambias un número.

Paso 3: crear el objeto en el mundo
local function soltar(objeto, posicion)
local drop = Instance.new("Part")
drop.Name = objeto.nombre
drop.Size = Vector3.new(1.5, 1.5, 1.5)
drop.Color = objeto.color
drop.Material = Enum.Material.Neon
drop.CanCollide = false -- que el jugador no tropiece con él
drop.Anchored = false
-- Un poco de dispersión para que no salgan apilados
local desvio = Vector3.new(
math.random(-30, 30) / 10,
2,
math.random(-30, 30) / 10
)
drop.Position = posicion + desvio
drop.Parent = workspace
-- Un empujoncito hacia arriba, queda mejor
drop.AssemblyLinearVelocity = Vector3.new(0, 15, 0)
-- Se borra solo a los 30 segundos para no llenar el mapa
game:GetService("Debris"):AddItem(drop, 30)
return drop
end
Tres detalles que marcan la diferencia:
CanCollide = false: si los drops chocan, el jugador se queda enganchado en un montón de monedas.- La dispersión aleatoria: sin ella, si un enemigo suelta tres objetos salen los tres exactamente en el mismo punto y parece uno solo.
Debris:AddItem: los drops que nadie recoge se borran solos. Sin esto, en una hora de partida tienes mil Parts en el mapa y el juego va a tirones.

Paso 4: que se pueda recoger
local function hacerRecogible(drop, objeto)
local prompt = Instance.new("ProximityPrompt")
prompt.ActionText = "Recoger"
prompt.ObjectText = objeto.nombre
prompt.MaxActivationDistance = 8
prompt.RequiresLineOfSight = false
prompt.Parent = drop
local recogido = false
prompt.Triggered:Connect(function(jugador)
if recogido then return end
recogido = true
-- Aquí lo metes en el inventario del jugador
print(jugador.Name .. " ha recogido " .. objeto.nombre)
drop:Destroy()
end)
end
Otra vez una bandera: sin recogido, dos jugadores que pulsen a la vez se llevan los dos el mismo objeto.
Paso 5: todo junto
humanoide.Died:Connect(function()
if yaSolto then return end
yaSolto = true
local raiz = enemigo:FindFirstChild("HumanoidRootPart")
local posicion = raiz and raiz.Position or Vector3.new(0, 5, 0)
-- ¿Suelta algo esta vez?
if math.random() > PROBABILIDAD_DE_SOLTAR then
return
end
local objeto = elegirBotin()
local drop = soltar(objeto, posicion)
hacerRecogible(drop, objeto)
-- El cadáver se borra a los 3 segundos
game:GetService("Debris"):AddItem(enemigo, 3)
end)
Guardar la posición antes de que desaparezca el cuerpo es importante: si esperas, HumanoidRootPart puede haberse ido ya y el botín aparece en el origen del mapa.
Paso 6: soltar varios objetos
Para un jefe, o para que suelte monedas siempre y además algo con suerte:
local CUANTOS = 3
for i = 1, CUANTOS do
local objeto = elegirBotin()
local drop = soltar(objeto, posicion)
hacerRecogible(drop, objeto)
task.wait(0.1) -- pequeño escalonado, queda mucho mejor
end
Ese task.wait(0.1) entre objetos hace que salgan disparados de uno en uno en lugar de todos en el mismo fotograma. Es un detalle visual que se nota.
Pruébalo aquí
Mátalo y mira qué suelta
Las dos tiradas del artículo, funcionando: primero si suelta algo, luego qué suelta.
| Objeto | Peso | Probabilidad | Te ha salido |
|---|
Errores habituales
Suelta el doble de objetos
Falta la bandera yaSolto. Died puede dispararse más de una vez.
El botín aparece en el centro del mapa
Estás leyendo la posición después de que el cuerpo desaparezca. Guárdala en una variable nada más entrar en Died.
Los drops se acumulan y el juego va lento
No estás usando Debris:AddItem. Sin eso, cada objeto que nadie recoge se queda ahí para siempre.
Dos jugadores recogen el mismo objeto
Falta la bandera recogido dentro de Triggered.
El jugador se queda atascado en los drops
CanCollide está activado. Desactívalo en el Part del botín.
attempt to index nil with 'Position'
El enemigo no tiene HumanoidRootPart, normalmente porque es un modelo hecho a mano sin la estructura de un personaje. Usa el PrimaryPart del Model, o cualquier Part suyo.
Preguntas frecuentes
¿Cómo hago que solo pueda recogerlo quien lo mató?
Died no te dice quién fue: tienes que llevar tú la cuenta del daño. Guarda en una tabla quién le pegó y cuánto, y en Triggered compruebas que el jugador sea ese.
¿Cómo evito que un jugador con suerte reviente la economía?
Ahí es donde entra ajustar los pesos y poner topes: máximo de objetos raros por hora, o subir el precio de las cosas conforme el jugador acumula.
¿Puedo soltar herramientas de verdad y no cubos de colores?
Sí: en vez de crear un Part, clona una Tool de ServerStorage y ponla en el Backpack del jugador al recoger.
¿Esto se puede trampear?
Si el script está en el servidor, no. Si la tirada la hiciera el cliente, cualquiera se daría legendarios. Como siempre: las probabilidades se resuelven en el servidor.
Última revisión: 1 de septiembre de 2026



Deja una respuesta