#animation event
1 messages · Page 1 of 1 (latest)
Oh wow, thanks man, I'll go get my laptop soz
just a note, still in a dungeon rn, might take a minute xD
i do have a coroutine version with a CustomYieldInstruction for (what i think) you want
for "wait until the animator finishes playing the current state"
using UnityEngine;
class AnimatorPlaying : CustomYieldInstruction {
Animator animator;
const int startBufferFrames = 2;
public override bool keepWaiting {
get {
if (bufferFrames > 0) {
bufferFrames--;
return true;
} else {
return animator.GetCurrentAnimatorStateInfo(0).normalizedTime < 1;
}
}
}
private int bufferFrames;
public AnimatorPlaying(Animator animator) {
this.animator = animator;
bufferFrames = startBufferFrames;
}
}
Ok so this is basically what I tried doing, if this makes any sense.
I tried to make the transitioning more general this way, instead of my specific use case
Like this is for animations in other levels, whereas in level 1, it's basically only transitioning between the Talking and Waiting states
This is how it worked in my first level, just basic transitions
The events being fired based on signal emitters in unity timeline
!code
📃 Large Code Blocks
Use links to services like:
https://paste.mod.gg/, https://hastebin.skyra.pw/, https://paste.ofcode.org/, https://paste.myst.rs/
📃 Inline Code
Surround code with three backquotes. Not quotation marks.
To format as C#, add cs to the first line:
```cs
// Your code here
```
Add a comment with a line number if there is an error message.
Ah ok, sorry, thought screenshots would be fine
using Cysharp.Threading.Tasks;
using UnityEngine;
public class AnimationController : MonoBehaviour
{
public Animator anim;
private void Awake()
{
anim = GetComponent<Animator>();
GameState.decisionTime += PlayerSpeaking;
GameState.distributeDecision += _ => NPCSpeaking();
GameState.verdictTime += PlayerSpeaking;
}
// Start is called once before the first execution of Update after the MonoBehaviour is created
public virtual void NPCSpeaking()
{
anim.SetTrigger("NPC_Speaking");
}
public void PlayerSpeaking()
{
anim.SetTrigger("Player_Speaking");
}
//public async UniTask StateTransition(string stateName, string triggerName)
//{
// anim.SetTrigger(triggerName);
// while (!anim.GetCurrentAnimatorStateInfo(0).IsName(stateName))
// {
// await UniTask.Yield();
// }
//}
protected void OnDestroy()
{
GameState.decisionTime -= PlayerSpeaking;
GameState.distributeDecision -= _ => NPCSpeaking();
GameState.verdictTime -= PlayerSpeaking;
}
}
Mhh and what part of that is giving you trouble now?
I understand what you are trying to do, but not what part of it you are having trouble with
Well not that necessarily, it's more so how I can have that UniTask function react to an event that would start the transition if you get me, what I'm trying to do is:
React to progress bar filling:
-
Transition to an idle animation
-
Start silencing the audio, using an audiomixer snapshot.
-
Wait for the NPC to transitioning to a different animation.
-
Restore the normal audio, using an audiomixer snapshot.
-
Play the other timeline sequence to complete the transition
does this make sense?
@humble ridge
Ok this is what I came up with for this:
public class Level2Timelines : TimeLineController {
{...}
protected override void Awake() {
metreManager.TriggerInterruption += (interruptType) => PlayInterrupt(interruptType)
{...}
}
protected void PlayInterrupt(string interruptType) {
{...}
//I want to fire and forget this in PlayInterrupt to carry out the event, but still await it inside itself to complete the transition.
_ = interruptionTransition
}
protected async UniTaskVoid interruptionTransition()
{
Debug.Log("Starting silence transition");
_ = level2Animations.InterruptedAnimation();
_ = audioMixerControl.SilenceTransition();
await UniTask.WaitUntil(() => level2Animations.GetCurrentState().IsName("Waiting")
&& audioMixerControl.getCurrentSnapshot() == audioMixerControl.silence);
_ = level2Animations.IdleToArguing();
_ =audioMixerControl.BackToNormal();
await UniTask.WaitUntil(() => level2Animations.GetCurrentState().IsName("Arguing")
&& audioMixerControl.getCurrentSnapshot() == audioMixerControl.normal);
activeInterrupt.Play();
}
}
using Cysharp.Threading.Tasks;
using System;
using UnityEngine;
public class Level2Animation : AnimationController
{
public event Action NPCTalking;
public override void NPCSpeaking()
{
NPCTalking?.Invoke();
}
public AnimatorStateInfo GetCurrentState()
{
return anim.GetCurrentAnimatorStateInfo(0);
}
public async UniTaskVoid InterruptedAnimation()
{
anim.SetTrigger("Start_Interruption");
await UniTask.Yield();
}
public async UniTaskVoid IdleToArguing()
{
anim.SetTrigger("NPC_Arguing");
await UniTask.Yield();
}
}
using UnityEngine;
using UnityEngine.Audio;
using Cysharp.Threading.Tasks;
public class AudioMixerControl : MonoBehaviour
{
public AudioMixer gameAudio;
public AudioMixerSnapshot normal;
public AudioMixerSnapshot silence;
protected AudioMixerSnapshot currentSnapshot;
protected float transitionTime = 0.1f;
private void Awake()
{
normal = gameAudio.FindSnapshot("Normal");
silence = gameAudio.FindSnapshot("Silence");
currentSnapshot = normal;
}
public AudioMixerSnapshot getCurrentSnapshot()
{
return currentSnapshot;
}
public async UniTaskVoid SilenceTransition()
{
silence.TransitionTo(transitionTime);
currentSnapshot = silence;
await UniTask.Yield();
}
public async UniTaskVoid BackToNormal()
{
normal.TransitionTo(transitionTime);
currentSnapshot = normal;
await UniTask.Yield();
}
}
For more clarity
Sorry for the tag, just wanted to make sure you can see this but don't feel rushed to reply obvs
Also, the reason why I have hardcoded strings is because this is for a one-off use case
Pretty much my project is a prototype of a serious game I'd like to make
Also the reason I have those Yield statements, is because I wanted to fire and forget them in the first screenshot so that they start simultaneously, then I thought adding a frame buffer would be helpful in ensuring synchronisation.
Then after those two fire, we just wait until they result in the values we want.
Please correct me if I'm wrong.