I’m currently attempting to optimize a scenario when I have many agents on screen at once:
I have two sides, a Friendly side and an Enemy side.
Both sides have troops that have the capacity of melee + ranged attack (firing guns).
The issue I’ve repeatedly run into is that performance tanks when there are more than 150 troops on screen.
So far I have created a singleton “troop mover” that only moves bullets and troops every other frame. This has helped, but has caused the troops to appear at a lower framerate.
If I am running the game at 60fps and only moving troops every other frame, it looks like the troops are moving at 30fps. Which is odd when most other things in the game are moving at 60fps.
Are there techniques to hide this? A way to lerp agents so that even if they’re being updated less frequently, it doesn’t look jarring?
It sounds like you’re making an RTS of some sort. There are lots of things that can be done to improve performance in general (@coderjo 's links are definitely worth pursuing…), but there are also lots of things you can do specifically in your case.
The first thing I’d suggest is, rather than having your “troop mover” do things every other frame, split your troops up into groups and update one group per frame. That way there’s something moving every frame, but you’re amortizing the cost across multiple frames.
I’d also suggest splitting up your update logic into physics and AI:
physics is the stuff that has to happen ever frame; things moving, collisions…
ai is decisions about what do do next, and can happen much more sporadically
Ideally you want each unit (troop/whatever) to have a simple goal or goals it can act on each frame; follow a path, track a target, shoot at something, explode… Then at a higher level (and much less often) something can think a little harder about setting that goal. The orders don’t have to come in very fast as long as everything has orders.
The idea is to try to amortize the cost of decision making across multiple frames without sacrificing movement and action.
Do you think that the same sort of strategies (dividing into groups, etc) are the go-tos for bullets as well? ie moving them, raycasting collision, etc.
Potentially, though there are other things I’d consider as well. For example, if you’re doing a classical style RTS where the screen is a relatively constrained view of a big map, you probably want to bias updates towards things that are onscreen. If something out of view shoots something else that’s out of view, rather than spawn a shot and do all the per-frame updates on something that will never be drawn, you can just note that the target will take damage in 0.3 seconds.
A lot of the time, making a game is about finding corners to cut where the player won’t notice the difference. Try to avoid doing any calculations you don’t need to make. Any calculations you do need to make, try to amortize over time.
You might also consider cheaper weapon physics. Do you need raycasts and collision, or can you just decide where the target point is and lerp() the bullet from start to target? A lot of earlier RTS games didn’t even have projectiles; the attacker would have a shoot animation and the defender would have a being hit animation, and the shots were implied rather than drawn.
This is helpful, thank you! The one question still remaining is this from the first post:
If I am running the game at 60fps and only moving troops every other frame, it looks like the troops are moving at 30fps. Which is odd when most other things in the game are moving at 60fps.
Cutting the troops into groups and processing them that way works well, but causes them to look lower FPS as they are being processed less frequently.
If I am running the game at 60fps and I divide the troops into 4 groups, each will look like it is running at 15fps (being moved once every 4 frames).
Are there techniques to deal with this? I have Physics Interpolation turned on, but that doesn’t seem to help.
Turning physics/common/physics_interpolation on means the physics movements will be interpolated. But if the physics/common/physics_ticks_per_second (FPS for physics, default 60) is the same as the FPS (also default 60), what needs to be interpolated? So you need to decrease physics/common/physics_ticks_per_second to allow the interpolation to work.
I’d like to say a few words about the movement algorithm. A* (that is, A Star) is a famous algorithm for path-finding, and another algorithm called Flow Grid. Both algorithms are interesting and fun to learn, each with its advantages.
With the path-finding algorithms done, let’s focus on the collision avoidance algorithm, the RVO2 (aka ORCA). While the path-finding algorithms handle finding a valid path, RVO2 handles the dynamic movement on the scene, avoiding all the units rushing into a single point or converging into a line when marching.
These are just brief introductions to algorithms you might need for an RTS game, I did this because I was interested in this stuff for a long time. You might not even need them for a long period, but if someday you’re going to learn them, there are many great tutorials on YouTube, and libraries implement the algorithms on GitHub.