4
« on: October 17, 2011, 07:40:46 am »
At a very quick glance I stumbled upon this:
sf::Sleep(1.0f/FPS);
You could replace this with something like
if(1.0/window.GetFrameRate() < 1.0/FPS) {
sf::Sleep(1.0/FPS-(1.0/window.GetFrameRate()));
}
It calculates the actual delay between frames for desired FPS. Say your target FPS is 60, the desired delay between frames is 1.0/60 = ~0.01667 seconds. Now, if your game runs at 80 FPS, the actual delay between each frame is 1.0/80 = 0.0125 seconds. Because 0.01667 - 0.0125 is 0.004 seconds, the program sleeps for approximately 4 milliseconds to increase the frame time to ~0.01667, and making FPS to a approximate of the targeted 60. However, note that this isn't an ideal approach either, because if FPS fluctuates a lot between frames, this can't provide consistency needed to cope with it, but for this case it should help things a bit.
Do you have compiler optimizations turned on? On what kind of a machine do you run the code?
There's lots of room for improvement in the code, however, of what I can tell it's hardly anything complex which a compiler shouldn't be able to optimize away anyway(e.g. there are multiple if()'s inside a loop, which all could be avoided by doing comparisons and branches before entering the loop).
You're also initializing a sf::Event local variable inside the main loop of game::Run() for some reason. You could make it a member variable of the class and avoid always generating a new variable. This isn't likely to hurt your performance though, but it's horribly bad code when you think about it. Local variables get "freed" at the end of the scope, so you keep initializing and freeing the variable for nothing.
After you handle the events, you test if the snake eats food with Terrarium[0], this is fine and good. However, after that, you loop through the snake and do the following per every node of the snake:
CollideBody() to check if the head has it part of the body
EatFood() to check if any of the nodes have eaten food
Update() to move the nodes of the body
Draw
The bolded one makes no sense. The head has already traversed the exact positions of the nodes already and they are certainly free of any food, so there's no way for the rest of the body to stumble upon food if you change your food::NewFood function to make sure the new food does not spawn on locations of the snake's body. I also suspect that the EatFood() function is the root of all evil here as it calls the function which does pixel perfect collision, which is definitely slow.
Also the CollideBody() function could be changed to loop through the snake body inside the function rather than calling the function per every node of the snake's body. This wouldn't only be good design but also would avoid the function call+return overhead(which isn't much, but still something you should avoid in this case).
Also initializing the Terrarium vector with a big enough value to hold the snake from the beginning without having to resize every now and then can save you from a few hiccups which happen because when the vector gets full, it has to allocate new memory(usually double size of the old) and copy the contents to that new memory and free the old memory. This usually happens when the vector reaches size of 2, 4, 8, 16, 32, ... etc. It only gets "visible" in forms of performance loss when the vector contains lots of data to copy around.
As always though, these are mere guesses and hints for you to take a closer look at, I am not able to run the code and as such it's nearly impossible to get an actual understanding of what truly holds you back in terms of performance. The only real way to measure that would be to run the code and use a performance profiler to get an idea what functions are being called the most and what functions take longest to finish, and as such focus on those slow/frequent functions in terms of optimizing. Usually in these cases the popular 80-20 rule applies; 80 % of time is spent by 20 % of code. Locating and focusing on that 20 % is the first and most important thing to do when considering code performance and optimizing. As always, measure the performance before and after you make any changes.
..and remember, after all the most important thing to do is to measure twice and cut once(..and curse three or four times).