I’ve been cleaning up some code and trying to put things in the right place. There are times where putting some code in BeginPlay/EndPlay wasn’t the best place but then I ran into some components breaking after I moved code into UninitializeComponent.
I’ve seen a lot of engine code have some things in one function and some in other functions. I’m wondering if there’s a rule of thumb of where things should go generally.
It’s quite difficult to say because it depends on what you want to do. Some code can only run in the constructor, some only on BeginPlay or after some form of initialization process.
If we look at the AActor class we can see that the initialize methods are called conditionally at various moments which does not make this simpler to explain. The below scheme is simplified, note that methods are called or skipped conditionally.
Top to bottom: Execution order.
Indentation depth: Method is called by the method above it with less indentation.
In general , do everything within BeginPlay if possible and do not make your code dependent on other actors having ran BeginPlay, since BeginPlay can run at any time in any order. Make your delegate bindings on BeginPlay and act on delegates using the observer pattern, so you barely have to worry about the order in which things execute.
I noticed MovementComponents tend to do some things in InitializeComponent like auto assigning themselves to act on the root component of the actor.
Endplay was always kindof confusing since there are different reasons for Endplay to be called. UninitializeComponent, I expect, is definitely called when the component is essentially being killed off. Is it a good idea to always check that the reason is Destruction before doing things in EndPlay?
I don’t know, have not used that method myself. It might be a strange place to implement any logic because I have a feeling many objects would be invalid so “late”. But I could be wrong.
It normally runs right after EndPlay just if the object is for sure needing to be uninitialized, just like BeginPlay runs right after InitializeComponent.
In fact, I may be wrong but I think UninitializeComponent is recently added, but InitializeComponent has definitely been around for a while since I saw it used in MovementComponents long ago.
It seems like InitializeComponent is a great place to do things like check for existing components in an actor and link things up. Like how MovementComponent finds the RootComponent and tries to set that as its target. These are things you know would already be set up in the actor. It’s also a C++ only function so you wouldn’t even be able to do these things in anything but BeginPlay if it was blueprint.