‫Hello and welcome back.
‫Now we are moving our tank forward and backward, but we have no way to actually steer the tank.
‫So in this video, we're going to work on actually turning the tank using something called local rotation.
‫This is the rotational analog to add actor local offset.
‫Now add actor local offset had multiple input parameters and we only passed in the first one as the
‫other three were optional.
‫But one of those other three had to do with sweeping.
‫And we're going to discuss a little bit about sweeping before we continue implementing rotation.
‫So I'm back in the documentation for ADD Actor Local Offset.
‫So let's take a look at these input parameters once more.
‫The second one is called B Sweep and it's a Boolean.
‫Now, if we scroll down a little bit more and read the information here for B sweep, it says Whether
‫we sweep to the destination location triggering overlaps along the way and stopping short of the target
‫if blocked by something.
‫It also goes on to say that only the root component is swept and checked for blocking collision.
‫Child components move without sweeping.
‫If collision is off, this has no effect.
‫So let's talk about what this means now in games programming, sweeping is a technique done by the engine,
‫as long as sweeping is enabled.
‫If we have a moving object such as a sphere represented by this circle, each frame as this sphere is
‫moving, the engine is performing sweep checks.
‫This means it's checking to see if that move for this particular frame would have resulted in an overlap
‫between two objects.
‫So I have this block here represented by this rectangle.
‫Now let's just consider that these are the only two objects in the world.
‫So while sweeping is enabled as the sphere is moving towards the object, the engine is checking to
‫see if these two objects are overlapping.
‫Now, as the sphere continues to move, let's say during one of these frames the sphere would have moved
‫such that it's overlapping the other object.
‫Now what sweeping enabled does is the engine will detect this overlap and move that sphere back for
‫that particular frame so that it never actually penetrates the object.
‫Now we never actually see the sphere penetrate the object.
‫The engine catches that overlap before the movement is actually implemented.
‫So the result is that we see that the sphere stops just short of overlapping.
‫So if this rectangle were a wall, for example, the sphere would stop at the surface of the wall.
‫That is what sweeping achieves for us.
‫Now the documentation says if collision is off, this has no effect.
‫So collision has to be enabled in order for sweeping to work.
‫So back here in tanks CP in the move function, here's our call to add actor local offset and if we
‫want we can pass in another input parameter here, the second one being the sweep boolean so we can
‫pass in true here.
‫So let's compile this and see the effect of enabling sweeping.
‫Now if we press play and we attempt to move through a wall, for example, we'll see that we move right
‫through the wall.
‫So something isn't quite working here.
‫Now let's look at what that route component for the BP pond tank is.
‫Recall, we used the capsule component for the route.
‫So with capsule components selected in BP pond tank.
‫Let's go to the details panel and scroll down and we'll see here a section called Collision.
‫And here we see Collision Presets and it has a dropdown.
‫So let's expand that.
‫Now, Collision Presets can be set to any number of options and by default we see overlap all dynamic.
‫Now, depending on the version of Unreal Engine you're using.
‫You may see something else here, but we can change this.
‫If we select the dropdown and choose block all dynamic, then the grayed out options below change.
‫Remember we were on overlap all dynamic and here we see three columns of checkboxes.
‫These are collision responses and the column to the left show a list of collision object types.
‫So any given component has its own collision object type.
‫Notice we can see the object type for the capsule set to world dynamic.
‫And when we change collision presets to block all dynamic, you'll see that the collision responses
‫are all checked to block in response to all other collision object types.
‫So let's press play and see what happens when we try to pass through things.
‫You'll see that we stop just short of overlapping with.
‫The other ponds.
‫Now, if I move the tank so that we can attempt to overlap with the wall and sort of go around the other
‫ponds.
‫Now, if I press play, I block the wall as well.
‫So this collision preset block, all dynamic sets the collision response to block all other object types.
‫And you can always see the collision object type of a particular component by selecting it in the components
‫panel and scrolling down to the collision section in the details panel and opening the dropdown for
‫Collision Presets.
‫I have the base mesh selected and its object type is world dynamic and it's set to block all.
‫So now we see that sweeping is working since we set our collision presets for the capsule comp to block
‫all dynamic.
‫And we saw in the documentation that only the root component is swept and checked for blocking collision.
‫So it doesn't really matter what the other components are set to.
‫We're only checking to see if the root component is blocking something.
‫Now, one issue that's tripped up some students is that they cannot move as soon as they set the capsule
‫to block all dynamic.
‫Now, one reason for this could be that your capsule is overlapping with the floor.
‫If the capsule is overlapping with the floor, you won't be able to move because the engine will not
‫allow your tank to move if the capsule component is overlapping with something that it's set to block.
‫So an easy fix for this would be to make sure your capsule is not overlapping with the floor.
‫Now, you can go into your BP -- tank and make sure that your capsule is just above the wheels here.
‫I'm going to go into orthographic view.
‫And select my base mesh and just bring it down.
‫So the wheels are just below the capsule component.
‫So now if your mesh is just on the floor and the capsule is just above the mesh.
‫You should be able to move around.
‫So I'm going to hit play and there we go.
‫So now that we have sweeping out of the way, it's time to start implementing rotation.
‫Let's go back to our project settings.
‫So we go to edit project settings, scroll down to input and in the input section we have our axis mappings.
‫Now we've already taken care of.
‫Move forward.
‫It's time to take care of the next one called Turn and Turn has D and A assigned to it where D has a
‫scale of one and A has a scale of negative one.
‫We'd like to use the D and AX to rotate the tank.
‫So in order to bind a function to the turn axis mapping, we need a function to bind.
‫So we're back in V's code and I'm going to go into the tank file so we can create a function to bind
‫to that turn axis mapping.
‫Now I'm just going to call this void function turn and just like move.
‫It needs a float input parameter and we'll call this value.
‫So we've declared this function, let's define it and tank CP and I'm going to put it just under the
‫move function.
‫So I've given it a function body and I need the class name along with the double colons just before
‫the function name.
‫Now we have a proper function.
‫Now, this isn't the only thing we need to do.
‫We need to make sure that this function is bound to the axis mapping called turn.
‫We do that in setup player input component and we do it just like we did the move forward axis mapping.
‫So we're going to say player input component, we're going to use the arrow operator and bind axis.
‫Now the first parameter is going to be the axis mapping name wrapped in a text macro.
‫So we're going to say turn as that was the axis mapping name.
‫Next is the object we're binding the function for.
‫We can pass in this and finally we pass in the function we'd like to bind again.
‫We need the address of operator and it's going to be a tank turn.
‫So it's as easy as that.
‫We've bound the turn function to the turn axis mapping.
‫The only thing left is to actually do something in the turn function.
‫Now we've seen that we have ADD actor local offset, but there's a rotational analog to this function
‫and it's called ADD Actor local rotation.
‫What this does is adds a local rotation to the actor as its name suggests, and you'll see that there
‫are two different versions of the function, one that takes an F rotator and one that takes something
‫called an F quad.
‫We're going to use the version that takes an F rotator.
‫It's called Delta rotation.
‫And just like ADD Actor Local offset, it can also take a sweep parameter and the same other two input
‫parameters as add actor local offset.
‫And these last three input parameters are optional, just like add actor local offset.
‫So instead of an F vector, we're going to pass in an F rotator.
‫Now back here in the turn function, if we create an F rotator and we call this Delta rotation, we'll
‫see that if we right click on F rotator and go to definition, we're taken to rotator and we'll see
‫three public member variables here of type float.
‫Now just like the F vector F rotator has these three components only instead of X, Y and Z, we have
‫pitch yaw and roll.
‫Now, yaw is the component that we're interested in.
‫It says rotation around the up axis in parentheses around Z axis.
‫And that's the only type of rotation we care about rotating around the Z axis.
‫That's how we can steer our tank.
‫Now, I'm just going to point out to you that there are multiple constructors for the F rotator as well,
‫and that the default again says no initialization, just like with the F vector.
‫So we can use the one that takes a single float and all components will be initialized to that float
‫value.
‫There's one with three float values and you can take a look and see some of the others.
‫Now, I'll also point out that there's a zero rotator and by the way, this is a static zero rotator.
‫That's why we can go back into tank CP and say something like equals F rotator zero rotator zero rotator
‫is a static member variable and you can access static member functions and variables like this by specifying
‫the class name with the scope resolution operator and referencing that static variable or function by
‫name.
‫That's what we're doing here with you.
‫Gameplay statics get world delta seconds is a static.
‫Function, meaning we don't need an actual instance of the game gameplay statics class to exist for
‫us to access that static function.
‫It just exists already.
‫Same with zero rotator and zero vector.
‫So I'm going to close out of rotator h and we have this delta rotation and it's initialized to a zero
‫rotator.
‫Now your pitch and role are zeroed out just like X, Y and Z are zeroed out for the F vector.
‫So we're going to need to change that your component.
‫So just like I did with our delta location in the MOV function, let's create some pseudocode for delta
‫rotations.
‫Ya, we're going to want y'all to be set to value scaled by Delta time of course, because we want this
‫turning to be frame rate independent, but we also need some sort of turning speed we can call this
‫turn rate.
‫So once we've set that, yeah, then we can add that local rotation which is going to rotate the actor
‫according to the F rotator each frame and that ya will be scaled by value.
‫So it'll be zero if we're not pressing any keys and it will have a value if we're pressing the DX and
‫ax.
‫So now you have a challenge.
‫This is going to work just like adding the actor local offset.
‫The only difference is we're rotating the actor now.
‫So since we need some sort of turn rate for rotating the actor, you're going to create a turn rate
‫variable, make this a float and put it in the private section right next to the speed variable.
‫Expose this variable with you property and choose the appropriate new property specifiers.
‫Now in the turn function you're going to set Delta rotation in particular, we care about the your component
‫set the value equal to value times our turn rate variable and also multiply by delta time and then you're
‫ready to call add actor local rotation passing in this f rotator now for the second parameter go ahead
‫and pass in true for the B sweep input since we do want to sweep when rotating, pause the video and
‫implement rotation for the tank now.
‫Okay.
‫So this is going to be fairly simple.
‫We just need a turn rate variable.
‫Now I'm going to go into tank just under speed and create float turn rate.
‫Now you probably initialize this to some value and that's okay.
‫If it's different than what I'm choosing, I'm going to go with 45 F and see how that works.
‫But we're going to expose this to blueprints so we can change it while we're developing.
‫Now I'd like it to be edit anywhere and I'm going to stick it in the same category movement as speed.
‫So I'm going to go ahead and steal this you property and paste it right here above turn right so it
‫set it anywhere.
‫Category movement now and tank CP.
‫I'm ready to set the yea for Delta rotation.
‫So we're going to say Delta rotation.
‫Yeah.
‫And we're going to set it equal to value times, turn rate times, delta time.
‫And of course we can get Delta time with U gameplay statics, get world delta seconds passing in this
‫as the world context object.
‫So I'm going to paste that right there.
‫Now I know that my pseudocode doesn't exactly match.
‫It's in the wrong order.
‫Delta time is in the middle here.
‫It doesn't matter because when multiplying three values together, you can multiply them in any order
‫and still get the same result.
‫So just in case you were wondering about that, the math will still come out the same if you multiply
‫these three values in a different order.
‫So don't worry about that too much.
‫Now we have delta rotation.
‫The only thing left to do is to call add actor local rotation, and we're passing in Delta rotation
‫and for the second input we're going to pass in true to enable sweeping when rotating.
‫So let's compile this.
‫All right, we're compiled now.
‫You may notice in a couple of the next videos that zero vector and zero rotator are missing from these
‫lines.
‫That's because I started off with these initialized and realized later that these should probably be
‫initialized at least with zero values.
‫So don't worry if you see these lines later looking like this on initialized, keep your zero vector
‫and your zero rotator and you'll see that I catch this in a near future video.
‫So don't worry.
‫If you don't see these initialization ones, they should be there.
‫And we're back in the editor.
‫Let's hit play and I'm going to use the D key and we're rotating and the A key rotates me back the other
‫way and we can also move forward and back.
‫So now that we can rotate and move forward, we have the ability to move around the world.
‫This is a great milestone.
‫Now I'm moving quite slowly, but that's okay because I can select my tank and I can search for the
‫movement category and change turn rate to something higher such as 90.
‫So let's go ahead and hit play.
‫And that's quite a bit faster.
‫Now, if you think this is still a little slow.
‫You can, of course, adjust these.
‫So I'm going to select the -- tank again.
‫And instead of 400, let's make it 800.
‫Why not?
‫Instead of 90, let's go to say 120.
‫Now, if I press play, I'm quite a bit faster.
‫So this is looking really, really good.
‫So looking back at the section plan, we now have a tank that can move throughout the world.
‫That first bullet point is definitely checked off and we're handling WASD movement.
‫We're not handling mouse input just yet, but we'll get to that.
‫But we're one step closer to making this game complete.
‫So in summary, we learned what sweeping is and how we can enable that so that our objects do not pass
‫through one another.
‫We added an actor local rotation and we did this implementing a turn rate that we could adjust in the
‫details.
‫Panel in the editor to make development a little bit easier.
‫Great job.
‫We're now moving the tank throughout the world.
‫I'll see you in the next video.