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

Updated Democracy 4 to build 1.24

Here are all the exciting changes!

[1.24]
1) Improved new game debt slider so it always defaults to the middle and allows zero or doubling the debt.
2) Added Tobacco Awareness Campaign to the Canada, Australia and Spain missions.
3) Cynicism has a stronger effect now.
4) Added a link between inequality (low equality) and violent crime.
5) Added a link between average temperature and violent crime.
6) Edits to South Korea Mission: President not Prime Minister, Removed Royal Family, Added State Broadcaster.
7) Fixed bug where the North Korea threat could we warned about to any country!
8) New Australia-specific dilemma: Mining on aboriginal lands.
9) Australia gets a default energy industry boost, and some other values have been tweaked.
10) Australia now has stronger impacts on CO2 from renewable energy due to good solar power potential.
11) Fixed bug where the financial cost of situations never seemed to change.
12) France and Germany now have an EU Contribution situation that costs money, Spain has EU Subsidy situation as income.
13) Added EU Monetary policy to France, Germany and Spain. Effectively uncancellable Quantitative Easing.
14) Members of the EU can no longer impose capital controls.
15) Optimizations to startup, and general UI.
16) EU countries now have a 4x multiplier to the political capital required to change immigration / tariff rules, due to needing EU agreement.
17) The US now has custom names for ministers (like sec of state etc…)
18) The US now has reduced anger at handgun laws from parents, reduced anger at armed police from liberals, and higher default racial tension due to it’s history.
19) UK now has a monarchy situation.
20) Added Nuclear Weapons policy.
21) Fixed tooltips on customise mission screen, and we now hide 3rd party details if not enabled.
22) Fixed bug where start of new game added one turn’s deficit to the debt.
23) Increased Canadian government debt to the correct (much higher) figure.
24) Private Prisons now also reduce the severity of prison overcrowding.

BTW the game is currently 30% off on steam. OH MY GOD Grab it now etc.

CPU/GPU concurrency in video games

I’m no graphics programming expert, and not really any kind of programming expert, unless you want a strategy game coded with its own engine, in C++ for the windows platform in which case *cracks knuckles* I’m pretty experienced. (Actually I dont know hot to crack my knuckles).

What I do know,. is what to look out for, when you are worried about performance. One of the things I learned early on, was learned REALLY early on, when I made a game called Kombat Kars (probably in directx5) and was working on particle systems. To make it clear just how many aeons ago this was, lets take a look at an epic image of the rear boxart (yes! retail!)

Kombat Kars (2001) Windows box cover art - MobyGames

Yup, its not the frostbite engine.

Anyway, I was working on optimizing the drawing of vertex buffers full of particles, or asteroids or whatever, and I was depressed to discover after doing some cunning batching of my draw calls, that the performance went DOWN. Yup. Making the game more efficient in how few draw calls it made, made the game run SLOWER.

How can that be?

Actually super-easy, barely an inconvenience, but to understand why, you need to conceptually understand whats going on in the box when you run a PC game under windows. You basically have two CPUS. One of which is on the motherboard and is general purpose, the other is on the video card and specialized for processing vertexes and shaders and so on. It used to be 95% CPU work, and 5% GPU work. These days the GPU is often the most expensive, and powerful component in the box. On a lot of setups, the capabilities are fairly equal.

Its that equality of power that can actually cause problems. The peak performance of the machine is when the CPU is 100% busy (all threads!) and AT THE SAME TIME the GPU is 100% busy (multiple streams at once etc…). This is almost impossible to achieve, but its possible to actually make things worse than they should be, when you get too obsessed with batching.

If you don’t care about performance you code like this:

PrepareAMesh();
RenderAMesh();
PRepareAMesh();
RenderAMesh();
PrepareA..

Then one day you read some articles about the reason your frankly low-poly indie game runs at 20fps is that you have WAY too many draw calls. You read about batching, and your new code looks like this

for(int n = 0; n < lots; n++)
    PrepareAMesh();
RenderAllThoseMeshes();
for(int n = 0; n < lots; n++)
    PrepareAMesh();
RenderAllThoseMeshes();

And all is good in the world, because suddenly you are not flushing the queues on the video card every nanosecond, and its doing what it likes to do, what it was BORN to do, which is to stream through a whole ton of data like a sieve and throw polygons at the screen fast! But hold on…things can go wrong…

for(int n=0; n < eleventybillion; n++)
  PrepareAMesh();
RenderTheWholeDarnedGame();

This can actually be a REALLY BAD IDEA. Why? surely batches are good right…? well…to an extent. It really depends how you structure the code. It *might* be that during all those bazillion PrepareAMesh() calls, the GPU has run out of things to do. Maybe it hasn’t done ANYTHING yet this frame. It finished the last frame, and now its basically watching netflix waiting to hear from you some day…

…and once the CPU calls the GPU to render all bazillion polygons, depending how you structure the code, the CPU may be doing nothing. Maybe this is the frame end, and the CPU has to sit on its ass waiting for a Flip() or present() call from the GPU to get back to it some time maybe next week after the rendering is finished, when it can start thinking about the next frame?

This is the CPU/GPU concurrency issue. You can be TOO BATCHY. You can inadvertently set things up so that the GPU is always waiting for the CPU and the CPU is always waiting for the GPU. This is BAD for performance.

Luckily, free apps like VTune let you analyze this. FWIW Democracy 4 has no such problems with this at all, but to show you how it looks, here is the output of a very brief snippet of the vtune CPU/GPU concurrency analyzer:

You can see near the bottom how busy the GPU and CPU are. Luckily for me, they both keep pretty busy, even if I zoom in a lot to see the span of individual frames, but if your zoomed in CPU/GPU concurrency stuff shows big empty blocks within a frame, you have some optimizing to do.

The reason this catches out so many experienced coders is that it *sounds wrong*. Surely batching is good right? It is… but you have to remember that if the GPU would otherwise be sat on its ass eating crisps, even doing a bunch of small inefficient batches of 50-100 vert each, is MORE efficient that just letting it sit idle.

Think of the CPU/GPU as a team trying to do the dishes. The CPU is washing em, the GPU is drying them. Don’t let either of them stand idle.

Improvements to the political compass / voters opinions

I’ve been trying to improve voter behavior in Democracy 4 with a bunch of goals. Firstly to maker the political compass Overton window not look so ‘forced’, and more importantly, to allow for more realistic modeling of the variety of opinion. As some players have pointed out, there is always SOMEONE in the electorate who will not ever vote for you, always some communists, always some capitalists, and so on. How to fix this?
Here is the political compass for a new game as Australia:

And here it is with my new changes I am considering:

The voters are less confined to the Overton window, and yet are still influenced it. We clearly have people far to the left of the political consensus zone, but not quite as far left as Stalin and Lenin. I think this makes sense. Even people who are claiming to be outsiders and not swayed by the mainstream media or mainstream politics are still vaguely influenced away from the extremes.

The (debug-mode-only) tooltip data for impressionability illustrates this. The game has always modelled the ‘impressionability’ of voters, but with recent changes, I’ve improved how this calculation is used to determine a final opinion. Here is the final calculation:

Final Socialism = (CurrentGlobalSocialism * Impressionability) + (InnateSocialism * (1-Impressionability))
(This is a new equation for this version, it was different before)

So every voter is born with an innate predisposition to socialism (also liberalism) or not, and this is their ‘starting’ position. They then get swayed towards the ‘consensus’ position (Global Socialism) by how impressionable they are.

Impressionability is calculated as a normal distribution but then squeezed in so its between 15% and 85%. (Its then multiplied by 0.95 which is an internal value and not important…)

Note that if the ‘Polarization’ situation is active, the value of InnateSocialism gets pushed out to the extremes by the strength of the situation.

I need to do a lot of play testing, but I think this change will make the game feel more realistic.