Lymbo
9 4 weeksLymbo is a surrealist exploration game with PSX-visuals. For this project I worked on the Dialogue and Quest Systems.
C++, Unreal Engine, Dialogue System, Quest System
The project where I felt Unreal just clicked. For this project I mainly worked on the branching Dialogue System as well as the Quest System. Spanning only four weeks while being responsible for two major systems has shown me the importance of planning ahead and being open to improvising
The largest task was definitely getting the dialogue system in working-order to let designers prototype as early as possible. I first began sketching out the dialogue system by looking at other similar implementations and found a project called Yarn Spinner, which is a dialogue scripting language.
I knew that I wanted to have a script-like structure because our dialogues would require branching based on predicates such as player items and quest completion. However implementing a custom script parser was unfortunately slightly outside of the scope of this project. Ultimately, I landed on a compromise between the versatility of a script-language and the rigidness of a DataTable and ended up using instanced DataAssets for my Dialogue which contains DialogueNodes.
Using DataAssets meant DialogueNodes could be stored polymorphically which meant any combination of events, triggers and predicates could be combined and matched to the project’s needs as it grew. One unforeseen consequence of this was the sheer size of DialogueAssets and the number of DialogueNodes which made them somewhat cumbersome to work with.
While they are largely distinct the quest system is actually quite similar to the dialogue system at its core. Quests are implemented as DataAssets that contain different predicates/conditions in order to pass a quest. These can either be evaluated linearly with one quest leading to another or with multiple active conditions at a time. I gave these a base class UQuestNode that has blueprint overridable features so designers can personally author new nodes whenever required to.
Upon completing all QuestConditions the QuestComplete function is called and an event is fired for any other subsystem that needs to react to quest system updates.
For the world to react to Quest Progression a ProgressionSubsystem was also made which keeps track of globally triggered gameplay tags. These are set along with each quest and its respective conditions and updated whenever a quest is started and finished.
In retrospect, this project has taught me a lot about how separation of data and gameplay can greatly impact development time, both negatively and positively. So a potential improvement would be to store all dialogue lines in a DataTable rather than a DataAsset to separate the dialogue lines from the actual logic that handles them. This would not only make localization easier but would make authoring new dialogues far easier.