Page cover

Switching between scenes

SNow that we have our game manager ready and our level info display, we can now start with adding different scenes in our game and switch to those scenes depending on which you've entered.

Creating a scene

We need to have a scene(s) to transition to once the player has selected a specific level they want to enter. For this demo we only have two level nodes, so lets create two scenes.

Note: Make as many scenes as the amount of level nodes you have in your world.

Now that we have our scenes created, we also need to add them to the "Scenes In Build" section of Unity's "Build Settings". To do this go to File --> Build Settings.

Click on the button "Add Open Scenes" and you'll now see your world map scene added to the list.

Now follow this same process in all your level scenes. In the end you should have something looking like this.

Important: Make sure the world map scene is above all your other level scenes! Otherwise the rest of the code we're about to write won't work properly!

Up next we need to adjust a lot of code in our already created scripts we did before in order to get everything working properly. In the end, we'll have to change some objects set up in the hierarchy and the inspector.

Adjusting the game manager

Now that we have our scenes and build settings in order, it is time to work on our game manager script again.

Adding the references and variables

At the top of our script we need to add "using UnityEngine.SceneManagement;" in order to access the scene manager functionalities.

We now also need to add a reference to our world data SO. That way we can later update our unlocking status of a level after completing it.

Since the path manager will only exist in this scene, we can't use a serialize field anymore to set it as a reference. We just have to make it private and create a function that gets the path manager once the game manager is in the world map scene again.

To solve this issue we create a public set path manager function that takes the path manager as a parameter. Then, we set the path manager value equal to the path manager we get passed through from our parameter.

Then we need to create an integer to store our level index for when we want to switch to a different level.

Lastly, we need to create a start function with an if statement that checks if the boolean is fading black is false. If this is the case we want to start our fade effect coroutine with the is fading black boolean as our boolean parameter and null for our level node data. This is because we haven't selected a level yet, but want to display the world map to the player, instead of looking at a black screen.

Adjusting the fade effect coroutine

Now lets first adjust our fade effect coroutine by adding in an extra parameter and that is the level node data script.

Note: You'll see a red line appear underneath the function everywhere you start the coroutine. Don't worry, this will get fixed soon.

Inside the coroutine where you start this again, add "selectedLevel" as its parameter.

We also need to add the level node data parameter to our scene transition function and pass this through as an parameter in the start coroutine function.

Check level index

Now lets make a new function called check level index that takes a parameter of level node data. We'll use this function to determine which scene needs to be loaded based on the integer value.

First, we need to check if the selected level, we get passed through is not equal to null. This means we're currently trying to enter a level and not trying to return to the world map. If this is the case we want to set our level index value equal to the level number that is stored inside the level data reference of the level node. If this is not the case we set our level index value to zero, so we return to the world map scene.

Afterwards we need to check if our level index value is equal to zero or not. Depending on the outcome we load in the world map scene or our selected level scene.

And with that we've set up our scene transition, but we'll come back to this function later once we're going to adjust the UI references later in this page. The only thing left for us to do is add this function underneath our toggle enter level info function inside our fade effect coroutine with our level node data reference as its parameter.

To finish off our fade effect coroutine we need to build in an extra check to see if our path manager reference isn't empty. If that is the case we know the player is back on the world map and needs to call the check unlocking movement function on that script to see if they are allowed to walk around or not.

Level complete

Once we get to setting up our level completion, we need a way to update our path information in our world data SO paths in world list. To do that we need to create a new function called level complete that takes in a path data as a parameter.

First, we need to check if the path data information we get passed through is not null, meaning there is a path we've unlocked a new path by completing the level. Then we need a for loop that loops over all the paths inside the world data SO paths in world list.

In the for loop we need to check if the selected path in our world data SO paths in world list is equal to the path get passed through as a parameter. When this is true, we call the update unlocked status function on our path manager, giving it the path data's first time boolean and an integer value as its parameters.

Adding the UI references

Now that we have our main scene switching in place, we need to adjust our UI display and references as well. To start of we add "using TMPro" at the top of our script.

Up next we need to copy our our level name, level number and level enter info reference over from our path navigator script to the game manager script. Simply cut and paste it over so you'll have the error messages inside your path navigator script so it's easier to find where we need to make some changes later on.

And with that we've got all our references and values we need inside our game manager. Now, let's create the function we need to still display the same values as we had before when this was located on our path navigator.

Let's start off with a public function that will display the information about when we entered a level. This function takes a level node dat as a parameter. Then we simply set our level enter info text equal to a string line, "Now entering level " and add on the level number we get from our level data reference of our passed through level node data parameter.

For the level info container we only have to set this game object inactive once the player is going to enter a level. So we can set this game object inactive in our else statement of our check level index where we check if our level index is equal to zero or not.

Lastly, we need a function that sets our level information that is being displayed in the top-left corner of the scene. This function also takes in the level node data as its parameter.

First, we need to check if our level node data parameter is empty, meaning we leave the level node we're currently standing on so we need to empty out our display. Just like we did in our path navigator script we set our level number and level name to display the default information.

When this is not the case we need to fill level number and level name with the information provided via our level node data reference.

And with that we've set up all our function we need inside our game manager script to display our UI elements again with the proper information. Now we need to call these functions inside our path navigator script.

Adjusting the path navigator

Now that we have all our UI functions set up we now need to call them in the correct function. But first, we need to remove "using TMPro" from the top of our script since this will no longer be used inside this script.

Inside our on trigger enter we can remove our text reference and replace it with our function set level UI data display with as parameter the current level reference. We do this by typing out the game managers script name, then its instance name, followed by the function name.

This same step we also need to do for our on trigger exit function, but with a slide difference. We still call the function with the same method as we did for our on trigger enter, but as a parameter we provide it with "NULL" so the game manager knows it needs to empty out the level node info display.

Lastly, we need to adjust our on confirm function. First, we need to add our current level reference as it's required parameter for our scene transition function.

Up next, we need to remove our reference where we set our text for our level enter info display and call the set level UI data enter function like we did before. This function also gets the current level reference as its parameter.

And with that our path navigator is now also ready to be used.

Adjusting the path manager

Another script we need to adjust is our path manager script. First, we can remove the serialize field attribute from our world data reference, since we now get this via our game manager instance.

Since this will only exist in the world map scene, we need to be able for the path manager to add itself back to the game manager when this scene is loaded. Luckily, we've already created a function that does this for us, so all we have to do is call that function in our start function we need to create first.

Then we can set our world data container variable equal to our world data reference on our game manager.

Now we have to create a new function called get all paths that does everything we do in our on enable function, minus the part where we call the check already unlocked paths function. We can also remove our on enable function since this is no longer needed.

We then need to call this function inside our start function.

Now this function should also be called inside the check unlocking movement function, but only when the paths in world list is empty.

Next, we need change our update unlocked status function. We are only gonna need to have a boolean and an integer as its parameter, because this function is only going to be used to update the path status inside our world data SO. This will break our functionality in the path decorator script, but we'll fix that at the end.

We can now remove everything inside this function since these functionalities are no longer required here. What we will do instead here is to set our path booleans we store in our world data SO equal to the values we set in here. To get our correct path we pass through our integer we got from our parameter to get the right path in the list. Then, we set the unlocked boolean to true and the first time boolean equal to the first time unlocked value it got passed through as a parameter.

Now we need a new function that will update our first time boolean after the path decoration is done displaying for the first time and enables the player's movement. For this function we need a boolean as a parameter as well as the path data to update the correct path in our world data SO list.

First, we need to loop over our paths list in our world data SO.

Then, we need to check if the path inside our list is equal to the path we got from our parameter. If this is true, we set our first time boolean of that path in our list equal to the boolean value we got from our parameter and call the check unlocking movement function.

We've now got everything ready to update everything, but we also need to set certain values first. Mainly the first time unlocked value. We need to create a function that does this for us. Inside this function we first need to check if the paths in world list is not zero, meaning we're on the world map and need to adjust our first time boolean value based on the value inside our world data SO reference.

Let's also create two for loops, one that loops over the paths in world inside our path manager and the other from our world data SO.

Next, we'll check if our path data reference in our paths in world list of our path manager is equal to the one stored inside our world data SO list.

Once this is true, we need to get the index position of that path from our world data SO list and store this value temporarily inside an integer.

Then we need to check if the path inside or path manager list has the path decorator script attached to it. If it does we need to set the first time boolean of that script equal to the first time boolean stored inside our world data SO. We do this by getting the index position with the stored integer value we've just made from our world data SO paths in world list.

The last thing we need to do is call this function inside our get all paths function underneath our for each loop.

Up next, we need to make another function that updates our path managers paths in world list. What this function basically does it compares the path selected from the paths in world list and compares the corresponding path inside the world data SO list. Based on the outcome if the path inside the world data SO list is true or not, it unlocks or doesn't unlock the path.

First, just like we did before with our set first time function, we need to loop over both our path lists inside the path manager and world data SO and compare them to see if it's a match or not.

Then we need to check if the path inside our world data SO is unlocked or not.

If this is true, we need to, just like we did inside our set first time function, get the index position of the path inside the world data SO list. Then we set the path from our paths manager list unlocked boolean equal to the value stored in the world data SO, using the stored index value to get the correct path from our world data SO list.

Then we need to call this function in our set first time function inside the if statement where we check if the paths in world list is not equal to zero.

Lastly, we need to call our check already unlocked paths function under our first for loop in our update paths list function.

Now we have to adjust our check already unlocked paths function. Since we need to change quite a lot it is better to remove everything in this function and start with a clean and empty function. That way we won't make any mistakes.

Luckily, we can copy a lot over from our update paths list we've just finished. We can copy over both our for loops, both our if statements checks and inside the unlocked statement check we only need the part where we temporarily store our integer value.

First, we need to check if our selected path in our paths in world list has the path decorator script attached to it. If it does we get this path decorator and store it temporarily into a variable.

We then need to set the first time and unlocked boolean values equal to the once stored in our world data paths in world list. We get this value by making use of our stored world data integer reference to get the correct path from our world data SO paths in world list. After that, we start the decorate path coroutine.

The last function, we need to adjust in this script is the check first time unlocked boolean function. Since we've now created a function that will set our level unlocked boolean we can remove the line where we set our unlocked boolean to true. What we'll add is a temporary variable to store in our path decorator script reference in that we get from our selected path inside our paths in world list.

We then need to wrap the return false into an if statement that checks if the path decor's first time boolean is true or not. If it is true we want this function to return false. Otherwise, it'll return true.

And with that, our path manager script is ready to be used. We now need to go into our path decorator script and where we used to call the update unlocked status function, we need to replace this with the update first time function. In this function's parameters we pass through our first time boolean and our path data we get from our path lay-out reference.

And with that we've changed everything we needed to do in our scripts. Now we need to go back into Unity and assign missing references to the Game Manager.

Assigning the references to the game manager

Now that we are done with updating our scripts, we can now assign the missing reference to our game manager. Similar to what we did before, we can either drag and drop the missing reference to the corresponding slots or select them from the little pop-up window when clicking on the missing reference. In the end the game manager should look something like this.

And with that we're done with the game manager. All there is left to do is set up our objects in the hierarchy.

Setting up the hierarchy

We need at least two canvas objects that are a child object of the game manager object. One to hold our fade panel and the other for our level info display. We can rename our already existing canvas to "Fade Canvas" and we set this as a child object of the game manager.

Now we create a new canvas from our game manager object and name it "World map Canvas" and place this above the fade canvas object.

Now we need to set our level info display and level enter display objects as a child of the world map canvas. In the end your setup should look something like this.

The last thing we need to do is on our world map canvas is to change or sort order from zero to minus one. We do this so that the level info display will always be placed behind the fade canvas and thus can never be visible in front of the fade panel.

Level completion

Now that we have everything ready for the level transition and being able to unlock the next level with corresponding path, we now need to hook this up to an actual level scene to see as a whole.

Let's create a new script called unlock next level and attach this to our canvas, then open it. We can remove the update function since we don't need it. In the end your script should look something like this.

First, we'll need a reference to our path data so we can let our function inside our game manager know which path we want to unlock. We have to make it serialized so we can later set it via the inspector.

Up next we'll need a coroutine that will return us to the world map after a couple seconds. We'll call this coroutine inside our start function for this tutorial, but you can call yours in an on trigger enter or on collision enter if your level already has a start and finish.

In order to update our unlocked status, we need to call the level complete function on our game manager. To do this we get the game manager instance, call the function and give the path data with as its parameter.

Next we'll wait a couple seconds before executing the rest of the code so we don't instantly fade back to black when calling the scene transition function the same way as we did for the level complete function. In the scene transition, the only parameters we need to give it is a boolean value and a level node data reference. We do want our transition to fade to black so we pass in true and we don't need to reference our level node data since we want to return to the world map and not to a level.

And with that, our unlock next level script is now also ready to be used. Now all we have to do is go back into Unity and assign the path you want to unlock in the empty slot.

Note: If this level is your last level, or you simply don't want to unlock a path after finishing it, leave this slot empty.

Important: Don't forget to add your scenes to your "Scenes In Build" in your build settings!

You've now completed everything you'll need to switch between scenes, update your first time and unlocked booleans and save this progress into Scriptable Objects. Your end result should look something like this.

And that concludes our Crash style world map implementation. If this is all you wanted for your project then this is the end of the tutorial for you and I hope you've found it helpful and learn full.

I'm currently still working on and figuring out how to properly implement a Mario style world map functionality. As soon as I have this all figured out and working as optimally as possible I'll update this tutorial.

Last updated