Hello, I am making a tower defense game, and then I figured that using the default Roblox humanoids ruins the performance by a lot, so I’ve decided to make a custom humanoid to optimize my game. I’ve ran into a serious issue, and that is that my movement code for the enemies doesn’t seem to work as expected on different distances. They move at different speeds depending on the traveling distance. For example: If the goal is 500 studs away, they’ll move faster, if it’s 5 studs away, they’ll move slower.
So far I’ve been doing research and trying to fix it, yet nothing seemed to help, so here’s my code:
function humanoid.MoveTo(mob, cframe)
-- The 'cframe' property is the goal
if mob:FindFirstChild("HumanoidRootPart") then
if mob:GetAttribute("Health") > 0 then
local canceled = false
local startPos = mob.HumanoidRootPart.Position
local info = TweenInfo.new(
(startPos - cframe.Position).Magnitude / mob:GetAttribute("WalkSpeed"),
Enum.EasingStyle.Linear
)
local tween = TweenService:Create(mob.HumanoidRootPart, info, {
CFrame = cframe * CFrame.new(0, mob.HumanoidRootPart.Size.Y / 2 + mob:GetAttribute("HipHeight"), 0)
})
tween:Play()
local onSpeedChanged = mob:GetAttributeChangedSignal("WalkSpeed"):Connect(function()
canceled = true
tween:Cancel()
humanoid.MoveTo(mob, cframe)
end)
tween.Completed:Wait()
if not canceled then
onSpeedChanged:Disconnect()
return true
end
else
task.wait()
return false
end
else
task.wait()
return false
end
end
function mob.Move(mob, path)
local waypoints = workspace.Waypoints[path]
for waypoint=mob.MovingTo.Value+1, #waypoints:GetChildren() do
if mob:FindFirstChild("HumanoidRootPart") then
if mob.Name == "Arrow" then
local wps = #waypoints:GetChildren()
local colorA = Color3.fromRGB(0, 255, 75)
local colorB = Color3.fromRGB(255, 50, 20)
local alpha = waypoint/wps
mob.HumanoidRootPart.Arrow.Color = colorA:Lerp(colorB, alpha)
end
mob.MovingTo.Value = waypoint
repeat
local reached = humanoid.MoveTo(mob, waypoints[waypoint].CFrame)
until reached
end
end
local health = mob:GetAttribute("Health")
local speed = mob:GetAttribute("WalkSpeed")
if speed <= 0 then return end
if mob.Name ~= "Arrow" then
mob:Destroy()
baseHurtEvent:FireAllClients()
workspace.Base.Humanoid:TakeDamage(health)
end
return
end
I am also already using waypoints for this. Probably should include this piece of code in the post as well.
function mob.Move(mob, path)
local waypoints = workspace.Waypoints[path]
for waypoint=mob.MovingTo.Value+1, #waypoints:GetChildren() do
if mob:FindFirstChild("HumanoidRootPart") then
if mob.Name == "Arrow" then
local wps = #waypoints:GetChildren()
local colorA = Color3.fromRGB(0, 255, 75)
local colorB = Color3.fromRGB(255, 50, 20)
local alpha = waypoint/wps
mob.HumanoidRootPart.Arrow.Color = colorA:Lerp(colorB, alpha)
end
mob.MovingTo.Value = waypoint
repeat
local reached = humanoid.MoveTo(mob, waypoints[waypoint].CFrame)
until reached
end
end
local health = mob:GetAttribute("Health")
local speed = mob:GetAttribute("WalkSpeed")
if speed <= 0 then return end
if mob.Name ~= "Arrow" then
mob:Destroy()
baseHurtEvent:FireAllClients()
workspace.Base.Humanoid:TakeDamage(health)
end
return
end
what is the mob argument? can you give more details on it. so its an anchored humanoid with health and a walkspeed? and the mob is also walking properly?
The mob argument is the mob itself. The mob IS walking properly, but doesn’t always move at the same speed. I am bad at explaining things so I don’t know what else to say.
I’m not super sure, but it might be the :MoveTo because it might need to first calculate some path?
Which could be different in different instances.
Cant really think of anything else…
Tweening is bad for movement here. You would want to create a stepping function that manually cframes the HRP everyframe, which will also allow you to maintain speed efficiently.
local function stepMovement(currentPos: Vector3, goal: Vector3, dt: Number)
local look = (goal - currentPos).Unit
local right = look:Cross(Vector3.yAxis).Unit -- might have to reverse this
local newPosition = currentPos + (look * speed / dt)
local finalCF = CFrame.fromMatrix(newPosition, right, Vector3.yAxis, look)
return finalCF
end
This is basic and youd want to heavily edit this to also work with deltatime but this should give you a rough direction.