Using Animations with Directional Movement
Face the Music
We're now going to make our first function. This allows us to contain a complex set of Blueprint nodes into a single custom node that we can call. It keeps our Event Graph clean and easily readable.
Double-click and open up your Hero's Blueprint. On the left side, beneath Components, in the My Blueprint window, you'll see a hierarchy of tabs with Graphs, Functions, Macros, Variables, Event Dispatchers, and Local Variables. This contains all the information your Blueprint has. We're interested in Functions. Go to the little + symbol to the right of the Functions category label and when it expands hit "+ Function".
Getting funky. |
Name it something like "Set Flipbook" as I have. If it didn't open up automatically, double-click the new function to pull up a clean new graph, similar to the Event Graph tab. There will be one lonely node named after your function. This is where your function begins when it's called.
The first thing we want to take a look at is whether or not we're receiving input from either of our axes that we've established as our movement inputs. If you recall these were "UpOrDown" and "LeftOrRight". To check these we can use getters to check the return values of those axes.
Check for input. |
We want to use a Branch node (which is our If-Else Statement to use some programming parallels) checking a Boolean "OR" node, which will be flipping our Branch to "True" if we're getting anything other than 0 from our inputs. If we are receiving input then we know we're moving and we need to change our animation to the direction we're moving in. If we're not moving then we want to just use the current animation for whatever direction we're already in.
Create a comment block around these nodes to keep them grouped as a singular purpose. Before we continue with how to handle the True/False results from the Branch, we need to create a few things.
The first of which is an Enumeration Blueprint.
Enumerations and Structures
Once again we're going to return to our content browser and right click to create. You want to go to Blueprints > Enumeration under "Create Advanced Asset".
Enumeration and Structure creation. |
We will also be using a Structure soon too, so go ahead and make one of those as well. Name the Enumeration and Structure with appropriate names like I have. The Enumeration will be a list of possible directions we can move in, and the Structure will hold the animations we can use.
If you need more information about exactly what an "enumerated type" is, or an enum, please read up on it as it comes up in C/C++ and will be used frequently in your game development or programming pursuits.
Once your enum is created, open it, and setup four Enumerators inside as shown below.
Our four directions. |
With that finished, go back to your Hero's Blueprint. Similar to how we made a function before, make a new variable on the left side by hovering over the + and hitting "+ Variable" when it expands. It'll make a Boolean probably by default, or something else, but we want to change this variable type to our fresh Enumeration we made.
Select the new variable and on the right side—the Details panel, if you have the default window layout—change the variable's name to something like "CurrentMoveDirection" and then select the Variable Type drop down and search for what you named your Enumeration. Mine is named "Move Direction" so that's what I selected.
Setting up our variable. |
We now have a variable of the type of Enumeration we created that holds those four Enumerators, or in our case directions. We can use this in our function. Compile your Blueprint in order to make that "Default Value" section appear, and set the default Current Move Direction to Down, or whatever you may wish. I want my character to spawn facing downwards—with his face to the camera—so this is the default I chose.
You may also want to begin organizing your variables as well with categories. I made an Animation category and placed this variable within it.
Make the Connections
It's time to continue off our Branch node. We'll begin with the True output.
You can click and drag your CurrentMoveDirection variable out onto the graphing area, and you'll be presented with a menu of "Get" or "Set" for your variable. We want to set. For quick access in the future, you can Alt-Click and Drag to get a Set node, or you can Ctrl-Click and Drag for a Get node.
We need to now send data into that Set node to specify which Enumerator we want it set on. It's by default set to Down, or whatever you chose for your default Current Move Direction. We want that to change every time we move.
We'll use the "Select" node.
Selecting directions. |
The Select node changes based on context—specifically the Index. If it doesn't look like above yet, it's because you haven't attached the other nodes yet. Don't worry.
The first Select node will be deciding if we're moving Up. Based on our axes and inputs, this means we want to see a value greater than 0 coming from the UpOrDown axis. Put a "Get UpOrDown" node down, send it to a ">" Boolean test, and then send the result to the Index. This should modify the Select node.
If it's True, then we want our Enumeration variable set to Up. Send the "Return Value" to our Set node.
If it's False, then we need to keep testing. The next test is whether or not it's less than 0 on the same axis. Make another Select node off our False, and again set up a similar test with the "Get UpOrDown" but use a "<" Boolean test this time. If this is True, then we're facing Down. If it's False, it means that our axis is 0, and we could be going Left or Right. We now have to test for that.
Do one more Select node, and this time hook up the "Get LeftOrRight" to a ">" Boolean test. If it's True, we're facing Right. If it's False, well, it can only be Left because we're out of Enumerators to select.
Comment those nodes to keep them grouped together and organized.
Changing Animations
We now have the ability to set our Current Move Direction based upon our input axes. But we're not doing anything with that information yet. It's time to use the "Set Flipbook" node (not to be confused with our own function which we're currently making, Set Flipbook. And now that I think about it, and write this, I realize it would be best to rename the function to establish the difference...I have now renamed this function to "Set AnimationFlipbook").
Drag off of the output pin of our Set node and find the "Set Flipbook (Sprite)" function. It should automatically grab an additional node—a reference to the Sprite component—and have that set to the Target input. Any time you see something in parentheses after the function's name that's usually what it means it's going to do: it'll automatically create the referenced object's node.
You will also want to connect the False output of our Branch to the Set Flipbook node, because if we're not moving we don't want our walking animations to continue going. We want to stand still.
For this next group of nodes we will be using our Structure Blueprint we created earlier. Let's set that up now.
Go back to the content browser and open your Structure.
Very structured. |
Here's some extra reading on what a structure is in C++.
Make eight variables. Each of these need to be set to Paper Flipbook type. We need four idle variables and four walking variables. Set their default values to each of your Flipbooks you made.
See something interesting? Remember how I said we only had left-facing sprites, and no-right facing? We're about to get to that. I sat for a bit wondering how to solve this conundrum, because I didn't want to have to go and get Photoshop and mirror every sprite I use. I wanted a simple solution that could be done automatically with code and not require repetitive manual labor.
Set your right idle and walking values to be identical to your left idle and walking values for now.
Once that's all created, go back to your Hero's Blueprint and our function graph.
Selecting and setting our animations. |
The Set Flipbook node is going to change the currently set Flipbook of our Paper Character's Sprite Component. You can see that by clicking on the Sprite (Inherited) component and checking the Details panel. If you did what I did it should be set to the down-facing idle Flipbook.
Make another new variable and this time give it the Variable Type of our Structure. Search for whatever you named yours. Mine was named "Animation Structure".
Details for our animation structure. |
I put mine in the Animation category again. Since our defaults for this Structure have already been setup to our Hero's associated Flipbooks we don't need to change any of our Default Values.
Dragging off the Set Flipbook's "New Flipbook" pin, make a Select node. This is going to be based upon whether or not we're moving, or idle. So for the Index, we want to chain together nodes that can tell us this information. We want "Get Velocity" sent to "Vector Length" sent to a ">" Boolean test in that order. The result is then sent to the Index pin of our Select node. This will tell us if we're moving.
Off the Select node, we want two more Select nodes—one for False and one for True. If we are False—not moving—we want to get the appropriate Idle Flipbook. If we are True we want to get a Walking Flipbook.
This time we want to Ctrl-Click and Drag out a reference to our "Current Move Direction" Enumeration variable and use that as the Index for our new Select nodes. You'll immediately see how the Select node changes based on context of that Index. We get dropdowns for Up, Down, Left, and Right. We could manually select our Flipbooks, but this is why we made a Structure.
Ctrl-Click and Drag out our Structure variable—I named mine "FlipbookList"—and connect the associated pins to the Select nodes. "Flipbook List Idle Up" connects to the Up pin for the Select node attached to False, "Flipbook List Walk Up" connects to the Up pin for the Select node attached to True, and so forth, until you have a full selection of your idle and walk Flipbooks. Your setup should resemble what I've done in the above image.
Comment all of those nodes to make them grouped together.
We now have a fully functional animation selection for our movement. There's only one last thing to do, and that's to mirror our sprite for when he's walking right.
Sprite Mirroring
What is it we want to accomplish? Well, we simply want to swap the X-axis scale (our left and right axis) from 1.0 to -1.0 to make the sprite mirrored on that axis. In order to do this, we will use the Switch node.
How to mirror your sprite. |
Ctrl-Click and Drag a reference to our Current Move Direction variable. Drag off its pin and search for "Switch" and you'll find the "Switch on MoveDirection" node. Execute this after our Set Flipbook function from before.
Create a "Set World Scale 3D" node for both the Left and Right pins. If the reference to the Sprite isn't made automatically, just Ctrl-Click and Drag out the Sprite component to get one and set it as the Target for both of those nodes. That's what we're modifying.
If we're going Left, we want to keep things as they are. So the scale should be 1.0 in all our axes. But if we're going Right we want to mirror our Sprite. So set the X to -1.0 to mirror it over that axis.
And that's it. We now just want to call this function, and we want to call it every single frame of gameplay.
Go back to our main Event Graph tab, click and drag our new function out from the left side, and hook it up to the "Event Tick" node.
Make it so. Over and over. Forever. |
Our function will now be called every frame of gameplay. So if we're running at 60 frames per second (fps) we will call our function 60 times per second. Luckily our function isn't too slow. Be careful about what you're calling every frame.
Compile and save everything. Go back to your main tab with your level open. Hit "Play". You should now be able to move your Hero or Heroine around, and animations should be called and changed based upon direction and input values.
Congrats! You're that much closer to making a game.
- Matthew
I couldn't find the Get LeftOrRight node anywhere in the entire program. Where would I find that?
ReplyDeleteThat's what I named my "input". You have to setup input under project settings, then you can get the axes, and the node will be named whatever name you have them.
Delete