Today I learned the hard way: SpawnActor will immediately call BeginPlay on the new actor, even before continuing with the nodes after SpawnActor.
Just as a reminder to other people, here was a problem that I was running into today and how to avoid it.
What I wanted to do and what I assumed would work:
- I wanted to create a new actor via SpawnActor, let’s call that new actor [FONT=courier new]“ANewAreaOfMyLevel”.
- After that [FONT=courier new]ANewAreaOfMyLevel actor was created I was trying to set an object reference to an object called [FONT=courier new]“MapManager” on [FONT=courier new]ANewAreaOfMyLevel.
- Do some other bookkeeping work in those nodes after SpawnActor.
- I (wrongly) assumed that once the execution of all nodes inside the function that spawned [FONT=courier new]ANewAreaOfMyLevel finished, the engine would eventually call BeginPlay on [FONT=courier new]ANewAreaOfMyLevel, where I would access the [FONT=courier new]MapManager reference and call a function (SpawnRandomEnemies) on it.
- But all I got was “Accessed None trying to read property MapManager” error messages and at first I had no clue why.
Well, it turns out that BeginPlay on [FONT=courier new]ANewAreaOfMyLevel was called immediately after SpawnActor, even before running the nodes that came after SpawnActor and where I would set the [FONT=courier new]MapManager object reference of [FONT=courier new]ANewAreaOfMyLevel. So basically my SpawnRandomEnemies function of [FONT=courier new]ANewAreaOfMyLevel was called too early and [FONT=courier new]MapManager hadn’t been properly initialized yet and was still set to None, which triggered the error messages.
So, long story short: Be careful with what functions you call in BeginPlay. If those need to access member variables that need to get set from the outside then you either need to call these functions some time later after BeginPlay finished (for example from where you called SpawnActor) or find another way to set those variables from inside BeginPlay. Or (maybe, I didn’t try it) mark your member variable ([FONT=courier new]MapManager in my case) as “Expose on Spawn” so that you can set it right from the call to SpawnActor, but that did not work in my case because the class of my new actor is dynamically determined at runtime.
Now that was a nice trap to fall into and took me a moment to figure out. Maybe this post might help someone in the future.