Search Unity

Resolved Animation blending logic

Discussion in 'Scripting' started by polgi12, May 28, 2023.

  1. polgi12

    polgi12

    Joined:
    Mar 29, 2023
    Posts:
    11
    Hello. I'm making a 3D isometric game. Movement and look direction were determined by WASD keys, so I only needed a standard forward running animation so far. However, recently I added an ability where the player's look direction faces the mouse position on the screen when RMB is held, in order to aim in that direction. This requires 3 additional running animations, backwards, left strafe and right strafe.

    So, I made a blend tree to include all 4 animations. It is clear as day to me how this is supposed to function, but I can't for the life of me figure out what exactly I'm doing wrong. Here's the relevant code for blending between the 4 animations:


    Code (CSharp):
    1. private void Move()
    2.     {
    3.         if (Input.GetMouseButton(1))
    4.         {
    5.             anim.SetBool("Running", false);
    6.             anim.SetBool("Blending", true);
    7.             // Get the mouse position on the screen
    8.             Vector2 mousePos = Input.mousePosition;
    9.  
    10.             // Get the screen width and height
    11.             float screenWidth = Screen.width;
    12.             float screenHeight = Screen.height;
    13.  
    14.             // Determine which part the mouse is in
    15.             int part;
    16.             if (mousePos.x + mousePos.y < screenWidth && mousePos.x - mousePos.y > 0) part = 1; // Top
    17.             else if (mousePos.x + mousePos.y > screenWidth && mousePos.x - mousePos.y > 0) part = 2; // Right
    18.             else if (mousePos.x + mousePos.y > screenWidth && mousePos.x - mousePos.y < 0) part = 3; // Bottom
    19.             else part = 4; // Left
    20.  
    21.             // Set the moveX and moveY parameters based on the part and the input direction
    22.             switch (part)
    23.             {
    24.                 case 1: // Top
    25.                     anim.SetFloat("moveX", _input.x); // Left -> Left strafe, Right -> Right strafe
    26.                     anim.SetFloat("moveY", _input.z); // Forward -> Forward, Backward -> Backward
    27.                     break;
    28.                 case 2: // Right
    29.                     anim.SetFloat("moveX", _input.x); // Left -> Backward, Right -> Forward
    30.                     anim.SetFloat("moveY", _input.z); // Forward -> Left strafe, Backward -> Right strafe
    31.                     break;
    32.                 case 3: // Bottom
    33.                     anim.SetFloat("moveX", -_input.x); // Left -> Right strafe, Right -> Left strafe
    34.                     anim.SetFloat("moveY", -_input.z); // Forward -> Backward, Backward -> Forward
    35.                     break;
    36.                case 4: // Left
    37.                     anim.SetFloat("moveX", -_input.x); // Left -> Forward, Right -> Backward
    38.                     anim.SetFloat("moveY", _input.z); // Forward -> Right strafe, Backward -> Left strafe
    39.                     break;
    40.             }
    41.         }
    42.         else
    43.         {
    44.             anim.SetBool("Blending", false);
    45.             anim.SetBool("Running", true);
    46.         }
    47.         Vector3 movementDirection = new Vector3(_input.x, 0f, _input.z).normalized.ToIso();
    48.         _rb.MovePosition(transform.position + movementDirection * _speed * Time.deltaTime);
    49.     }
    So, the screen is split into 4 parts, and the mouse position in the game is supposed to alter which animation plays when one of the movement keys is held(WASD). The code works when the mouse is in the top part of the screen, but anywhere else and it all turns to mush. I cannot figure out what I'm doing wrong in the switch statement so that the moveX/moveY parameters aren't changing correctly.

    https://prnt.sc/igc2zd2sBBfJ
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,687
    Did you check the actual blend tree as good first?

    To debug the blend tree, disable the script and run, the wiggle the input in the editor to make sure that's set up properly.

    Once you get the blend tree absolutely positively correct, then it is...

    Time to start debugging! Here is how you can begin your exciting new debugging adventures:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the names of the GameObjects or Components involved?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    "When in doubt, print it out!(tm)" - Kurt Dekker (and many others)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.
     
  3. polgi12

    polgi12

    Joined:
    Mar 29, 2023
    Posts:
    11
    I'm not gonna lie, I came here hoping someone would spot the error in my code, correct me, and I'd be on my merry way, so I was kinda let down when I saw the generic post...

    BUT THEN... I decided to take what I can get and apply your comment to my problem, and lo and behold, all it took was adding a few Debug.Logs to figure out my case determining logic was flawed:

    Code (CSharp):
    1.  int part;
    2.             if (angle < 45) part = 1; // Top
    3.             else if (angle > 135) part = 3; // Bottom
    4.             else if (playerToMouse.x > 0) part = 2; // Right
    5.             else part = 4; // Left
    6.  
    7.             // Set the moveX and moveY parameters based on the part and the input direction
    8.             switch (part)
    9.             {
    10.                 case 1: // Top
    11.                     anim.SetFloat("moveX", _input.x); // Left -> Left strafe, Right -> Right strafe
    12.                     anim.SetFloat("moveY", _input.z); // Forward -> Forward, Backward -> Backward
    13.                     Debug.Log("Case 1");
    14.                     break;
    15.                 case 2: // Right
    16.                     anim.SetFloat("moveX", -_input.z); // Left -> Backward, Right -> Forward
    17.                     anim.SetFloat("moveY", _input.x); // Forward -> Left strafe, Backward -> Right strafe
    18.                     Debug.Log("Case 2");
    19.  
    20.                     break;
    21.                 case 3: // Bottom
    22.                     anim.SetFloat("moveX", -_input.x); // Left -> Right strafe, Right -> Left strafe
    23.                     anim.SetFloat("moveY", -_input.z); // Forward -> Backward, Backward -> Forward
    24.                     Debug.Log("Case 3");
    25.  
    26.                     break;
    27.                 case 4: // Left
    28.                     anim.SetFloat("moveX", _input.z); // Left -> Forward, Right -> Backward
    29.                     anim.SetFloat("moveY", -_input.x); // Forward -> Right strafe, Backward -> Left strafe
    30.                     Debug.Log("Case 4");
    31.  
    32.                     break;
    33.             }
    I dread the next time I benefit from you directly answering me (because that means I've been stuck on a problem far too long), but, I'd like to use this opportunity to thank you for doing the Lord's work on these forums, by providing us newbies with all the necessary information to figure out and solve the problem by ourselves, because that feeling cannot compare to getting the answer served on a platter. Changing the flair to resolved.

    THANK YOU!!!
     
    orionsyndrome likes this.
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,687
    Wow, thanks.

    You nailed it: I want to offer everybody the universal hints they need to find the problems themselves.

    It's the whole "give a man a fish" or "teach a man to fish" decision.

    And most problems like this are all about just chopping the problem up into smaller and smaller pieces until you find the one tiny rotten chunk and fix it. The extra challenge comes when there are more than one rotten pieces and you only find one, not the other. :)
     
    Last edited: May 28, 2023
    orionsyndrome and polgi12 like this.