Learning Async Unity Scene Loading

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello internet today i want to start a little project that i'm working on to do a better or more intuitive way of loading scenes between levels um i've been playing a lot of vampire the masquerade bloodlines and there's if you're not familiar with that game it's an rpg and there is a club in in the game and there are two levels on an elevator this i don't think is a very uncommon thing in games where there are multiple levels um what i would like to do is have each of those levels of maybe a hotel or office building or whatever be different scenes in our unity editor and we can load each of them independently by just going to the elevator and selecting which one to go to this is going to happen over the course of multiple videos um as as i learned what i'm doing um playing with scene loading is not something that i'm very familiar with so that's sort of the point here is to kind of dive into that and see what we can learn and see if we can do something cool with it i think this will turn out cool or it'll blow up in my face and and we'll learn something either way so what we're going to do in this video specifically is look at just loading between two different scenes using an uh async operation so we can actually asynchronously load something what async means is that it's happening simultaneously in parallel with everything else in your game the important part of that means that if you are doing something asynchronous it means the rest of your game can continue running uh if you are familiar with normal loading stuff uh typically everything just stops um and that's usually not great uh it's sort of the morrowind experience um we want to avoid that and instead ideally what will happen is you will press a button and you'll stay in the video build and move around you'll be able to do all sorts of normal things interact with your ui do all that other stuff and we'll just be swapping the scenes out behind the scenes um so that that's the goal uh in this case we're going to create two scenes so scene a i think i just did yeah so scene a uh let's do scene a uh the naming actually doesn't matter because i'm gonna try to use the names to transfer between these instead of the build id um again this is something that i'm still learning uh unity has messed with how their scene loading works uh this async stuff was different when i previously used it so uh we're we're still learning i'm gonna also try to copy that that doesn't work so we're gonna just save the scene as scene b as well there we go and now we have uh our sample scene which is just my test project for this but then we have cna and saying b cna is going to load scene b and we're going to do an additive load between these which means that we're not going to unload everything we are just going to effectively add on scene b onto scene a this is not ideal but what it's going to allow us to do is control how we remove the objects from scene a are ourselves um so instead of having unity handle that we are going to be able to do do that for ourselves uh so we're going to cna we have our main camera and our directional light uh that's all fine but i think we're probably we're this is going to cause some issues so so really when you implement something like i'm thinking about there's going to be three scenes we are not doing that the reason there's going to be three is there's going to be like global objects um so think about like the directional light of the sun uh the player the camera different like global game objects things like that you probably want them all isolated somewhere that is going to persist between scenes we are going to be changing all of that um so that is no longer going to happen instead we're effectively going to be uh using two scenes so so there's no way to really do that i am going to kind of fake it and we can add that in later later in the project um so we have our main camera our directional light in our cube the cube is going to be just a symbol of what is loaded um that's going to be the easiest way for us to tell that this is the correct scene uh really we have the main camera directional light so that should all already work um but we're going to skip that and we're just going to jump to scene b uh cnb is going to have less um so we're going to delete everything um that's going to make it appear a little bit weird in this what you can do with unity is actually load multiple scenes so if you want to edit two things simultaneously you can just drag and drop them over here and now you'll see and i have scene a and scene b um when we're talking about having one that controls all the global objects this is this would be the editing experience you would expect because you'd have one scene loaded that had the global elements and one scene loaded that was the current scene you were actually editing um so that way you could actually see what it would look like without having to to like insert fake objects that you'd need to remember to delete later uh so i added a cube we actually don't want a cube instead let's add a sphere and so we're going to just add a sphere above it i guess doesn't really matter we just need two different objects um so cna scene b we are going to unload cnb uh we'll just remove it actually there so that's gone now uh but that's what we need to load so we need a script to to do that i do have some notes over here uh just because i do not remember how to do this we're going to be doing this with a co routine and those are also something that i don't use very often um so uh load level level sure why not um this is all work in progress stuff why is it opening another version of visuals anyway um basically what this is going to do is we're going to kick off a co-routine a co-routine is a unity function that effectively runs over multiple frames um so it's not going to complete in a single frame or a single step it's going to be an action that takes a longer period of time and this is captured using an ienumerable or enumerator that captures the steps i guess you're going to take so in this case we have start update we need to do a public tool load level uh maybe this is going there we go there it is uh and public string of the level name ah this is going very slowly i'm not entirely sure why uh resharper resharper is why it's going very slowly great uh it can go away now so we load the level we love have the level name and that should be everything i think uh making this up as i go so who knows uh but yeah so we don't need to start we're not going to use that instead we're going to have this load level thing uh so if load level equals true uh first we should put this in an if statement because that is not going to work so if that's true all right let's let's do if statements correctly all right cool if that's true then we want to start a co-routine and we're just going to say load level and that's that uh so this expects a thing apparently oh ah we can't do load level uh load level async this is probably bad form uh i wouldn't necessarily recommend calling something this uh the reason is um async functions in c sharp are sort of a paradigm that this does not follow um typically if something is called has async at the end and a c-sharp function that means that it returns some form of task and is creating more a task and doing something asynchronously using that task system ah we're not doing that we're creating a co um so so i this naming scheme if if you're doing this in your project make sure it's consistent this will probably confuse people who are not familiar with your project who are coming from c-sharp uh so keep that in mind so we need an i enumerator and this is just going to allow us to use uh yields so if you're not familiar with c sharp yield it's effectively a way to stop a function halfway through and continue where it was the next time you call it um so you i have an entire video on this it goes far more in depth but you can use this to create like infinite functions that generate things effectively creating lists that are generated using code rather than lists that you fill and then pass to an object um so they they're pretty powerful in this case we're using yield to kind of say wait uh and do something else uh so the way this works is we need to start loading in uh a scene um so we're just gonna say their progress equals uh the scene manager dot start nope load scene load scene async is going to return an async operation uh as far as i'm aware this is not related to anything async and c-sharp doesn't use any of any of that stuff instead it is just unity's own object to store information about this async operation so you can handle that um i would need to double check so that may not be accurate at all but that is my understanding right at right now so we're going to give it the level name and there's this other thing uh the load scene mode the default here is going to be single um what single means is it's going to close everything else when you try to load it that's not what we want because that means we will lose everything that is currently there now this is useful if you're transitioning from like a menu into your real game for example you don't want to carry that whole main menu ui to your new scene but if you actually do want to just add a level on top of another one the additive is probably what we want so we're gonna do that and what this should do is this should mean that we should have our cube on top of our sphere with the light in the camera so all four objects should should exist from the two scenes uh rather than just three objects in one and then one object um so that is sort of the the effect that we're going for if we do this right that's that's what we'll see um but this is an async operation which means it's not going to complete um when you call this function your level is not loaded um so you can't just start doing everything that you want because this hasn't finished this is just starting the process this is just saying go drive and pick up groceries or whatever you're just you're just beginning that task you need to check the progress which is why we saved that so progress has a whole bunch of fun things in it we have our progress which is a float so you can actually track apparently the actual progress i didn't know that was there um but we'll work what we care about is the is done thing uh there's also a completed event which seems like that could be useful as well um that's fine uh we're just going to track is done so while uh progress dot is done we want to make this a not um so while it's not done we're just going to wait in this co routine um so we should do something like this i need to double check but it should be yield return no um there is no object that is being returned here effectively what we're saying is just yield return and then wait um so this is just going to spin infinitely until that finishes um so once we pass this block our level has loaded that's how we that's how we can tell um so once we get out of this while loop the progress of this level should be completed so we should have that new scene loaded in so what we should be able to do is do a debug.log and just say level loaded and hopefully that means that we did this correctly um i think this is probably the best way to do this if you're using a callback so if you're using the event based system you probably don't need a co-routine at all you can probably just skip that um but i think this is probably the simplest um events in unity are something that seems relatively new i say relatively new they started adopting them with unity ui like years ago um but they're still they're still a relatively new thing um compared to a lot of the other things like co-routines are much older than the event system uh so uh what i imagine that would look like if we wanted to do that would be this var progress we do progress dot completed uh and just add a callback here and say uh what does this event even contain async operation so up sure we'll pass that in so that gives our async operation we're just gonna say uh debug log uh level loading done um so we should see both of these actually pop up um i'm going to not do this because this is not a good idea um we're going to load the level twice uh actually you know what let's do it why not uh this can actually actually be kind of useful because it'll show that we're doing these asynchronously i think um and it it shouldn't hurt uh i'm i'm expecting this to be relatively fast our scene is not complex um so this should not be something that takes a very long time if it is i've done something wrong uh i may have already done something wrong but we're gonna pretend like this is all good and just go from there but this is these are the two paradigms i can see happening um i would recommend doing this immediately after the load scene async my understanding is that this is going to cue something up uh so the level loading will not start until the update completes until the end of the frame that is not something i have validated though so i do not know if that is the actual behavior but that is typically how these things sort of work if you instantiate an object it typically waits until everything is completed until all the the updates and stuff have done and then it will fire all the instantiations and the deletions um but again that that maybe that's different here um i would hope it works that way though because otherwise this this could theoretically turn into a race condition uh so ignoring that tangent uh let's run this and see what happens um so we're in cna what happens if we if we run this uh we need to attach it to our main camera and do this uh this is going to break before i do this uh i was about to crash my computer let's avoid that um so let's say load level equals false um we were going to turn on a boolean that was going to tell it to load a new scene twice a frame um we'd start off with about 800 some frames and we would quickly end up with about zero frames um so this should mean that this is a one-time operation um obviously this isn't how you would do this in a normal game you would not use a boolean to control this you would use a function um but we are trying to use unity's inspector as sort of a debugging tool so we have a way to kind of test this uh so that is why all of that is the way it is um so what do we call this we call that scene b right so if i do load level scene b i we may need to add it to the build list i'm not sure if that's required or not though so we're going to find out uh but if i do load level click that it does freeze null reference exceptions cool couldn't be loaded because it hasn't been added to the build list all right cool uh so we can do that really quickly we just go to the build settings uh add open scenes uh we need to switch to the project and add scene b as well uh this tells unity what scenes exist uh and then the name needs to match the name of it um if you have duplicate names so if you have multiple things that are like called main menu or menu or something like that uh instead of giving scene b as the name you would give the full path um so in this case it would be scenes slash scene b um that's how how those are distinguished but this should now work uh we should no longer get an error hopefully um we'll see so if i do that now we have two sets of scene b uh you can actually see in the inspector over there they actually popped up separately and so now the those should all be loaded and we have our spheres everything is good uh we didn't lose our other object and both of them completed yay so that is i guess async scene loading this is not the best example of this um as i build up this project and the scenes get more complex you will see why this is uh more useful um just as an example like you couldn't even tell that that was a thing um there's also a non-async version so scene manager that load scene and you just give it the level name like this and we want to do it additively so load scene additive um this works too um you you can just do this so there this should also do everything that you needed um if you have a really simple scene or you do not care about it sort of freezing uh maybe like the first set of things or you actually need these to happen at the same time for whatever reason um you can just force it with this so we attach it to the main camera if we go here we can just click that and now we get our new scene um so that also works again that is a blocking call so it is simpler but it is going to block which means that if the player is actually trying to actively do something in your game and you try to load another scene like the next world whatever they're doing is going to stop until this finishes um so keep that in mind uh especially a lot of developers tend to have more powerful computers uh if that's you and you're running this and you're like oh yeah it's fine uh double check that um and make sure for lower powered pcs especially ones with like normal hard drives and less ram uh make sure that this actually does what you think it does um because that that thing's performance can change depending on your system and if you have a really overpowered system you or may not see all those performance hiccups that other people are going to experience so that is just something to keep in mind uh but this is i guess basics of scene loading we we'll be picking this up in another video to kind of expand on this i talked about using three scenes we're probably going to look at that next and also being able to persist one scene and keep the other two sort of in flux so we can swap them out and unload them so that is that is the next plan uh so hopefully this is useful and you can use it in your projects uh i i tried to keep this as symbols like i know there's just how do i load a scene that seems like a useful thing so hopefully we cover that here um i'll post some links in the description to some of unity's documentation that goes through a lot of the same stuff um their code is fairly similar to mine so hopefully it all just kind of comes out and you can you can use it so that is everything that i have so i will see you in the next video so until then see internet you
Info
Channel: World of Zero
Views: 22,007
Rating: undefined out of 5
Keywords: world of zero, lets make, SceneManager, LoadScene, LoadSceneAsync, Scene, Scene Manager, Load Scene, c#, unity3d, unity 3d, unity (game engine), unity development, software engineering, programming, load scene unity3d, async scene loading, additive scene loading, add scene to current scene, csharp, c sharp, c #, woz, worldofzero, development, game development, script reference, SceneManagement.SceneManager.LoadSceneAsync, SceneManagement, Scene Management, how to, learning, walkthrough, code
Id: Oq2ytDvHTYM
Channel Id: undefined
Length: 21min 20sec (1280 seconds)
Published: Fri Mar 19 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.