How to Animate Characters in Unity 3D | Two Dimensional Blend Trees Explained

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Love seeing how you keep adding onto this! Your animation is dope!

👍︎︎ 2 👤︎︎ u/TheIncredibleCJ 📅︎︎ Aug 24 2020 🗫︎ replies
Captions
hi i'm nikki welcome to my channel about game development this is a video in a series dedicated to learning unity's animation system in the previous video we learned all about creating dynamic animations using blend trees and a single float parameter today we're going to expand upon that knowledge by adding an additional float parameter and learn about two-dimensional blend trees alright let's get going to get everyone up to speed in the previous video we created a one-dimensional blend tree that was dependent on a single float parameter titled velocity after adding a script to control the current value of velocity through a player's input our idle animation would transition to the blend tree where dynamically created animations would blend our walk animation and our run animation really cool and helpful stuff i recommend you check it out if you haven't because there's knowledge from that video that will be applied today but now let's take those concepts to the next level we'll start today off by returning to mixmo.com and selecting our previously downloaded character we will download animations for strafe walking left and strafe walking right and we'll also download animations for straight for running left and strafe running right if you're new to the series go ahead and download idle walk and run animations [Music] as we know from the original exporting from miximo video we can leave the keyframe reduction off 30 fps for frames per second switch the format to fbx for unity and we'll set without skin because we already have the mixomo model in our scene lastly we'll be sure that the in-place checkbox is checked we will import these animations to our unity project folder and return back to our animator component where we currently have our idle animation as the default state and a one-dimensional blend tree used to blend our walk and run animations let's start by creating a completely new blendery rename it to 2d blendtree and set it as the default state we can move the old idle state and the original blend tree off to the side in the parameters tab we'll notice our leftover parameters from the previous video two boolean parameters titled is walking and is running and a single flow parameter titled velocity let's add another flow parameter titled velocity x and rename velocity to velocity z then we'll double click on the blend tree node to navigate us into the blend tree layer in the inspector window we'll notice that 1d for one dimensional is selected as the blend type this is the blend tree type that we used last time when we press down on the drop down we have four new options 2d simple directional 2d freeform directional 2d freeform cartesian and direct these are all considered 2d or 2-dimensional blend trees the stated difference is quote how the influence of each motion is calculated and they are all quite different because of this calculation our main takeaway from this definition should be that despite each option sharing two-dimensional in their names these blend trees each have their own specific use cases we'll start with 2d simple directional on selection we'll immediately notice that the inspectors format has changed the field titled parameter will now be titled parameters with two drop down menus currently set to our velocity x and velocity z parameters if your variables don't match up to mine simply select them so that they do next for our example we'll add seven motion fields after the second motion is added we will notice the newly displayed graph this graph can be interpreted as a standard x and y axis graph where our first parameter velocity x is represented by the x-axis and velocity z is represented by the y axis and the red dot in the center is the coordinate point defined by the current value of velocity x and velocity z once we have finished adding all seven motions let's set each of our seven animations idle walk run and all four strafe animations as we add each animation we'll see new nodes being added on the graph we'll discuss these further shortly but for now you may notice your position x and position y of each motion might be different than what's on my screen let's go ahead and reset all of them to the origin 0 for position x and 0 for position y now we'll go through them in order and properly place them for our idle animation we'll have it set to zero on the x-axis and zero on the y-axis this is because when the player is not moving they should not have velocity in the x or the z direction taking a look at our character in the scene view we can see that it is face in the z direction for this reason our velocity z is what we will use to drive the character's forward animations remember our blend tree uses the parameter on the right for position y so let's set our walk animation with a position y of 0.5 and a run animation with the position y of 2. so for idle animation sitting on the origin of the graph is to be our character's neutral position again where velocity x and z are both set to zero then we can set our strafe walk right animation to position x of 0.5 and strafe run right animation to position x of 2. and our characters strafe walk left animation to position x of minus 0.5 and strafe run left animation to position x of -2 so now that the nodes are set to the correct positions let's learn what they do at the graph we'll notice the color gradient ranging from blue to white without selecting emotion the areas that are more prominently blue are highly influenced by motions while areas in white are less influenced by motions if we click on a motion's node the graph will change to display only the area that this particular motion has influence over and if we drag our red dot around we'll notice small blue circles starting to expand from the motions that are close to the current location of the dot these circles are a way of showing us that these particular animation motions currently have influence and weight over the blendtree's animation let's try testing out our current blend tree in play mode but before we do be sure to disable the script if you haven't enabled from last episode when testing we'll notice some unexpected results for starters if we increase velocity z pass a value of 1 our running animation is never blended with our walk animation and when we test velocity x our idle animation will blend with our left walk animation but not our left run animation write animation or write run animation what's happening here i think this might be easier to understand if we fix the problem first scrolling back up to our blend type we'll switch from 2d simple directional to 2d freeform directional [Music] voila everything now works as expected so what's the difference here the difference is actually in the name 2d simple directional simple directional blend trees are intended to only use a single motion for any direction this is proven and showcased as we increase velocity z our blend trees blend between our idle and walk animation but it does not blend a second time between our walk and run animations additionally it will not use the left strafe run animation because it's in the same direction as the left animation we'll see a warning stating simple directional blend should have motions with directions less than 180 degrees apart this is the reasoning behind our left walk animation playing but not right walk animation it will not use either of the right animations because both animations are exactly 180 degrees from the left animation this can actually be proven by making the right strave walk less than 180 degrees from the left and this warning is removed if we add an additional animation below the origin this is because of how a simple directional blendtree's influence is calculated but we should still note that the additional motions in each direction are excluded from the blend i found the reason that the idle animation was still playing is because simple directional will also accept an animation at the origin so simple directional are not meant to be used for our current setup they're actually meant to be used for well simpler concepts that use less motions now that we understand simple directional we also know that freeform directional is intended for many animations that can be in the same direction and without a degree limitation so for today's project the freeform directional blend type is what we'll be sticking with now before we get into our code let's take a look at 2d freeform cartesian if we switch to this blend type we'll notice that all of our animations still work as intended and the difference is actually really hard to notice however if we take a side by side look at the blend graph between freeform and cartesian we'll see that they are in fact different this brings us back to what we learned earlier the difference between all three of these blend types is how the influence of each motion is calculated so what we're seeing on the graph is unity's difference in calculation for each blend type i actually found the master's thesis of the unity employee which these two blend types are based off of it's rather complex and truthfully well above my current knowledge and understanding but the main takeaway should be what's stated in the unity docs freeform cartesian is best used for animations that do not represent different directions and this blend type can have different concepts for the x and the y parameters such as degrees an example would be using vertical and horizontal angles to blend aiming animations and the last type of 2d blendery is direct direct allows you to control the weight of each node directly and is typically used for facial expressions unity has a great video covering this and i may cover it myself in the future awesome now that we have a base understanding of all 2d blend types we know that for our current setup we're going to use freeform directional because we are focused on velocity for both parameters and we have multiple animations in each direction now let's put control of these animations into the hands of the players using our code to avoid deleting code we wrote for our one-dimensional blend tree we'll create a completely new script we'll be applying similar logic that we have in the past so you may be able to complete this script without even needing to follow along as a fun experiment you can try pausing the video and testing your current knowledge to see if you can get the two-dimensional blend tree up and running selecting the y-bot we'll click add component type script and select new script let's title our script two-dimensional animation state controller double-click on the newly added script and our ide will open so we know that we need access to our animator component because it's where animations and parameters are stored in the scope of our script we'll declare a variable animator of type animator and in the start function we'll set the reference to the animator component by using unity's get component function passing in animator as the argument this will search the game object that the script is attached to and find the animator component next we'll declare two variables that will represent our velocity on the x and z axis below our animation declaration we'll write float velocity z is equal to zero and float velocity x is equal to zero navigating to the update function will start to handle player input we'll create four boolean parameters to track when a player presses four different keys we'll write the boolean forward press is equal to input.getkey passing w in as the parameter and we'll replicate this code for left pressed right press and run pressed passing in a and d and left shift to each get key function respectively as the parameters each of these booleans will be true or false depending on if the player is pressing down on the pass in key we'll now want to create some conditional statements so that we can modify velocity z and velocity x if the keys are pressed let's start with one we are familiar with from previous episodes we'll write if forward pressed velocity z plus equals time dot delta time times acceleration as a reminder time dot delta time is the amount of time since the update function was last called and we will need to declare our acceleration variable below our velocity variables we'll write the public float acceleration is equal to 2. by adding public to this declaration we'll have access to this in the unity editor and before continuing with our conditionals we'll also create a deceleration variable for when the player is not pressing the keys down let's duplicate and rename the acceleration code to deceleration alright let's now create two more conditionals to handle our changes in velocity on the x-axis which will control our strafing we'll write if left press velocity x minus equals time dot delta time times acceleration and then we'll write if right press velocity x plus equals time dot delta time times acceleration we use minus equals for left because in our blend tree we set the two left animations to the values of minus 0.5 and -2 if we enter play mode now and attempt to use our newly set up controls nothing will happen this is because our velocity x and velocity z variables are local variables to our script but remember we create a reference variable to our animator when we first created our script so we can actually access our velocity x and velocity z parameters with the help of this reference at the bottom of our update function we'll add the code animator.setfloat and pass in two parameters the first will be the string velocity z and the second will be our own velocity z variable next we'll duplicate this code and just change velocity z to velocity x let's test our new controls in play mode success holding the w key has our velocity z increasing and holding a and d will decrease and increase our velocity x accordingly awesome but there's definitely some improvements to be made to start we need to implement deceleration for both axis we should also cap the maximum and minimum velocities when each button is held down we also want to incorporate our left shift to run feature lastly we can refactor our code for better performance returning to our code we'll start by adding the maximum and minimum values to each of our current conditional statements for forward press we'll add a maximum value of 0.5 because we set our walk animation at point 5 of position y on our graph we'll then set a minimum value of minus 0.5 for left pressed and a max of plus 0.5 for right press the thing is we only want these minimum maximum values for when run press is not true so we'll add that condition as well by adding exclamation run pressed let's implement deceleration for our forward movement we'll write if forward is not press and velocity z is greater than zero then velocity z minus equals time dot delta time times deceleration we can also add the conditional if 4 does not press and velocity z is less than 0 then set velocity z equal to 0. this will reset our velocity z in case the deceleration ever overshoots our minimum value of zero next we'll implement the deceleration on the left and the right we'll write if left is not pressed and velocity x is less than zero then velocity x plus equals time dot delta time times deceleration we'll duplicate and modify this code for the right stating if right is not pressed and velocity x is greater than zero then velocity x minus equals time dot delta time times deceleration this code will slow down our character when the respective directional keys are not pressed and velocity x is not equal to zero now let's implement a similar reset that we have for forward press but for when both right and left are not pressed stating if left does not press and right is not pressed and velocity x is not equal to zero and is either greater than minus point zero five or less than point zero five then set velocity x equal to zero for this logic to work properly it's worth noting that we may need to adjust the point zero five values depending on what the acceleration and deceleration values are testing this in play mode we'll now see our character decelerating in all directions and locking at zero for both velocities when all keys are not pressed perfect so we've implemented our velocity min and maximums and we added deceleration let's proceed to handle running if we take a look at a lot of our conditions we'll notice repeating float values in the process of adding our running functionality we're going to refactor these float values by replacing them with a single float variable and the best part is we can reuse this value to work with both walking and running below where we declared our deceleration variable we'll declare two new public float variables called maximum walk velocity and maximum run velocity we'll set our maximum walk velocity to 0.5 because we place our walk animations all at 0.5 and we'll set maximum run velocity to 2.0 because in our blendery graph we set the running motions to 2.0 in our update function we can make a new float variable called current max velocity which is equal to either maximum walk velocity or maximum run velocity depending on if run press is true this code is called a ternary operator and we'll set the variable equal to the first option after the question mark if the statement before the question mark is true otherwise it will set the variable equal to the second option so in our case if run press is true then it will set the value equal to maximum run velocity otherwise it'll set it to maximum walk velocity we can then replace the conditions where we are using 0.5 with the current max velocity doing so will allow the player to exceed the 0.5 limitation when they are holding left shift because it updates the current max velocity in the conditional statement and our acceleration will continue to increase then we'll remove the condition for when run is not being pressed testing this in play mode it works but now let's set some caps for the increase in velocity we'll say if forward pressed and run press and velocity z is greater than current max velocity then velocity z is equal to current max velocity we would ideally do something similar for walking however replicating this logic without run press and with current max velocity would set the velocity to 0.5 immediately after letting go of run we prefer to decelerate to the maximum walk velocity so we'll write else if forward press and velocity z is greater than maximum walk velocity then velocity z minus equals time dot delta time times deceleration this leads to unwanted and jittery results we'll write one last else if statement stating else if forward press and velocity z is less than current max velocity and velocity z is greater than current max velocity minus .05 then set velocity z to the current max velocity and we'll copy the velocity logic to the previous else if statement but we need to reverse it because we're coming from a deceleration standpoint what this does is check to see if we're close enough to the current max velocity and if it is then we should just set it to the current max velocity in play mode we'll find that when we press w our forward velocity increases and maxes out at exactly 0.5 holding run will increase our velocity toward the 2.0 limit and again it will reach exactly 2. and if we let go our character decelerates back down and locks in at 0.5 once again perfect [Music] we can replicate this logic for left and right pressed we'll copy and paste this code twice and we'll replace forward press with right press and left press in each block of code for left press however it can get quite confusing we need to also modify the current max velocity so that the value is negative and we will need to switch a couple of the less than greater than signs we can test this again in play mode to make sure that everything works exactly as we intended locking at point 5 and 2 and decelerating [Music] our last task for today is going to be a little code refactoring refactoring is important for both performance and readability of our own code we'll definitely appreciate the small amount of time we take now to refactor in the future when we come back and try to understand our own work we'll start with a refactor we have done in the past we'll declare two int variables velocity z hash and velocity x hash in our start method we'll set each to animator dot string to hash and we'll pass in the string version of the parameter we are using in the setfloat function at the bottom of our update method then we'll replace the string version with the newly defined and set variable next we'll replace each string argument in our input.getkey function with their associated keycode just another small performance different refactor and our last refactor is just for readability if we take a look at our update function it's massive and without the comments above each the code is simply daunting to understand let's extract our blocks of code into two new functions to clean this up the first we create will be called change velocity and we'll pass in each of our local variables we have set at the top of the update function then we'll cut and paste our blocks of code associated with increasing and decreasing our two velocities from the update function and paste them into the new function and we'll do the same for a second function called lock or reset velocity passing in the same parameters and moving the remaining conditional statements from the update function to this new one now we just need to call change velocity and lock a reset velocity in the update function and pass in all of our variables as arguments one last time we'll test this in play mode and we'll see that everything is still working as intended amazing job today in the next video we're going to take a look at how to retarget our animations from our miximo character to our own we'll continue the series based on unity's animation system by learning to make more complex animation state trees we'll also take a look at animation state layers and animation based events i want to take a second to thank everybody for your support this channel has grown a lot faster than i ever expected it to and a lot of that has to do with all of you the positive reception is really what gets me through some of these early morning wake ups and the late nights i spend dedicated to each video so thank you so much for your support i really do appreciate it if you're interested in joining me and a growing community there's now a channel discord the link is in the description we've already had some great conversations and we're really helping each other out when it comes to coding and learning how to use all these animations and as always if you learned something new today or found the video entertaining please consider pressing the like button and subscribing to the channel it helps me out and lets me know that we're headed in the right direction that's all for today thank you for watching and i'll see you in the next video bye
Info
Channel: iHeartGameDev
Views: 52,356
Rating: undefined out of 5
Keywords: How to Animate Characters in Unity 3D | Two Dimensional Blend Trees Explained, blend trees, how to animate characters in unity, how to animate walking in unity, animate in unity, character animations unity, unity character animations, player controlled animations, blend tree tutorial, blend tree unity tutorial, unity blend trees explained, unity two dimensional blend tree, 2 dimensional blend tree, unity 2d blend tree, two dimensional blend tree, 2d blend tree tutorial, nicky b
Id: _J8RPIaO2Lc
Channel Id: undefined
Length: 23min 15sec (1395 seconds)
Published: Sun Aug 23 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.