Quest System Tutorial

Build a comprehensive quest system with objectives, rewards, and visual editor tools.

Quest System Overview

The quest system provides a flexible framework for creating engaging missions and objectives that drive player progression.

📋 Quest Types

Multiple quest types: Kill, Collect, Deliver, Interact, and more

🎯 Objectives

Multi-step objectives with progress tracking and completion states

🎁 Rewards

Flexible reward system supporting XP, gold, items, and custom rewards

🔧 Editor Tools

Visual quest editor for easy creation and management

Quest Data Structure

Step 1: Quest ScriptableObject

Create the core quest data structure:

1[CreateAssetMenu(fileName = "New Quest", menuName = "RPG/Quest")]
2"keyword">public "keyword">class Quest : ScriptableObject
3{
4 [Header("Basic Info")]
5 "keyword">public "keyword">string questId;
6 "keyword">public "keyword">string questName;
7 [TextArea(3, 5)]
8 "keyword">public "keyword">string description;
9 "keyword">public QuestType questType;
10
11 [Header("Requirements")]
12 "keyword">public "keyword">int levelRequirement = 1;
13 "keyword">public Quest[] prerequisiteQuests;
14
15 [Header("Objectives")]
16 "keyword">public QuestObjective[] objectives;
17
18 [Header("Rewards")]
19 "keyword">public Reward[] rewards;
20
21 [Header("Settings")]
22 "keyword">public "keyword">bool autoComplete = false;
23 "keyword">public "keyword">bool canAbandon = true;
24 "keyword">public "keyword">float timeLimit = 0f; "comment">// 0 = no limit
25
26 [Header("Dialogue")]
27 "keyword">public DialogueTree introDialogue;
28 "keyword">public DialogueTree progressDialogue;
29 "keyword">public DialogueTree completionDialogue;
30
31 "comment">// Runtime data
32 [System.NonSerialized]
33 "keyword">public QuestState currentState = QuestState.NotStarted;
34 [System.NonSerialized]
35 "keyword">public "keyword">float startTime;
36
37 "keyword">public "keyword">void Initialize()
38 {
39 currentState = QuestState.NotStarted;
40
41 "comment">// Initialize all objectives
42 "keyword">foreach (var objective in objectives)
43 {
44 objective.currentProgress = 0;
45 objective.isCompleted = false;
46 }
47 }
48
49 "keyword">public "keyword">void StartQuest()
50 {
51 currentState = QuestState.InProgress;
52 startTime = Time.time;
53
54 Debug.Log($"Started quest: {questName}");
55 }
56
57 "keyword">public "keyword">bool IsCompleted()
58 {
59 "keyword">return System.Array.TrueForAll(objectives, obj => obj.isCompleted);
60 }
61
62 "keyword">public "keyword">float GetCompletionPercentage()
63 {
64 "keyword">if (objectives.Length == 0) "keyword">return 0f;
65
66 "keyword">int completedObjectives = System.Array.FindAll(objectives, obj => obj.isCompleted).Length;
67 "keyword">return ("keyword">float)completedObjectives / objectives.Length;
68 }
69
70 "keyword">public "keyword">string GetQuestGiver()
71 {
72 "comment">// Find NPC that gives "keyword">this quest
73 var npcs = FindObjectsOfType<NPC>();
74 "keyword">foreach (var npc in npcs)
75 {
76 "keyword">if (npc.questToGive == "keyword">this)
77 "keyword">return npc.npcName;
78 }
79 "keyword">return "Unknown";
80 }
81}
82
83"keyword">public "keyword">enum QuestType
84{
85 Main,
86 Side,
87 Daily,
88 Repeatable,
89 Hidden
90}
91
92"keyword">public "keyword">enum QuestState
93{
94 NotStarted,
95 Available,
96 InProgress,
97 Completed,
98 Failed,
99 Abandoned
100}

Step 2: Quest Objectives

Define the objective system:

1[System.Serializable]
2"keyword">public "keyword">class QuestObjective
3{
4 [Header("Objective Info")]
5 "keyword">public "keyword">string id;
6 "keyword">public "keyword">string description;
7 "keyword">public ObjectiveType type;
8
9 [Header("Target")]
10 "keyword">public "keyword">string targetId; "comment">// Enemy ID, Item ID, NPC name, etc.
11 "keyword">public "keyword">string targetNPC; "comment">// For delivery/interaction quests
12 "keyword">public Vector3 targetLocation; "comment">// For location-based objectives
13
14 [Header("Progress")]
15 "keyword">public "keyword">int targetProgress = 1;
16 "keyword">public "keyword">int currentProgress = 0;
17 "keyword">public "keyword">bool isCompleted = false;
18
19 [Header("Optional")]
20 "keyword">public "keyword">bool isOptional = false;
21 "keyword">public "keyword">bool showInUI = true;
22
23 "keyword">public "keyword">string GetProgressText()
24 {
25 "keyword">if (type == ObjectiveType.Reach || type == ObjectiveType.Interact)
26 {
27 "keyword">return isCompleted ? "✓ " + description : description;
28 }
29
30 "keyword">return $"{description} ({currentProgress}/{targetProgress})";
31 }
32
33 "keyword">public "keyword">void UpdateProgress("keyword">int amount = 1)
34 {
35 "keyword">if (isCompleted) "keyword">return;
36
37 currentProgress = Mathf.Min(currentProgress + amount, targetProgress);
38
39 "keyword">if (currentProgress >= targetProgress)
40 {
41 isCompleted = true;
42 }
43 }
44}
45
46"keyword">public "keyword">enum ObjectiveType
47{
48 Kill, "comment">// Kill X enemies
49 Collect, "comment">// Collect X items
50 Deliver, "comment">// Deliver item to NPC
51 Interact, "comment">// Talk to NPC
52 Reach, "comment">// Reach location
53 Escort, "comment">// Escort NPC
54 Defend, "comment">// Defend location/NPC
55 Craft, "comment">// Craft X items
56 Custom "comment">// Custom objective
57}
58
59[System.Serializable]
60"keyword">public "keyword">class Reward
61{
62 "keyword">public RewardType type;
63 "keyword">public "keyword">int amount;
64 "keyword">public Item item; "comment">// For item rewards
65
66 "keyword">public "keyword">void GiveReward()
67 {
68 switch (type)
69 {
70 case RewardType.Experience:
71 GameManager.Instance.playerStats.GainExperience(amount);
72 break;
73
74 case RewardType.Gold:
75 InventoryManager.Instance.AddGold(amount);
76 break;
77
78 case RewardType.Item:
79 "keyword">if (item != null)
80 InventoryManager.Instance.AddItem(item, amount);
81 break;
82 }
83 }
84}
85
86"keyword">public "keyword">enum RewardType
87{
88 Experience,
89 Gold,
90 Item,
91 Reputation,
92 Skill
93}

Quest Manager

Core Quest Management

Implement the quest management system:

1"keyword">public "keyword">class QuestManager : MonoBehaviour
2{
3 "keyword">public "keyword">static QuestManager Instance { get; "keyword">private set; }
4
5 [Header("Quest Collections")]
6 "keyword">public List<Quest> availableQuests = "keyword">new List<Quest>();
7 "keyword">public List<Quest> activeQuests = "keyword">new List<Quest>();
8 "keyword">public List<Quest> completedQuests = "keyword">new List<Quest>();
9
10 [Header("Settings")]
11 "keyword">public "keyword">int maxActiveQuests = 10;
12 "keyword">public "keyword">bool showQuestNotifications = true;
13
14 "comment">// Events
15 "keyword">public System.Action<Quest> OnQuestStarted;
16 "keyword">public System.Action<Quest> OnQuestCompleted;
17 "keyword">public System.Action<Quest, QuestObjective> OnObjectiveCompleted;
18 "keyword">public System.Action<Quest> OnQuestFailed;
19
20 "keyword">void Awake()
21 {
22 "keyword">if (Instance == null)
23 {
24 Instance = "keyword">this;
25 DontDestroyOnLoad(gameObject);
26 }
27 "keyword">else
28 {
29 Destroy(gameObject);
30 }
31 }
32
33 "keyword">void Start()
34 {
35 InitializeQuests();
36 }
37
38 "keyword">void InitializeQuests()
39 {
40 "comment">// Initialize all quests
41 "keyword">foreach (var quest in availableQuests)
42 {
43 quest.Initialize();
44 }
45
46 Debug.Log($"Initialized {availableQuests.Count} quests");
47 }
48
49 "keyword">public "keyword">bool StartQuest(Quest quest)
50 {
51 "keyword">if (quest == null) "keyword">return false;
52 "keyword">if (activeQuests.Count >= maxActiveQuests) "keyword">return false;
53 "keyword">if (activeQuests.Contains(quest)) "keyword">return false;
54 "keyword">if (completedQuests.Contains(quest) && quest.questType != QuestType.Repeatable) "keyword">return false;
55
56 "comment">// Check prerequisites
57 "keyword">if (!ArePrerequisitesMet(quest))
58 {
59 Debug.Log($"Prerequisites not met ">for quest: {quest.questName}");
60 "keyword">return false;
61 }
62
63 "comment">// Check level requirement
64 "keyword">if (GameManager.Instance.GetPlayerLevel() < quest.levelRequirement)
65 {
66 Debug.Log($"Player level too low ">for quest: {quest.questName}");
67 "keyword">return false;
68 }
69
70 "comment">// Start the quest
71 activeQuests.Add(quest);
72 quest.StartQuest();
73
74 "comment">// Show notification
75 "keyword">if (showQuestNotifications && UIManager.Instance != null)
76 {
77 UIManager.Instance.ShowQuestNotification("Quest Started", quest.questName);
78 }
79
80 OnQuestStarted?.Invoke(quest);
81
82 Debug.Log($"Quest started: {quest.questName}");
83 "keyword">return true;
84 }
85
86 "keyword">public "keyword">void CompleteQuest(Quest quest)
87 {
88 "keyword">if (!activeQuests.Contains(quest)) "keyword">return;
89
90 activeQuests.Remove(quest);
91
92 "comment">// Only add to completed "keyword">if not repeatable
93 "keyword">if (quest.questType != QuestType.Repeatable)
94 {
95 completedQuests.Add(quest);
96 }
97 "keyword">else
98 {
99 "comment">// Reset repeatable quest
100 quest.Initialize();
101 }
102
103 quest.currentState = QuestState.Completed;
104
105 "comment">// Give rewards
106 GiveQuestRewards(quest);
107
108 "comment">// Show notification
109 "keyword">if (showQuestNotifications && UIManager.Instance != null)
110 {
111 UIManager.Instance.ShowQuestNotification("Quest Completed", quest.questName);
112 }
113
114 OnQuestCompleted?.Invoke(quest);
115
116 Debug.Log($"Quest completed: {quest.questName}");
117
118 "comment">// Check "keyword">for newly available quests
119 CheckUnlockedQuests();
120 }
121
122 "keyword">public "keyword">void UpdateObjective("keyword">string objectiveId, "keyword">int progress = 1)
123 {
124 "keyword">foreach (var quest in activeQuests.ToList())
125 {
126 "keyword">foreach (var objective in quest.objectives)
127 {
128 "keyword">if (objective.id == objectiveId && !objective.isCompleted)
129 {
130 "keyword">int oldProgress = objective.currentProgress;
131 objective.UpdateProgress(progress);
132
133 "keyword">if (objective.isCompleted && oldProgress < objective.targetProgress)
134 {
135 OnObjectiveCompleted?.Invoke(quest, objective);
136
137 "keyword">if (showQuestNotifications && UIManager.Instance != null)
138 {
139 UIManager.Instance.ShowObjectiveNotification(objective.description);
140 }
141
142 Debug.Log($"Objective completed: {objective.description}");
143 }
144
145 "comment">// Check "keyword">if quest is completed
146 "keyword">if (quest.IsCompleted())
147 {
148 "keyword">if (quest.autoComplete)
149 {
150 CompleteQuest(quest);
151 }
152 "keyword">else
153 {
154 quest.currentState = QuestState.Completed;
155 Debug.Log($"Quest ready to turn in: {quest.questName}");
156 }
157 }
158
159 break;
160 }
161 }
162 }
163 }
164
165 "keyword">public "keyword">void TurnInQuest("keyword">string questId)
166 {
167 var quest = activeQuests.Find(q => q.questId == questId);
168 "keyword">if (quest != null && quest.IsCompleted())
169 {
170 CompleteQuest(quest);
171 }
172 }
173
174 "keyword">public "keyword">void AbandonQuest(Quest quest)
175 {
176 "keyword">if (!activeQuests.Contains(quest) || !quest.canAbandon) "keyword">return;
177
178 activeQuests.Remove(quest);
179 quest.currentState = QuestState.Abandoned;
180 quest.Initialize(); "comment">// Reset progress
181
182 Debug.Log($"Quest abandoned: {quest.questName}");
183 }
184
185 "keyword">bool ArePrerequisitesMet(Quest quest)
186 {
187 "keyword">if (quest.prerequisiteQuests == null || quest.prerequisiteQuests.Length == 0)
188 "keyword">return true;
189
190 "keyword">foreach (var prerequisite in quest.prerequisiteQuests)
191 {
192 "keyword">if (!completedQuests.Contains(prerequisite))
193 "keyword">return false;
194 }
195
196 "keyword">return true;
197 }
198
199 "keyword">void GiveQuestRewards(Quest quest)
200 {
201 "keyword">foreach (var reward in quest.rewards)
202 {
203 reward.GiveReward();
204
205 "comment">// Show reward notification
206 "keyword">if (showQuestNotifications && UIManager.Instance != null)
207 {
208 "keyword">string rewardText = GetRewardText(reward);
209 UIManager.Instance.ShowRewardNotification(rewardText);
210 }
211 }
212 }
213
214 "keyword">string GetRewardText(Reward reward)
215 {
216 switch (reward.type)
217 {
218 case RewardType.Experience:
219 "keyword">return $"Gained {reward.amount} XP";
220 case RewardType.Gold:
221 "keyword">return $"Received {reward.amount} gold";
222 case RewardType.Item:
223 "keyword">return $"Received {reward.item.itemName}";
224 default:
225 "keyword">return "Reward received";
226 }
227 }
228
229 "keyword">void CheckUnlockedQuests()
230 {
231 "keyword">foreach (var quest in availableQuests)
232 {
233 "keyword">if (quest.currentState == QuestState.NotStarted && ArePrerequisitesMet(quest))
234 {
235 quest.currentState = QuestState.Available;
236 Debug.Log($"Quest now available: {quest.questName}");
237 }
238 }
239 }
240
241 "comment">// Public getters
242 "keyword">public Quest[] GetActiveQuests() => activeQuests.ToArray();
243 "keyword">public Quest[] GetCompletedQuests() => completedQuests.ToArray();
244 "keyword">public "keyword">bool IsQuestActive("keyword">string questId) => activeQuests.Any(q => q.questId == questId);
245 "keyword">public "keyword">bool IsQuestCompleted("keyword">string questId) => completedQuests.Any(q => q.questId == questId);
246 "keyword">public "keyword">bool CanCompleteQuest(Quest quest) => quest != null && quest.IsCompleted();
247 "keyword">public "keyword">bool HasActiveQuest() => activeQuests.Count > 0;
248
249 "keyword">public Quest GetQuestById("keyword">string questId)
250 {
251 "keyword">return availableQuests.Concat(activeQuests).Concat(completedQuests)
252 .FirstOrDefault(q => q.questId == questId);
253 }
254}

Objective Tracking

Objective Handlers

Create systems to automatically track quest objectives:

1"keyword">public "keyword">class QuestObjectiveTracker : MonoBehaviour
2{
3 "keyword">void Start()
4 {
5 "comment">// Subscribe to game events
6 "keyword">if (GameManager.Instance != null)
7 {
8 GameManager.Instance.OnEnemyKilled += OnEnemyKilled;
9 GameManager.Instance.OnItemCollected += OnItemCollected;
10 GameManager.Instance.OnLocationReached += OnLocationReached;
11 }
12
13 "keyword">if (InventoryManager.Instance != null)
14 {
15 InventoryManager.Instance.OnItemAdded += OnItemAdded;
16 }
17 }
18
19 "keyword">void OnDestroy()
20 {
21 "comment">// Unsubscribe from events
22 "keyword">if (GameManager.Instance != null)
23 {
24 GameManager.Instance.OnEnemyKilled -= OnEnemyKilled;
25 GameManager.Instance.OnItemCollected -= OnItemCollected;
26 GameManager.Instance.OnLocationReached -= OnLocationReached;
27 }
28
29 "keyword">if (InventoryManager.Instance != null)
30 {
31 InventoryManager.Instance.OnItemAdded -= OnItemAdded;
32 }
33 }
34
35 "keyword">void OnEnemyKilled(Enemy enemy)
36 {
37 "comment">// Track kill objectives
38 "keyword">string enemyId = enemy.enemyId;
39 QuestManager.Instance.UpdateObjective($"kill_{enemyId}");
40 QuestManager.Instance.UpdateObjective("kill_any");
41 }
42
43 "keyword">void OnItemCollected(Item item, "keyword">int quantity)
44 {
45 "comment">// Track collection objectives
46 "keyword">string itemId = item.itemId;
47 QuestManager.Instance.UpdateObjective($"collect_{itemId}", quantity);
48 }
49
50 "keyword">void OnItemAdded(Item item, "keyword">int quantity)
51 {
52 "comment">// Track when items are added to inventory
53 OnItemCollected(item, quantity);
54 }
55
56 "keyword">void OnLocationReached("keyword">string locationId)
57 {
58 "comment">// Track location objectives
59 QuestManager.Instance.UpdateObjective($"reach_{locationId}");
60 }
61
62 "keyword">public "keyword">void OnNPCInteraction(NPC npc)
63 {
64 "comment">// Track interaction objectives
65 QuestManager.Instance.UpdateObjective($"talk_{npc.npcName}");
66 QuestManager.Instance.UpdateObjective("talk_any");
67 }
68
69 "keyword">public "keyword">void OnItemDelivered(Item item, NPC npc)
70 {
71 "comment">// Track delivery objectives
72 QuestManager.Instance.UpdateObjective($"deliver_{item.itemId}_to_{npc.npcName}");
73 }
74
75 "keyword">public "keyword">void OnItemCrafted(Item item, "keyword">int quantity)
76 {
77 "comment">// Track crafting objectives
78 QuestManager.Instance.UpdateObjective($"craft_{item.itemId}", quantity);
79 }
80}
81
82"comment">// Quest trigger "keyword">for specific locations
83"keyword">public "keyword">class QuestTrigger : MonoBehaviour
84{
85 [Header("Trigger Settings")]
86 "keyword">public "keyword">string triggerId;
87 "keyword">public TriggerType triggerType;
88 "keyword">public "keyword">bool triggerOnce = true;
89
90 [Header("Quest Actions")]
91 "keyword">public Quest questToStart;
92 "keyword">public "keyword">string objectiveToUpdate;
93
94 "keyword">private "keyword">bool hasTriggered = false;
95
96 "keyword">void OnTriggerEnter2D(Collider2D other)
97 {
98 "keyword">if (hasTriggered && triggerOnce) "keyword">return;
99
100 "keyword">if (other.CompareTag("Player"))
101 {
102 ExecuteTrigger();
103 }
104 }
105
106 "keyword">void ExecuteTrigger()
107 {
108 hasTriggered = true;
109
110 switch (triggerType)
111 {
112 case TriggerType.StartQuest:
113 "keyword">if (questToStart != null)
114 QuestManager.Instance.StartQuest(questToStart);
115 break;
116
117 case TriggerType.UpdateObjective:
118 "keyword">if (!"keyword">string.IsNullOrEmpty(objectiveToUpdate))
119 QuestManager.Instance.UpdateObjective(objectiveToUpdate);
120 break;
121
122 case TriggerType.ReachLocation:
123 QuestManager.Instance.UpdateObjective($"reach_{triggerId}");
124 break;
125 }
126 }
127}
128
129"keyword">public "keyword">enum TriggerType
130{
131 StartQuest,
132 UpdateObjective,
133 ReachLocation
134}

Rewards System

Flexible Reward System

Implement a comprehensive reward system:

1[System.Serializable]
2"keyword">public "keyword">class QuestReward
3{
4 [Header("Basic Reward")]
5 "keyword">public RewardType type;
6 "keyword">public "keyword">int amount;
7 "keyword">public Item item;
8
9 [Header("Advanced Options")]
10 "keyword">public "keyword">bool isOptional = false;
11 "keyword">public "keyword">string customRewardId;
12 "keyword">public AnimationCurve scalingCurve = AnimationCurve.Linear(0, 1, 1, 1);
13
14 [Header("Conditions")]
15 "keyword">public RewardCondition[] conditions;
16
17 "keyword">public "keyword">bool CanGiveReward()
18 {
19 "keyword">if (conditions == null) "keyword">return true;
20
21 "keyword">foreach (var condition in conditions)
22 {
23 "keyword">if (!EvaluateCondition(condition))
24 "keyword">return false;
25 }
26
27 "keyword">return true;
28 }
29
30 "keyword">bool EvaluateCondition(RewardCondition condition)
31 {
32 switch (condition.type)
33 {
34 case ConditionType.PlayerLevel:
35 "keyword">return GameManager.Instance.GetPlayerLevel() >= condition.value;
36 case ConditionType.QuestCompletion:
37 "keyword">return QuestManager.Instance.IsQuestCompleted(condition.stringValue);
38 default:
39 "keyword">return true;
40 }
41 }
42
43 "keyword">public "keyword">void GiveReward()
44 {
45 "keyword">if (!CanGiveReward()) "keyword">return;
46
47 "keyword">int scaledAmount = Mathf.RoundToInt(amount * GetScalingMultiplier());
48
49 switch (type)
50 {
51 case RewardType.Experience:
52 GameManager.Instance.playerStats.GainExperience(scaledAmount);
53 ShowRewardFeedback($"Gained {scaledAmount} XP!");
54 break;
55
56 case RewardType.Gold:
57 InventoryManager.Instance.AddGold(scaledAmount);
58 ShowRewardFeedback($"Received {scaledAmount} gold!");
59 break;
60
61 case RewardType.Item:
62 "keyword">if (item != null)
63 {
64 InventoryManager.Instance.AddItem(item, scaledAmount);
65 ShowRewardFeedback($"Received {item.itemName} x{scaledAmount}!");
66 }
67 break;
68
69 case RewardType.Reputation:
70 "comment">// Handle reputation system
71 break;
72
73 case RewardType.Custom:
74 HandleCustomReward();
75 break;
76 }
77 }
78
79 "keyword">float GetScalingMultiplier()
80 {
81 "keyword">int playerLevel = GameManager.Instance.GetPlayerLevel();
82 "keyword">return scalingCurve.Evaluate(playerLevel / 100f);
83 }
84
85 "keyword">void HandleCustomReward()
86 {
87 "comment">// Handle custom rewards based on ID
88 switch (customRewardId)
89 {
90 case "unlock_shop":
91 "comment">// Unlock special shop
92 break;
93 case "fast_travel":
94 "comment">// Unlock fast travel point
95 break;
96 }
97 }
98
99 "keyword">void ShowRewardFeedback("keyword">string message)
100 {
101 "keyword">if (UIManager.Instance != null)
102 {
103 UIManager.Instance.ShowFloatingText(
104 GameManager.Instance.GetPlayer().transform.position,
105 message,
106 Color.yellow
107 );
108 }
109 }
110}
111
112[System.Serializable]
113"keyword">public "keyword">class RewardCondition
114{
115 "keyword">public ConditionType type;
116 "keyword">public "keyword">int value;
117 "keyword">public "keyword">string stringValue;
118}
119
120"keyword">public "keyword">enum ConditionType
121{
122 PlayerLevel,
123 QuestCompletion,
124 HasItem,
125 Custom
126}

Quest Editor Tool

Custom Editor Window

The quest editor provides a visual interface for creating and managing quests:

Editor Features:

  • Visual quest creation and editing
  • Drag-and-drop objective management
  • Real-time validation and error checking
  • Reward configuration interface
  • Prerequisite quest linking
  • Quick quest testing tools

Using the Quest Editor:

  1. Access: Go to RPG Tools → Quest Editor in Unity menu
  2. Create: Click "Create New Quest" to make a new quest asset
  3. Edit: Select existing quest in the object field to edit
  4. Objectives: Use "Add Objective" button to create quest objectives
  5. Rewards: Use "Add Reward" button to configure quest rewards
  6. Save: Changes are automatically saved to the quest asset

Quest Creation Workflow:

1
Define Quest

Set name, description, and type

2
Add Objectives

Create objectives with targets and progress

3
Set Rewards

Configure XP, gold, and item rewards

4
Link Prerequisites

Set quest dependencies and requirements

NPC Integration

Connecting Quests to NPCs

Link your quest system with NPCs for seamless quest giving:

1"comment">// Add to NPC "keyword">class "keyword">for quest integration
2"keyword">public "keyword">class NPCQuestHandler : MonoBehaviour
3{
4 [Header("Quest Management")]
5 "keyword">public Quest[] availableQuests;
6 "keyword">public Quest currentQuest;
7 "keyword">public "keyword">bool hasGivenQuest = false;
8
9 "keyword">public "keyword">void CheckQuestAvailability()
10 {
11 "keyword">if (currentQuest != null && !hasGivenQuest)
12 {
13 "comment">// Check "keyword">if player can receive "keyword">this quest
14 "keyword">if (CanGiveQuest(currentQuest))
15 {
16 ShowQuestAvailableIndicator();
17 }
18 }
19 "keyword">else "keyword">if (HasQuestToTurnIn())
20 {
21 ShowQuestCompleteIndicator();
22 }
23 }
24
25 "keyword">bool CanGiveQuest(Quest quest)
26 {
27 "keyword">return QuestManager.Instance != null &&
28 !QuestManager.Instance.IsQuestActive(quest.questId) &&
29 !QuestManager.Instance.IsQuestCompleted(quest.questId);
30 }
31
32 "keyword">bool HasQuestToTurnIn()
33 {
34 var activeQuests = QuestManager.Instance.GetActiveQuests();
35 "keyword">foreach (var quest in activeQuests)
36 {
37 "keyword">if (quest.GetQuestGiver() == GetComponent<NPC>().npcName && quest.IsCompleted())
38 {
39 "keyword">return true;
40 }
41 }
42 "keyword">return false;
43 }
44
45 "keyword">public "keyword">void GiveQuest()
46 {
47 "keyword">if (currentQuest != null && CanGiveQuest(currentQuest))
48 {
49 "keyword">if (QuestManager.Instance.StartQuest(currentQuest))
50 {
51 hasGivenQuest = true;
52 HideQuestAvailableIndicator();
53
54 "comment">// Play quest give animation/sound
55 PlayQuestGiveEffects();
56 }
57 }
58 }
59
60 "keyword">public "keyword">void CompleteQuest()
61 {
62 var activeQuests = QuestManager.Instance.GetActiveQuests();
63 "keyword">foreach (var quest in activeQuests)
64 {
65 "keyword">if (quest.GetQuestGiver() == GetComponent<NPC>().npcName && quest.IsCompleted())
66 {
67 QuestManager.Instance.TurnInQuest(quest.questId);
68 HideQuestCompleteIndicator();
69 break;
70 }
71 }
72 }
73
74 "keyword">void ShowQuestAvailableIndicator()
75 {
76 "comment">// Show exclamation mark or similar indicator
77 var indicator = transform.Find("QuestAvailableIndicator");
78 "keyword">if (indicator != null)
79 indicator.gameObject.SetActive(true);
80 }
81
82 "keyword">void ShowQuestCompleteIndicator()
83 {
84 "comment">// Show question mark or similar indicator
85 var indicator = transform.Find("QuestCompleteIndicator");
86 "keyword">if (indicator != null)
87 indicator.gameObject.SetActive(true);
88 }
89
90 "keyword">void HideQuestAvailableIndicator()
91 {
92 var indicator = transform.Find("QuestAvailableIndicator");
93 "keyword">if (indicator != null)
94 indicator.gameObject.SetActive(false);
95 }
96
97 "keyword">void HideQuestCompleteIndicator()
98 {
99 var indicator = transform.Find("QuestCompleteIndicator");
100 "keyword">if (indicator != null)
101 indicator.gameObject.SetActive(false);
102 }
103
104 "keyword">void PlayQuestGiveEffects()
105 {
106 "comment">// Play sound effect
107 AudioManager.Instance?.PlaySFX("QuestGive", transform);
108
109 "comment">// Play animation
110 var animator = GetComponent<Animator>();
111 "keyword">if (animator != null)
112 animator.SetTrigger("GiveQuest");
113 }
114}
115
116"comment">// Quest UI integration example
117"keyword">public "keyword">class QuestUIHandler : MonoBehaviour
118{
119 [Header("UI References")]
120 "keyword">public GameObject questPanelPrefab;
121 "keyword">public Transform questListParent;
122
123 "keyword">void Start()
124 {
125 "comment">// Subscribe to quest events
126 "keyword">if (QuestManager.Instance != null)
127 {
128 QuestManager.Instance.OnQuestStarted += OnQuestStarted;
129 QuestManager.Instance.OnQuestCompleted += OnQuestCompleted;
130 QuestManager.Instance.OnObjectiveCompleted += OnObjectiveCompleted;
131 }
132 }
133
134 "keyword">void OnQuestStarted(Quest quest)
135 {
136 "comment">// Create UI panel "keyword">for "keyword">new quest
137 "keyword">if (questPanelPrefab != null && questListParent != null)
138 {
139 var questPanel = Instantiate(questPanelPrefab, questListParent);
140 var questUI = questPanel.GetComponent<QuestUIPanel>();
141 "keyword">if (questUI != null)
142 questUI.SetupQuest(quest);
143 }
144 }
145
146 "keyword">void OnQuestCompleted(Quest quest)
147 {
148 "comment">// Update UI or remove quest panel
149 Debug.Log($"Quest completed UI update: {quest.questName}");
150 }
151
152 "keyword">void OnObjectiveCompleted(Quest quest, QuestObjective objective)
153 {
154 "comment">// Update objective UI
155 Debug.Log($"Objective completed UI update: {objective.description}");
156 }
157}

Quest Design Best Practices

📝 Quest Design

  • Write clear, engaging quest descriptions
  • Create meaningful objectives that advance the story
  • Balance difficulty with appropriate rewards
  • Use varied objective types to maintain interest

🔄 Progression Flow

  • Design logical quest chains and prerequisites
  • Provide clear feedback on objective progress
  • Implement auto-completion for simple objectives
  • Allow quest abandonment when appropriate

🎁 Reward Balance

  • Scale rewards with quest difficulty and time
  • Mix different reward types (XP, items, story)
  • Consider player progression curves
  • Provide meaningful non-combat rewards

🔧 Technical Tips

  • Use unique IDs for all quests and objectives
  • Implement save/load for quest progress
  • Test quest chains thoroughly
  • Optimize objective tracking performance

Common Quest Patterns

Kill Quest

kill_goblin

Objective: Kill 5 goblins in the forest

Collection Quest

collect_herbs

Objective: Collect 10 healing herbs

Delivery Quest

deliver_letter_to_mayor

Objective: Deliver letter to Mayor Johnson

Exploration Quest

reach_ancient_ruins

Objective: Reach the ancient ruins

Continue Learning

Explore related tutorials to expand your knowledge