Welcome.
Now, throughout our levels, we're going to have enemies.
Now, sometimes you may not want all of your enemies spawned at the beginning of the game, even if
your player controlled character starts off way far enough away from them for them to even find the
nearest player, they're still taking up resources, aren't they?
And you may not want them to spawn in until your player controlled character has progressed to a certain
area.
For example, maybe in this little mini dungeon, you may not wish to spawn any characters until Ora
runs through this hallway here, at which point you may wish to spawn in some enemies back here.
Now I'm going to go ahead and take this.
It's sort of in the way at this point, and I'm going to, I think, remove it for now.
And let's just say we want a couple of goblins back here, but we don't want them to exist until Ora
runs through here right?
Only at that point do we want those goblins to spawn in, and this little section here is going to bother
me, so I'm going to move it in slightly.
Okay, now with our current system, because there's a nav mesh bounds volume over the entire level,
if I drag in, say, two goblin spear enemies by going to Character Goblin Spear and just bringing in
two.
Well, if I press play, what do you think is going to happen?
They're going to come in after me, right?
They're coming for me.
And maybe that's not what you want.
Maybe you want them to not even be there yet.
That's why I'd like to create a spawn volume.
Some kind of actor that has an invisible volume, perhaps a box component that once we overlap with
that box component, then we can spawn in enemies at any location we want.
Say I run in through the hallway here.
As soon as I run in through the hallway.
I'd like two spear enemies here and perhaps a slingshot goblin somewhere up there, just for example.
How can we manage to make that happen?
Well, that's actually not too difficult.
And if you're so inclined, take it as a mini challenge to create this system right now.
Otherwise, let's get started.
I'm going to create a spawn volume.
Now that's going to be an actor, but I'd also like to create a new class for a target point that can
be placed in the world.
Now there exists a class in the engine called Target Point.
In fact, if we go to the Place Actors panel and search for target, this is the target point actor.
It's quite simple.
We can drag it in and it is simply an actor with a billboard that looks like a target, and we can use
it for its location in the world.
I'd like to use this class, but I'd like to subclass it.
It would be nice if I could bring in a target point, and here in the details panel, select the character
class and its level to spawn a character in at.
So that's my goal, and I'm going to create a class based on this target point actor to do that.
So I want two new classes, right?
I'm going to open up my C plus Plus classes folder into Aura Public.
And these can go into the actor folder.
First I'm going to make a new C plus plus class and search for Target Point.
I'm going to choose Target Point and I'm going to call this aura Enemy spawn point.
I'm going to create this class.
I'm going to click no because I want to create another one.
And this one is going to be a simple actor.
So I'm going to select actor next.
And this will be called Aura Enemy Spawn Volume.
And we'll go ahead and create this class and close out.
Now what are these classes going to have.
Well they're not going to be extremely complicated.
Let's get them both open I'm going to get their CP files open first so they can stay to the left.
I'm going to open first my aura enemy spawn point dot CP and aura enemy spawn point dot h, then aura
enemy spawn volume dot cp and aura enemy spawn volume dot h.
Opening them in that order puts them up in the order that I want them to be in.
Lifehack now aura enemy spawn point doesn't need much, but I'd like it to have at least some information
now.
It'd be really, really useful if the spawn point itself could contain the class to spawn.
So what I'm going to do is make a public section and give this a subclass of.
Of class a ora enemy not enemy.
Spawn point a ora enemy.
The actor.
Now yes, I know I've been forward declaring up at the top the whole time.
Why would I go and break that convention?
Now?
Let's just keep that consistent and we'll call this enemy class.
Of course it gets a U property, but it's going to be edit anywhere, blueprint read only and category
enemy class.
Now, I'd also like to spawn an enemy in at a given level.
So I'm going to make an INT 32 called enemy level and set it to one by default.
So if we don't set it well, we don't have to worry.
We'll get a level one enemy.
I'll give it the same exact U property.
And finally an E character class.
We're going to add the include and that include is for character class info.
So we'll just get that include.
And this is going to be the character class.
This can get an E character class warrior value by default if we don't set it.
And again same U property.
And finally, I'd like each of these spawn points to be able to spawn their own enemy so we can give
it a function called Spawn enemy.
And this can even be blueprint callable so as to maximize its usefulness.
And we can go ahead and define spawn enemy.
So what is spawn enemy going to do.
Well it's going to spawn an enemy of course.
And I'd like to make some f actor spawn parameters called spawn params.
Spelled correctly for the enemy.
And the first thing I'm going to set on spawn params is the spawn collision handling override.
Because not having this set right could give you some behaviors that you don't expect.
So I'm going to use e spawn actor collision handling method.
Adjust if possible, but always spawn that way, even if there's stuff in the way and we can't quite
adjust the location good enough, which shouldn't be the case.
If you are a good level designer and put these points in places, that shouldn't be problematic, but
still we'll adjust if possible, but still always spawn.
Now for the spawning, right?
I'm going to make an A or a enemy called enemy and use get world spawn actor.
And I'm actually going to use spawn actor deferred a or enemy.
Now we do need to pass in enemy class.
Of course, and we can give it the transform with Get Actor Transform.
This will get the transform of this spawn point.
But I want a spawn actor deferred because I want to set some things on the enemy, right?
The enemy needs to come in at the correct character level.
So.
So our enemies have a level.
Let's go back and look at what that's called in the character folder.
Let's go to the public folder character or enemy and search for level.
And I believe it's actually just called level but it's protected.
We want to be able to set that level.
So I'm just going to make a public getter for it.
And while we're at it, what about our character class as well?
Looks like that is something on the character base.
And that is going to be protected as well.
So we're going to need a function to set both of these.
Set the character class and set the level.
Let's add a public function to set the character class first void set character class e character class
class.
And it's going to set character class.
Equal to class.
In fact, let's call this in class.
Class is just too close to things with other meanings in C plus plus.
So we got that public setter in or a character base, and then our enemy is going to have a void set
level and 30 whoops and 32 in level.
And level equals in level.
So we have those setters and our or enemy spawn point can call set level.
Now I'm going to close our enemy close or a character base and we have enemy level.
We can set that and we can set the character class.
So enemy set character class, character class.
Now we can finish spawning so we can say enemy finish spawning.
And use get actor transform.
Get actor transform.
And finally, one last little detail.
When spawning AI characters, they're not going to spawn in with a default controller unless we call
spawn default controller.
Now they'll be able to run around and attack us.
So now we have our enemy spawn point.
Great.
Now we need our enemy spawn volume.
Now this is also going to be quite simple.
I don't even want it to tick.
I'm going to remove the tick function altogether.
I'm going to remove these useless comments and remove the tick function in the cpp file.
Remove the useless comments here I'm going to set B can never tick to false because I don't want a tick.
And here we go.
We're ready to code now.
I'd like this enemy spawn volume to be a saved actor with a breached boolean, just like our checkpoints.
Why?
Because if we've reached this already, I'd like to save that.
And next time we come into the level.
I don't want to spawn those same enemies anymore.
I want to consider that part of the dungeon completed.
So here's what I'll do.
I'll inherit publicly from the I save interface, and we can implement the function on the I save interface.
Therefore we're going to say save interface here.
And we're going to have an end save interface here.
And this section is for virtual void load actor implementation.
Let's go ahead and get that in here.
And we're also going to have a boolean for when we've been reached be reached.
It'll be false by default but it can get a Uproperty.
We can give it blueprint read only.
And we're going to make it a save game variable.
That way when it's loaded back in, be reached will be set to true.
And we can check that in our load actor implementation.
But what really is this spawn volume going to have?
It's going to have a couple things.
For one, it's going to need a box component.
I'd like a private section for that.
So it's going to be a T object pointer of type U box component.
We're going to add a forward declaration for that and call this box give it a U property I'm sorry this
is a way at the bottom of the screen.
Let me scroll up a little bit and visible anywhere we'll have a box.
We'll also have an on box overlap which is going to have the same signature as our other on overlap
functions, such as that in the checkpoint.
So we can go to checkpoint dot h and steel on sphere overlap.
Of course it's now going to be called on box overlap.
But we're going to steal that.
And put that in the protected section on sphere overlap becomes on box overlap.
And hey, we're coding, let's get this defined.
And let's while we're at it in begin play, we'll take our box get on component began overlap.
Add dynamic.
This and a or enemy spawn volume on box overlap like that.
Okay, so when our box has been overlapped, we can set first of all be reached equal to true.
That way when we load the actor, we can check that if be reached is true.
And you know what?
This can be as simple as if be reached.
Destroy, then not only can we not overlap with the box component, this actor won't even be here anymore.
It's going to destroy itself.
Now the constructor can do a couple things.
It can construct our box.
We haven't done that yet.
So we can say Createdefaultsubobject you box component and we'll call this simply box.
We can set the box to be the root component.
We can take the box and set collision enabled to E collision enabled query only.
No physics necessary.
And it looks like I accidentally put be reached here.
We can also set its collision object type.
We can make it EQ world static.
We can set its collision response to all channels and we can use ECR ignore.
And we also are going to want to set the collision response to the pawn to overlap.
So set collision response to channel E collision channel pawn ECR overlap.
Now what would we like to do in on box overlap.
Now that we're set to overlap with the pawn class?
Well first I don't want to overlap with any pawns except for Ora.
So I'm going to say if not.
Other actor implements you player interface.
We'll return.
In that case.
I don't want it to do anything unless it's Ora.
Now, if it is Ora, I want to spawn some enemies.
Which means I need some spawn points so I can go back to Ora enemy spawn volume and add an array of
those.
So this will be a ora enemy spawn point pointers called spawn points, and I want to set this from each
individual instance in the world.
So this is going to be edit anywhere.
Now for spawn points we're going to loop over these.
So we're going to say for a or an enemy spawn point we'll call it point in spawn points.
And we'll check if that point is valid.
So if is valid point.
Then if it is valid, we'll take the point and we'll call spawn enemy.
And by the end of all this, after that for loop, I'm going to destroy this spawn volume.
And that's it.
That's all the spawn volume is going to do.
So let's go ahead and run and debug mode and make a couple of blueprints based on this.
All right.
So I'm going to make a new folder in blueprints.
We'll call this spawn volumes.
Here in spawn volumes, I'm going to make a new blueprint based on our enemy spawn volume called BP
Spawn Volume.
I'm also going to make a new blueprint based on our enemy spawn point, and we'll call this BP Spawn
point.
Now first I'm going to configure the spawn point.
I'm going to give it some default values for the enemy class.
I'll give it BP Goblin Spear.
I'll let it be a level one warrior.
And that's all good.
Now for BP spawn volume.
I'm going to take my box and set its line thickness to something bigger, like five, so we can see
it in the world.
And for now, I think I'm going to set hidden in game to false so I can see it even in the game.
And I'm going to bring one in right here into the hallway.
And with it selected, I'm going to select its box and adjust the box extent like so.
Now that I have a box extent, I can give it a couple of points.
So I'm going to bring in two spawn points.
One here, I'll bring it up a bit as if it's in the ground.
That can cause some issues with spawning.
Now these have default values of BP Goblin spear.
All I need to do is add them to my box as it has a spawn points array, so we can take spawn points
and add two elements and use the eyedropper tool and choose one and use the eyedropper tool and choose
the other.
And now it has points.
So saving all we can press play and we can overlap.
We see that the box went away and here come a couple of enemies.
Now I'm seeing that they're not attacking, so that's a problem.
But our spawn volume works.
So let's see what's going on with I.
We'll go to the AI.
Let's take a look at the tasks and BT attack right here.
Let's see if we're even getting this attack task.
We'll print the string.
Hello.
And let's get those enemies in.
Okay.
We're getting.
Hello.
We're going to try Activate Abilities by tag so we can go to the melee ability, blueprints, ability
system, enemy abilities, melee attack, and I don't see any montage.
I'd like to make sure that our.
Goblin spear.
Has its attack montages.
For some reason it does not.
I'm going to click plus and give it its attack montage.
Am attack Goblin spear.
I'll give it its montage tag.
Let's see what our Goblin slingshot has.
It has montage attack one.
Goblin spear can get.
Montage attack one.
And the socket tag is going to be combat socket weapon impact sound.
I believe was SFX swipe.
No it wasn't.
It was actually Goblin swoosh.
Yes.
Okay.
So that got reset somehow.
Let's make sure that that's going to work.
Yep, there we go.
Now, of course, aura dies because we're not loading in from disk.
She's actually loading in with zero health.
Notice those ghost globes go all the way down to zero.
But the important thing is that these enemies spawn in and they attack and cause damage as expected.
Okay, so we have spawn volumes.
This is great.
And we can also check to see if they're being saved by going in and loading from the load menu.
I'm going to go ahead and just delete any slots I have and make a new one.
Load that slot and run in here.
Trigger this volume.
And I need to actually save the game.
And I don't want these enemies to stun me.
So I'm going to need that goblin melee attack.
To not have a debuff.
Chance of 100.
I'm going to set it to zero.
And it looks like their attack is set to damage lightning.
I'm not sure how that happened or when, but I'm going to set their damage type to physical and now
they shouldn't just automatically debuff me.
Now I'm going to load in through the load menu, and I have to trigger this and then go back and save
the game.
Like so and then load back in.
Okay, so it was not saved.
So looking at ora enemy spawn volume.
We're implementing the save interface, we're setting breached to true upon overlap.
We need to make sure we're saving this.
So I'm going to check out the game mode or a game mode base.
And look at load world state.
I'm going to place a breakpoint here.
And I'm going to.
Go in through the load menu.
And just cycle through the actors.
We're loading.
We have a beacon.
We have.
A checkpoint.
And we can see it up here.
Checkpoint two.
Checkpoint.
Begin.
And that's it.
We don't get our spawn volume.
So in our game mode, save slot data, I'm realizing that because we call destroy on the actor, it
will not be valid by the time we save the game.
So if we really want to save this actor, then we're not going to destroy at the end of spawning all
of these, really, the only thing we need to do is disable the box collision and it'll destroy itself
next time we load.
So we'll just take the box here, set collision enabled to E.
Collision enabled.
No collision.
That's going to fix that.
So I'm going to go ahead and close out and we'll run in debug mode.
So it's things like this that testing will bring to light.
It'll make you realize that if you destroy this, well, next time you save the world, you're not going
to actually save it.
It's been destroyed.
So now what we can do is we can load in through the load menu.
We'll create a new slot for this.
We'll go ahead and use this.
We'll reach it.
Now we're not destroying it.
But if we save the game.
And exit and come back.
Looks like I still have my break point, so I'm going to remove that and continue.
Now I came back in no spawn volume.
It's been destroyed at the beginning of the game.
Perfect.
So now our spawn volumes work.
We can use them to flesh out the rest of our levels.
Excellent job.
I'll see you soon.