Set mecanim animation playback time/position - c#

I'm trying to set an animator's playback time. (or, start an animation at a specific time) I haven't had success with either approach.
Note: I am setting the Animator (an) in the Start().
Code I've tried:
Public Animator an;
public void SetTime(float time)
{
an.playbackTime = time;
}

Oops, I guess this one was pretty easy!
I didn't see the constructor options for the Play() method!
The answer:
an.Play("YourAnimation", 0, 0.4f);
However, I am still currious why my original code didn't work. So I figured out how to make an animation play/start at a specific time... Does anyone know how to basically "rewind" an animation to a specific point? (while it's playing)

Related

Method not being called after invoke delay (unity)

I'm trying to create a apply a fairly simple buff to my character for a short duration, but it seems that whatever method I try to use it does not want to apply.
I've tried creating a manual timer, making use of coroutine and now making use of invoke with a delay, but in each case it applies the increase in speed on collision, but then never does anything after the delay (also doesn't debug log after delay), see the screenshot below for the code.
Image of code
Any help would be greatly appreciated! Thanks
You destroy the gameobject allong with the script, that's why it never get's executed.
I'm not sure why you destroy the gameobject but you can remove the Destroy(this.gameObject);
If the Destory() method is necessary, you can use it inside your TimerBuff() method like this.
public void TimerBuff()
{
Debug.Log("timerstop");
PlayerMovement.runSpeed = 5f;
Destroy(gameObject);
}

Unity StateMachineBehaviour : Start function called once?

i'm making my first enemy AI in unity. I'm trying to make a finished state machine with the animator controller to do it.
I just discovered the StateMachineBehaviour script which is called when the AI is in a state. It has multiple methods, including the OnStateEnter. It is called everytime the AI enter the state.
My problem is only about optimization, my AI need to get the GameObject "Player" in order to attack it. So i'm getting it in my OnStateEnter method for the moment, which i feel is bad, because i'm getting it every time the animation is called, i would like to get it only once, at the start.
I basicly need a start function but it's not working, i have made research and found nothing. I tried to watch video about people making a finished state machine but they are just getting the same GameObject multiple time ( example here : https://youtu.be/dYi-i83sq5g?t=409 ).
So, is there a way to have a start function or to get an element only once ?
I could make a bool that is called only the first time and that get the GameObject, but again that would be an "useless" if running in my function.
Any suggestions ? Thanks
No, unlike a MonoBehaviour a StateMachineBehaviour has no Start message only OnStateEnter, OnStateExit, OnStateIK, OnStateMove and OnStateUpdate.
There are also Awake and OnEnable but I'm pretty sure they are not used in the StateMachine and might not behave as expected.
You can however either use
OnStateMachineEnter
Called on the first Update frame when making a transition to a StateMachine. This is not called when making a transition into a StateMachine sub-state.
Or use a simple bool flag like
bool alreadyExecuted = false;
OnStateEnter()
{
if(alreadyExecuted) return;
// Do your stuff
alreadyExecuted = true;
}
(Just a guess)
In the Inspector you actually can enable and disable StateMachineBehaviours like components. So it might be able to do this also in script maybe the same way using
enabled = false;
but I didn't find anything about it in the API and since I'm currently on my Smartphone I can't test it.

Unity 5.5.0f3 play animation backwards at runtime

Original question on the Unityforums here
I've been trying to get an animation to not only slow down and speed up, but also play backwards depending on user input for my Hololens-application. I am using the Mecanim system, not legacy animations.
The whole thing is supposed to happen at runtime, through dynamic user input.
I know that it's possible through scripting, as I had it working before I lost local progress and some files during some Unity-Collaborate issues. As stupid as it sounds, since then I have not been able to remember what I did different from my current approach.
Right now I'm manipulating the value Animator.speed, but that only works for values >= 0.
Any help would be greatly appreciated!
Edit: In case the link is not working or visible for anybody, here is my code:
private Animator anim;
//...
anim = gameObject.GetComponent<Animator>();
//...
public void OnManipulationUpdated(ManipulationEventData eventData)
{
if (anim.isActiveAndEnabled)
{
anim.speed = eventData.CumulativeDelta.x;
anim.Play("KA_Cover_Anim");
return;
}
//...
}
Edit2: Incorrectly marked as dupicate! The linked question does not regard a similar problem and required a different solution
Edit3: For clarification, the linked "duplicate" uses the legacy animation system which is irrelevant for my question. In Mecanim, the new animation system in Unity 5.xx, you can not access the Animations directly as shown in the selected answer. Neither is it possible to alter the animation speed as shown in in the second answer.
I'm not exactly sure what you're end goal is, but you can play animations backwards and at different speeds by using a parameter.
On the animation state, you can make it watch a parameter and multiply it against the default speed of the animation. All you need to do in code is something like
animator.setFloat("Speed",-1.0f);
Hope that helps.

What is the best practice for determining when an animation has completed running? [duplicate]

This question already has answers here:
Play and wait for Animation/Animator to finish playing
(2 answers)
Closed 5 years ago.
Why doesn't this work? I am finding that my while loop is exiting immediately. My death animation takes about 1second, and I am watching the death state be active for that duration, after which, it exits to my Idle state. Is there a timing issue, where my boolean condition is being tested before the death state is started?
I am trying to find a direct test on an animation for when it stops running.
private void playerDestroyed ()
{
int deathHash = Animator.StringToHash("PlayerDeath");
GameController.instance.pauseGame();
_anim.Play(deathHash);
while ( _anim.GetCurrentAnimatorStateInfo(0).nameHash == deathHash) {
System.Threading.Thread.Sleep(100);
}
GameController.instance.gameOver();
}
EDIT:
So I changed my question to reflect what I'm really after: a best practice for knowing when an animation has completed. I have seen examples using a WaitForSeconds strategy, but with the time to wait hardcoded, which is not ideal. If I was to use this, I would want to pull the time of the animation, but I have had trouble accessing the animation clip length via the animator.
Ok, kudos to rutter for mentioning the "will the game wait one frame". It was driving me mental that the AnimationInfo[] coming back was null for me when I tried accessing the running clip. I didn't think the Animator needed time to update it's statuses after a direct call to play an animation.
Also interestingly, I tried the same code but using a trigger instead of dealing with the hash business, and the code below fails. My variable s comes back with Length of Zero. The trigger needs more time than a single frame to work, I guess.
I thought I would put this together as an answer for how to achieve a test for an end of a clip. However, please let me know if there is a better way!
private void playerDestroyed ()
{
// a global var for the Animator object
_anim = GetComponent<Animator>();
int hash = Animator.StringToHash("Base Layer.PlayerDeath");
_anim.Play(deathHash);
StartCoroutine("WaitForAnimation");
}
IEnumerator WaitForAnimation() {
yield return new WaitForEndOfFrame();
AnimationInfo[] s = _anim.GetCurrentAnimationClipState(0);
yield return new WaitForSeconds( s[0].clip.length);
//do something now, after the animation is complete
GameOver();
}

How to wait some seconds before doing something in OnMouseUp Event

I'm writing a game with some animations, and use those animations when the user clicks on a button. I would like to show the user the animation, and not "just" call a new level with Application.loadLevel. I thought I could use the Time.DeltaTime in the onMouseUp method and add it to a predefined 0f value, then check if it is bigger than (for example) 1f, but it just won't work as the onMouseUp method adds just "it's own time" as the delta time.
My script looks like this now:
public class ClickScriptAnim : MonoBehaviour {
public Sprite pressedBtn;
public Sprite btn;
public GameObject target;
public string message;
public Transform mesh;
private bool inAnim = true;
private Animator animator;
private float inGameTime = 0f;
// Use this for initialization
void Start () {
animator = mesh.GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
}
void OnMouseDown() {
animator.SetBool("callAnim", true);
}
void OnMouseUp() {
animator.SetBool("callAnim", false);
animator.SetBool("callGoAway", true);
float animTime = Time.deltaTime;
Debug.Log(inGameTime.ToString());
// I would like to put here something to wait some seconds
target.SendMessage(message, SendMessageOptions.RequireReceiver);
}
}
}
Im not entirely sure what your trying to do by using Time.deltaTime in onMouseUp. This is just the time in seconds since the last frame was rendered, and should act the same no matter where you try to access it. Normally it is used in a function that is called every frame, not one-off events like onMouseUp.
Despite not being certain what you are trying to achieve, it sounds like you should be using Invoke:
http://docs.unity3d.com/ScriptReference/MonoBehaviour.Invoke.html
Just put the code you wish to be delayed into a separate function, and then invoke that function with a delay in onMouseUp.
EDIT: To backup what some others have said here I would not use Thread.Sleep() in this instance.
You want to do this (and all waiting functions that do not appear to make the game "freeze") by blocking the Update loop by using a Coroutine.
Here is a sample of what you are probably looking for.
void OnMouseUp()
{
animator.SetBool("callAnim", false);
animator.SetBool("callGoAway", true);
//Removed the assignement of Time.deltaTime as it did nothing for you...
StartCoroutine(DelayedCoroutine());
}
IEnumerator DoSomethingAfterDelay()
{
yield return new WaitForSeconds(1f); // The parameter is the number of seconds to wait
target.SendMessage(message, SendMessageOptions.RequireReceiver);
}
Based on your example it is difficult to determine exactly what you want to accomplish but the above example is the "correct" way to do something after a delay in Unity 3D. If you wanted to delay your animation, simply place the calling code in the Coroutine as I did the SendMessage invocation.
The coroutine is launched on it's own special game loop that is somewhat concurrent to your game's Update loop. These are very useful for many different things and offer a type of "threading" (albeit not real threading).
NOTE:
Do NOT use Thread.Sleep() in Unity, it will literally freeze the game loop and could cause a crash if done at a bad time. Unity games run on a single thread that handles all of the lifecycle events (Awake(), Start(), Update(), etc...). Calling Thread.Sleep() will stop the execution of these events until it returns and is most likely NOT what you're looking for as it will appear that the game has frozen and cause a bad user experience.

Categories