Cutscene questions: Getting objects by name, using empty nodes, changing portraits

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
wedgiebee
Posts: 16
Joined: Wed May 25, 2022 6:40 pm

Cutscene questions: Getting objects by name, using empty nodes, changing portraits

Post by wedgiebee »

Hi there!

I'm getting around to setting up some cutscenes, and after setting up my first one I've got a few questions:

1) Strings in SequencerCommands

Relying on object names in SequencerCommands wigs me out a little bit. I'm scared of changing object names later on and forgetting they're being used by dialogue and then not realizing things are broken. I get that this is a writing tool so it makes sense that things are gonna be hooked up in text rather than through references, but it is very new to me!

Maybe it's just a mindset change but do you have any recommendations on best practices since object naming is important now? Or are there other ways of sequencing cutscenes that rely on object references rather than object names?

I see that you can invoke scene events in a node, but for an action like MoveTo, where I'd want to wait to proceed until that action is done (for example: MoveTo(target, mover, 1)->Message(Next); Continue()@Message(Next);), is there a way I can do that with referenced objects instead of object names?

2) Using Empty Nodes

I want to run a cutscene sequence where a character moves from one point to another, but I don't want to show any text during it. To do that I'm running a sequence in an empty node. Is that the correct way to do that? Also, I run SetContinueMode(false); at the start of the empty node to prevent skipping while there's no text. Is there a way to default to that behavior for all empty nodes, so that I can't skip the moments where there's no text? Also I have SetContinueMode(true); as the default sequence in the DialogueSystemController.

3) Changing actor portraits and also Spine

I want to set a different portrait for one of my actors on certain lines. I've added a few more portrait sprites to his actor's definition in the database. But it looks like the SetPortrait() sequencer command expects a textureName, when I'd expect to just be able to use the desired index of the sprite.

Also - in the same way you can list multiple portrait sprites in an actor's portrait list, does integrating the Spine integration allow you to do the same thing but with Spine animations?
User avatar
Tony Li
Posts: 21678
Joined: Thu Jul 18, 2013 1:27 pm

Re: Cutscene questions: Getting objects by name, using empty nodes, changing portraits

Post by Tony Li »

Hi,
wedgiebee wrote: Fri Dec 01, 2023 11:56 pm1) Strings in SequencerCommands
Yes, this was a big point of debate, but ultimately text works better for many reasons such as being able to import from other writing tools such as articy:draft and Twine.

Use the special keywords and markup tags as much as possible. The most useful ones are:
  • speaker: The GameObject that's speaking the current dialogue entry. (The dialogue entry's Actor dropdown.)
  • listener: The GameObject that the speaker is addressing. (The dialogue entry's Conversant dropdown.)
  • speakerportrait & listenerportrait: The Portrait Image UI elements of the speaker and listener.
  • [var=variable]: Markup tag that gets replaced by a DS variable's value.
  • [lua(code)]: Similar to the [var] tag, but for arbitrary Lua code. (You can hook your own C# code into Lua, too.)
  • entrytag: Unique identifier for dialogue entry. (See: entrytags)
Example:

Code: Select all

LookAt(speaker, listener);
LookAt(listener, , 1);
MoveTo(listener, , 2)@1;
AudioWait(entrytag)@2
The first line rotates the listener to immediately face the speaker.
The second line rotates the speaker (the default subject) to face the listener over 1 second.
The third line moves the speaker (the default subject) to the listener over 2 seconds starts at the 1-second mark.
The fourth line plays an audio clip named by the dialogue entry's entrytag through the speaker's Audio Source, at the 2-second mark.
wedgiebee wrote: Fri Dec 01, 2023 11:56 pm2) Using Empty Nodes
I think you might have already solved this on Discord, but yes - a node with empty text is fine. Use HidePanel() or SetDialoguePanel(false) if you need to hide other UIs.
wedgiebee wrote: Fri Dec 01, 2023 11:56 pm3) Changing actor portraits and also Spine
SetPortrait() also accepts indices. Example:

Code: Select all

SetPortrait(speaker, pic=2)
If you only want to change the portrait image for a single dialogue entry, you can use the [pic=#] markup tag in the text instead of using a sequencer command:
  • Dialogue Text: "Haha! Great joke. [pic=2]
BTW, in either case, you can use variables if that helps. For example, say you've set the DS variable LaughingPic to 2. Then you can use:

Code: Select all

SetPortrait(speaker, pic=[var=LaughingPic])
or:
  • Dialogue Text: "Haha! Great joke. [pic=[var=LaughingPic]]
If you're using animated portraits, use the speakerportrait/listenerportrait special keywords:

Code: Select all

AnimatorPlay(Laughing, speakerportrait)
wedgiebee wrote: Fri Dec 01, 2023 11:56 pmAlso - in the same way you can list multiple portrait sprites in an actor's portrait list, does integrating the Spine integration allow you to do the same thing but with Spine animations?
Yes. :-)
wedgiebee
Posts: 16
Joined: Wed May 25, 2022 6:40 pm

Re: Cutscene questions: Getting objects by name, using empty nodes, changing portraits

Post by wedgiebee »

Thanks so much for the thorough info! Keywords and markup tags are a great tip, I wasn't using those.
I think you might have already solved this on Discord, but yes - a node with empty text is fine. Use HidePanel() or SetDialoguePanel(false) if you need to hide other UIs.
Ok good to know! I'm actually not on the Discord so I think someone else and I just had the same question! If I did need to use HIdePanel() and SetDialoguePanel(false), is there a way to set that as the default behavior for any node with empty text?
User avatar
Tony Li
Posts: 21678
Joined: Thu Jul 18, 2013 1:27 pm

Re: Cutscene questions: Getting objects by name, using empty nodes, changing portraits

Post by Tony Li »

A node with empty text shouldn't open a closed subtitle panel. But if the subtitle panel is already open (e.g., set to Always From Start, Until Superceded, etc.) then a node with empty text won't close it either. If you need to automatically close a subtitle panel in this case, you could add a script with an OnConversationLine(Subtitle) method to the Dialogue Manager. If it's not the START entry (id==0) and the subtitle text is blank, hide the subtitle panel. Something like:

Code: Select all

void OnConversationLine(Subtitle subtitle)
{
    if (subtitle.dialogueEntry.id > 0 && string.IsNullOrEmpty(subtitle.formattedText.text))
    {
        DialogueActor dialogueActor;
        var panel = DialogueManager.standardDialogueUI.conversationUIElements.standardSubtitleControls.GetPanel(subtitle, out dialogueActor);
        panel.Close();
    }
}
wedgiebee
Posts: 16
Joined: Wed May 25, 2022 6:40 pm

Re: Cutscene questions: Getting objects by name, using empty nodes, changing portraits

Post by wedgiebee »

Thanks! I realize my issue wasn't the closed subtitle panel getting opened - it was that I wanted the continue button to automatically deactivate (and not be waited for) during lines that contain a sequence but no text. Then, when this "purely cutscene" line is done and another text line starts, I wanted the continue button to automatically reactivate. I used your advice with OnConversationLine and put this code in a script on the Dialogue Manager:

(in case it helps anyone else with a similar issue)

Code: Select all

    private bool _thisLineHasNoText;
    
    void OnConversationLine(Subtitle subtitle)
    {
        if (subtitle.dialogueEntry.id > 0 && string.IsNullOrEmpty(subtitle.formattedText.text))
        {
            _thisLineHasNoText = true;
        }
        else
        {
            _thisLineHasNoText = false;
        }
    }

    void OnSequenceStart(Transform actor)
    {
        if (_thisLineHasNoText)
        {
            _thisLineHasNoText = false;
            SetContinueMode(false);
        }
        else
        {
            SetContinueMode(true);
        }
    }

    // based on code in HandleSetContinueModeInternally() in Sequencer.cs
    private void SetContinueMode(bool value)
    {
        DialogueManager.displaySettings.subtitleSettings.continueButton = value ? DisplaySettings.SubtitleSettings.ContinueButtonMode.Always : DisplaySettings.SubtitleSettings.ContinueButtonMode.Never;
            
        // If a conversation is open, update its continue button mode immediately:
        if (DialogueManager.conversationView != null)
        {
            if (DialogueManager.conversationView.displaySettings.conversationOverrideSettings != null)
            {
                DialogueManager.conversationView.displaySettings.conversationOverrideSettings.continueButton = DialogueManager.displaySettings.subtitleSettings.continueButton;
            }
            DialogueManager.conversationView.SetupContinueButton();
        }
    }
User avatar
Tony Li
Posts: 21678
Joined: Thu Jul 18, 2013 1:27 pm

Re: Cutscene questions: Getting objects by name, using empty nodes, changing portraits

Post by Tony Li »

Thanks for sharing!
Post Reply