Quest System
A general quest pipeline built from Kill -> Talk -> Collect steps. It tracks progress through gameplay events and works for RPGs, casual games, and mission systems.
Structure
QuestSystem (pure C# instance)
- Manages active quests and routes events
QuestDefinition (ScriptableObject)
- Title, description, rewards
[SerializeReference] List<QuestStep>
QuestInstance (runtime)
- Current step index and completion state
QuestStep (abstract, [Serializable])
├── KillQuestStep - Kill N enemies of a type
├── TalkQuestStep - Talk to a specific NPC
└── CollectQuestStep - Collect N items of a type
Quick Start
1. Create a QuestDefinition
Create -> AchUtils/Quest/Quest Definition
QuestId : "MainQuest_01"
Title : "Slime Hunt"
Steps:
[0] KillQuestStep
EnemyType : "Slime"
RequiredCount : 5
[1] TalkQuestStep
NpcId : "GuardNPC"
[2] CollectQuestStep
ItemId : "SlimeGel"
RequiredCount : 3
Rewards:
[0] QuestReward { RewardId: "Gold", Amount: 500 }
[1] QuestReward { RewardId: "Exp", Amount: 200 }
2. Create a QuestSystem Instance
QuestSystem is a pure C# class that only owns quest state. Create it from the object that owns the quest flow.
3. Start a Quest
using AchUtils.Quest;
private readonly QuestSystem questSystem = new();
[SerializeField] QuestDefinition mainQuest01;
var instance = questSystem.StartQuest(mainQuest01);
instance.OnStepCompleted += step =>
Debug.Log($"Step {step} completed");
instance.OnQuestCompleted += () =>
GiveRewards(mainQuest01.Rewards);
4. Publish Events
Call Progress from anywhere in the game. Every active quest receives the event.
questSystem.Progress("Kill", "Slime");
questSystem.Progress("Talk", "GuardNPC");
questSystem.Progress("Collect", "SlimeGel");
Event Key Rules
| Key | data argument | Step |
|---|---|---|
"Kill" | Enemy type string | KillQuestStep |
"Talk" | NPC ID string | TalkQuestStep |
"Collect" | Item ID string | CollectQuestStep |
API
QuestSystem
QuestInstance StartQuest(QuestDefinition definition)
void Progress(string eventKey, object data = null)
bool IsCompleted(string questId)
bool IsActive(string questId)
QuestInstance GetActive(string questId)
List<QuestInstance> GetAllActive()
event Action<QuestInstance> OnQuestStarted
event Action<QuestInstance> OnQuestCompleted
event Action<QuestInstance, int> OnQuestStepCompleted
QuestInstance
QuestDefinition Definition
int CurrentStepIndex
bool IsCompleted
QuestStep CurrentStep
event Action<int> OnStepCompleted
event Action OnQuestCompleted
Custom Steps
[Serializable]
public class ReachLocationStep : QuestStep
{
public string LocationId;
private bool _reached;
public override bool IsComplete => _reached;
public override void OnProgress(string eventKey, object data)
{
if (eventKey == "ReachLocation" && data is string loc && loc == LocationId)
_reached = true;
}
public override void OnStart() => _reached = false;
}
questSystem.Progress("ReachLocation", "DungeonEntrance");
Duplicate Start Guard
The same QuestId cannot be started twice. Completed quests are not started again.
questSystem.StartQuest(mainQuest01);
questSystem.StartQuest(mainQuest01); // Ignored