Godot.AnimationMixer.AnimationFinished C#

Godot Version

Godot_Mono 4.3

Question

I can’t seem to find how to connect to the signal for Godot.AnimationMixer.AnimationFinished in C#.

Could somebody point me to a simple way of creating a function that will work with += assignment?

I’m playing an animation using a button and want the button to change colour when the animation has stopped playing.

AnimationFinished passes a StringName parameter. Function/signal signatures are the same in gdscript and C#.

1 Like

That is what I thought.

This is what I’m trying…

Action<StringName> AnimationFinishedAction;
AnimationFinishedAction = (StringName animName) => OnAnimationFinished(button);

animationPlayer.AnimationFinished += AnimationFinishedAction;

Where the function called is:

private void OnAnimationFinished(Button button){
	button.Text = "Play";
}

The error I get is the following:

Cannot implicitly convert type 'System.Action<Godot.StringName>' to 'Godot.AnimationMixer.AnimationFinishedEventHandler'CS0029

I’m relatively new to C# and Godot but I use the same pattern elsewhere and it works.

This event requires a function that takes a StringName as an argument, so you should do this.

1 Like

Thanks for your answer.

Doing that gives the same error:

Cannot implicitly convert type 'System.Action<Godot.StringName>' to 'Godot.AnimationMixer.AnimationFinishedEventHandler' 

I would also think that the lambda should handle the function signature and also allow me to pass in the button as in my example which is what I need.

How do you get the reference to the AnimationMixer node? I feel like you might be trying to use a node other than the AnimationMixer one.

1 Like

I’m using an instance of Godot.AnimationPlayer actually.

Should I be using an AnimationMixer? It’s true that the error references an AnimationMixer and not an AnimationPlayer.

In that case you should use the AnimationPlayer’s AnimationFinished event. Unless you absolutely need the base class for something.

1 Like

I don’t think there is an AnimationPlayer override so it is defaulting to the base class.

This is the code that I think handles the connection in AnimationMixer:

    /// <summary>
    /// <para>Notifies when an animation finished playing.</para>
    /// <para><b>Note:</b> This signal is not emitted if an animation is looping.</para>
    /// </summary>
    public unsafe event AnimationFinishedEventHandler AnimationFinished
    {
        add => Connect(SignalName.AnimationFinished, Callable.CreateWithUnsafeTrampoline(value, &AnimationFinishedTrampoline));
        remove => Disconnect(SignalName.AnimationFinished, Callable.CreateWithUnsafeTrampoline(value, &AnimationFinishedTrampoline));
    }
    /// <summary>
    /// Represents the method that handles the <see cref="Godot.AnimationMixer.AnimationFinished"/> event of a <see cref="Godot.AnimationMixer"/> class.
    /// </summary>
    public delegate void AnimationFinishedEventHandler(StringName animName);

The AnimationPlayer node has it’s own AnimationFinished event. I’m not sure what you’re trying to achieve here I’m afraid. How come you can’t just use the AnimationPlayer node directly?

1 Like

Your problem is that the AnimationFinished expects a variable of type AnimationMixer.AnimationFinishedEventHandler. You are attaching a value/function of type Action<StringName>. While these might functionally seem the same, the are two different types for the compiler.

You can fix this by specifying the correct type for your lambda:

// the type is AnimationFinishedEventHandler
AnimationMixer.AnimationFinishedEventHandler AnimationFinishedAction;
AnimationFinishedAction = (StringName animName) => OnAnimationFinished(button);

animationPlayer.AnimationFinished += AnimationFinishedAction;

You mentioned that it worked in other cases. My guess would be that this was for events that don’t pass any parameters. In this case Godot does no create a separate delegate but simply uses Action.

As @tibaverus mentioned I suggest that you specify it as a separate function, then you don’t have to think about the type.
You say that you get the same error, but that shouldn’t be the case. Did you define the function and attached it to the event exactly as @tibaverus showed?

You can also pass an anonymous lambda:

animationplayer.AnimationFinished += animName => OnAnimationFinished(button);

But then you cannot disconnect anymore. This is a problem when the receiver is freed before the animation-player. See here: C# signals — Godot Engine (stable) documentation in English.

I also see that there is some confusion about AnimationPlayer and AnimationMixer. AnimationPlayer inherits from AnimationMixer and the latter actually defines the animation_finished signal. That’s why the error is in the AnimationMixer class. You probably still want to use AnimationPlayer to have all the ‘extras’ that come with it.

1 Like

Thank you for your very comprehensive answer. That was exactly the problem.