Welcome back.
Now our Arcane Shards ability is going to spawn some shards, right?
And I'd like my shards ability to spawn multiple shards.
And when I say multiple shards, let's go into assets effects, arcane shards and open up this Niagara
system.
And in preview scene settings, I'm going to show the floor just so I can see what it looks like on
the ground.
I'm going to uncheck Show environment, and I'm going to set the background to a darker color so that
I can see really more closely what it's going to look like.
Now, this system here, I'm referring to that as a shard.
Or we could call it a group of shards.
Now I'd like to spawn one of these, and at level one, I think our ability can spawn it right there
in the center of our decal.
But at say, level two, I'd like to spawn two of these, and at level three, I'd like to spawn three
of them.
And for arcane shards, I'd like to go all the way up to say, level 10 or 11.
I'd like to spawn a whole bunch of these, and I'd like them to be spawned at roughly evenly distributed
locations, and depending on how many were spawning, I'd like them to spawn starting at the inside
of the circle and propagating outward.
So how is that going to work?
Now?
One way is to calculate these locations, to spawn these at procedurally or with some kind of algorithm.
That's one way.
Another way is to have some collection of points that we've handcrafted, rather than using lines of
code to calculate mathematically where we're spawning things.
Now, I'd like to use the approach of having a collection of points that I've placed out manually.
In other words, I'd like to have some kind of actor that contains a bunch of points.
Now, this method has a couple of advantages.
One is that obviously it looks better when points are hand placed rather than calculated with some kind
of algorithm.
Not necessarily, but in general, if you can hand place points, it looks good.
And another thing is our point collection, if it's an actor we create can have its own functions that
can calculate things.
For instance, let's say that we cast our spell on the stairs.
If I want a collection of points, I want to make sure those points have correct locations, especially
their elevation.
I want them to not be spawned underneath the stairs.
I don't want some of them to be spawned at the top of the stairs, and then others in the air above
the bottom steps.
I'd like them to be spawned on the stairs and perhaps even oriented correctly.
Or if we're on a sloped surface, I'd like to spawn these particle systems on the ground.
And so for that reason, a point collection actor can be useful because it can perform some sort of
line trace down to the ground and get the ground location corresponding to those spawn points.
So for that reason, I'd like to make a point collection actor, and this is going to just be an actor.
We're going to stick it in the actor folder so I can go to C plus plus classes or a public actor and
we can put it here.
So I'm going to go ahead and make a new C plus plus class.
I'm going to choose actor and I'm going to call this point collection.
So I'm going to create this class.
I'm going to go ahead and close down the editor, save all my changes.
And I'm going to get this point collection actor open.
I'll go ahead and close all tabs for now and open up Actor Point Collection.
And we'll go ahead and get both header and CPP files open.
So let's clean up this file.
I'll go ahead and remove those comments that I don't like, and move the tick function up to the constructor
and delete that third public section.
We can also remove comments from the cpp file.
And actually my point collection doesn't need to tick.
So I'm going to set primary actor tick be can never tick to false and just remove the tick function
altogether.
No need to override it at all.
And we have a point collection.
Now a point collection should have points.
It should have points that have their own locations.
And one of the most simple types of components that has a location is the scene component.
So we can have ourselves a scene component for each point that we'd like.
So what I want to do is create a whole bunch of scene components.
And I could put these in a private section, and these can be t object pointers, each to a U scene
component.
So in other words, I'll have point one.
I can just use DT one I can actually start at zero because we're programmers, and programmers start
indexing things at zero, don't they?
Unless you program in Lua if you've ever heard of that language.
But that's beside the point.
Let's make a bunch of points.
Now I want about 11 of these, so I'm going to go ahead and just copy paste 11 times.
But I suppose it would be smarter to add a uproperty and copy paste that too.
So I'm going to go ahead and give this blueprint read only.
And when autocomplete isn't working that's an indicator that you have a typo.
So blueprint read only I'll make it visible anywhere.
And if it's going to be blueprint read only, then it should either have meta allow private access like
this.
Equals true.
That would allow us to have a blueprint read only in the private section, or we could just let it be
protected.
I tend to opt for the second option, so we'll go ahead and do that.
So now we have point zero.
We have point one.
And we can paste this a few more times.
I think I'd like to have up to point ten.
So let's do this.
So we have ten scene components.
In addition to that, I'd like to keep these in an array.
And that's going to make them easy to iterate over.
So I'm going to make a T array that holds.
You seen component pointers.
So you seen component pointer.
And this is going to be called immutable points.
Pts immutable in a sense that I don't want to ever change this.
I want to keep it unchanged.
And this is going to be blueprint read only visible anywhere.
And we'll just add all of our scene components to this right off the bat as we construct them.
So to the constructor we're going to go over to the constructor here.
And we're going to construct each of these starting at point zero.
So point zero equals we're going to use Createdefaultsubobject with you scene component.
And we're just going to give these each the name.
That corresponds to their variable name.
So the same internal name.
We're going to add it to a mutable points.
So a mutable points dot add point zero.
And we're also going to set point zero as the root component.
So I'm going to say set root component point zero.
And after that I'm going to construct all the others.
So I'm going to copy these two lines and paste them and change this to point one.
So that I'm creating and adding it to a mutable points.
The difference for this is I'm going to take point one and call setup attachment, and we're going to
call get root component here.
After this we can copy this a few more times until we have all the way up to point ten.
So let's do that.
Okay so that's ten points.
So that's great.
Our point collection is just a glorified array with some perks right.
It has seen components with each their own location in space.
Seen components here are going to be a little bit more valuable to me than just f vectors because I
can place these wherever I want in relation to the root component.
Now, in addition to having a bunch of points, I'd like a nice function that can return an array of
these only.
I'd like to return an array that's a copy of these scene components, or at least an array of locations
in space that represent these.
But the reason I'd like to return an array is because I want to be able to get all these points on the
ground, making sure that they're not below the ground.
Above the ground.
We're going to be performing some line traces.
So I'm going to create a public function here that can get these points.
So whether we return an array of scene component copies or just an array of locations, it doesn't really
matter.
I like the idea of a function returning an array of scene components because they have location, but
also rotation.
So if we have a rotation and we'd like to angle our particle systems that we spawn based on, say,
the normal of the ground, well, we can use scene components for their rotations as well.
So I'm going to make a function here in the public section that returns a 2D array of you scene component
pointers.
And we're going to call this get ground points.
Now get ground points is going to need a couple of pieces of information.
One, it needs to know the ground location.
So we're going to pass that in as a const vector.
We'll call it ground location.
In addition to this, I'd like to be able to pass in an integer into this function to get a limited
number of the points in the collection.
For example, I'd like the first three that are closest to the center, and so on.
So I'm going to go ahead and make an int 32 input parameter here called num points.
And then I'd like to be able to override the rotation as a your value.
So I'm going to say your override and that'll be a float.
But if we don't pass this in I'd like it to be initialized to zero by default.
And this can be a blueprint pure function.
I'm going to make it you function blueprint pure.
As every time we call this, we're going to want it to be executed afresh, anew, a different time.
So let's go ahead and generate the definition.
And what exactly is this get ground points going to do for us?
Well, the first thing is, if I call the function and I pass in num points and num points is more than
how many points I have, I'm going to punish the user who called this function with a nice crash.
So I'm going to say check f, I'm going to say immutable points dot num.
And I want to make sure that this is greater than or equal to num points.
If it is greater than or equal to num points, we're good.
Otherwise we're going to crash with a nice nasty crash log message.
We're going to say attempted to access immutable points out of bounds.
Okay, now that we're done being nasty, let's continue.
And what I'm going to do is first and foremost make a T array.
That's a copy of my immutable points.
So if I shuffle them around in my array, for example, or I remove anything from the array, at least
my original array won't be touched.
So this will be a t array of you seen component pointers.
And I'm going to call this array copy.
Now what I'm going to do is loop through my immutable points array.
I'm going to say for you seen component pointer I'm going to call it t short for point.
And I'm looping through immutable points.
And each iteration of the for loop I'm going to check if array copy dot num.
Is greater than num points.
If it is, we should just return array copy.
As there's no point in continuing, right?
Because array copy now contains greater than num points elements.
After that.
What I'd like to do is get the location of all the points in my immutable points array.
All of my scene components.
But I'd also like to rotate all of my points by the amount of your override that I'm passing in.
And the way that I'm going to set this up is point zero is at the center, so we don't need to rotate
point zero, but I want to rotate all the other points relative to point zero.
And I'm just going to have points one through ten.
Get farther and farther away based on their order away from zero.
So what I'm going to do is I'm going to say if point is not equal to point zero.
Because there's no point in rotating point zero.
So what I'm going to do is make an f vector called two point, and this is going to be the vector from
the center to the point.
So I'm going to take point get component location minus point zero.
Get component location.
So I have the vector from the center to point and I'm going to rotate it.
So I'm going to take two points and set it equal to 2.. rotate angle axis.
And I'm going to rotate about the up vector an amount equal to your override.
So I'm going to say your override as the amount to rotate.
And I'm going to use f vector.
Up vector.
And now that I've rotated this two point vector, then I can go ahead and set my point location.
I could say point set world location, and I can get my point underscore zero and get its location.
So get component location.
Of course this is also the same as get actor location because this is the root component.
But we can get that actor location and add two point to it.
And now we'll be repositioning this point such that we've rotated it by our yaw override.
This allows us to get some variation in the rotation of our point collection.
Now, after doing that, I'd like to perform a line trace straight down to the floor to get the ground
location.
So for that, we need a trace start and a trace end, which will be raised and lowered locations, respectfully.
So I'm going to make a const f vector and call this raised location.
Now this is going to be an f vector.
I'm going to use the f vector constructor.
But I'm going to initialize it with x, y, z components starting with point get component location
dot x so it can have the same x.
I'm also going to use point get component location dot y for the y.
So dot y there.
But for z I'm going to add some to it.
I'm going to use point get component location dot z plus 500.
I don't want to go too far beyond 500 above this points location for the start of my trace.
The end of the trace is going to end up below, so it's going to be called lowered location.
And for this the Z is going to be the original Z of the point -500.
So we start 500 above and we end 500 below.
And now we can line trace between these two.
So I'm going to make a line trace which requires an f hit result I'm going to call it hit result.
And of course, if we line trace, we just might trace down and hit an enemy or any kind of thing we
don't want to hit.
And luckily there's a function to get all live players within radius.
It's a function we added to you or a ability system library.
And we call this get live players within radius.
And this can take a world context object that can be this.
And it also takes an array of overlapping actors.
I'm going to make an array to pass in.
So it's a T array of a actors.
Pointers, of course.
And I'm going to call this ignore actors.
And I'm going to pass ignore actors in here.
Why?
Because get live players within radius will fill that in with all live players.
And that's basically anything that implements the combat interface that isn't dead.
So I'm going to pass that in.
Now this function itself requires an array of actors to ignore.
That's not going to be my ignore actors.
I'm going to ignore nothing with get live players within radius.
So I'm going to make a t array of a actor pointers, but an empty one.
So passing in an empty array there and we need a radius.
So I'm just going to pass in 1500.
We can make that a member if we want.
And then it needs a sphere origin.
We're going to use get actor location again.
That's the same as the point zero location.
But the point of this is to get all the live players within radius and fill them in to my ignore actors
array.
Why?
Because I'm going to now use this as my ignore actors for my line trace.
Pretty clever right?
So what I can do now is I can perform a line trace, and the particular line trace that I'd like to
use is line trace by profile, so that I can only trace against objects that have a specific collision
profile.
And profiles are things like block all, block all dynamic, things like that.
So here's what I'm going to do.
I'm going to call get World Line Trace single by profile.
The first input is the hit results.
So I'm going to pass in hit result.
The second input is the trace start that's going to be raised.
Location.
Next is the trace end that's going to be lowered location.
After that we have the profile which is a profile F name.
And I'm going to trace against block all.
And now we need collision query params.
We can just create some f collision query params here.
I'm going to call these query params.
And this is where I can use my ignore actor's array.
So I'm going to take query params.
Dot, add, ignore or ignored actors and pass in ignore actors.
And we can pass query params in as the last of the inputs for this.
Now that we're tracing and we're ignoring all of the live players within a radius we specified, well,
this is great because now we can take this line trace and get that location from its hit result.
And really, I only care about the Z location of it.
So I'm going to make a new const fvector called adjusted location.
And it's going to be a new f vector.
And I'm going to use the points x and y.
So I'm going to use point get component location dot x point get component location dot y.
I'm going to copy those and paste them here.
And for the Z I'm going to use my hit results dot impact point.
Dot z.
So the only thing that really matters from our line trace is that z location.
Now, after all this.
Now that we have an adjusted location, I'm going to take my point and call set world location passing
in my adjusted location.
Now I can also set its rotation based on that hit result because we have the impact normal.
So what I can do is take point and call set world rotation.
And this needs to be a rotator.
So how do I get a rotator from a vector.
Well I can use you Kismet math library.
And there's a handy function called make wrote from Z.
And this can take in an f vector I can use hit result dot impact normal.
The normal is the vector from the ground straight out perpendicular.
We call it orthogonal when we use 3D vectors to that face that was hit.
And this is actually you kismet math library, not just you kismet math.
I thought I autocompleted it, but looks like I didn't.
Now by the end of this point has been adjusted.
It's been rotated potentially, and it's been elevated or lowered potentially.
So after doing this I'd like to add it to my array copy.
So array copy dot add.
And I'm going to add the point.
Now this doesn't mean that we're creating a copy of the scene component.
We're not.
There's only ten scene components here.
We're not creating any new ones.
We're just moving around those scene components.
So they start off at their original positions, we move them and we return an array that contains some
of them.
Not all of them, just some of them.
Just enough for our needs determined by num points.
And we're looping over all of these points starting at zero.
And each time we're adding one to our array copy, and we're going to return as soon as our array copy
becomes equal to num points.
We said greater than we could use greater than or equal to here.
Really.
Because once this array contains num points we're ready to return it.
And then we can use those scene components in any way we want.
So now we can see how this works.
Of course, our get ground points needs to return an array.
So by the very end of this we have to actually return array copy.
And now that this returns something, we can try this out.
Let's go ahead and compile and launch the editor.
All right, so back in the editor.
Looks like I can close arcane shards there.
I'm going to close our character.
And here in my Arcane shards gameplay ability.
I can try to use my point collection, but I'm going to close project settings.
And before we go and create a point collection, I'm going to make a blueprint based on our point collection
class.
So let's go to blueprints I'm going to go to.
Ability, system or abilities.
Arcane arcane shards.
And I'm going to make a new blueprint here, and I'm going to make this based on my point Collection
class.
And I'll just call this BP Point Collection.
So I'm going to open my point collection.
Now here are my scene components and you can't really see them unless you select them.
You can move them around.
I'd like to position these by hand, and I'd like to position them in order closest to the origin.
The lower their number is.
So what I'm going to do is select point one and move it.
But before I do that, I want to be able to see all of these relative to each other.
So I'm going to take each one, select it and add a billboard.
And that's going to allow me to see that component.
So I'm going to add a billboard to point one.
And then I'm going to move point one.
Now if you add a billboard to point one, don't go moving the billboard, because point one will just
stay there and then they'll have an offset which will just confuse you.
You're going to want to move point one instead.
But before I do that, I'm going to change the billboard texture.
If I search for target, I can use target icon that looks a little bit cooler.
So I can select one of these target icons.
There's one in editor materials in the engine and there's one in engine debug materials.
So now that I have that, I can select point one and I can move it.
Now you can use snapping if you want snapping, or you can just move these by hand.
I'm going to move it a little bit without snapping and just to see where that origin is, I'm going
to take point zero and I'm going to add a billboard to point zero as well.
And I'll go ahead and change this one as well.
I'm going to search for target point or just target.
And here's a target icon spawn.
It's a little bit different and we can just use that to distinguish that middle point.
Now point one over here is 100 units away.
And really, we just kind of need to know how big those shard particles are.
And so in order to see that what we can do is we can drag one in, we can go to effects arcane shards,
and we can bring in arcane shards.
We can set arcane shards at a specific location, let's just say zero zero for x, y.
And if we duplicate this and move it over.
Then we can move this arcane shards over, and it looks like I've moved it by -200.
And we can see what they look like next to each other.
And then we can ask ourselves, are we okay with our shards ever being that close together?
I'm going to set its location X to zero and its location Y to 200, so I can see what they look like
next to each other this way.
Now, if you're okay with that much of a separation, then you can use that as a ballpark when you position
your points in your point collection.
If you need a little bit more room than that, you can set this at say, 250.
And that way you'll see that they're a little bit more spaced apart.
I think that's probably a better distance.
So with that, I can take these and remove them and go back to my point collection and just make sure
that I move point one at least 250 units away from that central point.
And make sure based on this gauge here, that we don't ever move points much less than 250 units away.
So we'll use this as a kind of metric.
Point one is 250 away.
Now I'm going to position the rest of these.
So first I'm going to take point two.
And I'm going to add a billboard component.
And I'm going to search for target and use the target icon.
From editor materials, and I'm just going to position it.
And I don't even have to use snapping.
I don't even have to go perfectly in one direction or another.
That's part of the strength of having a point collection is we can place these by hand.
So I'm going to place it about there.
And I'll add a billboard.
To point three and change it to use the target icon.
And I'm going to move point three, not the billboard, but point three itself over.
And I'm going to put it right there.
And you know what?
I think I'm going to take two.
And it looks like I moved point two billboard.
So I'm going to actually reset its location and select the billboard itself and move that.
So just something to be aware of.
I'm going to have points.
One through three, evenly spaced out, so that if we spawn these starting at point zero, I'd like
to go out in this kind of manner.
So it doesn't hurt to select those scene components themselves and make sure that they're exactly at
the locations you expect.
We can also go to top mode if we want to see it from this perspective.
And we don't want any sort of optical illusions fooling us into where exactly we think these are.
So now that I have points one through three, I'm going to go ahead and minimize those and start on
point four.
So I'm going to add a billboard to that.
And because the rest of this is going to be repetition, I can time lapse four through ten.
And I'm just going to space these evenly out.
And I'm going to make sure that the lower the number, the closer to the origin of the actor, the closer
to its root component.
And that way as we're spawning these, if we use that order to our advantage, then we can choose locations
closest to the center when we only want to spawn for some of these locations.
So I'm going to time lapse the rest of this.
Okay, so I believe I have all ten points.
And I can just run through each of them and make sure that the closest ones are the lowest in number
for their names.
So there's point one for me.
Point two, here's three.
They're not in order here in the components panel.
So I need to be careful there.
Here's four.
Here's five.
It's out there a little bit.
Here's 678 okay.
So I'm going to go from top to perspective and rotate a bit.
And here's my little point collection.
And of course you could go all out with this.
You can put as many of these as you want.
But at least now I have this point collection.
And the reason I wanted the ability to rotate these is because, well, if I use the same point collection
every time, even if I pick random locations from around inside of it, well, that's going to become
noticeable, but not if you rotate it every time.
So now that I have a point collection and it has points in it, I'm going to go into arcane shards and
I'm going to spawn one of these point collections and just use its points.
So we'll just start by drawing some debug spheres.
Now to spawn this I'm going to use Spawn Actor.
And I can use spawn actor from class and just specify my point collection class.
So if I search for BP point collection, I have a point collection.
Now where do we want the point collection to start?
Well, we know how to get target data under the mouse.
That would be a good start for us.
So what I'm going to do is right click and get target data under mouse.
An on press can be hooked up to this.
And then once we have valid data, then we can go on and spawn an actor, because now our data handle
has that hit result.
We can call get hit results from target data.
And this hit results we can break.
So break hit result and we can get the impact point.
From it.
And if I just hook this up to spawn transform, then this is going to create a transform from the vector.
And if you don't like that, you don't like that you can't see what the rotation and scale are.
You could split the struct pin and you can just plug impact point straight in.
And then you can see for sure what those values are.
Spawn transform, rotation is zero, scale is one, and so on.
Now for the collision handling override I'm just going to use always spawn ignore collisions even though
we shouldn't have any.
This is just a bunch of scene components that really are no collisions to be worried about.
But after we've spawned the actor, now we have a point collection and I'm going to take that point
collection.
And I'm going to call the blueprint pure function, get ground locations or get ground points rather.
And this can take in a location to start with.
That can be our impact point.
I'm just going to drag it on behind that node, even though I don't like doing that.
For now, I'm just going to drag it in there and we know that we can pass in anything up to and including
11, and we can try a your override as well.
But I'm going to try first with zero.
And after getting those ground point locations I'm going to draw some debug spheres.
But it would be a great idea once we spawn this to promote it to a variable so we can delete it later.
So I'm going to call this point collection.
And once we're done with the point collection we can go ahead and destroy it.
So after getting the ground points, how are we going to draw debug spheres?
Well, we can loop over this array we can use for each loop.
We can hook this up.
And for each of these scene components, we can draw a debug sphere.
So in the loop body draw debug sphere.
And I'm going to take each element and get its location.
So get world location.
And that will be the center for the sphere.
The radius can be 20.
We'll leave the line color at white.
The duration can be 20s thickness will leave alone.
And by the time we're done with this for each loop, we can then end our ability by hiding that magic
circle, having a delay, and ending the ability.
And of course.
We can also destroy our point collection.
So we're going to call Destroy actor on it.
And then every time we execute this ability, we're making a new point collection.
And we can even try different your overrides here.
So let's give this a shot.
I'm going to save all and press play.
And I'm going to try pressing the one key.
And then we're now waiting for input.
So I'm going to press it again.
And there we have our points and check it out.
One of these is up on the stairs.
So we're now seeing how useful that line trace can be.
Pretty cool.
So that's looking pretty nice.
So once again I'm going to go ahead and press one.
Press it again.
And we have these points right now I'd like to see what happens if we pass in a yaw override.
First of all I'm just going to pass in a value like 45.
So I expect to see a different set of points.
And to me it does look different.
But it's a little hard to tell.
So one way we can tell is by using a random value.
So random float in range and we can go from say 0 to 360 and we can hook that in and then we can do
this a couple times.
We can show these ground points twice.
So we can place our mouse cursor at one particular location.
I'm going to just come out here so I have more room.
So I'm going to place my mouse cursor at this location here.
Let's full screen and I'm going to press one.
And then press one again.
There's my points.
And now I'm going to keep my mouse at that location, press one and press one again.
And the second time we see new points.
If that your override didn't work, we wouldn't see points just come out of nowhere.
These spheres would all be drawn on top of each other.
So that tells us that we're rotating these points.
So this is great.
Now we have some points and we can use this point collection.
And of course we can always adjust these points.
I may not have the most even distribution here of my points.
So it might be worthwhile for me to go through and just kind of maybe spread them out a little bit or
make sure that they're not quite so elongated as they are.
But the cool thing is that we have these points and we have the ability to get some random rotation
as well.
So that's the next step in our ability is being able to get some random points.
And.
That's looking pretty good.
Now these are random points, but if you're observant, you're going to notice something.
If I press play and I create my random point cloud.
Well, here's what it looks like.
And if I go ahead and eject.
And I take a good look from the top here, and then I go into my point collection.
There's something wrong.
This collection of points looks nothing like this collection of points.
Even though we gave a random rotation, the rotation should be consistent.
It should be like taking the whole actor and rotating it by a certain amount.
But this looks seemingly like a bunch of random points that have all been rotated randomly individually.
And that's exactly what is happening, because these are blueprint pure nodes.
You see, every time we use a blueprint pure node, it's going to be evaluated again, especially with
these random number generator functions.
If the wire that's using it's output is used for anything, then the blueprint pure function is called
again.
And that includes using them in for loops.
For example, in our for each loop this get ground points that returns an array is returning a new array
every single time because it itself is a blueprint pure function.
So for that reason we have to be careful with these blueprint pure functions.
For one, they're expensive.
If you use a for loop with a blueprint pure function, especially one that does some array business,
and for two they can be confusing.
Now I'm going to set the get ground points num points input to four and just show you really what I
mean.
It's easier to tell this kind of thing when we have a smaller number of points.
So the points number of points is four I'm going to press one.
Press one again.
Now look at that.
This doesn't really look like the first four points.
Not if we go in and take a look at point zero here in the middle.
Point one here right there.
Point two is right here.
So we have this triangle.
And then point three is right here.
So we basically have one big triangle and one point in the center.
That's the origin.
That's what we should see if we didn't have any random rotation.
If the yaw override was zero then if we go in and press one and press one again, that's what it should
look like a big triangle, one in the middle.
And if we were rotating everything consistently, then that whole triangle would then be rotated right.
So the way to fix this is to promote this array returned from ground points to a variable.
So we go ahead and promote to variable.
And we can call this ground points.
And once we do that, now we have a variable.
And if we use that instead in our array, we're not evaluating a blueprint pure function multiple times.
We can just evaluate it once and cache off that data.
So if I hook this random float back in, now that we're using this ground points array, instead of
evaluating the blueprint pure node every time, let's see how that ends up.
So I'm going to press one and one.
And we have our familiar triangle.
It's not all muddled up.
And if I press it again we have the same triangle but it's rotated.
And I can do this multiple times, and I see that each new set of points is just three new points,
a triangle with one point in the middle.
And that's exactly the behavior that I was expecting and wanting.
So now that we have this function that gives us a collection of points that's rotated, we can trust
it when we increase that number of points there.
Okay, so with that we now have a point collection.
It has points in it.
We can rotate the point collection.
We can get any number of points.
Well not any number but up to 11 because that's how many points we have in here.
And we can generate a bunch of random points and we can specify how many we want.
And if we only want one, we should get that central point.
So right there in the middle.
And with our ability at level one, that's where we're going to spawn that first shard.
But then when we level up our ability, we're going to pass in higher numbers.
So at level two I'd like to spawn two shards.
And it's going to look like this one at the center and one slightly far out of it.
But we're getting a random rotation every time, so that way it doesn't look the same every single time.
And then when our ability levels up to level three.
Will spawn three of them.
And it'll be a little triangle like this.
And of course, at level four.
Then it'll look more like this, where we have one in the middle and three and so on.
You get the point.
Now these are spaced a little bit too far apart, so I'm going to just bring them in.
I'm going to time lapse bringing them in.
And then we're going to wrap up this video.
Okay.
And with that, I'm just going to pass in 11 and see the spread here.
And that looks pretty good.
Okay.
So now we have random locations and they're evenly spread out.
So if we had just picked random locations with random number generators for each location, we could
have shards overlapping with each other.
So another benefit of this is we have evenly distributed points randomly selected.
So in the next video we're going to start going about how we can actually spawn those shards and make
this actually look really cool.
So excellent job and I'll see you soon.