Game Design, Programming and running a one-man games business…

Memory allocation improvements

I’ve been working on about 16 different things, but one of them was to reduce the memory leakage of GSB. I know some people design very cunning survival-mode fleets and have battles that can go on for an hour or more, and basically GSB leaks memory quite badly right now. Also, if I ever want this game ported somewhere, it will need to get it’s memory use under control. Plus campaign games sometimes lead to some VERY big battle, which makes the issue worse.

Lots of fiddling around (writing my own memory allocation debug stuff) means I could watch exactly what was getting allocated mid battle. I dumped every memory allocation during battle to a text file, then chopped off the first 10,000 (so I don’t worry about early allocations, which are then cached and re-used anyway), so I could see what the long term persistant offenders were.

The next step was to ensure I was looking at the *amount* of RAM being used, not the number of small trivial 20 byte allocations. Those need optimizing too, but not now. To do this, I stuck all the text which looked like this:

file:..\src\GUI_Particles.cppline:429 28672
file:..\src\GUI_Ship.cppline:733 204
file:..\src\SIM_TargetedModule.cppline:905 48
file:..\src\SIM_TargetedModule.cppline:981 12...

Into Excel, and created a pivot table out of it, to nicely summarise each allocation type by number of calls and total RAM allocated. It was clear that particle allocations were rare, but huge. It was immediately clear that I was allocating memory for a big mega explosion even for the tiniest 7 particle fighter-impact effect. All I did was re-write the particle code to calculate on application-start what the maximum number of particles were that this emmiter could ever need, and then ensure it never allocated more than that when I created it.

Some more work with extensive debug display code mid-battle was done to ensure the new system was working as expected, and that the majority of the allocated RAM was indeed needed and being used.
End result? My test battle (Multari nebula, a fair few fighters, fought to the end with all options turned on) went from a peak of 403MB for GSB.exe to 305MB. That’s pretty darned good. The savings on bigger, longer battles will be pretty noticable.

Expect that improvement to be folded into a future update.

Basic principles of game optimisation

Making games run faster is a pet topic of mine. Code samples are too specific to help many people, so here are some general principles I’ve learned.

1) Design to avoid the code.

Sounds horrid doesn’t it, but people do it all the time. ‘Skinned’ animation at points like shoulders and knees is CPU intensive and tricky. Ever noticed how many characters in games have big shoulder-pads? Makes life much easier. GSB is a 2D game, mainly because I prefer 2D gameplay, but I can’t ignore the fact that it would be horrendously more draining on the CPU/GPU to be in 3D

2) Run the code offline.

If the output of your code is a one-off, only ever do it once, and before you ship the game. The GSB campaign game code has some really inefficient slow brute force stuff for calculating planet-travel distances. It’s done as a one-off, and the results loaded in at run time. If there are calculations your game makes at run time that are based on data that never changes, just pre-calc them and load in a table, assuming the table is small enough

3) Run the code once, and cache it.

This is the ultimate big win. In the old days, people used tables of cosine/sine lookups, rather than calculating them. Hold on! GSB does that for some stuff too (nothing gameplay critical). Never make a calculation twice in a  function if you can do it once and reference it later. It’s amazing what a difference this makes. even simple stuff like STL list end() calls can mount up with really large containers

4) Don’t run the code every frame.

Not much code has to be run every frame. The minimap in GSB isn’t updated every frame. Can you notice? I can’t, because most frames a ships movement would be ‘sub-pixel’ anyway. If stuff like this seems to jitter, update half the code one frame, the other half the next frame. A frame should be 1/60th of a second. Nobody will notice.

5) Don’t process what isn’t seen.

GSB does some cunning code for all kinds of cosmetic things that only applies if that activity happens onscreen. In theory you can pause the game, scroll around and spot very minor inconsistencies (good luck). With strategy games, most of the time, most of the action isn’t being viewed, so you can skip allsorts of stuff. I don’t update timers for running lights offscreen, for example.

6) Re-order and group stuff.

Graphics cards like to do things in big clumps. give them a single texture, and 50 sprites to draw and they are happy. Give them 50 sprites with different textures and they are not. This is why all the GSB debris is clumped into a single texture, ditto the laser bolts. I also re-order ships in the game code so that similar ones are drawn one after the other, even when drawn as icons. This minimizes texture swaps. Because GSB doesn’t use a z-buffer(for blending reasons), that makes for some spaghetti like code, but it’s worth it. The easiest system I’ve found is to maintain spritelists for different textures. You still draw sprites as normal, but when they draw they just get thrown into the relevant list, and the list gets drawn later.

7) Save stuff for when you are not busy

GSB does this. It’s very tricky, but you can have code that only runs when the CPU is idle. If a laser bolt hits some debris in GSB, the debris explodes. This ONLY happens if the CPU is idling. People spot it occasionally and think it’s l33t. They never spot that it doesn’t happen all the time.

8) Optimize the UI

People get a fast engine then slap some super-slow UI on top. Madness! With a lot of text, icons, dialog box backgrounds and multi-part buttons, you can have crazy overdraw, crazy texture-swaps and huge inefficiency. Keep an eye on it.

Don’t forget that you can also optimize textures too. Some textures are ripe for compression, others not, but you can also do crazy tricks with some stuff, like chop a circle texture into one quarter, and raw it as 4 flipped and mirrored sprites (I do that a lot). Not everyone has 512 MB video cards, and its quicker to load a small texture than a big one anyway.

Most coders probably know all this already, but it doesn’t hurt to recap. It’s easy to forget about optimising and just worry about features, but gamers will thank you for it. I get a lot of people remarking how surprised they are at how well GSB runs on their machine. This is no accident :D.

At last reaching code size issues

For indie games, my games are pretty big in code terms. By the standards of big triple A games, they are fairly simple. The problem with any game, is not really the lines of code as such, but the interconnections and complexities.

Now, if you have coded big systems for ages, you get used to writing very modular stuff. All my games are split into SIM and GUI classes, which in theory have very very little overlap. The problem is, that games of the sim/management genre become more and more intertwined between those two concepts. This means lots of unintended side-effects, and that often means more bugs. It also means a lot of possible permutations to test, and that invariably leads to more bugs.

In theory, I suspect the real answer to scaling up code is to go beyond merely thinking in a modular way, and to write totally distinct programs, or at least DLLs. Having a clearly defined interface between the Sim, the UI and the gameplay rules is very handy and if you actually stick the GUI in a separate project, it makes it easier to stick to that with real discipline. That also makes it easier to have people port your game, switch to a different graphics API, or mod the game. To be honest, I’m not as good at this stuff as I should be, and the campaign code for GSB is bringing that home. It’s been far too tempting for me to just stick a bunch of spaghetti into the GUI code for a dialog box that does some SIM stuff. I re-designed various code today to make it more organised, but I should probably do quite a bit more of it.

I wish I’d coded totally open AI that could have been scriptable, or at least existed as a DLL that modders could expand. Coding that sort of stuff is normally a full time job for someone for a year though, so you can imagine why I didn’t do it :D

How to stay motivated whilst programming a game

Lots of people want to know the answer to that question. Most indie games fail. Most indie projects never get completed. I don’t have any way to prove that, but any indie game veterans will know it’s true. Here are my top tips. Some of them may seem like they de-motivate, rather than motivate, but I get motivated by knowing how important and serious it is for me to work hard. Most indies don’t realise how hard they are going to have to work, and how good their game has to be.

1) Code something you like.

Just because you did your research and can prove that a poodle simulator is the best choice for the current games market, doesn’t mean you want to program one. You might kid yourself that you can see it as a ‘mere engineering challenge’, but you won’t. Getting out of bed when nobody forces you to, with no deadline and no boss, to go code poodles probably won’t motivate you for a solid year. Pick something you are passionate about. I love sci fi and space battles, so making gratuitous space battles was a no-brainer. On a related note, save up some ‘fun’ coding for when motivation is low. Feeling keen? code the save game system and the options menu. Get them out of the way.

2) Surround yourself with inspiration

I listen to music from star wars or star trek when coding easy stuff or doing art. Coding scrollbars can seem dull, but the music reminds me these are spacefleet scrollbars and that makes it ok. The people who play your game won’t see the code, only the art and the game, so keep a picture of the final ‘atmosphere’ of your game in your head all the time. Does your pc desktop wallpaper not reflect the mood of your game? why not?

3) Keep a log of what you did each day.

Sometimes its easy to think the day was wasted, that nothing got done. I have lists of things to do for my games like this:

  • Fix bug with plasma torpedoes
  • Resize scrollbars
  • Add tooltips to buttons
  • Add transition to options screen

At the end of the day my log looks like this:

  • **DONE**Fix bug with plasma torpedoes
  • **DONE**Resize scrollbars
  • **DONE**Add tooltips to buttons
  • **DONE**Add transition to options screen

And that makes me realise how much I got done. You get a tiny adrenaline rush by crossing things off a todo list. Make one each day. Make the entries small, simple items, rather than huge projects. It should always be possible to cross something off each day.

4) Do some shiny

Mr Spock would code the entire game engine, get the gameplay balanced using just coder art, then add the graphical fluff last, to minimize re-doing work. I used to assume that made sense too. I used to rail against Lionhead for having so much artwork, code and music done before we were even sure how the game played. So much work got thrown away. Now I realise it’s important for your motivation to have something that looks and plays nice ASAP. The GSB campaign add-on hasn’t got all its gameplay coded yet, but theres a gratuitous map-zoom effect in already, plus background music. Having those things there keeps me positive about how cool the final game will look. There really is a good reason to code some shiny stuff in the first 25% of your project. Just don’t go mad.

5) Hard lessons in money

I gave a talk at a conference recently about the reality of indie games as a business. To be short and sweet, you need to sell a full-price game direct to a customer every 45 minutes, or you probably won’t make a career as a  full-time indie. That means at the very least someone grabbing your demo every 240 seconds. When you keep this in mind, you realise you need to make your game really good. Better than it is. You need to do better, just to survive in this market.

6) Stay aware how high the bar is (know your competition)

Don’t forget that for most gamers, the competition isn’t other indie games, but AAA games, or even other activities, TV, movies, etc. When I worked on the battles for GSB, I spent very little time looking at rival games, and virtually no time looking at indie space games. I compared it to the best sci-fi battle scenes I knew of, by ILM. Yes, you have to pick your battles, and graphics might not be one of them. Spiderweb compete on game length, Dwarf fortress on gameplay depth. Whatever it is that you are competing on, you need to ensure you aim as high as you can. Also remember that your game isn’t measured against the best game there is right now. It’s measured against the best game when your’s gets released…

8) Take short breaks.

Get away from the PC for a short while, so when you come back, you are fresh, keen and energised. Physical activity is a good idea. I do archery now and then. It’s ideal because it involves standing upright, concentrating on a distant object, and 100% focus on what you are doing. It’s the perfect sport for desk-bound geeks

===

Staying motivated is hard. Everyone has the same problem. Often, its the deciding factor between getting your project done or not. High motivation trumps everything. There are indies making games who are homeless (yes really) and who had to make them ‘undercover’ in Cuba. They still got stuff done. Lack of experience, lack of money, lack of time, can all be overcome by sheer bloody determination, if you can summon it. Now stop reading this, and type out tomorrows todo list.

Crappy windows code

Soo… some people have a bug in GSB where in fullscreen mode, the titlebar of the windows ‘window’ is still there, but invisible, meaning you can accidentally hit the close or miniomize buttons, or worse-still, double click and then ‘maximise’ the already fullscreen window.

I have encountered this a few times in GSB myself. but cannot reproduce it right now. It’s certainly not reliable. And it’s annoying. I would love to fix it. I’m pretty sure its something to do with the windows code that selects either a windows style or windows class.

currently I use:

wcex.style            =    CS_CLASSDC | CS_DBLCLKS;

and

HWND gWnd = CreateWindow(appname,appname,
 WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
 0,0, width, height, GetDesktopWindow(), NULL, hInstance, NULL);

Both chunks of code I haven’t changed in ages. I suspect the code is wrong, but am finding it impossible to find what is ‘correct’. Looking at the directx samples makes me want to cry. In amongst 500,000 pages of incredibly convoluted, confusing, totally over-engineered MFC style bullshit that they call ‘DXUT’, there is a hint that microsoft themselves use just CS_DBLCLKS and WS_OVERLAPPED. The thing is WHY? There is no documentation. In the old days, directx5 used to tell us we need to use WS_TOPMOST or somesuch.

You would imagine that as 95% of people using directx write games, and 90% of them want to, at some point, run fullscreen, that the directx docs would have a line saying “for fullscreen apps, you need to select these options for your window”. No such clues have emerged though.  Another evenings trolling through coding forums no doubt…