Blog

Don’t Break the State Machine!

Designing finite state machines requires good discipline and a shift in design paradigm. It’s very easy to “break” a state machine by implementing improper design. It is very tempting to take shortcuts, but it never leads to clean lasting code. In this post, I want to examine (rant on) some tempting pitfalls.

The basic premise for an FSM is: each state updates and states run one at a time, each state has enter and exit logic and has one or more switch conditions to different state(s).

The examples are very simple, just a state enum and a state variable. But the associated issues could equally appear in a similar form in a more complex implementation. Even simple FSM frameworks cannot prevent abuse without unnecessarily restrictive or cumbersome design.

Conditions in State Updates

One of the biggest grievances of state update methods is when they grow new conditions in them:

becomes

This is another state. There should never be branching conditions in a state machine that toggle the state’s actions. If state’s actions are conditional, then those are–by definition–different states. This can also appear as simply as:

Pausable States

Let’s say some state can be suspended:

Again, that’s another state. There is no such thing as “pausing” a state. A paused state is a different state whose logic is to wait until and resume the original state. Pausing a state is the same as adding a condition where one branch is “do nothing”.

External State Changes

While writing a state machine that reacts to external conditions, it’s tempting to simply tell the state machine to change. Even if this method is part of the state machine and the actual state and value are not exposed:

Firstly, this is still external from state machine’s point of view. This bypasses any state switch conditions or logic and introduces a second mechanism to switch states. What the proper state-respectful and error-tolerant way to do this is to set the “desired state” flag:

and somewhere later, when one or more state switch are considered, check this flag in addition to any normal conditions (and reset it when the state is finally switched):

The state value should always be read-only to anyone but the state machine’s state switch code. In other words, there would be only one place in code that assigns the state value.

Manual State Update Code

Each state should run at and only at its designated update time. For a simple example, the essential logic is this:

It is possible to write logic for the states while completely ignoring any state logic separation:

In small doses, this may even make sense (formatted nicely, it looks like good code). But this really just throws the state design out the window. This code cannot be refactored. The whole point of states are to be independent.

Reusing State Values

The simplest state machine is just an enum:

Since it’s an enum, you could manually assign underlying values to it:

And then actually use them for other purposes:

This is breaking single responsibility principle. This is bad because neither the states nor the values can be refactored without affecting the other usage. This is also very forced. Variations include things like label[(int)state].Show() or  animator.state = (int)state;.

Enumerated States

States can require additional persistent data. It could in some cases be encoded in the states themselves:

This has 5 “Floor” states that do exactly the same logic, but for different floor numbers. This mainly breaks “don’t repeat yourself” principle and makes adding new states of changing numbering cumbersome. This should likely be closer to:

It’s still a bit ugly. Depending on how it’s used and the way the state machine is implemented, there are many ways such data can be stored (that I won’t go into).

Modifying State Data

States can have data and–unless we are using a fancy encapsulated framework–this data could likely be just another variable:

It’s important to not touch this variable outside the designated state (and rarely multiple states). It might be tempting to do something like:

This makes assumption about the current state and state specifics. It should be the state that handles this at the appropriate time (if necessary, there should be a separate variable for “next bonus”):

Unknown Initial State

I haven’t added an initial state, such as “None”, to my examples above. In a real system, that can be a dangerous assumption if the system has persistent data and could halt and restart unexpectedly. Consider a forklift:

We may expect the lift to always lower when it is powered off, but what if the power cuts off? In other words, the state machine has to know which state to enter first. It might be tempting to simply add some initial conditions:

Besides assigning state directly, this is also making assumptions about how a state switches/starts. The code is now duplicated for state entry and awaiting many hours of debugging.

Final Thoughts

A lot of issues can be solved simply by using an existing framework. Most frameworks would enforce proper design. Unfortunately, more complex frameworks also have downsides, such as learning curve, reduced performance and increased memory usage or many new classes. Many of these downsides come into play when the application has dozens if not hundreds of state machines. I often find myself needing a quick state machine in a single class and making half a dozen extra classes for a full-blown state machine is hard to justify. So I would use a simple state machine pattern, but one open to abuse without discipline.

State machines are alive and kicking. As with any design pattern, knowing its strengths and weaknesses let’s you choose and use it appropriately. When used correctly, it is a powerful tool that can divide complex timed systems into manageable chunks. FSM is still one of my favorite design patterns.

Posted in Blog | Tagged , , | Leave a comment

Technical Debt and Delivery Times

Today, I want to muse on how new code features take ever-so-longer, specifically, how increasing delivery times are the symptoms of bad code. I’ll focus primarily on recognizing the issue (rather than avoiding or solving it).

The Mystery of Increasing Estimates

Here’s a typical scenario: You are a project manager and you hire a programmer for a new feature set. You request the first core feature. It gets delivered. You request an expanded feature. It gets delivered somewhat late. You request a further expanded feature. It gets delivered way past the deadline. (P.S. every estimate runs twice over.) You panic and have your senior programmer take over. They estimate the next delivery at twice your worst expectations!

So what’s wrong with this picture; how come it’s consistently taking longer? Here’s where the senior programmer shakes their fist grumbling, “is your code clean?” Or did you just add technical debt to the project? It takes an experienced programmer only a moment to spot bad code. Hell, they could spot it from the class outline alone.

Hidden Technical Debt of Estimates

There are two (grossly simplified) time consumers when programming:

Feature and Techical debt bars legend

Features are all the good things you want and it takes time to do. Technical debt is the stuff you don’t want and it takes time to prevent and undo. Features are immediate and highly visible. Debt is expert at hiding and won’t appear straightaway.

Let me illustrate with some example programmers. We are comparing the time it took to implement a working feature versus time unspent it would take to fix the left-over technical debt.

Technical debt versus feature time example

Programmers A and B gave realistic estimates and delivered on time. They left technical debt. They are pretty average cases if you have no oversight by a lead. Programmer A took a bit longer, but ensured a bit less work later. B hurried it a little and left over more stuff to fix.

Programmer C is a rock star programmer and everyone talks about how he delivers in record times. He is on feature #3 already. He changes jobs every 4 months. (He never finds out what happens to the codebase down the line.)

Programmer D had the longest estimate. He left almost no debt. He uses smart programming words. He keeps talking about some religion called “unit testing”.

Lastly, U is the ideal genius programmer. Before you get any ideas, U stands for “unicorn”.

Deceptive Results

This is what the manager looking at the product sees as immediate time invested:

Externally spent time on features

But this is the future time required that a (lead) programmer sees:

Internally expected technical debt time from features

The main point to take from this: it’s not externally obvious if a feature comes with little or a lot of debt. It may appear that programmers and features take roughly the same time or are really productive/slow. Such cases actually also carry hidden costs and benefits. Fast features are never “free”. In contrast, time invested is time saved.

Growing Debt

Okay fine, but we’re on a deadline – we’ll fix it later! So what if the feature is not perfect? Right?

Ignoring technical debt in favour of faster feature time

The reason this is bad long-term is that technical debt bends the rules of math:

Tech debt math - more debt is created than the sum of two

Debt creates debt creates debt creates debt… Not only are individual code parts smelly, but the connections between them start to smell and it leaks into other parts. One hack becomes two hacks just to use the first hack. The very nature of technical debt is that it intertwines and couples code, creating ever-increasing inter-dependencies.

And features don’t exist in vacuum. You cannot make new features without fixing at least some technical debt to keep it from growing exponentially:

Feature time overlap with technical debt and extra time

Or to put it another way, when you encounter unexpected technical debt that needs fixing:

Unexpected technical debt eroding the time from the next feature

An experienced programmer can spot the debt and will adjust their estimate accordingly. An inexperienced programmer won’t and will run over the estimate trying to make their code work. Worst yet, they won’t fix existing debt nor recognize their own debt. In short, your next feature will cost more.

The Cost of “Fixing it Later”

Sure, you can fix it later, it’s not that much. But “later” will arrive sooner than you think. And it will arrive suddenly and irreversibly. Let’s say we only fix the debt that is absolutely critical to making new features. You will see delivery times something like this:

Multiple feature accumulated costs from programmers

A and B started off great, but their estimates and delivery times keep growing and growing. They assure you that they are working exactly as before. Not only that, they are occasionally fixing old code too. You are perplexed, but shrug it off as typical costs of increasing complexity.

C was doing so amazing, but they had to leave after the fourth feature. Perhaps someday you’ll find another one like them! At least you had their photo framed.

D seems to always have exactly the same estimate and delivery. In fact, he seems to suffer no increased delivery time symptoms that A and B have. He must be putting in extra hours or something.

Of course, we know exactly what’s going on:

Multiple feature accumulated technical debt from programmers

A and B have a steadily growing debt. D is managing theirs at a near-constant level. C ran away when they saw the avalanche.

Suddenly D is the most efficient programmer and A and B just cannot get back to how they started. (It may not even be their fault with such tight deadlines.) This is the long-term price of technical debt.

As a side note: of course bad code is hardly the only reason for increasing deadlines. But it’s the biggest reason when it comes to sudden and hard-to-explain delays. Ideally, the feature estimates already include modifying and connecting to the existing code.

Caveats

There is one “upside” to technical debt though: code can only get so bad before it no longer matters:

A lot of technical debt no longer creates new debt

At some point, you can just delete it all and redo, as that’s going to be faster. Hopefully, without repeating the same mistakes.

Secondly, not all technical debt is equal in scope versus time. 80/20 rule can probably be applied to this. 80% of time would be spent fixing 20% of the debt:

20-80 rule for technical debt prevention

So you can deliberately choose to not fix the last 20%. A sufficiently modular and independent code can survive with moderate debt without affecting the rest of the codebase.

Finally, it takes longer to fix someone else’s debt than your own. At least, you yourself know what you hacked together. Can you tell with any confidence what someone else hacked up?

To sum up

Beware short estimates, because they can carry new technical debt. Beware short estimates, because they likely don’t account for existing technical debt.

Get ahead of the programmer. Expect unclean code. Features are only half the work; prepare for the other half.

Technical debt chasing feature cartoon

 

P. S. I hope to also write up a generic “Preventing Technical Debt” post in the future.

Posted in Blog | Tagged , , | 2 Comments

Braille – Ludum Dare Jam entry

I participated in Ludum Dare again and this time with Phil as artist (our entry). The theme was “alone”, which lends itself nicely to all kinds of depressing, scary, atmospheric games. Then again, everyone was doing one. So we made a short Limbo-esque commentary on a little, blind, hospitalized girl’s journey.

The main mechanic of the game is that the girl is blind and you can only “see” via sound from environment, your footsteps, or thrown rocks. The level starts nice and real, although still quite disconcerting. It then slowly turns progressively more twisted as you slowly go through the girl’s inner emotions. May be it was all just a dream? Or may be it was a long-awaited escape?

Software: VS (C# + XNA), Photoshop
Requires: Windows, .NET, XNA, mouse/keyboard (headphones would be nice)

You can download and play it here: http://www.uprootworld.com/Braille.zip

XNA 4 redist: http://www.microsoft.com/download/en/details.aspx?id=20914
.NET 4 redist: http://www.microsoft.com/download/en/details.aspx?id=24872

Update

Phil made a playthrough/commentary track:

We also have a double timelapse here.

Update 2

We got some pretty nice comments on the entry and videos, and we also scored rather high if I should say so myself:
#9/174 — Overall (3.67/5)
#3 — Mood (3.88)
#6 — Theme (3.88)
#9 — Graphics (4.22)
#15 — Innovation (3.39)

Edit: I cannot believe I forgot to click Publish on this blog post after the edit… *facepalm*

Posted in Blog | Leave a comment

Soul Hellscape – Ludum Dare 48 entry

As promised, I entered Ludum Dare 48-hour game making competition and submitted my game, called “Soul Hellscape” (entry here).

In this sandboxy game you help trapped souls by placing your “Holy Light” beam that attracts them and lets you guide them to the Gate of Hell, where they can escape. All while several types of baddies attempt to nibble on the delicious, innocent souls. You can zap them with a “Divine Lightning”. Plus a few more fancy features.

Software: VS (C# + XNA), Photoshop, Maya, sfxr
Requires: Windows, .NET, XNA, mouse/keyboard

You can download and play it here:
http://www.rudythedev.com/SoulHellscape2.zip

XNA 4 redist: http://www.microsoft.com/download/en/details.aspx?id=20914
.NET 4 redist: http://www.microsoft.com/download/en/details.aspx?id=24872

Update

The competition ended. I got some nice and some more… informative comments. :) Overall, I’m pretty glad with how it turned out. Even made a little motivational post about it. The final scores are (I think) above average. — 3.11/5 overall. That’s not in top 50, so *sad face*.

I guess what killed my scores is lack of graphics, lack of quirkiness, lack of nostalgia, complexity and lack of music. I must admit that the target audience is not quite what you would expect. After all, you get rated by the developers themselves. I won’t go into details of what I learned, let’s just say I took a few notes home.

As a rater, I rated 51% of the 599 games, and ended up 5th place on the “coolness” (raters) scale. Yay, me! And shame on those who didn’t rate a single game!

See you in December, Ludum Dare #22!

Posted in Blog | Tagged | Leave a comment

Wow! I haven’t posted for a long time

I really have not posted anything with content for a while now. WordPress even managed to roll out a few updates in the meantime slightly changing the whole interface. I also got about 100 spam comments.

I’m still here, still willing to work on a video game. Note the intentionally indefinite use of “video game”. It won’t take a genius to conclude I may have (temporarily) shelved the actual whatsitname isometric game. Or have I? Well, yes, for the past 3 months I have. Am I on a summer vacation? What silliness, I’m just lazy.

O.K., O.K., I am not that irresponsible. I did actually work a little more on the game itself:

I also went on a separate development “branch” where I had a great idea for a spaceship/AI/sandbox kind of game:

I actually quite like the idea, but I fear the project is too big for me to take it on as the “first” game. I won’t go into details, because I don’t want to accidentally convince myself to do it.

Finally, the vast majority of my time went into a theoretical platform shooter/survival/RPG game. Practically, I made a platformer with a little gameplay:

I’m actually rather proud of this and I see some potential in this (after the fact that half the indie games are platformers). Characters are made of several body parts, that can move independently. There is walking animation, holding and aiming the weapon in all direction, shooting, bullets, flashes and sounds. You can walk, jump, aim. There’s a map editor and some fast collision detection with a k-d node tree. Blah, blah, in short, enough to post some 10 blog posts. But I never did. I don’t know why… oh, wait, yes I do — because I am lazy.

I think this is what the majority of my problems boil down to. Laziness and short attention span. I am considering entering Ludum Dare at the end of August for a 48-hour game creation challenge. (May be if I say this out loud [on paper {in blog} ] I may actually do it.) I never have and this might be fun. May be someone will actually read my blog besides Google Bot, Yahoo Slurp and that third one no one uses.

Anyway, less typing, more coding!

Posted in Blog | Leave a comment

Resource gathering in video games, part 2/6: Physical resources

“Physical” resources are such that some physical object in the game world changes as a direct consequence of the player acquiring the resource. In other words, for an RTS, something in the overworld either appears or disappears. In human terms, if you were in the game you could “touch” either the resource’s source or the resource itself as it was being collected.

Much of the diversity and strategy of RTSes comes from the specific way in which each physical resource is distributed in the game environment; so this is how I will primarily differentiate between physical resources. This entry will discuss how the vast majority of resource types can be grouped using two simple metrics — by the 1) distribution in an area and by the 2) available quantity. Continue reading

Posted in Blog | Leave a comment

Resource gathering in video games, part 1/6: Introduction

In this series of short articles I will discuss resources as they appear in real-time strategy (RTS) and similar video games. Specifically, I am interested in collectable (harvestable, gatherable, acquirable) resources and their implementation from the gameplay perspective. It does not matter if you are mining minerals, chopping trees, or collecting spacenuggets; this is about the method and the fun (or tedium).

But first, let’s do some research in the field. And, surely, there are few better ways to do research than playing video games. Alas, there are hundreds of examples to choose from, and hundreds more exceptions to every rule. Needless to say, redundant or obscure examples or methods I haven’t heard of will be left out.

Continue reading

Posted in Blog | Leave a comment

Blog (re)Launch

I have been meaning to upgrade my Blog for quite some time now; and I have finally done so. I switched from my own code to a WordPress blog framework. After some time playing with themes, CSS, and source files, I got it looking almost like the old version. To be honest, I’m not even sure how one could get around anything past the basic features without at least a rudimentary knowledge of CSS.

So, in memoriam, here is the previous version’s screenshot:

Not much of a visual difference! The real upgrade lies in the back-end features that I really want — categories, tags, proper comment system, administration panel, media, RSS, etc. I could make a long, detailed list of why a ready-made approach is better than building this myself; but I’ll just say the benefits far outweight the few downsides. This may be obvious to most, but I have always notoriously done things myself — from ground-up, without using existing templates or frameworks. I have re-invented so many metaphorical wheels, I’m a borderline programming masochist.

I have considered posting Development Diary entries less frequently, instead making them higher quality — better writing, clearer details, informative graphics. But I decided against it, and instead split the blog into “Blog” and “DevDiary”. You see, I rarely proof-read or change anything in the DevDiary; as I often type it last thing before being done for the day. In contrast, I want to have a different approach to the “main” Blog, and post coherent, decently written entries over several days on thoughts and topics not necessarily relevant to my game.

Posted in Blog | Leave a comment