Why my AnimationPlayer is working except if I call it a second time before the end of the first one ?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Kakumi

Hi,

I recently ran into a problem using AnimationPlayer.
I have 2 monsters on the map and when I kill the first one, there is no problem. Animation is played and at the end, monster is destroyed. But when I kill the second one during the animation of the first one, the first monster replay the animation from the start.

There is how it’s developed :
Entity is a main scene with Sprite and Animation Player (Has Entity.cs)
Bat inherits from Entity Scene (Has Bat.cs inherits Entity.cs)

When an entity died, the script inside Entity.cs call “PlayAnimation”.

        if (_animationPlayer.HasAnimation("EntityDeath"))
        {
            _animationPlayer.Play("EntityDeath");
        }

“EntityDeath” is an animation inside the Entity’s AnimationPlayer. This script load a ShaderMaterial (Local to scene activated) with a gdshader (Local to scene activated too) and play on a shader parameter
Animation

There is some logs details :

Entity Bat died
Bat Shader Progress : 0

Bat Shader Progress : 0.78
Entity Bat2 died
Bat Shader Progress : 0
Bat2 Shader Progress : 0

Bat Shader Progress : 1
Bat2 Shader Progress : 1

Hope you can help me !
Thank you

Can you post the code that implements the animation? I am not sure if there is enough here to pinpoint the issue. I doubt it is your shader if the animation is playing. Likely its something in the logic/implementation.

SnapCracklins | 2022-04-26 19:53

public virtual void Died()
{
    if (!Dead)
    {
        Logger.Instance.Info($"Entity {Name} ({EntityName}) died");
        Dead = true;
        EmitSignal("Death");
        if (_animationPlayer.HasAnimation("EntityDeath"))
        {
            _animationPlayer.Play("EntityDeath");
        }
        else
        {
            OnDeathAnimationEnd();
        }

        _name.Visible = false;
        _hurtbox.Shape.SetDeferred("disabled", true);
    }
}

AnimationPlayer : 1 hosted at ImgBB — ImgBB

Kakumi | 2022-04-27 14:46

:bust_in_silhouette: Reply From: Kakumi

I found the problem. I think it was because I created my Shader Material in the parent node and even if it’s “local to scene”, it’s somewhat related to the same shader.

My solution is to create the animation programatically. I used C#, here is the code :

protected virtual void CreateDeathAnimation()
{
    var material = new ShaderMaterial() { Shader = GD.Load<Shader>("res://Resources/Shaders/DeathShader.tres") };
    material.SetShaderParam("beam_size", 0.03f);
    material.SetShaderParam("color", new Color().FromRGBA(255, 0, 0, 1));
    CreateShaderAnimation(EntityAnimation.EntityDeath, 1, 0f, 0.5f, material, nameof(OnDeathAnimationEnd));
}

private void CreateShaderAnimation(EntityAnimation name, float length, float from, float to, ShaderMaterial material, string method)
{
    var animation = new Animation();
    animation.Length = length;
    animation.Loop = false;
    animation.Step = 0.1f;
    animation.AddTrack(Animation.TrackType.Value, 0);
    animation.AddTrack(Animation.TrackType.Value, 1);
    animation.AddTrack(Animation.TrackType.Method, 2);
    animation.TrackSetPath(0, GetPathTo(_sprite) + ":material");
    animation.TrackSetPath(1, GetPathTo(_sprite) + ":material:shader_param/progress");
    animation.TrackSetPath(2, GetPathTo(this));
    animation.TrackInsertKey(0, 0f, material);
    animation.TrackInsertKey(0, 1f, null);
    animation.TrackInsertKey(1, 0f, from);
    animation.TrackInsertKey(1, 1f, to);
    animation.TrackInsertKey(2, 1f, new Dictionary<string, object>()
    {
        { "method", method }, { "args", new object[] {} }
    });
    _animationPlayer.AddAnimation(name.ToString(), animation);
}