4
\$\begingroup\$

We're working on a game that's going to be split into three episodes, which we'll release one after another, as they get finished. I'm worried that our typical somewhat-monolithic architecture is not a good fit for this model.

The game code consists of basically three parts:

  • _Engine_: Renderer, physics, UI etc.
  • _Logic_: The concrete scenes and entities.
  • _Scripts_: Levels and dialogs.

_Engine_ and _Logic_ are native code, _Scripts_ are shipped with the game data and executed at runtime.

I think I can safely assume that:

  • _Engine_ will be the same for all episodes.
  • _Logic_ will be largely the same for all episodes. but have some specific parts.
  • _Scripts_ will differ significantly for each episode.

I see three options for organising this:

  1. Create episode two by copying all the code from episode one, adjusting as needed. I believe this is how sequels are typically done; id Tech 4 appears to be part of the "Doom 3" code, not clearly separated.
  2. Keep all the shared code in one place, making it possible for each episode to override parts of it.
  3. Create a reusable engine, completely separating _Engine_ from _Logic_ and _Scripts_, to be used by all episodes. Shared _Logic_ will either be duplicated for each episode, or generalised and moved into _Engine_. This is how the folks behind "Penumbra" apparently did it.

The major drawback I see with the first approach is that I'll have to back-port any fixes and refactoring to episode one, manually.

The major drawbacks I see with the second approach is that it's more upfront work, and that I'll have to make changes to already released episodes, requiring me to keep testing them.

The major issue I have with the third approach is that it's a big amount of upfront work. and smells a bit like premature generalisation. I cannot fully predict what changes I'll have to make for episodes two and three; it depends on their unfinished design. On the other hand, it would probably give us more flexibility, and speed up development, later.

What is the typical way of organising the code for episodic games? Do I have options, other than the three I can think of?

\$\endgroup\$
7
\$\begingroup\$

If you're already putting in solid efforts to abstract engine code from game code, AND you want to keep your various game projects up-to-date with the latest version of the engine, then and only then would I suggest keeping it in a separate repository, since that would make it worth the effort.

Otherwise, if you're only developing a single game, don't worry about doing this till the game has been or is about to be released, i.e. when you have time for it. Until you start writing a second game, you have no guarantee that the code needs to be separated, so it's likely to be a waste of time.

If your goal is to write a game, then you will use your time effectively and focus on that and only that. That is plenty of work as it is, without self-imposing additional concerns.

Whereas if you, for instance, have multiple projects on for clients and wish to use / are using the same engine, then you / your company might make a smart business decision by abstracting out your engine code in every sense (code architecture and version control), ASAP.

It's that simple. Most game developers do what it takes to get a finished game out the door, instead of committing themselves to tasks which may never see any real-world use, such as abstraction of unproven engine code. For triple-A or otherwise fairly extensive episodic games this will be the case, since changes in technology or in game design over time (between one episode and the next) will obsolete many of the original ideas and necessitate an engine rewrite anyway.

Ultimately, apply the Pareto Principle: If you're really very keen on separation, do that small amount of abstraction work that wins you the majority of the abstraction prize. Don't push too hard on separating engine code out, and where it's in question, just leave it and mark is as "for later".

\$\endgroup\$
  • \$\begingroup\$ I'm not sure I've made myself clear: This is an episodic game that consists of 3 different, but highly similar games. I'm not talking about building a generic engine for whatever games I want to make in the future. Anyway, I'll read that as a vote for options 1 or 2 (I can easily start with 1 and develop it into 2 as I go, only 3 needs real upfront effort I think.) \$\endgroup\$ – futlib Jan 3 '14 at 13:14
  • \$\begingroup\$ Reading your answer again, I guess I did make myself clear. So you're saying that episodic AAA games typically approach this just like typical games and sequels, which is my first option above? \$\endgroup\$ – futlib Jan 3 '14 at 13:18
  • \$\begingroup\$ Yes, you'll find that's nearly always the case. Trying to keep your game in sync with engine API changes can be a big time drain. First, write it with the distinction held loosely in mind. Then, get the game mostly complete or well into production (content addition etc. so that you know it all works as required). Then do the final engine abstractions. The elephant in the room is that it's quite difficult to generalise an API with only one use case. So it's best not to invest to much into the abstraction until you are at least into the second game. \$\endgroup\$ – Engineer Jan 3 '14 at 14:30
  • 1
    \$\begingroup\$ That's great to hear, I thought option 1 was too naive and would get me into trouble, but if that's the common approach, I'm happy with it. I'll first finish the first episode then. And you're right, I'd be highly surprised if we wouldn't introduce new mechanics with later episodes. I guess it's not as different from a sequel as I thought. \$\endgroup\$ – futlib Jan 3 '14 at 14:39
  • 1
    \$\begingroup\$ The TL;DR is suppose to be a summary; your TL;DR is larger than the rest of the answer D: (just a nitpick I wanted to point out) \$\endgroup\$ – Gnemlock May 17 '17 at 3:25
2
\$\begingroup\$

Data-driven development is key here!

You don't want to copy any code between episodes, that's just plain terrible and will become a maintenance nightmare.

Instead strive to make your code generic and configurable via data obtained from files that are specific to each episode. You can create each episode from the exact same codebase, only resource files (which includes scripts) should change. If a new episode demands a new code feature, it'll simply be ignored in the older episodes.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.