So we're going to be ramping up the complexity here and start to look at Line Traces. These are ways we have, in engine, of firing a line from one point to another and seeing what we hit.. Also known at hit scans or ray casts, they're incredibly powerful and versatile.
So let's try not to get too complex too soon - here we're just making a tool that casts a ray down and then moves a Cube to the hit location, assuming it hits. Let's break it down:
LineTraceByChannel: This Node takes two World Space Positions and draws a line between them and checks to see what was hit. This Line Trace is using the Visibility channel to see what objects to check against (basically can we see the object or not). It's also possible to do a LineTraceForObjects, where we can check for Static or Dynamic Objects only but we're just going to use ByChannel for now. There's also the option for a SphereTrace where the engine moves a Sphere along the ray to see what it hits, but again let's just stick to lines for now.
GetActorLocation: By getting the location of the DefaultSceneRoot we're getting the location of the Blueprint in the world - great, that's the start location of our line trace. To just check straight down we just need to take away a value from the Z component of the world space vector. We could use a Vector or, as we're doing here, just do Vector + Vector and break the second Vector and plug a Float Parameter into the Z.
Note the Debug Draw Type options - this doesn't work very well in the Construction Script but when we get to using these in game this will give a very useful preview of the line being cast.
Branch: The line trace node outputs a Boolean value depending on if the trace was successful or not, ie, did the trace hit anything. If we didn't hit anything, then we don't want to do anything so we can just leave the False pin blank.
Break Hit Result: The other output pin from a Line Trace is a custom Struct with all the information about the Trace that we might need. We've talked about Structs earlier in the Data Types lesson but all we need to know here is that we have to Break it to get to the data inside. There's lots of data available but all we really need to get is the Location of the hit, which is returned in World Space.
SetRelativeLocation: We only want to move the Cube relative to the origin of the Blueprint, but we have the World Space location of the Hit. So to do this we just simply subtract the Blueprint origin location from the Hit Location to get the difference, which is the Local offset. Don't worry if this isn't super obvious, it'll take a few tries to work out the math first few times you do it but once you start doing a lot of traces then it starts to make more sense.
So when I said the term 'hit scan' earlier you may have thought of weapons in a video game and that's exactly what we're going to make here! Firstly we can copy our code into the Event Graph and make a few changes. We need to get the position of the Player Camera as our Trace Start location, then we need the Forward Vector (ie the direction the camera is facing) if we multiply this by a Range value (5000 is a good starting point) and Add it to the Camera Location, we have our End Point. Now, instead of moving a Cube, we can spawn a Particle Emitter at the Hit Location and we're almost there.
Lastly we can just make a Keyboard Input for our Blueprint (don't forget the Input AutoActivate) and when we play our game pressing the SpaceBar will create an explosion where we're facing.
So, explosions are cool and all but what if we want to create something that doesn't automatically destroy itself after it activates, such as some Fire! Well we'll need some way to store some information about all the Fires we've dynamically created - enter Arrays. Arrays are a different type of Data Type that allows us to store multiple items of data in a single Variable - notice the small grid icon next to the Variable Type drop down. Unreal also supports Maps and Dictionaries which are similar, but we'll just stick with Arrays for now.
So what exactly are we doing differently - on a LeftClick we create a Fire PFX and add it to our Array, which dynamically grows to fit. Now when we RightClick we do a ForEach Loop and Destroy all the Fires. This ForEachLoop is new but hopefully you can work out what it does - it's similar to a normal ForLoop but instead of us saying how many times to loop it does it once for each Element of the Array, perfect for affecting everything in an Array with a simple Loop!
Finally we have to Clear the data from our Array so we don't try and destroy the same Fire multiple times.
So before we get to our final Line Trace example we need to make another Blueprint to act as a target for us. Here I've just created a Custom Event that starts a Timeline that changes an Opacity material Parameter from 1 to 0. Once that's done it destroys the whole Blueprint, simple enough.
So for our final example we're just making a small change. Sadly it involves introducing a whole new concept from computer science - that of Casting. Basically Casting is a way of checking if an object is the sort of object that you think it is. I.e. is the object that we've hit with our Line Trace a TargetBox blueprint, if it is (the Cast is successful) then we want to do our Fade. The Cast To node allows us to do this by allowing us to do something As the object that was Cast to - basically we can use it to access our Events and Functions, allowing us incredible control over how we divide up our Blueprints and control everything.
Finally a short comment about performance - sadly Line Traces can start to get expensive, especially if they're large distances and happening frequently. They're incredibly useful and powerful when they're used correctly but if you start doing 15 traces a frame around the whole world you're going to have some very annoyed coders to deal with when your frame rate drops to single digits. That isn't to say never use them, but just be aware when you do that they're going to have some overheads.