Eray Erdin
Eray Erdin

Reputation: 3149

AnimationPlayer animations do not play in Godot

Forewords

Firstly, I know posting graphical resources for codes is not encouraged in this platform. I will also post the code but, in this particular case, I think posting a video about it is much more helpful than just posting some arbitrary code because the structuring of game projects really vary depending on their requirements. However, I still respect the platform's rules so if a mod asks me to format my question according to the community rules, I can do that or they also can simply delete my question. I respect that.

The Issue

It's actually a simple issue but it's driving me crazy because of its simplicity. I just want to fade in when I load a scene and then fade out whenever I click a button. As to how I do that, this is the video about it.

To sum up, I load another scene called "Fader" which contains a ColorRect with a black color and AnimationPlayer to change ColorRect's alpha value.

The code is below with extra comments on relevant parts:

using Godot;
using System;

public class TitleScreen : Control
{
    private Button[] buttons;
    private Control fader;  // the scene that I inject

    public override void _Ready()  // when title screen gets ready
    {
        GD.Print("Preparing TitleScreen...");
        InitButtons();
        InitFader();  // initialize fader
        FadeIn();  // do fade in animation
    }

    private void InitFader()  // initializing fader
    {
        GD.Print("Initializing fader...");
        var faderScene = (PackedScene)ResourceLoader.Load("res://components/Fader.tscn");  // load external fader scene
        fader = (Control)faderScene.Instance();  // instantiate the scene
        fader.SetSize(OS.WindowSize);  // set the size of fader scene to the game window, just in case
        var rect = (ColorRect)fader.GetNode("rect");  // get "rect" child from fader scene
        rect.SetSize(OS.WindowSize);  // set "rect" size to the game window as well, just in case
        fader.Visible = false;  // set the visibility to false
        AddChild(fader);  // add initialized fader scene as a child of title screen
    }

    private void InitButtons()
    {
        GD.Print("Initializing buttons...");
        buttons = new Button[3]{
            (Button)GetNode("menu_container/leftmenu_container/menu/start_button"),
            (Button)GetNode("menu_container/leftmenu_container/menu/continue_button"),
            (Button)GetNode("menu_container/leftmenu_container/menu/exit_button"),
        };

        GD.Print("Adding events to buttons...");
        buttons[0].Connect("pressed", this, "_StartGame");
        buttons[2].Connect("pressed", this, "_QuitGame");
    }

    private void FadeIn()
    {
        GD.Print("Fading in...");
        fader.Visible = true;  // set visibility of fader to true
        var player = (AnimationPlayer)fader.GetNode("player");  // get animation player
        player.Play("FadeIn");  // play FadeIn animation
        fader.Visible = false;  // set visibility of fader to false
    }

    private void FadeOut()
    {
        // similar to FadeIn
        GD.Print("Fading out...");
        fader.Visible = true;
        var player = (AnimationPlayer)fader.GetNode("player");
        player.Play("FadeOut");
        fader.Visible = false;
    }

    public void _StartGame()  // whenever I click start game button
    {
        FadeOut();  // fade out
        GetTree().ChangeScene("res://stages/Demo01.tscn");
    }

    public void _QuitGame()  // whenever I click quit game button
    {
        FadeOut();  // fade out
        GetTree().Quit();
    }
}

Seems like I can't see something. Why does it not fade in and out?


Environment

Upvotes: 0

Views: 2500

Answers (1)

Eray Erdin
Eray Erdin

Reputation: 3149

So, the issue was Play method on AnimationPlayer object kinda runs like async (dunno if this is the correct term for it).

Luckily, there is a feature called signals in Godot. There are animation_started and animation_finished signals on AnimationPlayer objects. Basically, I created a C# script for Fader scene, hooked the signals from player to fader as in:

  • animation_started to _FaderAnimationStart
  • animation_finished to _FaderAnimationEnd

At the end, my script looks like below:

using Godot;
using System;

public class Fader : Control
{
    private ColorRect rect;
    private AnimationPlayer player;

    public override void _Ready()
    {
        GD.Print("Initializing Fader...");

        rect = (ColorRect)GetNode("rect");
        player = (AnimationPlayer)GetNode("player");

        SetSize(OS.WindowSize);
        rect.SetSize(OS.WindowSize);

        Visible = false;
    }

    private void _FaderAnimationStart(String anim_name)
    {
        Visible = true;
    }

    private void _FaderAnimationEnd(String anim_name)
    {
        Visible = false;
    }
}

I solved it thanks to njamster's answer and Hans Passant's comment.

However, this only solves half of the problem. Yes, the scene now fades in when it loads but it does not fade out. Given that it executes kinda-async (again, I'm not sure if this is the correct term), changing scene interrupts while running the animation. I will update the answer when I solve that problem as well.

Update

Well, I cannot seem to solve the fade out part because it requires to access parent node from initialized child scene. There are some methods I can think of.

First one is to somehow parameterize "Fader" scene. This can be done in many ways but at the end, when you initialize it from another scene, you need to cast it to Fader and I don't know if this is a valid way to do it. Another concern is standardizing this in the codebase. A similar method is discussed in here.

Second one is to write it as a plugin which has it benefits and drawbacks. C# is not really battle-tested in this particular area.

Third one is to use a state management system. Here is a redux implementation for Godot. And you need to somehow integrate it for signals, which seems like a hassle.

So, overall, I still do not know how to fade out.

Upvotes: 1

Related Questions