Scene Manager - Struggling to get a correct query

I’ve spent several hours and I don’t have a solution that I am happy with.

Environment
I have several ‘level’ scenes in my game an I will be increasing that number as I go. I just drop a new level into the build settings each time one is created. When this is done my ‘Lose, Settings & Developer Settings’ scenes get bumped down the stack.

Requirements
When a level is completed I wish scene manager to use the buildindex +1 to get the next scene and query its name before loading it. If its not the ‘Lose’ scene then load it.

To me, this seems like a fundamental requirement but I am struggling to achieve it in a basic way.

I have a post on Unity forums so there is no point re writing it. If you would be so kind to take a look it is Located Here

Thanks Guys

Paul

Hi @Paul_Land,

Why not flip it around the other way? Why not have it so that the non-playable scenes are at the start of the build index, then, whatever else comes after that would be a playable scene, this would remove the need to bump the scenes down as you create more.

Assuming your conditions for determining a win and a lose are strong, the only thing you would need to check for then would be that you haven’t reached the last playable scene. You could achieve that by comparing the build index of the current scene to the total number of scenes in the build, then load the required scene.

Hey @Rob thanks for the reply

I did have the same thought at the beginning but also wondered if I would be able to know that my last level was.

There is no Win condition but the lose condition is very dynamic and strong.

I could use SceneManager.sceneCountInBuildSettings as you suggested to get a total. The only thing I don’t like is that this will rely on human intervention to do a calculation after , all be it small, and remember if I add a new non ‘levelnn’ scene to add it to the calculation. I know this seems a trivial thing but I have tried to build my game framework so that it does ‘stuff’ dynamically.

I could use EditorBuildSettings.scenes to build an List array, to do it dynamically, but that seems a bit long winded for something I thought should be quite straight forward.

I think I will try using EditorBuildSettings.scenes to build the array and get on with it. I just thought I must be doing something wrong.

Thanks for the reply

Paul

1 Like

I guess it depends a bit on what exactly you are trying to achieve and if there is a bigger picture. From the above, the only human intervention I see would be needing to add your scene to the build settings and, update an array of names with another non-playable scene name. That’s not too costly. Could probably skin it a few other ways… having the names is only necessary if you want to compare the name of non-playable scenes to that of the current one. If you had all of your non-playable scenes at the start of the build settings, lets say there are three, you could just have a int firstPlayableSceneIndex = 3 variable to use (lose, menu, options, level_01 etc). The only change then would be incrementing this number if you added another non-playable scene (how often would that be?)

Regarding doing it dynamically, I think which ever way you skin it, you would need some form of config which is created by human intervention in the first place, whether it’s lists, player settings etc.

What I had in my head was something a bit like this

  1. Build a List array using EditorBuildSettings.scenes in a start Method in my Level Manager.
  2. Get the last ‘level’ scene index from that array … say Level05 = index 5.
  3. Each time a request comes to the Level Manager for the next level do …

Psudo Code logic

Start(){
foreach(/* search the array pattern match for the last 'Levelnn' before another scene that does not start with 'Level*' */)
{//true logic - make it  = lastIndex)
}

LoadNextScene(){
int thisIndex = Scene.buildIndex;
int nextIndex = thisIndex +1;
 
if ( nextIndex != lastIndex){
//load the next level}
else {//load Level01
 }
}

Of course I am a beginner and could well be talking complete nonsense :slight_smile:

It needs to be a Dictionary array not List array.

Ok, I think I see what you are aiming to do, and yes I believe you could get the desired outcome the way you are suggesting.

You are really just asking whether the current scene is the last playable level or not, if it is, start again, if its not, load the next playable scene.

I’m guessing your LevelManager isn’t actually included in each scene? You would only want to perform that foreach iteration the once for the life time of the game, effectively extracting the scene/indexes from the build settings. There is still a manual step there which is putting the scenes into the build settings and of course it will rely heavily on the naming of your levels, misspell one and that level won’t be included.

So, you end up with a list of scene index numbers, which, depending on where you have put the non-playable scenes in the build settings may look like this;

0,1,2,3,4,5,9,10 - where 6,7,8 were non-playable scenes

Based on what you have in the pseudo code example, nextIndex would get incremented after scene index 5, it wouldn’t equal the last playable scene index (10) and would then try to load scene index 6 - a non-playable scene.

Unless I’ve misunderstood?

If you had this;

Build Settings;
Lose           0
Menu           1
Settings       2
Dev Settings   3
Level01        4
Level02        5
Level03        6

You would only need to know about the total number of scenes, and which index the first playable scene was, after that you can just increment numbers whilst the number is <= the total. As soon as the next number is higher than the total, go back to the first playable-scene.

Assuming the LevelManager is only loaded once itself you could have something like this;

// private fields to retain some useful settings/info
private int _totalScenes = SceneManager.sceneCountInBuildSettings;
private int _nonPlayableScenes = 4;
private int _firstPlayableSceneIndex = (totalScenes - nonPlayableScenes) + 1;
private int _activeSceneIndex;

// loads the next appropriate scene based on the current scene index
LoadNextScene()
{
    _activeSceneIndex = SceneManager.GetActiveScene().buildIndex;
  
    if ( (_activeSceneIndex +1) < _totalScenes)
    {
        // load the next playable level
        SceneManager.LoadScene(_activeSceneIndex +1);
    }
    else 
    {
        // load the first playable level
        SceneManager.LoadScene(firstPlayableSceneIndex)
    }
}

Note: If there are additional load a level methods, you would want to ensure that the _activeSceneIndex was being set accordingly (refactor to another method and call it from each of the load methods etc)

The only downside I can see with the above is that it assumes that the next level is always playable, thus, you need to ensure that non-playable scenes are first in the build settings and, you set _nonPlayableScenes accordingly.

Yep.

You are really just asking whether the current scene is the last playable ‘level’ or not, if it is load the first (‘level01’) again,** if its not, load the next playable level.

The only thing that I need to do is make sure that my ‘levels’ follow the naming convention i’m pattern matching for.

My level manager is an extension of the one in Laser Defender. It does get loaded every scene so It would be better to keep this Array in my NumberCruncher.cs as this is persistent and only loads once for the game. In the scope of what I am doing it is probably more appropriate place anyway. The Level Manager already has a connection to Number cruncher so can get the lastLevel value. (lastLevel - being the last game playable level).

Indeed. (see above!)

The rest of what you said is a great idea and would negate the need for pattern matching the next non ‘level’ scene etc.

Ill give it a go and report back as usual! :wink:

1 Like

My level manager is an extension of the one in Laser Defender. It does get loaded every scene so It would be better to keep this Array in my NumberCruncher.cs as this is persistent and only loads once for the game. In the scope of what I am doing it is probably more appropriate place anyway.

Gotcha…

I had something similar before with effectively a GameController and a SceneController. The SceneController was only concerned with things that were happening / may happen within the context of the current scene. So for example, loading the next scene wasn’t any of it’s business. The GameController was responsible for loading another scene, and for keeping track of the Player (which in turn kept track of the score / health etc), like wise, it didn’t concern itself with the more granular scene specific things. Your LevelManager / NumberCruncher configuration sounds similar.

Ill give it a go and report back as usual! :wink:

Look forward to hearing how you get on.

@Rob

Well after a bit of tweaking that approach works!

I had to split the value assignment in the declarations into the Start method as Unity was complaining.
Also, can’t remember were, but I was getting a 4 + 1 = 41 as apposed to 5 so fixed that.
Also my persistent NumberCruncher got loaded twice when I went back to Level01 so fixed that too.

TODO

  1. I will replace private int _nonPlayableScenes = 4; with an array so that it can be processed and a value automatically created instead of me having to manually change that number each time I add a non level scene.

So its been a success Rob.

Thanks for your help and advice as usual. :grin: A few hours finishing this of and I will actually be building levels properly and starting with enemy AI. It’s been a long time coming to get my framework ready so I can just ‘bang em out’ as it were.

Many thanks

Paul

Also, can’t remember were, but I was getting a 4 + 1 = 41 as apposed to 5

String concatenation instead of numeric?

I will replace private int _nonPlayableScenes = 4; with an array so that it can be processed and a value automatically created instead of me having to manually change that number each time I add a non level scene

I was tempted to suggest using the length of the array in my post but I was trying to give a solution that didn’t involve another list (as the build settings scenes is already one obviously).

Really glad to hear you’ve made progress anyhoo, are there any teaser screenshots to be viewed in the near future as you create your levels?

Yes I realised you were keeping it simple for proof of concept.

Lol, there can be. It will probably be a few weeks though. I’ve been doing stuff like testing it on Windows, OSX, Ubuntu Linux, Android, iOS, Windows Phone. Making the Joystick controls resizable etc. A lot of stuff that could have been left till the end but as I’m new to all this I didn’t want any major surprises. I’m happy now that I can get on and do the fun stuff like the creation of new artwork for the sprites and level design.

The course has been fantastic for me and I have put into practice using a GDD extensively and flow charts too. The game will be my version of Laser defender and it’s been fun playing even just the single level testing the changes each day. It’s funny but having it on my phone has given me a lot of encouragement to keep plugging away.

I’ve only just finished the Glitch Garden section on the course but I learned a lot from that about animation and triggering scripts that I will now put into practice.

Anyway …, what are you up to, You still working on your project?

1 Like

I don’t see a way of being able to get access to the scene names if they have not been loaded already by scene manager. I can get a total number of scenes, as we have already done, but not access to the names in the Build Settings.

So I guess I will just stick to manually changing the number in our nonPlayableScenes. No biggy but again, I am very surprised that this isn’t an option. Maybe I am missing a trick. I suppose I could load each scene and read its name until I get to the first load scene … then start my game as normal, but its really not worth it and it is a complete fudge!

Oh well, I’ll move on. I will even give this a new major version number! Trumpets Sound :trumpet:

1 Like

Any use?


Updated Wed Feb 08 2017 15:03

Hey Paul,

Been having a play with this specific thing and want to be sure I fully understand what you want to do as I have had mixed results so far.

Am I correct in saying that you want to determine the number of playable levels based on a specific level name format, but that other than for this specific reason the name of the level doesnt actually matter; e.g. Level01, Level02 could be Fred01, Fred02 as long as your pattern matching was updated to look for “Fred” instead of “Level”?


Updated Wed Feb 08 2017 16:25

Pretty sure this one should nail exactly what you want. From within Unity you will be able to save an .asset file which contains the paths of the scenes, this is subsequently loaded in at run time, so as long as you aren’t making any on-the-fly changes to the scenes during game play this may well be a solution for you.

From what I have seen this afternoon, it would seem that the names are simply derived from the path in Unity anyway, and there’s a regex at the end of the tutorial to help with that. You may have to tweak it slightly as from what I can see he doesn’t bother exporting the build indexes out to the .asset file, just the paths.

http://davikingcode.com/blog/retrieving-the-names-of-your-scenes-at-runtime-with-unity/

It’s a bit of work and will most likely expose you to some additional aspects, but could be worth following the short tutorial from a learning perspective.

or…

You could just update that local field with the number of non-playable levels :wink:

Completely correct.

Yes that sounds very promising that you think it’s do-able.

Lol. Fair point well made!

I think I’ll defer it to a day late next week. I’ve spent 3/4 of today fixing various bugs from having multiple levels loading and a few more that have happened as I’m looping my levels. Been Okay though as I’ve learned a few new ways to achieve stuff.

Thanks for your hard work as ever :wink:

Paul

Lol. Fair point well made!

hehe :wink:

I think I’ll defer it to a day late next week.

I’d be interested to know how it goes, as the same method would be useful for other configuration aspects also.

I’ve spent 3/4 of today fixing various bugs from having multiple levels loading and a few more that have happened as I’m looping my levels. Been Okay though as I’ve learned a few new ways to achieve stuff.

Sounds like an awesomely productive day, well done :slight_smile:

1 Like