Search Unity

Application.LoadLevel resets Input.GetAxis - Work arounds?

Discussion in 'Scripting' started by boomcallister, Jan 7, 2012.

  1. boomcallister

    boomcallister

    Joined:
    Nov 19, 2011
    Posts:
    2
    I'm making a continuous Metroidvania-style sidescroller, with a variety of different rooms and corridors, each saved as a different scene. I want the player to be able to transition seamlessly through these rooms - i.e. the run out on one side of the screen, and run back in on another.

    However, whenever I change a scene through Application.LoadLevel(), my input get's completely reset. I'll be holding down the left key - GetAxis() returning a -1 - the next scene will load, and I'll suddenly GetAxis will return 0. It won't start returning normal values, until I release the key and press it again.

    I've experimented around with this, and it looks like the only axis that Input retains between scenes is whatever the last key pressed was. So if I'm only running between scenes it works, fine, but if do a running jump between scenes, by Horizontal axis goes to 0 and all forward movement stops.

    Has anyone seen this before? Does anyone know any work arounds for this?
     
    MaximillianCoburn likes this.
  2. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Wow, didn't know about this thing!

    I'm not sure about the solutions, but I have a couple ideas (though I have no idea if they'd work):
    1. Try LoadLevelAsync instead, maybe it doesn't reset the axis?
    2. Try to understand the exact moment when the axis is reset. Is it when you start loading the level, or when it's loaded? You might find a way to store the axis just a moment before, and the re-apply them the moment later (though this looks messy :p)
     
  3. grolapin

    grolapin

    Joined:
    Oct 1, 2012
    Posts:
    7
    Same issue here... :confused:

    Need help !

    Is there a way to force Input Update ?
     
  4. vitor.franchi

    vitor.franchi

    Joined:
    Jul 12, 2012
    Posts:
    1
    I have the same problem here.

    1. I tested using LoadLevelAsync, it doesn't change anything. Input buttons get reset anyways.
    2. How can I set the axis of an Input button? The problem is that when you switch scenes, the Input doesn't even return the GetKeyUp event. It's like it doesn't know anything about what keys are pressed.

    Does anyone have a solution?
     
  5. MrSteve1

    MrSteve1

    Joined:
    Sep 27, 2012
    Posts:
    11
    It might be a pain in the arse but would Input.GetKeyDown(KeyCode.a) work any better for you? I can only assume you're using WASD rather than Cursor.
     
  6. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,197
    I'm having the same problem here.. @boomcallister have you found a solution?
     
  7. Brian-Kehrer

    Brian-Kehrer

    Joined:
    Nov 7, 2006
    Posts:
    411
    The more robust way is to only use Input.GetKey(KeyCode k), and track up / down yourself. I typically wrap up Unity's Input system in my own classes, entirely - for two reasons.

    1. avoid funny behavior like this, or tabbing in and out and missing up / down events.
    2. allow users to dynamically rebind keys.

    That said, if they are internally calling ResetInputAxes - the documentation says "Resets all input. After ResetInputAxes all axes return to 0 and all buttons return to 0 for one frame."
    In which case, you might be out of luck. I'd file a bug on that.
     
  8. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,197
    Even using Input.GetKey the inputs gets reset... I'm making a game where the player can walk/run and enter and exit rooms, buildings and etc. Then everytime the player is teleported for another level (room, buildings, etc) he stops walking and running.. I think the inputs are getting reset internally like you said.. frustrating =/
     
    Last edited: Apr 15, 2013
  9. Ash-Blue

    Ash-Blue

    Joined:
    Aug 18, 2013
    Posts:
    102
    Working on a game with Castlevania SOTN like level transitions and this is making my life hell. Any ideas on how to fix this? Feels like a bug to me, so I'm surprised there isn't a patch or some sort of workaround for it.
     
  10. Pysassin

    Pysassin

    Joined:
    Dec 27, 2012
    Posts:
    87
    Are you using a player object that have http://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html in them? I'd assume that if your motor functionality were all on the player object with this attached some where via codes that it shouldn't affect it. But I've not really tried it as loading rooms as separate scenes feels/sounds pretty clunky to me.
     
  11. Ash-Blue

    Ash-Blue

    Joined:
    Aug 18, 2013
    Posts:
    102
    Was able to solve the input issue using additive loading and it works great. Here is a test video I threw together of it in action. If anybody has questions on how to get this working just ask and I'll gladly help.

     
    Wichenstaden likes this.
  12. direcalmly

    direcalmly

    Joined:
    Sep 5, 2013
    Posts:
    3
    Confirmed with the additive loading--it worked for my game too.

    Instead of using Application.LoadLevel("whatever") I set up a function that destroys every game object in the scene and then additively loads the level again. Kind of a silly work-around but it allows my player to hold down the "Sprint" axis the whole time instead of having to let go of it every time they die and the level reloads.

    Sample codez0rs:

    Code (CSharp):
    1. public static class LevelManager
    2.  
    3. {
    4.     private static Transform[] allObjects;
    5.  
    6.     public static void Reload()
    7.     {
    8.         //Find & destroy all objects in scene
    9.  
    10.         allObjects = GameObject.FindObjectsOfType(typeof(Transform)) as Transform[];
    11.  
    12.         foreach (Transform t in allObjects)
    13.         {
    14.             GameObject.Destroy (t.gameObject);
    15.         }
    16.  
    17.        
    18.         Application.LoadLevelAdditive (Application.loadedLevel);
    19.  
    20.     }
    21. }
    Works great for my scenario. Surprisingly simple fix too.
     
  13. NoradZero

    NoradZero

    Joined:
    Apr 24, 2014
    Posts:
    95
    Amazing solution! Thanks for this.
     
  14. Xinyu007

    Xinyu007

    Joined:
    Feb 11, 2015
    Posts:
    1
    you can use
    Code (CSharp):
    1.  
    2.         [DllImport("user32.dll")]
    3.         public static extern short GetAsyncKeyState(int vkey);
    instead of Input.GetKey()
    in windows
     
  15. TruffelsAndOranges

    TruffelsAndOranges

    Joined:
    Nov 9, 2014
    Posts:
    92
    Urgh. Don't want to destroy all objects manually... I'm afraid I'll forget something, and my whole hierarchy built with DontDestroyOnLoad doesn't work any more. Any solution when not using Additive load?

    Even worse, the DontDestroyOnLoad flag is not even exposed to the developer.

    A lot of people having problems with this, and some even created their own scene management (from scratch!) just to overcome this problem:
    http://answers.unity3d.com/questions/191228/inputgetaxis-returns-0-after-scene-load.html
    http://answers.unity3d.com/questions/946279/mousebuttondown-not-being-stored-between-scenes.html

    I feel there is some pretty lazy development here, not having fixed this after 2 years.
     
    Last edited: Sep 27, 2015
  16. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,197
    And here I am again 2 years later in a different project requesting that they fix this... :oops:
     
  17. Ash-Blue

    Ash-Blue

    Joined:
    Aug 18, 2013
    Posts:
    102
    Nothing to fix here actually. Think of a level load as a complete refresh of the entire application. It dumps everything in the system and restores it to the original state. You have to use additive level loading if you want to fix it. If you need some help I put together a live training video on how to write some code for this from scratch a few months back.



    If you just want the source code and don't want a tutorial see the GitHub repo here: https://github.com/ashblue/unity-additive-level-loading
     
    Wichenstaden likes this.
  18. aFeesh

    aFeesh

    Joined:
    Feb 12, 2015
    Posts:
    35
    I understand that a level load is considered a complete refresh, but I see my peripheral Input as something outside of Unity that should not be apart of this refresh.

    If someone is holding down the D key to move, then the next level loads and they keep holding it down, they should keep moving. Instead Unity is telling the Input system to make it believe the D key is not held down, when in fact it is. Seems like a bug to me.

    If it stays this way they might want to reconsider changing descriptions in some of their documentation for instance Input.anyKey says: "Is any key or mouse button currently held down?" when it should say: "Is any key or mouse button currently held down since the scene has loaded?"

    Even some kind of high level api call to turn this input refresh feature on/off, would be nice.

    Additive level loading is a solution, but is there any way to do async additive level loading for large scenes? Not too mention Finding All Objects in a scene and then destroying them is a very expensive/resource heavy process.
     
    Rodolfo-Rubens likes this.
  19. Sersh

    Sersh

    Joined:
    Oct 25, 2015
    Posts:
    23
    I also don't get what is the gain of resetting the input between scene loads? There seems to be tons of this kind of threads everywhere on the internet where people are struggling with this issue.

    So people have to come up with workarounds like the additive load and manual destruction of the previous scene and stuff. Why? What is the reason to reset the input, what kind of scenario profits from this decision? I can't think of any. If i call "Input.GetKey()" i want to know if the player is currently physically holding down that button, no matter if the application was restarted/tabbed out/reloaded whatever.

    Edit. Also the Additive load "solution" seems to fill my hierarchy up with obsolete scene objects?
     
    Last edited: Jul 23, 2017
    Sharkbird likes this.
  20. isckjr

    isckjr

    Joined:
    Jun 27, 2017
    Posts:
    1
    Thanks! This works like a charm.
    Here's my (simplified) code if anyone's looking to see how that works:

    Code (CSharp):
    1.  
    2. using System.Runtime.InteropServices;
    3.  
    4. public class test : MonoBehavior {
    5.  
    6.     [DllImport("user32.dll")]
    7.     public static extern short GetAsyncKeyState(int vkey);
    8.  
    9.     public const int LEFT_ARROW_KEY = 0x25;
    10.     public const int RIGHT_ARROW_KEY = 0x27;
    11.  
    12.     if ((GetAsyncKeyState(LEFT_ARROW_KEY) & 0x8000) > 0) {
    13.             // move left
    14.     } else if ((GetAsyncKeyState(RIGHT_ARROW_KEY) & 0x8000) > 0) {
    15.             // move right
    16.     }
    17. }
    18.  
     
  21. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,619
    If you think you found a bug in Unity, I recommend to submit a bug-report following the advice in this document.

    Using the bug-reporter seems to be an important step, because it makes sure the report is in Unity Technologies bug-tracking pipeline and has to be processed at some point. Using the forum is often used to add to a little more attention to a bug-report, but does not replace submitting the bug-report.

    It's from advantage to attach a project to the bug-report that UT can use to reproduce the issue and test their fix against. The easier an issue can be reproduced by QA, the more likely it is to get forwarded to a developer, who might or might not work on a bug-fix for that at some point.

    After you submitted the bug-report, you receive a confirmation email with a Case number. UT often asks us to post the Case number in the forum thread, which allows them to find that bug-report if they look at your post.

    Following these steps will increase the chance that UT is looking at your issue tremendously.
     
  22. Shadoninja

    Shadoninja

    Joined:
    Nov 12, 2013
    Posts:
    26
    Yikes I am here in 2018 to find that this has been complained about for over 6 years with no fix. That stings a little.
    @Time_Flys sums it up best. The state of my keyboard and controllers are independent of the Unity. This behavior should be classified as a bug and fixed. I am really disappointed to see the community talk about this for over half a decade and get no help from the Unity devs.
     
    Slyfincleton, MUGIK, Globotix and 2 others like this.
  23. erichope

    erichope

    Joined:
    Dec 12, 2012
    Posts:
    4
    Far more than 6 years. I keep hoping they'll fix it, but as of the latest today, they haven't. I threw together an example project with this script that demonstrates it, wrote up a bug, and pointed them back at this thread for context. Fingers crossed. Not holding my breath :/
     

    Attached Files:

  24. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Is it a bug? Arguably. Will it be fixed? Probably not.

    Instead, engineer thyself a trivial workaround and get back to game-making!

    The work-around:

    - Load your next scene additively
    - When it finishes loading, unload the previous scene

    Note now the
    Input
    axes do not reset when you do this.

    Thank you, drive through!

    I threw together an example project to prove this workaround.

    Read directions in
    Scene1.unity
    for setup: you need to add
    Scene1
    and
    Scene2
    and
    Scene3
    to your Editor Build Settings.

    EDIT: Tested and works in Unity5.6.6 and Unity2021.1.0.

    EDIT: Package updated to isolate the meat and potato script, which also now included right here:

    Code (csharp):
    1. using UnityEngine;
    2. using UnityEngine.SceneManagement;
    3.  
    4. public static partial class SceneHelper
    5. {
    6.     // @kurtdekker - to load next scene without resetting Input axes
    7.     public static void LoadScene( string SceneNameToLoad)
    8.     {
    9.         PendingPreviousScene = SceneManager.GetActiveScene().name;
    10.         SceneManager.sceneLoaded += ActivatorAndUnloader;
    11.         SceneManager.LoadScene( SceneNameToLoad, LoadSceneMode.Additive);
    12.     }
    13.  
    14.     static string PendingPreviousScene;
    15.     static void ActivatorAndUnloader( Scene scene, LoadSceneMode mode)
    16.     {
    17.         SceneManager.sceneLoaded -= ActivatorAndUnloader;
    18.         SceneManager.SetActiveScene( scene);
    19.         SceneManager.UnloadSceneAsync( PendingPreviousScene);
    20.     }
    21. }
     

    Attached Files:

    Last edited: Apr 3, 2021
  25. nannings

    nannings

    Joined:
    Sep 5, 2016
    Posts:
    4
    This works but some of the references of components are missing after a scene change using this way of loading...
     
  26. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    This has nothing to do with the above way of loading and everything to do with a mismatch in your design between the lifecycles of GameObjects that reference each other. Fix that first.
     
  27. SpeedyYT2499

    SpeedyYT2499

    Joined:
    Apr 23, 2023
    Posts:
    1
    Ok so i know its been so long and probably no one cares now, but i would like to know how this works to better understand it, thanks in advance :)