Background
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!
The code
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