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>() });
}
}