I’ve started making a tower defense project and I’ve encountered a bug that I do not know how to fix.
Basically, the higher I set the FPS, or the amount of position updates in a second of the zombie the slower it is.
Here’s a video that shows how slow 3 walkspeed becomes at a high value like 1080 FPS:
As you can see that is clearly not 3 walkspeed.
Here’s the whole movement function I use:
function Normal:StartMoving()
local enemy = self
local enemyModel: Model = self._model
local humanoid: Humanoid = self._model:FindFirstChild("Humanoid")
local root: BasePart = self._model:FindFirstChild("HumanoidRootPart")
if not enemy or not enemyModel or not humanoid or not root then return end
AnimateEvent:FireAllClients(humanoid, enemyModel.Animations.Move)
--ClientLerpEnemyEvent:FireAllClients(enemyModel)
for waypoint = 2, #workspace.Waypoints:GetChildren() do
if not enemyModel then
return
end
local previousPoint = workspace.Waypoints[waypoint - 1]
local nextPoint = workspace.Waypoints[waypoint]
enemy._movingTo.Value = workspace.Waypoints[waypoint]
local CFrame1 = root.CFrame
local CFrame2 = CFrame.new(CFrame1.Position, nextPoint.CFrame.Position)
for i=0,1,1 do
root.CFrame = CFrame1:Lerp(CFrame2,i)
end
local PosDifference = nextPoint.Position - root.Position
local Distance = PosDifference.magnitude
local HumanoidCFrame = root.CFrame
local newCFrame = CFrame.new(root.Position, nextPoint.Position) + PosDifference
local speed = humanoid.WalkSpeed
local timeToReach = Distance / speed
local steps = math.ceil(timeToReach / (1 / FPS))
for i = 0, steps do
if enemyModel:FindFirstChild("HumanoidRootPart") then
root.CFrame = HumanoidCFrame:Lerp(newCFrame, i / steps)
else
break
end
task.wait(1 / FPS)
end
end
if enemyModel then
enemyModel:Destroy()
setmetatable(self, nil)
end
end
I want the walkspeed to be the same at low FPS and high FPS.
sorry but can you quickly give me the entire part of the script that runs this function? if its a runservice loop, then the entire function for that part please
local RS = game:GetService("ReplicatedStorage")
local Events = RS.Events
local AnimateEvent = Events:WaitForChild("Animate")
local ClientLerpEnemyEvent = Events:WaitForChild("ClientLerpEnemy")
local RigModel = script:WaitForChild("Normal")
local EnemyModule = require(script.Parent)
local ServerInfo = require(script.Parent.Parent.ServerInfo)
local FPS = ServerInfo.FPS
local Normal = {}
Normal.__index = Normal
function Normal.new()
local self = setmetatable(
{
_model = RigModel:Clone(),
}, Normal)
return self
end
function Normal:Spawn()
local model: Model = self._model
local hum: Humanoid = model:FindFirstChildOfClass("Humanoid")
if not model then
return
end
local Config = EnemyModule.AddConfig(model, false)
self._movingTo = Config.movingTo
hum.Health = 4
hum.MaxHealth = 4
hum.WalkSpeed = 3
model.Parent = workspace.Enemies
model:MoveTo(workspace.Waypoints["1"].Position)
task.spawn(function()
self:StartMoving()
end)
hum.Died:Connect(function()
model:Destroy()
setmetatable(self, nil)
end)
end
function Normal:StartMoving()
local enemy = self
local enemyModel: Model = self._model
local humanoid: Humanoid = self._model:FindFirstChild("Humanoid")
local root: BasePart = self._model:FindFirstChild("HumanoidRootPart")
if not enemy or not enemyModel or not humanoid or not root then return end
AnimateEvent:FireAllClients(humanoid, enemyModel.Animations.Move)
--ClientLerpEnemyEvent:FireAllClients(enemyModel)
for waypoint = 2, #workspace.Waypoints:GetChildren() do
if not enemyModel then
return
end
local previousPoint = workspace.Waypoints[waypoint - 1]
local nextPoint = workspace.Waypoints[waypoint]
enemy._movingTo.Value = workspace.Waypoints[waypoint]
local CFrame1 = root.CFrame
local CFrame2 = CFrame.new(CFrame1.Position, nextPoint.CFrame.Position)
for i=0,1,1 do
root.CFrame = CFrame1:Lerp(CFrame2,i)
end
local PosDifference = nextPoint.Position - root.Position
local Distance = PosDifference.magnitude
local HumanoidCFrame = root.CFrame
local newCFrame = CFrame.new(root.Position, nextPoint.Position) + PosDifference
local speed = humanoid.WalkSpeed
local timeToReach = Distance / speed
local steps = math.ceil(timeToReach / (1 / FPS))
for i = 0, steps do
if enemyModel:FindFirstChild("HumanoidRootPart") then
root.CFrame = HumanoidCFrame:Lerp(newCFrame, i / steps)
else
break
end
task.wait(1 / FPS)
end
end
if enemyModel then
enemyModel:Destroy()
setmetatable(self, nil)
end
end
return Normal
Sorry if it’s messy or bad, it’s my first time making a tower defense game by myself and didn’t really have an idea on how to make it.
For clarification, yes I’ve used a bit of ChatGPT for this part of the code:
local timeToReach = Distance / speed
local steps = math.ceil(timeToReach / (1 / FPS))
for i = 0, steps do
if enemyModel:FindFirstChild("HumanoidRootPart") then
root.CFrame = HumanoidCFrame:Lerp(newCFrame, i / steps)
else
break
end
task.wait(1 / FPS)
end
end
It’s a module that basically stores and returns values like FPS, only FPS for now.
Oh and its not being run on the client it’s on the server, I’m planning on making it run on the client later on and making it update only 5 times a second on the server.
the way you want it to work, is that the enemies are first made on the server, but they would be like, an invisible part, and the server would tween them. this way the player doesnt see it. then, to make it smooth on the client, you would detect a remote event everytime a enemy is created. then you would spawn the model on the client, and you can either tween in, your lerp it. if you want to lerp it you can see the post i linked at the bottom so you can see how to make it frame independent, so it would be the same speed on every framerate. the server would run the attacking of the enemies, and when the server wants to shoot a bullet or smthn, it would use the invisible part.
yeah no problem, right now if you dont feel like doing that. just lerp the zombie on the server. the performance may not be that good but it would look better than what you have right now
I’ve realized that.
Like, from the start I knew that fraction of the code was weird.
I’m quite young and not that good at math so thank you for linking this post, I’ll try learning from it.
Hey, so I did everything in that post and this is my code:
local startTime = tick()
while true do
local dt = task.wait()
local dist = (nextPoint.Position - root.Position).Magnitude
local speed = humanoid.WalkSpeed*dt
local timeToReach = speed / dist
if tick() - startTime >= timeToReach then break end
local adjustedLerpAlpha = math.min(timeToReach,1)
print(adjustedLerpAlpha, timeToReach, speed, dist, dt)
root.CFrame = HumanoidCFrame:Lerp(nextPoint.CFrame, adjustedLerpAlpha)
end
The problem is, this is what I’m getting in the console from printing all the values: