Archive for June, 2009

Illustrating Farmlands

June 20, 2009

I’ve been experimenting with the look of cultivated areas today. I’m quite happy with the result so far–it’s much better than the flat yellow surface I use in most places, that’s for sure.

The lines and dots in the fields are all vector data.. Maybe I should use bitmap textures for these things instead? I’m completely inexperienced with vector graphics design work, so I don’t know how people usually handle this kind of stuff.

I also added shadows underneath the tanks, to place them more firmly onto the ground.

screenshot-090620-2

Submarines

June 20, 2009

I took a break from coding and worked a bit on the graphics instead. The map is much bigger now and stretches from the west coast of Denmark to the east coast of Sweden. Here’s a screenshot of a new u-boat outside the German coast:

090620-1

Proactive Air Defense

June 19, 2009

Anti-aircraft units are now much better at defending their area, since they get to shoot first–during the enemy’s turn. Things are a bit confusing now, though, because the chain of events isn’t made manifest to the player. If you lose concentration and accidentally move a plane into the range of an hostile anti-aircraft unit you may be surprised to find your unit suddenly half as strong as it used to be. If you’re really unlucky the whole unit may disappear, with no indication of who fired at it.

In short, this change makes animation a requirement, and not just a feature that would be nice to have. I probably won’t take care of that right now, though.

Automatic Reactions

June 14, 2009

I haven’t completed any new functionality yet, but I’m working on a framework for managing automatic reactions. This is needed by anti-aircraft guns for instance, since they must be able to react immediately to defend their area effectively. Before an attacking plane is allowed to drop any bombs, all air defense units in range will get a chance to shoot it down.

To make this work I need to decouple the request for an action from actually performing the action, so that other units get a chance to intercept. When the user tries to attack an enemy unit, I now send an attack request to an arbiter object running in another (lightweight) thread. The arbiter asks enemy units nearby if they want to counter the action, and schedules the resulting actions. The schedule is then executed and the results broadcasted to everyone who can see them.

These changes not only enable automatic reactions; They also bring me closer to having networked play and fog of war (which refers to the inability to see where all the enemy’s units are).

The Perils of Mutable State

June 7, 2009

A few weeks ago, I spent more than a week debugging parts of a very large software system at work. I will not go into detail about the software, but I want to write down what I learned from it so that I will remember it better, and share my conclusions with you.

Actually, I started thinking about similar problems months earlier when I was writing new code that gradually became much more complicated than I had expected. Why did I end up in a morass of special cases and conditions?

Both problems involved updating the state of several different data structures that had to be kept synchronized. The basic problem was that changes to the data were spread out over many different functions and that early changes could invalidate later changes or affect the control flow in an undesired way by changing the outcome of a conditional branch.

When I was working on the first problem I was writing new code and had free hands when it came to design. After realizing I would have to scrap my first design to make further progress, I decided I would partition the problem into two distinct parts: One would figure out which changes needed to be made and encode them in a class called a ChangeSet; The other would apply the changes. The idea was that it would be easier to debug and understand the algorithm if you could print out the ChangeSet and check invariants before it was applied. This worked well and simplified the code enough that I was able to make progress again.

The other problem had another important ingredient: randomness. The iteration order of several central datastructures (such as sets) is random in our system (a side effect of our generational garbage collector’s decisions) and caused the (very large) algorithm to update the data structures in a different order from one run to another. Most of the time everything worked fine, but every now and then things failed with random symptoms.

It has slowly dawned on me that these two problems were essentially the same: Many changes had to be made to many different data structures, and those very changes could cause the algorithm to trip itself up.

My solution to the first problem (using a ChangeSet) worked well not only because it made following the changes easier, but also because it concentrated all state changes to one phase, letting the first part of the algorithm discover what needed to be done in a temporarily immutable world. I think there is an important and general principle here: Changes to mutable state should be confined to as few points in both space and time as possible. This goes for any language with mutable state. Object-oriented principles do not seem to cover this problem, since hiding the state inside a class does not make the state go away; It is just changed via a method instead.

An interesting parallel is that the solution I described above is similar to what database systems do with transactions, and databases are specialized on managing mutable state in unpredictable environments.