Animator Controller not set on custom portrait images

Announcements, support questions, and discussion for the Dialogue System.
User avatar
Tony Li
Posts: 22055
Joined: Thu Jul 18, 2013 1:27 pm

Re: Animator Controller not set on custom portrait images

Post by Tony Li »

I attached a patch to my email reply. The fix will also be in the upcoming version 2.2.5.
VoodooDetective
Posts: 222
Joined: Wed Jan 22, 2020 10:48 pm

Re: Animator Controller not set on custom portrait images

Post by VoodooDetective »

Thank you so much! Works perfectly.
michaelheiml
Posts: 46
Joined: Thu Nov 08, 2018 5:47 am

Re: Animator Controller not set on custom portrait images

Post by michaelheiml »

Hi Tony,

I think I run into the same issue, could you please send me the patch as well?

Thanks
Michael
User avatar
Tony Li
Posts: 22055
Joined: Thu Jul 18, 2013 1:27 pm

Re: Animator Controller not set on custom portrait images

Post by Tony Li »

Hi Michael,

Here it is:

DS_SubtitleAnimatorPatch_2020-02-04.unitypackage

(Note for future readers: If you're using version 2.2.5+, you don't need this patch.)
michaelheiml
Posts: 46
Joined: Thu Nov 08, 2018 5:47 am

Re: Animator Controller not set on custom portrait images

Post by michaelheiml »

Hi Tony, thanks, the animated portrait works BUT: (I *shortcut* hijack this thread, maybe my "follow-up issue" is related)

Issue: I have 3 NPCs with animated portraits, but it's always the same (first-line-talking) NPC of which the portrait is animated (in my case, eyes+mouth movement) where it should be the currently speaking NPC.

Setup
- 3 NPCs ("Dialogue Actors"), using "Subtitle Panel Number:Custom" (referencing to 1 same prefab, a speech bubble)
- speech bubble: correctly referencing "portrait" (GO) including animator with "Idle" and "Talking" animation (Animator "wiring" as in your posted example)
- each "Dialogue Actors" NPC links to it's own "Portrait Animator Controller" (so one Controller for each NPC, using Idle and Talking)
- DialogueManager Default Sequence is set to (and not overwritten in dialogue):
AudioWait(entrytaglocal, speaker, silence_1s); //unrelated, for typewriter/audiofile
AnimatorPlay(Talking, portrait); //Talking animation, GO name in the speech bubble prefab is "portrait"
AnimatorPlay(Idle, portrait)@{{end}}; //Idle animation, GO = "portrait"

Whatever I change in the settings, it's always the NPC that talks the first line whose portrait is animated, its' even animated when the "other" NPCs are "saying" a line (their portraits' animation should be playing then but they aren't).

Am I overseeing something or is this a bug? Please help :)
User avatar
Tony Li
Posts: 22055
Joined: Thu Jul 18, 2013 1:27 pm

Re: Animator Controller not set on custom portrait images

Post by Tony Li »

Hi,

I think your situation is different.

Normally you only need to use the Dialogue Actor's Dialogue UI Settings > Portrait Animator Controller if you will use the same subtitle panel for different characters. For example, the dialogue UI in the tutorial video could have different characters in these positions throughout the game:



Each subtitle panel's portrait image has a unique name, such as 'Portrait Image 1', 'Portrait Image 2', etc. The AnimatorPlay() sequencer commands refer to each portrait image by its unique name.

---

In your case, each character has its own speech bubble subtitle panel. It does not have to share its subtitle panel with any other characters.

In this case, you can add an instance to each character instead of using the prefab. Or you can make a prefab variant for each character. Either way, each character's portrait image should have a unique GameObject name. Here is an example:

BubblePortraitAnimationExample_2020-02-10.unitypackage

In this example, I created 3 characters named 'NPC1', 'NPC2', and 'NPC3'.

NPC1's speech bubble subtitle panel has a portrait image named 'NPC1 Portrait'.

The example conversation uses this Sequence:

Code: Select all

AnimatorPlay(Talk, NPC1 Portrait);
AnimatorPlay(Idle, NPC1 Portrait)@{{end}}
---

Optional bonus note: If you want to make the Sequences more generic, you can use [var=Actor] and [var=Conversant] tags. For example, NPC2's node has this Sequence:

Code: Select all

AnimatorPlay(Talk, [var=Actor] Portrait);
AnimatorPlay(Idle, [var=Actor] Portrait)@{{end}}
Since NPC2 is assigned as the conversation's Actor, at runtime the Sequence will be equal to:

Code: Select all

AnimatorPlay(Talk, NPC2 Portrait);
AnimatorPlay(Idle, NPC2 Portrait)@{{end}}
michaelheiml
Posts: 46
Joined: Thu Nov 08, 2018 5:47 am

Re: Animator Controller not set on custom portrait images

Post by michaelheiml »

Hi Tony,

thanks for your quick reply. (and sorry for hijacking this thread, maybe we should move to a new one?)

Anyways, unfortunately I run into several issues with the provided solution :(

1. If importing the package to a new Unity (2019.3.0f6) project, the conversation works, but:

1a. if I change e.g. Sequence "NPC3 Portrait" to the suggested "[var=Actor] Portrait", it does not work (I assume it's because getting the Actor variable always returns the dialogues "Actor" which is "NPC 2" for the entire conversation where it should change based on who is speaking, in this case "NPC 3")

1b. this leads me to the 2. problem: if I now change the conversations' Actor from NPC2 to NPC3 (and due to this change correct sentence 2 to "Actor NPC2 - Conversant NPC1")I get the warning "Game Object with animator is inactive" when NPC2 should say its line (I assume this is because [var=Actor] does not work on NPC2 now that the conversations' Actor is NPC3).

1c: this leads me to a more general issue; for several reasons it would be very unpractical if I needed to define a custom sequence for each sentence referencing to a static GameObject name (as it would be required to solve 1a+1b when changing the conversation Actor to NPC3 and then its only possible to use [var=Actor] for NPC3 whereas "NPC1 Portrait" and "NPC2 Portrait" now have to be static strings).. with other words, for each actor that is not the conversations' actor, I would need to add a custom sequence referencing to a static game object name, which can easily become a big problem later on if changes are needed..

-> what I'd like to do (for many other simplification reasons) is to use the "Default Sequence" in "Camera & Cutscene Settings" (no custom sequence on each sentence) where I put in "AnimatorPlay(Talk, speaker);AnimatorPlay(Idle, speaker)@{{end}}" - but when I do this (and remove the Sequence in each sentence) I only get the warnings "Animator.GotoState: State could not be found" followed by "Invalid Layer Index '-1'" (when Debug.Log Sequencer.cs line 1396 "subject", I get e.g. "NPC1" Transform and not "NPC1 Portrait" of course, because NPC1 is the speaker) - would there be a way to access the "NPC1 Portrait" in the "Default Sequence" ?

2. Assuming (1) can be solved via the "Default Sequence", I would run into another even bigger issue with the suggested solution: I have many actors (for now 3, but they will go up to 10-20 and eventually be hundreds) and many different speech bubble prefabs (currently 23, defined by their shapes like angry, whisper.. and some unique settings) re-used on many "pages" (imagine a series of books). If I would need to have a prefab variant for each actor and each speech bubble, I would at least now already need 3 x 23 = 69 prefab variants for uniquely naming the portrait according to your suggestion ("NPC3 Portrait" and so forth..) and with each newly introduced actor, this would grow fast. Plus, I prefer the "instancing prefab" way of a speech bubble over having all of them in the scene (e.g. because the speech bubble does some internal setup on instancing and positions itself based on the Actors anchor - I would need to do this for all many speech bubbles manually if I do not use the "instance way").
-> so I really would like to keep it that way that 1 speech bubble shape gets instanced and has the same "Portrait Image" GameObject name (=portrait) independent from the actual speaker that speaks via the bubble.

Since the "Standard UI Subtitle Panel" already knows the "Portrait Image" (and thus where the Animation Controller is), I think it might be a solution to define the animations in the way the "Visibility" animations are defined (so on "Standard UI Subtitle Panel" I define "Talking" and "Idle" as the animations that are played on "Portrait Image" Animation Controller.

Or as another way, using the "Default Sequence", it plays the Animations (Talking, Idle) on the "Portrait Image" Game Object of the instanced speech bubble (+ it doesn't matter that there are several Game Objects with the same name, since its always one speaker that speaks with one "Portrait Image" associated..

I have the feeling that it is a bit hard to describe the exact setup or what I am trying to achieve (or I would need to bother you with even more explanation text :( ... maybe it would be easier if I showed you the setup/problem e.g. via Skype/Screensharing. I have good experiences with that on other Unity Asset Store questions/communication. If that would be an option for you as well, please send me a PN and we could arrange a quick call.

Thanks Michael
michaelheiml
Posts: 46
Joined: Thu Nov 08, 2018 5:47 am

Re: Animator Controller not set on custom portrait images

Post by michaelheiml »

Hi Tony,

I found a workaround (which I am not sure if its a good idea) + but the workaround shows a potential problem itself in Sequencer.cs :

1) As described in my first reply, I'd only like to use the "Camera & Cutscene Settings" "Default Sequence", so instead of adding a sequence command to each sentence in the dialogue, I just added this to the "Default Sequence":
AnimatorPlay(Talking,[lua(Variable["Actor"])]);
AnimatorPlay(Idle,[lua(Variable["Actor"])])@{{end}};
-> as a result, I get the Game Object with DialogueActor class on it

2) This leads to Sequencer.cs line 1396 "subject" being the GameObject with DialogueActor class on it

3) Now, in line 1410 "Animator animator = subject.GetComponentInChildren<Animator>();" searches the children of the DialogueActor GameObject for the Animator Component and it of course finds one, but the wrong one - my speech bubble prefabs that are instantiated contain 2 animation controllers: 1 for the Visibility stuff (Show/Hide/Focus/Unfocus) and the 2nd one being the Animation Controller for the portrait. Unfortunately, a GetComponentInChildren returns the first Animator (Visibility), where it would need the second Animator (portrait GO).

-> my workaround for this potential issue within Sequencer.cs is to access the proper Animator by replacing line 1410 with
"Animator animator = subject.GetComponent<DialogueActor>().standardDialogueUISettings.customSubtitlePanel.portraitImage.gameObject.GetComponent<Animator>();"

-> this accesses the correct Animator that is on the portrait.

With this workaround, I can use the generic default sequence described above and have n speechbubbles instantiated (one for each DialogueActor) where all speechbubbles are the same prefab with only one GameObject Name for the portrait GameObject that is animated.

-> Although this workaround works, I do not 100% like it since I have to change the mentioned line 1410 in Sequencer.cs, and of course if I ever pull a DSFU update I might loose that change (or worse, this change breaks something else in DSFU somewhere completely else). So I was wondering, what are your thoughts on this approach?

(I assume that the "GetComponentInChildren" is not intended to work in a way that it can return the wrong Animator when using both Visibility animations and portrait animations?)
User avatar
Tony Li
Posts: 22055
Joined: Thu Jul 18, 2013 1:27 pm

Re: Animator Controller not set on custom portrait images

Post by Tony Li »

Hi Michael,

That's the way it's intended, because for different customers' UI setups the visibility animator may be in different locations.

I recommend writing a custom sequencer command -- for example called AnimatePortrait. This will make everything much simpler. Your Dialogue Manager's Default Sequence could then look like this:

Code: Select all

AnimatePortrait(Talking);
AnimatePortrait(Idle)@{{end}}
Here's an example:

BubblePortraitAnimationExample_2020-02-13.unitypackage

The sequencer command script looks like this:

SequencerCommandAnimatePortrait.cs

Code: Select all

using UnityEngine;
namespace PixelCrushers.DialogueSystem.SequencerCommands
{

    // Syntax: AnimatePortrait(animatorState, [subject])
    // 
    // - animatorState: The animation state to play.
    // - subject: The character to animate. If omitted, uses the speaker.
    // Subject should have a PortraitAnimatorReference component.
    public class SequencerCommandAnimatePortrait : SequencerCommand
    {
        public void Awake()
        {
            string animatorStateName = GetParameter(0);
            Transform subject = GetSubject(1, speaker);
            if (subject != null)
            {
                var portraitAnimatorReference = subject.GetComponent<PortraitAnimatorReference>();
                if (portraitAnimatorReference != null)
                {
                    portraitAnimatorReference.portraitAnimator.Play(animatorStateName);
                }
            }
            Stop();
        }
    }
}
It uses a tiny script on each NPC that points to the portrait image's Animator:

PortraitAnimatorReference.cs

Code: Select all

using UnityEngine;
public class PortraitAnimatorReference : MonoBehaviour
{
    public Animator portraitAnimator;
}
michaelheiml
Posts: 46
Joined: Thu Nov 08, 2018 5:47 am

Re: Animator Controller not set on custom portrait images

Post by michaelheiml »

Hi Tony,

thanks for your suggestion, I've implemented it that way.

Since I have some other questions about my setup and do not want to further hijack this thread, I've created a new thread here:

https://www.pixelcrushers.com/phpbb/vie ... f=3&t=2937

Thanks,
Michael
Post Reply