Text Adventure Game (Need Help)

Hey there Unity Community

I’m working on a practice project where I can get away with not using many art assets or complicated objects. As a writer IRL, I like focusing on story and development, but I’m still relatively new to programming. I understand the fundamentals, but some of the more advanced logic is still getting me stumped.

So I’ll explain this as best as I can:

I’m working on a text adventure game. But I want it to be more robust and dynamic than something like Ren’Py can accomplish - as in an inventory system, many choices for actions or dialog, dynamic NPCs, etc.

What I’m asking for help with specifically in this post is this:

What do you think is an effective way to script out the game to accommodate the stories and events? I’ve dissected a few smaller open source programs that were poorly put together (i.e. the code only barely worked), and one tutorial used a state system that seemed like it would get wildly out of hand very quickly (though I might not have understood it properly).

Do you guys have any suggestions? I would greatly appreciate feedback. I’ve provided a few images to better display what I’m asking here, in case my description was confusing…


Thanks in advance for any advice =)

1 Like

While well illustrated, I’m afraid I’m not clear on what it is you’re looking for. You appear to have your “character stuff” well in hand, and it sounds like you have the initial scene working and then displaying the options? If I’m understanding correctly, the option buttons each load a new scene? Where are you having trouble? This all seems pretty straightforward… If button A is pressed, load scene A… If button B is pressed, load scene B… Etc. Lather, rinse, repeat :wink: I’m sure I must be missing something, so please feel free to elaborate and I’ll help however I can.

1 Like

I think what @Avamarine is trying to figure out is how to structure his game from a technical point of view (Whether moving from A to B is done as a state system or something else), but you’re right that a bit more detail is needed to understand exactly what the right approach should be.

@Avamarine You’re probably right about a simple state system (presuming a Switch statement) getting out of hand quite quickly, that would work fine for a small number of scenes but get increasingly messy the bigger your project got. Since you already discounted a simple system, I’d assume you aiming for a larger project with an eye towards reusability - a data driven approach. Does this sound right?

There are a couple of ways of going about this sort of system, which you choose depends on how comfortable you are with programming, how reusable you want it to be, and what other interactions you intend to have. As @krougeau mentioned, your diagram seem to show quite a simple A to B to C style system - which could be done as simply as using the number of each scene to index into arrays of relevant data. Although since you do mention wanting an inventory and dynamic NPC’s, I suspect there’s more to what you’re trying to achieve.

What other player interactions or system responses are you expecting to deal with? Are they additional to the ‘options’ for each scene? Or are the options intended to be dynamically listed? Are these options the only way the player moves through the game? What exactly is a dynamic NPC?

It may help to talk us through a small example of how you see a ‘scene’ playing out.

PS: Nice to see a detailed question from a new user. Kudos for that :slight_smile:

1 Like

Sorry, I re-read my post and realized that yeah, it’s really vague. I shouldn’t try to write things so late, haha. Alright, so let me articulate this a lot better…

What I’m after specifically is how to structure the data within the code so that it can balance the various scenes and pull them dynamically as needed. @NomadKing You’re right when you say that the data structure gets out of hand quickly when I’m dealing with hundreds of scenes - and that’s just in the early state of the program. Taking away all of the frivolities I mentioned earlier (because those aren’t really needed for what I’m asking), I’ll just lay this out in how I’m looking at this from a non-coded point of view:

A scene plays out, and when it ends it leaves the user with a set of reaction choices.

  • Choice A - C are standard
  • Choice D may only show up if certain conditions had previously been met

This sounds simple enough to code, however when I started to lay it all out, I realized that there may be a more organized or structurally sound method of achieving this so that the code, which is already going to be ridiculously long, isn’t a jumbled mess of disorganized fury. Especially when you start to consider NPCs and stats playing into the mix.

A friend of mine suggested a Graph, where the various scenes and actions are stored as nodes and can be called upon. The problem is that I know nothing about utilizing Graphs in code. He linked me to this ( Graph (abstract data type) - Wikipedia ) but I left the page more confused than when I went in.

I really hope this is more informative than my first post…?

1 Like

I am still fairly new as well, but I would suggest looking at the unity programming video on this site that is called data persistence, its maybe an hour long but well worth watching especially if your wanting to persist and bring data from that many scenes. I watched that video many times when i was trying to work out a way to persist data. Aslo another thought i would have is possibly setting your similar data up together in Arrays. you could possible use a singleton design set up that way and just be able to pull all your data and values from the GameControl script. (it covers that in the video i mentioned)

1 Like

if you need a direct URL to the video let me know and ill go grab it for you

Actually, my friend went ahead and broke down what he meant. He was actually talking about Directed Graphs, which is exactly perfect for what I’m after.

https://directedgraph4net.codeplex.com/documentation

@Sylvir I’m ok with the various data structures like Arrays and State Machines, the problem with these data structure methods is for the sheer amount of data that I’m going to be referencing throughout the code, and how frustrating that would be to sync up with previous character decisions and such.

The node system for Directed Graphs and Directed Acyclic Graphs means that I can set up a visual structure that I can then translate over into the code, and allows for more versatility and dynamic scene calling than a State Machine or Array setting without a -lot- of tweaking that could get real messy real fast. When I dissected other code of this nature, that was exactly the problem I was seeing and leads to problems where the character may encounter something they aren’t supposed to because the SM and Array lists would have to be designed more linear.

This is still something I’ll have to fiddle with though.

I usually write my posts early in the morning and suffer from the same problem! Your post wasn’t that vague, but I wanted to make sure of the details before I directed you down a potentially over-complicated rabbit hole :stuck_out_tongue:

Directed Graphs are one possible option, although I think a Tree structure based around 2 classes would probably serve you better. Truth be told they are quite similar things and I can’t quite remember the exact distinction that makes something one or the other. I think that Graphs are better suited for searching / sorting data, and based on what you’ve said, you shouldn’t need that in your system.

For the type of Tree system I’m talking about, you’d make a Class that could hold all the relevant data for that Scene. This would include an array of a 2nd Class called an Action (these are your choices)*. The Action Class would hold a link to next Scene and the other relevant data for the Action - probably just the Text this action displays and any flagging data it needs to check to be considered active. Now, you could skip the Action class entirely and just have a couple of arrays for the choices / text displayed / condition flags, but this kind of depends on the complexity of your conditions for any choice to be displayed. Personally, I think a 2nd Class gives you more room for complexity further down the line, but you know more about what you’re planning than me :slight_smile:

As for getting the data into the system, I’d look at using XML files to structure your data, and have your system simply load it in and create an array of Scene (and Action!) data with the appropriate linkage. This keeps your system abstract from your game specific data, and lets you work on your story in a more readable out-of-editor way. You could even go as far as to create Editor extensions to display your XML in a visual / node way while you’re working on it, although that itself can be quite complex. There are also a bunch of resources / tutorials floating about on using XML within Unity which is obviously a big plus!

After talking about all this, I’m starting to feel the need to work on a text adventure of my own! If any of my early morning rambling needs more detail, or you want some pseudo-code example of WTF I’m talking about, just let me know :stuck_out_tongue:

*I wonder if this is actually a Graph after all… lol

@NomadKing Those are some very interesting methods and ones I’ll definitely look into. I particularly like the XML file idea to store the text, because holy omg that would make my life so much easier.

My biggest problem is that while I understand programming for the most part, even up to advanced logic, I’m not usually the one writing it. In the past I’ve always been the team-lead or the debugger or the problem solver, but very rarely have I actually sat down and physically written my own code. This project is my way of trying to fix that problem though, by just sitting down and doing it.

Though I would greatly appreciate some elaboration on the tree/class system you’re talking about, maybe just some basic pseudo code. If you’d ever like to discuss more one-on-one or real-time, you’re welcome to PM me and we can work something out (but that’s totally up to you).

I think it’s better to keep the discussion here for now. Knowing how to go about structuring code is probably one of the things that a lot of new users struggle with, so if in the process of talking about your project we happen to splash some knowledge onto other new users, great! It also means that others might join in with improvements on what I’m suggesting, which would be great too! With that being said, if there’s anything specific to your game that you don’t want to share here, feel free to PM me.

With regards to actually writing code, I’d say that it’s much easier figuring out a compiler error because your syntax is wrong, than getting no errors and wondering why it isn’t working because you designed it wrongly. You’re already here asking the right questions to avoid the 2nd situation, so don’t let coding intimidate you. It’s easy to look up stuff like Classes etc. in the Scripting tutorials or a million other places on the internet (especially if you use C#).

Anyway, pseudo-code incoming! :slight_smile:

So for the purpose of this example, I’ve make a simple XML structure to represent the type of data you might be using

<Chapter TotalScenes="2">
    <Scene Title="Amazing Castle" NumActions="3" BG="1" Music="5">
        <Desc>The wonderful castle is so pretty it make my face hurt... blah blah blah.</Desc>
        <Action type="0" flag="0">Enter the Castle</Action>
        <Action type="0" flag="0">Punch the Castle</Action>
        <Action type="1" flag="6">Blow up the Castle!</Action>
    </Scene>
    <Scene Title="Evil Forest of Spiders" NumActions="1" BG="5" Music="3">
    ...
    </Scene>
</Chapter>

Some of the data here may or may not be needed. This comes down to the specifics of whatever you use to read your XML into unity. For example, TotalScenes may not be needed as the XML parser will probably hold the Scenes as some form of array that you can get the length from. Since you need this size for creating your data in Unity, I’ve kept it in the example for clarity.

The rest of the data is a very simple representation of the Scene / Action concept. Each Scene has a title, some data to indicate what music and background image you want to use, then a simple text description and actions as child elements. You could expand this to have elements to indicate different character art appearing and moving, effects or sounds firing - pretty much anything you want, as long as you expand your system to handle this data and produce the results inside Unity. A simple example might be replacing Desc with multiple paragraphs of text and including a timing attribute for each one to delay them being displayed.

For the Actions, I’ve included a type and a flag attribute. This allows us to have different types of actions and gives us a place to put any extra data that might be needed. In this example, type 0 simply means it’s an Action that is always displayed (and thus the flag data is ignored), and type 1 means that the Action requires us to have a certain item, where the flag then becomes a unique ID for that item. Type 2 might require a certain quest to be finished and the flag becomes the ID of the quest, or be something else entirely.

On the Unity side of things, these are the Classes that would handle this data:

class Scene {
    //Scene specific data
    string title;
    string desc;
    int background;
    int music;

    Action actions[];

    void SetData (int numActions, string myTitle, string myDesc, int myBG, int myMusic)
    {
        title = myTitle;
        desc = myDesc;
        background = myBG;
        music = myMusic;

        actions[] = new Action[numActions];
    }
}

class Action {
    //Action specific data
    int actionType;
    int actionFlag;

    Scene nextScene;
   
    void SetData (int myType, int myFlag, Scene myScene)
    {
        nextScene = myScene;
        actionType = myType;
        actionFlag = myFlag;
    }
}

At this point they are little more than Data Classes with simple data setting functions, everything from the XML is mirrored in the Class data. Also, in my example I’ve allowed for the number of actions for each Scene to be dynamically created.

Taking in the XML data and creating our Class data would be done somewhere during your setup / loading phase, perhaps like this:

Scene allScenes[];

Initialise () {
    XMLData = GetXMLData;
   
    //Make an array of scenes
    allScenes[] = new Scene[XMLData.TotalScenes];

    //Set scene data
    for (int counter; counter < allScenes.Length(); counter++)
    {
        allScenes[counter].SetData(XMLData.Scenes[counter].NumActions, XMLData.Scenes[counter].Title, ... etc)
       
        //Set action data
        for (int counter2; counter2 < allScenes[counter].actions.Length(); counter2++)
        {
            allScenes[counter].actions[counter2].SetData(XMLData...);
            //Note: For the Scene parameter of SetData you'll want to use the nextScene from the action in the XML as the index into allScenes, and pass that
        }
    }
}

We create the allScenes array using the TotalScenes from our XML data, then simple go through each setting the data, creating the Actions, and setting the action data. Pretty straight forward. The rest of your system then becomes about simply displaying the text / images / flying pigs associated with the current scene and displaying the right Actions to allow the player to move on.

Speaking of the Action Class, one of the benefits of using classes is that we can make them responsible for certain things in our system. So for example we could add this function to our Action class:

//Valid test
bool IsValid (CharData myChar)
{
    if (type == 0)
        return true;

    if (type == 1) {
        if (myChar.HasItem(flag)) {
            return true;
        }
    }

    return false;
}

We pass the Action a link to our character data and let the Action be responsible for checking to see if they should be shown. We’d have to test these type/flag combos somewhere, but by doing it here we keep other parts of our system clean and readable. For example, displaying our Actions could be as simple as this:

//Show Actions
if (TimeToShowAtions){
    for (int counter; counter < allScenes[currentScene].actions.Length(); counter++){
        if (allScenes[currentScene].actions[counter].IsValid(myData)){
            //Create / Enable UI button to let people click this action
        }
    }
}

Of course there are other ways of doing some of the things I’ve done, but perhaps some of this rambling helps shed some light on one way to approach it, and clarifies what I was talking about before. It’s pseudo code and it’s rough, but hopefully it helps.

I’m not typing at 8am this time, so no excuses if I don’t make any sense! :stuck_out_tongue: