0

After closing the game and reopening it, I want to load the last scene, so the player can continue from the level he reached. I've tried using PlayerPrefs as you see in the code bellow, but the game crash on startup.

GameManager Script:

    bool GameHasEnded = false;
    public float RestartDelay = 2f;
    public float NextLevelDelay = 5f;

    int level_index;

    private void Start()
    {

        level_index = PlayerPrefs.GetInt("Last_Level");
        SceneManager.LoadScene(level_index);


    }

    public void CompleteLevel()
    {
        Invoke("NextLevel", NextLevelDelay);
        level_index = level_index++;
        PlayerPrefs.SetInt("Last_Level", level_index);
    }

    public void EndGame()
    {
        if (GameHasEnded == false)
        {
            GameHasEnded = true;
            Invoke("Restart", RestartDelay);
        }
    }

    void NextLevel()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex +1);
    }

    void Restart()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().path);
    }
}

All scenes are linked with GameManager, they all have the same code that load the next scene:

FindObjectOfType<GameManager>().CompleteLevel();
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
Taik
  • 265
  • 9
  • 28

1 Answers1

0

You need to specify a defaultValue for GetInt so that the first time it starts up, it can pick the appropriate scene to start at.

Also, you need to track whether or not you have already loaded at scene start, and only do this load if it hasn't yet happened. GameManager seems like it should be made into a singleton but since it's not, you can just make this loaded flag static, so that is common among all GameManager instances.

Altogether, this might look like this:

public readonly int defaultLastLevel = 1; // Set as appropriate
private static bool loaded = false;

void Start()
{
    if (!loaded) {
        loaded = true;
        level_index = PlayerPrefs.GetInt("Last_Level", defaultLastLevel);
        SceneManager.LoadScene(level_index);
    }
}

Also, your CompleteLevel has some very strange code where you post-increment and assign in the same line:

level_index = level_index++;

This is extremely hard to read and actually doesn't do what you want it to do. You can do level_index = SceneManager.GetActiveScene().buildIndex + 1; instead.

Also, you need to Save changes you make to PlayerPrefs with PlayerPrefs.Save();

Altogether, this makes your CompleteLevel look like this:

public void CompleteLevel()
{
    Invoke("NextLevel", NextLevelDelay);
    level_index = SceneManager.GetActiveScene().buildIndex + 1; // use this instead
    PlayerPrefs.SetInt("Last_Level", level_index);
    PlayerPrefs.Save();
}
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
  • That didn't work for me, the game start but nothing was working – Taik Dec 31 '18 at 18:45
  • @Taik Please be more descriptive than "nothing was working." Did the wrong scene load? Did it reformat your hard drive? There is no way for us to know. – Ruzihm Dec 31 '18 at 18:47
  • The first scene was loaded but it's paused, so I can't play or do anything – Taik Dec 31 '18 at 18:51
  • @Taik That sounds like a completely separate problem now. Did your code work with `LoadScene` **before** you tried using `PlayerPrefs`? – Ruzihm Dec 31 '18 at 19:02
  • It was working perfectly when there was nothing on the Start method – Taik Dec 31 '18 at 19:05
  • @Taik It seems like you have one instance of `GameManagement` in each scene, so you need to make sure it doesn't re-try to load the scene perpetually. I added a `loaded` flag to my answer that should prevent this. – Ruzihm Dec 31 '18 at 19:20
  • Now the game work fine but after closing and reopening, the last scene didn't load, it start from the first scene again – Taik Dec 31 '18 at 19:32
  • @Taik I found a bug in your `CompleteLevel` method. Check my answer for a fix. – Ruzihm Dec 31 '18 at 19:44
  • It work only with the second scene, I mean for example when closing after reaching the scene 5, on the next start the scene 2 was loaded instead of scene 5. – Taik Dec 31 '18 at 19:58
  • @Taik There is not enough information to determine why. Please [edit your question](https://stackoverflow.com/posts/53990274/edit) or [ask a new question](https://stackoverflow.com/questions/ask) and include the code that detects when scene 4 is complete and calls the code that transitions to scene 5. – Ruzihm Dec 31 '18 at 20:02
  • All scenes are linked with GameManager Script (this one), they all have the same code that load the next scene ( I mean this code: FindObjectOfType().CompleteLevel();) – Taik Dec 31 '18 at 20:09
  • @Taik In that case it sounds like you never call `PlayerPrefs.Save();`, so depending on how you quit your application, it may never save. I have added that to my answer in `CompleteLevel`. If that does not fix the problem, can you add a breakpoint on the `PlayerPrefs.SetInt` line and share the value of `level_index` each time the breakpoint is hit? – Ruzihm Dec 31 '18 at 20:16
  • that didn't work, sorry but I don't know how to do breakpoint – Taik Dec 31 '18 at 20:51
  • In that case, add a `Debug.Log("level_index: " + level_index);` before the `PlayerPrefs.SetInt` line and tell me what it prints out each time it logs. – Ruzihm Dec 31 '18 at 21:59
  • when moving from scene to the next one I got the same message: "level_index: 1 UnityEngine.Debug:Log(Object) GameManager:NextLevel() (at Assets/Script/GameManager.cs:45)" – Taik Jan 01 '19 at 11:35
  • I found the solution, it's a little a bit different, I used "level_index = PlayerPrefs.GetInt("Last_Level");" instead of "level_index = PlayerPrefs.GetInt("Last_Level", defaultLastLevel);", and "level_index = SceneManager.GetActiveScene().buildIndex + 1;" instead of "level_index += 1;" – Taik Jan 01 '19 at 12:27
  • @Taik you still need to use `defaultLastLevel` or it won't work for someone who has never played before. I put the second part in my answer. – Ruzihm Jan 01 '19 at 16:57