Page 1 of 3

Writing Custom Sequencer for Movement

Posted: Fri Jan 03, 2020 8:54 pm
by Mackerel_Sky
Hi,

I'm looking at trying to make a cutscene with Dialogue System now and had a couple of questions regarding sequencer commands.

1.
I'm trying to write a custom sequencer command that will interact with the game's physics engine to enable an NPC to walk to a certain point in the middle of a conversation I'm not sure how to do this- I understand from the documentation that there is a GetParameter command but I'm not really sure how to use it. I know I need to get a reference to a input component in the NPC that controls its movement.

2.
I haven't really looked into getting this working yet, but I'd like to play/loop two different animation states within one dialogue node. For example, the NPC says a line, then starts mining or something. The two animation states I need is a 'windup' or preparatory animation that transitions into a looping mining animation. I've managed to get animations to play using the AnimatorPlay function but haven't really done any research on getting this to work aside from looking at the documentation.

Any wisdom you might have on this is appreciated. Thanks!

Re: Writing Custom Sequencer for Movement

Posted: Fri Jan 03, 2020 9:23 pm
by Tony Li
Hi,

I'll answer #2 first, since you can do that without writing a custom sequencer command. Let's say the animations are in an animator controller, and the animation states are named "MiningWindup" and "Mining".

You could always create a transition in your animator controller from MiningWindup to Mining. Then you'd simply need to play MiningWindup with a Sequence like this:

Code: Select all

AnimatorPlay(MiningWindup); {{default}}
I added {{default}} so it would include the Dialogue Manager's Default Sequence, which typically delays for a duration. You can add something else if you want.

Let's say you have a Boolean animator parameter named "IsMining". When it's true, the animator controller transitions to the MiningWindup state, which then automatically transitions to Mining. When IsMining is false, the Mining state transitions back to Idle. In this case, you'd use a Sequence like this:

Code: Select all

AnimatorBool(IsMining, true); {{default}}
However, if you have neither animator paramters nor transitions, you can control both animations from the Sequence itself:

Code: Select all

AnimatorPlayWait(MiningWindup)->Message(ReadyToLoop);
AnimatorPlay(Mining)@Message(ReadyToLoop);
{{default}}
The first command plays the MiningWindup state and waits for it to finish. When it's finished, it sends an arbitrary message ("ReadyToLoop") to the sequencer. The second command waits for the sequencer to receive the message "ReadyToLoop"; then it plays the Mining state.

You can also send messages to the sequencer from your own C# code. Let's say you want the NPC to stay on that node until they mine a gold nugget. You can set the Sequence to something like:

Code: Select all

AnimatorPlay(MiningWindup);
SendMessage(StartMining);
AnimatorPlayWait(Celebrate)@Message(GotNugget)
In this example, the first command plays MiningWindup; I'll assume it transitions automatically to the Mining loop. I'll explain the second command in a moment. The third command waits for the sequencer to receive the message "GotNugget". Then it plays an animator state named "Celebrate". At this point the sequence ends, so the conversation can proceed to the next node.
The second command uses Unity's SendMessage method to call any method named StartMining() on any scripts on the NPC. Let's say you have a script with a StartMining() method that delivers a gold nugget after a random duration. When it delivers the gold nugget, use Sequencer.Message("GotNugget") to tell the sequencer. The C# method might look like:

Code: Select all

public void StartMining()
{ 
    Invoke("GenerateNugget", Random.Range(1, 5); 
}
void GenerateNugget()
{
    // <your code here to spawn a gold nugget>
    PixelCrushers.DialogueSystem.Sequencer.Message("GotNugget");
}
This is total aside: (Even more than the asides above! ;) )
If you want to get super fancy, let's say the NPC cycles through several jobs (mining, hauling, stretching, etc.). You could put the job's animator state name in a Dialogue System variable. Let's say that variable is named "currentJob". Then you can use a Sequence like this:

Code: Select all

AnimatorPlay([var=currentJob]); {{default}}
The special tag [var=currentJob] will be replaced by the value of the currentJob variable. You can get even more elaborate and use the [lua(code)] tag to replace it with the result of any Lua code, even your own C# methods that you've registered with Lua.

Re: Writing Custom Sequencer for Movement

Posted: Fri Jan 03, 2020 9:26 pm
by Tony Li
To answer #1:
To make a custom sequencer command, copy the template from Plugins / Pixel Crushers / Dialogue System / Templates / Scripts. Fill in your code where indicated.

These functions are available in your script: SequencerCommand

Skip past all the "Inherited by" text until you get to the "Protected Member Functions" section.

If you want to get the first parameter as a string:

Code: Select all

string firstParameter = GetParameter(0);
If you want to get it as an integer:

Code: Select all

int firstParameter = GetParameterAsInt(0);
If you want a reference to the node's speaker GameObject, it's the speaker property.

Re: Writing Custom Sequencer for Movement

Posted: Sat Jan 04, 2020 7:54 am
by Mackerel_Sky
Hey Tony,

I was able to generate the custom command using the template but I'm still a little bit confused about the parameters right now. How do they work in particular? I'm not really understanding how I can generate parameters and use them to interface with the component I need. Actually, I'm not really sure what a parameter is right now :V

Could you go into a bit more detail as to what I need to do?

Thanks

Re: Writing Custom Sequencer for Movement

Posted: Sat Jan 04, 2020 8:13 am
by Tony Li
Hi,

When you enter a command like this in the Script field of a node:

Code: Select all

SetActive(ForceField, true)
The values "ForceField" and "true" are parameters. "ForceField" is parameter 0 and "true" is parameter 1.

The C# implementation of the SetActive sequencer command looks a bit like this:

Code: Select all

void Awake()
{
    string subjectName = GetParameter(0); // Get parameter 0 as a string.
    bool value = GetParameterAsBool(1); // Get parameter 1 as a bool.
    GameObject subject = GameObject.Find(subjectName);
    subject.SetActive(value);
}
The actual implementation is different. I simplified it above for clarity.

Re: Writing Custom Sequencer for Movement

Posted: Sat Jan 04, 2020 6:39 pm
by Mackerel_Sky
Hey Tony,

Thanks for clearing that up. I think I understand how to use parameters now. I had issues with getting the controller component to reference properly but moving the script into a different folder fixed it for some reason.

Thanks!

Re: Writing Custom Sequencer for Movement

Posted: Sat Jan 04, 2020 10:21 pm
by Tony Li
Strange that moving the file got it to reference properly, but maybe it just needed a recompile. Anyway, glad it's working now!

Re: Writing Custom Sequencer for Movement

Posted: Sun Jan 05, 2020 5:27 am
by Mackerel_Sky
Just a couple more questions regarding the sequencer, I've managed to get the character to walk as required. I also turned the dialogue panel off with SetDialoguePanel(false) while they were walking and it was great to see that the conversation didn't end when the panel went away.

However I'd like to progress it to the next node of the conversation once they have finished walking and restore the panel once this is done. I tried using the messages as covered in the documentation. The sequencer command looks like this.

Code: Select all

WalkToPoint(Owen, 1, 4, true);
SetDialoguePanel(false);
SetDialoguePanel(true)@Message(FinishedWalking);
Continue()@Message(FinishedWalking)
However when the message sends Unity throws an error: Coroutine couldn't be started because the the game object 'Subtitle Panel' is inactive!

Do you have any ideas?

Re: Writing Custom Sequencer for Movement

Posted: Sun Jan 05, 2020 9:12 am
by Tony Li
Hi,

If you're not using version 2.2.4, please back up your project and update. I believe that was fixed in 2.2.4.

Re: Writing Custom Sequencer for Movement

Posted: Mon Jan 06, 2020 3:56 am
by Mackerel_Sky
Hey,

I've updated to 2.2.4 as required. The debug error went away but the issue persists. I can see that the next node of the conversation is indeed highlighted, it's just not showing up.