Welcome to the forums @teleportingtortoise!
Optimizing can be hard, especially when you have many nodes all interacting at the same time. My guess is that some of the performance drops are simply because of having so many physics bodies all moving at the same time, as the physics engine needs to calculate each body, it's velocity, collisions, etc.
Without seeing the code it is hard to recommend anything specific, but below I have listed some things you may want to try to improve performance:
1 - Avoid doing complex calculations as much as possible! If there is a way to move a complex calculation only once or only when needed, that is almost always going to be the most optimal.
For example, if colliding with certain objects changes an ant's mood, you will want to put the code for changing the mood (and perhaps even determining the results of the mood change) in the collision callback code. Like if ants go back to their ant hill when sad, then you might be able to save performance by calculating the path to the ant hill once in the collision callback function (assuming nothing can dynamically block the ant from returning)
2 - Move variables outside of loops if they are created in every loop. For example:
# works, but not ideal
for i in range(0, 10)
var string = str(i) + " - hello"
print (string)
# better
var string = ""
for i in range(0, 10):
string = str(i) + " - hello"
print (string)
# best (probably, have not benchmarked)
for i in range(0, 10)
print (str(i) + " - hello")
3 - Update at a slower rate than every _process
(every rendered frame) or every _physics_process
(every physics frame, default 30 times a second). There are several ways to do this, but one way is like this:
var update_timer = 0
# every quarter second update
const TIME_NEEDED_TO_UPDATE = 0.25
func _process(delta):
update_timer += delta
if (update_timer < TIME_NEEDED_TO_UPDATE):
return
else:
update_timer -= TIME_NEEDED_TO_UPDATE
# other code here
Then you are only updating less often, which can improve performance. You can even apply an offset to each one randomly or deterministically, depending on your need, to help spread it out so the updates happen gradually:
func _ready():
update_timer = rand_range(0, 0.25)
That is just a few things I might try right off. What you might want to do is benchmark the game using the Godot profiler and see what function(s) and processes are taking up the most processing time, and then look at optimizing them. It can be time consuming, but it may help shed light on what is slowing down performance.
Before implementing any of the optimizations though, I would highly recommend making a backup of the project if you have not already, so you can revert the changes if something breaks or performance doesn't increase. :smile: