This is a puzzling one for me so I thought I’d ask here. How does one manage their transitions (intro/outro) that including having something happen inbetween the two events?
A simple example:
You have two scenes that you want to do a camera cut between with a dip to black covering the camera cut. The format would go:
play dip to black animation > cut > play dip from black animation
But let’s say you want that at a system level so you can have all your UI screens have transitions. How do you do it?
I’ve thought about having my UI send an interface call to my UI manager class that then fires an event dispatcher that other things can listen to but I don’t like that approach.
Should I create a separate UITransitions class that handles all the transitions on a case by case basis? That seems unwieldy and unnecessary surely.
I can’t quite wrap my head around this one.
For the record I don’t want to rely on built in animations in any kind of system like Common UI because that doesn’t give me enough control over the animation (and also just does a simple transition between screens as far as I can tell and doesn’t appear to allow for doing something inbetween).
Use a UMG animation to fade out (or however else you want to manipulate) the Menu’s background. If you need it in multiple Menus, just pack it into a widget blueprint that automatically triggers the animation when set to visible (for example), and add that widget as a child to any Menu that needs it. Animating UMG Widgets in Unreal Engine | Unreal Engine 5.5 Documentation | Epic Developer Community
Sorry I think I should have been clearer. This is more of a logic/timing issue than the actual transition itself. I want to play an animation, then when that animation is finished, do some functionality, then play another animation. But the kicker is it needs to be generic so it can be reused but also the functionality in that middle part needs to be different per use case.
Example 1 - scene transition:
Fade to black, load next scene, fade from black
Example 2 - changing screens:
Screen outro animation, load next screen, screen intro animation
Example 3 - go from pause menu to gameplay:
Pause menu outro plays, resume game, fade in hud
The problem is that middle part in each of those scenarios since I don’t want my UI to be doing any kind of direct control with the game.
Maybe I’m overthinking it and I should just do it on a case by case basis but it still feels like this would be a lot of custom use cases.
there are many ways to do it.
organizing the time flow for what you are programming is a great way.
it depends on your project.
As for things you can use. i’d avoid using JUST timers. They are fine if you need something quick. but can break once you have many things in sequence. (i do love timers)
I do use timers on the sample code below.
i’d use Delegates. and a careful study of the flow.
i’ll have one class that controls the flow, and then notify through delegates what’s happening.
if it needs to wait for something to do something else asynchronously (loading or a ui animation or X), then you’ll need this system to subscribe to the other thing’s delegate.
i’d avoid timers to coordinate these sort of things.
here’s an example. i’ve made a foss plugin to deal with “story” steps. when i change from one step to the other, i allow to optionally fade in/out, during which i also load stuff.
take a look, it might give you a hint.
i have a manager actor, that hosts the ui and world stuff. that listen to the Fade delegate and notifies the ui.
then the ui does its thing.
though these are the base classes in the plugins. in my game i subclass these and fill them out.
I understand the use cases feel similar enough to generalize, but they also feel different enough not to generalize. For example, the middle parts in your examples all have different “end” logic:
scene loading might need to use a streaming delegate of sorts if the scenes are big
screen loading might or might not need a delegate
resume game is instant and you need to time the fade in yourself
Seems like you know how to implement the actual functionality, so I’d suggest you do just that, on a case-by-case basis. When you actually run into significant duplication or the logic starts feeling annoying to maintain, refactor it. Generalizing in advance holds the same risk anyway (= if it turns out the use cases are incompatible you’ll have to rework it later), so may as well start case-by-case until you actually run into significant duplication. Most of the logic is built-in anyway, you’ll mostly be making data assets (animations, materials, whatnot) and calling UE functions (delegates, pause/resume, etc.).
This is basically the way I’m doing it now and it works I just wasn’t really sure if it would scale well. I think maybe I’m overthinking it though and will continue down this road. Thanks for the clarification.
Yes I think ultimately this is what I needed to hear. I’m at that point right now where I think it’s very easy for me to overthink my base architecture and try and create something generic since my gut tells me that’s cleaner, when in reality I’m just over-complicating matters.
I’ll continue with my current methods until I face some reason to change it.
awesome.
don’t stress too much. it’s ok to be free to experiment and find what suits better.
it’s good you did a sanity check anyway.
i agree with kemichar and you. you might be overengineering.
imho i’ve found that what works for me after many years of trying different things is:
just program what you need, and not more, in the best way you can think of at the moment.
try it out for some time.
refactor or add features, but only when necessary.
generalize and optimize once the systems are in place and tested. not before. (unless your app is performance oriented like real time trading).
maybe you can start three systems. and later, after testing and seeing how they grow, you can generalize the bits that make sense.
i find that when implementing something, it’s almost always the case, that you find out of edge cases and quirks you werent planning.
you will notice that your understanding of the problem, and even your skills, gets clearer as you let the systems “settle” for a time. that still happens to me after many years.
a saying from my grandfather that used to be an electric engineer was “measure twice, cut once”. which implies you try it out and see how it fits before you commit.