November 24, 2016 | Filed under: programming005
Occasionally I see some interesting posts on reddit or gamasutra or some other dev site where programmers are asking about stuff to do with game development, and I find myself thinking ‘these aren’t the things you really ned to know’, but because its such a DIFFICULT thing to articulate, I never even try. I’m going to try now…and it will be messy.
A long time ago, when the world was in black and white and you could get your milk delivered even in the cities, I went for a job as a game programmer with a smallish UK game studio. I didn’t get the job. I remember in the interview being asked about my code, and in some vague way trying to explain that I knew what I was doing and a proper software developer. I waffled really badly about how giving sensible names to variable meant that I knew what I was doing and not some n00b.
In my mind…this:
for(int counter = 0; counter < total; counter++)
Made me so much better a software engineer than
for(int x = 0; x < total; x++)
That just goes to show how much I had to learn. The real problem is that the stuff you need to learn is big ‘hand-wavey’ stuff that its really hard to explain, let alone teach! if you haven’t already read a book like Code Complete, Now would be a good time. I will try and explain the sort of stuff that it really helps to learn, and it will be vague and awkward, and hopefully that kind of makes my point about how hard it is to grok this stuff.
I have a class in my latest game called GUI_Tile. Its the visual representation of an actual tile in the game world called SIM_Tile. Each SIM_Tile has a GUI_Tile, and anything that is on-screen is handled by GUI_Tile. In order to draw my world, I go through all of the GUI_Tile objects and call draw on them. Actually, thats what I used to do, but it turns out there are a lot of them and thats fairly time consuming. When I profile the code, looking at where the time is spent, I realize that a lot of it is not actually directx calls, but its transform stuff, and scaling stuff, and working out the sizes of sprites based on some animation they are doing, and their offsets and whether or not they are even on-screen given the current camera position. The actual DrawSprite() bit of each GUI_Tile call is only the last statement…kind of a footnote.
While all this is going on, the other 7 effective cores of my CPU are chatting about whats on TV and picking fluff from their navels.
So clearly, I should find a way to multi-thread all this, even though I’m using Directx9 which is effectively single-threaded.
Soo… I could create a new thread at the start of the app, and make that my directx render thread. it could then do nothing but make render calls, and all the other stuff could happen in another thread, thus allowing me to double up on what was going on. To keep things from going crazy, and me updating a sprites co-ordinates just as directx rendered it, I need a hard STOP! (or mutex etc) at the time I start rendering, but it will still allow some overlap surely? I could carry on with the windows message handling and sound/input processing in thread 2 while thread 1 was still rendering the previous frame.
I could split the GUI_Tile::Draw() call into GUI_Tile::PreDraw() and GUI_Tile::ReallyDraw(). If all of the stuff in the PreDraw() is self contained or ‘read-only’ (in other words that function never changes the value of any data outside its own object), then I can run a whole bunch of those at the same time. I can keep my directx in the main thread, but pass all the tiles in bunches off to 7 other worker threads to do PreDraw(), then when they ALL finish, I can just quickly loop through the Draw() calls, which are way faster.
I could not do a lot of this transform stuff or drawing stuff each frame anyway. I could use a dirty-rects system, where when I render a frame I keep a copy of the whole thing in an offscreen buffer. I then only bother calling Draw() on those tiles which I know have actually changed or done anything. That way I’m massively cutting down on the number of Draw() calls I make, and I can keep the entire thing in one thread and thus way simpler.
The real thing you need to learn to be a decent game developer, is which one of those solutions will work best for this game, with this hardware, with this API, with this data. Coding any one of those solutions takes TIME. Debugging them takes more time, and profiling and analysing to see which works best takes more. Maybe having 8 threads all running is actually slower than just one (this can happen if you do it badly). Maybe a dirty rects system falls apart dramatically when zooming and scrolling. Maybe assuming PreDraw() is a nice self contained function is a bug-prone disaster waiting to happen in obscure and impossible-to-debug ways.
This is the real hard stuff, and the main reason its real hard is that its very difficult to get on top of this sort of thing until you have done it a LOT. If you have programmed, for example, a sound engine…well done. Take a bow, its honestly not that easy, and I bet you learned a lot. You have programmed your FIRST sound engine. Now delete all the code and program it another way entirely. then again, then again, then again. NOW, you know how to program a sound engine. you know why method A is slow, why method B is buggy, why method C is hard to maintain, why method D doesn’t scale, and method E Is awesome, but only on Playstation 4.
This is why the top jobs often to go to coders with experience, and why the sheer amount of code you have written and the number of hours you have been typing code really does matter. Being a good programmer is rarely about those things that are often bandied around like ‘always comment your code’ or ‘use descriptive source control commit descriptions’ or ‘use this syntax in your code’. Its mostly about the big ‘code architecture’ decisions. The way you lay out your code, the overall designs, the thinking behind how the whole process snaps together.
The most efficient coding you ever do is probably with a pen and paper, or a big chalkboard on the wall. When you have done this a LOT, you can do that in your head, but that takes decades. The more you code, the better you get.