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:
- Access: Go to
RPG Tools → Quest Editorin Unity menu - Create: Click "Create New Quest" to make a new quest asset
- Edit: Select existing quest in the object field to edit
- Objectives: Use "Add Objective" button to create quest objectives
- Rewards: Use "Add Reward" button to configure quest rewards
- Save: Changes are automatically saved to the quest asset
Quest Creation Workflow:
Define Quest
Set name, description, and type
Add Objectives
Create objectives with targets and progress
Set Rewards
Configure XP, gold, and item rewards
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