• Unity
  • Pause game using Time.timeScale = 0.0

Related Discussions
...

Hi, sorry if this question has been posted before, but I couldn't find it. When the player clicks the pause button in my game, I use the typical method to stop all logic:

Time.timeScale = 0f;

Unfortunately this causes certain spine animations to throw errors either immediately or when the game resumes. Is this a supported way of pausing all Spines? I am using spine-unity-3.8-2021-07-12.unitypackage with Unity editor 2020.3.16f1.

Just to give a quick example, I'm getting an Index out of Bounds in this AnimationState.BinarySearch():

internal static int BinarySearch (float[] values, float target) {
   int low = 0;
   int high = values.Length - 2;
   if (high == 0) return 1;
   int current = (int)((uint)high >> 1);
   while (true) {
      if (values[current + 1] <= target)
         low = current + 1;
      else
         high = current;
      if (low == high) return (low + 1);
      current = (int)((uint)(low + high) >> 1);
   }
}

On this line:

if (values[current + 1] <= target)

If I modify Skeleton Animation.Update() to the following:

      void Update () {
         #if UNITY_EDITOR
         if (!Application.isPlaying) {
            Update(0f);
            return;
         }
#endif

// NEW GUARD
      if (Time.deltaTime <= 0.001f)
      {
        return;
      }

  Update(Time.deltaTime);
  }

It seems to generally work better, but sometimes I get that same exception immediately on pause, or an NaN exception in ApplyRotateTimeline() upon resume or pause. Any help would be appreciated, thank you!

Can you post the full exception stacktrace? Then we can see what timeline is causing the problem.

Yes sure! Here's one of the NaN errors that appears sometimes when the game pauses and sometimes when it resumes. (This is without the little modification I mentioned above.)

ArithmeticException: Function does not accept floating point Not-a-Number values.
System.Math.Sign (System.Single value) (at <695d1cc93cca45069c528c15c9fdd749>:0)
Spine.AnimationState.ApplyRotateTimeline (Spine.RotateTimeline timeline, Spine.Skeleton skeleton, System.Single time, System.Single alpha, Spine.MixBlend blend, System.Single[] timelinesRotation, System.Int32 i, System.Boolean firstFrame) (at Assets/Spine/Runtime/spine-csharp/AnimationState.cs:561)
Spine.AnimationState.Apply (Spine.Skeleton skeleton) (at Assets/Spine/Runtime/spine-csharp/AnimationState.cs:271)
Spine.Unity.SkeletonAnimation.ApplyAnimation () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs:225)
Spine.Unity.SkeletonAnimation.Update (System.Single deltaTime) (at Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs:211)
Spine.Unity.SkeletonAnimation.Update () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs:196)

We have not yet encountered any problems with Time.timeScale = 0f; leading to Update(0) calls, which are quite typical in order to trigger an update without progressing time.

Could you please send us your problematic exported Spine assets that you use in Unity (the three files)? If you would like to keep them confidential you can send them to contact@esotericsoftware.com, briefly mentioning this URL so that we know the context.

Yes, emailed, thank you!

From the exception it seems somehow a NaN got into timelinesRotation, but I can't see how that could happen. We got your email, thanks! We'll check it out and post here soon.

In case it helps, here's a stack trace from when it throws an IndexOutofRange:

IndexOutOfRangeException: Index was outside the bounds of the array.
Spine.Animation.BinarySearch (System.Single[] values, System.Single target) (at Assets/Spine/Runtime/spine-csharp/Animation.cs:115)
Spine.DeformTimeline.Apply (Spine.Skeleton skeleton, System.Single lastTime, System.Single time, Spine.ExposedList`1[T] firedEvents, System.Single alpha, Spine.MixBlend blend, Spine.MixDirection direction) (at Assets/Spine/Runtime/spine-csharp/Animation.cs:1174)
Spine.AnimationState.Apply (Spine.Skeleton skeleton) (at Assets/Spine/Runtime/spine-csharp/AnimationState.cs:257)
Spine.Unity.SkeletonAnimation.ApplyAnimation () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs:225)
Spine.Unity.SkeletonAnimation.Update (System.Single deltaTime) (at Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs:211)
Spine.Unity.SkeletonAnimation.Update () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs:196)

In both cases, I have characters on the jog_backward and jog_forward animations, so it's likely related to those. It doesn't happen on the other animations.

I do have another totally different animation with the same issue, so let me know if you'd like to see that one.

Unfortunately we could not reproduce the problem you described with your assets, we never received any exception when pausing and resuming any of the animations. Could you perhaps send us a minimal Unity project as a zip package that still shows this error?

Sent! Thank you so much for taking a look.


Ah! It was my fault. I use this function to sync the speed of a character's walk cycle to the speed of its motion, where stride is the units per full walk cycle:

public void SyncWalkToVel(Vector2 currXY, Vector2 oldXY, float stride, int trackID = 0)
{
  GetTrackEntry(trackID).TimeScale = ((Vector2.Distance(oldXY, currXY) / Time.deltaTime) / stride);
}

The problem is if Time.deltaTime is 0 (because Time.timeScale is 0), it won't crash but it will pass NaN to track.TimeScale, which will later cause an issue when it tries to update. So instead I have changed it to this:

public void SyncWalkToVel(Vector2 currXY, Vector2 oldXY, float stride, int trackID = 0)
{
  float modifiedTime = 0.0f;

  // this prevents a divide by 0 error
  if (Time.deltaTime >= 0.001f &&
      stride >= 0.001f)
  {
    modifiedTime = (Vector2.Distance(oldXY, currXY) / Time.deltaTime) / stride;
  }
  
GetTrackEntry(trackID).TimeScale = modifiedTime; }

Does this equation look correct to you guys based on what I'm trying to do? Meaning, will the player's walk animation speed properly compensate for deltaTime, which may fluctuate?

Glad to hear you've figured it out already, thanks for letting us know!

riverman_paul wrote

Does this equation look correct to you guys based on what I'm trying to do? Meaning, will the player's walk animation speed properly compensate for deltaTime, which may fluctuate?

Your calculations look good. This is under the assumption that your stride parameter will be set to the "standard velocity" (in units per second) of the animation playing at speed 1.0.

Okay great! Thank you both as always for your expertise and responsiveness.

You're welcome!