Help with spawning enemies and peforming an action before AI takes control

Hi, I’m working on a Enemy Spawn system for a side scrolling beat em’ up and I’m trying to figure out how to make an actor take a set of actions before the AI controller takes over.

What I think I need is to pass information into a spawned actor from the SpawnActor node or barring that a method of how to infer this when an enemy is spawned into the world.

The main setup is

1.) A Battle Event actor that is a collision box checking for when all players overlap to start the battle event itself. It also holds a data asset reference with information about each “wave” of enemies I want to spawn for the event including

  • Number of waves that will spawn
  • what the transition between waves in (all enemies defeated or spawn next wave after a timer)
  • a list of enemies to spawn in the wave that includes
    • Reference to the class
    • Where it should spawn (this is the main information I’m trying to get access to when spawning), left, right, top or bottom

2.) A battle event manager actor that listens for the battle event call from the battle event actors in the level

When the battle event sends the trigger event of “Battle Event Started” the battle event manager then handles a few things
1.) Ease the camera to the battle event area and lock it
2.) Set up level bounds so players can’t leave the screen area
3.) Set up information and remember information about the on going battle event (# of waves, current enemies, enemies defeated, etc..)
4.) Begin spawning enemies using said information


What I’m trying to achieve is, when an enemy spawns, it needs to set an animation (based upon position of the screen it’s coming in from, left, right, top or bottom) and then move onto the screen.

The hope here is you have the standard beat em’ up style of the enemy walking in from the sides before the AI controller takes over, but also can drop in from the top (like falling from a ceiling vent) or come in from the bottom (maybe they’re climbing up a cliff face the players are walking past)

I don’t think I can achieve having the “walk on” set of actions in the event manager as then each enemy would have to walk on one by one instead of all at the same time which is what I want.

I’m assuming that the best route here is in the begin play for the enemy to take in the passed in position and then switch upon what animation it should set (walking, falling, climbing) move onto the screen and then have the ai take control.

I’m just not sure how to pass in, upon dynamic spawn, the information for it to make that decision, so I was hoping I could get some help connecting those dots.

(I know I have the spawn default controller in the event manager, but this is left over from testing out solutions)

4 Likes

Alright so, after a lot of back and forth, trial and error, an extra couple grey hairs I have come to a solution that i’ll share in case one day maybe it helps someone else out.

What follows probably isn’t what most would consider the “best” solution, but it’s what i’ve come up with after trying to get answers from different sources and good ol’ fashion elbow grease, but i’m very happy for any feedback or pointers as a nooby if anyone has some to give.

First things first, handling your spawned actor taking an action is both much easier than it appeared, though met with a couple issues.

Simply put, the SpawnActor node’s return value is a reference to said actor, so form there I just created a function in said enemy called “Spawn Actions” that you can call once you have said reference.

*Note that in the long run I intend to turn this into a Blueprint Interface to avoid casting to specific objects here, but this is my “get it working on the screen” fix as I only have one functional enemy at the moment.

Now the hard part here is I couldn’t technically complete the actions I wanted to within a function.

The goal is for the enemy to spawn offscreen and walk onto it before the AI controller (and thus the Behavior Tree) takes effect.

Issue #1 - My original implementation of just kind of passing in a side of the screen left a lot to be desired and required a lot of calculation / data passing that wasn’t easily handled directly in the manager, things like spawn position, where to spawn, and what will likely be more info in the future as the game expands.

To get around this I ended up creating a BP_SpawnActor actor that is an object placed in the world, with a set of them as an array attached to the Battle Event that has an enum to represent it’s position relative to the battle event. This should in theory allow for a designer to come in an easily set up battle events without knowing any code, you just set # of waves, enemies to spawn in said wave, and which position they spawn at and when the event manager triggers a wave it just cycles through the spawners to find one that matches with the position it should spawn at and initiates SpawnActor.

This makes it a lot easier for me in the long run to determine decisions in the spawning itself, like which direction they should walk towards the player (as they may not have a valid target yet)

Issue #2 - Making the enemy walk onto the screen was a lot harder than it seemed it should be. I wanted them to spawn and complete their action before the spawner is allowed to be in use again which necessiated two things, a move function and a callback (as other enemies like a boss may also play an animation and sound effects before their “spawn action” is complete)

While there are some Move To functions you can call, you can only call AI MoveTo (which provides a callback to when the move is finished) inside the main event graph since async options don’t work inside a function, so what you can see from above is I get some necessary information and then call a “SpawnEvent” that then runs the async options I want to happen.

Definitely note the stop and start logic there. One thing that was tricking me is the AI MoveTo does not work unless an AIController is already spawned for the enemy, so I needed to do that for that function to work, however the Behavior Tree would immediately kick in resulting in the AI MoveTo being immediately disregarded in favor of the other actions the behavior tree expects to do. So to get around that thankfully we have access to the Stop and Start logic functions which essentially acted as my “AI Controller take back control after I do the initial custom thing when you spawn”

One option that was suggested to me as well was in the Behavior Tree have a Bool Blackboard Key “hasCompletedSpawnLogic” that is it’s own mini behavior tree section to do all the things I want and then turn that bool object to true so the rest of the behavior tree functions as normal. While I don’t mind this solution it was proving rough to implement as i’m not amazing with behavior trees and was just taking me too long.

I am also very tempted to test out and potentially switch over to State Trees as they look more intuitive to how I want to make the AI work that I didn’t want to get bogged down in the Behavior Tree since I was already kinda planning to refactor it out if my research into State Trees shows I like them better.

Now it’s definitely not perfect and I’m already aware of some issues i’ll need to handle with more polish in the long run, like how to handle a spawned enemy being beat up before it’s spawn action is complete and i’m sure other things, but I was at least happy to kind of get my initial idea into a working state.

So here’s a GIF of it working in action!

Spawner