Godot – Basic quest system example

Hi everyone, I’ve been working on Cavefish after a (very) long hiatus for personal reasons – I promise I’ll share an update on Cavefish soon enough – but in the meantime, I’ve switched over from Unity to Godot. Unfortunately, Godot still hasn’t got as many assets and tutorials as Unity does. So I’ve decided to share my own internal dev tools with the community.

I’ve been developing a simple quest system for Cavefish. I don’t want quests to be too limiting or too complex, as the game is about freedom of movement and expression.

There’s a link to my Godot Simple Quest System Example at the bottom of this post.

This project creates new quests on demand and updates them on the screen accordingly.
Here are the two scene layouts in the project, QuestSystem is the main UI one whilst QuestBlock is created dynamically for each quest.

QuestBlocks hold all information for each quest, including the quest’s title, objectives and a long description.
QuestSystem adds/removes quests from the container in the main scene. So basically you just call “addQuestBlock(1)” to add Quest 1, or “removeQuestBlock(2) to remove Quest 2.
Easy, right?

Here’s the full code for the QuestSystem.gd:

#QuestSystem.gd
extends Control
var questBlock = preload("res://QuestBlock.tscn")
@onready var questContainer = $VBoxContainer
var currentQuestBlocks
var isQuestPresent = false

func _on_check_button_toggled(toggled_on):
	if toggled_on: #Checks if already present and if not, adds a new quest block
		addQuestBlock(1)
	else: #finds and removes quest block
		removeQuestBlock(1)

func _on_check_button_2_toggled(toggled_on):
	if toggled_on:
		addQuestBlock(2)
	else:
		removeQuestBlock(2)

func _on_check_button_3_toggled(toggled_on):
	if toggled_on:
		addQuestBlock(3)
	else:
		removeQuestBlock(3)

func addQuestBlock(questId:int):
	if !isQuestIdActive(questId): #If this questId doesn't exist, add quest block
		var newQuestBlock = questBlock.instantiate()
		questContainer.add_child(newQuestBlock)
		newQuestBlock.add_Quest_To_List(questId)
		questContainer.queue_sort() #forces a rearrange of the Container

func removeQuestBlock(questId:int):
#Check if this questId is shown. If so, we delete it.
	if isQuestIdActive(questId): #if the quest is present, delete it.
		for questBlockChild in questContainer.get_children():
			if (questBlockChild.questBlockId == questId):
				questBlockChild.queue_free()
				questContainer.queue_sort() #forces a rearrange of the Container

func isQuestIdActive(questId:int):
	isQuestPresent = false #check within each child of Container if this questId exists.
	if (questContainer.get_child_count() != 0): #if there are any child questblocks
		for questBlockChild in questContainer.get_children():
			if (questBlockChild.questBlockId == questId):
				isQuestPresent = true #this questId is already shown so we won't repeat
	return isQuestPresent

…And here’s the code for QuestBlock.gd. This holds all quests and fills in the text fields for each quest. The quest ID is requested by QuestSystem.gd

extends Control

@onready var questBlockId = 0
@onready var questTitleObj = $QuestTitle
@onready var questObjectivesObj = $QuestObjectives
@onready var questLongDescriptionObj = $QuestLongDescription

var questTitle = {
	1:"The first quest title",
	2:"The second quest title",
	3:"This is the third quest title"
}
var questObjectives = {
	1: "This is the quest objective text",
	2: "Another quest objective text",
	3: "Wow. A third quest objective text"
}
var questLongDescription = {
	1: "This is a relatively looooooooooooong description text of the first quest objectives.",
	2: "Once upon a time there was an incredibly long text which was the description of the second quest",
	3: "One could write a very long sentence with just three words, provided that those words are very long indeed."
}

func add_Quest_To_List(questId:int):
	if(questTitle.has(questId)): #check if a quest with this ID does exist
		if (questObjectives.has(questId)):
			if(questLongDescription.has(questId)):
				questBlockId = questId #setting this Id helps find/sort quests in QuestSystem
				questTitleObj.set_text(questTitle.get(questId))
				questObjectivesObj.set_text(questObjectives.get(questId))
				questLongDescriptionObj.set_text(questLongDescription.get(questId))
				name = "QuestId_"+str(questId)+"_Block" #changes the quest block's name to make it easier to remove when quest is complete
			else:
				print("Error: quest's long description not found.")
				queue_free() # Destroy the current node
		else:
			print("Error: quest's objectives not found.")
			queue_free()
	else:
		print("Error: quest's title not found.")
		queue_free()

With some font tweaks and background changes this is what it currently looks like in the spy game Cavefish.

-Yes, this is the first image of Cavefish since a few months ago! A lot has changed.
Leave any questions or ideas in the comments section below!

Download the project file here.

Do I deserve a tip for making this tutorial?
Did it help you?


Dropping a coin to helps support the costs of running this blog.
Check out Cavefish and share this page with your Gamedev pals!
Thank you.
❤️

Enjoy your day!
Rui S.

1 thought on “Godot – Basic quest system example”

  1. Pingback: Cavefish – Dev Diary 5 - Starchild Studios

Leave a Comment

Your email address will not be published. Required fields are marked *