2
\$\begingroup\$

I am creating an rpg. So far I've used a global game stage as well as individual npc stages (increased when completing a quest for example) to control the "stage" the game is in. I.e if I have a log blocking a road, If game stage is > 10 then the log should not be there anymore.

This worked fine for basics but I want more control. And was considering a system with flags. For example a static class with booleans like "isLogRemoved", that I can use on top of stages to get more control. Plus it would be easy to save/load.

Before I make my own system along these lines I wanted to ask you more experienced people if there is a "proper" approach to this problem. Take a game like Zelda for example, where there are so many things that act differently depending on the stage (or state) of other objects in the world. Does anyone have a clue what a system like that looks like or how it works?

Hope I'm making sense. Having a hard time formulating this one.

\$\endgroup\$
3
\$\begingroup\$

While I can't speak to any game specifically, my first instinct would be to approach this using a graph. It sounds like something you have started doing, by your use of "stages", though maybe only linearly.

For anyone unfamiliar with graphs as a mathematical and programming concept: https://en.wikipedia.org/wiki/Graph_theory
https://en.wikipedia.org/wiki/Directed_graph

Conceptually, each node in your graph could have a set of flags like you were thinking. And each edge is some condition of the current game state.

To use an example from Zelda Link to the Past, you're supposed to collect all three pendants before being able to carry on. And for each pendants you collect, it should no longer be shown on the map as a current objective.

So we have 4 nodes in our graph of this simplified example:

  • A: New Game
  • B: Has Pendant 1
  • C: Has Pendant 2
  • D: Has Pendant 3
  • E: Has All 3 Pendants

Then we create our edges between the states, with the conditions for moving along that edge.

  • A -> B requires getting Pendant 1
  • A -> C requires getting Pendant 2
  • A -> D requires getting Pendant 3

  • B -> E requires getting All Pendant
  • C -> E requires getting All Pendant
  • D -> E requires getting All Pendant

Simple image of proposed graph

So with this, we have a branching structure, allowing the player to get the pendants in any order. But they won't reach the final state E without getting all pendants.

Then we attach our flags to each state:

A:

  • isPendant1Showing = true
  • isPendant2Showing = true
  • isPendant3Showing = true
  • canProgress = false

B:

  • isPendant1Showing = false

C:

  • isPendant2Showing = false

D:

  • isPendant3Showing = false

E:

  • canProgress = true

To figure out then what state our game is:

  • Start at A
  • Set flags as they are in A
  • Evaluate each connection
  • If condition is true evaluate the connected node the same way, overwriting any flags

For save files then you just need to save the data that is relevant to the conditions for the edges.

For added complexity to a game, this method can be applied recursively or to individual elements of the game. The condition for an edge could be based on the result of another graph. Or the graph could exist per NPC, and the conditions are based only on the state of a specific NPC. Programming wise, I'd recommend that any graphs that are identical (same states, same conditions, same flags) exist once, and you simply pass the NPC to the graph to get a list of flags back.

\$\endgroup\$
  • \$\begingroup\$ I'll try to put together a graphic for this when I can. \$\endgroup\$ – Chris Sep 8 '17 at 12:32
  • \$\begingroup\$ Maybe I'm missing something but couldn't you just represent this as can_progress = isPendant1Showing && isPendant2Showing && isPendant3Showing;? A graph/flowchart is a fine way to conceptualize a condition like this but I'm less sure it's a good way to represent it in code. Another way to put it is the Abstract syntax tree of your program is already a graph, (trees are a subset of graphs) so use that if you can. A graph representation might be the right answer for more complicated conditions though I suppose. \$\endgroup\$ – Ryan1729 Sep 8 '17 at 19:14
  • \$\begingroup\$ @Ryan1729 right for very simple cases you are essentially building this graph in an if,elseif statement or maybe a switch. However, with the graph you can conceptualize this in design and then implement that way. And with a graph in code, you can more easily change things, add new steps, remove steps, etc. It's also easier to visualize from a graph, which is backed by data and not code. Also, the graph could even be changed at runtime if need be. \$\endgroup\$ – Chris Sep 8 '17 at 19:49
2
\$\begingroup\$

When you just have one integer variable which tells you the current story progress, then you are limited to a completely linear story progression. There is no way to implement branching story routes, multiple objectives which can be completed in any order or optional sidequests.

If you don't need those, you can get away with just one stage-variable. But if you want any of that, then you will need multiple story flags.

One problem you might run into when you use story flags is that you might accidently run into situations where the player runs into a flag combination which doesn't allow them to progress at all. Or that you hide some content behind a flag combination which isn't actually possible to achieve anymore after you reorganized your story a few times. So it is important that you keep track of what story flags you have, where and when they are set and what they are used for. A good way to document this is by drawing a flowchart where you label each arrow with the corresponding story flag.

Many open world RPGs (like the Elder Scrolls or the Mass Effect series) allow story variables to act both as Boolean flags (to check simply if something did or did not happen) or to carry an integer value (like the current stage of a linear sidequest). If you want to keep it simple, you could implement your story variables with an associative array mapping String to Integer.

\$\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.