Hi there,
In 4.5 the behaviour of the functions relating to montages on UAnimInstance changed. This is largely due to the change in behaviour of how GetActiveMontageInstance works.
Previously GetActiveMontageInstance would go through the MontageInstance array and return the last as long as it was valid.
Now GetActiveMontageInstance check it is active as well and many functions also use GetActiveInstanceForMontage which uses the new ActiveMontagesMap.
When a montage reaches the blend out time they are calling Stop on themselves (in FAnimMontageInstance::Advance). In 4.5 the stop now calls OnMontageInstanceStopped on the anim instance which removes it from the ActiveMontagesMap.
What all of this now means, is that blending out montages no longer get returned by most of the functions on AnimInstance, including Montage_IsPlaying, Montage_GetCurrentSection etc.
Is this change of behaviour intended?
We were relying on a lot of these functions so we could track exactly how far through animations it was etc, and now the second a montage blends out we are getting invalid data (Montage_GetPosition returns 0.0f for instance).
For now I will write some work arounds to use the MontageInstances array like before, which works fine.
Thanks.
Hi Ben.Driehuis,
To answer the question, “Is this change of behavior intended?” I’ve consulted the developers and received the following explanation:
"Yes, this is intentional. The reasoning behind this is that once a Montage has been stopped, it is no longer active and you cannot do anything to it anymore. You cannot change its position, play rate, section, etc. as you have stopped it and that’s not a reversible action.
Also, if you are pushing another montage on the same group, the previous one will be marked inactive and blend out. If you want to use any of the Montage API functions, it will reference the new active montage, and the other one is basically stopped, inactive, and going away."
I’m glad to hear you were able to come up with some work-arounds and hope this clarifies the reasoning behind the change in how the GetActiveMontageInstance works.
Hmm ok, I guess its a bit off because of the blending out making it considered stop before the animation is finished. It would be nice to be able to at least be able to poll information about it state. I mean what if you have a animation with a long fade out time, it would be considered stop very quickly.
I am sure this change will catch a few people out, especially those who don’t use C++, as they will have no idea why all of a sudden they are being told their animations are finishing earlier now.
Thanks for the reply, it will just mean we will have to write our own solutions and not rely on the anim instance ones.
For anyone who is interested in the code solution, its simply to do what the anim instance code used to do.
float AYourCharacter::GetMontagePosition(UAnimMontage* InMontage)
{
if (Mesh)
{
UAnimInstance * AnimInstance = Mesh->GetAnimInstance();
if (AnimInstance)
{
//start at end, so if we requested to play it again we return that data
for (int32 InstanceIndex = AnimInstance->MontageInstances.Num() - 1; InstanceIndex >= 0; InstanceIndex--)
{
FAnimMontageInstance * MontageInstance = AnimInstance->MontageInstances[InstanceIndex];
if (MontageInstance && MontageInstance->Montage == InMontage)
{
return MontageInstance->GetPosition();
}
}
}
}
return 0.0f;
}
There were a few things we are doing. The most complicated one involves us traversing a movement system over the course of an animation, using montage sections to help us know when to move during the animation. Thus we need to know exactly how far the animation is through, what section it is in etc, even when its at the end fading out (We handle when we call stop on it).
Others are just trying to wait until the animation is fully done (including fade out) before we do other things. Having the same animation play again in these cases didnt really affect us, as the old code would just give us the newest one which was all we needed.
Using the pointers is not a bad option in some cases, on the other hand the issue you brought up isnt one we had to worry about. We might well change to it though so we are more clear about not using the anim instance functions.
Hi Ben, I am curious of your usage case. Why are you polling the montage as it’s been stopped? What are you trying to achieve?
The problem with your solution is if you push the same montage again, it will stop the previous one. Since both are the same UAnimMontage asset, you have no way to tell which one GetMontagePosition is going to find and use.
So we’ve made our API only work on Active montages.
It seems that what you would want to do is after you’ve played your Montage, hold on to its FAnimMontageInstance pointer, and use that to poll its position until it is terminated.
Hi Ben, I am curious of your usage case. Why are you polling the montage as it’s been stopped? What are you trying to achieve?
The problem with your solution is if you push the same montage again, it will stop the previous one. Since both are the same UAnimMontage asset, you have no way to tell which one GetMontagePosition is going to find and use.
So we’ve made our API only work on Active montages.
It seems that what you would want to do is after you’ve played your Montage, hold on to its FAnimMontageInstance pointer, and use that to poll its position until it is terminated.
Ok. For things like knowing the position and section while fading out, you can hold onto the FAnimInstance pointer. That would be the most reliable solution.
For knowing when the animation is terminated, you could just bind a delegate to that event, no need to monitor the position of the montage.
Thanks for all the information