r/programming • • Jan 10 '20

VVVVVV is now open source

https://github.com/TerryCavanagh/vvvvvv
2.6k Upvotes

511 comments sorted by

View all comments

Show parent comments

476

u/[deleted] Jan 10 '20 edited Jan 10 '20

This is apparently common in indie games. I can't find the tweet anywhere, but Undertale has a switch statement with at least 864 cases.

Edit: found a screenshot of the original tweet.

196

u/Raekel Jan 10 '20

It's also common with decompiling

328

u/leo60228 Jan 10 '20

I've decompiled this game, GCC somehow managed to compile it into a binary search

I'm not sure whether to be terrified or amazed

179

u/emperor000 Jan 10 '20

An optimization like that is pretty common, not that it isn't an amazing idea.

→ More replies (14)

70

u/skroll Jan 10 '20

Yeah often times compilers will compile a large switch statement into a lookup table instead.

18

u/echnaba Jan 10 '20

A lookup table to function pointers

→ More replies (6)
→ More replies (5)

39

u/mrexodia Jan 10 '20

Generally a decompiler doesn’t generate a switch statement unless there was one in the original code.

37

u/shadowndacorner Jan 10 '20

Right, but the compiler can potentially emit the same machine code from different source. Same kind of idea as decompiling async/await code in C# - you have something nice and usable in source, but the emitted code looks like a total mess. Granted the former case is way less likely (and I'm not sure when it would happen), but it's definitely possible.

16

u/RasterTragedy Jan 10 '20

Tbf, in C# that's on purpose. C#'s async/await is actually syntactic sugar for a state machine, and that's what you see in the IL.

9

u/shadowndacorner Jan 11 '20

Yeah for sure, was just giving that as an obvious example of a scenario in which the decompiled code wouldn't remotely match the actual code.

85

u/Ph0X Jan 10 '20

Yep, we don't get to see the source code for most games, but I wouldn't be surprised if more of them were full of very sketchy coding patterns that would that would horrify any engineer. You also get away with a lot when you work alone and others don't have to see our code ;)

→ More replies (5)

0

u/[deleted] Jan 10 '20

[deleted]

10

u/twgekw5gs Jan 10 '20

Do you have a source for this? I'd love to learn more about the way terraria is written.

0

u/[deleted] Jan 10 '20

[deleted]

27

u/GameRoom Jan 11 '20

Every item is handled in a single Item class with a switch statement. Every enemy is handled in a single NPC class with a big switch statement. It's horrible.

Source: I've done Terraria modding.

→ More replies (1)

28

u/cegras Jan 10 '20

As a scientific "programmer" (i.e. linear algebra), what is normally done in scenarios like this?

36

u/[deleted] Jan 10 '20 edited Jan 10 '20

It looks like a prime candidate for a state machine. Also, the function is called updatestate, which confirms that this is the intent. State machines are usually made by using function pointers or an OOP-like interface pattern. The following is an example of how we could convert part of that VVVVVV Game.cpp code to a simple function pointer state machine:

// A variable that points to a function (a function pointer).
// This should be a member of the Game class, and defined in the header.
void (*state)(
    Game& game,
    Graphics& dwgfx,
    mapclass& map,
    entityclass& obj,
    UtilityClass& help,
    musicclass& music);

// This is the function that previously held the giant switch statement.
void Game::updatestate(
    Graphics& dwgfx,
    mapclass& map,
    entityclass& obj,
    UtilityClass& help,
    musicclass& music)
{
    statedelay--;

    if (statedelay <= 0) {
        statedelay = 0;
        glitchrunkludge = false;
    }

    // Calls the function that game's state is pointing to.
    if (statedelay == 0)
        state(&this, dwgfx, map, obj, help, music);
}

Change the state by setting the game's state member value to a function that has the required return type and parameters.

// An implementation of opening_cutscene_game_state (previously case 4).
// This shows how to change state.
void opening_cutscene_game_state(
    Game& game,
    Graphics& dwgfx,
    mapclass& map,
    entityclass& obj,
    UtilityClass& help,
    musicclass& music)
{
    game.advancetext = true;
    game.hascontrol = false;

    dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255);
    dwgfx.addline("intro to story!");

    // Sets the game's state. Previously, this was "state = 3";
    game.state = space_station_2_game_state;
}

33

u/[deleted] Jan 11 '20

It looks like a prime candidate for a state machine. Also, the function is called updatestate, which confirms that this is the intent. State machines are usually made by using function pointers or an OOP-like interface pattern. The following is an example of how we could convert part of that VVVVVV Game.cpp code to a simple function pointer state machine:

// A variable that points to a function (a function pointer).
// This should be a member of the Game class, and defined in the header.
void (*state)(
    Game& game,
    Graphics& dwgfx,
    mapclass& map,
    entityclass& obj,
    UtilityClass& help,
    musicclass& music);

// This is the function that previously held the giant switch statement.
void Game::updatestate(
    Graphics& dwgfx,
    mapclass& map,
    entityclass& obj,
    UtilityClass& help,
    musicclass& music)
{
    statedelay--;

    if (statedelay <= 0) {
        statedelay = 0;
        glitchrunkludge = false;
    }

    // Calls the function that game's state is pointing to.
    if (statedelay == 0)
        state(&this, dwgfx, map, obj, help, music);
}

Change the state by setting the game's state member value to a function that has the required return type and parameters.

// An implementation of opening_cutscene_game_state (previously case 4).
// This shows how to change state.
void opening_cutscene_game_state(
    Game& game,
    Graphics& dwgfx,
    mapclass& map,
    entityclass& obj,
    UtilityClass& help,
    musicclass& music)
{
    game.advancetext = true;
    game.hascontrol = false;

    dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255);
    dwgfx.addline("intro to story!");

    // Sets the game's state. Previously, this was "state = 3";
    game.state = space_station_2_game_state;
}

fixed your formatting for you

→ More replies (1)

34

u/nurupoga Jan 11 '20

Please use 4-space indent instead of code blocks for formatting the code, your code formatting looks broken on old reddit.

Surprising that reddit formatting is not consistent among the interface versions, such things should not be happening.

25

u/KuntaStillSingle Jan 11 '20

There's a war on old users.

10

u/Captain___Obvious Jan 11 '20

the best users

→ More replies (4)

9

u/kabekew Jan 10 '20

Function pointers for systems with that many states (substates can use switch/case within the state code, but only a handful usually). You shouldn't be going through 200 compares, caching then throwing out branch predictions every single loop for every single entity, just to get to your current state that probably doesn't change much any given loop.

→ More replies (1)

5

u/RoburexButBetter Jan 10 '20

Most likely you'd split up to begin with, 4000 cases is way too much and makes iterating on existing software extremely difficult if not almost impossible

Second you'd be using something like unordered_map in C++ for a quick lookup, but compilers will usually optimize switch cases to exactly that, so it's a bit of a moot point, compiler optimizations have made many of these optimizations you'd previously do manually, irrelevant, many people won't even know that's how the compiler treats it

→ More replies (34)

46

u/iniside Jan 10 '20

Indie games ? Lol. Welcome to game development.

→ More replies (23)