0
\$\begingroup\$

I'm facing an issue when loading scenes in unity.

My game is composed of full screen levels where players exit to the next level when touching the edges. So, when the player touches an edge I load next level and position the player at the correct position to start traversing the new scene. For example if I'm exiting Level1 from the right side, I load Level2 and I position player on the left.

Player is a "DonDestroyOnLoad" game object.

The problem is that unity seems to only keep last key pressed between scene loads. For example if I walk to the right in level1 and reach the edge of level, second level is loaded and player keeps moving to the right because the key is still pressed. But, If I walk to the right in level1 and jump (while pressing right arrow key) and I touch the edge of the screen, level2 is loaded but the Right key is lost (the first I pressed in level one).

I have found this here at stackexchange -> Why doesn't Unity keep keydown states between scenes, and how can I change that? but it seems very hacky.

\$\endgroup\$
2
  • \$\begingroup\$ Are you using the old or the new input system? If you are using the old one (like the question you linked to), then I wonder if this might be one of the many problems with the old input system which are fixed by the new one. \$\endgroup\$
    – Philipp
    Commented Oct 7, 2021 at 13:53
  • \$\begingroup\$ Old input system. I could try new input system, but I just started with the one I know :). \$\endgroup\$
    – Notbad
    Commented Oct 7, 2021 at 14:12

2 Answers 2

1
\$\begingroup\$

This appears to be a bug wherein even a keyboard polling gameObject loses track of second keypresses across scene loads. One workaround is to keep a minimal main level that keeps track of all the inputs, scores, handles basic mechanics etc, and loads and unloads scenery overlays additively, so those controllers always persist.

Here's a simplistic script that illustrates this:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class KeyPressTest : MonoBehaviour
{
    float timer;
    bool nextSceneLoaded;
    public string nextScene;


    void Update()
    {
        timer += Time.deltaTime;
        if(timer > 2 && !nextSceneLoaded)
        {
            SceneManager.LoadScene(nextScene,LoadSceneMode.Additive);
            nextSceneLoaded = true;
        }
        if (Input.GetKey(KeyCode.A))
        {
            Debug.Log("A " + timer.ToString());
        }
        if (Input.GetKey(KeyCode.S))
        {
            Debug.Log("S " + timer.ToString());
        }
    }
}

Put this in a start scene and provide a second scene name. Hold down the A & S keys and you'll see they continue to both be polled after the second scene loads.

EDIT Note -- editted intro to this answer per @Notbad's clarifying comment below, as after further experimentation it does appear that even if a gameObject is marked as DontDestroyOnload it will lose the second keypress when a new scene is loaded in single mode. To illustrate this, here is the above script modified so the start scene is discarded and only the poller persists. Sure enough, after the second scene loads, only one key will still be polled...

// Doesn't Work! 
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class KeyPressTest : MonoBehaviour
{
    float timer;
    bool nextSceneLoaded;
    public string nextScene;

    private void Start()
    {
        DontDestroyOnLoad(gameObject);
    }


    void Update()
    {
        timer += Time.deltaTime;
        if(timer > 2 && !nextSceneLoaded)
        {
            SceneManager.LoadScene(nextScene,LoadSceneMode.Single);
            nextSceneLoaded = true;
        }
        if (Input.GetKey(KeyCode.A))
        {
            Debug.Log("A " + timer.ToString());
        }
        if (Input.GetKey(KeyCode.S))
        {
            Debug.Log("S " + timer.ToString());
        }
    }
}
```
\$\endgroup\$
4
  • \$\begingroup\$ "You are losing the keyboard input because the script that is tracking it is being destroyed across scene loads" -> How can this be if the script is flagged as Don't Destroy on load? \$\endgroup\$
    – Notbad
    Commented Oct 7, 2021 at 14:09
  • \$\begingroup\$ Ah -- I assumed the keyboard input script wasn't attached to the player gameObject. If that's not the case, I'm not sure why you are getting this, But keeping the player in the main scene that is never destroyed should fix this \$\endgroup\$ Commented Oct 7, 2021 at 14:15
  • \$\begingroup\$ It works, if no more than one key was pressed. It is really odd. If more than one key was pressed, just the last one is remembered as pressed beside first one is still pressed and never was released. \$\endgroup\$
    – Notbad
    Commented Oct 7, 2021 at 14:20
  • \$\begingroup\$ See additional edit made to my post. You are right, a polling gameObject marked as DontDestroyOnload will only continue to poll a single key even if two are pressed across loads. But the solution in the first script does work, and is actually not a bad pattern to use... \$\endgroup\$ Commented Oct 7, 2021 at 14:29
0
\$\begingroup\$

Just for reference I ended doing this in my game controller:

void Start()
{
    DontDestroyOnLoad(gameObject);
}

void OnEnable()
{
    SceneManager.sceneLoaded += OnSceneLoaded;
}

void OnDisable()
{
    SceneManager.sceneLoaded -= OnSceneLoaded;
}

public void MoveToNextScene(string sceneName, ExitType exitType)
{
    _lastExitType = exitType;
    SceneManager.LoadScene(sceneName, LoadSceneMode.Additive);
}



void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
    StartCoroutine(_OnSceneLoaded(scene));
}

// Update is called once per frame
IEnumerator _OnSceneLoaded(Scene scene)
{
    var asyncOperation = SceneManager.UnloadSceneAsync(0);
    while (!asyncOperation.isDone)
        yield return asyncOperation;
    ...
}

Thanks to @Acme Nerd Games instructions. It felt a bit hacky to me but well, it at least works and I can move to other more important subjects.

The only thing that I don't like is that I could end with both screens loaded for a litle period of time and the player could notice it. But it is easy fixable with a quick fade out effect.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .