Is speed of the essence?
I'm currently trying to make an isometric tile based game and I have some questions about some things I ran into.
To draw one screen, I have to calculate which tiles to draw (how much for y and how much for x). To do this I have (in my opinion) a heavy calculation, but it works. It's something like this, but with other vars:
a = ((b % c) + d) / e + (((b % c) + d) % e != 0) + 1;
all vars are integers.
as you see (b % c) + d is in there twice so I thought maybe I can simplify it. I thought about it, but can't figure it out.
But is it necessary to simplify such a calculation? Is it wurth it? Like I said this calculation is done each frame. Would it slow things down a lot?
(And BTW do you know how to simplify this calculation ;))
Also, here's a tip that can cut 90% of your draw time down, as well:
Don't redraw every tile every time. Redraw only those tiles which need updating.
If you're using a good front buffer/back buffer approach, blit the front buffer into the back, make only the necessary changes, blit to the front.
By making this one change, I've cut draw times from 14 ms to 3 ms in similar applications.
I'll try that updating tip...
I found out that I *can* simplify that calculation. Well not really, but I'll try to explain.
I also tried using another var to store (b % c) + d but I can't really see the diffirence yet because I haven't put in a fps counter yet, so I looked at the assembly code created from it to see how many lines (so how many operations) there were.
From that assembly code I found out that "/" and "%" use the same operator but diffirent registers (or whatever they're called). So using assembly I should be able to optimise this. And I tried...
While learning (a little) assembly I brought back the code from 20 operations (17 with a temp var) to 12 :)
I don't know if this is a huge diffirence, but I'm happy and pleased that it could be done ;)
But is such improvement really necessary???
I'll answer the last part of your question - is it worth it.
Really, it depends on you and what you're trying to program. In the long run, if you fully optimize every single calculation, you'll maybe save yourself a couple fps. But really, simplifying a single calculation, even if it's in your main game loop, won't significantly or noticably speed up performance. Some programmers like to make sure that every single calculation they do is fully optimized, and maybe if you're going to release a commercial game, it's worth it, but it's my opinion that the time some programmers spend on speeding up calculations (I've seen people spend twenty minutes figuring out how to change all his multiplication to bit shifts in a one of his calculations) is better spent optimising other sections of code. For example, if you fix up every calculation in your program to full optimisation, you'll save a couple fps as I said before... if you do as The V. suggested and only redraw necessary tiles, your fps will probably more than double (unless you're already running near to the max :)). Although, in a perfect world, programmers have all the time they need to do everything and have the time to optimise every single thing....
Thanks for answering my second question HappyDude. I never know if I have to go for optimisation or not. Maybe I just want too much sometimes. But I'll try to use the updating sequence The V. suggested and I'll see what it gives me...
Well, I've done a tile based game, and there are a *few* optimizations I will do, but I don't try to optimize EVERYTHING.
The other really handy thing, besides keeping track of which areas need to be redrawn, is the fact that if you do math with one operand a power of 2, there are usually *really* easy ways to do this.
Ex: Division by 2^n is the same as right shifting by n bits, and multiplication is left shifting. As often, you need to multiply by, say, 32 if you use 32x32 tiles, doing:
x << 5;
is the same as
x * 32;
but much faster. Similarly, modulus is equivalent to bitmasking if you are taking the modulus of a power of 2. For example:
x & 1F;
is the same as:
x % 32;
but again is faster.
Because there is so much "power of 2" math in games, and because it's something like 60 times faster to do bitwise operations, it's a handy thing to know how to use.
And, how fast is fast enough depends on the nature of the program. A tile based RPG can probably easily get away with fixing redraws at 30 FPS and looking just fine.
BTW, a handy trick is to use the timeGetTime() method to clock each part of your game, to see which parts are taking up the largest shares of time. You can use this:
int startT = timeGetTime();
// do some stuff
int elapsedTime = timeGetTime() - startT;
Then, you can figure out what parts of the game are taking too much time (and too much is all relative). Optimizing an area of code that takes 1 ms or less to execute is kind of pointless, as it's not your limiting factor. Knowing how much time each piece of your code is taking will tell you where you should think about optimization.
I know how to use those bitwise operations. I just never knew they were *so* much faster.
The thing is I never thought of using them now, because my tiles aren't a power of 2. Because I use a isometric approach the width is 2* height. But I didn't make the height a power of two. But I guess I can make it 32 in stead of 30 or someting like that and use the bitwise operations in stead of the %, * and /.
It's just that I always try to start out with a general implementation for all sorts of tile widths and heights, so I can choose later which sizes to take. But I can always change that later.
For now I was working on calculating which tiles are visible on the screen, so I know which ones I have to draw. If I only redraw the parts that have to be updated, I could still use this, because I first have to check which tiles have to be updated. And that can be done by checking the visible tiles.
I have one question about this. If a tile is not visible on screen, but it has a entity that is so tall that it IS on the screen, how could I check this? Should I just also check each tile under my visible field to see if there are any tall (or heigh above the ground) entities? Whouldn't this be a bad thing?
It's not a particularly good idea to go round rewriting various bits "optimally" until the program is complete. It's pretty hard to work out where the hot spots are until you've done that.
When the program is complete, then you use a profiling tool to analyse where the program is really spending all the time. Then you can focus your optimisation efforts.
The result is you only optimise what you need to.
x << 5;
is the same as
x * 32;
most compilers will spot this even in in unoptimisation mode.
gcc in particular knows how to do a lot of the non-obvious ones as a series of shifts and adds.
> a = ((b % c) + d) / e + (((b % c) + d) % e != 0) + 1;
If your compiler supports common sub-expression elimination, it will cope with this problem for you, and only evaluate ((b % c) + d) once.
Until then, the focus should be on clear code which is obvious to the reader. Debugging 'optimised' code is a nightmare.
I'm not trying to make my code optimised right away. But this part is finished now and works perfectly (no bugs). So I could try to optimise it.
I don't know if my compiler does what you called common sub-expression elimination. Maybe in the release version, but in the debug version (looking at the assembly code) it doesn't.
I've heard about a profiler tool before, but I've never used one. It is, if I'm correct, to see which function is taking up the most time. That way you could try to optimise it.
I'm working with VC++. Do you know if there is a profiler with it? Or could I use one out there on the net? I've tried looking for one, but haven't found one yet...
> Maybe in the release version, but in the debug version (looking at the assembly code) it doesn't.
The debug version is meant to make the source and assembly match up (so it makes sense debugging).
> I'm working with VC++. Do you know if there is a profiler with it?
In the professional and enterprise editions.