Pet Following Help!

So i’ve used the pet following script form this guy : How to create a pet system that dynamically generates positions

the problem with this is that is soo lagy

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Network = require(game.ReplicatedStorage.FrameWork.Main.Network)
warn(Network)

local Characters = {}
Characters.__index = Characters

function Characters:new()
	warn("Setting up character...")

	local PlayerData = Network.Invoke("GetData")
	warn(PlayerData)

	if not PlayerData or not PlayerData.Characters then
		warn("Failed to get PlayerData or Pets is missing!")
		return nil
	end

	local self = setmetatable({
		Characters = PlayerData.Characters
	}, Characters)

	return self
end

function Characters.Follow()
	--getting RunService
	local RunService = game:GetService("RunService")

	--Congiurable values
	local maxPetsPerRow = 3 --how many pets can be in one row
	local distancebetweenColumns = 5 --gap between columns
	local distanceBetweenRows = 3 --gap between rows
	local behindPlayerDistance = 3 --distance from player
	local floatHeight = 3 --height above the ground
	local smoothness = 4 --how fast the pet gets into position

	--Main function to change Position formations
	function Characters.GridPositionGen(numOfPets, petIndex, playerHrp) :Vector3

		--lua for loop starts at 1
		petIndex -= 1
		local temp = maxPetsPerRow 
		if numOfPets < maxPetsPerRow then
			maxPetsPerRow = numOfPets
		end

		local horizontalOffset = 0

		if petIndex - maxPetsPerRow*math.floor(numOfPets/maxPetsPerRow) < 0 then
			horizontalOffset = (petIndex%maxPetsPerRow * distancebetweenColumns) - ((maxPetsPerRow-1)*distancebetweenColumns)/2
		else
			maxPetsPerRow = numOfPets - maxPetsPerRow*math.floor(numOfPets/maxPetsPerRow)
			horizontalOffset = petIndex%maxPetsPerRow * distancebetweenColumns - ((maxPetsPerRow-1)*distancebetweenColumns)/2
			maxPetsPerRow = temp
		end

		local backwardsOffset = playerHrp.Position - playerHrp.CFrame.LookVector*behindPlayerDistance - playerHrp.CFrame.LookVector*distanceBetweenRows*(math.floor(petIndex/maxPetsPerRow))
		local offset = backwardsOffset + playerHrp.CFrame.RightVector*horizontalOffset

		maxPetsPerRow = temp

		return offset

	end
	function Characters.CheckForFloor(offset:Vector3, filter:{Instance})

		--raycast from the offset downwards to detect the floor
		local rayParams = RaycastParams.new()
		rayParams.FilterDescendantsInstances = filter
		rayParams.FilterType = Enum.RaycastFilterType.Blacklist
		local ray = workspace:Raycast(offset + Vector3.new(0, 5, 0), Vector3.new(0, -9999, 0), rayParams)

		if ray then 
			--If the ray hit a floor it will return the Y coord + floatHeight
			return ray.Position.Y + floatHeight
		else
			--If the ray didn't hit a floor is will return nil and print a warning
			warn("no floor detected")
			return
		end

	end

	--Goes through a player's pet folder and put the pets at the correct position
	function Characters.RenderPets(petsFolder, player, deltaTime)

		--checks if the player's character spawned yet and if deltaTime was given else don't
		--render this player's pets
		if not player.Character or not player.Character.HumanoidRootPart then return end
		if not deltaTime then print("no deltaTime given") return end

		--getting the players's Character and HumanoidRootPart
		local char = player.Character
		local hrp = char:WaitForChild("HumanoidRootPart")

		--loop through each pet of the folder to lerp them
		--into eh correct position
		for i, v in pairs(petsFolder:GetChildren()) do

			--getting the offset from the player, note we have to subtract 1 from i as it starts from 1
			--but we need it to start from 0 otherwise every pet 1 space off 
			local offset = Characters.GridPositionGen(#petsFolder:GetChildren(), i, hrp)

			--Getting the distance we need from the floor so the pet will stay at a constant height from
			--the floor
			local verticalPos =  Characters.CheckForFloor(offset, {char, petsFolder}) or hrp.CFrame.Position.Y 
			--the or is for if the ray did not hit the floor, the pet will be at character Y position

			offset = Vector3.new(offset.X, verticalPos, offset.Z)

			--creating the CFrame where the pet should be
			local c = CFrame.new(offset, offset + hrp.CFrame.LookVector)

			--Lerping the pet to the target CFrame so its more smooth
			v.PrimaryPart = v:WaitForChild("HumanoidRootPart")
			if v.PrimaryPart and v.PrimaryPart.CFrame  then
			v:SetPrimaryPartCFrame(v.PrimaryPart.CFrame:Lerp(c, smoothness*deltaTime))
			end
		end

	end

	RunService.Heartbeat:Connect(function(deltaTime)
		for i, player in pairs(game.Players:GetPlayers()) do
			if not workspace.Pets:FindFirstChild(player.Name.."-Pets") then continue end
			Characters.RenderPets(workspace.Pets:FindFirstChild(player.Name.."-Pets"), player, deltaTime)

		end
	end)
end


Characters.Follow()

return Characters


this is the script

1 Like

The reason why it’s lagging is due to the amount of player models (probably because of the humanoid?).

Many pet simulators and tds games would usually limit the pet/unit count to 3-6 to reduce lag. From what I’m seeing, the code is not optimised enough for that many pets (e.g. the amount of ray and position callbacks within runservice for each pet).

Overall, i’d suggest for you to limit the amount of pets following you. (Important)

Although, if you’re willing to change the code up a bit. You could try using lerp or tweenservice while giving your runservice a bit more delay so that it won’t be heavy on the system.

1 Like

Thank you! ill try that out! ill let you know

one thing i don’t use Humanoid:MoveTo() i generate a Lerp and then SetThePrimartyPartCFrame to the generateed Lerp