Pular para o conteúdo
PTEntrar

Como fazer uma roleta no Roblox?

Sorteie o prêmio primeiro e anime depois. O servidor tira um número com peso, decide qual fatia ganhou e manda esse índice para o cliente; o cliente gira a roda para parar nela. Animar primeiro e ler o ângulo depois é como uma roleta vira algo pagável pelo cliente.

Em resumo

  • Pesos, não fatias iguais: um prêmio de 1 em 200 é peso 1 contra 199.
  • Quem sorteia é o servidor. O giro é a animação de uma decisão já tomada.
  • Faça a roda parar sempre na fatia que o servidor escolheu, nunca o contrário.

Toda roleta que já foi explorada foi feita na ordem errada: gira a roda, vê onde parou, paga aquilo. Faça ao contrário e não há o que explorar — o cliente está só reproduzindo um resultado que ele não consegue mudar.

Passo a passo

1. Escreva os prêmios como pesos

Peso é "quantos bilhetes este prêmio tem no saco". Lê melhor que porcentagem porque acrescentar um prêmio não obriga você a recalcular todos os outros números.

local PREMIOS = {
	{ nome = "50 moedas",    peso = 400, moedas = 50 },
	{ nome = "150 moedas",   peso = 250, moedas = 150 },
	{ nome = "500 moedas",   peso = 100, moedas = 500 },
	{ nome = "2.000 moedas", peso = 40,  moedas = 2000 },
	{ nome = "Pet raro",     peso = 9,   pet = "Rare" },
	{ nome = "Pet mítico",   peso = 1,   pet = "Mythic" },
}

local TOTAL = 0
for _, p in PREMIOS do
	TOTAL += p.peso
end

2. Sorteie no servidor

Um objeto Random para o servidor inteiro, não um novo por giro: um Random.new() criado dentro de um laço, com semente do relógio, pode dar o mesmo prêmio a dois jogadores no mesmo tick.

local rng = Random.new()

local function sortear(): number
	local bilhete = rng:NextInteger(1, TOTAL)
	local soma = 0
	for i, p in PREMIOS do
		soma += p.peso
		if bilhete <= soma then
			return i
		end
	end
	return #PREMIOS
end

3. Pague e só então diga ao cliente onde parar

O que viaja é o índice, não o prêmio: o cliente já tem a lista, e mandar o pagamento é convidar alguém a mudá-lo no caminho de volta.

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local giro = Instance.new("RemoteEvent")
giro.Name = "SpinWheel"
giro.Parent = ReplicatedStorage

local espera: { [number]: number } = {}

giro.OnServerEvent:Connect(function(player: Player)
	-- O único limite que importa: o cliente dispara um RemoteEvent na
	-- velocidade que quiser, então recusar um giro tem de ser barato.
	local agora = os.clock()
	if espera[player.UserId] and agora - espera[player.UserId] < 3 then return end
	espera[player.UserId] = agora

	local indice = sortear()
	local premio = PREMIOS[indice]
	if premio.moedas then
		local stats = player:FindFirstChild("leaderstats")
		local moedas = stats and stats:FindFirstChild("Coins")
		if moedas then
			moedas.Value = moedas.Value + premio.moedas
		end
	end
	giro:FireClient(player, indice)
end)

Players.PlayerRemoving:Connect(function(player)
	espera[player.UserId] = nil
end)

4. Gire a roda até aquela fatia

O ângulo é aritmética: as voltas inteiras para o show, mais o deslocamento da fatia vencedora. O TweenService com um ease-out longo faz o resto.

local TweenService = game:GetService("TweenService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local roda = script.Parent -- um ImageLabel com as fatias desenhadas
local FATIAS = 6
local giro = ReplicatedStorage:WaitForChild("SpinWheel")

giro.OnClientEvent:Connect(function(indice: number)
	local porFatia = 360 / FATIAS
	-- Quatro voltas inteiras e, no fim, a fatia vencedora no topo.
	local destino = 360 * 4 + (360 - (indice - 1) * porFatia)
	local tween = TweenService:Create(
		roda,
		TweenInfo.new(4, Enum.EasingStyle.Quint, Enum.EasingDirection.Out),
		{ Rotation = destino }
	)
	tween:Play()
	tween.Completed:Wait()
	roda.Rotation = destino % 360 -- deixa o número pequeno para o próximo giro
end)

Onde decidir o prêmio

Onde o sorteio aconteceO jogador consegue mudarParece instantâneoVeredito
Servidor, antes da animaçãonãosim, o giro cobre a esperaÉ o que fazer
Cliente, servidor só pagasim — inteiramentesimNunca: o pagamento é uma variável do cliente
Servidor, lendo o ângulo finalnão, mas frágilnãoEvite: um erro de arredondamento paga a fatia errada
Servidor com espera por jogadornãosimIgual à primeira linha, com um piso contra spam

Perguntas

Como fazer um prêmio de exatamente 0,5%?

Dê peso 1 a ele e faça os outros somarem 199. Porcentagem é o que você imprime na interface; peso é o que o código sorteia. Manter os dois separados deixa um designer acrescentar um prêmio sem refazer seis números.

A roda precisa ter fatias iguais?

Visualmente não, e é melhor que não tenha — uma fatia desenhada como um risco fino já comunica raridade. O que importa é que a fatia no topo quando o tween para seja a que o servidor escolheu, então a geometria desenhada e a ordem dos índices têm de bater.

Dois jogadores podem tirar o mítico no mesmo instante?

Podem, e está certo: cada giro é um sorteio próprio. Se você quer um prêmio que exista uma vez só na experiência inteira, isso não é problema de roleta — é um contador de estoque num DataStore, reduzido com UpdateAsync antes de o prêmio ser anunciado.

Por que a minha roda dá um salto antes de girar?

Porque Rotation ficou num número tipo 1.448 do giro anterior e o tween novo começa dali. Normalize com % 360 quando o tween terminar, como acima.

Atualizado: Testado no Studio: Roblox Studio, outubro de 2026Autor: GustavoLicença: O código deste guia pode ser usado em qualquer experiência do Roblox, inclusive paga

Pack relacionado

Ultimate Script Pack

Ultimate Script Pack

US$ 40Ver o pack

Quero ser avisado

Em breve

Deixe seu e-mail e a gente te avisa na hora em que este pack sair.