Sign in to follow this  
AverageJoeSSU

Unity JRPG Dialouge/Chat System...

Recommended Posts

I have been mulling over how i should do a chat system similar to the one seen in final fantasy 7.

 

Rendering it isn't an issue (that part works). Mainly I am concerned with how/where I should store it.

 

Currently my game has a sqlite database that works quite nicely. Also im using unity pro but really that doesnt matter for something like this.

 

I have identified several requirements like:

 

-Dialouge between two characters during a "cutscene", but i do not have notion of cutscenes quite yet. (i suspect it will just be a C# script per cutscene that is fetched by the game although when im not 100% sure)

 

This is triggered by entrance into the scene, and then removed from the database once it is run.

 

-Then there is a conversation when a player talks to an NPC, which can be influenced by the current event going on in the world.

This is triggered by interacting with the NPC.

 

-Then there are other arbitrary triggers that can start a dialouge (ie as the player leaves a scene he is stopped and someone talks, a monster says something before fighting, a treasure chest, a door, etc).

 

My question is general, what fits in my database and what doesn't. Does every bit of dialouge connect to the character that is speaking it? does my table for a piece of dialouge contain foreign keys of all the characters involved? bools of what triggers it (a scene, a trigger, or an interaction with an NPC? Do i record arbitrary triggers in the database so that the game knows a trigger connects to a dialouge?

 

I am not 100% convinced i have the correct approach, any advice or reference material would be great.

 

Thanks,

-J

 

 

 

 

 

Share this post


Link to post
Share on other sites

I personally would aim to make the actual dialog run off of some markup format to allow for an editor.  My approach would be as such...

 

Create a new "Dialogs" table.  Basically id, npc_id, conditions, script.

use npc_id as a reference to the NPC table and the ID of the NPC this dialog is for

use conditions as a varchar(255) index of some major influence words (pre-war, friendly, parents-alive)

 

This would give you a pretty easy means to get a script for a potential dialog scene.  Inside that script I would probably use xml serialized objects that could chain multiple "say -> respond" events.  Basically you could just have each object be a list of conditions, what is said, what your response options are.  Build a little parser that finds the condition matches, display the text get the response and so on.  Something along the lines of...

 

    public class NPCDialogEvent
    {
        // If your not accepting inputs you can use this to chain next dialog event without needing input
        public List<NPCDialogEvent> childEvents = new List<NPCDialogEvent>();

        // This dictionary would serve where you could pass key = value requirements
        public Dictionary<string, string> conditions = new Dictionary<string, string>();

        // This is what is said on this event.
        public string dialogStatement = 'Hello mr player man';

        // If the player says "Yes" to this
        public List<NPCDialogEvent> yesEvents = new List<NPCDialogEvent>();

        // ...
    }

 

 

Basically the idea here is that when you initiate this conversation it would search through the SQL DB and load the NPCDialogEvent object that matches the table's conditions.  Say it's your neighbor, it's pre-war your friendly and your parents are alive.  So the NPCDialogEvent contains a simple little walk through story.  This would be a childEvent.

 

Later on in the game maybe things change and you'll get a different dialog, maybe this time you have to answer some questions.  The dialogStatement would ask a question and display answers.  You would just add conditional NPCDialogEvent's to the respective lists.  When the player chooses an answer, the game would find the best conditional match and go from there.

 

Hopefully that at least gives you some idea's.  May not have been the answer you where looking for but that's the approach I would take.

Share this post


Link to post
Share on other sites

Once upon a time I may have accidentally tripped and fell and landed on a decompiler and happened to see that in their older games Square would trigger the dialog routine with a pointer to the dialog instructions for that particular conversation. Most of the dialog was stored in large groupings littered around the place.

Or so I heard.

I tend not to mess with formal databases, but if you just let the logic sort out which strings are required then you can grab them one at a time as you need them. Does your database allow tiered storage (or whatever it's called)? In other words, can you store a database entry that is a collection of database entries? If so then you could collect your strings into groups appropriate for the NPC/Event/Whatever that you're interacting with.

Edited by Khatharr

Share this post


Link to post
Share on other sites

Hey Guys,

 

Thanks for the replies.

 

You guys present two very different approaches, and I think the first approach is perfect for my first demo/proof, but a hybrid of the two sounds like something i should work towards.

 

When I think about it, script mania ala ff7 totally makes sense, if i really wanted to i could run a script per scene and manage conversations that way. however that seems like it has the possibility of becomming spaghetti code. Thanks for the insight into that! one important fact about that method is it worked well.... lol.

 

I do like the idea of minimizing what is in the database. Perhaps my first iteration could be the first proposal of a treelike structure.

and i could create forms for inserting chat (i actually wanted to extend the unity editor with a tree editor but i just cant make time for that, so a basic form will have to do).

 

On a second iteration of the chat i could add a reference script and then have delegate functions that are called before, after, and during a dialouge like so

 

    public class NPCDialogEvent
    {
        // If your not accepting inputs you can use this to chain next dialog event without needing input
        public List<NPCDialogEvent> childEvents = new List<NPCDialogEvent>();

        // This dictionary would serve where you could pass key = value requirements
        public Dictionary<string, string> conditions = new Dictionary<string, string>();

        public delegate void OnBeforeChat(NPCDialogEvent current);
        public delegate void OnDuringChat(NPCDialogEvent current);
        public delegate void OnAfterChat(NPCDialogEvent current);

        // This is what is said on this event.
        public string dialogStatement = 'Hello mr player man';

        // If the player says "Yes" to this
        public List<NPCDialogEvent> yesEvents = new List<NPCDialogEvent>();

        // ...
    }

this would allow for animations to be played and scripted, while allowing the scripting to be able to hook into the conditions.

Share this post


Link to post
Share on other sites
I had intended to suggest a hybrid approach. Most JRPGs I've seen use a kind of markup language for displaying text with escaped characters representing dialog or timing events and allow a dialog to return state codes indicating user selections in interactive situations. I was just commenting on where to store the data. Like I said, I don't know about formal databases, so whatever's clever in that respect. You guys would know better than me.

If I recall correctly the game I'm thinking of examined the game flags and etc and then just used that to feed the dialog proc a pointer to a starting point. After that the dialog continued in a data-driven style. The markup language included things for displaying character names, triggering sound or music effects, changing the font style, waiting for a keypress, presenting a choice and returning a value or setting a flag/variable based on the selection, etc, etc.

The dialog calls were triggered by 'events' which were NPCs, triggers based on passing a line on the map, treasure chests or other things of that nature. There was some bytecode-style scripting that started when an event was triggered and the dialog call was within the script, so that based on the results of the dialog the game could remove or add characters or items. I was actually surprised how similar it was to the method used in RPG Maker, although it was a lot more optimized since it was a console game (string tables, condition tables instead of embedding everything in the event concerned). Edited by Khatharr

Share this post


Link to post
Share on other sites

Ah yes, and i didnt reply to your comment about database entries, I think the best way would be to keep all NPCDialouge data in one table, and then each entry stores its parent id and any children IDs (hmm) (and maybe its root id for query optimization).

 

The key for that kind of setup is the fetching query that checks conditions, something i'm sure i will not get right the first try.

 

My "API" for my event scripts will likely stem from my main game script, which will provide a set of commands to do the stuff you mentioned.

Edited by AverageJoeSSU

Share this post


Link to post
Share on other sites

The RMXP method was to create a set of 'canned' dialog reactions inside the main game script in a section called "Interpreter". Events had different kinds of triggers that were configurable in the main RMXP UI and those were basically converted into Ruby objects and marshalled for use at runtime. When an event trigger happened the event's internal store of Interpreter commands would get executed, so it was basically a doubly scripted system, which made editing events in the UI very easy but managing events from the Ruby side (which there was no real need for) was very clumsy since the event objects got incredibly complex.

Example of 'Interpreter' method:

class Interpreter
  #--------------------------------------------------------------------------
  # * Show Text
  #--------------------------------------------------------------------------
  def command_101
    # If other text has been set to message_text
    if $game_temp.message_text != nil
      # End
      return false
    end
    # Set message end waiting flag and callback
    @message_waiting = true
    $game_temp.message_proc = Proc.new { @message_waiting = false }
    # Set message text on first line
    $game_temp.message_text = @list[@index].parameters[0] + "\n"
    line_count = 1
    # Loop
    loop do
      # If next event command text is on the second line or after
      if @list[@index+1].code == 401
        # Add the second line or after to message_text
        $game_temp.message_text += @list[@index+1].parameters[0] + "\n"
        line_count += 1
      # If event command is not on the second line or after
      else
        # If next event command is show choices
        if @list[@index+1].code == 102
          # If choices fit on screen
          if @list[@index+1].parameters[0].size <= 4 - line_count
            # Advance index
            @index += 1
            # Choices setup
            $game_temp.choice_start = line_count
            setup_choices(@list[@index].parameters)
          end
        # If next event command is input number
        elsif @list[@index+1].code == 103
          # If number input window fits on screen
          if line_count < 4
            # Advance index
            @index += 1
            # Number input setup
            $game_temp.num_input_start = line_count
            $game_temp.num_input_variable_id = @list[@index].parameters[0]
            $game_temp.num_input_digits_max = @list[@index].parameters[1]
          end
        end
        # Continue
        return true
      end
      # Advance index
      @index += 1
    end
  end

Example of actually setting up an event in the UI:

[attachment=13010:rmxp.JPG]

The improvements in the console game were that the script commands were written in a proprietary bytecode stored in a table. Events were placed on the map and initialized with a specific set of triggers linked to specific entry points in the table. Strings were stored separately in other tables and referenced by the scripts to display dialog. This made the events a lot more lightweight than an RMXP event would be since the logic contained in the event object was very small and just included different entry points to the main logic table.

Edited by Khatharr

Share this post


Link to post
Share on other sites

Not quite sure all of the triggers are really as effective as they might seem.  In actuality the dialog scenes are just text (maybe audio and video interpretations of said text).  Seems like the idea of executing logic based on inputs coming from a dialog scene itself is a bit of an outdated way of doing it.  Try not to consider so many of the possible options that any dialog could have or need and focus more on what your game needs.  Assuming you use good object oriented coding practices it would be easy to get going, even without a database server.

 

Consider your overall design a little more minimalistically.  You are working on a dialog engine for your game, it should be a code library that can be used from an editor and in your game to handle dialog scenes.  Dialog scenes are just a collection of potential conversation points depending on some rather simple conditional statements if you design it right.  With that in mind you would be looking to develop a system that could load a script, compare the conditionals to see if this NPC will even talk to you.  If so scan the collection of child events comparing conditions and select the next event.  Say something, either scan the next collection or wait for a response and scan the next collection. So the basic flow of events for a dialog scene would be...

 

1 Open the dialog file

2 Compare root DialogEvent object's conditions to see if we'll talk

3 If we're going to talk figure out which event in the collection is best (scan through them, compare conditions, somehow pick one)

4 Say something

5 Wait a few seconds or wait for input

- Back to step 3 with the this event's child collection

 

I personally would try to limit any coding you would have to do in the dialog script to make it easier on creating an editor later on and less exposed to hacking.  So the engine at code level would actually do all the comparisons.  The dialog scene conditions would just be key names that refer to a referenced value in the engine and the target value.  If this doesn't cover enough add in a list of advanced conditions that can contain more variables and so on.the key here is that the script file is just all variable references and values.  Then put your code in the engine.  Since the engine will convert the file into an object tree for you, you can then use these lists of variables to calculate scores or select options.  Unless you want to allow the community to add some really off the wall code conditions there's really no reason you can't just use variables as token names, flags and selections.

 

I've always been a fan of JRPG's and have considered doing dialog engines and editors before.  I might be interested in providing a little code and technical assistance if your interested.  You can find all of my relevant contact information on gravidar, feel free to look me up when your around.  http://en.gravatar.com/daniwan

Share this post


Link to post
Share on other sites

I decided to go the scripting route, i sense it is not as scalable and user friendly as some of the other ways, but it gives me the most flexability and i have used C# delegates to provide OnComplete and other methods for the scripts to submit methods to.

Share this post


Link to post
Share on other sites
Scripting should be very user-friendly. That's its purpose. smile.png

It should make content creation a lot easier on you if you go that route. The hard work is in implementing/embedding the interpreter, but once that's done you should be able to create/modify content pretty painlessly.

Share this post


Link to post
Share on other sites

Here's how I store conversations a little Javascript RPG I was working on. It gets the job done, but it doesn't address your triggers issue:

 

{
    'start': {
        'text': "Hello! How are you today?",		
        'responses': [
            { 'text': 'Awesome!', 'next': 'great' },
            { 'text': 'None of your business!', 'next': 'rude' }
        ]
    },
    'great': {
        'text': 'That's great! I'll be going now!', 'next': 'end' }
    },
    'rude': {
        'text': 'I was just trying to be friendly. No reason to be a douche about it.',
        'next': 'end',
        'callback': function (conversation, self, other) { 
            self.updateHostility(other, hostility.HOSTILE);
        }
    }
}

 

Each conversation has a 'start' screen, which is the first dialog screen that will be displayed. Each screen has a set of possible responses, with each response indicating the 'next' screen when that response is selected. Additionally each screen has an optional callback that is invoked when the screen is shown. You may not have the ability to integrate scripts within your dialog definitions, but you could accomplish similar functionality without them:

 

'signal': 'set hostility hostile',
Edited by smr

Share this post


Link to post
Share on other sites
Scripting should be very user-friendly. That's its purpose. smile.png

It should make content creation a lot easier on you if you go that route. The hard work is in implementing/embedding the interpreter, but once that's done you should be able to create/modify content pretty painlessly.

 

Ah you are mistaking me when i say "scripting".... i mean C# unity scripts.... not a script like the above post just mentioned.

 

i just laid out the framework a couple nights ago, before i start laying out the scenes that are going to make up my demo, i need to do my battle system in case i need to make changes to the overall data structures.  I won't know how i feel about the dialouge system until i start scripting dialouge in a week or so.

 

And yes, i suspect having some sort of arbitrary format would be nice for quick edits and quick finds and all around reader friendliness, but visual studio is a pretty nice tool and has search and replace so its not THAT bad, just not very elegant and custom :).

Edited by AverageJoeSSU

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Announcements

  • Forum Statistics

    • Total Topics
      628320
    • Total Posts
      2982056
  • Similar Content

    • By PING YI LIN
      Hi,
      I am an indie game developer from Taiwan.
      This is my game” Wo Yao Da”, which is on sale on Steam now.
      Wo Yao Da video
      Wo Yao Da is a third-person ARPG game, in which the player plays as a tribe warrior and a mysterious weirdo, adventuring in the world of gremlins.

      The tribe warrior is good at using knife, spear, bow and arquebus, and his prototype is the warriors from the Gaoshan Tribe (high mountain tribe) in Taiwan in the early 19th century.

      While the prototype of the mysterious weirdo is the founder of a “special” and new religion. He created a series of “Buddha dance.”
      STAR WARS 莊圓大師
      再掉槍啊
      【莊圓大師 : 對十方世界的復仇】1080p高畫質正式中文預告片,全球搶先上映!(HD)
      He does behave rather differently and in the game, the player attack just like whatever he does in real life, such as rolling on the ground over and over and over… oh yes, that Buddha Dance too, which is something you don’t want to miss.
      I did refer to objects in history for the costumes and buildings, but the story plot is a work of fiction. Please take it lightly and have fun.

      The gremlins in this game looks like this:

      Thank you.
      Steam Page: Wo Yao Da 我要大
    • By Hilster
      Hello 2D Artists,
      I've started making a 2D Puzzle Adventure game for mobile and I'm looking for someone who would want in on creating assets for the game. The core of the programming is pretty much complete, you can walk within the grid laid out and push boxes, when there is an object on top of a pressure pad it will activate the linked objects or if there is one object with multiple linked pressure pads it requires you to activate all points for the object to become active. 

      The level iteration for the game is quick and simple, a Photoshop file that is made of individual pixels that represents objects is put into the game and it creates the level out of those pixels with the assigned objects.
      The objects that need sprites created so far is the character, box, pressure pad, door, trap door, the walls, the stairs and the tiled background.
      I intend to add more objects so the amount I'd like to add will be extended.
      My motivations for posting here is to have something that looks nice to be able to display on my portfolio, so if you're looking for a working game that you can place your art into and improve the look of your portfolio then we're in business.
      Please reply with a few past examples of your art below and I'll be in touch!
    • By thefollower
      Hi
      I have set up my TcpClient to connect to my server and that works fine. But i am a bit confused how i read messages from the network stream with it continuously running via async, without ever closing the connection ?
      My TcpClient Manager class has:
       
      public async Task<bool> Connect(string address, int port) { try { await _tcpClient.ConnectAsync(address, port); IsConnected = true; return true; } catch(Exception e) { Debug.Log(e); return false; } } public async Task<int> Read(byte[] readBuffer) { if (!IsConnected) return -1; using (var networkStream = _tcpClient.GetStream()) { try { var bytesRead = await networkStream.ReadAsync(readBuffer, 0, readBuffer.Length); return bytesRead; } catch (Exception e) { Debug.Log(e); IsConnected = false; return -1; } } }  
      So i thought to just run a co-routine and call Read constantly to get the most recent message, but that doesn't make much sense to me since a co-routine would be blocked with the await. How is this actually done? The MS Docs don't have very good Async examples with the TcpClient class so i don't know fully get how to keep calling Read correctly.
    • By NUITGaming
      Landscaping back ground maid in Unreal 4.18
  • Popular Now