Custom movement script for a tower defense game doesn't move at the same speed on different distances

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
1 Like

why not try pathfinding instead and using checkpoints instead of this

2 Likes

Because the enemies are anchored, they can literally phase through walls and walk on air, so they don’t need pathfinding.

2 Likes

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
1 Like

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?

1 Like

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.

1 Like

This code should already handle the speed (or the time for the tween) correctly! I don’t see the issue!

Are you sure the Attribute is always the same? if not try removing it and replace it with something like 30

1 Like

The attribute changes sometimes, but I already handle that. But even if it doesn’t change and remains the same the issue still remains.

1 Like

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…

Yep, turns out it was that. I’ll try to simplify my code. Thanks!

2 Likes

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.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.