This Godot 4 Scene Manager Does it ALL

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
with just one line of code this scene manager handles transitions loading and data transfer between levels should we take a [Music] look before we get into any code let's take a look at what this one line can do so I've got this sample project made with assets from Kenny by the way thank you Kenny much appreciated anyhow what we've got here is a simple Zelda likee dungeon game so that first transition is what you're seeing manage with this line of code then we've also got this uh Zelda style sliding transition and then also this sort of fading transition to simulate you know maybe changing levels or going somewhere darker so how do we do all that with one line of code we're going to be creating this scene manager Singleton or Auto load as they're called in gdau that will allow us to pass the path to an asset that we want to load and Define the type of transition that we want to use now of course yes I did say one line of code obviously there's a lot more going on here inside the scene manager and in the loading screen that's going to handle the transitions but I wasn't trying to deceive you the point I was trying to make is because throughout the life cycle of a game we're going to be transitioning between menus and the game game and different levels within the game and passing data around um I wanted to build a very simple system for doing that because we're going to do it a lot and I don't want the calls to be complex I'd like to just be able to say scene manager I need this go get it for me so here's the basic structure that we're going to be working with we're going to pass that resource and the type of transition we want to the scene manager then the scene manager is going to instantiate our loading screen it'll play the first half of the transition that we selected then once it's at the midpoint where the screen is obscured it's going to load the new content behind that it'll then continue playing the second half of that transition revealing what we've now added and before freeing the previous scene if we're moving between two levels we're going to hand off some data from the old level so that we can initialize things [Music] properly so let's take a look at how each level's constructed uh if I click on the root node here you'll see that the level script requires that we Define a player and then create an array of all the doors in that level so with that understanding of how the levels are constructed let's take a look at the door so the door is very basic it's it's just an area 2D that's one grid size big with a collision shape on it and this door script and the door script is extremely basic first we're going to make sure that we're only reacting to the player colliding with this if something does collide with this that's not a player it's just going to dump out on line 13 once the player does come in here um we're going to emit a signal and pass along the door itself because the door contains a bunch of information that the next level's going to need and after that we're going to look at the transition types which is one of the enes we'll talk about in a second if it's the Zelda level transition we're we're going to use this load function of the scene manager and if it's anything else we're going to use this generic load scene and then we're going to call Q free to remove the door because we've collided with it and this is one of a couple of ways we're going to make sure that we only collide with it once uh down here I'm not going to go into too much detail but these are two very basic helper functions this top one calculates the position in front of the door that we want to put the player when it enters a new level this other one just inverts up to down left to right based on our entry Direction so that we can make sure that the player is facing the right direction when they enter a new room so if I click on the door we can look at these we can actually look at these uh five export variables this first one defines the direction of the room relative to the door so for example if I go back to the level this door here has an entry direction of East which is this way so we Define our entry Direction we choose which transition we want to use here uh how far we want to move the player off of this space when they're entering a room 16 works for all of the doors but in the event we have a funky siiz door or a funky size entryway you can change that on a pero basis this is the path to the scene that we want to load and this is the name of the door that we're entering so if I'm moving from this door to go west into level two I'm GNA come through this East door here so I'm defining West door is arriving at East door from level two so basically what happens is when the player collides with this door it triggers this on body entered fires off this uh player entered door which the level script is listening for and it tells the scene manager what to load and what transition to use and everything sort of goes from there so let's move over to the loading screen I'm going to try to do this somewhat chronologically the loading screen is fairly simple it's a canvas layer that has a panel we're going to animate for the transitions it has a progress bar that we're going to optionally show depending on how long it's taking to load the scene in our case it'll probably almost never be shown we've got an animation player node to handle the Transitions and then I've added a timer that we're going to use to show the progress bar if enough time is elapsed and the content still isn't loaded so let's just take a look at how this works I'm going to start with the fade 2 so the way I've set this up is the first half of the transition is a something two and then the second half of that transition is the same thing but from instead of two and that'll make sense in a second so our fade two just is a basic transition from transparent to Black once it's black we start loading the content in the background when we've determined that content is then loaded we switch over to our fade from and reveal the new content behind it that's basically how that works we have a Fade to Black and then we've got this wipe transition that you saw when we left the menu and then if there's time at the end of this we'll we'll add one more together because it's actually very easy to add additional transitions to the system looking at the code here we start by hiding the progress bar because we're only going to show that after we've hit a threshold I've got it set to 3 seconds you'll have to choose what works for your project if the content loads in less than 3 seconds you'll never see the progress bar which is totally fine otherwise it just sort of flashes on screen and looks kind of crappy so I prefer to hide the progress bar until we know we're going to be loading for quite a while so the scene manager is going to handle adding our loading screen to the tree which actually you can see if I play this and you look at our remote tree Once I hit enter you'll see a loading screen appear and then it gets freed once the transition is complete and the loading is complete this start transition is called by our scene manager we're going to check to make sure that the animation we're using actually exists if it doesn't we're going to push out a warning and then we're going to set it to one that we know does exist this allows us to be warned in our development environment but if for some reason we ship with an error the game isn't going to crash it's just going to use maybe the wrong animation Which is far better than the game locking up on us we're going to store our starting animation name because we're going to need this when it's time to initialize the second half the fade from half and then we start that transition and we also start our timer and then you can see down here this is called by the scene manager after we've finished loading the content behind the middle point of the transition we're going to stop the timer because if we've gotten here before the oneshot timer has gone off then we don't want it to go off while we're finishing our transition we're now using a uh just a the replace string function to go from Fade to Black to fade from black and then we're basically just repeating that same process with the same checks to fade from black instead of to Black and then down here we're going to use the weight command which will listen for our animation player to emit the animation finished which every animation by default emits when it reaches the end of its timeline and then we're going to call Q free to let go of our loading screen and down here we just have two very basic functions uh one is called when our um shut up bird there's a bird squawking outside I'm going to try to ignore it anyway nope I am now done shouting at the crow in the tree like an old man it's a wild ride folks okay so where was I uh this is the the function that's called when our timer uh emits its timeout signal and it'll just show our progress bar and then this report midpoint function um just emits a signal here I'll show you we're actually using this in the animation player so if I come into our two animations you can see we're animating we're animating these properties here that's these little diamonds but down here we've got this function track and when it reaches 4 seconds on our timeline we're actually calling this report midpoint function this is the signal that the scene manager is listening listening for to know that we've obscured the whole screen with the transition and that we're going to start loading the content behind it okay so chronologically uh we've gone over the doors and how that can trigger the scene manager to call up the loading screen now we can take a look at the actual level level's pretty simple um our on ready function disables input on the player just to make sure that we don't move while we're still in transition this determines whether we're coming from another level so anytime our data object which is this level data handoff I'll show you this in a second but if our data is null meaning we didn't get handed that packet from a previous scene then we're not transitioning between levels and we we can just go directly into this enter level method which performs a similar check so if it's not null that means we are transitioning from a previous level so we should initialize the player location to be in front of the door that we came through and then of course once we've put the player where they need to be we're going to show them we're going to enable input and then we're going to call connected doors I'll jump down here I have actually two functions that connect to all of the doors in our door array and listens for whether a player has walked into it and again you're you're you're going to see this running theme before we try to connect to it we're making sure we're not already connected to it and before we disconnect from it we're going to make sure that we are connected to it and then we can call these functions when we start the room and when we enter the room to make sure that we're not leaving any signals connected to objects that don't exist anymore I think gdau does a pretty good job of handling that with garbage cleanup but I prefer not to leave Loose Ends anyhow so so that's your um your enter level this is called by the scene manager once our transition is complete this is our helper function that we called here and basically it just looks at the door data that we passed in pushes them into the appropriate location and makes them face the appropriate way so if I play the game you can see I'm facing left because I'm walking left and I end up getting pushed 16 pixels uh into the room and I am facing left if that method weren't there to orient the player when it initializes and reveals this player he would be in the correct location but he would be facing to the right which it's not the end of the world but it's a little detail that can take your players out of the immersion of your game all right so back to the level uh so this is the last bit of the level um at least for our sample project which doesn't do very much uh in our door we emit this player entered door signal and back in the level we're listening for that and this is where we call that disconnect from doors to make sure that we don't fire any more of those we're going to disable and remove the player then we're going to set up our data object so this level data handoff I'm going to show you it's just a very basic it just holds the name of the door that we're coming in through and the direction that we were moving if I go back to the level you can see we're creating an instance of that data we're adding those two bits of information and then we're pausing a process that I we're not even using but whatever it's not going to hurt anything so now we can look at the scene manager which is going to have the bulk of the code in our example project here um I'm going to walk you through all of it obviously it's not as scary as it as it sounds we're just going to break it down piece by piece so if we go all the way back to the start of the game where we called load new scene we calling load new scene we're passing in the path to our first level and we're saying we want to use our wipe transition so I'm going to actually uh control click on this to take me the definition and I'll walk you through this so the first thing we're going to do is store this transition in a property so that we can reference it later when everything is loaded to make all of our other transitions work so we're going to need this down the line after our content is loaded this is where we initialize our loading screen and add it to the scene tree and then like I said start that transition and then we're going to call our load content function which is fairly simple it takes the content path we've been working with it checks whether we're using the loading screen it'll be not null if we've added it to the scene tree because we're storing it in this variable so if we are using the loading screen we want to wait here until that animation is played in and obscured the whole screen uh if we're not which in the case of the Zelda transition we're not using the loading screen which is a personal preference if we're loading massive levels you probably do want to display some sort of loading graphic but if you think back to the old school Zelda games the dungeons didn't show any loading they just kind of smoothly transition from one to the next so I chose not to use the loading screen we're still doing all the background loading and waiting for that to complete before we start our transition the difference is we're not actually using the loading screen to display any of that loading progress or handle a visual transition for us we're going to store the content path here uh that we've passed in because we're going to need that to check in on our loading progress and then we're going to start the loading process through this resource loader load threaded request and then of course like we've been doing we have a little check here uh that will dump out if we pass in something that doesn't exist and we're going to emit this content invalid signal so I actually I'm going to skip down to the bottom here for a second these are the functions that get called when any one of our four signals fire off if the scene manager was a Choose Your Own Adventure book these are the four destinations we can end up once we've started loading a piece of content so up here if what we tried to load doesn't exist we're going to emit our content invalid signal that's going to dump us out in here it's going to end that function because we're returning and then it's going to print out this error so that we can debug it similarly if something does exist but it fails to load we'll dump out here and get a similar um error and then these other two are for when we seed so if we finish loading and it's well we'll get to that in a second so jumping back up here once we've passed this check and we know that our content does exist we're going to create a new timer it's a check in on our load progress every tenth of a second defined here by this weight time so we connect it to this monitor load status every tenth of a second we'll run through this function um and this is just adding it to the tree you need to add it to the tree in order for it to work and then you need to start it so every tenth of a second what we're going to do is we're going to Ping the resource loader with that content path that we saved and it's going to give us back a load status um which is going to come as this array because we're loading a threaded request we might be loading separately multiple things and they would all come as a different element in the array we're only ever going to work with one so every tenth of a second we're going to request a load status from our resource loader and it's going to give us back one of these four status messages uh a zero indicates an invalid resource in which case we're going to again emit that content invalid signal and then we're going to stop our progress timer to to kill this Loop if we get a one that's a good signal that means we're still loading and it's going to give us back the progress so load progress zero because it's the first element in the array because we're only loading one array we don't have to track anything beyond that we're going to get something like 0.1 which means 10% loaded uh anyway anyway if I go over to my loading screen um in the case of that 0.1 we're going to multiply it by 100 which is going to give us a value of 10 and it's going to give us a 10% load so in the case of something that loads properly it's going to continually drop into this section here and update our progress bar until ultimately it gives us a three which is our thread has finished loading and in that case we're going to get rid of the timer and then we're going to check back to that transition we saved up at the top and if it's Zelda we're going to drop into our content finished loading for Zelda and if it's anything else we're going to drop into this other one so let's take a look at this um content finished loading this is the method that we're going to drop into I'm sorry I keep using method and function interchangeably and for all intensive purposes they're the same thing if I say method just think function so if we've dropped into this function first thing we're going to do is store a reference to our our current scene in this outgoing scene because that's the scene that we're going to discard when we're finish the transition so when we go from the start screen into level one when that's all done we want to discard the start screen which is the reference is saved in the outgoing scene um then we're going to check to see if we're working with the level so this content if we come back up here when we emit this signal what the resource loader gives us back is I suppose it's a packed scene more or less uh because we can I'm in calling the instantiate function on it which means that when we emit this signal we actually receive the content that we've loaded inside of this content variable at that point we can now run checks against this content so right here we're saying if the current scene is of data type level meaning this is a transition from say level one to level two then we know that that the current scene has a data packet for us so we're going to get that data packet by calling get tree. Curren scene. dat so that's this right here this data variable and we're going to store it in this incoming data variable because we're going to need that later to pass into the new scene and then we're going to do a similar check against that content like I was talking about so at this point if we're transitioning from say level one back to the main menu this will work and we'll grab a reference to that but then we're going to get down here we're going to notice that content is start screen which is not of data type level and then we're going to skip over this and it's never going to happen and that's important because if it tries to access the data property on the start screen it's not going to find it it's going to crash so if we've gotten this far that means our screen is obscured by the first half of the transition we've harvested whatever data it might have for the upcoming level we can get rid of our outgoing scene we don't need it anymore so right here we're going to add our new scene to the tree and we're going to set it as the current scene so the next time we do this gdau knows that this is our current scene and if we try to retrieve the data from this new scene next time it'll be stored as the current scene and then down here is where we finish our transition so added the new scene we're going to tell our loading screen to finish the transition so if we've paid Fade to Black now we're going to play Fade from black if we're working with a level we're going to want to place the player in the proper location then we're going to wait again like we did before we're going to wait for the animation player to finish the fade from black and then again if we're working with a level we want to call that enter level function and kick things off that's the the process that takes you all the way from initializing a scene load through the transition passing the data off finishing the transition discarding the stuff we don't need um for our standard transition which for for right now is just the fade to and from black and the the white transition if on the other hand we've selected the Zelda transition which again is this guy no not that guy this one so kind of smoothly fading up and down left and right so on and so forth we're actually going to do that differently again we're you know getting the data to pass back and forth like we did and then instead of using the Lo screen for the transition I'm just uh tweening one level in and the old level out basically and we can use the information stored in our incoming data on the direction that we're moving to determine the positions that we want to start in and move each level to uh by multiplying by our vectors and the size of our level or the size of our game screen which I'm doing I've just hard coded up here in a larger project you probably have these constants in a different autoload in the interest of Simplicity I just put them on top of this file so this basically sets the new level just off screen and moves both the old and new level such that the new level is now centered on the screen and that the old one is pushed off we're then waiting for that that tween to finish and doing our initialization and cleaning up our old scene and then again setting the new scene as our current scene uh you could do this with uh tweening cameras around instead of moving the levels themselves around uh either works I'm sure there are trade-offs to both I spent many many years working as a flash developer um where there were no camera systems at least not by default and so I just got used to doing things this way I do have other projects where I'm using um the built-in camera system I just to be perfectly honest honest with you this is the first thing that came to mind and it works so you could certainly do it either [Music] way so let's go over to the loading screen before we wrap up and just add one animation together let's take a look at this real quick so we have this we have this transition where we're going down into this dark basement and it fades to Black and on the way up it fades to Black well what if we wanted to fade to and from White so that when we go downstairs it's fading to Black because it's dark and white coming up because we're coming up into the light how would that work so we can click our animation player I like to go to our reset node just to make sure that we're working with the more or less the idle state of the scene we click on animation new and we're going to say Fade to White and that's going to give us a new animation so let's select our panel come over here into visibility and we'll set this self modulate to White and we're going to pull our opacity all the way down to zero and then we're going to key frame that it's going to ask about a reset track you can hit create and then we're going to bump this forward to 3 seconds like the other one we're going to set this to White and we're going to key frame that again so now we have our Fade to White animation we're going to set this to 0. five so we don't need it to run that long we're going to add our track on our loading screen move it one more point4 just past when the F fading completes and we're going to report our midpoint and that's all we need to do for fade 2 white now we need to create our fade from White remembering we have to swap two for from set this to 0. five as well and we can key frame this because that's already where we want it to be move it to three and now we're fading from White so we're going to go to transparent we'll key frame that and that's all we need to do we don't need any method calls because this one will run to the end and it will fire off where is our scene manager we're waiting for this we're waiting for the animation player. animation finish so it's going to do this fade out and when it hits 0 five it's going to emit this signal and we're going to continue through our code so now that we've added our two and from we can go over to our door and we can just add let's add right here another Fade to White and then let's go into our basement scene select this door and instead of Fade to Black let's select Fade to White so now if I enter this we still have our Fade to Black but if I go back up we get our Fade to White animation that's pretty much all there is to [Music] it okay so there was one last thing I wanted to show you which is the loading bar so I've come in here and I've toggled off where we hide it so that it shows immediately which will also demonstrate why we hide it because it's going to make the transitions look a little goofy because they're so fast this can be kind of hard to demonstrate locally because everything loads so quickly but what I've done is I've added five very large jpegs to the background now when I go downstairs you'll see we actually do get our loading progress and then it completes and of course on the way back up it looks awkward because we don't need it um if we come back into our loading screen and turn this back on we may not actually see the loading bar depending on how how quickly it happens which is fine because it actually doesn't take that long to load you see that transition didn't feel like it was hanging was a little long compared to the others but not so long that you would dump out of the game if it took significantly longer than that you would want the loading bar to show up so that demonstrates the loading bar and why we time it out okay now to the actual outro we did it I hope you found this helpful and if you did please consider a like subscribe or share to help me reach more developers just like you and if you're looking for more coding content you should check out my let's make snake series it's a great way to build your first game in Gau until next time be kind to yourself be kind to [Music] others
Info
Channel: Bacon and Games
Views: 16,781
Rating: undefined out of 5
Keywords: godot 4 scene manager, how to change scenes in godot 4, how to switch scenes in godot, how to change main scene in godot, background loading godot, transitions in godot, godot load level, progress bar godot, loading bar godot, godot 4.2 tutorial, scene transition in godot, godot 4 tutorial, kenneynl, animationplayer godot 4, animationplayer godot 2d, godot resource loader, godot threads, godot 4 autoload, godot 4 singleton, godot scene manager, gdscript tutorial
Id: 2uYaoQj_6o0
Channel Id: undefined
Length: 28min 49sec (1729 seconds)
Published: Sun Dec 24 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.