Reverse of a blueprint animation widget

Hello everyone :slight_smile:

I write to a question about the reverse of an animation made with widget blueprint.

In my game, I created a pair of binoculars that when pressing “Z” zooming in a room.

In widget blueprint, I created an animation that pressure, indicates the level of zoom available.

I managed to run the animation to play well, but I can not figure out how do you do the reverse of the animation created with widget blueprint.

I am attaching a screen to be more clear.

I wish the best to all

B6

From what i know umg don’t have that, so you have to make 1 more animation to do the reversed yourself, currently i do that for mine also. Not sure maybe they will add this in future.

Thank you the answer, I will follow your advice and I also hope that I will do this thing in the next updates.
thanks a lot

B6

Edit: Just noticed that UE4.7 changed the code dealing with Widget animation. So I’ll mention that this code was designed for UE4.6. Basic principle is the same, though 4.7 allows you to specify a start time.

I just got a solution that seems to be working, though it will require some C++ coding because like Duncan Dam said, there is no support for this by default. The code can be placed into your project source or a plugin if you want, though keep in mind that your module has to have the correct dependencies and that your widget will need to inherit from UUserWidget.

Here’s the header files you should be including, you can look these up and get which module they’re apart of as well in Epic’s documentation:

//Whatever slate includes you need, pretty sure you need at least SlateBasics.h and UserWidget.h
#include "UMGSequencePlayer.h"
#include "WidgetAnimation.h"

#include "IMovieScenePlayer.h"
#include "Runtime/MovieSceneCore/Classes/MovieScene.h"
#include "Runtime/MovieSceneCore/Public/MovieSceneInstance.h"

Now, the idea is that you’ll create your own function that will queue up the animation sequence to play in reverse and in a function called every frame, or whenever you want to update your animation, you’ll update the animation by negative delta time.

You’re going to need these two variables:

    // This class handles animation playback for widgets.
	UUMGSequencePlayer *animationReverser; 

    // As far as I can tell, animation time is only tracked in UUMGSequencePlayers 
    // and is private so I need a value to track animation time for myself.
	double animationTime; 

Here’s the set up function:

void ReversePlayWidgetAnimation(UWidgetAnimation *_animation)
{
	UUserWidget* widget = this->GetUserWidgetObject();

	if (widget->IsValidLowLevelFast())
	{
		if (_animation)
		{
			if (!animationReverser)	// create an animation sequencer to play
			{
				// Create the sequencer
				animationReverser = ConstructObject<UUMGSequencePlayer>(UUMGSequencePlayer::StaticClass(), this);
				animationReverser->InitSequencePlayer(*_animation, *widget);

                // This will be the start time of the reversed animation
				float animTimeLength = animationReverser->GetAnimation()->MovieScene->GetTimeRange().GetUpperBoundValue(); 
                // A widget animation will automatically stop 
                // when it reaches the max value its time range so we multiply
                // by a number barely less than one to allow it to actually play
				animTimeLength *= 0.99999f;  

				animationReverser->Play();	// Play will automatically set the animation time to 0. It will always start at the begining, which isn't what we want

				animationReverser->Tick(animTimeLength);	// Tick will add to the animation's internal time. Since it was just set to 0, send the animation length. This sets time to length.

				animationTime = animTimeLength;	// We need to track the animation time ourselves since the value is private with no getter in the sequencer for some raisin.
			}
			else
		{
			// Pausing or Stopping might screw us over as it won't set 
			// the reverse player to null, but it will reset animation time.
			// I'll figure this out later,  
			// or just pray I'll never need to impletement this.
		}
		}
	}
}

And here’s the function that will update your animation. I just wrote it directly in Tick in this example:

void Tick(float DeltaTime)
{
	// Bypass UMGSequencePlayer's Tick function since it's designed to only play forward 
    // We just want the good bits to adapt for reversed playback
	if (animationReverser)	// If not null then play an animation in reverse
	{
            // If you were to look in UUMGSequencePlayer's Tick function then all it  
            // really does is this, though adding to animationTime instead
		double prevTime = animationTime;
		animationTime -= DeltaTime;

            // Update the animation here!
		animationReverser->GetRootMovieSceneInstance()->Update(animationTime, prevTime, *animationReverser);

            // Check to see if animationTime has passed the start of the animation time
		if (animationTime <= animationReverser->GetAnimation()->MovieScene->GetTimeRange().GetLowerBoundValue())
		{
			// Stop and clear out the animation sequence
			animationReverser->Stop();
			animationReverser = nullptr;
		}
	}
	// Continue on with whatever you need to do each update
}