As you probably know, Humanoids in large numbers can cause a LOT of lag and so when you are making a game that needs a lot of units moving around you can run into some problems. In the game im working on a need a lot animals and so Ive made my own basic humanoid for them, it just includes basic gravity, being able to move up and down slopes and moving to any given point in a straight line
Ive successfully made my custom Humanoid for these units and have already seen drastic improvements from normal Humanoids. I was able to spawn 200 units on my baseplate and have them all move to the center without no-clipping through anything while still having everything running smoothly without lag. When i attempted to do this with regular Humanoids it lagged so much I could barely move the camera. So there is already some fair improvement.
However in the script performance tab under Activity it says im using 50% which is higher than id like. When I try this on my phone it runs ok, but there is some obvious lag, nothing game-breaking but its enough to be annoying to look at
This is my first time making something like this and Id like help optimizing my code for this so that it will run as efficiently as possible, thus more units. This is about 120 lines of code so I understand if you don’t want to take the trouble to analyze it but if anyone sees anything that could be improved please chime in with a reply, thanks for any suggestions!
This code is in a server script calling functions from a module script in a Stepped event which I believe is being called every 1/60th of a second. The functions being called are applying gravity because the animals are anchored and they are updating the animals’ CFrames and trying to move them towards their target point every iteration
game["Run Service"].Stepped:connect(function() for x, animal in ipairs(workspace.Animals:GetChildren()) do animoidCore.walkToPoint(animal) animoidCore.applyGravityAndFloorStops(animal) end end)
This code for the above functions is in a seperate module script shown below
local gravity = 1 local stepsPerSecond = 60 local lerpIterations = 10 --Applies gravity to the animal also makes the animal stop falling when it hits the ground and allows it to stay on top of a slope function module.applyGravityAndFloorStops(animal) local animoid = animal.Animoid local animalCframe, animalSize = animal:GetBoundingBox() local gravityRay = Ray.new(animalCframe.p, Vector3.new(0, -animalSize.Y/1.5, 0)) local partHit, hitPoint = workspace:FindPartOnRayWithIgnoreList(gravityRay, animal:GetChildren(), false, true) --Detect if the animal is no longer on the ground if not partHit and animoid.Grounded.Value == true then animoid.Grounded.Value = false end --Detect if the animal is moving into a slope if partHit and animalCframe.p.Y ~= (hitPoint.Y + animalSize.Y/2) then animoid.Grounded.Value = false end --Apply gravity to the animal if partHit and not animoid.Grounded.Value then local distLeft = (animalCframe.p.Y - animalSize.Y/2) - hitPoint.Y animal:SetPrimaryPartCFrame(animal:GetPrimaryPartCFrame() - Vector3.new(0, distLeft, 0)) animoid.Grounded.Value = true elseif not animoid.Grounded.Value then animal:SetPrimaryPartCFrame(animal:GetPrimaryPartCFrame() - Vector3.new(0, gravity, 0)) end return true end function distanceBetweenPoints(v1, v2) return math.sqrt(math.abs(v1.X - v2.X)^2 + math.abs(v1.Z - v2.Z)^2) end --Makes the animal walk in a straight line towards the point set in its Animoid Folder function module.walkToPoint(animal) local animoid = animal.Animoid local point = animoid.WalkToPoint.Value local animalPosition = animal.PrimaryPart.Position point = Vector3.new(point.X, animalPosition.Y, point.Z) --Make sure the animal isn't already at the point, ignore Y-axis if animalPosition ~= point then --Make the animal face the point its moving to if animoid.Core.FaceLerpIteration.Value <= lerpIterations then local goalCframe = CFrame.new(animalPosition, point) local lerpCframe = animal:GetPrimaryPartCFrame():lerp(goalCframe, animoid.Core.FaceLerpIteration.Value/lerpIterations) animal:SetPrimaryPartCFrame(lerpCframe) animoid.Core.FaceLerpIteration.Value = animoid.Core.FaceLerpIteration.Value + 1 end --------------Movement--------------- local direction = (point - animal.PrimaryPart.Position).unit--The direction that the animal needs to travel in local distance = distanceBetweenPoints(point, animalPosition) local walkSpeed = animoid.WalkSpeed.Value/stepsPerSecond local increment = direction * walkSpeed local newCFrame = animal:GetPrimaryPartCFrame() + increment ---Collision Detection--- local _, animalSize = animal:GetBoundingBox() local ray = Ray.new(animalPosition, direction * animalSize.Z/0.5) local partHit = workspace:FindPartOnRayWithIgnoreList(ray, animal:GetChildren(), false, true) --Check if we should increment regularly or just jump to the end position if distance > 0.2 and not partHit then animal:SetPrimaryPartCFrame(newCFrame)--Just increment the movement elseif not partHit then --Jump to the end position local rotation = animal.PrimaryPart.CFrame - animal.PrimaryPart.CFrame.p animal:SetPrimaryPartCFrame(CFrame.new(point) *rotation) end end end