Search Unity

Question Animation Bug when Switching Weapons while reloading.

Discussion in 'Scripting' started by Wunderzorro, May 2, 2022.

  1. Wunderzorro

    Wunderzorro

    Joined:
    Feb 1, 2021
    Posts:
    3
    Hello.

    I'm making an fps game and I'd Like to showcase an issue I'm having where whenever I switch weapons, the pistol is in the exact position as the frame of the reload animation where I switched weapons on.

    I need to know how to fix the issue and make the pistol in the normal position when I switch while reloading.

    (Video of the problem)


    Animation Code:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class M1911Master : MonoBehaviour
    6. {
    7.     public Animator anim;
    8.     public bool isReloading;
    9.     public bool isSwitching;
    10.  
    11.     M1911Reload reload;
    12.  
    13.  
    14.     void Start()
    15.     {
    16.         reload = this.GetComponent<M1911Reload>();
    17.         anim = this.GetComponent<Animator>();
    18.     }
    19.  
    20.     void Update()
    21.     {
    22.         if (!Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.LeftShift))
    23.         {
    24.             anim.SetBool("isIdle", true);
    25.         }
    26.         if (Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.LeftShift))
    27.         {
    28.             anim.SetBool("isIdle", false);
    29.             StartCoroutine(wait());
    30.         }
    31.         else
    32.         {
    33.             anim.SetBool("isWalking", false);
    34.             // StopAllCoroutines();
    35.         }
    36.         if (Input.GetKey(KeyCode.LeftShift))
    37.         {
    38.             if (Input.GetKey(KeyCode.W))
    39.             {
    40.                 anim.SetBool("isIdle", false);
    41.                 StartCoroutine(waitRun());
    42.             }
    43.  
    44.         }
    45.         else
    46.         {
    47.             anim.SetBool("isRunning", false);
    48.             //StopAllCoroutines();
    49.         }
    50.  
    51.  
    52.         if (reload.Reloading == true)
    53.         {
    54.             isReloading = true;
    55.  
    56.             anim.SetBool("Reload", true);
    57.         }
    58.         else
    59.         {
    60.             isReloading = false;
    61.             anim.SetBool("Reload", false);
    62.  
    63.         }
    64.  
    65.     }
    66.  
    67.     private void OnEnable()
    68.     {
    69.         isReloading = false;
    70.     }
    71.  
    72.     private void OnDisable()
    73.     {
    74.      
    75.     }
    76.  
    77.     IEnumerator wait()
    78.     {
    79.         yield return new WaitForSeconds(.1f);
    80.         if (Input.GetKey(KeyCode.W))
    81.         {
    82.             anim.SetBool("isWalking", true);
    83.         }
    84.     }
    85.     IEnumerator waitRun()
    86.     {
    87.         yield return new WaitForSeconds(.1f);
    88.  
    89.         anim.SetBool("isRunning", true);
    90.  
    91.     }
    92.  
    93. Reloading Code:
    94.  
    95. }
    Code (CSharp):
    1. public class M1911Reload : MonoBehaviour
    2. {
    3.     public int CurrentMag = 10;
    4.     public bool Reloading;
    5.     public M1911Master m1911master;
    6.  
    7.  
    8.  
    9.     // Start is called before the first frame update
    10.     void Start()
    11.     {
    12.  
    13.         Reloading = false;
    14.  
    15.  
    16.  
    17.         m1911master = this.GetComponent<M1911Master>();
    18.  
    19.  
    20.  
    21.  
    22.     }
    23.  
    24.     // Update is called once per frame
    25.     void Update()
    26.     {
    27.         if (CurrentMag > 10)
    28.         {
    29.             CurrentMag = 10;
    30.         }
    31.  
    32.  
    33.         if (Input.GetKeyDown(KeyCode.R) && !Reloading)
    34.         {
    35.             if (CurrentMag < 10)
    36.             {
    37.  
    38.                 Reloading = true;
    39.                 Reload();
    40.             }
    41.         }
    42.  
    43.     }
    44.  
    45.     public void Reload()
    46.     {
    47.  
    48.         if (Reloading == false)
    49.         {
    50.  
    51.         }
    52.  
    53.  
    54.     }
    55.  
    56.     private void OnEnable()
    57.     {
    58.         Reloading = false;
    59.     }
    60.  
    61.     public void fillAmmo()
    62.     {
    63.  
    64.         CurrentMag += 10;
    65.         Reloading = false;
    66.         m1911master.isReloading = false;
    67.  
    68.     }
    69.  
    70. }
    Weapon Switching Code:

    Code (CSharp):
    1. public class WeaponSwitch : MonoBehaviour
    2. {
    3.     public int selectedWeapon = 0;
    4.  
    5.     // Start is called before the first frame update
    6.     void Start()
    7.     {
    8.         SelectWeapon();
    9.     }
    10.  
    11.     // Update is called once per frame
    12.     void Update()
    13.     {
    14.      
    15.             int previousSelectedWeapon = selectedWeapon;
    16.  
    17.             if (Input.GetAxis("Mouse ScrollWheel") > 0f)
    18.             {
    19.                 if (selectedWeapon >= transform.childCount - 1)
    20.                     selectedWeapon = 0;
    21.                 else
    22.                     selectedWeapon++;
    23.             }
    24.             if (Input.GetAxis("Mouse ScrollWheel") < 0f)
    25.             {
    26.                 if (selectedWeapon <= 0)
    27.                     selectedWeapon = transform.childCount - 1;
    28.                 else
    29.                     selectedWeapon--;
    30.             }
    31.  
    32.             if (previousSelectedWeapon != selectedWeapon)
    33.             {
    34.                 SelectWeapon();
    35.             }
    36.         }
    37.  
    38.         void SelectWeapon()
    39.         {
    40.             int i = 0;
    41.             foreach (Transform weapon in transform)
    42.             {
    43.                 if (i == selectedWeapon)
    44.                     weapon.gameObject.SetActive(true);
    45.                 else
    46.                     weapon.gameObject.SetActive(false);
    47.                 i++;
    48.             }
    49.         }
    50.     }
    Hopefully with the code I provided you guys can find a solution, I've been looking everywhere for one and I'm struggling quite badly. (Image of my Animator Controller)
     
  2. Wunderzorro

    Wunderzorro

    Joined:
    Feb 1, 2021
    Posts:
    3
    Image of my animator controller
     
  3. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    602
    You probably hit the issue of Unity overwriting "default" animation property values each time object gets enabled. Thus if you disable object while animation is playing, and all animations don't have all the changing properties set, enabling it will break the object making it look like it's stuck.
    People have been complaining about it for years, but Unity response is that "it is by design".

    None of the workarounds I know are very good or universally applicable:
    * create new animated object each time -> not good for performance
    * in all animations set the values for all properties which you change in any of animations even when current animation leaves it at default state. This is quickly gets unmanageable outside very simple cases. When you decide to change default state you have to update all the animations.
    * reset animation state before disabling it, so that when it gets enabled back default values get reinitialized with correct values
    * never disable objects only hide them -> not practical in many cases
    * there are some scripts where people try to save all the default animated property values -> no idea how reliable they are
    * `keepAnimatorControllerStateOnDisable` property, if I am not mistaken it will keep all of animator state including statemachine not just the default values. Sometimes you might want that, but often resuming the animation from last position is undesirable. If your state machine isn't rock solid there is also risk of getting stuck in unexpected state or playing animation you didn't expect.
     
  4. Wunderzorro

    Wunderzorro

    Joined:
    Feb 1, 2021
    Posts:
    3
    All the animations have "write defaults" disabled.

    Either the reset animation state before disabling it option or the keepAnimatorControllerStateOnDisable option sound good to me, although I don't know what to exactly do when it comes to those options.
     
  5. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    602
    If you are not using "write defaults" then the problem I mentioned before doesn't apply to you. And doing reload after switching back to gun should fix the visuals, which it seems you are demonstrating at the end of video. In the the case I was describing before gun would be stuck in the broken state forever (or until you switch again) and doing additional reloads wouldn't fix it.

    Since you are not using "write defaults" setting, resetting state to defaults before disabling object might be a bit more trickier. I haven't tested which strategies work in this case. With "write defaults" enabled I think I tried calling 'Play("default_state_name")' and `WriteDefaultValues()`. Playing default state won't help if it doesn't animate all properties and you aren't using "writeDefaults". No idea if "WriteDefaultValues()" work when you aren't using write defaults setting, it still might since write defaults can be changed for each state separately.

    keepAnimatorControllerStateOnDisable would probably still work in your case. You can enable it either using script or by enabling debug mode in inspector to show hidden properties and set it there.

    Next problem that you will likely have to deal with is how you track that reload is in progress and you can't shoot yet. There are both technical challenges and gameplay questions that need to be answered. The way you handle this will interact with the way you handle interruption of reload animation. Some combinations will work better or worse.
     
  6. guluerechan

    guluerechan

    Joined:
    Mar 24, 2022
    Posts:
    9
    You will likely have to manually put a point to reset the weapon animation before you switch to it.