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

Building a deterministic space auto-battler

This was not part of the plan. When I made Gratuitous Space Battles, it was not a deterministic sim. Multiple runs of a battle could lead to slightly different results. It was not ideal. And I was not even thinking about it with Ridiculous Space Battles, until I started to do balance testing and started designing campaign levels. And in that testing I started to really appreciate how infuriating a lack of determinism was. That was more than a week ago. Maybe two weeks…

To explain: Ideally if you do two battles in RSB with the exact same deployments, you should get the same result. Not just victory or defeat, but the exact same score. This is is the whole core of the game. The smaller the fleet you win with, the more points you score. So running the whole battle again with just ONE less squadron, is definitely worth it for the meta-game (and bragging rights). But that might mean fielding 99 squads instead of 100. In other words, the game has to be accurate down to that 1%, and actually that means 100% deterministic.

Here is the problem. A missile fired from a frigate drifts 0.0001 units to the left compared to the previous run-through. That means it actually hits its target VERY slightly later, but that ‘later’ means just *after* its target fires its massive mega-gun that takes out a crucial enemy cruiser. Without that cruiser, the fleet will narrowly lose. With it, the fleet will narrowly win. So that missile MUST hit its target in the exact same frame, every time…

…and its worse. That missile might even be a dummy missile. It might even miss! it does not matter. Because in theory that 0.0001 units means its the nearest target for a point defense laser, or not. That could still lead to a chain of events that results in the whole outcome of the battle being changed. In practice, if you want the outcome of a big battle to be predictable, and repeatable you need a 100% deterministic simulation. Thats not 99.99999% deterministic. Its absolutely 100%. And that is… hard.

I’m not a n00b coder. I know this problem is hard, AND I know in theory how to avoid it. Have a constant simulation rate, and detach the frame rate from the sim rate. Do not use any truly random numbers, but precalculated ones based on a fixed random seed. You can use true randoms for UI, but never for the sim. The sim is the sim. The UI is the UI. They never get confused. Simple right? And I am sure coders who haven’t worked on it before already think its an afternoon’s work. It is not!

It would have been WAY easier if I had worried about this right at the start of coding the game, but I did not, and so I had to take a huge existing game and MAKE it deterministic, and its taken weeks and I’m not yet 100% sure I’ve cracked it. I have definitely made it much better, but am I at 99.99999% or 100%? Lots of testing tomorrow will answer that for me. But briefly, this is what was involved:

Step 1 was to move from a variable frame rate (capped at 60 fps) to a dual system where the sim runs at a constant interval, but the frame rate is independent. This is complicated by the fact that the game has 5 speeds, from 1/4 speed to 4x speed. Actually to be fair this part of the work was quick and easy. I still have a ton of macros in the code referring to SIMTIME that actually should now just be ‘4.0f’, but thats the beauty of macros. There was a fair bit of find/replace to change a lot of calls in the code to either use SIMTIME or FRAMETIME, but that was simple. Now every tick assumes 4ms has passed, and the ratio of ticks to frames simply depends on the current game speed. This does mean I have kind of lost the ‘frame-smoothing’ for when the GPU is under more or less strain, but TBH the game runs so fast its ludicrous anyway, and for super low spec GPUs the game has a ton of graphics detail settings.

So that sim/graphics decouple was a big step, and an easy step, but after that the real problems began. Basically there were mistakes somewhere in the code. There were circumstances where things drifted out of synch, and it took a ton of detective work to find them all. Things went much quicker when I realised there was no escaping just writing a big ‘Determinism’ class that analysed data across two runs. I made a ton of mistakes here, and they are stupid, but thats coding for you :D. The most embarrassing one was this: I collected a TON of information for every tick, in huge arrays, and then on the second playthrough, I built a second bunch of arrays and kept cross checking them to spot errors. Sounds reasonable right?

Firstly like a muppet, I was checking for ‘drift’ of values every frame, but storing all this data a second time. Stupid. I only need the PREVIOUS playthrough’s data. I just need to collect *this* frames data, and compare against the past. But thats a ‘current-frame’ snapshot. I don’t need to store that! Secondly I was stupidly searching for a matching tick’s data in the previous playthrough. Madness. I KNOW what tick we are on. I can just index it, and do a super quick compare ffs…

You might think thats stupid worrying about optimisation in pure-debug code…but this is a 32 bit app, so limited to 2GB (or maybe 4GB depending on settings), and although my game stays nicely at about 6-700MB, storing 80,000 frames of simulation data for every ship, missile, drone, mine and bullet very rapidly hits that limit. I needed super comprehensive simulation snapshots, but memory-efficient ones. This proved tricky. You might think ‘store everything’ but trust me, its just NOT an option for a long, large battle with this level of complexity and 240 ticks a second (60fps but possibly 1/4 speed so 240 sim ticks per second).

Oh BTW if you think ‘cliff that’s dumb. At 4x speed you still only need 1 tick, just make it a tick thats 4x as long’. NO. This is because in code, a missile moves every tick. If it hits the target, stuff happens then, and in the following ticks. If you bundle 4 ticks into 1, then the missile ‘hits’, but nothing else, whereas it may hit in tick 1, and then ticks 2,3,4 the affected shield slowly regenerates. In other words my sim is discrete tick based, not variable time equation based. Its just simpler this way :D.

So what other really stupid mistakes took me days to sort out? Well they are all kinda dumb, but in a code-base this big, I think I should cut myself some slack. And actually in TWO of the big cases, in the back of my mind I knew as I coded them that they were flaky as hell. Normally my code is VERY cleanly split between simulation and graphics. In fact all my classes are called SIM_Thing or GUI_Thing, to make that super clear, and make sure I don’t do anything dumb like change the sim from the GUI, which would be really bad software engineering that obviously I shouldn’t do and obviously I did in two places :D.

The first one was a bit obscure. When ships ‘escape’ the battle, they quickly zap off the screen like they are entering hyperspace. To make it seem cool, every ship zaps-away at a slightly different speed, because then it looks like the rebel fleet going into hyperspace in return of the jedi… And thats all well and cool, but it used a proper random number in the GUI code, and at the end of the warp-jump, it then told the SIM the ship had escaped at last… What terrible code. This was the GUI setting times for the SIM. Madness. And a determinism destroying bug. Very rarely that extra 50ms was long enough for an enemy ship to get just one extra enemy-destroying shot off…

The second one is even more obscure. I have classic graphics-distorting shockwaves when big ships explode. They look cool, AND they also move debris, hulks, escapepods and (it turns out) missiles, slightly in space as the ‘wave front’ hits them. I coded this with the GUI determining what SIM objects to move when… because it was way easier. I know in the GUI code the radius of the shockwave, so I can detect anything I need to move in the GUI code, and apply a physics force to them. The trouble is…thats the GUI lecturing the sim again, and because speeds can vary we cannot ensure the sim tick / frame rate ratio, which means in one playthrough a shockwave moves a missile maybe 4ms before another playthrough, and that tiny difference is determinism-destroying. For now, I just stopped missiles reacting to shockwaves. The rest is just UI and doesn’t matter.

So thats where I am now. I have run 6 consecutive tests on 2 different (smallish) levels, and its 100% deterministic. It was HARD. All the mistakes were dumb ones by me, which is basically the definition of coding alone. It took a lot of detective work, and really focusing on the very first deviation from known values to track it all down. (There were many other minor causes). One of the side effects of working so hard on all this is that it really has reminded me how much I love the TV show devs. Which if you have never watched… why the hell not?

Some thoughts after visiting China

I was woken today at 6.20AM, so you get to hear my thoughts on a 2 week trip to China before breakfast. First, where did I go? It was a 2 week trip starting in Hong Kong, then flying to Beijing, then a train to Xian, then a flight to ZhangJiaJie, then a flight to Shanghai, then home. Yes, multiple flights, I know. I offset everything, and took the train for the one trip where it was viable. Anyway, here is my experience!

Hong Kong!

…was amazing and cool, but at the end of the holiday it became clear that Hong Kong is massively like the west in comparison to the rest of China (still). It reminded me more of South Korea than the rest of China. Its also a fairly ‘low-key’ city. I thought the skyline was impressive, and we went out on an old Chinese fishing boat on the river to see it (which was probably the highlight of that city for me), but later having gone to Shanghai, Hong Kong was ‘meh’. However it was a good place to start, to get used to using the payment system everyone uses (alipay), the food, and the rarity of people who speak any English.

Beijing!

Beijing is FLAT and has a lot of trees. Two things nobody expected! They seem to deliberately limit high-rise building. And there are a lot of tree-lined streets, even really major ones. This was our first encounter with electric cars in China. OH MY GOD. They are EVERYWHERE, and I would guess 99% of the motorbikes are electric. Its so amazing. Super-busy intersections are both quiet and pollution free. Our guide told us charging-points are everywhere and electricity is super cheap. And no, he really didn’t seem to be a communist party agent! Most of our guides had worked or lived in the west at some point.

The highlight of Beijing has to be the forbidden city. It is HUGE and also amazing. Imagine something like Buckingham Palace in the UK, but about 20x the scale. And its a super popular tourist spot with the Chinese. This was another shock. Really very few western tourists. It felt like 90% internal Chinese Tourism.

We also took a day-trip to see the great wall of China. Its pretty incredible. While we were there we saw a helicopter zipping around, asked the guide, and he said it was £300 for 10 minutes. I am NOT going to return to the great wall in my lifetime, so that seemed like a no-brainer. I love helicopters :D. So we did it. I’ve done a lot of helicopter trips on holidays. I have NEVER had one booked and arranged so casually. No 30 minute ‘safety briefing’ here. Just write down your weight, tick a box and jump in!

It sounds like an indulgent luxury thing, but I massively recommend it. You see the wall in a totally different way, including bits that are not accessible and overgrown with plants. It was incredibly cool.

Xian!

We took an eight hour high speed train to Xian. This was pretty good, and it was how we saw ‘rural’ China. SUPER FLAT for the whole trip (although I assume the train is routed that way for this reason), and oh my god the number of wind turbines was insane. I can assure you Trump is wrong. The Chinese love wind farms. Also we zipped past a LOT of farmland on that trip.

Xian is visited mainly for the terracotta warriors which are very impressive, and presented in a way that the scale is vast, like everything in China. On the way to the site, we zipped along a motorway past dozens if not hundreds of huge apartment blocks and skyscrapers, as our (second) guide casually mentioned that this was farmland five years ago! They literally build a city in five years. Its staggering…

I am very pleased with that photo. Check out the people at the sides to get the scale. It helps that I am a foot taller than the average Chinese tourist.

Also we had another insanely good Xian experience. On a guide’s recommendation, we went to the ‘local show’. We expected a normal theatrical performance. But no… its China. So this one hour theater/acrobat/dance performance had six distinct scenes. In the west, we would pause, maybe lower a curtain, and stage-hands would shuffle the scenery. HA! In China they build SIX massive stages around the theater (which held about 3,000 seats I think), and then rotate the ENTIRE BUILDING around the six stages, so there are no gaps. Yup. Just build an entire theater on a turntable. Simple. Also the show was amazing…

Oh and the show had a ton of people in it, and live animals, dogs and camels and so-on, and incredible acrobatics. The tickets were cheap and it was not full.

ZhangJaiJae!

This is my new favorite place on Earth. I simply cannot possible describe it in words, I could paste a hundred pictures here. Its basically ‘pandora’ from avatar (and the inspiration for the movie). It is STAGGERING. Its like some artist took the Grand Canyon in the US, made it ten times larger, filled it with tropical plants, and then installed glass bridges, cable cars and lifts to make it possible to view all of it from a hundred different places. If you think China is all tower blocks and concrete go here. Its amazing. It also has the worlds second-largest glass bridge (the other one is also in china). I am VERY scared of heights, but crossed it twice!

Like anywhere truly amazing you cannot really capture it in photos. Just go there. If you go nowhere else in China, go here.

Also we went on an insanely good cable car. Why be like boring westerners who would build a cable car from the base of a mountain to the top? Just build a cable car from the city center right to the mountain top, and have it trundle over half the city! Because China… Also we went to the 999 steps to the gate to heaven. But I am not super-fit, so we took the series of NINE escalators in tunnels bored into tunnels in the rock that take you to the top. Again, because… China.

Shanghai!

I was VERY sorry to leave, but next up was Shanghai. Wow. If you have been to a place that feels more like Blade Runner, I would be surprised. They do love their high rise skyscrapers here. This was another city massively into Electric Cars, and a city with a ton of variety. We saw parks with retired people doing Tai-Chi and playing jazz and dancing. We saw an amazing night food market, we went to some brilliant shopping areas, saw some incredible historic buildings, and crazy skyscrapers. This was taken from my hotel room 17 floors up.

I bought a cool watch from the shanghai watch company! We mingled with all the trendy young Chinese people (95% women) dressed up in traditional Tang-Dynasty outfits. It was amazing. And like everywhere we went, it seemed 100% safe, 100% clean. No litter, no graffiti, no homeless people, no begging. You can be cynical about this, but I think the west over-do that cynicism. Anyway I preferred shanghai to Hong Kong.

Thoughts!

99% of what you read in the west about China is BOLLOCKS. We talk about Chinese state propaganda, but its got nothing on the hatchet job the west continues to attempt on China to distract from our own problems. Actually going there is amazing, but also depressing, because you see just how much we are being lied to. We had 4 different guides, so we didn’t get just one perspective. They all worked for private companies. Don’t believe conspiracy bullshit about them being ‘party’ appointed. Our first guide was especially relaxed and frank about what is good in China, and not so good. They make it hard to get a job in a city you were not born in, (in some cases). Another guide admitted he had one child because of the one-child policy (not in place now), and you could tell he was a bit sad about that. He also pointed out that there were real ‘ghost cities’ where too much housing got built.

Too Much Housing

This is the thing. China has its problems for sure, and its NOT a place for the privacy minded. In 15 days I reckon my passport was scanned 60 times and my face scanned each time too. On the flipside, we saw zero litter, zero crime, zero graffiti, and a lot of police in busy public places. To be fair the police seemed fairly chill, and some traffic laws get casually ignored by people on scooters. But anyway let me return to… Too Much Housing.

I am a lucky middle-aged man in the UK who owns his house outright. But young people in the west are kinda *fucked*. House prices are insane and unaffordable. Now to be fair house prices in trendy bits of shanghai are no different to central London, but in general, everything seems CHEAP in China. They have just built so much infrastructure its insane. There was a maglev train from the airport to city-center in Shanghai that goes 300kph, took 8 minutes and cost peanuts. All public transport is ludicrously cheap. Food is roughly a third of the price in the UK. And the public transport is modern, fast and high spec. And the provision for electric cars… oh my god. They are the DEFAULT in many cities. Not just of new cars, of ALL cars on the road. Its wonderful.

When I got home to the UK, I made my regular weekly drive to Bristol. For the last 6 months there has been ‘road widening’ on a stretch of an A-road, maybe 2 miles long (at most). Its still not finished. If you had told me all work had been paused for the 2 weeks I was away I would believe it. We spend BILLIONS on trivial infrastructure that takes decades and progresses at a snail’s pace. China builds fast and dramatically and at huge scale. My local road widening would be at most a week’s work in China, not six months. It is *embarrassing* how both technologically behind the west is, and how useless we are at construction.

Anyway, don’t take my word for it. Search youtube for China impressions from US tourists. They are always similar. Its amazing. Do not believe any western media bullshit about China. And do not listen to anyone who has not been there in the last five years. This is a staggering country that is accelerating away from the west so fast we cannot comprehend it. And go there! Especially ZhangJaiJae!

Solar-Powered Borehole Opening Ceremony!

So our solar-powered borehole in Cameroon is now live and working and providing clean drinking water at zero effort to hundreds of people. Yay! There are more details about the borehole here, here and also here. I might not have mentioned it before, but the cost is just over £20k. Very worthwhile when you think about how many people it will affect and the changes and improvements it enables. Anyway, they sent a very nice video celebrating the opening of the borehole, and here it is :D.

Solar-Borehole project update!

Just got an update from SHUMAS, the organisation on the ground in Cameroon that helps us do those charity things, like the two schools. Looks like things are going well. Hopefully lots of pics and updates to come!

Ridiculous Stats Battles

A while ago I re-designed the post-battle stats screen for Ridiculous Space Battles. I was MUCH happier with this than the earlier versions and I loved the horizontal histograms for every weapon which showed not just how much damage they did, but how much was reflected or absorbed by each of hull, armour and shields. I think it was a vast improvement on what I had previously. However! there was much room for improvement.

The biggest issue was that the list of stats chosen didn’t seem to be that helpful. If your fleet was 95% frigates, why bore you with the ‘best’ cruiser and fighter weapons? I re-designed the system to show you more interesting key stats such as the most cost-effective weapon, the ship that was hardest to damage (toughest?) and the weapons that were in use the most (or least). These stats are way more helpful:

Although that was a big improvement, play-testing showed me that a key problem still remained (which is true of all auto-batllers), which was namely ‘How can I translate what I learn from all these stats into adjusting my deployment the next time I fight this battle? This is a big problem (and it was back in the Gratuitous Space Battles days), and I have experimented a lot and come up with a solution I am super happy with!

In hindsight, the solution is obvious. Give the player a way to view want went wrong last time, when they try the level again. In code terms, this was a ton of work, but it works!

So when a battle ends, after viewing the current stats (probably best thought of as stats-highlights now), if you then want to try the level again you have a togglable overlay over the deployment map which shows the fleet you tried last time, with a ton of stats for every single squadron showing how they did.

The coloured squares and the percentages show survival rates for each squad, and you get Survived/Escaped/Destroyed percentages as a tooltip, but click on any squad to see a pop-up with a bunch more stats, tabbed into defensive and offensive data.

And at any point you can use a hotkey (or the buttons at the top of the screen) to toggle from this ‘previous battle overlay’ to your placed deployment for your next attempt at a battle. This makes it SO MUCH EASIER to look at your deployment and work out what went wrong and why, and correct it for the next battle. It is also persistent saved-to-disk data, so you can come back to a failed mission months later and still see the battle stats from your last attempt.

I know the games development keeps taking longer and longer but its definitely getting to be a lot better as a result, and I would rather ship a great game late than a not-as-great game on time. Thanks for your patience, and for following its development! Since I took that screenshot, I have had a MUCH better idea for how to make that screen even better, and I’m working on that now. This means even more work, but its going to be awesome.