Como fazer um pet que segue o jogador no Roblox?
Mova o pet no cliente, a cada quadro, com matemática de CFrame — não com um BodyMover e não no servidor. O pet é um modelo ancorado que caminha por lerp até um ponto atrás do personagem. O servidor só decide qual pet está equipado; o seguir é local e não custa nada.
Em resumo
- Partes ancoradas e RenderStepped, nunca física: pet com física briga com o personagem.
- Um deslocamento por vaga, para dois pets nunca ficarem um dentro do outro.
- O servidor manda em qual pet está equipado; o cliente manda em onde ele está.
Os pets que parecem bons não são simulados, são desenhados. Um pet movido por física no servidor empurra o jogador numa rampa, atrasa num ping de 200 ms e custa uma atualização de rede por quadro. O mesmo pet interpolado no cliente fica exatamente onde deveria, de graça.
Passo a passo
1. Prepare o modelo
Um Model com PrimaryPart, todas as partes ancoradas e sem colisão. Pet que colide é pet que empurra o jogador da ponte.
local function preparar(modelo: Model): Model
for _, parte in modelo:GetDescendants() do
if parte:IsA("BasePart") then
parte.Anchored = true
parte.CanCollide = false
parte.CanQuery = false
parte.CanTouch = false
parte.Massless = true
end
end
if not modelo.PrimaryPart then
modelo.PrimaryPart = modelo:FindFirstChildWhichIsA("BasePart")
end
return modelo
end
2. Dê um deslocamento a cada vaga
Três pets no mesmo lugar parecem um pet. Os deslocamentos são uma tabela pequena, em studs, relativa ao personagem.
local VAGAS = {
Vector3.new(-2.5, 1.5, 3),
Vector3.new(2.5, 1.5, 3),
Vector3.new(0, 1.5, 4.5),
}
3. Siga no RenderStepped
Lerp é o truque inteiro: ande uma fração da distância que falta a cada quadro e o pet vem atrás naturalmente, sem nenhum código de easing.
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
local function seguir(modelo: Model, vaga: number)
local desloc = VAGAS[vaga] or VAGAS[1]
local balanco = 0
RunService.RenderStepped:Connect(function(dt: number)
local char = player.Character
local root = char and char:FindFirstChild("HumanoidRootPart")
if not root or not modelo.PrimaryPart then return end
balanco += dt
local alvo = root.CFrame * CFrame.new(desloc + Vector3.new(0, math.sin(balanco * 3) * 0.25, 0))
-- Olhando para onde o jogador olha, e sempre em pé.
alvo = CFrame.new(alvo.Position) * CFrame.Angles(0, select(2, root.CFrame:ToEulerAnglesYXZ()), 0)
-- 0,15 por quadro a 60 fps dá um rastro suave; 1 cola o pet no ponto.
modelo:PivotTo(modelo.PrimaryPart.CFrame:Lerp(alvo, math.min(1, dt * 9)))
end)
end
4. Equipe pelo servidor
O servidor diz quais pets estão fora; o cliente constrói. O que viaja é a lista, não os modelos.
-- Servidor
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local equipado = Instance.new("RemoteEvent")
equipado.Name = "PetsEquipped"
equipado.Parent = ReplicatedStorage
local MAX_FORA = 3
local function definirEquipados(player: Player, petIds: { string })
local fora = {}
for i = 1, math.min(#petIds, MAX_FORA) do
fora[i] = petIds[i]
end
-- Todo mundo vê os pets de todo mundo, então isto vai para todos os clientes.
equipado:FireAllClients(player, fora)
end
-- Cliente
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local modelos = ReplicatedStorage:WaitForChild("PetModels")
local equipado = ReplicatedStorage:WaitForChild("PetsEquipped")
local vivos: { [Player]: { Model } } = {}
equipado.OnClientEvent:Connect(function(dono: Player, petIds: { string })
for _, m in vivos[dono] or {} do
m:Destroy()
end
local criados = {}
for i, id in petIds do
local fonte = modelos:FindFirstChild(id)
if fonte then
local m = preparar(fonte:Clone())
m.Parent = workspace
seguir(m, i)
criados[#criados + 1] = m
end
end
vivos[dono] = criados
end)
Como mover o pet
| Método | Fica bom | Custa rede | Empurra o jogador | Veredito |
|---|---|---|---|---|
RenderStepped + Lerp no cliente | sim | nada | não | É o que fazer |
AlignPosition no servidor | às vezes | todo quadro | sim, em rampas | Evite para pets |
BodyPosition / BodyGyro | não | todo quadro | sim | Obsoleto; não use |
| Soldar no personagem | não — fica rígido | nada | não | Só para uma mochila, não para um pet |
Perguntas
O pet deve ficar dentro do modelo do personagem?
Não. Coloque em workspace (ou numa pasta dentro dele) e mova com PivotTo. Dentro do personagem ele herda a física do personagem e o Humanoid passa a tratá-lo como parte do corpo.
Por que o meu pet atrasa quando o jogador corre?
Porque o fator do lerp está pequeno, ou porque você está movendo no servidor. Suba o dt * 9 até algo como dt * 16 para um seguir mais colado. Se estiver no servidor, nenhum fator resolve: a posição está chegando pela rede.
Os outros jogadores veem o pet?
Só se o evento de equipar for para todos os clientes, como acima, e cada cliente construir o modelo localmente. Um pet criado no servidor é replicado para todos e custa uma atualização por quadro — que é justamente o que este desenho existe para evitar.
Quantos pets um jogador pode ter fora?
Três é um teto razoável, e o teto fica no servidor (MAX_FORA). O cliente poderia desenhar trinta; o que impede é o servidor nunca nomear mais de três.
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
