Playing and Stopping Scenes (and Resetting) // Game Engine series

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up guys my name is achana welcome back to my game engine series so last time we talked about uuids and introduced them into the engine check out that video if you haven't already and today now that we've got uuids let's talk about how we can actually hit play and set off our scene runtime because so far what we've been doing is simulating an existing scene whereas we know that in reality what we probably want to do is basically load up the scene that we've been editing in like a runtime state so what does that even mean and how does that work okay well let's let's jump into what we've got so far so we've got this um uh basic setup that we established i think last episode and maybe during the box 2d kind of physics episodes this is what we have if we hit play it'll jump to whatever the game camera kind of is and then obviously we will see this kind of physics simulation taking place right that's all good but as soon as we hit stop obviously we don't reset anything um you know it would be ideal for you to reset everything right and that's probably another thing we should do is um not display the gizmo or at least display the gizmo in the correct location when we hit play using this camera instead but anyway the point being that you can see that we obviously don't reset anything when we hit stop everything just remains exactly as it was because all we're doing when we hit play is rendering from a different point of view and then running the physics simulation which allows us to modify our transform component data that's all that is that is actually happening here which is not good for a number of reasons or on a number of levels really because the thing is if you think about the issue at the moment yes it might be true that all we really need to do is just like remember the transforms of these objects or of any physics object and then just reset it when we hit stop right but that's not really sustainable and it's also not going to scale well because at the end of the day there are a lot of things that can happen during a scene right i mean if you if you think about involving a script runtime i mean just think of a game made in like unity or something like that right we could have a script which spawns the entire level procedurally does all of this stuff right sets up prefabs you know spawns them into the world runs physics simulations runs other code that generates like assets like textures even you know the amount of work that we can do once a game starts is i mean it's honestly infinitely it's infinitely large right like we could do literally anything especially once once we have like a script runtime so what we kind of want to do with this scene is not necessarily reset it what we want to do is actually create an entirely new scene based on whatever this editor scene is right so that we have physics 2d this is our current scene right when i hit play i want to be able to basically load this scene in kind of a runtime fashion i guess you know establish the box 2d world and anything else that needs to be kind of present for a real scene but then like you know run that scene instead and then when i hit stop i can just delete that scene you know release it and then basically change the scene that is at play here in the editor to be that original editor scene that we were editing right so in summary i mean again long story short if you actually think about what needs to happen here we just need to copy whatever scene is currently being displayed here we just need to copy this scene into a new scene which we can call runtime scene and then basically switch the editor to now be kind of to use that runtime scene as the context for literally everything right but then when we hit stop switch that contacts back to whatever the scene was that we were editing so how we're going to do that one other thing i want to quickly point out before we go there someone i think pointed out a bug where if you are playing and then you try and load a scene it will just crash so we should probably fix that before we get into it into this but other than that that's kind of the plan for today just to make that kind of copying behavior work so if we go over here so okay so open scene i guess we just won't let scenes be opened if we're running or rather we'll stop the scene first because we still want to load the scene probably so if if we do open scene if the current uh state scene state equals let's just say if it doesn't equal edit right then we're just going to run stop scene or scene stop on scene stop right so that should fix that bug let's take a look at that make sure that works all right scenes physics 2d i'll hit play and i'll drag it in again okay so you can see it just stops it which is kind of what you would expect okay great um i mean we could bring up a dialogue being like hey are you sure you're doing this maybe your hand just had a spasm and you accidentally dragged that in i don't know but we'll leave it like this for now so that's that that's that bug fixed okay so copying scenes and all of this architecture how is this going to work so of course this was kind of discussed and i did implement this in the last live stream right so i'll kind of be using the code that's already actually present in the in the dev branch not to be confused with hazel dev it's not hazeldub this is just the dev branch on the github uh repository right that's there'll be a link in description below so you can always you can obviously kind of see the code that's already been written as part of the live streams that happen on twitch or tv slash the churno but anyway getting into it so the thing that really needs to happen here is we obviously need to uh basically have some kind of runtime version of this scene now we have a scene called active scene and this is fine but what i'm going to do is i'm like i'll leave active scene like it is but then i'm going to explicitly set up two different scenes an edison scene and a runtime scene right now you don't technically need to retain three kind of scene refs or three pointers here because i mean at the end of the day there's really only two scenes there's the editor scene and the one that we're currently running i'm just i've written it like this with three actual scenes just so that it's a little bit more verbose and will make hopefully more sense so in the beginning what happens is well not in the beginning but when we open a scene what we want to do is uh basically instead of setting the active scene to be this new scene that we're loading over here we want to specifically if the decentralization worked out i want to set the editor scene to be this new scene right that's kind of what's going on here instead and then we can do all of this resize stuff but then what i'll do is kind of when that's all done and maybe based on some other states i'm going to actually set this to be the editor scene so the active scene and the editor scene are actually kind of equal i mean they're two different references here that they're two different shared pointers but obviously the object itself is the same so these are this is what happens when we deserialize the scene we load it into the editor scene and then we set that to be to be active now when we hit play though we don't want to just do one runtime start what i want to do here is i actually want to set the runtime scene to be um some kind of like i don't know maybe we'll make a function called copy uh well the way this works in hazel dev it's actually called copy2 and then you can give it a target scene to copy into but i'm actually just going to make a scene a scene copy function and it's going to return a new scene for us right and then so we'll create that runtime scene and then what we can do is well we can call onruntime start and then we can set the active scene to be the runtime scene right and then all we have to do over here is make sure that we obviously call runtime stop over here and again whether or not you do this on the active scene or on the runtime saying they should be equal so it's not really a big deal but the point is we're going to change the active scene to the editor scene now by doing so right um i mean by doing so the runtime scene here obviously like the um if we keep track of all of these reference counts in our mind the editor scene is always going to be parked here right and i'm beginning to think that maybe this is even kind of over complicating it so well i i but i do think that the distinction between the names is good i don't know because and you're about to see why i'm saying this in a minute but uh what we're doing here is the editor scene will permanently be parked in the editor scene shared pointer right so that will always kind of exist in memory but here if we do the same thing with the runtime scene that's obviously not something i want to do because once a runtime scene gets stopped we can basically delete it right and the simplest way to do that is probably to just set runtime scene equal to null pointer so what this will do is uh reassign runtime scene to be something else right which will mean that the reference count will be decremented and it doesn't matter really where you do this like we could do runtime scene on runtime stop right runtime scene equals null pointer then activecalls editors in but the point is as soon as nothing obviously has that run time scene anymore then the reference count will fall will fall to zero and we will completely delete that object from memory so the idea is when we hit stop obviously since nothing else is holding a reference to the runtime scene it will in fact be destroyed uh yeah but it's important i guess not to um and you can probably tell here that there's no need for this runtime scene right because active scene is runtime scene and it only exists for that lifetime but i've just written it this way so that it's um a little bit more kind of aware but again i'm i'm doubting myself as i'm recording this episode because i don't know maybe just makes sense to have an active scene and an editor scene and then obviously what you would do is just basically well you wouldn't need this you just said active scene equals to scene copy active scene or editor scene right so we make a new scene out of that maybe i'll do it that way you guys can let me know what you think in the comments below didn't really plan this to be honest but we could make the active scene copy the editor scene and that's obviously a reassigning active scene to this new scene that we've made right assuming that everything goes okay which it should um and then we just do active scene stop active scene null pointer or rather we don't even have to do that we just set active scene to edit scene and since active scene is the only thing that ever held onto this kind of new scene that we've made it will then get destroyed so it's a little bit cleaner this way but it might be a little bit harder to understand because active c anyway whatever so the thing with active scene is that everything else kind of works with this design right like you can see that basically like you know we still have active scene on update active scene on render uh wherever that happens or on update sorry does the rendering active scene on viewport resize you know what i mean like we've just changed the active scene to be this new scene so everything else will work we don't need to do any kind of like if it's the runtime update the runtime scene um no it's all kind of going to be inside active scene and of course that would have worked if i had the runtime scene pointer as well it doesn't matter anyway so it's in copy editor scene this is kind of the meat of it right so how are we going to write this function well the hardest part of copying a scene is copying the end registry right because it doesn't really have a good copy function or clone function i think it used to but it's been removed and i think they're planning to add it back because this isn't really traditionally like it's not really traditionally a behavior that the entity component system should really support i mean it definitely should because there's so many reasons too right but in terms of the scope of an actual ecs you don't really copy an ecs usually right it's kind of the meta programming that you do around the ecs that would require you to copy it within the ecs itself there's no reason to your registry kind of just exists with all these entities you don't really copy it right but for this purpose we obviously need to copy all of the entities all of the components that are inside here and remember it's really just the registry is really just component data and then we have entities which are identifiers into certain kind of components right so that we're aware that like our camera has a camera component and a transform component with these values so the components are really what we are trying to copy but we also need to somehow retain the entities so that we know which components belong to which entity right because that's equally as important as just having the physical component data there but anyway so what we'll do is um i guess i'll just maybe i'll do it up here static ref scene copy right and then this will take in just another scene that we are going to copy um i don't know maybe i should do this at the bottom i like putting static stuff at the bottom but if it's to do with construction i generally put it here so let's create this okay cool get rid of all of this extra fluff so ultimately like the point here obviously is just to create one of these scenes so i'll call this new scene right now this will just be create ref uh scene now if we look at what a scene actually is i mean it's the registry but then it's also just a viewport with height and a null pointer kind of box2d world which really is only needed for the runtime scene so if you bought width and height i don't know if we need to copy that the reason i'm saying that is because if we look at editor layout i think it just sets the viewport like every frame maybe so set viewport size edit the camera active scene on viewport resize well no actually it so it gets the viewport size from the frame buffer from the frame buffer specification okay i i think what it probably should do here because yeah because for we don't have a scene renderer yet that's right yeah okay i guess we probably should do that just because obviously i don't think the frame buffer is going to change and then therefore we won't have the correct values in this new scene so what we'll do actually is as the first kind of step over here is we'll just copy those values right so a new scene um and by the way i could use a copy constructor i'm aware i just wanted to kind of make this return a ref specifically and be a little bit more kind of explicit as to like you want to copy this um so it's not like an accidental copy so we'll do new uh scene viewport width equals a viewport yeah height is obviously what i wanted um and then we'll do height and sorry m is um this is static right so we need the other scene as well so other is like the source that's like the destination i could kind of rename the source and dest but i guess we'll keep it like this to be deliberately hard right okay so the way this is gonna work is there's basically two stages to this we need to copy the entity identifiers right which means we need to create entities in this new scene but then we also need to patch up their components and copy the components and it would be it would be good to try and kind of do this obviously as efficiently as possible so what i what i'm actually going to do and the other really important thing right is that we can't simply just create entities we actually need to make sure that we use this new function we wrote last time to retain the identifiers of the entities because obviously those ids are going to be used for a lot of things and they need to match right if another entity is like a child of some other entity which i know we don't support yet but we will right then obviously it needs to know what its parent is if it like some entity references another entity again it's probably going to do that internally via the uuid so therefore it needs to actually match right you can't just create this whole new scene with completely different identifiers because then nothing will like the relation between objects and between entities will be lost so we need to specifically do this right so the way we're going to do that is basically we're going to just look into every entity that we have and the best way i think to do that is um basically to just establish this kind of okay well the first thing i might do is pull out the registry so we'll say um we'll call this like source scene registry and this will just be sourcing being other so other m registry right this is just a little alias just to make it a bit easier and this will be our kind of destination scene registry which is going to be this new scene and then out of there what i'm going to do is actually i'll call this id view we're just going to basically ask the source scene registry where we're copying from to set up a view with id component right because what this is going to do is basically i mean ultimately this is going to give us every single entity that we have right because obviously every single entity is going to have an id component and then we're going to loop through this all of these id components that we have and just create entities and we can do that by basically well there's a few ways we could do that i mean ultimately at the end of the day we're just trying to call um new scene create entity with uuid but clearly we need two things a uuid and a name for that entity so that's what we're gonna pull out here um the uuid uh will just be e dot um well i guess we'll just use we won't make it in like a hazel entity sourcing registry get um id components dot id and sorry we need the the actual entity and then we'll also get the const order i guess name which will be the tag component right so we have a con string here so uuid and name right so what we've done here um is we basically created all of these new entities so every for every entity that we had in the old scene we've created a new entity in this new scene right now they are going to have the same id the same uid however within and within entity right within that library the id that they have is going to be different most likely right so what that means is that again like that's fine because we don't trust that anyway that's just uses an indexing for a data structure right uuid is what we actually use to identify entities and that's the way it should be so the last thing that's going to be a problem here which we might revisit later because we'll naturally see this this pop up is we need some way to actually know which entities you know which of these entities that we've created here corresponds to which uuid now we could ask it to please give us all the entities without with id components let's iterate through them and let's try and find you know an entity with this id right why because we obviously have to give it components now that's the next step so we'll talk about how we can do that with a little bit less kind of finding by just using a map basically but the next step is to copy components um now the two components we don't need to copy right is id component and a tag component why oh well um yeah id and tag why because this is what we've we've already copied them right so create entity with a uid obviously adds an id component with that id and a tag component with that name right it has the transform component however we still have to copy the values from that transform component so we'll have to do that here in a minute but the point is that id and tag should be intact and now we just need to copy everything so how do we do that well i'm going to write this in a very simple easy to understand way that we will probably change a bit later because i just want to introduce it kind of softly but what we're going to do is we're going to write a function called copy component and we're going to basically call it for every single component right it's going to be a templated function just trying to be a little bit relaxed here on the templates and stuff so template type name t i'll call this component actually and then this is going to be called copy component um so how do we copy a component well a few things has to have has to happen here right so we need to um basically look it up from the source registry see what it is and then copy it into the destination registry for a particular entity and this is again where things get a little bit complicated because we can easily pass in these registries right so it's just going to be ant registry so we'll do this um i guess i'll put the destination first kind of like uh mam copy and stuff so we'll have the destination registry the source registry um but the problem is that whilst uh you know we can copy the components if they exist um and we'll talk about that in a minute we obviously need a little bit more information than just this is a component right because a component has you know so like the component is its data but then we also need to kind of link that component to an entity because an entity has to own a component but the problem is if we're arbitrarily copying components here well yeah we have a bunch of entities in destination we have a bunch of entities in source but as far as ant is concerned their ids don't match right uuid is what we need to use to match them up right so how do we know which component belongs to which entity and this is where it gets a little bit tricky so ultimately though let's start setting this up we just want to look we just want to establish a view right of the source registry for whatever component thanks for that correction for whatever component we're trying to copy so in other words in this case it's transform component i'm passing in the destination scene registry and the source scene registry so i've got this i've got this transform component that's what component is i'm establishing a view of of the transform components which again should be laid out all together kind of in memory right and if that is the case then obviously it's nice to iterate over all of them it should be quite efficient so then we'll go ahead and we'll just do auto e uh in view right but again like what needs to happen here is i need some way now to because i know the source registry entity is e right but i don't know where it should go into the destination for which entity should i be copying this transform component into right that's what i don't know but that's again where that uuid comes in so if i just do a source dot get right it's going to be id component for e right then what i've done is i actually know what the uuid should be right that is the uuid of this source entity which can tran which contains a transform component but what i need to do is somehow figure out where inside and that id component is for that new entity this is getting very complicated and it's hard to explain it really makes sense i probably should just draw something but i think you guys are hopefully getting the point maybe i'm over explaining this but my point is that again we've established the uuid of the source entity from the source registry that we're copying from we just need to know where to put it into the destination and we know that obviously the id is going to be the same but how do we communicate that to end right because ant is the thing that is actually going to store this like we need the ant id right which is ants entity this is what we need so that we can add a component to it but we don't have that right so this is where um we're going to introduce a map so that we can actually map these id components into that because the other option would be to basically um set up a view right an id view or something into the destination registry so we could do like a destination view id component right and then obviously we could iterate through that so that would be like d e destination entity id view and then see if d e um you know get uh sorry um what would it be uh id idview.getidcomponent uh d e right dot id equals this source id right and if that's the case then d e is where we add it so we can do d e you know in place um d should be an n t right no sorry it's from the register obviously so it'll be like dst dot in place um whatever we're copying you know four there's a nightmare for the this entity right and that's how we would basically and we'd pass this along into the copy constructor like um so well we need to actually get the component as well right so we'd need to retrieve the component as well like whatever this is so that would be like auto component equals source dot get component e why does it keep capitalizing it come on go away i've never actually done this before so if i try to type in like transform component which it doesn't even know then i think it should be able to maybe like look it doesn't even know do i have to do hazel transform component does that work thanks bro maybe that will help with intellisense but anyway and then you pass in component so hopefully this makes sense right this would work and this is fine but we have this like extra level of like for you know we get a nested forward we have to iterate through all the entities in our scene just to find it like that's really really annoying considering we already have the both the uuid and the entity kind of thing here so what i'm going to do instead right of doing it this way is i'm going to basically set up something um and this can be i don't really care what this is it could be unordered it could be ordered it doesn't really matter i guess we'll put it into an unordered map um because we haven't i don't think we've implemented the lesson operator anyway and we have the hash operator so we'll do uid and then end entity which is really just like a uint right but the the point is what we have now is an ant map and we're just going to make it like on the stack over here i'm like we're not going to set it up as a member or anything like that doesn't need to be and then what we'll do is into copy component we'll pass in this end map right and then i'll grab the end map like so it's going to be a const in fact the source can be const as well the source registry um and we'll call this antmap right and what so what does this do it avoids this entire search right because instead of this what we do is like we have the id right it's over here let me just bring this out and try and be as clear as i can um [Music] right we have the source id right which is the same as the destination id so now all i have to do is basically just do end map dot at right uh uid and that gives me the actual entity [Music] like identifier so ant id that's it right that's it so this one kind of line avoids this entire kind of search here which is obviously going to be very good for us so uh and that will only just grow when you have you're basically reducing like this kind of linear search um with uh you know just like a constant time lookup right so order n i guess versus order one so anyway the point is uh this is a better way of doing things and that's why we've done it that way i had a pretty long day today by the way so if i'm a bit slow i apologize um so yeah that that's basically it right and then we can actually get to the meat of this which is copying the component so we know which entity is kind of the destination receiving entity this is the entity this is the destination entity id i'll be really clear about that right so the destination end id so now what we can do is into the destination registry i can now here's what i want to do i want to do in place or replace why because it already has a transform component so i want to replace it with this new transform component right whereas for a lot of components it won't be replacing it'll just be adding so for a camera component that obviously wouldn't exist so i'm actually creating it so in place of replace is a good function for this so what i'm going to do is do in place or replace and then we're going to do whatever component it is that we're working on right which is in our little example as a transform component and then we're going to actually put in this component right oh and of course we need the entity which is destination cid right and again what this will do is it forwards all the arguments into the actual uh you know constructor and of course every one of our components has a copy constructor here it is so that's what we're doing here we're just using that copy constructor to basically copy it now you know we could probably make this a little bit um cleaner but i'll leave it like this because i think it makes more sense and then we basically have to do this for every component that we have now as i said i'm going to do this the kind of easier way um what we probably should do is establish some kind of component registry so like a component type registry right where we just have like all of the components that are components and then we can like kind of i don't know constexpr statically compile time iterate through that and then call copic into component write a template which expands that into every single uh component that we have right if someone wants to write that by the way then maybe like open a github issue on the repository and just write like an implementation of that i'd be happy to review it and accept it in the next episode uh i'm doing it this way for now because first of all i think it's just going to be a little bit more clear without just complicating the code so that people understand like the basic premise of how it works and also because i'm i'm not going to pretend i'm a template expert it's probably going to take me a little bit of time to actually write something like that so uh but if you want to then that would be great because we will we will do that eventually like i'll probably switch to that in any way uh okay so let's take a look at all the components we have so transform sprite renderer uh we don't have that many so i'm not gonna bother like um you know kind of going through all of them and that's why this is also okay i think that actually might be it do we really only have five what do i have oh yeah native script which i think is right on the camera i'm doing it in the same order as it appears over here all right so that's it um now we've copied everything and of course i think that should be it so we've copied the entities we've created new entities right so create let me just uh just reorganize this so create entities in new scene and then of course uh copy the components right which is the actual data that makes up the entity so that looks good to me i don't hopefully i haven't introduced any bugs here um but yeah that's actually pretty much it that's all there is to making this new scene we should now have a scene that is identical to our other scene apart from maybe some different um like entity ids like ant ids very hard to distinguish between between the word and c and then the library entity because they're called the same thing but anyway you get the point all right great so back over here um what does this mean uh well i actually think it will just work possibly so let's it'll be scary let's try and um compile this around this and we'll see what happens okay so here is our physics 2d test scene let's hit play okay we get a crash that's okay um yeah one thing i should have done is probably in a certain oh well actually that's a bit silly so this maps are obviously empty so we need to actually add the stuff into the map i can't believe i forgot that so um basically again once we have the destination entity which we've created over here right because what it does is it returns an entity i'll call this new entity right a new entity is going to contain an id which i think if we just use it as a s so how do we get the handle out from it well actually it it has an implicit cast so we can basically we should be able to just do and map the uuid is uid equals new entity just like that and we can obviously be a little bit more explicit about this if we want but again the type is just that so it should be fine right so there we go we um we are putting that in and of course you know you could cut that whole thing out if you wanted to and just do that right but i'll be a little bit more explicit as usual okay great so now and again you know what we could do is it's very it's very unlikely if this to ever really happen but since we are using at and not find we could put in a little assert to make sure that um nmap find uh was called uuid doesn't equal and map and just to like you know be like this shouldn't happen hopefully it makes more sense kind of in the code i guess assets by the way they're not just i think they're not just for like actual debugging and validation during runtime like like they usually are used for they also make more sense on code right because you're telling the programmer here that this should never happen pretty obvious right so they kind of they actually document the code pretty well as well all right so um hit play we got our play hit stop we've got our stop right so what we have achieved here is again we can hit play we can do whatever we want with our scene um you know and obviously what's going to happen is when we hit stop it's going to reset pretty amazing stuff now the last thing i want to do today actually which i almost forgot about is i just want to be able to duplicate entities right so we have um the ability now to copy components right and because we have the ability to copy components we should also be able to kind of uh introduce this kind of uh duplicate function which actually i mean copy component is a little bit different because this uses like an ant map and it's clearly made for scenes but what i want to do is uh just write a function here called duplicate entity um entity entity right and this is just going to duplicate it so what do we need to do for duplicating an entity well let's create a new entity now obviously in this case we actually do want to do create entity without uuid right we wanted to generate a new id for it because obviously we're creating a new entity so the name is going to be uh well i guess we'll use the same name so we can do entity get component or is there just a get tag no well let's add that that's kind of nice so we have get uuid so i'm also going to do a const std string get name right and then it's just going to return tag component tag we should probably call them names because tags can be used for other things but uh that way we can just do get name and everything looks good and then finally what i want to do is i actually want to create a function called copy component if exists right so this is going to be similar to this it's just a bit different because we like this is within the same registry right so it's obviously way more kind of simple but what we do need to know is the source entity and the destination entity right so and i'll call it copy component if exists because obviously if it doesn't exist then we won't copy it and you'll see how this is going to work it's very very very simple if the source entity has the component every time then destination uh dots destination add now the problem here is that again we want a bit of like that in place or replace thing so what i'll do is i'll actually copy this and i'll call it uh i guess what should i call it probably like add or replace component something like that um add or replace component so we don't need to set this um because it's fine if it already has it uh and then we'll just do in place or replace that's really the only difference and then i guess we'll do this garbage as well but that's it right and then this again for things like transform component it will just overwrite it but then for things that don't um have it right because i'm talking about the destination just because when we create the destination obviously it's going to already have a transform component and that kind of stuff but we'll do um add a replace component component visual studio and then um uh you know we'll have to do like source i guess get just going to copy this because otherwise it's going to capitalize it and i think that's it right so if the source has the component we add it into the destination entity and that's it again this all happens within one registry so clearly it's kind of different than what we had uh before now all of the components right we'll do it the same way again once we have um the uh kind of component registry we'll just iterate over it but what we'll do is let's do so this is going to be copper components this and then we'll call it i don't like this isn't okay that's okay though so destination is new entity source is entity not the best um naming as usual but that's okay all right we'll go ahead and uh go through all of these as quickly as we can and that's it right so we now should be able to duplicate entities so if we go back over here um we i'm going to make obviously a way for us to be able to do this through the editor i'm just going to make a control d so we have uh on saying stop on we'll just make a function called on duplicate and see we should have like some kind of command thing maybe soon but this is like really simple this is just gonna be like if um [Music] i guess if m scene hierarchy panel get selected entity if that's even like if we've even got anything selected then we'll do em edit the scene now uh this i guess should only happen if we're in edit mode right so if if scene state doesn't equal edit we'll just return but otherwise oops just close the file um but otherwise we'll just do editor scene duplicate entity and then it'll just be this so i guess i'll do i don't know should we write code like this probably not i don't know if that works on all compilers these days we'll just do this so um yeah and then we'll just basically just duplicate it so how do we how do we call this well ctrl d as i mentioned so if we go over here um we'll just add another one of these commands maybe i don't know those are also commands uh scene commands maybe i don't know uh d and then obviously if we hit just control i don't know if i like this whole on for this but whatever f5 so yeah so now we should be able to duplicate entities which is actually going to be oh errors everywhere never mind so in place or a place uh didn't seem to work out because i have parentheses in the wrong place all right loading in our physics scene so this is actually this duplicate into you might be like why am i adding this because it makes it so much easier to make little levels right so all i have to do now hopefully this even worked is if i hit control d ah didn't work this is just fun so create entity with something to do with the tag error characters okay let's debug this so what error that was just an error entity.getname okay so that didn't oh well so what if it doesn't have a name but it has to have a name right because if it doesn't have a name then it has it has the name entity if this if it was created with an empty name so definitely should have a tag right so i wonder why um wait did i i definitely had something selected yeah i did get name get component attack and part another tag const string okay tag component tag uh that should be okay let's try and debug this a little bit we'll see what the entity handle is if it lets us so let's go back to duplicate nc oh it's got an empty handle of zero that's weird so we didn't have anything selected handle zero then why did that pass that oh cause zero isn't null so i guess so is that fine then i guess it is fine zero is a valid id that's right i keep thinking zero is not valid but this this clearly didn't work this is very strange i still don't know why this is happening the other thing i can think of is um because what happened is so we retrieved the name here but then we call create entity with id which adds another tag component so it's possible that the location in memory has changed for the original tag but that like i don't know so what i guess what we could try is that's very annoying though isn't it we could try give it like a name that's you know been copied but it's kind of annoying so basically if we go back here we do antsy name like this let's see if that also um doesn't work okay so one thing i'm noticing by the way just as i open this is that the scene hierarchies is blank what is it what that's suspicious already um why is this scene hierarchy panel blank oh because it gets the context gets set to active scene which is not which is nothing okay so let's do this we'll go to open scene so if it had no context then it couldn't have returned a correctly so that nc never existed i think was the problem because it never had it never had a real scene but no but hang on when we hit open though we set it to be active scene oh but this is before we do that all right so editor we'll change this to the editor scene and then the other thing i want to do is when we actually hit play we should set it to not be the editor scene right so on scene um on scene play we'll set the context to be this runtime scene which is active scene and then we'll do the same thing on stop right so that way uh you know if we are spawning entities while our game is running we'll be able to see them pop up in the scene hierarchy panel so i suspect that we probably like that makes sense now oh well that just crashed i was gonna say that makes sense now um but i i don't think we need the let's see why that crashed but i don't think we need the yeah the the string and um copying the string and stuff like that anymore but what's going on here on i'm going render doesn't work uh yeah because context is null so what happens do we not can this just not deal with no scene that's weird well whatever so basically obviously we only want to do this if we have a context though the way i'm i'm shocked that this worked before that's very weird so if there's no context then we'll just do a blank panel yeah i don't know what was going on there that's weird i guess when you create it you're forced to give it a context immediately oh but where's the properties panel whoops so the properties panel happens here so and that's only if we've got selection contacts so actually that doesn't need to it's just this panel if there's nothing to display then there's nothing to display and again it will have if it's an empty scene it'll just have an empty context like it won't be empty empty meaning it's null it'll just be a blank scene um yeah this whole engine is uh okay that must have just been me yeah because end is here oh begin yeah whoops we still want to draw the actual panel just not the contents inside it if you like for the scene hierarchy panel lots of little stuff here happening but um okay so let's try and let that scene okay we actually have that stuff now so now if i hit control d yeah that seems to have worked let's go back and fix our code so that it's not um doing this so that should be okay right we should be able to just get the reference of it because we don't want to copy the string because it should still remain where it is i guess and then if i hit ctrl d oh it crashed this is um super interesting what i want to do is let's just grab this again let's put a breakpoint in and i want to see what's actually happening here because it looks like um because i want to see what happens when we hit ctrl d let's see what our name is so our name is floor that looks like it's correct we're on duplicate entity but then once we add this tag components aha our name is changed error rating characters of string right so i guess what's happened is it has in fact been moved in memory and now the reference is invalid right so uh yeah that's a bit unfortunate i guess um but that's the way it is so we will have to actually preserve this somehow you could also make it so this doesn't like return a const reference right because i guess it is kind of dodgy this will always give you a reference if you don't copy it so you could always do that but i guess for name like if you wanted to you could change it to return by value like that but again me personally i think that if you know what you're doing it's better to just have it returned by reference so that if in fact it wasn't a scenario in which we're actually playing with the registry um and potentially moving things then it would actually uh you know it would still remain a reference but this way if you actually want to copy it that's very bright but this way if you actually want to copy it then you can of course you know write code like this which will in fact copy it because you're making a copy of it so now i guess this should work yeah that was unexpected i think i'm pretty sure i wrote the code with the const reference and with everything in the live stream and it was totally fine so it might have just been a case of the registry didn't need to resize yeah weird i don't know or maybe i'm just missing something now no clue but anyway let's get rid of all of this stuff control d yep seems to have worked anyway so as i was saying the benefit of control d and all of that stuff is that obviously now we can uh easily set up this scene to be way more interesting right so if i um come over here you know maybe let's set this up here we'll duplicate this you can see how we can start to create a pretty interesting world right of this thing moving down pretty easily right and if we hit play then we can see that's rolling now we can be extra cool with this right what i can do is i can actually make my camera we could also give the camera a rigid body and a box collider and make it dynamic and now that's strange um we probably uh should uh the problem is it'll it'll start bumping into stuff itself so maybe i wonder why the size is zero by default though shouldn't that not be zero shouldn't be like 0.5 why is it zero i don't know box colliders had um a size of zero yeah it should have a size of 0.5 uh is it because it's duplicating it from somewhere no i just added the component hmm that's very strange oh i think i know what this is i think so let me just hit like control s here um oh control s doesn't work rip oh my goodness me okay whatever i didn't lose that much work but ctrl s should fix it right now but we're out of time anyway um let me quickly see i think i saw a comment about this yeah we're just displaying the offset twice so this is actually size whoops not in russian um so yeah so i think i was um [Music] yeah it was like the actual values are fine it's just it was being displayed incorrectly i can't believe that stupid control s anyway all right so take three um let's do something exciting now um let's move this around i hate not having ctrl s we should do it very soon okay and if we hit play then that's great but we can't see anything so let's go to the camera let's add a box collider except we can make it quite small um 0.1.1 or something and then we'll add a rigid but it doesn't matter where it is like the fact that the camera is far away because of course it's only 2d physics so we'll make it dynamic and now you can see we kind of kind of follow it right kind of now one thing we could also do is actually fix the rotation that'll probably make it a bit easier but yeah you can see how we kind of more or less follow this but the camera actually has its own physics associated with it which is pretty cool and we can be really cool and add like some restitution as well so that we're a little bit bouncy and you can see how fun that is right so you can see that we can kind of already start making some kind of game here and obviously the great thing is when we hit reset everything resets and everything's fine let's maybe make this this dynamic that'll be interesting now everything kind of falls that's that's it it's kind of boring anyway um yeah so i think what i'm gonna do right now actually just because you know what i'm i'm just gonna do it episodes long anyway let's add ctrl s so back to editor layer um what we'll do is we'll do save scene as i'll just make a save scene right that's just going to save the current scene now for that to happen we need we need to know what the current scene is right so active scene i don't know if this has a file path i don't think it does because it doesn't know anything about files so what we'll do is we'll um just make an std file system path current uh scene path or we'll just say edit to scene path right when we open scene right if it works out and everything's fine then this path right if we deserialize we'll just set the editor scene path to be the path right and what this means is that when we want to save the scene so save scene let's go ahead and make that happen when we want to save the scene um we'll just use that so if the if this is like a real path because we might not even have something open and it also might not be i guess it might not have been made yet so is there a way we can yes check if it's not empty so if it's not empty uh then we'll just do this basically right so um well again this is a bit uh okay we might have to change this a bit but yeah ultimately this is what we're trying to do and this unfortunately takes a string so for now we won't change it but that's really all that needs to happen if it's if the path isn't empty we do that right now if we hit new scene um this is a big one you probably want to make sure that you actually like reset this right to something else i don't know if you can just set it to empty um i guess it doesn't like that sd file system path can i just not set a path i guess i can do that uh because we obviously don't want otherwise we'll hit ctrl s and we'll overwrite our old scene with this new scene that is empty and that's a great way to lose work so make sure you don't do that make sure you kind of keep up to date with that um and then obviously every time we open a scene when we do save scene as we also want to change that right so we'll do save scene as and then we'll do um what is it editor scene path equals file path so that's what we've saved it into so we basically need to update the path and we need to kind of keep track of that that's important so ctrl s if it's um shift so let's just do if control and then if shift we'll do save scene as else um well if it's nothing we'll just do save same okay and that's pretty much it now the only thing that i don't like about this is that we kind of have this kind of code duplication here which can make it annoying i mean i guess here we don't need to update it but what you could do is call save scene from here but this is specifically not safe scene maybe we should make a serialized scene function probably let's maybe do that so we'll have we have safe scene but let's make a serialized scene um and serialize scene is going to basically take in a scene to serialize and then a path so this will be like the ultra kind of um correct way of doing this so what we'll do is basically all i think it needs to do is this so we basically grab the scene and then we serialize it to this path and i think that's it doesn't ask any questions doesn't care you just do it right and so that's good because obviously we can call that and it's a little bit more clear as to what we're actually doing this this takes in the file path um [Music] and then here we do edit a scene path okay cool that looks pretty good to me so let's go ahead and hit f5 test that out i think that's the only two things that save anyway so i think we should be good and i made the control i'm actually implementing control s i think um if it's empty won't do anything but actually it should bring up um it should probably bring up the save as thing right so if we move well let's just duplicate this basically so i'll duplicate this put it somewhere else uh hit control s and then i don't know something else load it back there you go okay so it has in fact serialized it and then i guess the final thing i'll do to tidy this up a little bit is um yeah we can just say i guess else save scene as right you could also have make that happen inside that switch kind of on event function that's also fine this is programming lots of ways to do the same thing we could talk for hours about the the benefits but yeah the the good thing is that if i start a new scene and then hit ctrl s it's going to bring up that save as dialog box which is exactly what we want anyway thank you guys for watching this video i hope you enjoyed it if you did please don't forget to hit the like button you can show your support as well as get access to hazel 3d the big version of hazel i'll probably keep calling it everything even though we've agreed that this game engine series is hazel 2d and that is normal hazel but anyway patreon.com best way to help support the series get access to all of the lovely source code and of course you'll be supporting development of the series as i mentioned about 500 times a huge thank you to everyone who does do that that is in fact why i am able to do this so thank you i think we're pretty much caught up with like the live streams now uh the well the live stream that i did last week so tomorrow which is uh thursday i will be live streaming on twitter tv slash the channel as i do every thursday working on the next episode whatever that may be of this and then we'll probably have it come out like maybe on maybe even tomorrow night we'll see but anyway thank you guys for watching i'll see you next time goodbye [Music] you
Info
Channel: The Cherno
Views: 12,250
Rating: 4.967936 out of 5
Keywords: thecherno, thechernoproject, cherno, c++, programming, gamedev, game development, learn c++, c++ tutorial, game engine, how to make a game engine, game engine series, scene runtime, copying scenes, entt registry, copy, copying, starting scenes, playing scenes, game engine scene
Id: EAC6_h07izo
Channel Id: undefined
Length: 56min 51sec (3411 seconds)
Published: Wed Sep 29 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.