Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

How can I play a specific animation upon a combination of inputs using the Blend Tree?

Discussion in '2D' started by AssembledVS, Jul 6, 2015.

  1. AssembledVS

    AssembledVS

    Joined:
    Feb 23, 2014
    Posts:
    248
    I asked this question on Unity Answers, but it seems to be waiting for approval for a while.

    I am using a 2D Freeform Cartesian blend type to move my sprite around in a 2D top-down, Zelda-like game. My up, down, left, and right animations are working just fine. But I am having an issue with a specific animation playing upon a combination of inputs. When walking left, and only then up, for example (diagonal northwest), I want the left animation to continue playing instead of the up animation. When walking down, and then right, as another example, I want the down animation to continue playing (basically, the input that was pressed first should have the animation that is associated with it should play).

    Is this possible using the blend tree? I am attempting to do this using a bunch of if statements and counters (if left is pressed, ++, if up is pressed, ++, and if count == 2, trigger that specific animation), which is not all that straight forward or simple, it seems. Is there an easier way using the blend tree?

    Also, I am not using Input.GetButtonDown, etc. because I want this code to be usable by NPCs and other non-controllable characters. I am setting floats as parameters in the blend tree and triggering the animations in this way.
     
  2. DrHeinous

    DrHeinous

    Joined:
    Jun 25, 2013
    Posts:
    19
    So when I came on a similar situation (4 directional sprite animated movement, what happens when you hold down left AND up), I basically just did something like (this is from memory, so pardon any errors). This is a totally simplified example, of course. Basically it favors one direction over another and passes those values to the animation, rather than the raw directional values.


    Code (csharp):
    1.  
    2. //Simple input.  These values could come
    3. //from wherever in principle.
    4. float input_x = Input.GetAxis("Horizontal");
    5. float input_y = Input.GetAxis("Vertical");
    6.  
    7. //we'll save the original values.
    8. //That's what we will use to
    9. //actually move our rigidbody
    10. //or whatever
    11. float orig_input_x = input_x;
    12. float orig_input_y = input_y;
    13.  
    14. //For animation, favor X
    15. //animations over Y.
    16. if (Math.Abs(input_x) != 0)
    17.   input_y = 0;
    18.  
    19. //Set the actual animation values
    20. animator.SetFloat("X", input_x);
    21. animator.SetFloat("Y", input_y)
    22.  
    23.  
    24. //set rigidbody velocity or whatever
    25. //with orig_input_ values
    26. ...
    27.  
     
  3. AssembledVS

    AssembledVS

    Joined:
    Feb 23, 2014
    Posts:
    248
    Thanks for this. I'll take a better look a bit later and see if this can do what I need or give me any more insight.

    However, unless I'm reading it incorrectly, it does not seem like it will solve my most difficult issue: press left, and then up, will play one animation, and press up, and then left, will play another animation. The order matters here and I'm having some difficulty with this.
     
  4. AssembledVS

    AssembledVS

    Joined:
    Feb 23, 2014
    Posts:
    248
    I figured it out.

    DrHeinous, your idea got me going in the right direction. I still needed to use counters to test a specific combination of inputs, like up and then left, and not left and then up, for example.

    If anyone is having trouble with something like this, here are my Update() and FixedUpdate() functions. The code still has to be cleaned up quite a bit, but the logic seems to work:

    Code (CSharp):
    1. // Update ################################################################################### //
    2. void Update()
    3. {
    4.     // movement ============================================================================= //
    5.  
    6.     // get player input and store values as floats
    7.     // default settings from "Edit -> Project Settings -> Input"; already mapped to arrow keys;
    8.     // inputs will be 0, 1, or -1, which determine the direction of movement on a coord
    9.     // plane; no key press is 0, right is 1, left is -1, up is 1, down is -1
    10.     animInputLeftRight = Input.GetAxisRaw("Horizontal");    // 0.0f, 1.0f, or -1.0f
    11.     animInputUpDown = Input.GetAxisRaw("Vertical");         // 0.0f, 1.0f, or -1.0f
    12.  
    13.     // set movement inputs to values of animation inputs; this is done in order to separate
    14.     // animations from movement, as some animations should play regardless of what the
    15.     // movement inputs are
    16.     moveInputLeftRight = animInputLeftRight;
    17.     moveInputUpDown = animInputUpDown;
    18.  
    19.     // define movement as the direction for both axes multiplied by 'playerSpeed'
    20.     playerMovement = new Vector2(moveInputLeftRight * playerSpeed.x,
    21.                                  moveInputUpDown * playerSpeed.y);
    22.  
    23.     // animation ============================================================================ //  
    24.  
    25.     // favoring an animation is only done for up/down animations, as left/right animations are
    26.     // already favored while moving left, then up/down, or right, then up/down; the
    27.     // horizontal animations favored by default because their motions are listed first in
    28.     // the blend tree, and the first motions seem to be always favored by Unity
    29.  
    30.     // up, then left or right --------------------------------------------------------------- //
    31.     // when moving up, then left/right (northwest/northeast), favor up animation
    32.     if (animInputUpDown == 1)
    33.     {
    34.         upLeftRightCounter++;
    35.     }
    36.  
    37.     else
    38.     {
    39.         upLeftRightCounter = 0;
    40.         upLeftRightMotion = false;
    41.     }
    42.  
    43.     if (animInputLeftRight != 0)
    44.     {
    45.         upLeftRightCounter++;
    46.     }
    47.  
    48.     else
    49.     {
    50.         upLeftRightCounter = 0;
    51.         upLeftRightMotion = false;
    52.     }
    53.  
    54.     // if counter = 2, up, then left/right motion is triggered
    55.     if (upLeftRightCounter == 2)
    56.     {
    57.         upLeftRightMotion = true;
    58.     }
    59.  
    60.     // if motion is triggered, set y animation value to up (1)
    61.     if (upLeftRightMotion == true)
    62.     {
    63.         animInputLeftRight = 0;
    64.         animInputUpDown = 1;
    65.     }
    66.  
    67.     // down, then left or right ------------------------------------------------------------- //
    68.     // when moving down, then left/right (southwest/southeast), favor down animation
    69.     if (animInputUpDown == -1)
    70.     {
    71.         downLeftRightCounter++;
    72.     }
    73.  
    74.     else
    75.     {
    76.         downLeftRightCounter = 0;
    77.         downLeftRightMotion = false;
    78.     }
    79.  
    80.     if (animInputLeftRight != 0)
    81.     {
    82.         downLeftRightCounter++;
    83.     }
    84.  
    85.     else
    86.     {
    87.         downLeftRightCounter = 0;
    88.         downLeftRightMotion = false;
    89.     }
    90.  
    91.     // if counter = 2, up, then left/right motion is triggered
    92.     if (downLeftRightCounter == 2)
    93.     {
    94.         downLeftRightMotion = true;
    95.     }
    96.  
    97.     // if motion is triggered, set y animation value to down (-1)
    98.     if (downLeftRightMotion == true)
    99.     {
    100.         animInputLeftRight = 0;
    101.         animInputUpDown = -1;
    102.     }
    103.  
    104.     // trigger animations ------------------------------------------------------------------- //
    105.     // if no inputs are 0, there is movement; set variables to trigger appropriate animations
    106.     if ((moveInputLeftRight != 0) || (moveInputUpDown != 0))
    107.     {
    108.         playerAnimator.SetBool("isWalking", true);
    109.         playerAnimator.SetFloat("inputX", animInputLeftRight);  // will be either 1 or -1
    110.         playerAnimator.SetFloat("inputY", animInputUpDown);     // will be either 1 or -1
    111.     }
    112.  
    113.     // else inputs are 0, so there is no movement, therefore character is not walking
    114.     else
    115.     {
    116.         playerAnimator.SetBool("isWalking", false);
    117.     }
    118. }
    119.  
    120. // FixedUpdate ############################################################################## //
    121. void FixedUpdate()
    122. {
    123.     // set the player obj's rigidbody2D velocity to player movement (direction * speed = vel)
    124.     playerRigidBody.velocity = playerMovement;
    125. }
     
  5. DrHeinous

    DrHeinous

    Joined:
    Jun 25, 2013
    Posts:
    19
    Yup. In my case order didn't matter (basic left-up-right-down 2d game). I only cared about not trying to blend two animations (left/up, for example). Your case is definitely more complicated.
     
  6. StanMihai72

    StanMihai72

    Joined:
    Apr 8, 2015
    Posts:
    6
    Did you think of using a tree-like structure where you have different states based on input?
    For example you have the Left -> Up node, to which you can get from the idle node to left node and then to left -> up node by pressing left and then up.
    Based on this you could have each node update the current state in the Blend tree and control the input.
     
  7. AssembledVS

    AssembledVS

    Joined:
    Feb 23, 2014
    Posts:
    248
    I'm sorry, I don't think that I follow. Are these "nodes" abstract representations in code, or are you referring to the motions in the blend tree?