Animation seems to be broken in playmode tests.

Hi all,

Are there any tricks or gotcha’s for animations in playmode tests?

I’m trying to write a test which exercises attack → animation → collider hit → damage. The animation works fine when playing, but in testing, none of the animation keyframes are applied.

Sample code is below. I know the issue is in the animator, because if I move the attackedGameObject to be overlapping with the attackerGameObject, the test passes. I’ve debugged the Animator and I see the proper progress in the state view. In addition, if I run the animation manually during the test on the attackerGameObject - then the test will pass.

    public class SimpleMeleeAttackerTest
    {
        private GameObject _attackerGameObject;
        private GameObject _attackPointGameObject;
        private List<object> _log;
        private GameObject _attackedGameObject;
        private SimpleMeleeAttacker _simpleMeleeAttacker;

        [SetUp]
        public void SetUp()
        {
            _log = new List<object>();
            // This contains the minimum required components to get this to work.

            // Attacker Setup
            _attackerGameObject = new GameObject("Attacker", typeof(SimpleMeleeAttacker), typeof(Animator));
            _simpleMeleeAttacker = _attackerGameObject.GetComponent<SimpleMeleeAttacker>();
            var animator = _attackerGameObject.GetComponent<Animator>();
            animator.runtimeAnimatorController = Resources.Load<AnimatorController>("TestAnimationController");

            // Attack Point Setup
            _attackPointGameObject = new GameObject("AttackPoint", typeof(BoxCollider2D));
            _attackPointGameObject.transform.SetParent(_attackerGameObject.transform);
            _attackPointGameObject.GetComponent<BoxCollider2D>().isTrigger = true;

            // Attacked Object Setup
            _attackedGameObject = new GameObject("AttackedObject", typeof(BoxCollider2D), typeof(Rigidbody2D))
            {
                transform = { position = new Vector3(1.5f, 0, 0) },
            };

            _simpleMeleeAttacker.SetProfile(new SimpleMeleeAttackerProfile()
            {
                Animator = animator,
                AttackEffects = new List<IAttackEffect> { new LogEffect(_log) },
                AttackCollider = _attackPointGameObject.GetComponent<BoxCollider2D>(),
            });

            _attackPointGameObject.AddComponent<AttackPoint>();
        }

        [TearDown]
        public void TearDown()
        {
            Object.Destroy(_attackPointGameObject);
            Object.Destroy(_attackerGameObject);
            Object.Destroy(_attackedGameObject);
        }


        /// <summary>
        /// Given: An attacking character standing next to a damageable character,
        /// When: An attack is initiated,
        /// Then: The damageable character takes the effect.
        /// </summary>
        [UnityTest]
        public IEnumerator Attack_Scenario_1()
        {
            Debug.Break();
            yield return new WaitForFixedUpdate();
            _simpleMeleeAttacker.Attack();

            // Only need 3 - but putting a bunch to step through unity debugger
            yield return new WaitForFixedUpdate();
            yield return new WaitForFixedUpdate();
            yield return new WaitForFixedUpdate();
            yield return new WaitForFixedUpdate();
            yield return new WaitForFixedUpdate();
            yield return new WaitForFixedUpdate();
            yield return new WaitForFixedUpdate();
            yield return new WaitForFixedUpdate();
            yield return new WaitForFixedUpdate();

            _log.Should().Contain(new object[] { "ApplyEffect", _attackedGameObject.GetComponent<BoxCollider2D>() });
        }
    }

OH MAN! Finally got it.

So after doing dynamic crap- not sure what type of dynamic crap causes the need for a rebind, but I’ll say switching out the runtimeAnimatorController looks like it counts.

Use: animator.Rebind()