So I'm working on an first person shooter and too many enemies in the level causes the framerate to dip. It's only when the enemies "die"(self delete), that the framerate starts to go up and become more smooth. Is there a simple solution to this problem that doesn't involve cutting back on the numbers of enemies in the level? I only have 11 enemies in the level; that's a small amount. I heard of this think call "culling" but, there doesn't seem to be a beginner friendly was of getting it done. Also, I'm not too sure to what extend "culling" will help. I tried just running the game with the visibility of the enemies off and the framerate was still low. It's not completely unplayable but, not even decent either. :/
So I've got performance issues for a game I'm working on, got any help?
- Edited
I recommend going through the Optimization tutorials. It's quite a lot to read, but it's worth the effort :)
I tried just running the game with the visibility of the enemies off and the framerate was still low.
This hints at the botteleneck being your AI logic (in _process()
or _physics_process()
) or physics simulation. Make sure your collision shapes aren't too complex.
If it's on a desktop computer, 11 enemies should be no problem. It is most likely a problem with your script. Ray casting can be expensive, and it's possible you are not deleting them correctly.
- Edited
One thing you can do is don't do checks every frame. It depends on the situation how often they need to be done. Especially distance checks. You can generally do distance checks every .25 second and many times use the distance squared for comparison, for instance, closest.
@fire7side @cybereality @Calinou
Thanks guys. I still have some issues but, I do notice some performances increases when I stop manipulating the length and rotation of the raycast with code. So now I manipulate it with the animationplayer. Now perhaps using the anim_player could cause similar problems but, I haven't noticed it. What really helped performance is when the enemies aren't patrolling. I don't know how to feel about this. I do want my game to run smoothly but, I want to maintain the patrolling state as a made an animations for it. I'll keep you guys posted as I make improvements.
I'm not sure scaling raycast nodes is the best method. What I did in one of my games, was put several raycast nodes and different angles (one facing forward, and then two at 30 degrees to each side) and did not scale them. Leave them at the max distance that you want to track, and then if there is a collision, check the distance to see if it's within the limit you want (also, check distance squared, not distance, as distance requires a square root operation and can be slow).
Also, raycast checking does not need to be every frame. If it is for AI, then doing it every half second or even every second should be enough. For AI in general, you don't want to be doing checks and state changes every frame. It wastes performance and actually looks worse. For example, if an enemy is walking, it is more realistic if there is some delay between when an event happens (such as seeing the player or reacting to a grenade) as in real life if would take a moment for them to see and recognize what happened, and then determine how to respond.
You just want to make sure that there is an offset, so there aren't 20 enemies all calculating their state changes on the same frame. So if you picked 1 second as the tick rate, then on the ready function of the enemy, find a random number between 0.0 and 1.0 as an offset to the check. Then you can create a timer that updates the AI state. The timer itself would be on a 1.0 second repeat, but use a delay of 0.0 to 1.0 (from the random ready function) as a delay to start the timer. That way the logic is spaced out.
You can smooth things out with interpolation.
@fire7side @Calinou @cybereality
Okay, so I found out the problem. Most of what I learnt is this threat was helpful as I managed to get all 11 enemies to patrol around the level while maintaining a smooth framerate. Still, I think the biggest problem was how I was using the state machine. At the beginning of the enemy script, I had a variable for the default state( called default_state) and then placed in it the state. However, I didn't do it with the _onready function and I suspect that caused most of the performance troubles. I ran to other problems with my script but, they aren't related to this thread and I'll be easy to fix( I'm just too tired now). Thanks for the help everyone.
@Calinou
Okay, so today I found out that a strange occlusion was messing with my performs. However, the advice from cybereality has given me the ability to abandon collision shapes all together.