Now that we have a target that responds to the player shooting, we can add some sort of challenge to start making our project feel like a game. A simple way to do this is to add some movement to our target. To accomplish this, we will first have to declare that our target actor is an object that is intended to move, and then we need to set up logic within the Blueprint that will manage how it moves. Our goal will be to make the target cylinder move back and forth across our level.
Changing actor mobility and collision
To allow our target to move, we first have to change the actor's Mobility setting to Moveable. This allows an object to be manipulated while playing the game. From the main editor view, select CylinderTarget_Blueprint
, and look at the Details panel. Underneath the Transform values, you can see a toggle for Mobility. Change this from Static to Moveable, as shown in the following screenshot:
Note
By default, basic actors that are placed in the world are set to static. "Static" means that the object cannot move or be manipulated during gameplay. Static objects are significantly less resource intensive to render, and this should be our default choice for non-interactive objects so that we can maximize frame rates.
It is important to note that the version of the target cylinder that we changed in the level is just one instance of the Blueprint template for the target cylinders that we have created. An instance refers to an actual object that has been created, whereas our Blueprints are descriptions of the kind of features that those instances will have once they are created.
Any changes we make to a target cylinder already inside the level will be made for that particular target cylinder only. To make changes to all future targets, we need to modify the Blueprint directly. To do so, open CylinderTarget_Blueprint
again, either by navigating to the open tab in the editor, or by double-clicking on the CylinderTarget_Blueprint
file in your Blueprints
folder.
With the Blueprint open, we want to navigate to the Viewport tab located underneath the menu toolbar. Along the left side, you will see the Components panel, which lists all the components that make up this Blueprint. Since we want to edit a property of the physical object, or mesh, we click on component StaticMeshComponent. You will see a familiar-looking details panel. It includes the same properties and categories that we saw when we edited the target cylinder in the level editing interface. Here, we have to switch the same Mobility toggle, located beneath the Transform properties, from Static to Movable. This will ensure that all future targets created from this Blueprint will already be set to be moveable.
Because we want to target this object with our gun, we also need to ensure that the target is capable of being collided with so that our bullets don't pass through it. Still in the details panel, find the category called Collision and look for Collision Presets in the drop-down menu. There are many other options in this dropdown, and by choosing the Custom option, you can even set the object's collision interaction with different object types individually. For our purpose, we just need to ensure that this drop-down menu is set to BlockAllDynamic, which ensures that the mesh will register collisions with any other object that also has a collider.
Now that we have made our target moveable, we are ready to set up Blueprints that tell the cylinder how to move. In order to move an object, we will need three pieces of data:
- Where the cylinder currently is
- What direction it is supposed to move in
- How fast it is supposed to move in that direction
To understand where the object currently is, we need to get some information about the world itself. Specifically, what are the coordinates of the cylinder in the world? The speed and direction are the values we are going to provide to the Blueprint, though some calculations will be necessary to turn those values into information that is useful for the Blueprint to move the object.
Storing data with variables
The first step is to create the two variables we need: direction and speed. Find the panel labeled My Blueprint. You should see an empty category marker called Variables, with a + sign to the right. Click on that + sign to create your first variable.
In the Details panel, you will see a series of fields for editing your new variable. The four fields that we have to edit are the Variable Name, Variable Type, Editable, and Default Value. We want our first variable to contain information about the speed of movement, so name the variable Speed
. For Variable Type, we want a variable that can hold a number that will represent our desired speed, so select Float from the drop-down menu.
Check the box next to Editable to enable the variable to be changed outside of this Blueprint. This will be useful for quickly adjusting the value to our liking once we start testing the moving target in the game. The Default Value category will likely not have a field, but will feature a message asking you to compile the Blueprint first. Do that, and a field for entering an initial value will appear. Change the default value to 200.0
.
Using the same process, create a second variable called Direction
. Choose Vector for Variable Type. A vector contains information about the X, Y, and Z coordinates, and in this case, we need to indicate the direction of change we want for the object movement. Make the direction variable editable and set Default Value to -10.0
for the Y axis.
Readying direction for calculations
We will now explore the steps necessary to get the information we need to provide a movement instruction. It might look intimidating at first, but we will break down each section and see how each node fits into the larger goal.
The first calculation we need to perform is to take our vector value for direction and normalize it. Normalizing is a common procedure in vector math that ensures that the vector is converted to a length of one unit, which will make it compatible with the rest of our calculations. Fortunately, there is a Blueprint node that takes care of this for us.
Click on the Direction variable we created in the My Blueprint panel, and drag it into empty space in the event graph. A small popup will appear, prompting you to select Get or Set. We want to retrieve the value we set for the direction, so choose Get to create a node containing the direction variable's value. Click on the output pin of the Direction node, and drop it into empty graph space. Type normalize
in the search field and select the Normalize node underneath the category labeled Vector. This will connect your Direction
variable to a node that will automatically do the normalizing calculation for us.
Note
It is good practice to leave comments on the sets of Blueprints as you create them. Comments can help describe what a particular set of Blueprints is intended to accomplish, which can be helpful if you are returning to a Blueprint after some time and need to make sense of your prior work. To leave a comment on a Blueprint, click and drag a selection box around the nodes you want to create a comment around to select them. Then, right-click on one of the selected nodes and select the bottom option, Create Comment from Selection.
Getting relative speed using delta time
To make our speed value relate to direction, we first need to multiply it by delta time. Delta time is based on the fact that the time taken between the frames of the gameplay can differ. By multiplying our speed value to delta seconds, we can ensure that the speed at which our object moves is the same, regardless of the game's frame rate.
To do this, drag the Speed variable onto the event graph and choose Get to create the speed node. Now, right-click on empty graph space and search for delta
. Select the Get World Delta Seconds option to place the corresponding node. Finally, drag the output pin from either the delta seconds node or the speed node, and drop it into empty space. Type an asterisk in the search field (Shift + 8 on most computers) and select the Float * Float node. Finally, drag the other output pin onto the remaining input pin of the new multiplication node to multiply these two values, like this:
Translating the existing location
Now that we have a normalized vector direction and a speed value relative to time, we need to multiply these two values and then add them to the current location. First, find the StaticMeshComponent component from the Components panel and drag it onto the event graph. This will create a node from which we can extract any data contained within the mesh component of the object.
Next, we want to get the mesh's location. One of several ways to handle this is to look at the transform properties of an object and extract the location from there. Click and drag the blue output pin into empty space, and then type Get World
. Select the Get World Transform option to create the node. A transform contains information about the rotation and scale of an object, in addition to its location. This will be useful because we want to ensure that we preserve the rotation and scale of our target even as it is moving, and we will need that data to create a transform value from our new movement information.
Now we want to break down the transform into its component parts so that we can use just the location in our calculations, while preserving the rotation and scale. Drag the output pin from the world transform node, and search for the Break Transform node to add to our graph.
Now we need to add the necessary nodes to add speed and direction to the location information we just extracted. Right-click on empty grid space and search and select the Make Transform node. This will mark the end of your calculations, so make sure that it is positioned to the right of all of your other nodes. The Make Transform node has three inputs, Location, Rotation, and Scale. The Rotation and Scale inputs should be connected to the rotation and scale output pins on the Break Transform node we created earlier.
Next, we need to multiply the Direction
vector and the Speed
float we calculated. Drag the output node of the Normalize node into empty space, and search using an asterisk. Select Vector * Float and connect the green input pin to the output of the float multiplication node that we used with speed.
Our final calculation step is to add Speed
and Direction
to the current location we calculated. Click on the yellow vector output pin of the new multiplication node, and drag it onto empty space. Search using +
and select the Vector + Vector node. Ensure that one input pin of this addition node is connected to the previously mentioned vector multiplication node, and then connect the other input pin is connected to the Location output pin of the Break Transform node. Finally, drag the output pin of our addition node onto the Location input pin of the Make Transform node. When you are finished, the result should look like what is shown in the following screenshot:
Now that we have the transform calculated, we can adjust the location of our target actor by this value. We used delta time to make our speed and direction changes consistent across frames, and as a consequence, we can simply use the Event Tick node to fire our move action every frame. Right-click on empty grid space, search for Event Tick
, and place the node somewhere to the right of your Make Transform node.
To move the actor, we will be using the Set Actor Transform node. Drag a wire from the execution pin of Event Tick to empty grid space, and search for Set Actor Transform
. Place the node, and then connect the Return Value output pin on your Make Transform node to the New Transform input pin on the Set Actor Transform node, as shown here: