Sunday, November 17, 2019

... I am still programming

I meant to write this update last week, but I was this close to finishing my conversation system in a workable state that I just had to push it out before I wrote anymore. And so, now, I have done it. Yay! Now that this system is just about done there's only some vague UI and save/load problems left to tackle from the programming side (that I can see right now - sans refactoring).

Unexpectedly, I'm still on a programming run. I thought (as per last update) that I would switch over to either gameplay or art, but instead I've just been programming away. This has been good I guess, and I'm rounding out the logic to the point where serious game work might be able to begin at the end of the year. But of course, every step of the way and every breakthrough I make I get a firmer grip on how much there is to do and how far I have to go. And of course, it's a ways.

One thing that is becoming crystal clear is that there's no getting around the fact that at some point all my dialog is going to have to be written down in huge complicated files. I should backtrack a little first and quickly talk about what I've got at the moment for my conversation system's structure.

In a typical RPG game, your dialog choices with an NPC usually drive the rest of the conversation with that NPC. If the NPC asks, "how's your day?" And you reply "bad", they might respond with "oh no, what's wrong?". If you instead replied "good", they might say "that's nice", but the choice you made is forgotten by the game immediately afterwards; it only existed in the context of that specific conversation, or even just within that single response. There might be certain dialog choices in certain conversations that have a lasting impact in the world such as an NPC asking you "do you support faction A?" And later in the game faction B rejecting you for this. What I would like to do is have ALL conversation choices recorded. My game is going to be about the choices the character makes in every conversation. This demands a very comprehensive game state and a rigorous naming/namespace scheme.

Unfortunately, I'm not happy yet with what I've made. I pushed through and finished it into a working state however, because it's better to have something working than it is to just fret continuously over what could go wrong. Here's a diagram of what I have:


I realise it doesn't exactly make things crystal clear. Truth be, I think this system is a bit of a mess. But it works, for now, and so I'm going to push on. Each NPC has a "Conversation Manager" assigned to them. This manager contains a number of "Conversation Fragments" which in turn contain a list of responses. Each response has a condition to be available, and a post-selection outcome. Both of these are anonymous functions provided at instantiation of the class. Conversation Fragments can also contain conditions and can be set to be repeatable or one off conversations.

In this way, I can build up conversation "trees" full of conditions and responses. The responses to conversations are at the moment being stored in named Enums inside the global state. E.g. "responseJimAreYouOk.Yes". This again isn't ideal but is quick and dirty. You might also notice that the current method has all my conversations being created inside the script (C#) files. This doesn't bode well really, but again works for now. Ideally, I'd want the pure content strings of the conversations to be in external files, but I'm not sure how I can link them to my anonymous delegate functions for conditions and outcomes that must be in the codebase. I might end up creating some generic (named) conditions and outcomes as members of some conditions and outcomes classes, and then I could reference them via strings in external files. But for now, again, my rough system is ready.

The advantage of this system right now is that I can access any response to any conversation from the global state. A bit awkward for sure, when you might rightly expect the conversation states for an NPC's interactions to belong to that NPC only, but having random NPC's access other random NPC's to poll their interactions is just as icky if not more so than doing to to the static global state. That's my belief at this point, anyway.

The biggest risk with this system going forward is that I dump hours and hours into writing content inside of it only to find that it's got some huge flaw or to get some brainwave down the line for a much much cleaner system only to find it will take weeks of time to refactor into that system. So, I will proceed with caution with my testing, and create a moderately complicated set of test NPCs and mock gameplay to see how well the system performs under pressure.

I shouldn't leave you without a picture to show what my system looks like!

On a side note before I wrap this up, the Unity UI builder has been a little tricky to deal with, but overall not terrible. I've worked with some truly awful UI builders in the past and I understand it's a tricky problem to tackle. I've appreciated not having to work too hard to deal with UI this time around. The player controls settings are a bit more difficult to work with, however. I'm sure I'll get the hang of it.

No comments:

Post a Comment