Level System

Hello, I need help for my game. I guess all of you know games, if the player completes a level and he goes back to menu and press play he plays the next level and not the level which he has completed. I wanna make these system but I don’t know how. So I hope here is someone who can help me.

Here is my Player script:

using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using UnityEngine;
using TMPro;
using UnityStandardAssets.CrossPlatformInput;

public class Player : MonoBehaviour
{
    [SerializeField] SpriteRenderer playerImage;
    [SerializeField] TMP_Text playerNameText;
    [SerializeField] ParticleSystem konfettiFx;

    public float speed = 1f;

    Rigidbody2D rb;
    bool isMoving = false;
    float x, y;
    public GameObject completeLevelUI;




    void Start()
    {
        rb = GetComponent<Rigidbody2D> ();

        ChangePlayerSkin();
    }

    void ChangePlayerSkin()
    {
        Character character = GameDataManager.GetSelectedCharacter();
        if (character.image != null)
        {
            playerImage.sprite = character.image;
            playerNameText.text = character.name;

        }
    }

   
    void Update()
    {
        x = CrossPlatformInputManager.GetAxis("Horizontal");
        y = CrossPlatformInputManager.GetAxis("Vertical");

        isMoving = (x != 0f || y != 0f);
    }

    void FixedUpdate()
    {
        if (isMoving)
        {
            rb.position += new Vector2(x, y) * speed * Time.fixedDeltaTime;
           


        }
    }

    void OnCollisionEnter2D (Collision2D other)
    {
        string tag = other.collider.tag;

        if (tag.Equals ("Coins"))
        {
            GameDataManager.AddCoins(25);

            GameSharedUI.Instance.UpdateCoinsUIText();

            Destroy(other.gameObject);
        }

        if (tag.Equals("finish"))
        {
            completeLevelUI.SetActive(true);
            konfettiFx.Play();
        }
    }

   


}

and here is my SceneController script

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

public static class SceneController
{
    static int mainScene = 0;
    static int sceneToContinue;
   

    public static void LoadMainScene ()
    {
        SceneManager.LoadScene(0);
    }

    public static void LoadNextScene ()
    {
        int currentScene = SceneManager.GetActiveScene().buildIndex;
        if (currentScene < SceneManager.sceneCountInBuildSettings)
            SceneManager.LoadScene(currentScene + 1);
    }

    public static void LoadPreviousScene()
    {
        int currentScene = SceneManager.GetActiveScene().buildIndex;
        if (currentScene > 0)
            SceneManager.LoadScene(currentScene - 1);
    }

    public static void LoadScene(int index)
    {

        if (index >= 0 && index < SceneManager.sceneCountInBuildSettings)
            SceneManager.LoadScene(index);
    }

   
}

On level completion, save the index of that scene as the lastCompletedLevel.
Then when pressing Play simply LoadScene(lastCompletedLevel++)

1 Like

Thanks and how i do it?

like this?

public static void lastCompletedLevel()
    {
        int lastCompletedLevel = SceneManager.GetActiveScene().buildIndex;
        if (lastCompletedLevel < 0)
            SceneManager.LoadScene(lastCompletedLevel++);
    }

I dont know why you check for it to be smaller than zero. Just leave that check out. That’s it basically, yes. Just implement a way to set this variable when completing a level (for example by saving it to PlayerPrefs, or making it public static and thus globally accessible), and then get the value when you call that function.

1 Like

And and how should I do that “for example by saving it to PlayerPrefs, or making it public static and thus globally accessible, and then get the value when you call that function.”

Your SceneController is already static, and since the variable has to do with level loading anyways, it would make sense to just add it there. Then set it to the current scene buildIndex whenever you completed a level. If you want this information to persist between sessions (not just scenes) you will have to use PlayerPrefs or any other way or writing information to the drive.

public static int lastCompletedLevel;
1 Like

Hello again but how do I save it to the player prefs i’m a bloody beginner sorry for annoying you

You are not annoying me. And everybody was a beginner at one point. Asking questions is what a forum is for. You will find a lot of information with a simple google search tho, especially on super commonly used things such as Unity PlayerPrefs. Just searching for these two words directly turns up the documentation as the first result:

There we see that PlayerPrefs comes with a hand full of methods. Mostly one for getting and setting of a couple different data types. Which type are we interrested in? Since you intend to save a scene index, that would be the integer methods, so SetInt and GetInt. Clicking on those in the documentation turns up further explanations and even some examples:

As you can see there, you can set (“save”) an int value to PlayerPrefs by simply writing PlayerPrefs.SetInt(“someName”, someIntValue);. You can then later load this value using PlayerPrefs.GetInt(“someName”).

So when would you do this? You’d save the value once you complete a level. And you’d get the value once you need it to calculate the index of the following scene (which would be that value plus one). So basically when you press the Play button in your main menu, according to your own explanation for what this will be used for.

Hope this helps, if you have any more questions let me know. Also i hope this gives you an idea for how to look for information yourself, which is a highly important skill you need to learn if you want to programm :slight_smile:

1 Like

I really appreciate your tips, but I’m still not sure how to set it up in my scripts and does this script make sense or do I have to add something?

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

public static class SceneController
{
    static int mainScene = 0;
    static int sceneToContinue;
    static int lastCompletedLevel;




    public static void start ()
    {
        PlayerPrefs.SetInt("lastcompleteLevel", lastCompletedLevel);
    }

    public static void LoadMainScene ()
    {
        SceneManager.LoadScene(0);
    }

    public static void LoadNextScene ()
    {
        int currentScene = SceneManager.GetActiveScene().buildIndex;
        if (currentScene < SceneManager.sceneCountInBuildSettings)
            SceneManager.LoadScene(currentScene + 1);
    }

    public static void LoadPreviousScene()
    {
        int currentScene = SceneManager.GetActiveScene().buildIndex;
        if (currentScene > 0)
            SceneManager.LoadScene(currentScene - 1);
    }

    public static void LoadScene(int index)
    {

        if (index >= 0 && index < SceneManager.sceneCountInBuildSettings)
            SceneManager.LoadScene(index);
    }

  
}

I assume ‘start()’ is supposed to be called when you press Play? As i wrote in my last comment, that is where you would Get a previously saved value. You Set the value on level completion, in your other script. In order to load the next level scene you would also need to add a SceneManager.LoadScene(lastCompletedLevel+1) into the method. Also ‘start’ may be a bad name since it could be confused with Unitys’ own Start method.

I’m leaning a bit out of the window here, but am i right in the assumption that these are not self-written scripts? If you found them online and just want to adjust them that’s fine too, but i would strongly recommend you to take a look at good beginner tutorials and get a general understanding of programming in Unity + C# before being stuck at every little change. You wont ever find exactly the script you need online, and will always be required to do little changes to adjust them, at the very least.

1 Like

The “LoadNextScene()” is called when I press the play button. Now I made it like this:

This is my Player Script

void OnCollisionEnter2D (Collision2D other)
    {
        string tag = other.collider.tag;

        if (tag.Equals ("Coins"))
        {
            GameDataManager.AddCoins(25);

            GameSharedUI.Instance.UpdateCoinsUIText();

            Destroy(other.gameObject);
        }

        if (tag.Equals("finish"))
        {
            completeLevelUI.SetActive(true);
            konfettiFx.Play();
            PlayerPrefs.SetInt("lastcompleteLevel", lastCompletedLevel);
        }
    }

and this is my scenecontroller script where I load the next scene

public static void LoadNextScene ()
    {
        int currentScene = SceneManager.GetActiveScene().buildIndex;
        if (currentScene < SceneManager.sceneCountInBuildSettings)
            SceneManager.LoadScene(currentScene + 1);
        PlayerPrefs.GetInt("lastcompleteLevel", lastCompletedLevel);
        SceneManager.LoadScene(lastCompletedLevel + 1);
    }

But I guess it would be better if I do 2 seperate functions for “start” and “nextlevel” or?

Yes you should create two methods, as LoadNextScene implies by name to load currentScene+1. What you want would be harder to indicate by a small method name, but just calling it Play should be fine aswell, if that’s what’s supposed to happen when you press Play.
Also, currently you have two LoadScene in one method. I’m not exactly sure what the engine even does in this case, but i imagine it will try to load one scene, then the other, which is simply a waste of ressources.

1 Like

Now I did it like this:

public static void StartGame()
    {

        PlayerPrefs.GetInt("lastcompleteLevel", lastCompletedLevel);
        SceneManager.LoadScene(lastCompletedLevel + 1);
    }

But after I played a level and go back to main menu and press play the same level loads again instead of the next one.

Do you set lastcompletelevel in PlayerPrefs after completing a level? I assume not if the loaded level does not change.

1 Like

I did it like this, do I need a method for it? If yes I really don’t know how to do it.

Player Script:

 void OnCollisionEnter2D (Collision2D other)
    {
        string tag = other.collider.tag;

        if (tag.Equals ("Coins"))
        {
            GameDataManager.AddCoins(25);

            GameSharedUI.Instance.UpdateCoinsUIText();

            Destroy(other.gameObject);
        }

        if (tag.Equals("finish"))
        {
            completeLevelUI.SetActive(true);
            konfettiFx.Play();
            PlayerPrefs.SetInt("lastcompleteLevel", lastCompletedLevel);
        }
    }

There are two problems with what you wrote. Your first mistake is here actually. You need to assign the loaded value to something. Which is also shown in the documentation, and the examples i linked you. So change your GetInt part to this:

lastCompletedLevel = PlayerPrefs.GetInt("lastcompleteLevel");

For the SetInt part you need to assign the value of the current scene. So get the scene build index like you are in your main script. That is the value you are trying to save there. I dont want to sound rude, but that’s what you intend to do, right? In the scene the player last completed, save a value, such that we can load this value, in order to start at the next level. The value in question is the build index of the level just completed, ie the current scene.

And you really do yourself a favor going through some beginner tutorials. These are very basic problems you are currently stumbling over. Not to offend you, but it feels like you are guessing what to do, just pasting random pieces of code somewhere and hoping it works. In the end it’s of course up to you, but you will save time by improving your fundamentals.

1 Like

Can you show me how I should do it I really don’t know. I try to learn by doing or just say I try to understand what was done and to comprehend it. I often watch tutorials but I than I can’t apply it to my scripts.

I already told you how the GetInt part should look like:

lastCompletedLevel = PlayerPrefs.GetInt("lastcompleteLevel");
SceneManager.LoadScene(lastCompletedLevel+1)

Write that when you want to load the next level, ie when you press Play.

For the SetInt part, as i already mentioned above as well, you need to actually save the scene you just completed. So on completing a level, get the index of the scene and then save that value to your PlayerPrefs variable.

int currentScene = SceneManager.GetActiveScene().buildIndex;
PlayerPrefs.SetInt("lastcompleteLevel", currentScene);

So now once you complete a level, for example level 21, you save this value ‘21’ under the name of “lastcompleteLevel”. When you are in your main menu and press play, we load the value from “lastcompleteLevel”, add one, and then load the scene with that number, ie 22.

Programming is learning by doing. Dont just watch a tutorial. Do the tutorial. You will want to follow along, implement what the person in the tutorial does, and potentially experiment around with it a bit. Also, you will want to try and understand what the script does, which part of it does what and how it achieves what it does. Then in the future, when you write a script, you have some more tools in your toolbelt, because you already did something like that when you followed a tutorial. Or at least you have a slight idea how to approach the problem because you did something similar, or know which parts of something you did before may be useful for what you do now. It’s just about adding tools to your toolbelt. But without actually programming something, you wont know how / for what to use these tools, and thus they will remain useless. That’s why it’s learning by doing.
A great place to start (and follow along with the little exercises), would be here:

https://www.youtube.com/watch?v=_cCGBMmMOFw

1 Like

Thank you very very much man, now I will learn something about c# and unity. I guess without you I would just stop programming and I don’t know… Thanks that you took your time for me. I really appreciate it.

1 Like