Branching paths.

Started by
8 comments, last by Bigfatmeany 10 years, 1 month ago

I want to handle a story-line completely based off of branching selections. I.e selections you make affects others. Is there a better way to handle different paths, and disabling events that could happen in other paths if you select a different path, other than tons and tons of if statements?

Advertisement
Is there a better way to handle different paths ... other than tons and tons of if statements?

The amount of condition checks is given by the story and amount of branches. In the end you need to check as many conditions as are needed to drive the story. However, the question is how often particular conditions are checked and whether or nor they are checked needlessly.

If you implement the conditionals in a fat hard-coded program structure you are on the wrong way for sure. If you have a graph, where each story fragment is represented by its own node, and each node manages the possible transitions to other fragment nodes, then you are able to identify the current fragment and hence the current story branch and the currently possible transitions by investigating the node object referred to by the current value of the "story advance" pointer.

If you further make the story fragments and transitions abstract enough that they need not be coded individually, you get to the point where the story is data driven. The bunch of if statements, if you wish to say so, is then hidden in interpreting the condition describing data of the current story fragment.

Nicely said haegarr.

Bigfatmeany, have a look at this quest system thread for a few more design ideas:

http://www.gamedev.net/topic/652095-help-on-how-to-implement-stories-and-quests-on-an-rpg/

- Eck

EckTech Games - Games and Unity Assets I'm working on
Still Flying - My GameDev journal
The Shilwulf Dynasty - Campaign notes for my Rogue Trader RPG

Is there a better way to handle different paths ... other than tons and tons of if statements?

The amount of condition checks is given by the story and amount of branches. In the end you need to check as many conditions as are needed to drive the story. However, the question is how often particular conditions are checked and whether or nor they are checked needlessly.

If you implement the conditionals in a fat hard-coded program structure you are on the wrong way for sure. If you have a graph, where each story fragment is represented by its own node, and each node manages the possible transitions to other fragment nodes, then you are able to identify the current fragment and hence the current story branch and the currently possible transitions by investigating the node object referred to by the current value of the "story advance" pointer.

If you further make the story fragments and transitions abstract enough that they need not be coded individually, you get to the point where the story is data driven. The bunch of if statements, if you wish to say so, is then hidden in interpreting the condition describing data of the current story fragment.

So what your saying, is to make a value for the advancement in story, and as different things happen, set that value to a different number that will then be checked and then whatever path matches that value will be played? That way I wouldn't even be causes unnecessary events to happen. Im just making sure I understood what you said.

Nicely said haegarr.

Bigfatmeany, have a look at this quest system thread for a few more design ideas:

http://www.gamedev.net/topic/652095-help-on-how-to-implement-stories-and-quests-on-an-rpg/

- Eck

Thanks for this, this gave me some insight, and amazingly enough is applying more than I would though, I guess I could count these events as quests, and make them randomly generated if I find it necessary, or it seems stale to play more than once, as I will need some replay-ability to get my overall goal across.

I think the best way to handle branching paths is bottle-nosing story lines.

Basically what I mean is that, one of the most annoying thing when you have a story is that you have all these options and none of it matters or is taken into account in these other places, so what you'll get is places where you'll have a character, but they aren't in the scene or they are just doing/saying non-important things. So what you want are branching paths that bottle-nose so that all the choices you have made so far are considered. saved, and then branched out to the area that has all those things taken into account. Of course to do this, any branching path or side quest that changes the state of your story significantly becomes locked at the bottle nose.

Choose your own adventures books do this save for what they do is that any option you take is completely nullified by the bottle-nose point so it doesn't really matter what you've chosen, you'll be in same condition entering the bottle-nose.

A lot of games pretend like they have branching paths and other options, but when you look at them they are either just choosing between one set path and another or remaining on the same path with little aesthetic things being different, but nothing major really changes.

But all that said it depends on your game what method you really want to use...there's no point in doing the whole bottle nose thing if you're make something like DMC or God of War.


So what your saying, is to make a value for the advancement in story, and as different things happen, set that value to a different number that will then be checked and then whatever path matches that value will be played? That way I wouldn't even be causes unnecessary events to happen. Im just making sure I understood what you said.

Not exactly. I say that an address (be it an index, a pointer to an object, or something else) refers to the current fragment. Within the current fragment a couple of transitions is stored. Each transition is guarded by a condition. If a condition is evaluated to true, it is taken. A transition refers to the following fragment. If a transition is taken then the address mentioned at the beginning is set to the following fragment as referred by the transition. This is in fact the structure of a typical state machine. The advantage is that you need to check only those conditions that are stored with the one fragment currently addressed. These are probably only very few.


So what your saying, is to make a value for the advancement in story, and as different things happen, set that value to a different number that will then be checked and then whatever path matches that value will be played? That way I wouldn't even be causes unnecessary events to happen. Im just making sure I understood what you said.

Not exactly. I say that an address (be it an index, a pointer to an object, or something else) refers to the current fragment. Within the current fragment a couple of transitions is stored. Each transition is guarded by a condition. If a condition is evaluated to true, it is taken. A transition refers to the following fragment. If a transition is taken then the address mentioned at the beginning is set to the following fragment as referred by the transition. This is in fact the structure of a typical state machine. The advantage is that you need to check only those conditions that are stored with the one fragment currently addressed. These are probably only very few.

Im unsure why, but I'm having an hard time grasping this. Are you saying that I could use something like a switch statement, And when the player is at a part with a choice, simply use a switch statement to see what the player picks, and then the switch statement will tell the code what function to run, and just ignores everything else? If there is something external of the website that explains what you are talking about in a bit more detail that you could link me to it would be wonderful.

Since we don't know any specifics about your game, or the types of things you're wanting to change based on player decisions, it's tough to give more specific advice.

I'll come up with an example that will hopefully help you wrap your head around the general concept. If not, give us some specifics about your game, the decisions, and the repercussions.

Let's say there's a town that's having trouble with goblins in a nearby forest. And the player has to decide whether to help or not. The problems start out with caravans being hit which increases prices in this town 10%. And there will be goblin random encounters when in the "nearby forest" area so long as this problem exists.

You're correct to think that there is a better way instead of one mega-if-else-switch statement. Though technically doable, it would quickly become a nightmare to maintain.

Let's come up with a few classes for this.

StoryEventNode - Something that happens in our game.

Transition - A way to get from one StoryEventNode to the next. Could be a dialog choice, a quest completion, a quest failiure, an npc death, time delay, etc.

Consequence - Something that affects the game world.

So in our story graph, we're at the StoryEventNode (Goblins near Arcadia). It has a list of Consequences in it, so we apply those Consequence to the game world when we "visit" the node. Arcadia.MerchantPriceModifier += 10%, and the area HauntedWoods needs to add goblins to its random encounter table.

There are two main options here. The player helps, or the player doesn't. There can be a Transition here tied to GoblinKing_01's death. Killing the king kills off the goblin presence here. Prices go back to normal, and you stop finding them on your random encounter table of the HauntedWoods. On the other side of things, if the GoblinKing_01 is still alive for a week's time, the problem worsens. A nearby fishing village is burned to the ground, the goblins get tougher, and start showing up in a nearby dungeon's random encounter table.

Those "Transitions" (or triggers, or decisions) would hook into our game logic as a listener. And once they happened, we'd go to the next StoryEventNode on our list. If the player goes out and kills GoblinKing_01, we visit our (Goblins removed from Arcadia) StoryEventNode and apply its consequences (the prices return back to normal, and we take our Goblin random encounter(s) out of the HauntedWoods. If the player dilly-dallies for a week, we Transition to the corresponding StoryEventNode (Goblins overrun BubblingSprings) and apply its consequences, we destroy the fishing village and every NPC in it, level up our goblins, add "fish" to their random loot table, and put some Goblin random encounter(s) in the nearby dungeon area.

You need to take a little bit of time to see what you'd like to be dynamic in your game world. In this example, I wanted to affect town prices and random encounters. So my Town class would need a variable like merchantPriceModifier. And my RandomEncounterTable class would need to expose a way to change the table out entirely or add more entries to it. In this way, we have data driven these features and it's only a matter of adjusting the data when visiting our StoryEventNodes.

I hope this helps clear things up a bit. If not, give us some specific details about your game, and maybe we can get a little more specific with an answer. :)

- Eck

EckTech Games - Games and Unity Assets I'm working on
Still Flying - My GameDev journal
The Shilwulf Dynasty - Campaign notes for my Rogue Trader RPG

Since we don't know any specifics about your game, or the types of things you're wanting to change based on player decisions, it's tough to give more specific advice.

I'll come up with an example that will hopefully help you wrap your head around the general concept. If not, give us some specifics about your game, the decisions, and the repercussions.

Let's say there's a town that's having trouble with goblins in a nearby forest. And the player has to decide whether to help or not. The problems start out with caravans being hit which increases prices in this town 10%. And there will be goblin random encounters when in the "nearby forest" area so long as this problem exists.

You're correct to think that there is a better way instead of one mega-if-else-switch statement. Though technically doable, it would quickly become a nightmare to maintain.

Let's come up with a few classes for this.

StoryEventNode - Something that happens in our game.

Transition - A way to get from one StoryEventNode to the next. Could be a dialog choice, a quest completion, a quest failiure, an npc death, time delay, etc.

Consequence - Something that affects the game world.

So in our story graph, we're at the StoryEventNode (Goblins near Arcadia). It has a list of Consequences in it, so we apply those Consequence to the game world when we "visit" the node. Arcadia.MerchantPriceModifier += 10%, and the area HauntedWoods needs to add goblins to its random encounter table.

There are two main options here. The player helps, or the player doesn't. There can be a Transition here tied to GoblinKing_01's death. Killing the king kills off the goblin presence here. Prices go back to normal, and you stop finding them on your random encounter table of the HauntedWoods. On the other side of things, if the GoblinKing_01 is still alive for a week's time, the problem worsens. A nearby fishing village is burned to the ground, the goblins get tougher, and start showing up in a nearby dungeon's random encounter table.

Those "Transitions" (or triggers, or decisions) would hook into our game logic as a listener. And once they happened, we'd go to the next StoryEventNode on our list. If the player goes out and kills GoblinKing_01, we visit our (Goblins removed from Arcadia) StoryEventNode and apply its consequences (the prices return back to normal, and we take our Goblin random encounter(s) out of the HauntedWoods. If the player dilly-dallies for a week, we Transition to the corresponding StoryEventNode (Goblins overrun BubblingSprings) and apply its consequences, we destroy the fishing village and every NPC in it, level up our goblins, add "fish" to their random loot table, and put some Goblin random encounter(s) in the nearby dungeon area.

You need to take a little bit of time to see what you'd like to be dynamic in your game world. In this example, I wanted to affect town prices and random encounters. So my Town class would need a variable like merchantPriceModifier. And my RandomEncounterTable class would need to expose a way to change the table out entirely or add more entries to it. In this way, we have data driven these features and it's only a matter of adjusting the data when visiting our StoryEventNodes.

I hope this helps clear things up a bit. If not, give us some specific details about your game, and maybe we can get a little more specific with an answer. smile.png

- Eck

Think of my game kinda like persona where you have different social links, and you can either accept peoples invites to go do stuff, or you can not, but if you do accept an invite, you have to spend the entire time with them, and you miss out on everything else. This is what I want to achieve, However I want this to affect events that are avaliable in the future as well. also if I havn't said so already, I'm writing in C++.

This topic is closed to new replies.

Advertisement