Implementing a dialogues system for Camille & Laura

INTRO

This post was part of my first newsletter. I would greatly appreciate it if you would subscribe here. You will get these blog posts directly in your inbox and a few secret bonuses!

This is my first newsletter! I’ll work on finessing the process maybe, but for now we’ll just see how it goes.

These newsletters serve two purposes: primarily, I want this to be a space where I can update you on the development projects of my current projects. Right now, I’m working on Camille & Laura and, in this installment of the newsletter, I will explain how I ended up with the dialogues system I’m working with as it was one of the first piece of the game I put in the code.

So, for the small update, I got some funding in the form of a grant from the Canada Council for the Arts. For the time being, this means that I’m moving to development of Camille & Laura full-time for a little while. It’s an incredible opportunity and while I’d wish to be able to complete a game for each prototype I ever started, my main goal for now is to finish the game I’m getting paid to do right now, don’t you think? I’m doing the game in Godot even though I did the prototype in Unity, simply because I’ve found the Godot engine to be wonderful for my needs.

I want these to be transparent about my development but, you should know I’m far from being a perfect example. I’m somewhat scared of sharing code snippets and dev processes here because… what if I did it wrong? I’m sure a specialist in its field could look at my methods and just freak out at how messy or stupid my solutions are. That said, the thing about shipping games, especially as a solo dev, is to make things that work at a decent pace, not to perfect systems for hours on end. It’s also worth noting that I’m very much still learning, and I am self-taught, I completely expect to learn new ways of doing what I did just week after I put it to code, but alas. That’s how it works.

In a similar note, do know that I’m French first, so the writing here might be messy too. I mostly write in English here to make my stuff accessible to most, but Camille & Laura is being developed both in French and in English.

This wouldn’t be complete Olivier #content if there wouldn’t be a little rambling. If you follow or know me a little, you know that I think good design is encouraged by intellectual curiosity towards the world and that anything can become good inspiration for design. For me, it often (not always) ends up manifesting in my interest with many artistic mediums. I irregularly create videos and podcasts where I can gather my thoughts on stuff I’ve been engaging with recently – this can be videos of me reading Virginia Woolf or podcasts about the board games I have in my collection – and this newsletter presents a new opportunity to both ramble and share places where the ramblings have been ongoing. I’ll mostly talk about music, movies, books, board games and video games I’ve been engaging with – as those occupy most of my time outside of game development – but I’ll assuredly share more when the occasion presents itself.

If that doesn’t interest you, I will clearly mark the beginning of where I talk about my video game project in the newsletter so you can only read that and follow my gamedev endeavors there!

With no further ado:

RAMBLINGS

Music

Like everyone, I’ve been fairly obsessed with the bop Espresso by Sabrina Carpenter. I’m not going to start arguing that this is a classic in the making, but like many pop successes, this is a right beat at the right time kind of affair. It’s been the perfect easy listening background music while I’m coding stuff that makes my brain melt. I dunno how long it will last, the song has been a little more than a month now and every day that passes it becomes closer to being absolutely insufferable to listen to but, I would have expected it to lose its power way quicker than this already. For a “waiting for the summer”-bop, Espresso certainly deserves to be considered in the higher tier.

If you’re looking for a nicher, more highbrow recommendation, I’ve recently been discovering the electronic music of Bolis Pupul. Like so many insufferable dudes I pride myself in loving “all genres” of music, but I do realize that I have a fair number of blind spots, electronic music being one of them. It’s been great to find an artist I can latch too who both seems to be accessible, with identifiable melody that don’t stray too far from pop forms, while still having an approach that’s still experimental.

Television

I’m very late to the party but I’ve finally watched Craig Mazin’s Chernobyl. While I’ve been more appreciative of the TV medium recently, I still find that the praise for a lot of its classics tend to be overwrought and the discussion over them being overshadowed by the unstoppable marketing machine of television. I’ve found stuff like Breaking Bad or True Detective S1 to be just fine, frankly, and I’m hard pressed to find why they’re so beloved other than the fact that the TV release schedule forces the public to feel like it is living a cultural moment, everyone is sharing their reactions at the same time and such. The True Detective S1 whodunit revelation was laughably bad to me (it almost boils down to “a dog with mean eyes” did it like Homer presciently imagined in that episode of the Simpsons) and the philosophical musings felt surface level, interesting as a starting point but never getting anywhere.

Chernobyl is better than fine, it’s good even, but I still find it hard to see the masterpiece I’ve been told it supposedly was. Like many TV shows nowadays, the photography is film level but, the way its filmed tends to stay basic up until in departs the shot/reverse-shot conversations TV mindset. When Chernobyl treats the nuclear radiation like a cosmic horror monster, it’s effing great. There’s this one incredible scene where three dudes go on a suicide mission in the underbelly of the destroyed nuclear plant in the hope of limiting the damage, it's a silent scene where the ticks of their radiation monitors serve as the only noise as if they were stalked by the Alien. For me, this stuff just works.

On the other hand, it’s bogged down by what is to me a lot of structural TV problems. Some of the side stories, the Jessie Buckley and the Barry Keoghan ones especially, just go nowhere and serve more as filler than anything else. The last episode of the series, where the trial takes place, ends up feeling hollow and just regurgitates points that have been shows already in the previous episodes. I didn’t feel its place is warranted.

Finally, my main issue with the whole thing is an issue I often have towards north American media. Chernobyl presents the failure of government institutions and officials to see the problem they were warned about by scientists as an issue worth working on. The parallels with the ongoing environment crisis are obvious to me and I’m sure Mazin meant for them too. While I think it’s important to look at history to not repeat our failures, I think we are also at a point where the public is extremely resistant to compare our current issues with those of the past. I think a great part of Chernobyl’s public is not interested in seeing the similarities between the failures of Soviet’s communist dictatorship and those of American somewhat democratic capitalist society. While I think Mazin and his team intended to tell a story encouraging the public to ask their representants to be accountable for their inaction, the historical and societal dissociation that’s available by telling a story that happened in Soviet Russia will be an easy way out for most of the public. At this point, it sounds like I’m arguing that Chernobyl’s story should not be the one to tell, and this is not entirely true. I think this is an important story, I just wish American producers would be as inclined to show failures of our current society as much as failures that comes from what was and still too often seen as the enemy of the American way of life. At least, I would’ve hoped that Chernobyl would’ve explicitly stated the parallels of its story with contemporary failures.

Games

In the physical realm, I just recently started the Hemlock Vale campaign of the Arkham Horror LCG. Arkham Horror is one of my favourite board games to play solo (though you should know I play two-handed, if you know what that means) and I’m consistently impressed by how the designers are able to stretch the card game design into narrative adventures. At its worst, Arkham Horror LCG can become extremely finicky, and those experimentations can end up overwhelming the gameplay itself. It’s too early for me to say if Hemlock Vale will be one of the better expansions of the Arkham Horror LCG, but I’d argue that Arkham is still “good” at its worst. I do love the setting for the campaign, Hemlock Vale being an isolated village on an island very reminiscent of the Wicker Man’s village, and that helps a lot in my appreciation of it, I’m sure.

I also played Cosmic Encounter for the first time. It’s a classic for a reason! It’s crazy to think that design dates to 1977! I know the version I played got iterated upon for years, so I dunno what the game felt like forty years ago, but still! The age of the design also explains why it’s not a thing you see much of anymore in board games: Cosmic Encounter is inherently unfair. At the beginning of the game, you’re randomly assigned an alien species that comes with its own special power. There is no effort in making those species balanced at all. As a political game, Cosmic Encounter gives the responsibility of creating balance to its players. If one the player has a power that is too powerful, then the others alien species should join force in taking down this tyrant!

I should play more of it to get a proper idea of all the possibilities of the game, but as someone who never cared much about winning or losing in games, I do feel Cosmic Encounter is onto something. I often get bored with deterministic games with little to no negative interactions between players as I feel these undermine the drama that can happens in good games in the service of fairness. There’s nothing like finally finding a way to beat the player that acted like a tyrant the turn before or doing everything you can to simply survive because you’re one small defeat away from being eliminated from the game.

I do often feel that feeling bad about unfairness can be often just a player problem than it is a game problem, but then again the designs I like tends to be more interested in telling stories with systems than creating a win/lose game. This is not a point where I think I’m right about my approach on design and others are wrong, but I do wish we’d see more “unfair” games like Cosmic Encounter nowadays.

I barely have played video games recently. I’ve been going through Yakuza/Like a Dragon – Inifinite Wealth for months now, and while it’s still a wonderful game, I’ve found that the narrative has been losing its steam for a little while now (I’m in chapter 9). I’m dedicated to finish it now, but it may take another few months.

I’ve bought both Dread Delusions and Animal Well because they both sound great, but I dunno when I’ll take the time to play them. I don’t tend to have big backlog of unplayed game, but for smaller indies I do often buy games simply because I think the devs deserve it. If millions of people buy the new shiny AAA because of cultural inertia more than because of genuine interests, I feel like indies deserve a part of the cake too! Hell, I wish some people do that for Camille & Laura when I ship it…

Talking about video games…

CREATING A DIALOGUES SYSTEM

From my previous games

I think the first mistake I hear a lot talking when people think about dialogues systems in game is that a fair amount of bumbling gamedevs tend to think implementing dialogues is a solved problem. The reality is that even a dialogue tree can take different forms in the background depending on the needs of a specific game, and I personally wanted to make sure I’d be able to control a certain amount of my game elements in my dialogues system for Camille & Laura.

I opted out of using a premade solution like Ink or Dialogue Manager not because I have a problem with any of them but, because I wanted to understand my own solution and be able to modify it to fits my need. I am still learning a lot in how I implement and code my game, and these already-made solutions tend to be intimidating to me in that I would not know how to get in them and change them where needed. While I don’t have a lot of time to work on my game, I think that taking the time to implement my own solution would be beneficiary in the long run as the understanding of it that I’d gain by implementing it myself from the get-go.

I kinda cheated out my way of creating a proper dialogues system in my previous games. A Game About did not have a lot of text so I simply put a sprite of the text in the game. All text is handwritten, so what is there is simply images of the different texts. No parsing or actual programming necessary, it was all implemented directly in the Unity editor.

Please Hold Me, another project that I did a prototype of but never got funding for, was a lot more complicated. The game presents a conversation with a single character, and I wanted that conversation to have a lot of variability. Writing all the texts by hand would have been way too much work, but I still did not feel ready as a programmer to deal with JSON dictionaries and such – my eyes would glaze over as soon as I start reading about them – so I still decided to implement my text directly in my game’s code. The choice might seem silly in retrospect, but I feel one the biggest issue I had as a bumbling programmer – and one issue that seems to be minimized by devs that have a lot of experiences with these tools – is understanding the interaction between the many components of a game. It makes much more sense when you learn to have all the logic of one component of your game that in a single programming Class, even though it’s not the proper way to implement it, than to separate what feels like the same system between multiple class and data files of different types.

As such, all the dialogues of Please Hold Me exists in the one single Class. What I’ve done is that I essentially created two arrays – one for the actual dialogues that the character will say and one for the dialogues you can say to the character – that I will modify at runtime depending on my need. The game being a single conversation, the player input a subject of conversation to the character. From that subject, I call in the code of the dialogue system the function that is attached to that specific subject.

From there, I simply add a bunch of strings in the two arrays. The sentences array will be the dialogues that the character will say, and the questions array is the one that will establish the subject of conversation the player can input after.

I then simply iterate through the sentences array first. Each line in the array represents a line of dialogue the character will say, so I iterate by reading the first line of the array and removing it right after every time the player click to get a new dialogue. I don’t need to search the array or look for specific index (positions in the array) simply because I know that the next dialogue to say will be always at the first in line, the dialogues being removed as they are said.

If the player clicks and the array is empty, I know then switch to the question array and execute the same process, the only difference there being that the questions array does not wait a click from the player to iterate through itself. When this array is empty too, the game knows its interaction process is done and that the player is ready to interact again.

For my simple goals, this worked at the time. The first obvious problem here is that you need to go in the code to add and change dialogues, but this was never much an issue for me as a solo developer. The bigger issue, which I just accepted would be a problem that I’d deal with if I had actual money to work on my game, is that adding another component to this specific system would be a nightmare. For example, if I ever had to translate the game, having the option to pick between multiple language would basically ask me to reprogram my system close to its entirety.

 The Camille & Laura dialogues system

For Camille & Laura, I knew I wanted to make something that was more in line with the “proper way” of implementing a dialogue system. My main motivation was to learn, frankly, but considering I want Camille & Laura to be a commercial game, I hope having a proper system would let me implement translations and other systems as needed. I don’t think what I’ve ended up with is quite there – frankly, developing a game solo implies that you end up cutting a lot of corners for the sake of simply progressing – but I got much closer than in my previous efforts.

The first step was to ask myself what my requirements for my game were, so that I hopefully could make my whole dialogue system in one go and rarely need to go touch it back up, as that kind of refactoring can create issues you never anticipated in stuff you thought were bug-free. In tech term, this was my minimum viable product.

I came up with these requirements:

  1. It needs to be JSON, it seems to be the most used format for storing data similar to dialogues in game.

  2. I need to be able to add language on the go if ever I get support to translate my game in more languages. At the very least, I will try to implement an English and French version.

  3. I need to be able to change in-game variables from the dialogues to track dialogues choices.

  4. I need to have character animations that are timed with the dialogues, as such I need to be able to call those animations during dialogues.

  5. To create “air” in conversations, I need to be able to put pauses when needed between line of dialogues appearing.

  6. The system must be able to identify if there’s more dialogue to come, and if there is to automatically go to that next dialogue, or if is the end of a conversation and control needs to be given back to the player.

  7. My dialogues are implemented as speech bubbles appearing besides the characters. The dialogue needs to be able to identify which character is speaking and change its positions accordingly. There’s also multiple type of bubbles possible (ie. speech bubbles vs thoughts bubble) and the systems need to be able to change the shape of the bubble accordingly.

  8. Finally, there’s two “types” of possible dialogues, conversations that the characters will automatically go through and the dialogues “button” that the player will click on to make a dialogue choice.

Again, it’s worth noting that a lot if not all these requirements are already accounted for in a lot of already-made dialogue systems. For example, most visual novels engines out can take care of this, but they’re limited by some assumptions that come with the genre, like the fact that text boxes in visual novel are generally all in the same area and that the name of the speaker is indicated simply through text. I want my game to be closer to an interactive children show, so on top of needing to learn I felt that I could not work with the limitations of these systems.

JSON is not that complicated in itself; you need to understand its structure and how to parse it for your game. Thankfully, there’s a fair amount of information on how to deal with JSON files with Godot, so I managed to get that going very quickly. As for its structure, there’s a few examples available online. That being said, finding an easy and readable way to edit it is a tad more complicated. The best-case scenario seems obviously to be spreadsheets software like Excel or Google Sheets, but the issue is that the former needs some coding to export JSON (and it seems to be easier with a business license, which I don’t have the money for) while Sheets needs plugins that are supported (or not) by individuals. It’s easy to find a two years old reddit post that tell you to use this specific thing that does not work anymore because the single dev that did it never had the proper time to update it before. It’s the usual shitshow for internet tools, basically.

But anyway, worst case scenario any IDE (the same tools we use to write code) will be able to read JSON if you’re ready to abandon the joy of having it in a beautifully organized spreadsheets, so if things don’t work out, I will still be able to access and modify my data.

So, I created a JSON dictionary with data that looks like this:

So, a few things here. The advantage of a dictionary over an array is that not every piece of data needs to follow the same structure. Ideally, all my dialogues will have these properties, but if ever to add a certain type of information in an entry it should only create a problem if I try to access inexistent data which, anyway, would be a sign for me that I forgot something.

Obviously the first line represents the entry of the dialog, I use my own system to follow that, but it does not need to respect any structure. Because those IDs are unique (and the IDE will tell me if I’m trying to reuse an already present ID), I can easily search for them when needed.

For now, I only have the French or English dialogue entries, but I can easily add one in my JSON. When the game is launched or when the option is changed, I just change the variable that tells the code which language to look for, so that’s no issue for the future.

The NextDialog property is simple enough, if there’s any data in there it will go look for the ID entered there as the next dialog to cue in, if there’s none, then it knows that it’s the end of the dialog section.

Wait is not complicated either, the string variable that I entered there is converted into a float variable and the code waits there the amount of time indicated before making the code appears. I have an internal variable on the dialog that checks if the dialog is completely visible when the player clicks, so the dialog won’t destroy itself before it appears (so a player quickly clicking wouldn’t miss any line of dialogs).

I Speaker property indicates who will say the line. The dialogue automatically adds itself as a child of the speaker, so I can add as many speakers as I need (or invisible markers, if I want to have dialogues that appears out of nowhere) and will follow them as needed.

I cheated a little in the Orientation property. It’s too late to change it for now, but this property dictates the shape of the speech bubble. I have more than one bubble “prefabs” that I can pick here, like thought bubbles for example. The property was meant to simply decide if the bubble would show left or right of the character, but I ended up reworking it to decide both the orientation and the shape of the bubble. Left or right means the game will instantiate a regular bubble on the appropriate side, but I can also enter data like “ThoughtsRight” to create the appropriate bubble.

Where I faltered a little and ended up simplifying my solution is with the InvokeFunction property. I felt it was too complicated for not much benefits to be able to play with the variables and the animation directly in my dialogs, so I made a property that would let me call function as soon as a dialog appeared. I can add the necessary function in my dialog manager script depending on what I want to make in the moment, change a variable, play an animation, change the states of something, etc. The issue there is that I need to create a new function in the dialogues manager script every time I need to create a new behavior. This is barely an issue for a solo developer, as writing a simple function there takes no time, but it would be completely unsustainable for a team project where the coder and the narrative designer are not the same person.

I also forgot something there that I would realize a little too late. While I can call function when the dialog is instantiated, I cannot do the same when the dialogue is deleted. My alternative is silly but works better for me than refactoring my code at this point. I added a custom signal to my speech bubbles objects that my dialogue manager can subscribe to every time it creates a new instance of dialogue. The signal is emitted before the speech bubble is deleted, and the dialogue manager can then have function depending on which bubble was deleted this way. It’s hacky, but it works.

Finally, the “questions” property let me automatically create my dialogue options button. If it’s not empty, then the code switch directly to creating a button instead of regular dialogue. I enter the ID of the dialogue the question will be pointing to when it’s clicked, and my code takes the string I entered there and add it to variable in the question button that the code will be able to check when it’s clicked.

This is my solution for now, and I have absolutely no idea if this is a good one or a bad one, but it let me create my dialogue scenes at a decent pace.

And this is how I feel about the whole thing. Most tutorial you can find on dialogue management online presents a specific use case that will work for a plethora of games with an exactly similar dialogue design. If you want to simply push against it a little, it feels almost better to redo the whole thing from a scratch. I know my solutions are imperfect – as a solo I think I cannot use all my brain power be the best programmer and I need to move quickly.

That will be it for my first newsletter. I don’t know how insightful or interesting this is, but feel free to send me a mail here: contact@olivierb.org), check the website,  check BonjourBorzoï on twitter, bluesky and LinkedIn and tell me what you think there. It seems silly, but following these things is the best help I can while I’m developing. While I cannot promise I will be regular with updates – developing the game is the priority and that is more than enough for me to lose all my free time – I hope I can post a few updates here throughout the development. See you soon!