Ok so i got a pet script from someone helping me with bugs earlier and it works great, its exactly what i wanted, But, it lags SO MUCH!
ive tried everything i know about optimizing code (Not that much lol) but cant seem to fix it.
so only one solution! back to the dev forum !!
heres my code
-- module
local Pets = {}
Pets.__index = Pets
-- variables
-- players and their owned pets with a type so we understand the structure.
-- This type definition helps with understanding the structure of serverPets.
type PlayerPetArray = { [Player]: {typeof(setmetatable({}, Pets))} }
-- serverPets stores a table of pets for each player. The keys are Player objects, and the values are arrays of pet objects.
local serverPets: PlayerPetArray = {}
-- This function creates a new entry in serverPets for a player if one doesn't exist.
local function createEntry(player: Player)
serverPets[player] = {} -- Initialize an empty table for the player's pets.
return {} -- Return an empty table. This isn't strictly necessary, but it mirrors how Pets.new works.
end
local methods = {} -- This table will hold the methods for the Pet objects.
function Pets.new(player: Player,pet)
-- get the player's owned pets or create a new empty table of pets
-- If the player already has pets, retrieve them; otherwise, create a new entry for the player.
local theirPets = serverPets[player] or createEntry(player)
-- Create a new part to represent the pet.
local newPet = pet:Clone()
newPet.Name = `{player.Name}'s Pet ({#theirPets})` -- Give the pet a name based on the player and pet count.
newPet.Parent = workspace -- Parent the pet to the workspace.
table.insert(serverPets[player], newPet) -- Add the new pet's part to the player's pet array.
-- pet properties (example)
-- Create a new pet object using a metatable to give it methods.
local self = setmetatable({}, Pets)
self.petName = "john" -- Example pet name.
self.petRarity = "ultra rare glowy" -- Example pet rarity.
self.instance = newPet -- Store the pet's part instance.
return self -- Return the new pet object.
end
-- Method to move the pet.
function Pets:Move(newCFrame: CFrame)
local instance: Part = self.instance -- Get the pet's part instance.
instance.CFrame = newCFrame -- Set the pet's CFrame.
end
local RunService = game:GetService("RunService")
-- This function is called every heartbeat to update the pet positions.
local function onHeartbeat(deltaTime: number)
for player, petArray in pairs(serverPets) do -- Iterate through each player and their pets.
local character = player.Character -- Get the player's character.
if character then
local hrp = character:FindFirstChild("HumanoidRootPart") -- Get the HumanoidRootPart.
if hrp then
local baseCFrame : CFrame = hrp.CFrame -- Get the HRP's CFrame.
local position : Vector3 = baseCFrame.Position -- Get the HRP's position.
local rightVec : Vector3 = baseCFrame.RightVector -- Get the HRP's right vector.
local petCount : number = #petArray -- Get the number of pets the player has.
for i, pet in ipairs(petArray) do -- Iterate through each of the player's pets.
local targetPos: Vector3 -- Declare the target position.
local offsetDistance : number = 5 -- Distance between the player and the pets.
if petCount == 2 then -- Special case for two pets: one on each side.
if i == 1 then
targetPos = position + rightVec * offsetDistance
else -- i == 2
targetPos = position - rightVec * offsetDistance
end
else -- For more than two pets, arrange them in a circle.
local angle : number = (2 * math.pi / petCount) * (i - 1) -- Calculate the angle for each pet.
local offset : Vector3 = Vector3.new(math.cos(angle) * offsetDistance, 0, math.sin(angle) * offsetDistance) -- Calculate the offset.
targetPos = position + baseCFrame:VectorToWorldSpace(offset) -- Apply the offset relative to the player's CFrame.
end
local targetCFrame = CFrame.new(targetPos) -- Create the target CFrame.
local lerpAlpha = math.clamp(10 * deltaTime, 0, 1) -- Calculate the interpolation alpha.
pet:SetPrimaryPartCFrame(pet.PrimaryPart.CFrame:Lerp(targetCFrame, lerpAlpha)) -- Smoothly move the pet to the target position.
end
end
end
end
end
RunService.Heartbeat:Connect(onHeartbeat)
return Pets -- Return the Pets module.
Thanks for any help!
edit: before anyone says “Look up how to optimize code” i did and it did not help.
The pet visuals could be done on each player’s client instead of the server; this also gives you a way for a player to hide others’ (or their own) pets.
You can use RenderStepped in a LocalScript to move the pets on each player’s client.
Your script lags because it updates pet positions every frame, which is too demanding. reduce the update frequency and offload heavy tasks to separate threads.
My guess would be that moving the pets is what is laggy, but I don’t mean your code, I mean the roblox engine
However, there are tricks to speed that up by a lot
First of all SetPrimaryPartCFrame is deprecated, and PivotTo() should be used instead, but even PivotTo() is laggy
The most efficient way to move models around is by moving the rootpart of the model. The rootpart needs to be the only anchored part, and should be welded directly or indirectly to every other part
By doing so, you can update the CFrame property of the rootpart, rather than moving the model. workspace:BulkMoveTo() can also be used, but the performance increase isn’t as drastic
You shouldn’t, unless maybe you make a throttling system for far away pets, but imo not that worth doing
Simulating the pets on the client however will help as you’d reduce network usage, and the client wont have to simulate every pet (you can make a system to only simulate pets close by)
But ultimately, if it lags on the server, it is likely to still lag the client, so moving the pets using the rootpart is kind of required
Use a time-based system that updates pet positions at fixed intervals (eg. every 0.1 secs) and smooths movement with Lerp . Avoid while loops, as they block the main thread and can cause performance issues.
Use RemoteEvents to tell each client which pets are currently active. Then, simply locally move the pets.
Remember that the player would only be able to see their pets this way. If you wanted every player’s pet to be displayed for all players, you’d have to keep track of every single pet currently active.
From experience, the lag doesn’t come from calculating the position. While CFrame math is on the expensive side, moving objects around, especially models using PivotTo() is way more significant performance wise
To find these kinds of optimizations, the micro profiler is extremely useful, as it tells precisely what takes a long time
If I remember correctly, tweens aren’t more performant than changing the CFrame, or at least not by a lot. However, tweenServices activity is not shown in the script activity tab, because it runs in another thread I believe
It would work just fine - you’d just have to locally render every player’s pets on every player’s client. A bit more logic involved but nothing too difficult
Sorry for not providing the link earlier, I’m on my phone so it’s not very easy to do
The micro profiler is complicated to understand, but very powerful. I’m not sure I should recommend you learn to use it as a beginner, but nothing is better to optimize a game