How it works
- The server clones each equipped pet into a folder named after its owner, anchored and without collisions.
- Every client moves all the pets every frame, behind their owners. Movement done on the client is smooth at any ping, and since every client runs the same loop, everyone sees everyone’s pets in the right place.
1. Equip pets (server)
A Script in ServerScriptService. Pet models live in ReplicatedStorage.Pets. Here every player gets a Chick and a Bunny; call equip from your inventory code instead.
-- ServerScriptService > PetService (Script)
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local container = Instance.new("Folder")
container.Name = "PlayerPets"
container.Parent = workspace
local function equip(player, petName)
local folder = container:FindFirstChild(player.Name)
if not folder then
folder = Instance.new("Folder")
folder.Name = player.Name
folder.Parent = container
end
local pet = ReplicatedStorage.Pets[petName]:Clone()
for _, part in pet:GetDescendants() do
if part:IsA("BasePart") then
part.Anchored = true
part.CanCollide = false
part.CanQuery = false
end
end
pet.Parent = folder
return pet
end
Players.PlayerAdded:Connect(function(player)
equip(player, "Chick")
equip(player, "Bunny")
end)
Players.PlayerRemoving:Connect(function(player)
local folder = container:FindFirstChild(player.Name)
if folder then
folder:Destroy()
end
end)
2. Follow the owner (client)
A LocalScript in StarterPlayerScripts. Pets line up behind the player, ease towards their spot and bob a little; tweak the four numbers at the top.
-- StarterPlayerScripts > PetFollow (LocalScript)
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local container = workspace:WaitForChild("PlayerPets")
local SPACING = 3.5 -- studs between pets
local BEHIND = 5 -- studs behind the owner
local HEIGHT = -1.5 -- up or down from the owner's root
local SMOOTH = 8 -- higher = snappier
RunService.RenderStepped:Connect(function(dt)
local alpha = 1 - math.exp(-SMOOTH * dt)
for _, folder in container:GetChildren() do
local owner = Players:FindFirstChild(folder.Name)
local character = owner and owner.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
if root then
local pets = folder:GetChildren()
for i, pet in pets do
local x = (i - (#pets + 1) / 2) * SPACING
local bob = math.sin(os.clock() * 4 + i) * 0.15
local goal = root.CFrame * CFrame.new(x, HEIGHT + bob, BEHIND)
pet:PivotTo(pet:GetPivot():Lerp(goal, alpha))
end
end
end
end)
1 - math.exp(-SMOOTH * dt) keeps the easing the same at 30 and at 240 frames per second, so pets don’t lag on slow phones or jitter on fast PCs.
Make it feel like a pet game
- Walk animation: compare a pet’s position with the last frame; if it moved, play Walk, otherwise Idle. Using Cube Pets? Their README explains how to keep the built-in animator running on pets your own script moves.
- Many pets: past five or six, place them on a circle around the player instead of a line:
CFrame.Angles(0, i / #pets * math.pi * 2, 0) * CFrame.new(0, HEIGHT, BEHIND). - Flying pets: raise
HEIGHTfor birds and dragons only, with an attribute on the model.
Pets to follow you
Our Roblox packs are drag-and-drop .rbxm files with animations in code, rarity effects, studs and smooth looks. Try three of them free under CC BY: Cube Pets Free. For eggs and odds, see the egg hatching guide.