Why use LevelManager?

So my big question on the lose collider is why use the LevelManager at all? why not simply create a LoseCollider script and add only this to it:

	void OnTriggerEnter2D (Collider2D trigger){
	
	Application.LoadLevel("Lose");
}

It really is the same effect… only used during the Lose condition, and it has far less work. Just a thought :slight_smile:

2 Likes

Some good reasons as to why it’s usually always better to separate what-does-what. :wink:

https://unity3d.com/learn/tutorials/modules/intermediate/scripting/coding-practices

2 Likes

It would work as well, but it is not the ideal.

It is a good idea to have one GameObject to control some specific mechanics such as this (changing level). For example, if you want to save which level the player has already completed or not, it would make more sense to keep track of it using a gameobject with the name LevelManager rather than using LoseCollider, it also increases the readability of the code.

Imagine that after a couple of months you decided to update your game and add some new features such as slow effect when the player met some condition, if you do that you will want to reset the time.timescale to 1 after loading a new level, otherwise if the player wins while the slow effect is under play, it will start the next scene under this same effect. So, six months from now is very unlikely that you will look for a method that have the ability to change the scene under the LoseCollider, you will probably just add the reset time.timescale method to the methods within LevelManager and you would get yourself a bug happening when the player lose the game with the Slow under effect.

It is a very good habit to have a good readability on our code. If we are working on a big project, it is pretty common to forget how some features that you created yourself a couple of months before works.

2 Likes

Oh, I forgot to mention that Application.LoadLevel has been deprecated in Unity 5, among all the other things that me and Joao posted. :wink:

2 Likes

Oh I understand the coding practices and that Application.LoadLevel is depreciated in unity 5 (But SceneManager works the exact same way). I was talking about this specific part of the course, which is coded in Unity 4. Here is why:

@ben , in this instance of the course, talks about not using unnecessary lines of code if we do not have to. The Lose collider is going to be there in the level anyway (If you are going by the instructions). The lose collider has exactly 1 job: to jump to the lose / game over screen. That’s it. So instead of adding a level manager to the level, and adding a few more lines of code to call the level manager and have it take you to the lose screen, why not just use the Application.LoadLevel as stated above. Very few lines of code, its clean and readable, and does the exact same thing without all the extra additions.

I know everyone has different ways to code, and I know we are encouraged to find our own way, I get that. I just was curious as to why this particular method was used when it could have been done differently for the sake of simplicity?

1 Like

@EricPhillips,

When you create the habit to modularize the mechanics of your games, you can re utilize it in future games, the LevelManager for example can be exported into a asset along with objects like “SoundManager”, “LevelManager”, “OptionsPanel” and “PlayerPreferences”, you can always use the same asset pack in every new game, if you create an “Standard Gameflow and GameObjects” package, you could pretty much only code the things inside the game itself because everything else would be done already. Imagine that 4 years from now you will have over 30 games, and you did started to use LevelManager as one of your standard GameObjects, you wouldn’t even remember how is the method to call the LoadLevel anymore, your brain would be so used to LevelManager that you wouldn’t even need to think about it, and every time that they change the LoadLevel method you will just have to change the levelmanager itself one single time and you will keep using the LevelManager as you always did. This way you can concentrate in things that really matters (how your game will be and how it mechanics works).

But as you said yourself, everyone has a way to code, I’m just sharing my thoughts regarding this matter.

2 Likes

The Unity5 deprecated Application.LoadLevel() is a perfect example of why separating your code out can be so useful.

So with the game written in Unity5 using Application.LoadLevel() without using something along the lines of the LevelManager, your calls to load the levels will be scattered across the game.

Does this matter? The game still runs? Might depend where you want to draw the line I suppose.

Right now it will work as intended, fab! But what about when we want to change something? The deprecated method is a great example. If you use something like the LevelManager, which handles the loading of levels and perhaps other “level” related concerns, all of the “now load me the next level” type method calls across the game will point to this one object. When it comes to making changes, especially during the upgrade to Unity5, you can make them in the one place rather than across the entire application.

So, whilst it might be a few extra lines of code now, the time it will save you in the future will invariably pay dividends.

So, why not break everything into a million little parts and separate everything? It’s a balance. Trying not to do too much more now but at the same time not knowing causing big problems for the future.

In the specific case of the LoseCollider - should it really load the lose level? In this small version of the game, yeah I guess that’s ok… but what if your player had more than 1 life? Be nice not to have to start the whole game again :slight_smile: So in that case you may want to load the same level, change the number of lives, update the number of lives on the screen, adjust the score, play a sound, animate an image - the list goes on…

As you add all of those wonderful things, that’s quite a lot of extra lines of code in the LoseCollider - and should it really have them all there? I may want to play a sound else where in my game, so now I’m duplicating that code. I will most likely want to update the score, so now I’m duplicating that code. If I can lose lives, chances are there is a mechanic for gaining them, so now I’m duplicating that code…

What happens when I find a bug in one of those features… now I have to change it in multiple places throughout the game…

I’m sure you get the idea… :slight_smile:

As a rule of thumb, I tend to start refactoring my code the moment I find something doing pretty much the same job in more than one place, because if I’ve used it twice, chances are I’ll use it three, four or more times across the application.

It’s really worth considering the separation of concerns, what things should do what and what things should know about other things.

If I have a piece of code separated away for handling the addition and subtraction of lives from a player object, it doesn’t actually matter what causes the addition or subtract (getting a specific score, collecting a power-up, completing the level, or losing the ball, crashing into an enemy, running out of time etc), all it has to do is what it’s told, increment or decrement the lives of the player. As @Joao_Dalvi mentions above, it also provides a means of re-usability, if its generic enough it code be easily used across multiple games and without change.

This kind of approach isn’t perhaps a lot of fun to start a course off with, but the use of the LevelManager is perhaps a simple way of injecting an approach without it being too full on. It can however be a lot of fun as you get in to it, I personally find it really rewarding to refactor code and make it more generic, more usable, more maintainable…

Anyway, bit of a lengthy response but I hope there is something of use scattered amongst my many words! (sorry)

4 Likes

To expand a little on what @Rob very thoroughly explained, another thing that should be taught from start when approaching OOP is to never access directly instances of objects (i.e. publicly) from outside their own class, but instead to access them indirectly via the use of get and set accessors.

I encourage anyone who’s reading to start to do so asap, even in very small projects. :wink:

2 Likes

I fully agree with that and I find it painfull that Unity doesn’t expose propertied in the Inspector, forcing the use of the member vaiables :frowning:

The closest thing to “protecting” instances available in Unity is to expose non-public variables via the use of [SerializeField] afaik.

Edit: I just noticed after writing that you meant another thing - I guess this page in the Unity wiki explains the code needed to expose proprieties with get/set in the Inspector: http://wiki.unity3d.com/index.php?title=Expose_properties_in_inspector

1 Like

Yeah I saw that the other day and when I saw what was involved to do it it became fairly clear why everyone just exposes public variables! *shudder*

The more I investigated the more it seem to become about scripting the editor and I had to remind myself that as it was only me working on the project it was fairly pointless!

I have been able to use properties as I would expect in classes which do not inherit MonoBehavior, so just business entities if you like, but coming from a application development background this aspect in Unity feels a bit… ickky… :slight_smile:

1 Like

Privacy & Terms