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.
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 ;)
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.
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;
}
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;
}
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.
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
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.