WEBVTT

00:06.840 --> 00:07.950
Welcome back.

00:08.470 --> 00:14.080
Now our Arcane Shards ability is going to spawn some shards, right?

00:14.080 --> 00:19.060
And I'd like my shards ability to spawn multiple shards.

00:19.060 --> 00:27.550
And when I say multiple shards, let's go into assets effects, arcane shards and open up this Niagara

00:27.550 --> 00:28.390
system.

00:28.510 --> 00:33.190
And in preview scene settings, I'm going to show the floor just so I can see what it looks like on

00:33.190 --> 00:34.120
the ground.

00:34.120 --> 00:39.310
I'm going to uncheck Show environment, and I'm going to set the background to a darker color so that

00:39.310 --> 00:42.880
I can see really more closely what it's going to look like.

00:42.970 --> 00:47.320
Now, this system here, I'm referring to that as a shard.

00:47.320 --> 00:49.330
Or we could call it a group of shards.

00:49.330 --> 00:56.740
Now I'd like to spawn one of these, and at level one, I think our ability can spawn it right there

00:56.740 --> 00:58.750
in the center of our decal.

00:58.750 --> 01:04.780
But at say, level two, I'd like to spawn two of these, and at level three, I'd like to spawn three

01:04.780 --> 01:05.290
of them.

01:05.290 --> 01:10.990
And for arcane shards, I'd like to go all the way up to say, level 10 or 11.

01:10.990 --> 01:18.010
I'd like to spawn a whole bunch of these, and I'd like them to be spawned at roughly evenly distributed

01:18.010 --> 01:25.660
locations, and depending on how many were spawning, I'd like them to spawn starting at the inside

01:25.660 --> 01:28.390
of the circle and propagating outward.

01:28.390 --> 01:30.760
So how is that going to work?

01:30.760 --> 01:31.540
Now?

01:31.540 --> 01:38.950
One way is to calculate these locations, to spawn these at procedurally or with some kind of algorithm.

01:38.950 --> 01:40.300
That's one way.

01:40.330 --> 01:47.500
Another way is to have some collection of points that we've handcrafted, rather than using lines of

01:47.500 --> 01:51.550
code to calculate mathematically where we're spawning things.

01:51.550 --> 01:57.520
Now, I'd like to use the approach of having a collection of points that I've placed out manually.

01:57.520 --> 02:02.770
In other words, I'd like to have some kind of actor that contains a bunch of points.

02:02.770 --> 02:06.400
Now, this method has a couple of advantages.

02:06.400 --> 02:14.260
One is that obviously it looks better when points are hand placed rather than calculated with some kind

02:14.260 --> 02:15.310
of algorithm.

02:15.310 --> 02:20.890
Not necessarily, but in general, if you can hand place points, it looks good.

02:20.890 --> 02:27.910
And another thing is our point collection, if it's an actor we create can have its own functions that

02:27.910 --> 02:29.890
can calculate things.

02:30.460 --> 02:34.570
For instance, let's say that we cast our spell on the stairs.

02:35.180 --> 02:42.320
If I want a collection of points, I want to make sure those points have correct locations, especially

02:42.320 --> 02:43.340
their elevation.

02:43.340 --> 02:47.510
I want them to not be spawned underneath the stairs.

02:47.510 --> 02:53.150
I don't want some of them to be spawned at the top of the stairs, and then others in the air above

02:53.150 --> 02:54.350
the bottom steps.

02:54.350 --> 02:59.210
I'd like them to be spawned on the stairs and perhaps even oriented correctly.

02:59.210 --> 03:05.300
Or if we're on a sloped surface, I'd like to spawn these particle systems on the ground.

03:05.300 --> 03:12.770
And so for that reason, a point collection actor can be useful because it can perform some sort of

03:12.770 --> 03:18.860
line trace down to the ground and get the ground location corresponding to those spawn points.

03:18.860 --> 03:25.280
So for that reason, I'd like to make a point collection actor, and this is going to just be an actor.

03:25.280 --> 03:32.990
We're going to stick it in the actor folder so I can go to C plus plus classes or a public actor and

03:32.990 --> 03:34.160
we can put it here.

03:34.760 --> 03:37.520
So I'm going to go ahead and make a new C plus plus class.

03:37.520 --> 03:42.680
I'm going to choose actor and I'm going to call this point collection.

03:44.120 --> 03:46.040
So I'm going to create this class.

03:46.040 --> 03:51.170
I'm going to go ahead and close down the editor, save all my changes.

03:51.170 --> 03:55.760
And I'm going to get this point collection actor open.

03:55.760 --> 04:02.900
I'll go ahead and close all tabs for now and open up Actor Point Collection.

04:02.900 --> 04:07.190
And we'll go ahead and get both header and CPP files open.

04:07.190 --> 04:09.920
So let's clean up this file.

04:10.160 --> 04:16.580
I'll go ahead and remove those comments that I don't like, and move the tick function up to the constructor

04:16.580 --> 04:19.340
and delete that third public section.

04:20.440 --> 04:25.360
We can also remove comments from the cpp file.

04:25.360 --> 04:28.900
And actually my point collection doesn't need to tick.

04:28.900 --> 04:34.750
So I'm going to set primary actor tick be can never tick to false and just remove the tick function

04:34.750 --> 04:35.680
altogether.

04:35.680 --> 04:37.660
No need to override it at all.

04:38.290 --> 04:40.150
And we have a point collection.

04:40.450 --> 04:43.450
Now a point collection should have points.

04:43.450 --> 04:46.420
It should have points that have their own locations.

04:46.420 --> 04:53.500
And one of the most simple types of components that has a location is the scene component.

04:53.500 --> 04:58.960
So we can have ourselves a scene component for each point that we'd like.

04:58.960 --> 05:02.980
So what I want to do is create a whole bunch of scene components.

05:02.980 --> 05:13.000
And I could put these in a private section, and these can be t object pointers, each to a U scene

05:13.000 --> 05:13.900
component.

05:15.790 --> 05:18.940
So in other words, I'll have point one.

05:18.940 --> 05:24.940
I can just use DT one I can actually start at zero because we're programmers, and programmers start

05:24.940 --> 05:27.220
indexing things at zero, don't they?

05:27.220 --> 05:30.700
Unless you program in Lua if you've ever heard of that language.

05:30.700 --> 05:32.500
But that's beside the point.

05:32.500 --> 05:33.790
Let's make a bunch of points.

05:33.790 --> 05:40.600
Now I want about 11 of these, so I'm going to go ahead and just copy paste 11 times.

05:40.600 --> 05:46.300
But I suppose it would be smarter to add a uproperty and copy paste that too.

05:46.300 --> 05:50.020
So I'm going to go ahead and give this blueprint read only.

05:51.580 --> 05:56.950
And when autocomplete isn't working that's an indicator that you have a typo.

05:57.670 --> 06:01.120
So blueprint read only I'll make it visible anywhere.

06:01.120 --> 06:08.440
And if it's going to be blueprint read only, then it should either have meta allow private access like

06:08.440 --> 06:09.190
this.

06:12.730 --> 06:13.990
Equals true.

06:14.110 --> 06:19.930
That would allow us to have a blueprint read only in the private section, or we could just let it be

06:19.930 --> 06:20.860
protected.

06:20.890 --> 06:25.150
I tend to opt for the second option, so we'll go ahead and do that.

06:26.370 --> 06:28.710
So now we have point zero.

06:28.740 --> 06:30.240
We have point one.

06:30.240 --> 06:33.750
And we can paste this a few more times.

06:33.750 --> 06:35.670
I think I'd like to have up to point ten.

06:35.670 --> 06:37.710
So let's do this.

06:43.560 --> 06:46.650
So we have ten scene components.

06:46.650 --> 06:50.370
In addition to that, I'd like to keep these in an array.

06:50.370 --> 06:53.820
And that's going to make them easy to iterate over.

06:53.820 --> 06:56.370
So I'm going to make a T array that holds.

06:56.370 --> 06:58.260
You seen component pointers.

06:58.260 --> 07:01.890
So you seen component pointer.

07:01.890 --> 07:06.420
And this is going to be called immutable points.

07:06.690 --> 07:12.810
Pts immutable in a sense that I don't want to ever change this.

07:14.730 --> 07:16.920
I want to keep it unchanged.

07:16.920 --> 07:21.060
And this is going to be blueprint read only visible anywhere.

07:21.060 --> 07:28.890
And we'll just add all of our scene components to this right off the bat as we construct them.

07:28.890 --> 07:33.450
So to the constructor we're going to go over to the constructor here.

07:33.450 --> 07:37.020
And we're going to construct each of these starting at point zero.

07:37.020 --> 07:43.530
So point zero equals we're going to use Createdefaultsubobject with you scene component.

07:47.090 --> 07:50.600
And we're just going to give these each the name.

07:51.310 --> 07:53.680
That corresponds to their variable name.

07:53.680 --> 07:55.420
So the same internal name.

07:55.420 --> 07:57.250
We're going to add it to a mutable points.

07:57.250 --> 08:01.120
So a mutable points dot add point zero.

08:01.360 --> 08:06.310
And we're also going to set point zero as the root component.

08:06.310 --> 08:09.820
So I'm going to say set root component point zero.

08:11.970 --> 08:14.790
And after that I'm going to construct all the others.

08:14.790 --> 08:18.990
So I'm going to copy these two lines and paste them and change this to point one.

08:20.790 --> 08:24.240
So that I'm creating and adding it to a mutable points.

08:24.240 --> 08:30.270
The difference for this is I'm going to take point one and call setup attachment, and we're going to

08:30.270 --> 08:32.070
call get root component here.

08:33.150 --> 08:39.630
After this we can copy this a few more times until we have all the way up to point ten.

08:39.630 --> 08:40.950
So let's do that.

09:02.450 --> 09:05.150
Okay so that's ten points.

09:05.600 --> 09:07.460
So that's great.

09:07.460 --> 09:12.350
Our point collection is just a glorified array with some perks right.

09:12.350 --> 09:17.090
It has seen components with each their own location in space.

09:17.090 --> 09:22.610
Seen components here are going to be a little bit more valuable to me than just f vectors because I

09:22.610 --> 09:27.380
can place these wherever I want in relation to the root component.

09:27.960 --> 09:33.960
Now, in addition to having a bunch of points, I'd like a nice function that can return an array of

09:33.960 --> 09:35.700
these only.

09:35.700 --> 09:42.780
I'd like to return an array that's a copy of these scene components, or at least an array of locations

09:42.780 --> 09:45.150
in space that represent these.

09:45.150 --> 09:50.970
But the reason I'd like to return an array is because I want to be able to get all these points on the

09:50.970 --> 09:54.630
ground, making sure that they're not below the ground.

09:54.630 --> 09:55.650
Above the ground.

09:55.650 --> 09:58.080
We're going to be performing some line traces.

09:58.080 --> 10:03.270
So I'm going to create a public function here that can get these points.

10:03.270 --> 10:10.860
So whether we return an array of scene component copies or just an array of locations, it doesn't really

10:10.860 --> 10:11.790
matter.

10:11.790 --> 10:19.020
I like the idea of a function returning an array of scene components because they have location, but

10:19.020 --> 10:20.670
also rotation.

10:20.670 --> 10:28.080
So if we have a rotation and we'd like to angle our particle systems that we spawn based on, say,

10:28.080 --> 10:33.570
the normal of the ground, well, we can use scene components for their rotations as well.

10:33.570 --> 10:41.640
So I'm going to make a function here in the public section that returns a 2D array of you scene component

10:41.640 --> 10:42.570
pointers.

10:45.430 --> 10:49.060
And we're going to call this get ground points.

10:50.480 --> 10:55.490
Now get ground points is going to need a couple of pieces of information.

10:55.490 --> 10:58.250
One, it needs to know the ground location.

10:58.250 --> 11:01.100
So we're going to pass that in as a const vector.

11:03.560 --> 11:05.480
We'll call it ground location.

11:08.570 --> 11:15.770
In addition to this, I'd like to be able to pass in an integer into this function to get a limited

11:15.770 --> 11:18.470
number of the points in the collection.

11:18.500 --> 11:23.690
For example, I'd like the first three that are closest to the center, and so on.

11:23.690 --> 11:29.420
So I'm going to go ahead and make an int 32 input parameter here called num points.

11:30.290 --> 11:36.650
And then I'd like to be able to override the rotation as a your value.

11:36.650 --> 11:40.580
So I'm going to say your override and that'll be a float.

11:40.580 --> 11:45.500
But if we don't pass this in I'd like it to be initialized to zero by default.

11:45.500 --> 11:48.260
And this can be a blueprint pure function.

11:48.260 --> 11:51.410
I'm going to make it you function blueprint pure.

11:51.410 --> 11:59.210
As every time we call this, we're going to want it to be executed afresh, anew, a different time.

11:59.210 --> 12:01.670
So let's go ahead and generate the definition.

12:02.980 --> 12:07.630
And what exactly is this get ground points going to do for us?

12:07.630 --> 12:14.620
Well, the first thing is, if I call the function and I pass in num points and num points is more than

12:14.620 --> 12:21.340
how many points I have, I'm going to punish the user who called this function with a nice crash.

12:21.340 --> 12:26.440
So I'm going to say check f, I'm going to say immutable points dot num.

12:26.920 --> 12:30.940
And I want to make sure that this is greater than or equal to num points.

12:30.940 --> 12:34.360
If it is greater than or equal to num points, we're good.

12:34.360 --> 12:40.420
Otherwise we're going to crash with a nice nasty crash log message.

12:40.420 --> 12:48.640
We're going to say attempted to access immutable points out of bounds.

12:51.640 --> 12:55.690
Okay, now that we're done being nasty, let's continue.

12:55.690 --> 13:00.190
And what I'm going to do is first and foremost make a T array.

13:00.220 --> 13:03.520
That's a copy of my immutable points.

13:03.520 --> 13:11.200
So if I shuffle them around in my array, for example, or I remove anything from the array, at least

13:11.200 --> 13:13.960
my original array won't be touched.

13:13.960 --> 13:17.170
So this will be a t array of you seen component pointers.

13:17.170 --> 13:19.630
And I'm going to call this array copy.

13:20.830 --> 13:24.280
Now what I'm going to do is loop through my immutable points array.

13:24.280 --> 13:31.210
I'm going to say for you seen component pointer I'm going to call it t short for point.

13:31.210 --> 13:33.850
And I'm looping through immutable points.

13:33.850 --> 13:41.920
And each iteration of the for loop I'm going to check if array copy dot num.

13:43.930 --> 13:45.940
Is greater than num points.

13:46.780 --> 13:50.170
If it is, we should just return array copy.

13:54.500 --> 13:57.980
As there's no point in continuing, right?

13:57.980 --> 14:03.380
Because array copy now contains greater than num points elements.

14:05.030 --> 14:06.320
After that.

14:06.320 --> 14:12.800
What I'd like to do is get the location of all the points in my immutable points array.

14:12.830 --> 14:14.840
All of my scene components.

14:14.840 --> 14:25.250
But I'd also like to rotate all of my points by the amount of your override that I'm passing in.

14:25.250 --> 14:31.640
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

14:31.640 --> 14:36.710
point zero, but I want to rotate all the other points relative to point zero.

14:36.710 --> 14:40.400
And I'm just going to have points one through ten.

14:40.580 --> 14:45.680
Get farther and farther away based on their order away from zero.

14:45.680 --> 14:53.270
So what I'm going to do is I'm going to say if point is not equal to point zero.

14:54.860 --> 14:59.450
Because there's no point in rotating point zero.

14:59.480 --> 15:06.020
So what I'm going to do is make an f vector called two point, and this is going to be the vector from

15:06.020 --> 15:07.790
the center to the point.

15:07.790 --> 15:15.530
So I'm going to take point get component location minus point zero.

15:15.530 --> 15:17.300
Get component location.

15:18.080 --> 15:22.460
So I have the vector from the center to point and I'm going to rotate it.

15:22.460 --> 15:32.630
So I'm going to take two points and set it equal to 2.. rotate angle axis.

15:32.630 --> 15:39.260
And I'm going to rotate about the up vector an amount equal to your override.

15:39.260 --> 15:43.010
So I'm going to say your override as the amount to rotate.

15:43.010 --> 15:45.260
And I'm going to use f vector.

15:46.580 --> 15:47.630
Up vector.

15:49.010 --> 15:55.670
And now that I've rotated this two point vector, then I can go ahead and set my point location.

15:55.670 --> 16:05.630
I could say point set world location, and I can get my point underscore zero and get its location.

16:05.630 --> 16:08.360
So get component location.

16:08.360 --> 16:13.130
Of course this is also the same as get actor location because this is the root component.

16:13.130 --> 16:18.290
But we can get that actor location and add two point to it.

16:18.290 --> 16:26.270
And now we'll be repositioning this point such that we've rotated it by our yaw override.

16:26.840 --> 16:30.680
This allows us to get some variation in the rotation of our point collection.

16:31.370 --> 16:38.090
Now, after doing that, I'd like to perform a line trace straight down to the floor to get the ground

16:38.090 --> 16:39.080
location.

16:39.560 --> 16:47.870
So for that, we need a trace start and a trace end, which will be raised and lowered locations, respectfully.

16:48.350 --> 16:54.680
So I'm going to make a const f vector and call this raised location.

16:55.320 --> 16:57.450
Now this is going to be an f vector.

16:57.450 --> 16:59.970
I'm going to use the f vector constructor.

16:59.970 --> 17:07.770
But I'm going to initialize it with x, y, z components starting with point get component location

17:07.770 --> 17:11.070
dot x so it can have the same x.

17:11.580 --> 17:15.660
I'm also going to use point get component location dot y for the y.

17:15.690 --> 17:17.700
So dot y there.

17:18.090 --> 17:20.730
But for z I'm going to add some to it.

17:20.730 --> 17:26.430
I'm going to use point get component location dot z plus 500.

17:27.860 --> 17:34.310
I don't want to go too far beyond 500 above this points location for the start of my trace.

17:34.310 --> 17:40.700
The end of the trace is going to end up below, so it's going to be called lowered location.

17:41.180 --> 17:47.030
And for this the Z is going to be the original Z of the point -500.

17:47.030 --> 17:50.630
So we start 500 above and we end 500 below.

17:50.630 --> 17:53.150
And now we can line trace between these two.

17:53.180 --> 17:59.600
So I'm going to make a line trace which requires an f hit result I'm going to call it hit result.

18:00.730 --> 18:08.560
And of course, if we line trace, we just might trace down and hit an enemy or any kind of thing we

18:08.560 --> 18:09.760
don't want to hit.

18:09.760 --> 18:15.130
And luckily there's a function to get all live players within radius.

18:15.130 --> 18:19.900
It's a function we added to you or a ability system library.

18:19.900 --> 18:23.500
And we call this get live players within radius.

18:23.500 --> 18:28.690
And this can take a world context object that can be this.

18:28.690 --> 18:32.500
And it also takes an array of overlapping actors.

18:32.950 --> 18:35.320
I'm going to make an array to pass in.

18:35.620 --> 18:38.680
So it's a T array of a actors.

18:41.740 --> 18:42.790
Pointers, of course.

18:42.790 --> 18:45.160
And I'm going to call this ignore actors.

18:45.250 --> 18:48.190
And I'm going to pass ignore actors in here.

18:49.000 --> 18:49.630
Why?

18:49.660 --> 18:55.120
Because get live players within radius will fill that in with all live players.

18:55.120 --> 18:59.230
And that's basically anything that implements the combat interface that isn't dead.

18:59.230 --> 19:00.940
So I'm going to pass that in.

19:00.940 --> 19:05.620
Now this function itself requires an array of actors to ignore.

19:05.650 --> 19:08.440
That's not going to be my ignore actors.

19:08.440 --> 19:11.920
I'm going to ignore nothing with get live players within radius.

19:11.920 --> 19:17.860
So I'm going to make a t array of a actor pointers, but an empty one.

19:18.340 --> 19:22.480
So passing in an empty array there and we need a radius.

19:22.480 --> 19:25.390
So I'm just going to pass in 1500.

19:26.170 --> 19:28.630
We can make that a member if we want.

19:28.630 --> 19:31.720
And then it needs a sphere origin.

19:31.720 --> 19:34.450
We're going to use get actor location again.

19:34.450 --> 19:37.510
That's the same as the point zero location.

19:37.600 --> 19:44.500
But the point of this is to get all the live players within radius and fill them in to my ignore actors

19:44.500 --> 19:45.160
array.

19:45.160 --> 19:45.790
Why?

19:45.820 --> 19:50.950
Because I'm going to now use this as my ignore actors for my line trace.

19:50.980 --> 19:52.360
Pretty clever right?

19:52.360 --> 19:59.380
So what I can do now is I can perform a line trace, and the particular line trace that I'd like to

19:59.380 --> 20:09.520
use is line trace by profile, so that I can only trace against objects that have a specific collision

20:09.520 --> 20:10.420
profile.

20:10.420 --> 20:15.760
And profiles are things like block all, block all dynamic, things like that.

20:16.420 --> 20:17.890
So here's what I'm going to do.

20:17.890 --> 20:24.460
I'm going to call get World Line Trace single by profile.

20:25.030 --> 20:27.430
The first input is the hit results.

20:27.430 --> 20:29.140
So I'm going to pass in hit result.

20:30.270 --> 20:33.090
The second input is the trace start that's going to be raised.

20:33.090 --> 20:34.050
Location.

20:34.350 --> 20:38.040
Next is the trace end that's going to be lowered location.

20:38.730 --> 20:43.350
After that we have the profile which is a profile F name.

20:43.440 --> 20:46.470
And I'm going to trace against block all.

20:49.190 --> 20:51.560
And now we need collision query params.

20:51.560 --> 20:55.550
We can just create some f collision query params here.

20:59.850 --> 21:02.130
I'm going to call these query params.

21:05.060 --> 21:08.240
And this is where I can use my ignore actor's array.

21:08.240 --> 21:10.520
So I'm going to take query params.

21:12.020 --> 21:19.910
Dot, add, ignore or ignored actors and pass in ignore actors.

21:21.080 --> 21:25.760
And we can pass query params in as the last of the inputs for this.

21:25.790 --> 21:32.450
Now that we're tracing and we're ignoring all of the live players within a radius we specified, well,

21:32.450 --> 21:39.560
this is great because now we can take this line trace and get that location from its hit result.

21:39.950 --> 21:43.670
And really, I only care about the Z location of it.

21:43.670 --> 21:48.920
So I'm going to make a new const fvector called adjusted location.

21:48.920 --> 21:52.250
And it's going to be a new f vector.

21:53.240 --> 21:56.510
And I'm going to use the points x and y.

21:56.510 --> 22:02.810
So I'm going to use point get component location dot x point get component location dot y.

22:02.840 --> 22:04.910
I'm going to copy those and paste them here.

22:05.330 --> 22:11.240
And for the Z I'm going to use my hit results dot impact point.

22:11.760 --> 22:12.870
Dot z.

22:13.560 --> 22:18.960
So the only thing that really matters from our line trace is that z location.

22:19.470 --> 22:21.240
Now, after all this.

22:21.270 --> 22:29.640
Now that we have an adjusted location, I'm going to take my point and call set world location passing

22:29.640 --> 22:31.380
in my adjusted location.

22:33.380 --> 22:39.380
Now I can also set its rotation based on that hit result because we have the impact normal.

22:39.380 --> 22:44.000
So what I can do is take point and call set world rotation.

22:44.000 --> 22:46.250
And this needs to be a rotator.

22:46.250 --> 22:48.680
So how do I get a rotator from a vector.

22:48.680 --> 22:52.430
Well I can use you Kismet math library.

22:52.430 --> 22:56.540
And there's a handy function called make wrote from Z.

22:56.540 --> 23:03.020
And this can take in an f vector I can use hit result dot impact normal.

23:03.020 --> 23:08.720
The normal is the vector from the ground straight out perpendicular.

23:08.720 --> 23:14.420
We call it orthogonal when we use 3D vectors to that face that was hit.

23:14.420 --> 23:19.010
And this is actually you kismet math library, not just you kismet math.

23:19.010 --> 23:22.760
I thought I autocompleted it, but looks like I didn't.

23:23.180 --> 23:26.090
Now by the end of this point has been adjusted.

23:26.090 --> 23:31.190
It's been rotated potentially, and it's been elevated or lowered potentially.

23:31.670 --> 23:36.830
So after doing this I'd like to add it to my array copy.

23:38.150 --> 23:39.980
So array copy dot add.

23:39.980 --> 23:41.360
And I'm going to add the point.

23:41.390 --> 23:46.190
Now this doesn't mean that we're creating a copy of the scene component.

23:46.190 --> 23:47.180
We're not.

23:47.180 --> 23:49.700
There's only ten scene components here.

23:49.700 --> 23:51.170
We're not creating any new ones.

23:51.170 --> 23:53.990
We're just moving around those scene components.

23:54.440 --> 23:59.870
So they start off at their original positions, we move them and we return an array that contains some

23:59.870 --> 24:00.410
of them.

24:00.410 --> 24:03.020
Not all of them, just some of them.

24:03.020 --> 24:07.550
Just enough for our needs determined by num points.

24:07.970 --> 24:11.720
And we're looping over all of these points starting at zero.

24:11.720 --> 24:19.700
And each time we're adding one to our array copy, and we're going to return as soon as our array copy

24:19.700 --> 24:21.800
becomes equal to num points.

24:21.800 --> 24:25.460
We said greater than we could use greater than or equal to here.

24:25.460 --> 24:26.180
Really.

24:26.180 --> 24:31.820
Because once this array contains num points we're ready to return it.

24:31.820 --> 24:35.720
And then we can use those scene components in any way we want.

24:36.430 --> 24:38.740
So now we can see how this works.

24:38.740 --> 24:42.550
Of course, our get ground points needs to return an array.

24:42.550 --> 24:46.840
So by the very end of this we have to actually return array copy.

24:47.880 --> 24:50.820
And now that this returns something, we can try this out.

24:50.820 --> 24:53.190
Let's go ahead and compile and launch the editor.

24:54.360 --> 24:56.490
All right, so back in the editor.

24:56.520 --> 24:59.400
Looks like I can close arcane shards there.

24:59.400 --> 25:01.860
I'm going to close our character.

25:01.860 --> 25:04.800
And here in my Arcane shards gameplay ability.

25:05.580 --> 25:10.170
I can try to use my point collection, but I'm going to close project settings.

25:10.170 --> 25:16.050
And before we go and create a point collection, I'm going to make a blueprint based on our point collection

25:16.050 --> 25:16.500
class.

25:16.500 --> 25:20.310
So let's go to blueprints I'm going to go to.

25:21.090 --> 25:23.310
Ability, system or abilities.

25:23.310 --> 25:25.050
Arcane arcane shards.

25:25.050 --> 25:29.910
And I'm going to make a new blueprint here, and I'm going to make this based on my point Collection

25:29.910 --> 25:30.750
class.

25:33.540 --> 25:36.450
And I'll just call this BP Point Collection.

25:40.550 --> 25:42.380
So I'm going to open my point collection.

25:42.380 --> 25:49.670
Now here are my scene components and you can't really see them unless you select them.

25:49.670 --> 25:51.230
You can move them around.

25:51.770 --> 25:58.100
I'd like to position these by hand, and I'd like to position them in order closest to the origin.

25:58.100 --> 26:00.200
The lower their number is.

26:00.440 --> 26:05.090
So what I'm going to do is select point one and move it.

26:05.090 --> 26:09.740
But before I do that, I want to be able to see all of these relative to each other.

26:09.740 --> 26:15.110
So I'm going to take each one, select it and add a billboard.

26:15.110 --> 26:18.140
And that's going to allow me to see that component.

26:18.140 --> 26:21.800
So I'm going to add a billboard to point one.

26:21.800 --> 26:23.690
And then I'm going to move point one.

26:23.690 --> 26:29.030
Now if you add a billboard to point one, don't go moving the billboard, because point one will just

26:29.030 --> 26:33.140
stay there and then they'll have an offset which will just confuse you.

26:33.170 --> 26:35.960
You're going to want to move point one instead.

26:35.960 --> 26:40.640
But before I do that, I'm going to change the billboard texture.

26:41.300 --> 26:47.390
If I search for target, I can use target icon that looks a little bit cooler.

26:48.050 --> 26:51.350
So I can select one of these target icons.

26:51.350 --> 26:56.990
There's one in editor materials in the engine and there's one in engine debug materials.

26:57.540 --> 27:02.790
So now that I have that, I can select point one and I can move it.

27:03.610 --> 27:08.890
Now you can use snapping if you want snapping, or you can just move these by hand.

27:08.920 --> 27:14.320
I'm going to move it a little bit without snapping and just to see where that origin is, I'm going

27:14.320 --> 27:18.850
to take point zero and I'm going to add a billboard to point zero as well.

27:20.990 --> 27:23.270
And I'll go ahead and change this one as well.

27:23.270 --> 27:26.000
I'm going to search for target point or just target.

27:26.000 --> 27:28.460
And here's a target icon spawn.

27:28.460 --> 27:34.490
It's a little bit different and we can just use that to distinguish that middle point.

27:35.060 --> 27:38.900
Now point one over here is 100 units away.

27:38.900 --> 27:44.900
And really, we just kind of need to know how big those shard particles are.

27:44.930 --> 27:52.250
And so in order to see that what we can do is we can drag one in, we can go to effects arcane shards,

27:52.250 --> 27:54.470
and we can bring in arcane shards.

27:54.470 --> 28:02.120
We can set arcane shards at a specific location, let's just say zero zero for x, y.

28:02.420 --> 28:06.380
And if we duplicate this and move it over.

28:08.840 --> 28:14.480
Then we can move this arcane shards over, and it looks like I've moved it by -200.

28:15.160 --> 28:19.060
And we can see what they look like next to each other.

28:19.060 --> 28:24.040
And then we can ask ourselves, are we okay with our shards ever being that close together?

28:24.070 --> 28:32.470
I'm going to set its location X to zero and its location Y to 200, so I can see what they look like

28:32.470 --> 28:33.670
next to each other this way.

28:33.670 --> 28:40.960
Now, if you're okay with that much of a separation, then you can use that as a ballpark when you position

28:40.960 --> 28:42.820
your points in your point collection.

28:42.820 --> 28:47.950
If you need a little bit more room than that, you can set this at say, 250.

28:48.100 --> 28:52.030
And that way you'll see that they're a little bit more spaced apart.

28:52.480 --> 28:56.680
I think that's probably a better distance.

28:57.130 --> 29:03.430
So with that, I can take these and remove them and go back to my point collection and just make sure

29:03.430 --> 29:10.570
that I move point one at least 250 units away from that central point.

29:10.570 --> 29:18.280
And make sure based on this gauge here, that we don't ever move points much less than 250 units away.

29:19.330 --> 29:21.850
So we'll use this as a kind of metric.

29:22.300 --> 29:24.130
Point one is 250 away.

29:24.160 --> 29:27.160
Now I'm going to position the rest of these.

29:27.160 --> 29:29.980
So first I'm going to take point two.

29:29.980 --> 29:32.410
And I'm going to add a billboard component.

29:33.100 --> 29:38.890
And I'm going to search for target and use the target icon.

29:41.050 --> 29:44.770
From editor materials, and I'm just going to position it.

29:44.770 --> 29:47.740
And I don't even have to use snapping.

29:47.740 --> 29:52.570
I don't even have to go perfectly in one direction or another.

29:52.570 --> 29:56.680
That's part of the strength of having a point collection is we can place these by hand.

29:56.680 --> 29:58.300
So I'm going to place it about there.

29:59.960 --> 30:01.670
And I'll add a billboard.

30:02.750 --> 30:08.270
To point three and change it to use the target icon.

30:10.740 --> 30:16.470
And I'm going to move point three, not the billboard, but point three itself over.

30:17.200 --> 30:18.910
And I'm going to put it right there.

30:18.910 --> 30:19.840
And you know what?

30:19.840 --> 30:21.340
I think I'm going to take two.

30:21.340 --> 30:25.840
And it looks like I moved point two billboard.

30:26.260 --> 30:31.810
So I'm going to actually reset its location and select the billboard itself and move that.

30:31.810 --> 30:34.750
So just something to be aware of.

30:36.700 --> 30:38.470
I'm going to have points.

30:39.120 --> 30:46.650
One through three, evenly spaced out, so that if we spawn these starting at point zero, I'd like

30:46.650 --> 30:49.260
to go out in this kind of manner.

30:50.360 --> 30:56.600
So it doesn't hurt to select those scene components themselves and make sure that they're exactly at

30:56.600 --> 30:58.730
the locations you expect.

30:59.690 --> 31:03.560
We can also go to top mode if we want to see it from this perspective.

31:03.560 --> 31:11.930
And we don't want any sort of optical illusions fooling us into where exactly we think these are.

31:11.960 --> 31:19.670
So now that I have points one through three, I'm going to go ahead and minimize those and start on

31:19.670 --> 31:20.690
point four.

31:20.690 --> 31:22.430
So I'm going to add a billboard to that.

31:22.430 --> 31:28.400
And because the rest of this is going to be repetition, I can time lapse four through ten.

31:28.400 --> 31:31.430
And I'm just going to space these evenly out.

31:31.430 --> 31:38.000
And I'm going to make sure that the lower the number, the closer to the origin of the actor, the closer

31:38.000 --> 31:40.040
to its root component.

31:40.040 --> 31:46.880
And that way as we're spawning these, if we use that order to our advantage, then we can choose locations

31:46.880 --> 31:51.860
closest to the center when we only want to spawn for some of these locations.

31:51.860 --> 31:53.990
So I'm going to time lapse the rest of this.

32:32.650 --> 32:36.190
Okay, so I believe I have all ten points.

32:41.630 --> 32:48.650
And I can just run through each of them and make sure that the closest ones are the lowest in number

32:48.650 --> 32:49.700
for their names.

32:49.700 --> 32:51.470
So there's point one for me.

32:51.470 --> 32:53.600
Point two, here's three.

32:53.630 --> 32:57.020
They're not in order here in the components panel.

32:57.020 --> 32:58.910
So I need to be careful there.

32:58.910 --> 33:00.290
Here's four.

33:00.320 --> 33:01.490
Here's five.

33:01.490 --> 33:03.080
It's out there a little bit.

33:03.080 --> 33:06.980
Here's 678 okay.

33:06.980 --> 33:10.640
So I'm going to go from top to perspective and rotate a bit.

33:10.640 --> 33:12.560
And here's my little point collection.

33:12.560 --> 33:14.900
And of course you could go all out with this.

33:14.900 --> 33:17.000
You can put as many of these as you want.

33:17.000 --> 33:19.310
But at least now I have this point collection.

33:19.310 --> 33:24.770
And the reason I wanted the ability to rotate these is because, well, if I use the same point collection

33:24.770 --> 33:30.980
every time, even if I pick random locations from around inside of it, well, that's going to become

33:30.980 --> 33:34.610
noticeable, but not if you rotate it every time.

33:34.610 --> 33:40.100
So now that I have a point collection and it has points in it, I'm going to go into arcane shards and

33:40.100 --> 33:46.100
I'm going to spawn one of these point collections and just use its points.

33:47.460 --> 33:50.910
So we'll just start by drawing some debug spheres.

33:50.910 --> 33:55.560
Now to spawn this I'm going to use Spawn Actor.

33:56.250 --> 34:01.440
And I can use spawn actor from class and just specify my point collection class.

34:02.580 --> 34:07.200
So if I search for BP point collection, I have a point collection.

34:07.680 --> 34:10.710
Now where do we want the point collection to start?

34:10.710 --> 34:14.250
Well, we know how to get target data under the mouse.

34:14.250 --> 34:16.410
That would be a good start for us.

34:16.410 --> 34:22.380
So what I'm going to do is right click and get target data under mouse.

34:24.710 --> 34:27.080
An on press can be hooked up to this.

34:27.080 --> 34:33.740
And then once we have valid data, then we can go on and spawn an actor, because now our data handle

34:33.740 --> 34:34.970
has that hit result.

34:34.970 --> 34:37.700
We can call get hit results from target data.

34:37.700 --> 34:40.850
And this hit results we can break.

34:42.500 --> 34:46.790
So break hit result and we can get the impact point.

34:47.380 --> 34:48.400
From it.

34:48.400 --> 34:55.780
And if I just hook this up to spawn transform, then this is going to create a transform from the vector.

34:55.780 --> 35:01.780
And if you don't like that, you don't like that you can't see what the rotation and scale are.

35:01.810 --> 35:06.370
You could split the struct pin and you can just plug impact point straight in.

35:06.370 --> 35:08.980
And then you can see for sure what those values are.

35:08.980 --> 35:13.780
Spawn transform, rotation is zero, scale is one, and so on.

35:14.110 --> 35:19.810
Now for the collision handling override I'm just going to use always spawn ignore collisions even though

35:19.810 --> 35:21.010
we shouldn't have any.

35:21.010 --> 35:26.710
This is just a bunch of scene components that really are no collisions to be worried about.

35:27.400 --> 35:33.730
But after we've spawned the actor, now we have a point collection and I'm going to take that point

35:33.730 --> 35:34.630
collection.

35:35.720 --> 35:41.990
And I'm going to call the blueprint pure function, get ground locations or get ground points rather.

35:42.380 --> 35:46.460
And this can take in a location to start with.

35:46.460 --> 35:48.230
That can be our impact point.

35:48.230 --> 35:52.190
I'm just going to drag it on behind that node, even though I don't like doing that.

35:52.490 --> 35:58.010
For now, I'm just going to drag it in there and we know that we can pass in anything up to and including

35:58.010 --> 36:02.300
11, and we can try a your override as well.

36:02.300 --> 36:04.580
But I'm going to try first with zero.

36:04.580 --> 36:09.590
And after getting those ground point locations I'm going to draw some debug spheres.

36:09.590 --> 36:16.130
But it would be a great idea once we spawn this to promote it to a variable so we can delete it later.

36:16.130 --> 36:18.860
So I'm going to call this point collection.

36:19.070 --> 36:23.330
And once we're done with the point collection we can go ahead and destroy it.

36:25.420 --> 36:31.090
So after getting the ground points, how are we going to draw debug spheres?

36:31.090 --> 36:34.660
Well, we can loop over this array we can use for each loop.

36:36.440 --> 36:37.460
We can hook this up.

36:37.460 --> 36:42.920
And for each of these scene components, we can draw a debug sphere.

36:45.270 --> 36:49.470
So in the loop body draw debug sphere.

36:50.120 --> 36:53.900
And I'm going to take each element and get its location.

36:53.900 --> 36:55.790
So get world location.

36:56.360 --> 36:58.220
And that will be the center for the sphere.

36:58.220 --> 37:00.050
The radius can be 20.

37:00.530 --> 37:02.870
We'll leave the line color at white.

37:02.870 --> 37:08.120
The duration can be 20s thickness will leave alone.

37:08.330 --> 37:14.120
And by the time we're done with this for each loop, we can then end our ability by hiding that magic

37:14.120 --> 37:17.600
circle, having a delay, and ending the ability.

37:17.600 --> 37:18.590
And of course.

37:19.350 --> 37:23.100
We can also destroy our point collection.

37:24.650 --> 37:27.650
So we're going to call Destroy actor on it.

37:29.890 --> 37:35.680
And then every time we execute this ability, we're making a new point collection.

37:35.680 --> 37:39.760
And we can even try different your overrides here.

37:39.790 --> 37:42.340
So let's give this a shot.

37:43.090 --> 37:45.220
I'm going to save all and press play.

37:45.220 --> 37:49.450
And I'm going to try pressing the one key.

37:49.960 --> 37:52.180
And then we're now waiting for input.

37:52.180 --> 37:53.680
So I'm going to press it again.

37:54.280 --> 37:56.800
And there we have our points and check it out.

37:56.800 --> 37:58.720
One of these is up on the stairs.

37:58.720 --> 38:02.230
So we're now seeing how useful that line trace can be.

38:03.220 --> 38:04.330
Pretty cool.

38:05.340 --> 38:07.110
So that's looking pretty nice.

38:08.230 --> 38:10.930
So once again I'm going to go ahead and press one.

38:10.930 --> 38:11.950
Press it again.

38:11.950 --> 38:18.580
And we have these points right now I'd like to see what happens if we pass in a yaw override.

38:18.580 --> 38:21.730
First of all I'm just going to pass in a value like 45.

38:21.730 --> 38:24.580
So I expect to see a different set of points.

38:25.000 --> 38:26.860
And to me it does look different.

38:26.860 --> 38:29.230
But it's a little hard to tell.

38:29.230 --> 38:34.660
So one way we can tell is by using a random value.

38:35.550 --> 38:46.920
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

38:46.920 --> 38:48.450
this a couple times.

38:48.450 --> 38:51.150
We can show these ground points twice.

38:51.150 --> 38:55.890
So we can place our mouse cursor at one particular location.

38:55.890 --> 38:58.680
I'm going to just come out here so I have more room.

39:00.510 --> 39:03.720
So I'm going to place my mouse cursor at this location here.

39:05.080 --> 39:08.320
Let's full screen and I'm going to press one.

39:10.870 --> 39:12.460
And then press one again.

39:12.820 --> 39:13.870
There's my points.

39:13.870 --> 39:19.540
And now I'm going to keep my mouse at that location, press one and press one again.

39:19.540 --> 39:22.600
And the second time we see new points.

39:22.600 --> 39:27.730
If that your override didn't work, we wouldn't see points just come out of nowhere.

39:27.730 --> 39:31.210
These spheres would all be drawn on top of each other.

39:31.210 --> 39:35.500
So that tells us that we're rotating these points.

39:37.650 --> 39:38.520
So this is great.

39:38.520 --> 39:42.900
Now we have some points and we can use this point collection.

39:42.900 --> 39:46.680
And of course we can always adjust these points.

39:46.980 --> 39:51.240
I may not have the most even distribution here of my points.

39:51.240 --> 39:58.740
So it might be worthwhile for me to go through and just kind of maybe spread them out a little bit or

39:58.740 --> 40:03.270
make sure that they're not quite so elongated as they are.

40:07.120 --> 40:14.020
But the cool thing is that we have these points and we have the ability to get some random rotation

40:14.020 --> 40:14.800
as well.

40:17.000 --> 40:22.430
So that's the next step in our ability is being able to get some random points.

40:22.430 --> 40:23.540
And.

40:24.400 --> 40:25.960
That's looking pretty good.

40:27.020 --> 40:33.800
Now these are random points, but if you're observant, you're going to notice something.

40:34.370 --> 40:38.600
If I press play and I create my random point cloud.

40:38.990 --> 40:40.760
Well, here's what it looks like.

40:40.760 --> 40:42.710
And if I go ahead and eject.

40:44.380 --> 40:49.000
And I take a good look from the top here, and then I go into my point collection.

40:49.570 --> 40:51.310
There's something wrong.

40:51.310 --> 40:55.720
This collection of points looks nothing like this collection of points.

40:55.720 --> 41:00.730
Even though we gave a random rotation, the rotation should be consistent.

41:00.730 --> 41:04.630
It should be like taking the whole actor and rotating it by a certain amount.

41:04.630 --> 41:12.280
But this looks seemingly like a bunch of random points that have all been rotated randomly individually.

41:12.280 --> 41:17.170
And that's exactly what is happening, because these are blueprint pure nodes.

41:18.240 --> 41:25.620
You see, every time we use a blueprint pure node, it's going to be evaluated again, especially with

41:25.620 --> 41:28.050
these random number generator functions.

41:28.050 --> 41:35.130
If the wire that's using it's output is used for anything, then the blueprint pure function is called

41:35.130 --> 41:35.640
again.

41:35.640 --> 41:39.150
And that includes using them in for loops.

41:39.150 --> 41:46.710
For example, in our for each loop this get ground points that returns an array is returning a new array

41:46.710 --> 41:51.090
every single time because it itself is a blueprint pure function.

41:51.090 --> 41:55.440
So for that reason we have to be careful with these blueprint pure functions.

41:55.440 --> 41:57.630
For one, they're expensive.

41:57.630 --> 42:03.000
If you use a for loop with a blueprint pure function, especially one that does some array business,

42:03.000 --> 42:05.790
and for two they can be confusing.

42:05.790 --> 42:13.440
Now I'm going to set the get ground points num points input to four and just show you really what I

42:13.440 --> 42:13.830
mean.

42:13.830 --> 42:18.960
It's easier to tell this kind of thing when we have a smaller number of points.

42:18.960 --> 42:23.010
So the points number of points is four I'm going to press one.

42:23.010 --> 42:24.060
Press one again.

42:24.060 --> 42:25.050
Now look at that.

42:25.050 --> 42:27.870
This doesn't really look like the first four points.

42:27.870 --> 42:31.590
Not if we go in and take a look at point zero here in the middle.

42:31.620 --> 42:33.840
Point one here right there.

42:33.840 --> 42:35.460
Point two is right here.

42:35.460 --> 42:36.930
So we have this triangle.

42:36.930 --> 42:39.690
And then point three is right here.

42:39.690 --> 42:44.100
So we basically have one big triangle and one point in the center.

42:44.100 --> 42:45.300
That's the origin.

42:45.300 --> 42:49.140
That's what we should see if we didn't have any random rotation.

42:49.140 --> 42:55.080
If the yaw override was zero then if we go in and press one and press one again, that's what it should

42:55.080 --> 42:57.660
look like a big triangle, one in the middle.

42:58.510 --> 43:04.780
And if we were rotating everything consistently, then that whole triangle would then be rotated right.

43:06.110 --> 43:14.330
So the way to fix this is to promote this array returned from ground points to a variable.

43:14.330 --> 43:17.420
So we go ahead and promote to variable.

43:17.420 --> 43:20.240
And we can call this ground points.

43:22.860 --> 43:26.430
And once we do that, now we have a variable.

43:26.430 --> 43:32.850
And if we use that instead in our array, we're not evaluating a blueprint pure function multiple times.

43:32.850 --> 43:36.480
We can just evaluate it once and cache off that data.

43:36.480 --> 43:43.140
So if I hook this random float back in, now that we're using this ground points array, instead of

43:43.140 --> 43:48.060
evaluating the blueprint pure node every time, let's see how that ends up.

43:48.640 --> 43:50.500
So I'm going to press one and one.

43:50.500 --> 43:52.870
And we have our familiar triangle.

43:52.870 --> 43:54.160
It's not all muddled up.

43:54.160 --> 43:58.450
And if I press it again we have the same triangle but it's rotated.

43:59.280 --> 44:06.450
And I can do this multiple times, and I see that each new set of points is just three new points,

44:06.480 --> 44:09.660
a triangle with one point in the middle.

44:10.140 --> 44:14.220
And that's exactly the behavior that I was expecting and wanting.

44:14.220 --> 44:21.750
So now that we have this function that gives us a collection of points that's rotated, we can trust

44:21.750 --> 44:24.510
it when we increase that number of points there.

44:26.930 --> 44:32.900
Okay, so with that we now have a point collection.

44:32.930 --> 44:34.430
It has points in it.

44:34.430 --> 44:36.770
We can rotate the point collection.

44:36.770 --> 44:38.870
We can get any number of points.

44:38.870 --> 44:43.280
Well not any number but up to 11 because that's how many points we have in here.

44:43.280 --> 44:49.490
And we can generate a bunch of random points and we can specify how many we want.

44:49.490 --> 44:53.000
And if we only want one, we should get that central point.

44:55.760 --> 44:57.320
So right there in the middle.

44:58.240 --> 45:03.190
And with our ability at level one, that's where we're going to spawn that first shard.

45:03.190 --> 45:07.390
But then when we level up our ability, we're going to pass in higher numbers.

45:07.390 --> 45:10.960
So at level two I'd like to spawn two shards.

45:11.710 --> 45:15.820
And it's going to look like this one at the center and one slightly far out of it.

45:15.820 --> 45:22.960
But we're getting a random rotation every time, so that way it doesn't look the same every single time.

45:22.960 --> 45:26.530
And then when our ability levels up to level three.

45:27.300 --> 45:28.920
Will spawn three of them.

45:30.230 --> 45:32.780
And it'll be a little triangle like this.

45:34.610 --> 45:36.590
And of course, at level four.

45:38.060 --> 45:43.190
Then it'll look more like this, where we have one in the middle and three and so on.

45:43.190 --> 45:44.000
You get the point.

45:44.030 --> 45:48.830
Now these are spaced a little bit too far apart, so I'm going to just bring them in.

45:48.830 --> 45:50.750
I'm going to time lapse bringing them in.

45:50.750 --> 45:52.760
And then we're going to wrap up this video.

46:05.750 --> 46:06.290
Okay.

46:06.290 --> 46:10.310
And with that, I'm just going to pass in 11 and see the spread here.

46:11.050 --> 46:12.370
And that looks pretty good.

46:13.140 --> 46:13.740
Okay.

46:13.740 --> 46:20.340
So now we have random locations and they're evenly spread out.

46:20.340 --> 46:25.590
So if we had just picked random locations with random number generators for each location, we could

46:25.590 --> 46:28.140
have shards overlapping with each other.

46:28.140 --> 46:33.930
So another benefit of this is we have evenly distributed points randomly selected.

46:33.930 --> 46:40.620
So in the next video we're going to start going about how we can actually spawn those shards and make

46:40.620 --> 46:42.120
this actually look really cool.

46:42.120 --> 46:44.940
So excellent job and I'll see you soon.
