Tower defence enemies lagging behind

If you want the curve to be more exaggerated, you can move the nodes.

Also, could you show some code?

@Katrist
OH, i was using bezier path wrong. Wait lemme inplement it rq

@Katrist I tried implementing this, but it was super choppy, and it wouldnā€™t wait enough to delete its self. And on the 1st path, the enemies donā€™t damage the base at all.
Hereā€™s the code:

--!native
--!strict
local module = {}
local ServerStorage = game:GetService("ServerStorage")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local PhysicsService = game:GetService("PhysicsService")
local moveremote = ReplicatedStorage:WaitForChild("tweenenemy")
local Players = game:GetService("Players")

module.spawn = function(name:string, waypointfolder:Folder, exit, spawns:CFrame, boss:BoolValue)
	local offset = math.random(-1,1)
	local tweenenemy = ReplicatedStorage.tweenenemy
	local model: Model = ServerStorage.Enemies[name]:Clone()
	model:PivotTo(spawns + Vector3.new(offset,0,0))

	if boss then
		ReplicatedStorage.AddHealthBar:FireAllClients(name,model.Health.Value,model.Health.Value)
	end
	--for _,parts:BasePart in pairs(model) do
	--	if parts:IsA("BasePart") then
	--		parts.CollisionGroup = "Enemies"
	--	end
	--end
	model.Parent = Workspace:FindFirstChild(ReplicatedStorage.Map.Value).enemies
	--local health = model.health
	--health:GetPropertyChangedSignal("Value"):Connect(function()
	--	if health.Value == 0 then
	--		model:Destroy()
	--	end
	--end)

	model.PrimaryPart:SetNetworkOwner(nil)
	
	local speed:IntValue = model:WaitForChild("speed")
	--model.speed:GetPropertyChangedSignl("Value"):Connect(function()
	--	enemySpeed = model.speed.Value
	--end)
	local _, size = model:GetBoundingBox()
	local nodepositions = {}
	local enemyspeed = speed.Value
	local nodeindex = 0
	print("spawningenemy")
	for _ = 1, #waypointfolder:GetChildren() - 2 do
		nodeindex += 1
		local node:Part = waypointfolder:FindFirstChild(tostring(nodeindex))
		table.insert(nodepositions,node.CFrame.Position)
	end
	table.insert(nodepositions,waypointfolder.exit.CFrame.Position)
	print("got position table")
	print(unpack(nodepositions))
	local totalwait = 0
	nodeindex = 0
	for _ = 1, #waypointfolder:GetChildren() - 2 do
		local success, err = pcall(function()
			nodeindex += 1
			local node:Part = waypointfolder:FindFirstChild(tostring(nodeindex))
			local distance = (node.CFrame.Position + Vector3.new(offset,size.Y / 2,0) - model.PrimaryPart.CFrame.Position).Magnitude
			totalwait += distance
		end)
		if err then
			warn(err)
		end
	end
	print("generated wait")
	tweenenemy:FireAllClients(model,nodepositions,Vector3.new(offset,size.Y / 2,0))
	task.wait(totalwait / enemyspeed)
	ReplicatedStorage.BaseHealth.Value -= model.Health.Value
	model:Destroy()
end

return module

heres the client code:

ReplicatedStorage.tweenenemy.OnClientEvent:Connect(function(model:Model,Position:table,offset:Vector3)
	print("tweening enemy")
	local modelpath = BezierPath.new(Position,3)
	for i = 0,1,1/100 do
		model.PrimaryPart.CFrame = modelpath:CalculateUniformCFrame(i) + offset
		task.wait(0.1)
	end
end)

hereā€™s a vid:

@Katrist
thank you and have a happy new year!

Edit: wrong code, replaced code

I would do this all on the server, since BezierPath is fairly performant.

Code:

--!native
--!strict
local module = {}
local ServerStorage = game:GetService("ServerStorage")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local PhysicsService = game:GetService("PhysicsService")
local moveremote = ReplicatedStorage:WaitForChild("tweenenemy")
local Players = game:GetService("Players")

module.spawn = function(name:string, waypointfolder:Folder, exit, spawns:CFrame, boss:BoolValue)
	local offset = math.random(-1,1)
	local tweenenemy = ReplicatedStorage.tweenenemy
	local model: Model = ServerStorage.Enemies[name]:Clone()
	model:PivotTo(spawns + Vector3.new(offset,0,0))
	print("spawningenemy")

	if boss then
		ReplicatedStorage.AddHealthBar:FireAllClients(name,model.Health.Value,model.Health.Value)
	end
	--for _,parts:BasePart in pairs(model) do
	--	if parts:IsA("BasePart") then
	--		parts.CollisionGroup = "Enemies"
	--	end
	--end
	model.Parent = Workspace:FindFirstChild(ReplicatedStorage.Map.Value).enemies
	--local health = model.health
	--health:GetPropertyChangedSignal("Value"):Connect(function()
	--	if health.Value == 0 then
	--		model:Destroy()
	--	end
	--end)

	model.PrimaryPart:SetNetworkOwner(nil)

	local speed:IntValue = model:WaitForChild("speed")
	--model.speed:GetPropertyChangedSignl("Value"):Connect(function()
	--	enemySpeed = model.speed.Value
	--end)
	local _, size = model:GetBoundingBox()
	
	local nodePositions = {}
	
	for i = 1, #waypointfolder:GetChildren() - 2 do
		table.insert(nodePositions, waypointfolder[i].Position + Vector3.new(offset, size.Y / 2, 0))
	end
	
	table.insert(nodePositions, waypointfolder.exit.Position)
	
	local newPath = BezierPath.new(nodePositions)
	local t = 0
	
	while t < 1 do
		model:PivotTo(newPath:CalculateUniformCFrame(t))
		t += speed.Value / 100

		task.wait()
	end
	
	ReplicatedStorage.BaseHealth.Value -= model.Health.Value
	model:Destroy()
end

return module

Make sure to add a variable for BezierPath, I didnā€™t add one.

If itā€™s too fast, make sure to change this value:

t += speed.Value / 100

Make the 100 a higher number for the speed to be lower, or make the 100 a lower number for the speed to be higher.

Have you anchored the PrimaryPart? You also wonā€™t need :SetNetworkOwner(nil).

Happy new year to you too!

1 Like

I tried anchoring the primary part before, but that didnā€™t really work. I donā€™t know if calling set network ownership hanged the script, but il try it today. Thank you!

The script dosent work. It just teleports?

--!native
--!strict
local module = {}
local ServerStorage = game:GetService("ServerStorage")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local PhysicsService = game:GetService("PhysicsService")
local moveremote = ReplicatedStorage:WaitForChild("tweenenemy")
local Players = game:GetService("Players")
local BezierPath = require(ReplicatedStorage.Packages.BezierPath)

module.spawn = function(name:string, waypointfolder:Folder, exit, spawns:CFrame, boss:BoolValue)
	local offset = math.random(-1,1)
--	local tweenenemy = ReplicatedStorage.tweenenemy
	local model: Model = ServerStorage.Enemies[name]:Clone()
	model:PivotTo(spawns + Vector3.new(offset,0,0))
	print("spawningenemy")

	if boss then
		ReplicatedStorage.AddHealthBar:FireAllClients(name,model.Health.Value,model.Health.Value)
	end
	--for _,parts:BasePart in pairs(model) do
	--	if parts:IsA("BasePart") then
	--		parts.CollisionGroup = "Enemies"
	--	end
	--end
	model.Parent = Workspace:FindFirstChild(ReplicatedStorage.Map.Value).enemies
	--local health = model.health
	--health:GetPropertyChangedSignal("Value"):Connect(function()
	--	if health.Value == 0 then
	--		model:Destroy()
	--	end
	--end)

	model.PrimaryPart:SetNetworkOwner(nil)

	local speed:IntValue = model:WaitForChild("speed")
	--model.speed:GetPropertyChangedSignl("Value"):Connect(function()
	--	enemySpeed = model.speed.Value
	--end)
	local _, size = model:GetBoundingBox()
	
	local nodePositions = {}
	
	for i = 1, #waypointfolder:GetChildren() - 2 do
		table.insert(nodePositions, waypointfolder[i].Position + Vector3.new(offset, size.Y / 2, 0))
	end
	
	table.insert(nodePositions, waypointfolder.exit.Position)
	
	local newPath = BezierPath.new(nodePositions,3)
	local t = 0
	
	while t < 1 do
		model:PivotTo(newPath:CalculateUniformCFrame(t))
		t += speed.Value / 5

		task.wait(0.1)
	end
	
	ReplicatedStorage.BaseHealth.Value -= model.Health.Value
	model:Destroy()
end

return module

Keep it 100 and see what happens, Iā€™m assuming you set the speed to be far too fast. You should always test the code before editing values.

Also, make sure to anchor your PrimaryPart.

I set it to 5 and it just teleported to the end after a few seconds. Was I supposed to anchor the primary part?

Please read my post. I have said the same thing for the past two replies.

Oh okay sorry. But shouldnā€™t it still not be teleporting to the end?

I set it to 5ā€¦ shouldnā€™t it be extremely slow?

Oh wait srry Iā€™m stupid srry I didnā€™t read

Youā€™re dividing a number.

100 / 5 = 20
100 / 100 = 1

Higher divisor = lower speed.

Please just use my code and test without modifications.

I will try this tomorrow sorry itā€™s like 5 am for me rn

Okay, I am using your original code. I just added a value for the curve size, and the path to Bezier. I also had to amp up 100 to a ridiculously high value for me to even see the enemies.

Hereā€™s the code:

--!native
--!strict
local module = {}
local ServerStorage = game:GetService("ServerStorage")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local PhysicsService = game:GetService("PhysicsService")
local moveremote = ReplicatedStorage:WaitForChild("tweenenemy")
local Players = game:GetService("Players")
local BezierPath = require(ReplicatedStorage.Packages.BezierPath)

module.spawn = function(name:string, waypointfolder:Folder, exit, spawns:CFrame, boss:BoolValue)
	local offset = math.random(-1,1)
	local tweenenemy = ReplicatedStorage.tweenenemy
	local model: Model = ServerStorage.Enemies[name]:Clone()
	model:PivotTo(spawns + Vector3.new(offset,0,0))
	print("spawningenemy")

	if boss then
		ReplicatedStorage.AddHealthBar:FireAllClients(name,model.Health.Value,model.Health.Value)
	end
	--for _,parts:BasePart in pairs(model) do
	--	if parts:IsA("BasePart") then
	--		parts.CollisionGroup = "Enemies"
	--	end
	--end
	model.Parent = Workspace:FindFirstChild(ReplicatedStorage.Map.Value).enemies
	--local health = model.health
	--health:GetPropertyChangedSignal("Value"):Connect(function()
	--	if health.Value == 0 then
	--		model:Destroy()
	--	end
	--end)

	--model.PrimaryPart:SetNetworkOwner(nil)

	local speed:IntValue = model:WaitForChild("speed")
	--model.speed:GetPropertyChangedSignl("Value"):Connect(function()
	--	enemySpeed = model.speed.Value
	--end)
	local _, size = model:GetBoundingBox()
	
	local nodePositions = {}
	
	for i = 1, #waypointfolder:GetChildren() - 2 do
		table.insert(nodePositions, waypointfolder[i].Position + Vector3.new(offset, size.Y / 2, 0))
	end
	
	table.insert(nodePositions, waypointfolder.exit.Position)
	
	local newPath = BezierPath.new(nodePositions,2.5)
	local t = 0
	
	while t < 1 do
		model:PivotTo(newPath:CalculateUniformCFrame(t))
		t += speed.Value / 10000

		task.wait()
	end
	
	ReplicatedStorage.BaseHealth.Value -= model.Health.Value
	model:Destroy()
end

return module

And the video:

You can see the enemys spawning right at the first waypoint. And the enemies are also extremely choppy.

You need to add the spawn position into the nodePositions table.

Okay i added the spawn position.

But now the enemys get pulled apart, and the enemys arms and feet move in different positons.

Heres the code:

--!native
--!strict
local module = {}
local ServerStorage = game:GetService("ServerStorage")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Workspace = game:GetService("Workspace")
local PhysicsService = game:GetService("PhysicsService")
local moveremote = ReplicatedStorage:WaitForChild("tweenenemy")
local Players = game:GetService("Players")
local BezierPath = require(ReplicatedStorage.Packages.BezierPath)

module.spawn = function(name:string, waypointfolder:Folder, exit, spawns:CFrame, boss:BoolValue)
	local offset = math.random(-1,1)
	local tweenenemy = ReplicatedStorage.tweenenemy
	local model: Model = ServerStorage.Enemies[name]:Clone()
	model:PivotTo(spawns + Vector3.new(offset,0,0))
	print("spawningenemy")

	if boss then
		ReplicatedStorage.AddHealthBar:FireAllClients(name,model.Health.Value,model.Health.Value)
	end
	--for _,parts:BasePart in pairs(model) do
	--	if parts:IsA("BasePart") then
	--		parts.CollisionGroup = "Enemies"
	--	end
	--end
	model.Parent = Workspace:FindFirstChild(ReplicatedStorage.Map.Value).enemies
	--local health = model.health
	--health:GetPropertyChangedSignal("Value"):Connect(function()
	--	if health.Value == 0 then
	--		model:Destroy()
	--	end
	--end)

	--model.PrimaryPart:SetNetworkOwner(nil)

	local speed:IntValue = model:WaitForChild("speed")
	--model.speed:GetPropertyChangedSignl("Value"):Connect(function()
	--	enemySpeed = model.speed.Value
	--end)
	local _, size = model:GetBoundingBox()
	
	local nodePositions = {}
	table.insert(nodePositions,waypointfolder.enemyspawn.Position)
	for i = 1, #waypointfolder:GetChildren() - 2 do
		table.insert(nodePositions, waypointfolder[i].Position + Vector3.new(offset, size.Y / 2, 0))
	end

	table.insert(nodePositions, waypointfolder.exit.Position)
	
	local newPath = BezierPath.new(nodePositions,2.5)
	local t = 0
	
	while t < 1 do
		model:PivotTo(newPath:CalculateUniformCFrame(t))
		t += speed.Value / 10500

		task.wait()
	end
	
	ReplicatedStorage.BaseHealth.Value -= model.Health.Value
	model:Destroy()
end

return module

Heres a vid:

Also its extremally laggy. Should i start sending the lerps back to client?

The reason Iā€™m not telling you to do movement via the client is because itā€™s going to be hard to implement other systems like towers later. You can try though.

Also, are you sure you anchored ONLY the primary part?