Hello. I’m Everette, aka Digx7, and I’m looking for work in the games industry. In the meantime, I’m working on a 2D narrative-driven RPG under the working title of D2. This is my Dev Diary for 4/17 through 4/24.
Why Dev Diary?
First, why am I calling this a Dev Diary and not a Dev Log? Isn’t that what these are normally called? Yes, but, at least to me, they seem to have a bit of a reputation that I’d like to avoid. Most of them seem to rely on the spectacle of new features or new visual things being added each time. To the point where some developers focus on adding new features rather than making the game stable. Adding new features is cool but they are not the only part of game development.
I want to focus on both the progress I make and also on my thought process as I develop it. Hence going with the term Dev Diary rather than Dev Log. Well I’m still figuring out what kind of schedule I want to make these on, I’m thinking about one every 2 weeks.
4/17
At this point in the project, I am trying to create the first area of the game as a way of figuring out all the systems and processes I will need to make the rest of the game. In drawing it is common to start with a simple sketch to figure out the shape, then to slowly work in the details, before finally committing to a final render. So right now I am in the process of sketching out the first area.
Figure 1
Location and Conversation Graph
Note: Here is a graph I made of the different locations and conversations the player can have in this first area. Well, it’s not final, it gives me a plan to work on when sketching this area.
Figure 2
Placing Doors
I started by adding all the doors to each scene allowing the player to move between them. This may not seem like a lot but with 16 connections and each connection requiring 2 doors (1 in each scene), that means I had 32 individual doors I had to place and configure. It was at this point that I started to get a sense of how much content management would be a challenge for this project moving forward.
Figure 3
Working on Conversations
I next placed all the conversations in their locations in each scene. None of the dialogue was final and most of the conversations were just one line long with that line being the name of the conversation. But I had 22 conversations to make and place (about 2-3 per scene). Again managing all of these, especially as the game scales will take a lot of work.
Figure 4
Testing made conversions
Lastly, I added location title cards and improved how the game handled the scene transitions by adding a screen wipe and updating how the camera gets set up in each scene. I also built it so the scene transition can be interchangeable allowing me to add other scene transitions in the future. At the moment when playing it in the editor the game noticeably hitches on a scene change, but the transition hides this pretty well. I am uncertain what it would look like on a full build.
Figure 5
Location Title Cards
Figure 6
Scene Transitions
And that is all I did for 4/17. Well, the doors were all set up, and placeholder conversations were in place. I still needed to graybox each location. At the moment all my scenes are nothing more than simple hallways with doors.
I am also seeing the value of several dev tools I might need to develop to help speed up making or managing certain types of content.
The tools I have in mind are as follows:
- Dialogue Pipeline: Some way of creating dialogue in a node graph editor, exporting that to the game, and automatically hooking it up to localization.
- Sprite Wrangler: A grab bag of several small tools to handle various sprite-based bottlenecks. Including: slicing multiple sprites at once, and automatically generating multiple sprite-based animations at once
- Quest Graph: Some way of creating quests in a node graph-based way might be similar to the dialogue pipeline.
- Scene Connector: Some way of easily managing the connections between scenes in the editor.
4/24
Originally I was planning to graybox each of the scenes. But instead, I decided to work on making the Dialogue Pipeline tool.
Before I go into what I worked on this day I need to give some background on this tool and the problems it’s aiming to solve.
Figure 7
Showing the conversation before
At the moment in D2 dialogue is stored in a Unity ScriptableObject called a conversation. A conversation is just a list of nodes that can be either lines of dialogue, choices the player can make, or events to trigger (like progressing a quest line). However, working with a branching dialogue when you can only view it as a list will not scale well. I needed a way to work on it in a graph form, this was the first goal.
A second goal of the tool was to get it to connect to localization automatically. Well as a solo developer, it is unlikely I will have the funds to pay for a translation anytime soon, it would be foolish of me to not at least keep that option on the table. Especially given that this will be a primarily narrative and dialogue-driven RPG.
To solve the first problem there are solutions on the Unity Asset store that exist, unfortunately, they cost too much so I instead have to roll out my own solution. Unity has an experimental package that gives you access to a library of node graph-type functions to use in a custom editor window like what the Shader Graph does. And it well it seems robust it is also experimental. Custom editor window creations are also one of those areas of game development I know very little about and it feels super tricky to learn anything on. The problem is that Unity has 2 separate editor UI frameworks, its legacy framework, and UI Toolkit, each of which would take a lot to learn on their own. Also, both frameworks have gone through a lot of iterations so finding up-to-date documentation on either is difficult. So instead I decided to look elsewhere.
Technically I didn’t need this graph editor to exist within Unity. It could exist as its own tool and then have its data imported into Unity. At runtime, the game doesn’t care how the data is stored, so long as it can access it. So at runtime having the data in a list (as it already was in the Conversation ScriptableObjects) works just fine. Well, I’m sure there are some frameworks out there that let you easily build node graph editors. I could not find any at a quick glance. What I could find was a tool I already knew existed: Twine. [1]
Figure 8
Twine Showcase
Twine [1] is a simple node graph editor designed for making Choose Your Own Adventure-type stories that can be played in the web browser. It has a very simple and clean interface. It also has a feature called Story Formats that allows you to modify how the story gets displayed in the browser. One Story Format I found turns the entire story into a JSON file that you can use elsewhere [2]. I decided to see if I could use this to build my dialogue for D2.
Figure 9
Example JSON output from Twine
Now onto what I did.
I spent the first half of the day figuring out how to make Unity Editor scripts that could do each of the individual steps I would need for this Dialogue Pipeline. A way of importing JSON files from Twine into the dialogue for my game.
Figure 10
Creating a scriptable object with editor scripts
Figure 11
Code to create a scriptable object from editor script
I first figured out how to create new ScriptableObjects of a given type of ScriptableObject. It turns out the Unity Editor has access to a static class called AssetDatabase that allows you to do all kinds of asset manipulation, from making new assets, editing them, loading them, or deleting them. This class will be used in all the following steps.
Figure 12
Unity Localization Package
Next, I need to figure out how to connect this to localization. First I need to figure out how to handle localization. It turns out that Unity has a localization package [3] you can use. This package basically lets you create spreadsheets where each row is a unique string and each column is that string in a given language. So to get this setup I would need my Dialogue Pipeline to be able to edit existing English strings (if I was editing a conversion) or to create new rows and add the correct English strings (if I was making a new conversation). Eventually, I figured this out.
Figure 13
Modifying a localization table from a editor script
Lastly, I need to figure out how to parse a JSON file into anything else in Unity. It turns out Unity has a nice JsonUtility class that we can use. However, this class is designed to serialize or deserialize objects to and from JSON files. This means that I needed to create a new class that closely matched the structure of the JSON files Twine was giving me. I called these classes TwineStory classes. Using these TwineStory classes I was able to successfully deserialize the JSON files into these classes.
Figure 14
Twine Story class
Figure 15
Steps the Dialogue Pipeline takes
With each of the pieces figured out I spent the next half of the day making a Unity Editor script that put them all together. It would take a JSON file and deserialize it to a TwineStory object. Next, it would look at the name of the story and either make a new Conversation ScriptableObject or edit an existing one. It would fill the nodes of the Conversation with the lines it got from the TwineStory. Lastly, it would go through the Conversation ScriptableObject and add all the lines to the Localization table. Once this was all working I made it so this script could work on multiple JSON files at once.
Figure 16
Creating a dialogue from a JSON file
One problem I had to solve was the fact that in each Conversation Node, there can be more metadata than just the dialogue line itself. These can be things like the name of the speaker, or the image portrait to show. Also for nodes that trigger events, there can be all kinds of metadata needed about the event to trigger. To add these in Twine I am using a system of adding comments in the text to label these things. I then need to update the DialoguePipeline script to parse out this text and put the metadata in the correct spots. At the moment it only does this with the speaker and the main line. One thing I’ll have to look out for is possible bugs related to typos in this metadata since Twine itself has no way of validating this metadata.
And that’s all I did on 4/24. Regardless I am super happy with how this tool turned out and that I even got it working. As always there are still a few things left to work on. One is adding the Names and text for the player’s options to the localization tables, at the moment only the main line is added. Another thing is how best to handle option nodes and event nodes. I’ll need to figure out both the metadata needed and how to get my DialoguePipeline to parse that properly.
On the topic of managing a bunch of content, I am realizing that a strict naming schema for content will be needed going forward. Also, Localization will present some challenges in making sure that all the strings get connected, but also that we don’t have any dead strings. After all, I won’t want to pay for localization of strings that will never get used.
Anyway, now that it’s working I should try making a few more conversations to see how well the workflow scales.
And that’s all for 4/17-4/24 thanks so much for reading and I hope to see you in the next one whenever that is.
References:
Further Reading:
- How CD Project Red handled localization for Cyberpunk 2077 : link