Animation Duration
Animation Duration
Hello,
I am using the integration with Rogo Digital's Lipsync Pro. In a scene where the NPC is speaking with a lipsync and with a sequencer camera, I am also using AnimatorPlay(Talk, NPC) to play a talk animation. However, the animation is longer than the speech itself, and I am looking for a way to limit the duration of the talk animation to each speech, and crossfade to an idle towards the end of the speech. Without crossfade the transition to idle animation is very abrupt, and if I turn on the crossfade it will still wait until the talk animation is also over, which will linger into the next speech node.
I also tried to integrate the talk animations using the gesture component of Lipsync Pro. However, it also does not have a stop animation feature, and I run into the same problem where the animation transitions into the new node.
Is there an easy way to contain each talk animation within that speech node?
I am using the integration with Rogo Digital's Lipsync Pro. In a scene where the NPC is speaking with a lipsync and with a sequencer camera, I am also using AnimatorPlay(Talk, NPC) to play a talk animation. However, the animation is longer than the speech itself, and I am looking for a way to limit the duration of the talk animation to each speech, and crossfade to an idle towards the end of the speech. Without crossfade the transition to idle animation is very abrupt, and if I turn on the crossfade it will still wait until the talk animation is also over, which will linger into the next speech node.
I also tried to integrate the talk animations using the gesture component of Lipsync Pro. However, it also does not have a stop animation feature, and I run into the same problem where the animation transitions into the new node.
Is there an easy way to contain each talk animation within that speech node?
Re: Animation Duration
Hi,
If you're comfortable with a little bit of scripting, I recommend making a copy of SequencerCommandLipSync.cs. Maybe call it SequencerCommandLipTalk.cs. If so, the sequencer command to use would be LipTalk() instead of LipSync().
The last line of code in the script's Start() method is:
You could add some code like this to transition to an idle state 0.5 seconds before the end of the audio clip:
If you're comfortable with a little bit of scripting, I recommend making a copy of SequencerCommandLipSync.cs. Maybe call it SequencerCommandLipTalk.cs. If so, the sequencer command to use would be LipTalk() instead of LipSync().
The last line of code in the script's Start() method is:
Code: Select all
if (nowait) Stop();
Code: Select all
if (nowait) Stop();
yield return new WaitForSeconds(audioClip.length - 0.5f); // 0.5 seconds before the end...
subject.GetComponent<Animator>().CrossFade("Idle", 0.5f); // ...cross fade to Idle.
Re: Animation Duration
I think I can handle that much coding
I greatly appreciate it. I hope to share the updated snippet of a conversation on twitter today.
I greatly appreciate it. I hope to share the updated snippet of a conversation on twitter today.
Re: Animation Duration
Sounds good. I'll be back online in about 2 hours if you have any questions about it.
What's your Twitter?
What's your Twitter?
Re: Animation Duration
Ok, so much for being able to handle "that much of coding".
I got the following compiler error and I am not sure if I actually did it wrong. I placed it inside the Start() method under "if (nowait) Stop();".
Assets/Pixel Crushers/Dialogue System/Third Party Support/LipSync Support/Scripts/SequencerCommandLipTalk.cs(26,21): error CS1624: The body of `PixelCrushers.DialogueSystem.SequencerCommands.SequencerCommandLipTalk.Start()' cannot be an iterator block because `void' is not an iterator interface type
I got the following compiler error and I am not sure if I actually did it wrong. I placed it inside the Start() method under "if (nowait) Stop();".
Assets/Pixel Crushers/Dialogue System/Third Party Support/LipSync Support/Scripts/SequencerCommandLipTalk.cs(26,21): error CS1624: The body of `PixelCrushers.DialogueSystem.SequencerCommands.SequencerCommandLipTalk.Start()' cannot be an iterator block because `void' is not an iterator interface type
Re: Animation Duration
Sorry, I glossed over that. And even the explanation will sound like gibberish to non-programmers: to use the yield keyword, you need to make the Start method a coroutine by changing "void Start" to "IEnumerator Start", which also requires that you include "System.Collections" in the using statements at the top of the script.
In other words, add this line to the top of the script:
And also change this line:
to this:
Here's the whole script:
I should have also mentioned that this line:
assumes that you want to play the animator state named "Idle". And of course it assumes that it should start crossfading into that state in the last 0.5 seconds.
In other words, add this line to the top of the script:
Code: Select all
using System.Collections;
Code: Select all
public void Start()
Code: Select all
public IEnumerator Start()
SequencerCommandLipTalk.cs
Code: Select all
using System.Collections;
using UnityEngine;
using RogoDigital.Lipsync;
namespace PixelCrushers.DialogueSystem.SequencerCommands
{
public class SequencerCommandLipTalk : SequencerCommand
{
private LipSync lipSync = null;
private AudioClip audioClip = null;
private bool nowait = false;
public IEnumerator Start()
{
var lipSyncAssetName = GetParameter(0);
var lipSyncData = DialogueManager.LoadAsset(lipSyncAssetName, typeof(LipSyncData)) as LipSyncData;
var subject = GetSubject(1, Sequencer.Speaker);
lipSync = (subject == null) ? null : subject.GetComponentInChildren<LipSync>();
nowait = string.Equals(GetParameter(2), "nowait", System.StringComparison.OrdinalIgnoreCase);
if (lipSync == null)
{
if (DialogueDebug.LogWarnings) Debug.LogWarning("Dialogue System: Sequencer: LipSync(" + GetParameters() + "): LipSync subject not found");
Stop();
}
else if (lipSyncData == null)
{
if (DialogueDebug.LogWarnings) Debug.LogWarning("Dialogue System: Sequencer: LipSync(" + GetParameters() + "): LipSync Data not found");
Stop();
}
else
{
if (DialogueDebug.LogInfo) Debug.Log("Dialogue System: Sequencer: LipSync(" + lipSyncData + ", " + lipSync + (nowait ? ", nowait" : string.Empty) + ")");
lipSync.Play(lipSyncData);
audioClip = lipSyncData.clip;
if (nowait) Stop();
yield return new WaitForSeconds(audioClip.length - 0.5f); // 0.5 seconds before the end...
subject.GetComponent<Animator>().CrossFade("Idle", 0.5f); // ...cross fade to Idle.
}
}
public void Update()
{
if (DialogueTime.IsPaused)
{
if (!lipSync.IsPaused) lipSync.Pause();
}
else
{
if (lipSync.IsPaused) lipSync.Resume();
if (!lipSync.IsPlaying)
{
Stop();
}
}
}
public void OnDestroy()
{
if (lipSync == null) return;
if (nowait) return; // If nowait, don't manually stop.
if (lipSync.audioSource != null && lipSync.audioSource.clip != audioClip) return; // If already playing a different clip, don't stop it.
lipSync.Stop(true);
}
//// If you want to debug LipSync, uncomment the method below:
//private void OnGUI()
//{
// if (lipSync.IsPlaying) GUILayout.Label("LipSync.IsPlaying");
// if (lipSync.IsPaused) GUILayout.Label("LipSync.IsPaused");
//}
}
}
Code: Select all
subject.GetComponent<Animator>().CrossFade("Idle", 0.5f); // ...cross fade to Idle.
Re: Animation Duration
I appreciate taking the time to explain all of that and also prepare the script completely. I will implement it and check the results.
Now that I have taken the continue button out entirely (since given the voice-overs, it is not very necessary) and dialogues transitioning from one to the other, the animation continuing to the next one may also become less of an issue. I think I will set the delay to 0.1 seconds and ensure that animations do not transition to the next sequence.
Thank you so much.
Now that I have taken the continue button out entirely (since given the voice-overs, it is not very necessary) and dialogues transitioning from one to the other, the animation continuing to the next one may also become less of an issue. I think I will set the delay to 0.1 seconds and ensure that animations do not transition to the next sequence.
Thank you so much.
Re: Animation Duration
Glad to help! Strings of Ambivalence is looking better every day.
Re: Animation Duration
Thank you Tony. I really enjoy working on SOA. DSU is adding a great deal to this enjoyment. Many of the things DSU enables are things that I could only dream of doing a while ago.
I just noticed that if I leave the dialogue skip key enabled, it seems to bypass some of the sequence commands, namely the ones that I designated to work at a certain @time after that node begins, or the 0.5 second before the end of the node delay in the new modified script. This may end up causing the the animation to continue playing even after UCC is supposed to take over, so the character will be playing talking animation while walking.
I connected the talking animations back to idle, so it eventually turns to normal. But I was wondering if there was a workaround for this.
Thank you.
I just noticed that if I leave the dialogue skip key enabled, it seems to bypass some of the sequence commands, namely the ones that I designated to work at a certain @time after that node begins, or the 0.5 second before the end of the node delay in the new modified script. This may end up causing the the animation to continue playing even after UCC is supposed to take over, so the character will be playing talking animation while walking.
I connected the talking animations back to idle, so it eventually turns to normal. But I was wondering if there was a workaround for this.
Thank you.
Re: Animation Duration
Hi,
Yup, add the special keyword "required" in front of any sequencer commands that are required to run even if the player skips early.
Yup, add the special keyword "required" in front of any sequencer commands that are required to run even if the player skips early.