- Home /
Ideas for Animating while Paused?
Hey all,
The current project I am working on has animated menus, which are not programmatic but instead use Unity's Animation tool. There are also nicely animated transitions that occur between screens, also utilizing the Animation tool.
We are using Time.timeScale and setting it to 0 as a solution for pausing the game, in which case the Animations stop as well. This doesn't surprise me and it makes sense why this would happen, but it does cause problems when we're trying to play these animations during the pause screen.
Does anyone have a solution for this? I've done some digging for this and it seems like everything I have found would work for programmatic animations, but not Unity's Animation Clips.
Thanks in advance.
==
To help others notice this option though its not the accepted answer Animator Update $$anonymous$$ode --> UnscaledTime That will give you the desired result with no coding required as noted by @Salazar below
Answer by equalsequals · Nov 04, 2010 at 06:57 PM
First off I wanted to thank @Eric5h5, @Paulius Liekis and @Herman Tulleken for the answers. I actually used a mixture of solutions.
Basically, I had so much code invested in FixedUpdate, etc. That the pausing solution needed to remain the way it was. Inside my base animation manager class I adjusted the code so that animations run independently of Time.timeScale. I used a spin of Paulius and Herman's methods to achieve this.
This class is a more basic version of what I had to do to get this to work, it involves 2 animations, an in transition and an out transition.
using UnityEngine; using System.Collections;
[RequireComponent(typeof(Animation))] public class EQEQAnimationManager : MonoBehaviour { //for calculating our delta time float _timeAtLastFrame = 0F; float _timeAtCurrentFrame = 0F; float deltaTime = 0F;
AnimationState _currState;
bool isPlaying = false;
float _startTime = 0F;
float _accumTime = 0F;
void Update()
{
//we create our own deltaTime based on realtimeSinceStartup here
_timeAtCurrentFrame = Time.realtimeSinceStartup;
deltaTime = _timeAtCurrentFrame - _timeAtLastFrame;
_timeAtLastFrame = _timeAtCurrentFrame;
if(isPlaying) AnimationUpdate();
}
void AnimationUpdate()
{
//accumulate time
_accumTime += deltaTime;
//normalized time is from 0, the animation's beginning to 1, the end. We'll set it where the accumulated time is in the current animation's duration.
_currState.normalizedTime = _accumTime/_currState.length;
if(_accumTime >= _currState.length)
{
OnAnimationCompleted();
_currState.enabled = false;
isPlaying = false;
}
}
public void PlayAnimation(string suffix)
{
_accumTime = 0F;
_currState = animation[gameObject.name + " " + suffix]; //my animations are organized by the name of the game object, and what the animation is (ie "Main Menu Transition In" in which suffix would be "Transition In")
_currState.weight = 1;
_currState.blendMode = AnimationBlendMode.Blend;
_currState.wrapMode = WrapMode.Once;
_currState.normalizedTime = 0;
_currState.enabled = true;
isPlaying = true;
}
internal void OnAnimationCompleted()
{
//hook for end of animation
}
}
In this case, I took advantage of Animation States and AnimationState.normalizedTime, using my custom deltaTime (thanks again Herman) to allow the animation to play as expected even if Time.timeScale is set to 0. Since these are straight-forward, linear animations, I was able to get away with setting the AnimationState's values in PlayAnimation the way I did. In other cases I'd probably want to inject more parameters.
What I also noticed was that I lost connections to my AnimationEvents which I inserted using Unity's Animation Editor. In my case it was a single function call which was fired on completion. Again, because of the linear nature of these animations I was able to get away with just calling that function after the accumulated time reached the length of the animation in my custom update loop.
I hope this helps anyone else with a similar complication. I was lucky that I only had to modify a single class and everything worked as expected. I have good class and package structure to thank for that. :)
Chances are you may need to modify the code above to fit your needs but I hope it serves as a stable launch point for you.
Cheers
==
This is what I want!! Its GREAT solution. Thank you very much!
@GigaDeath: And this is not an answer! I've converted your "answer" into a comment.
@$$anonymous$$Pasek, Bunny83, Eric5h5: or anyone else:
Is there an equivalent method of doing this, but for Particle Effects, so that they Emit/Animate on Pause $$anonymous$$enus?
Thanks everyone, very helpful!
@AbsurdHart: To turn the above code into an equivalent solution for particle effects, you could try replacing line 34 above with "particleSystem.time = _accumTime", and removing other references to AnimationStates. I haven't tested this myself though. (And yeah, I realise your question is old :) )
i was using this code to run an animation while paused, but i can't run animation events with this, they simply wont run, is there any way around this?
Answer by Salazar · Aug 30, 2014 at 03:42 PM
I used Animator Update Mode --> UnscaledTime option in animator component of the gameobject.
For the solution of animated sprite menus.
This should be the accepted answer. I just wasted way too much time on the current "accepted" answer.
I know this is late, but one more thumbs up for this answer. It did exactly what I needed without any code.
for reading past the accepted answer ;) changing the Update $$anonymous$$ode on the animator gives the desired result with 0 code.
Answer by Eric5h5 · Nov 03, 2010 at 10:24 PM
Set the timeScale for pausing to something like .00001 instead of 0, and when pausing or resuming set the animation speeds to "1.0/Time.timeScale
".
Did you mean 1 divided by Time.timeScale or pausing/resu$$anonymous$$g respectively?
equalsequals: I meant one divided by Time.timeScale. Edited for clarity.
I just tried this method and it didn't work well at all for me. it worked ok until timescale reached about 0.4, after which there was a mismatch between the normal speed and the paused speed, growing more severe the slower time is set. At 0.0001 the animation played extremely slowly, despite being set to play at 10000 times speed
the animation speed is a float and floats lose precision at high values such as 100000.
Answer by Paulius-Liekis · Nov 03, 2010 at 10:22 PM
You just have to control animation time manually - it works with regular or Unity animations. Get the actual delta time from realtimeSinceStartup or something else that is not affected by time scale and set appropriate time on your animation.
Thanks for the idea, it was a nudge in the right direction. I had assumed this was the route I needed to go, but I was looking for something with a little less rigmarole. I submitted my own answer with code as to how I solved this.
Answer by Herman-Tulleken · Nov 04, 2010 at 06:19 AM
We use the following (clumsy, but workable) scheme. Most of our simulations run of a separate variable ourOwnDeltaTime, which is the same as Time.deltaTime when the game is running, but 0 when the game is paused. Things that should not pause runs off the proper deltaTime.
It is clumsy, because animations and particles have to be played and paused separately (because, of course, internally they still run of Time.deltaTime). It also requires a lot of discipline (you have to remember never to use the Time.deltaTime everywhere), and might not work well with 3rd party code.
A benefit is that game speed and interface animations can be controlled separately.
I could never understand why there is not a better built-in solution for pausing (in any game-engine I have worked with)...
I agree, there should be something internal for this, because every solution I've found is nothing short of a hack. It's unfortunate that those are the only options here. Luckily there is extremely little 3rd party code implemented in this project, and anything that wasn't written in-house is not timescale-dependent. I can implement this custom deltaTime with little to no rework outside of a single class in our animation framework.