Assertion failed on expression | New Unity Version Doesn't Like Transforms?

This week on “Things that Unity used to be fine with but now no longer likes” we take a look at the script I use to control ALL of the doors in my game, none of which work now.

Each time I call this script (ask it to open, close or toggle any doors or anything) I get 1 unique error per call, and 1 other error for each object I am trying to adjust.

The Unique Error

Assertion failed on expression: 'CompareApproximately(SqrMagnitude(result), 1.0F)'
UnityEngine.Transform:set_localEulerAngles(Vector3)
<DoMovement>c__Iterator0:MoveNext() (at Assets/Scripts/General Interaction/Door/DoorGeneric.cs:81)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

The Per-Object Error

transform.localRotation assign attempt for 'INSERTOBJECTNAMEHERE' is not valid. Input rotation is { NaN, NaN, NaN, NaN }.
UnityEngine.Transform:set_localEulerAngles(Vector3)
<DoMovement>c__Iterator0:MoveNext() (at Assets/Scripts/General Interaction/Door/DoorGeneric.cs:81)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

The Script

using UnityEngine;
using UnityEngine.Events;
#if UNITY_EDITOR
//using UnityEditor;
#endif
using System.Collections;

[System.Serializable]
public class Door
{
    public GameObject door;
    public float time = 1.0f;
    public bool rotation;
    public Vector3 open;
    public Vector3 closed;
    public int delaySeconds;
    public AudioClip clip;
    public UnityEvent after;
}

public class DoorGeneric : MonoBehaviour {

    public Door[] doors;

    public bool moving;
    public bool completedPos;
    public bool completedRot;
    public bool closed = true;

    public void ToggleDoor()
    {
        if(!moving && closed)
        {
            OpenDoor();
        }
        if(!moving && !closed)
        {
            CloseDoor();
        }
    }

    public void OpenDoor()
    {
        if (!moving && closed)
        {
            foreach(Door door in doors)
            {
                StartCoroutine(DoMovement(door.closed, door.open, door.time, door.door, door.rotation, door.delaySeconds, door.after));
                door.door.GetComponent<AudioSource>().PlayOneShot(door.clip);
            }
            closed = false;
        }
    }

    public void CloseDoor()
    {
        if (!moving && !closed)
        {
            foreach (Door door in doors)
            {
                StartCoroutine(DoMovement(door.open, door.closed, door.time, door.door, door.rotation, door.delaySeconds, door.after));
                door.door.GetComponent<AudioSource>().PlayOneShot(door.clip);
            }
            closed = true;
        }
    }

    IEnumerator DoMovement(Vector3 startPosition, Vector3 endPosition, float moveTime, GameObject obj, bool rotation, int delay, UnityEvent after)
    {
        moving = true;
        yield return new WaitForSeconds(delay);
        float startTime = Time.time;
        float endTime = startTime + moveTime;
        do
        {
            float timeProgressedPosition = (Time.time - startTime) / moveTime;
            timeProgressedPosition = Mathf.Sin(timeProgressedPosition * Mathf.PI * 0.5f);
            timeProgressedPosition = timeProgressedPosition * timeProgressedPosition * timeProgressedPosition * (timeProgressedPosition * (6f * timeProgressedPosition - 15f) + 10f);
            if (rotation)
            {
                obj.transform.localEulerAngles = Vector3.Lerp(startPosition, endPosition, timeProgressedPosition);
            }
            else
            {
                obj.transform.localPosition = Vector3.Lerp(startPosition, endPosition, timeProgressedPosition);
            }
            yield return new WaitForFixedUpdate();
        }
        while (Time.time < endTime);
        after.Invoke();
        moving = false;
    }

    public bool isMoving()
    {
        return moving;
    }
}

Any ideas as to why since Unity 4.8, up to 5.5 it was fine, ans as soon as I update to 5.6, this starts happening… or just how to fix it?

1 Like

This has got to do with the Quaternion that is created from your eulerAngles.

Setting ‘localEulerAngles’ really just does this:

    public Vector3 localEulerAngles
    {
      get
      {
        return this.localRotation.eulerAngles;
      }
      set
      {
        this.localRotation = Quaternion.Euler(value);
      }
    }

From the look of the errors.

It appears that the euler values you pass in, when converted to Quaternion, result in a quat that doesn’t have a magnitude of 1:

This is a malformed quaternion.

The next error is when said quaternion is attempted to be assigned to the localRotation, it receives a malformed quat… in this case all NaN… and freaks out.

Because it’s all NaN, either a) unity returns a NaN quat if the mag test fails… or b) why the mag test failed is because the euler angles you supplied were malformed, possibly NaN, inf, or resulted in a division by zero when normalizing.

Now… this COULD be the result of a bug introduced into Quaternion just before this build. Though, I’m suspect of that as there would be no real reason to modify the underlying code of Quaternion. It’s not like the maths of them has changed any time recently… but it could be that; a programmer may have attempted to optimize quats, or maybe they had a slight change when adding support for new frameworks/platforms… but I doubt it. Quality assurance testing should have caught that, Quats are integral parts of the game engine… they’re used so often that you’d trip over a bug in them.

Or, you’re passing in bad values.

Have you checked what the result of your Lerp statement is before it gets assigned to localEulerAngles just as it fails?

Try changing the code to:

var rot = Vector3.Lerp(startPosition, endPosition, timeProgressedPosition);
obj.transform.localEulerAngles = rot;

And put a break point on it for when it fails, and check the value. If rot is weird, the quat will be weird.

Make sure that the values of door.open, door.closed, or door.time aren’t malformed. If for instance door.time = 0, then there’s your NaN since you divide by moveTime, which comes from door.time.