Welcome back.
Now we have some demon enemies, but we'd like to summon these.
I'd like this to be part of a special ability for our shaman, where our shaman summons a bunch of little
demon minions.
So for that reason, I'm going to close all of these tabs.
And just to remind you what that summon animation looks like for our shaman, we can go to assets,
enemies, shaman animations and check out Shaman summon.
And this is what it looks like.
So what I'd like is an ability that will play this as a montage, perhaps, and choose a number of points
in front of the shaman at which to spawn little demons.
And those demons can go do its bidding.
So in this video, we're going to get started with that by creating the ability and devising an algorithm
to choose spawn locations for each of these demons.
So let's go ahead and get started.
Now I'm going to need a C plus plus class for a new ability for the shaman.
So I'm going to go to C plus plus classes or a public ability system abilities, and I'm going to make
a new ability.
Now, this particular ability is just summoning creatures.
It's not really spawning projectiles.
It's not really an attack per se.
So I'm going to base this on a gameplay ability as it doesn't really need a damage variable.
So I'm going to right click on aura gameplay ability and create a C plus plus class derived from aura
gameplay ability.
And this is going to be a summon ability.
So I can call this summon ability, we can call it aura summon ability if we want to.
In a sense that aura prefix's most of the things in this game.
So we'll call this aura summon ability, we'll create the class.
And we'll close the editor and I'm going to go ahead and close all tabs here and just open my abilities
folder, get my aura, summon ability open and we can start thinking about what to do with our aura
summon ability.
Now, I don't want to override, activate ability.
What I'd rather do is create a blueprint callable function and script out the ability logic in the blueprint
as we've been doing, as this is the way that gas is meant to be used.
So I'm going to make a nice blueprint callable function to calculate the spawn locations.
So this is a summon ability.
We need an array of spawn locations.
It could be an array with a single element in it, as I'd like, this ability to be sort of configurable
with parameters and all.
So first I'm going to make a public section and we'll make a function that returns a t array of vectors.
So t array of F vector and this is going to be called get spawn locations.
So get spawn locations is how we're going to know where we should spawn our little demon minions.
I'm going to refer to them as minions in this ability.
So that way it's not specific to demons per se.
It's really whatever minion you choose, whatever enemy class or whatever character class you choose
to spawn.
So as far as this ability is concerned, we're going to call that a minion whenever we spawn something.
Now this is going to be a new function with Blueprint Callable and get Spawn locations is going to be
an algorithm that we devise to get a number of locations around our enemy in the front of it.
And I'm going to want several variables to determine how this algorithm is going to behave.
So for one, we need a number of minions.
That's going to be an int 32 called num minions.
It could be num minions to spawn.
ET cetera.
Now I'm going to set it equal to a value by default, let's say five, but this should be configurable,
so it'll be a new property add anywhere.
Category.
And these are all going to be properties under the summoning of Minions.
So we're going to call this summoning.
So we have a number of minions, so we need to know what class to spawn or class is if we're going to
spawn multiple, even potentially different types of enemies or characters.
So we need to have an array and we can make this a t array of characters or pawns, but it should be
a subclass of I'll just make it a T subclass of a pawns that we can spawn and we're going to call this
minion classes.
And of course this needs to be editable.
We'll make this edit anywhere.
In fact, this is a gameplay ability, so I don't see any need to make it edit anywhere.
We can make them edit defaults only instead.
So we have our minion classes now.
I'd like a minimum and maximum for the distance from our shaman or whoever's doing the spawning.
I want a minimum and maximum distance away that we should spawn our minions at.
So I'm going to make a float called Min Spawn Distance and I'll just give it a default value of say,
50 and a float called Max spawn distance and I'll give it a default of say, 250.
And these both also get the same view property.
So we know how many minions, we know how far they should be spawned, but we also need a spread.
I really don't want to spawn these all around the shaman.
I'd rather them all be spawned relatively in front of the shaman.
So I want an angle of spread for spawning.
And I'm going to call this spawn spread.
It's a float.
And I'm going to set this to 90.
So basically we have a 90 degree spread and we'll fan out our spawn locations within that 90 degrees.
But this, of course, will also be editable.
Okay.
So we have a number of parameters and a function.
Let's implement this function.
I'm going to generate a definition and all I want to do is generate this t array and return it, but
also probably draw some debug shapes so we can visualize what this looks like.
Now I'd like to take this in steps.
First, I want to visualize that spread and the minimum and maximum distances.
So the first step I think is to get the actor forward vector.
I'm going to make a const f vector called forward and get the forward vector of the avatar actor.
So I'm going to get Avatar actor from actor info and call get actor forward vector.
So we have the forward vector.
We can also get the actor location as well.
I'll call it location and call get Avatar actor from actor info, get actor location.
So we have forward and we have location.
Now we can rotate vectors, for example, we can take the forward vector and we can rotate it by using
rotate angle axis.
Now if I use rotate angle axis, I have to specify how much to rotate my vector.
Now I can rotate it by half of the spread and that's going to rotate it.
If spawn spread is 90 degrees, it'll rotate it by 45.
So I'm going to take spawn spread and divide by two.
That will give me 45 when spawn spread is 90 and I'd like to rotate about the Z axis.
So what I can do is I can take F vector up vector that gives me the vector pointing up and this gives
me the forward vector, but rotate it.
I'm going to store this in a local variable for now, const f vector and I'll call this left of spread.
So it's to the left of our spread.
It's the left most boundary.
And what I can do is I can draw this as a debug arrow or a debug line.
I like debug arrows as they're directional and there's a way to draw a debug arrow with you.
Kismet System Library.
And the function is draw debug arrow and this requires a few parameters.
First, it needs a world context object we can pass in get Avatar actor from actor info.
Now for the start of the line that's going to be location for the end of the line.
That will be location plus left of spread.
But left of spread is a unit vector as our forward vector is a unit vector, a vector of length one.
So I'm going to scale this and I'd like to scale it by my max.
Spawn distance.
So our line end is location plus left of spread times.
Max spawn distance.
Now, for arrow size, we can just put whatever we want here.
I'm just going to put a four.
Dot f.
Now for the color, I'm going to have a vector for left of spread and right to spread, and I'm going
to make them different colors so we know which one is which.
So for left of spread, I'm going to make it an F linear color with green and then we'll really see
if it's to the left or to the right of the spread or not.
And for the duration.
I'm going to use three seconds.
And there we have our debug arrow.
So we have left of spread.
But I'd like to create another one called Right of Spread and I'd like to rotate it the other way.
So this one I'm going to call right of spread and instead of rotating it by spawn spread divided by
two, we're going to rotate it by negative spawn spread divided by two around the up vector, and we're
going to draw the debug arrow.
But instead of using left of spread, we're going to use right of spread and we're also going to change
the color.
Let's make the color something else like gray.
Okay.
So I think we're going to want to test out how this works so far.
So what we can do is we can choose to return an empty array for now.
So return t array.
Of F vectors.
And we'll just use parentheses there so that we can just return an empty array.
I'm not really concerned with the array just yet.
I just want to take a look at what our geometry looks like for these vectors we've calculated.
So let's go ahead and run and debug mode.
Okay, so we're back in the editor.
We're going to make a blueprint based on our new gameplay ability.
And this will go into blueprints, ability, system enemy.
And really, it doesn't have to go into enemy, but we're going to make one for the shaman specifically.
So we'll go into abilities, we'll right click create Blueprint class and use aura summon ability.
We'll select that and call this GA underscore summon ability.
We'll go ahead and open this.
And when this ability is activated, I'm going to right click and I'm going to call our blueprint callable
function, get spawn locations.
And from there we're just going to see a couple of debug arrows.
Now, if we want to see this actually happen, if we want to see this ability activated, we're going
to have to give it a tag.
If we go to class defaults and for the ability tags, we're going to give it the abilities attack tag
just so that it already works with our behavior tree task attack.
And now we just need to give this to our elementalist enemy type.
So what I'm going to do is go into blueprints, ability system data and open character class info and
for the elementalist instead of the enemy Firebolt.
I'm going to change this to a summon ability so it's not going to fire firebolts anymore.
At least not for now.
Don't worry, it will in the future.
We're just seeing how this works.
We're going to activate the summon ability.
So let's give this a try.
I'm going to remove these demons and just add a shaman.
So we're going to go into the shaman folder, bring that in, and as soon as BT attack the behavior
tree task is executed and it's going to activate abilities by Tag.
And because this has the attack tag, we should see these spawn locations.
So I'm going to save all press play.
And there we see the spread and we see the two different colored vectors.
Now we call the green one left of spread.
And from Ora's point of view, it is the left.
But from the enemy's point of view, that's actually the right, isn't it?
So we kind of got those mixed up.
The first one is the right, the green one, that is.
And the gray one is the left.
So what we can do is rename this one to right of spread.
So the first one is right of spread.
And the second one here, this is left of spread.
So we're going to just swap their names.
And that way we're looking at this from the point of view of the enemy, the shaman.
So that Green Arrow is actually the one to the right, as we can see when playtesting there, that's
the right the gray one is the left.
Okay, so it looks like we have a pretty good max distance.
We could probably up that to about 300 and we can't really see how far away the min distance is, but
I'm assuming we'll probably want to up that to to about maybe 75 to 100.
So we'll just tweak these parameters in some inability.
We'll go to class defaults, but we can always change their defaults in C plus plus as well.
But I'm going to use a min spawn distance of 75 and a max of 300, but I'd like to also take a look
at some debug spheres at those distances.
So what I'm also going to do is after drawing these debug arrows, I'm going to draw debug spheres at
the min and max distances along these lines, right of spread and left of spread.
So I'm going to actually call draw debug sphere.
The first input is the world I'm going to call Git World.
Next, we have the center of the sphere.
Now this is going to be at the location of Location Plus.
And I'm going to add right of spread only.
I'm going to scale right of spread by that min spawn distance.
This way we can visualize how far away it is.
Now, the radius of this sphere can be small.
I'm going to make it about 15.
Number of segments can be 12.
I always use 12 F color can be red.
And persistent lines can be false.
Lifetime can be three seconds.
So we're going to draw that debug sphere, but I'm also going to draw another sphere at the max distance.
So I'm going to copy and paste this and the only thing I'm going to change is from min spawn distance.
We're changing to max spawn distance, so we'll see a sphere at the min spawn distance.
This will allow us to know how far away or how close the demons will be once we start spawning them.
Or the minions, I should say.
Now we're going to do this at the right of spread vector, but we're going to spawn two spheres along
the line of the left of spread vector as well.
So I'm going to copy those two lines, paste them here and change right of spread to left of spread.
And now we're going to see what this looks like.
So I'm going to go ahead and close the editor and run in debug mode again.
Okay, I'll go ahead and open up our ability.
But really I just want to press play and see those debug spheres.
Now, as I suspected, the min spawn distance is a little close.
I don't want to spawn any minions that close so we can go back to summon ability and change min spawn
distance.
I think 150 is actually probably good.
Let's see what 150 looks like.
That's probably better.
And I could probably even push that max spawn distance out a little more to say maybe even 400.
And that way we'll have a nice area here and we'll spawn enemies within that area.
Now we want a spread, I want an even spread.
So I want to spawn an enemy somewhere along the lines of that left vector and somewhere along the lines
of that right vector.
And I'd like to spawn some enemies all in between.
So I kind of want to take this spread and divide it by my number of minions that I want to spawn, and
that should give me the number of vectors along which my minions can be spawned.
So what I'm going to do is I'm going to close the editor.
And I'd like to take my spread and divide it by the number of minions I want to spawn.
This will give me the number of vectors that I need to calculate.
So I'm going to have a float.
It'll be a const float and this will be called Delta Spread, which is going to be my spawn spread,
which by default is 90 degrees divided by my num minions, which by default is five.
So 90 degrees divided by five.
This will be the angle between each of the vectors that I want to spawn minions along.
Now, because I have a num minions, I'm going to want to do a for loop here and draw debug arrows in
a spread spreading out like a fan and I want to start at right of spread and continue rotating by delta.
Spread each iteration of the for loop and just draw some debug arrows.
So here's what I'm going to do.
I'm going to make a regular for loop with an int 32 called I set it equal to zero and as long as I is
less than num minions I want to continue.
Didn't mean to autocomplete that so it's going to be.
Num minions and we're going to use I plus plus.
So at first I is zero and I want to draw that right of spread vector.
This is going to be sort of my beginning vector, my starting vector.
So I'm going to move it just up above the for loop.
And I'm going to calculate a direction vector.
So const F vector.
Call direction and it's going to be right of spread.
But I'm going to take right of spread and rotate it.
So I'm going to use rotate angle axis and I'm going to rotate it by delta spread times I.
So the first time I will be zero, the first iteration of the loop and it will be just right of spread.
We won't rotate at all.
But the second iteration of the loop, we're going to rotate by delta spread and so on.
And we're going to rotate about the up vector, so F vector up vector, and then we can simply draw
that debug arrow.
So I'm going to copy that line, paste it here.
Only the debug arrow is going to start at location and end at location plus direction times max spawn
distance.
So now we'll be doing five lines because num minions is five and now I don't need those other draw debug
arrow function calls, so I'm going to comment those out and I can simply run this and see what these
vectors look like.
So I'm going to go ahead and hit debug.
So they should all be green arrows.
But now we can make sure that we're getting an even spread of these vectors.
So I can go ahead and hit play.
I don't really need to keep hitting the open button kind of a habit at this point, but I'm going to
press play and see and it looks like we've rotated the wrong way.
So that's why these debug arrows and shapes are so important because then we can really get to know
the geometry and make sure that we're not doing it wrong.
So we could either start spreading or rotating the other way or we can start with left of spread.
If we start with left of spread, then really all we need to do is replace the name with left of spread.
Arguably don't even need that step, but we need spawn spread here to be negative.
So we're rotating the other way and then direction will be left of spread, rotated by the same direction.
So we're actually rotating in the same direction.
We're just starting from a different orientation and now we don't need this left of spread.
So I'm going to comment it out.
Now.
What I'd like to do actually is take our two calls to draw debug sphere, cut them out and paste them
inside the for loop and replace right of spread with direction.
That way we'll get these spheres drawn and I'm going to make them even smaller.
I'm going to give them a radius of ten and then I can go ahead and comment out all the rest of these
lines.
So now we should see spheres all along each of our lines.
Let's give this a try.
Okay.
I'm going to press play.
And now we see something a little bit more along the lines of what we expected.
So here's what this spread means, at least for me.
This is what I have in mind, is I want to spawn five minions and each of them will be spawned somewhere
along one of these lines between the min spawn distance and the max spawn distance.
So we're going to pick a random location along each of these lines, and I'm going to add those to an
array that our function is going to return.
So what I'm going to do is I'm going to go ahead and pick a random location along the line in the for
loop.
So I'm going to create a const f vector called location.
Actually, I'm going to call this chosen spawn location and it's going to be equal to location.
That's the shaman's location plus direction.
And we're going to multiply direction by a random number in range.
We're going to use F math rand range and we'll use F rand range for the float version and the min is
going to be min spawn distance.
The max will be max spawn distance and that way we'll get some random value between Min and Max that
will be scaling that direction vector by and adding to location.
So this will be our chosen location and we're going to draw a debug sphere to show that spawn location.
So what I'm going to do is right after chosen spawn location, we'll draw the debug sphere and we're
going to draw it at our chosen spawn location here.
I'm going to make it a little bigger.
Let's make it about 18 in duration.
We'll give it a different color.
I'm going to choose Cyan and our other spheres.
I'm going to draw them even smaller.
We're going to draw them at five now.
So now we should be able to visualize our spawn locations and at this point we can actually start returning
something because now we have chosen spawn locations.
We can create a local array just outside the for loop t array of F vectors called spawn locations.
And each time we choose a spawn location, we can add that to spawn locations.
So we can say spawn locations, dot add.
And we can add chosen spawn location and at the end of the function we can return spawn locations.
So really all this stuff that I've commented out is now no longer necessary.
I can remove it and we now have a whole bunch of debug stuff that I'm just going to keep all together
right here.
And let's go ahead and see what those spawn locations end up looking like.
So I'm going to hit the debug button.
And we're just going to hit play.
And there we go.
We have random spawn locations all about that spread.
Pretty cool, right?
So this is nice because now we can kind of see the locations that would be chosen by this algorithm.
That one was a bit of a wider out spread.
This one was a little more random.
So pretty cool, right?
I think this is a nice little algorithm to get, you know, five different locations, but we parameterized
it.
It doesn't have to be five.
We can go back into our gameplay ability.
Let's go into enemy abilities and gain some inability and we could easily change these parameters.
We could change the number of minions to eight.
We can change the spawn spread to 120 and if we do that.
Now we can see that there's an even wider spread with more minions, more enemies to spawn, or at least
more locations to potentially spawn enemies at.
Right.
And that's kind of cool because you could make some kind of formula related to the abilities level,
for example, and then you could spawn more or less enemies based on that.
The possibilities are endless.
I'm going to set the spread back to 90 and the number of minions back to five, and we now have a nice
little algorithm to choose spawn locations.
And that's the first step to spawning enemies with our new spawn ability.
So great job sticking through this video.
It was a little longer, but we did need to devise a little bit of a more complex algorithm.
Not really complex, but more involved, right?
Actually kind of small.
When you remove all the debug stuff, it's not too bad.
But now we have a set of spawn locations and we can use those.
So great job and I'll see you soon.