Starting conversations without using components
-
- Posts: 33
- Joined: Tue Jul 05, 2016 6:18 pm
Starting conversations without using components
Hey there,
So I'm in a position where using the built in conversation trigger components is undesirable.
1) Each NPC can have potentially hundreds of conversations, and having hundreds of different trigger components attached sounds like bad juju.
2) There are other ways a player can interact with an NPC using the same interact button, depending on context. For example, the player could be holding an item, and in that context hitting the interact button would gift said item instead of starting a conversation. So using the built in trigger would require a different button be used for every type of NPC interaction, and that's not a great user experience.
3) NPCs are dynamically generated for modability, and it would be a better experience to somehow dynamically figure out which conversations an NPC has instead of manually having to create triggers, or in our case manually specifying a list of conversation ids in JSON.
At the moment, NPCs have an Interact method that gets triggered when any other character interacts with it (it can tell player from NPC and such). For early prototyping I just had the method use DialogueManager.StartConversation() with a hardcoded conversation id and a test DB.
Now that I'm beyond the initial prototyping, I instead need to be able to figure out which conversation should be started and that's where I'm not entirely sure how to proceed.
Is there already built in functionality to query the DB to find the first valid conversation for a given NPC, or is this something I need to build out myself?
If the latter, do you have an opinion as to how best accomplish that? Off the top of my head I'm thinking I'd have to parse the DB at game start for every conversation a given NPC starts, and then when interact happens roll through the list testing if the conversations criteria is met (I was thinking of using the first dialogue node's condition inside the conversation to have the conditions for that conversation since I didn't see a formal "conversation conditions" property anywhere other than conversation trigger, which I'm not using) and select the first conversation that passes.
I'm not even sure if that's possible or advisable though, and am totally open to any advice you have.
Thanks!
So I'm in a position where using the built in conversation trigger components is undesirable.
1) Each NPC can have potentially hundreds of conversations, and having hundreds of different trigger components attached sounds like bad juju.
2) There are other ways a player can interact with an NPC using the same interact button, depending on context. For example, the player could be holding an item, and in that context hitting the interact button would gift said item instead of starting a conversation. So using the built in trigger would require a different button be used for every type of NPC interaction, and that's not a great user experience.
3) NPCs are dynamically generated for modability, and it would be a better experience to somehow dynamically figure out which conversations an NPC has instead of manually having to create triggers, or in our case manually specifying a list of conversation ids in JSON.
At the moment, NPCs have an Interact method that gets triggered when any other character interacts with it (it can tell player from NPC and such). For early prototyping I just had the method use DialogueManager.StartConversation() with a hardcoded conversation id and a test DB.
Now that I'm beyond the initial prototyping, I instead need to be able to figure out which conversation should be started and that's where I'm not entirely sure how to proceed.
Is there already built in functionality to query the DB to find the first valid conversation for a given NPC, or is this something I need to build out myself?
If the latter, do you have an opinion as to how best accomplish that? Off the top of my head I'm thinking I'd have to parse the DB at game start for every conversation a given NPC starts, and then when interact happens roll through the list testing if the conversations criteria is met (I was thinking of using the first dialogue node's condition inside the conversation to have the conditions for that conversation since I didn't see a formal "conversation conditions" property anywhere other than conversation trigger, which I'm not using) and select the first conversation that passes.
I'm not even sure if that's possible or advisable though, and am totally open to any advice you have.
Thanks!
Re: Starting conversations without using components
Hi,
You'll need to implement it yourself. This is kind of a disgression, but: the Dialogue System is designed so you can re-use conversations for multiple NPCs, even if you've assigned a specific NPC as the conversation's primary Conversant in the dialogue database. The classic example I use in the documentation is the "shopkeeper" conversation. You can write one conversation and re-use it for shopkeepers in every village in your world. You can use [var=Conversant] to reference the conversant's name in dialogue text, such as:
So, anyway, you'll need to query DialogueManager.MasterDatabase. This property represents the sum of all dialogue databases that have been loaded into memory. In most games, only the database assigned to the Dialogue Manager's Initial Database is loaded. It's much simpler to use one database, and it provides a better workflow with third party editors such as articy:draft and Chat Mapper. (If you're using multiple databases, be sure to read How to Use Multiple Dialogue Databases.)
You can use a single Linq query if you like. Here's a simple proof of concept:
You'll need to implement it yourself. This is kind of a disgression, but: the Dialogue System is designed so you can re-use conversations for multiple NPCs, even if you've assigned a specific NPC as the conversation's primary Conversant in the dialogue database. The classic example I use in the documentation is the "shopkeeper" conversation. You can write one conversation and re-use it for shopkeepers in every village in your world. You can use [var=Conversant] to reference the conversant's name in dialogue text, such as:
- Dialogue Text: "I'm [var=Conversant]. Welcome to my shop!"
So, anyway, you'll need to query DialogueManager.MasterDatabase. This property represents the sum of all dialogue databases that have been loaded into memory. In most games, only the database assigned to the Dialogue Manager's Initial Database is loaded. It's much simpler to use one database, and it provides a better workflow with third party editors such as articy:draft and Chat Mapper. (If you're using multiple databases, be sure to read How to Use Multiple Dialogue Databases.)
You can use a single Linq query if you like. Here's a simple proof of concept:
Code: Select all
using UnityEngine;
using System.Linq;
using PixelCrushers.DialogueSystem;
public class ListActorConversations : MonoBehaviour {
public string actorName;
void Start() {
var actorID = DialogueManager.MasterDatabase.GetActor(actorName).id;
var actorConversations =
from conversation in DialogueManager.MasterDatabase.conversations
where conversation.ConversantID == actorID
select conversation;
foreach (var conversation in actorConversations) {
Debug.Log(conversation.Title);
}
}
}
-
- Posts: 33
- Joined: Tue Jul 05, 2016 6:18 pm
Re: Starting conversations without using components
Thanks for that reply. We're planning on using one DB, or (if it's a supported thing) merging in modded DBs (I'm not entirely sure how we're going to do that yet. We may just output everything to ChatMapper json and load it in, letting mod authors just mess around with json to add dialogue).
The shopkeeper example is still doable if we have generic shopkeeps (right now we're planning to have 0 generic characters), since we can just do a similar query on various generic character names (like "shopkeeper") and add those lines to the stored list.
How would/should I go about handling the conversation conditions? Is there a way to test the first dialogue nodes conditions, or should I instead do some type of customization to add that as a property on conversations?
Basically, excluding event-specific conversations, I'd like to be able to set conditions for conversations to be valid. It's not difficult to iterate through and test the conditions in code, I'm just not sure where the best place to use those conditions is (OOB it would be on the ConversationTrigger as I understand it instead of on the actual conversation).
The shopkeeper example is still doable if we have generic shopkeeps (right now we're planning to have 0 generic characters), since we can just do a similar query on various generic character names (like "shopkeeper") and add those lines to the stored list.
How would/should I go about handling the conversation conditions? Is there a way to test the first dialogue nodes conditions, or should I instead do some type of customization to add that as a property on conversations?
Basically, excluding event-specific conversations, I'd like to be able to set conditions for conversations to be valid. It's not difficult to iterate through and test the conditions in code, I'm just not sure where the best place to use those conditions is (OOB it would be on the ConversationTrigger as I understand it instead of on the actual conversation).
Re: Starting conversations without using components
Hi,
It's supported. (BTW, Chat Mapper format is XML, not JSON.) See How To Import Chat Mapper At Runtime. If you use multiple databases, the internal ID numbers generally need to be unique across them. If you can't otherwise guarantee that they'll be unique, you can use the DatabaseMerger class to merge multiple databases into a single database with unique IDs.tylerwsavatronix wrote:We're planning on using one DB, or (if it's a supported thing) merging in modded DBs (I'm not entirely sure how we're going to do that yet. We may just output everything to ChatMapper json and load it in, letting mod authors just mess around with json to add dialogue).
Use DialogueManager.ConversationHasValidEntry(). There are two versions. One accepts GameObjects for the actor and conversant participants, in case your conditions need to run checks against specific participants.tylerwsavatronix wrote:How would/should I go about handling the conversation conditions? Is there a way to test the first dialogue nodes conditions, or should I instead do some type of customization to add that as a property on conversations?
-
- Posts: 33
- Joined: Tue Jul 05, 2016 6:18 pm
Re: Starting conversations without using components
ChatMapper now supports exporting from jsonTony Li wrote: It's supported. (BTW, Chat Mapper format is XML, not JSON.)
http://www.chatmapper.com/features/
Though I'm guessing DS doesn't yet. Got plans for that to be supported eventually?
Ah, sweet. Thanks much!Use DialogueManager.ConversationHasValidEntry(). There are two versions. One accepts GameObjects for the actor and conversant participants, in case your conditions need to run checks against specific participants.
Re: Starting conversations without using components
Yes, in version 2.0. The minimum Unity version for Dialogue System v1.x is Unity 4.6.5. Dialogue System v2.0 (which is a way down the road) will bump the minimum up to Unity 5.4 to simplify a lot of Unity version-dependent compiler defines and also to take advantage of JsonUtility. Since all features are available with Chat Mapper XML, and it's been battle tested in many games, there isn't a pressing reason to add Chat Mapper JSON support until then.tylerwsavatronix wrote:ChatMapper now supports exporting from jsonTony Li wrote:(BTW, Chat Mapper format is XML, not JSON.)
http://www.chatmapper.com/features/
Though I'm guessing DS doesn't yet. Got plans for that to be supported eventually?
-
- Posts: 33
- Joined: Tue Jul 05, 2016 6:18 pm
Re: Starting conversations without using components
Yeah, I wasn't expecting it in any short term.
We probably won't be putting in that capability for another year or so at a minimum (It's not a thing that's going to be going into the demo we're currently building), and worst case scenario we could just write our own json importer.
But since the plan is to have all modable files make use of json it doesn't make long term sense in our case to have an oddball xml file to deal with, heh.
We probably won't be putting in that capability for another year or so at a minimum (It's not a thing that's going to be going into the demo we're currently building), and worst case scenario we could just write our own json importer.
But since the plan is to have all modable files make use of json it doesn't make long term sense in our case to have an oddball xml file to deal with, heh.
-
- Posts: 33
- Joined: Tue Jul 05, 2016 6:18 pm
Re: Starting conversations without using components
Since I'm trying to do some dependency injection on the class I'm creating to do these things (so I can mock and do unit tests) I have quick question:
Is the DialogueSystemController property DialogueManager.Instance functionally equivalent to the DialogueManager?
I'm assuming it is what the static DialogueManager methods/properties are referencing under the hood and is what I should take in as a dependency (which will allow me to mock it for unit testing), but just want to verify before taking road that's ill advised.
Is the DialogueSystemController property DialogueManager.Instance functionally equivalent to the DialogueManager?
I'm assuming it is what the static DialogueManager methods/properties are referencing under the hood and is what I should take in as a dependency (which will allow me to mock it for unit testing), but just want to verify before taking road that's ill advised.
Re: Starting conversations without using components
Hi,
Yes. Under the hood, the DialogueManager static methods are just wrappers for the DialogueSystemController Instance property.
Yes. Under the hood, the DialogueManager static methods are just wrappers for the DialogueSystemController Instance property.