When you are making an RTS game for Roblox you will encounter several problems in the process. I am writing this post, not only as a “dev-blog”, but as a resource for everyone interested in making an RTS. Im a developer of a game in development called “Conquest Napoleonic Wars”, a spiritual sequel of the original game called “Conquest”, alongside with a team.
First of all, the problem I faced at the start: network usage. I will talk about it in this topic, but here is another very good post from a dev of Astro Force, that is the post I got the information from to make the system for the game.
Optimizing network usage
It is pretty obvious that when you are handling a lot of parts both server-side and client-side, the network usage skyrockets. The way you can check the network usage in your game is by going to dev console → ServerStats. There are some things, but the most important one is the “Total Data KB/s”, that, as the name suggests, is the amount of data being sent / managed.
In the cate of a RTS game, of course, you will not have a problem when handling 5 or 10 units. But what about 100? 150? Thats when network optimization comes.
The most important think to take in mind is that every unit must be ““fake””. The server should only contain the data of the unit, like its positions and health. This is because that if you not only store and handle the data, but you also create the units models and such server-side, the network usage will get a lot higher than it should be. This is the reason why you shouldnt make any part to represent the RTS units in the server. Instead, only the clients should do it. Here is an image to represent it. Not the best, but it works.
Everytime a unit moves, attacks, or dies, the client creates the visual effects or whatever needs to be created to show it. This way not only the network usage is a lot lower, but the server CPU and memory usage is a lot lower too!
Take in mind that when sending the data to the client, it should be not in a dictionary, but as an array, this is because arrays have a lower size than dictionaries, so the network usage is lower.
Bad
{
UnitID = “123456”,
Position = Vector3.new(0, 0, 0)
}
Good
{
“123456”,
Vector3.new(0, 0, 0)
}
Of course, this makes readability a bit worse because this
local ID = UnitData.UnitID
Is easier to read than
local ID = UnitData[1]
But its the price to pay for good network performance. A very good thing that Roblox has is the type Vector2int16. Basically a 16 integer number that allows u to send numbers with a much lower size, saving bandwith. The disadvantage is that it only supports from 32767 to -32767 integers, so be carefull when using that. Here is a post with an example and more info about it:
Thats basically it about network usage optimization. Send as few data as possible and in the most optimized way possible. It is also a good thing to limit the rate the server sends the data. In Conquest Napoleonic Wars the server does it around every 10 frames.
Server CPU usage
We talked about network usage, but regarding to server CPU usage, there are a few things to take in mind too. First of all, always try to use parallel luau for every unit calculation that it can be used for. it is faster than calculating everything on one thread.Finally, the most important part about server CPU optimization for RTS games is making every unit search for a target to attack performant. Looping through every unit to check which to attack is very expensive. We can use a swarm module to make it a lot more performant, lowering server CPU usage. A swarm module works by dividing units positions in a grid and then just making every unit checking for a target loop through each square.
I will not talk much about it in this post, but here you have a link to a post from a Roblox staff member where I took the previous image from: Optimizing Unit Targeting in Roblox with a Swarm Module - Resources / Roblox Staff - Developer Forum | Roblox
Client replication
The idea is the same as network optimization. Do as few as possible, and do it in the most performant way. You wanna make particles? optimize them. Units models? optimize them. But a problem that seems not so easy to fix is making a lot of units move in the client without lag. To do this. dont move units models byModel:PivotTo()
It is easy, but it is not performant. Prefer to attach every unit part to the primary part of the model with weld constraints, unanchoring them all except the primary part, and then changing the pivot of the primary part instead of the model’s one.
Model.PrimaryPart:PivotTo()
I dont know exactly why, but it is a lot more performant than doing it the other way. Finally, merge as many parts of the units models as possible. This also improves prformance. Also, pretty obvious, but always set your units meshes with every property they dont need disabled and with RenderFidelity set to performance.
When replicating moving units positions, use lerping to smooth it. But check first if the unit model is too far away from the player. If it is, then just change the position, dont smooth it.
Extra
Pathfinding - Fast Flow
As everyone knows, pathfinding can get very expensive, specially for a RTS game, where you need to calculate pathfinding for a lot of units. You can improve the performance by using a pathfinding module like this one
FastFlowTake in mind that even with an optimized pathfinding system it is still expensive. Consider only checking units path every, for example, 5 frames instead of 60. This way the server CPU wont get that much pressure.
Conclusion
These are some things to take in mind when optimizing your RTS game, sure, there are more details, but this is a resumed post about all the three points. Let me know your opinion!