Design patterns for curating NPC

There must be a less verbose way to summarize what I’m describing, but in essence I’m trying to work out how to implement the behavior you see in virtually any RPG whereby which an NPC’s state will change as you interact with them. A fairly standard use case would be something like the following:

Bob the Villager can be found in his village every day, and when spoken to he’ll produce the same piece of dialogue. However, after the player completes some arbitrary benchmark like finishing a story quest, Bob will get a new dialogue in which he describes and issues a side quest he needs help with. Once that encounter has occurred, Bob moves from the village to the evil cave until the player finishes his sidequest, at which point he either reverts to his old location in the village or is removed from the world, depending on the outcome of the quest.

I know a lot of games build their own scripting language, and accomplish the above by using the dialogue or some kind of attached delegate that listens for scripted commands to directly inject logic into the game, but building a custom scripting language just for this use case is a pretty hefty chunk of work, and the resulting functionality is still clunky.

So is there an existing design pattern or general approach to accomplish what I’m describing without using an extra scripting language?

Sorry, if I don’t have any examples, but just some terms to narrow down your search:

  • Hardcode behaviour with if and switch statements, directly communicating between components etc.
  • Use a state machine (the AI state machine pattern), where each agent has several states in which he can be at a given point in time and different transitions between them. There are many tutorials on how to build this.
  • Behaviour Trees for more complex AI behaviour, where the amount of states would become unmanageable in a single automaton.

Hmm, thank you for specifying. :slight_smile:

The AI aspect is relatively straightforward, what I’m having trouble with is figuring out a standard way to author and enforce storyline-based changes; things like cued dialogue and location in the world rely heavily on the state of the story and the player’s actions, and it seems like exhaustively checking every possible flag at every juncture would be excessively expensive.

Depending on how extensive dialogue/branching you have, you might consider getting an asset to manage that - forking a little cash to save possibly weeks of dev time is usually worth it, even if you’d need to tweak it here or there.

Is there an existing asset that specifically address the issue of placement/flags? This seems like the sort of thing that shouldn’t be as complicated as I’m making it, if you were willing to brute-force it you could probably just build a giant XML tree and traverse it every time you need to spawn encounters, but my brain keeps bouncing off it when I try to think up a more elegant solution.

I’m pretty sure you could use Dialogue System to track the quest and spawn the actor conditionally in the scenes based on it’s state. It would also help in tracking conversation branching/requirements for the sample quest you’ve mentioned in your original post.

The asset itself has a price tag and requires some learning, but I’d say it should still be easier to use than making from scratch and given the user base of that asset and it’s track record, would save a lot of debugging/design time.

Creator of the asset, @TonyLi , will probably be able to answer if it would solve your issue as one would think that this functionality is common enough to be addressed already. Or maybe give some pointers how you could address what you need.

Hmm okay, thank you for the recommendation :slight_smile:

We’re doing this, and it’s pretty straight-forward:

  • there’s a save system that saves events that has happened. In your example, it’d be something like:
    story_quest_a_finished: true

  • Each dialogue asset has several possible sets of dialogue, each based on the state of the save system. So something like:
    if the story quest is finished:

  • say A, then B, then C
    else if the minor quest is finished

  • say D then B then C
    otherwise

  • say E then F
    This is set up as just a plain C# data structure, and we have a custom editor window where the level designer create these flows based on drop-downs.

  • If we want a character to dissapear from one place and reappear in another place based on the save system, we simply have the character in both scenes, and put scripts on it that destroy the character if the save is in the wrong state when you enter the scene. For your example, there’d a talked_to_bob_after_quest_a event, and if that’s set to true when you enter the city, the Bob version in the city gets destroyed. If you enter the cave and that’s not set to true, cave-Bob gets destroyed.

This is a very simplistic approach, but it works well for our case, where we have relatively few simultaneous “quests”, so it’s somewhat easy to reason about all the possible states of the game world.


I’ve been playing Skyrim lately, and from skimming the wiki, it’s obvious that they’re doing things very differently. Instead of having discrete events, they have quests with sub-objectives. So instead of saving story_quest_a_finished, it’s more of a “story quest A is at stage 3” kind of thing. See an example here.
Skyrim also doesn’t have different versions of an NPC that gets deleted, each NPC only exists at one point. That’s much harder to set up, but you’re guaranteed to not run into duplicate NPCs, which is a bug we’ve run into a few times.

On the other hand, if several Skyrim quests wants to move the same character to different places, I have no idea how they do that in a way that’s easy to reason about. There has to be a priority system, but is it the quest’s responsibility to move an NPC, or an NPC’s responsibility to check the current quests? Both will probably be messy.

The Dialogue System works similarly to the solution that @Baste described for their game, which also includes the critical point that this information must be integrated with your save system. The data has to persist across scene changes and in saved games.

I’ll describe how it works in the Dialogue System in case it can help you implement your own solution. (Or, of course, just use the Dialogue System. ;))

The Dialogue System uses custom assets called dialogue databases that contain conversation, quest, and variable definitions. (Quests can also have sub-objectives called tasks.) At runtime, it’s loaded into the runtime environment. Conversations can change quest states and variable values in the runtime environment. They can also branch to different lines of dialogue based on quest states, variable values, etc.

There’s also a library of trigger components that can change the runtime environment (quest states, variables, etc.) when things happen during gameplay, such as the player entering a trigger collider or a GameObject getting disabled or destroyed.

Another set of components save and load state information from the Dialogue System’s runtime environment. For example, the Persistent Position Data component records a GameObject’s position into the runtime environment when saving a game or leaving a scene. When loading a game or re-entering a scene, the component retrieves the position from the runtime environment and applies it to the GameObject. Most devs also do what Baste described by keeping a copy of a scene-jumping NPC in each scene. They use the Persistent Active Data component to activate or deactivate the NPC in the current scene based on information recorded in the runtime environment.

(As an aside, I should add that the Dialogue System does provide a Lua scripting environment under the hood, but it’s entirely optional to use it.)