Getting and sending responses through code

Announcements, support questions, and discussion for the Dialogue System.
Luke
Posts: 9
Joined: Tue Jan 28, 2020 2:24 am

Getting and sending responses through code

Post by Luke »

Hi, I'm struggling to find the relevant info in the documentation for what I'm trying to do. Instead of using a normal menu for responses, I want to:

1. Add text from another source to a dialogue bubble above the player
2. Get the list of available responses to the current dialogue node above the NPC
3. Send one of those responses back as if the player had chosen it
4. Continue to display for a brief time the dialogue entered in step one before displaying the next dialogue from the NPC, and then have both display for a brief time before the player dialogue bubble disappears

Thanks for your time!
User avatar
Tony Li
Posts: 22055
Joined: Thu Jul 18, 2013 1:27 pm

Re: Getting and sending responses through code

Post by Tony Li »

I'll suggest 2 ways you can do this.

1. Add 2 special methods to a script on the Dialogue Manager: OnConversationLine and OnConversationResponseMenu:

Code: Select all

void OnConversationLine(Subtitle subtitle)
{
    // Add text from another source:
    subtitle.formattedText.text += "This is additional text.";
}

void OnConversationResponseMenu(Response[] responses)
{
    StartCoroutine(AutoSelectResponse(responses));
}

IEnumerator AutoSelectResponse(Response[] responses)
{
    // Allow response menu to initialize: (You can make it invisible so player can't see it.)
    yield return new WaitForEndOfFrame();
    // Auto select response 0:
    (DialogueManager.dialogueUI as StandardDialogueUI).OnClick(responses[0]);
}

2. Or make a subclass of StandardDialogueUI and override the ShowSubtitle() and ShowResponses() methods.
  • Override ShowSubtitle() to add your extra text before calling the base.ShowSubtitle.
  • Override ShowResponses() to call OnClick(Response) instead of showing a menu.

Code: Select all

public class MyDialogueUI : StandardDialogueUI
{
    public override void ShowSubtitle(Subtitle subtitle)
    {
        subtitle.formattedText.text += "Some extra text.";
        base.ShowSubtitle(subtitle);
    }
    
    public override void ShowResponses(Subtitle subtitle, Response[] responses, float timeout)
    {
        // Auto select response 0:
        OnClick(responses[0]);
    }
}
Luke
Posts: 9
Joined: Tue Jan 28, 2020 2:24 am

Re: Getting and sending responses through code

Post by Luke »

Thanks!

I think that should work for me for the most part, but I won't have the full text ahead of time for the subtitle, it will be entered by the player bit by bit. Is there a method I can call from another script to update the subtitle as the player enters the text?
User avatar
Tony Li
Posts: 22055
Joined: Thu Jul 18, 2013 1:27 pm

Re: Getting and sending responses through code

Post by Tony Li »

Hi Luke,

You can add a script with an OnConversationLine method that adds text to the subtitle just before it's displayed:

Code: Select all

using PixelCrushers.DialogueSystem;
...
void OnConversationLine(Subtitle subtitle)
{
    subtitle.formattedText += " Here's some extra text at the end of the subtitle.";
}
If you need to change the subtitle text dynamically while it's being displayed, you'll need to change the subtitle text UI element's content. For example, you might be able to do something like this:

Code: Select all

var dialogueUI = DialogueManager.dialogueUI as StandardDialogueUI;
var subtitleText = dialogueUI.conversationUIElements.defaultNPCSubtitlePanel.subtitleText;
subtitleText.text += " I'm adding this text while it's being displayed.";
Then again I'm not sure exactly what your goal is. If the ideas above don't help, please feel free to post some mock-up screenshots that represent what you'd like to do.
Luke
Posts: 9
Joined: Tue Jan 28, 2020 2:24 am

Re: Getting and sending responses through code

Post by Luke »

So I think that second one is almost what I need.

Here's is a screenshot of what my project currently looks like:
Screen Shot.png
Screen Shot.png (208.42 KiB) Viewed 1944 times
I set up the speech bubbles with the method described here, with an instance of the prefab for the subtitle bubble as a child of the player gameobject, and the text element changed to a SuperTextMesh. What I want to happen is that when one of the buttons in the bottom left of the game panel is pressed, the word on that button should be appended to the end of the text currently in the speech bubble.

The subtitle bubble should become visible when the first word is added to it by one of those buttons.
User avatar
Tony Li
Posts: 22055
Joined: Thu Jul 18, 2013 1:27 pm

Re: Getting and sending responses through code

Post by Tony Li »

Hi,

Are those words (I Will Destroy All) defined in a conversation, for example as player nodes? Or are they separate from the conversation? It's probably easier if they're separate from the conversation.

You could add a script with an OnConversationLine method like this to the character:

Code: Select all

public string firstWord; // The text to show in the bubble.

void OnConversationLine(Subtitle subtitle)
{
    subtitle.formattedText.text = firstWord;
}
This will make the subtitle show the value of the 'firstWord' variable.

When the player clicks a button, set the text and start the conversation if it's not already started:

Code: Select all

void OnClickedButton(string word)
{
    wordsText += word + " ";
    if (!DialogueManager.isConversationActive) 
    {
        // If the conversation isn't started yet, set firstWord and start it:
        firstWord = word;
        DialogueManager.StartConversation("Your Conversation");
    }
    else
    {
        // Add a word to the subtitle text on the bubble panel that's a child of the character:
        var mySubtitlePanel = GetComponentInChildren<StandardUISubtitlePanel>();
        mySubtitlePanel.subtitleText += " " + firstWord;
    }
}
Luke
Posts: 9
Joined: Tue Jan 28, 2020 2:24 am

Re: Getting and sending responses through code

Post by Luke »

Thanks!

Combining a few of the things you've suggested, here's what I've got now attached to the Player game object:

Code: Select all

    
    private StandardUISubtitlePanel mySubtitlePanel;
    
    void Start () {
        mySubtitlePanel = GetComponentInChildren<StandardUISubtitlePanel>();
    }
    
    public void PushWord(string word)
    {
            mySubtitlePanel.Open();
            mySubtitlePanel.subtitleText.text += word + " ";
    }
There are some odd things happening with this current setup though.

While the first time I click on the buttons it now acts as I want it to, if the speech bubble is closed by a conversation ending (in this case by moving the player far enough away from the npc), or a conversation starting, It won't open back up. The bubble template game object and its child Main Panel game object reactivate when I click another of the word buttons, but not the children further down in the hierarchy, so nothing actually shows up on screen.

Another odd behavior is that the text in the bubble displays with one character on each line, but if I turn on Best Fit it resizes the text with each new word I add, though it at least isn't a vertical tower of letters anymore. Do you know how I could fix that?

There's also this weird thing where if the NPCs dialogue bubble is opened again anytime after the first time the text in it will be to the bottom right of the bubble and spilling out instead of in the middle like it should be. Or are these problems with Super Text Mesh and I should ask them about this part instead?

Also, I would like the dialogue bubble for the player to not respond to anything like a conversation start or end. Right now it keeps the text content if a new conversation starts, since I set it the visibility to "Always once shown", but it closes the bubble if a conversation ends. I would like for it to be its own separate thing unaffected by other parts of the system until the user submits their input, which I would then like to display like a normal subtitle dialogue, doing the appearing one character at a time thing, and then I'll take the user input text and run some other code on it to choose which of the responses to have actually sent to whatever NPC dialogue is currently open. Could you help me figure out how to do that?

I'm sorry I've not been very good at explaining what I'm trying to do, I feel like I keep moving the goalposts on what I'm asking for. Thanks again for your help so far.
User avatar
Tony Li
Posts: 22055
Joined: Thu Jul 18, 2013 1:27 pm

Re: Getting and sending responses through code

Post by Tony Li »

Hi,

I think you're getting close.

Would you mind jotting down the specs/requirements/intended result again so I have it all clear in my head?
Luke
Posts: 9
Joined: Tue Jan 28, 2020 2:24 am

Re: Getting and sending responses through code

Post by Luke »

Sure.

For context, the general idea is that the player will get a limited, not intuitively helpful set of words to build responses out of to solve dialogue puzzles, frequently with homophones and homonyms of the word selection they get.
  • When a word button is clicked, a dialogue bubble will appear above the player with the word in it that was on the button. If the bubble was already open, the new word should be appended to the end of the line in the dialogue bubble. I will probably change the graphic to a thought bubble to indicate that at this stage a sentence is being put together, but it is not yet being "spoken".
  • This dialogue bubble should stay open no matter what until the player manually closes it or some time after the player submits it, probably with a key or button press.
  • When the player approaches an NPC with dialogue, a dialogue bubble shows up above said NPCs head with some line for the player to respond to. This line stays visible until the player moves too far away or submits a response.
  • When the player dialogue is submitted it will play like a normal line of dialogue with the appearing one character at a time thing. The Dialogue bubble should then stay open for a few seconds.
  • Also when the player dialogue is submitted it will look for any running conversations and get the list of responses. The player input will be compared to the available responses for a match. If there is no match, more stuff will be done to decide what response to send. Once a match is found, that response will be sent to get the next line of dialogue for the NPC.
  • After the dialogue from the player has played the next NPC action is taken.
  • If no conversation was currently running when the player spoke, see if there is an NPC in range to start a new conversation with. If so, the NPC should generate a response to the line of dialogue that the player spoke. That response would be generated based on some other code, and then displayed through the dialogue system.
User avatar
Tony Li
Posts: 22055
Joined: Thu Jul 18, 2013 1:27 pm

Re: Getting and sending responses through code

Post by Tony Li »

Hi,

Thanks for the details. I think it will be easiest to handle the player's word bubble without using a subtitle panel. An example scene is probably worth more words than I can type here.

DS_MagneticWordsExample_2020-02-05.unitypackage

It looks like this:

magneticWordsExample.png
magneticWordsExample.png (43.12 KiB) Viewed 1914 times

On the NPC, I added a Dialogue Actor, bubble subtitle panel, and bubble menu panel. But I made the bubble menu panel invisible by removing its Animator and setting the Canvas Group to Alpha=0, Interactable=false.

On the player, I added a bubble subtitle panel to get the UI elements -- but then I removed all of the Dialogue System components from it. Instead, I added a script named PlayerWordBubble to the player. This script has a few methods:
  • AddWord(string): Adds a word to the bubble. (Called by the word buttons at the bottom of the screen.)
  • ClearWords(): Clears the bubble's text. (Hooked up to the 'X' button.)
  • SubmitResponse(): Checks all open menu panels' response buttons. If it finds a match, it calls the button's OnClick() method. The example conversation's response nodes' Dialogue Text contains a list of space-separated keywords such as "rocks good". SubmitResponse() tries to match the player's words to a response node's keywords.
Post Reply