Avoid these game programming mistakes. Part 1.

January 30, 2023
Last modified: January 31, 2023

Avatar

Juan M. Fornos Co-founder

Game Designer & Programmer


Introduction

Update: fixed typos

I’ve decided to write this blog post with the intension of helping other game programmers to write better code. Programming is a lifelong endeavour, and there’s always something to improve. We learn by doing, and by doing we make mistakes. The important thing is to learn from them.

This post also works as a personal catarsis, because I’ve seen all kinds horrors 😱 during these years.

Just to be clear, by mindful that this post is informal and covers pretty basic stuff. There’s plenty of academic literature covering these concepts.

It's fine

Mistake #1: Duplicating code

I have seen this one many more times than I would have liked. In code from junior to senior programmers, in amateur and professional games. Duplicated code is a sign that code design could be improved.

Imagine what happens if you need to change that duplicated code, for example, for some of the following reasons (which happen frequently):

  • the requirements change
  • the code need some tweaking
  • you need to add some logic
  • a bug is found

You’ve guessed. You have to change each duplication of the code. Assuming you actually find all the repetitions, in addition to being time consuming, this could lead to bugs in the actual process of replacing the code.

At the very least, and the following is not usually the best solution, put that code in a global function or equivalent (static method, Singleton, etc.).

Mistake #2: Using conditionals to handle behaviors that depend on states

When some behavior changes depend on a state, I usually find code written like this:

void Do() {
    if(this.state == "State1") {
        // behavior 1
    }
    else if(this.state == "State2") {
        // behavior 2
    }
}

This is hard to mantain and to reuse:

  • To add a new behavior, you have add an extra “else if”.
  • If you have another method where the behaviors changes depending on the state, the ifs statements are duplicated for each method.
  • Eventually the code gets so big is unmanageable.
  • Forget to reuse the code elsewhere!

Instead you could abstract the behavior, for example with inheritance, using an interface or abstract class. Something like this:

interface IBehavior {
    void Do();
}

class Behavior1 : IBehavior {
    public void Do() {
        // behavior 1
    }
}

class Behavior2 : IBehavior {
    public void Do() {
        // behavior 2
    }
}

And then instead of having lots of ifs, you just have this:

// this instance is set somehow depending on the state
IBehavior behavior;

void Do {
    this.behavior.Do();
}

Adding a new behavior is as simple as writing a new implementation. This is much easier to mantain and reuse.

This not only works for “game states” or “player states”. Concepts where you can apply this idea (usually with design patters like Strategy, Abstract Factory, Service Locator, etc.):

  • Modes (for example difficulty modes or a read only UI that also has some editing capabilities)
  • Platform specific code
  • Services like cloud save, analytics, ADS, IAPs, etc.

Usually, when you write a bunch of ifs, you can replace them with an some kind of abstraction. A bunch of ifs is a sign that the code design could be improved. This issue is even worse when each behavior depends on other code like an API:

// the horror 😱
void SendAnalyaticsEvent(string event, string data) {
    if(this.service == "AnalyticsService1") {
        // send data using AnalyticsService1 API
    }
    else if(this.service == "AnalyticsService2") {
        // send data using AnalyticsService2 API
    }
}

As usual, abstracting “states” with inheritance is a tradeoff that should be analyzed. Depending the situation, using ifs could be preferred.

Takeaways

  • Duplicated code is a sign that code design could be improved: centralize that code somehow.
  • A bunch of ifs to model behavior that depends on a state is a sign that the code design could be improved: abstract the behaviors, for example using an interface or an abstract class.

What’s next

Following parts will cover concepts like:

  • Misusing inheritance
  • Hardcoding
  • Coupling
  • Design Patterns

See you on part 2!

Get in touch

hoot@wiseshards.com

Jobs


Sign up for our newsletter to hear about our projects and secrets!

Sign me up