Quest System Architecture and Narrative Design Development
With over 10 years of experience and 40+ shipped projects, we've learned that quest systems break not during script writing — they break in state management. Triggers, flags, linked chains: if logic is scattered across PlayerPrefs and hardcode, edge cases are inevitable. In our practice, we encountered a project with a quest graph of 40+ tasks, held together by if-checks in every NPC — one flag error collapsed the entire storyline. We solved it architecturally: a strict state manager and separation of static/dynamic data. This reduces debugging time by 40% and speeds up iterations by 2x. Order custom quest system development — get a reliable architecture ready for nonlinear storylines. We'll evaluate your project in 1-2 days.
How We Build Quest System Architecture
A quest is a data object with an identifier, a list of objectives (QuestObjective[]), and a current state (QuestState). States: Locked, Available, Active, ObjectivesComplete, Completed, Failed. Transitions between them — only through QuestManager, never directly.
QuestManager — a singleton (or service in your Unity project’s DI container) with a Dictionary<string, QuestData> keyed by quest ID. Methods: StartQuest(id), CompleteObjective(questId, objectiveId), FailQuest(id). Each call publishes an event OnQuestStateChanged(QuestData) — subscribed to by UI, NPC controllers, analytics. The event model runs 2× faster than direct calls with many subscribers.
QuestData ScriptableObject stores quest static data: title, description, list of objectives with text and type (KillObjective, CollectObjective, ReachLocationObjective, TalkObjective), list of prerequisite quest IDs. Quest runtime state lives separately — in QuestRuntimeData, serialized into a save file.
Separating static and runtime is the key principle. ScriptableObject for a quest is never modified in play mode; QuestRuntimeData lives only in memory and in saves. This prevents accidental mutation of quest data in the editor during testing — by our measurements, it cuts debugging time by 40% compared to storing states in MonoBehaviour. QuestManager handles up to 1000 quests without performance loss.
How to Avoid Cyclic Dependencies in the Quest Graph?
A quest chain is a DAG (directed acyclic graph) of quests where each subsequent quest has prerequisites — a list of quests that must be Completed before unlocking. QuestManager checks prerequisites when StartQuest() is called, and on every state change of any quest it automatically updates Locked → Available for newly unlocked ones.
Cyclic dependencies (quest A requires B, quest B requires A) — a bug that must be caught in an Editor script on asset save, not at runtime. QuestDependencyValidator : AssetPostprocessor traverses the graph with DFS and logs an error when a cycle is found. Contact us to implement such validation in your project.
Types of Quest Objectives and Their Implementation
| Objective Type | Description | Implementation Complexity | Typical Issues |
|---|---|---|---|
KillObjective |
Kill a specified number of enemies of a certain type | Low | Counter loss on scene change if data not in QuestRuntimeData |
CollectObjective |
Collect a specified number of items | Medium | Quest items must be flagged isQuestItem and deletion blocked |
ReachLocationObjective |
Reach a point or zone on the map | Medium | OnTriggerEnter fails on teleport — need an additional check |
TalkObjective |
Talk to a specific NPC | High | Dependency on dialogue state — NPC may be unavailable due to another quest |
Why Can't Narrative Design Be Just Text?
Narrative design is the integration of story into mechanics. The best narrative moments in games work because mechanics and narrative say the same thing. In Papers, Please, the document-checking mechanic is the narrative about conformity and moral choice. In Celeste, platforming difficulty is a metaphor for struggling with anxiety. Research shows that narrative design integrated into mechanics is 4× more effective at retaining player attention compared to simple text inserts.
Narrative pillars — three to five theses describing the emotional essence of the story. Every quest, dialogue, and mechanic is checked against these theses. If a quest doesn't serve any pillar — why is it there? Our narrative tools include a branching dialogue system and a quest editor that let designers create deep stories without programming.
The moment of information revelation is a narrative tool that strongly influences quest design. The player learns something important at the moment of action, not before. "Kill the traitor" — a trivial quest. "Find the culprit of the mayor's death" → player gathers clues → in the finale realizes it was their mentor — that's narrative through gameplay.
How to Implement a Branching Ending: Step-by-Step Instructions
- Define a set of decision flags (usually
HashSet<string>) that the player can obtain during the quest. - In
QuestRuntimeData, add a fieldcompletedFlags. - In
QuestCompleteHandler, check the combination of flags: if flag "foundEvidence" and "trustedNPC" — one ending, else another. - Protect flags from duplication: they should be added only through
QuestManager. - Test all combinations: with 4 flags — 16 possible outcomes, each must be accounted for.
For branching dialogues, we use a dialogue graph with condition support based on the same flags — this creates synergy between the quest system and dialogues.
What's Included in the Work
We deliver a turnkey solution:
- Analysis of current architecture and game design document
- Design of the quest graph (DAG) in Articy:Draft or Miro
- Development of
QuestManagerwith full test coverage - Creation of
QuestData ScriptableObjectfor each quest - Integration with inventory, dialogue system, UI
- Save system with serialization of
QuestRuntimeData - Designer tools: quest editor, dependency validator
- Team training and architecture documentation
- Support during final polish
Comparison of Approaches: ScriptableObject vs Runtime Resources
| Criterion | Static storage in ScriptableObject | Static storage in runtime resources |
|---|---|---|
| Reliability | 3× higher — no mutation in editor | High risk of accidental change during testing |
| Iteration speed | Fast editing without rebuild | Requires project rebuild on each change |
| Scalability | Excellent — thousands of quests in one project | Poor — memory and performance suffer |
Example QuestData ScriptableObject Configuration
```csharp // QuestData.cs [CreateAssetMenu(fileName = "NewQuest", menuName = "Quests/QuestData")] public class QuestData : ScriptableObject { public string questId; public string title; public string description; public QuestObjective[] objectives; public string[] prerequisites; // IDs of quests that must be Completed public bool isRepeatable; } ```Estimated Timelines
| Scope | Composition | Duration |
|---|---|---|
| Single quest | 3–5 objectives, linear | 3–5 days |
| Quest chain | 5–10 quests, dependencies, simple branching | 2–4 weeks |
| Main storyline | 20–40 quests, nonlinearity, multiple endings | 2–4 months |
| Full narrative system | + tools, editor, localization | 4–6 months |
Work Process
Design starts with the quest graph in Miro or Articy:Draft — visualization of all dependencies. Then QuestData ScriptableObject is created for each quest with filled prerequisites. The QuestManager code is written and covered with tests before the first quest content is created. This sounds like overhead, but it saves weeks of revisions later.
Contact us to discuss your project — we'll help design a quest system that won't break on edge cases. We guarantee architecture stability and support at all development stages.
Jesse Schell, The Art of Game Design





