Tower Defense Enemy Movement

I plan on making a tower defense game and am wondering what would be the best way to move enemies?

I would use MoveTo but when setting the enemy’s speed higher, they go flying off the path.

I want to use TweenService but I am worried about lag seeing as every enemy would be moved on the server.

Any suggestions?

3 Likes

Try using PathFindingService

I linked the documentation here

additional info: PathfindingService, PathfindingModifier, PathfindingModifier | Roblox Creator Documentation

You can make pretty nice enemies using PathfindingService and Pathfinding modifiers
If you need it, here’s a sweet tutorial on PathfindingService

1 Like

Thats where client side rendering comes in.

For my system, enemies are just tables that hold info, no models or animations at all. Example table would be like

{
["HP"] = 100;
["CFrame"] = CFrame.new()
}

Then I use a Heartbeat to move them, using CFrame:ToWorldSpace() to move them in the direction they’re facing no matter the rotation, and having them face the next node. You should have nodes on the map which enemies use for movement.

Then about every 10-20 heartbeats, send a Remote to the client which contains the info for the enemies. You can then create the enemies model and tween/animate them nicely on the client, giving you a performant system that can still handle high numbers. My current enemy system can handle about 500 enemies before seeing any impact to performance.

6 Likes

Wouldn’t passing info by using a RemoteEvent be a lot more exploitable? (They can easily change values)

I would recommend using a module to handle enemies and using metatables.
you could have a function like module:SendData() to send the data from the module to the client, lemme write a quick example

local module = {}
local meta =  {__index = module}

function module.newEnemy(data)
    --[[the table would look like this
       {
        ['HP'] = 100
        ['CFrame'] = CFrame.new()
        ['Name'] = "Quick Zombie"
       }
    ]]
    local self = {}
    self.hp = data['HP']
    self.cframe = data['CFrame']
    self.name = data['Name']

    self.npc = game.ReplicatedStorage.enemies:WaitForChild(self.name)
    return setmetatable(self, meta) -- the reason we return the setmetatable is because now in the localscript you can access self through a variable!
end
-- other module functions here lolol

function module:returnData()
    return self -- returning this {['hp'] = 100, ['cframe'] = CFrame.new(), ['name'] = 'Quick Zombie', ['npc'] = workspace['Quick Zombie']}
end

return module

I hope this help with making your code a bit more secure!
(This is not required, if you have RemoteEvent checks, then you’re good to go :slight_smile: , just suggesting another method I sometimes use.)

1 Like

We would be sending the remotes TO the client from the server, not TO the server from the client. No remotes are used for interacting with enemies from the client to the server, so its not exploitable. Exploiters can only affect their client and remotes which send to the server.

Oh, sorry, i completely misunderstood you lol

1 Like

Every 10 heartbeats you fire an event that tweens the models to their destination?
Wouldnt you just be spam tweening them and creating lag?

https://gyazo.com/a698c60a41edf567aac7882e64b620a2?token=a51e44069e8ea090edfab2dc2f997929
https://gyazo.com/0de43a41a900bd00c6deeea362d5afba
The gif shows 72 NPC’s being tweened to the Position on the server which is represented by the Neon Brick (Neon brick is just there to display synchronization)

1 Like

If you do it like you are, it will cause lag. What you are supposed to do is for example tween them for 0.2 seconds and then once that is done tween it again, you wanna get the next position that it has to go to with the 0.2 seconds tween by lerping the distance. This is how i would do it, don’t know how Kdude did it but if you see this Kdude i would like better explanation as i always like to see different solutions.

1 Like