Data models - using data to create extensible, maintainable games in Godot

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello golden ear when you start out with gdau you often build all your game logic with gdau notes and this works for a while but when you add more and more features it often becomes difficult to make these features play with each other often the same objects need to be used in different situations for example a weapon in your game may appear in the game world but should also be used in an inventory dialogue modeling all of this with notes only can can become really difficult over time so in this video we are going to explore how you can use data models to represent items in your game and how this greatly simplifies the development process we're also going to explore how you can extend and combine these data models to add new features to your game finally we are going to look at some tools that can help you with maintaining your data models so that you can easily tweak and balance your game based on player feedback back this is an intermediate level tutorial to make the most out of it you should have a basic understanding of GD script and gau's node and scene system it will also help if you are familiar with gau's user interface system because we will build a few dialogues throughout this tutorial so we start with this little game and this could be some kind of RPG or crafting game where the player can move around and pick up stuff and craft new items here we have our player and we call him Mr G and Mr G can only move around and collide with stuff and that is about everything Mr G can do now we want to implement a new feature where Mr G can pick up stuff from the ground before we can teach Mr G how to pick up stuff we need to have something that Mr G can actually pick up so I have prepared this little pickaxe here now how would we Implement picking up an item well the first thing we need to do is to be able to see the thing that we want to pick up so we need to put this little pickaxe into our world and now when Mr G walks over this pickaxe he should automatically collect it from the ground and put it into his inventory we're going to do the inventory part later and start with to collect from the ground part for this we need to detect when Mr G walks over the pickaxe and we can use an area 3D for this so let's add a new node 3D so we have a root node that keeps everything together and then we put our pickaxe below this node 3D we also add an area 3D so we can detect something so control a to add a note area 3D and there it is so this area 3D will will detect our player and we need to add a collision shape to it so the physics engine knows how big the area is over here in the inspector we can pick a shape and let's use a capture shape for this one okay that looks nice so now when Mr G walks into this area the area will fire an on body entered signal and we can react to this signal and then tell Mr G to pick up the pickaxe so we create a new script and add this to our root node 3D here and we named this pickup. GD and now we can connect the onbody entered signal of this area 3D to this new script so we select the area and then we go to signals and then we connect this on body ENT signal to our code so now when Mr G enters this area then the area will call this new function on area 3D body entered okay for starters let's just print out something so we can see that it has worked we can try it out so we move around and we walk over the pickaxe and it works nice now we're able to detect that we have walked over this pickaxe but what do we give to Mr G when he walks over this pickaxe we surely do not want to give Mr G this whole 3D scene here because it contains a lot of stuff that we do not really need in an inventure we don't need this area we don't need this 3D model and we also don't need this whole scrip thing around picking up items so it seems that we need some kind of object that represents a pickaxe but isn't directly shown in the world and this kind of object is often called a data model it is just a simple object that stores information about an item but it is not concerned with how the item is shown or how it is used in the game so let's create a data model then a very simple way to do this is to just have a dictionary that holds all the information about the items in our game so let's create a new script and we call this items GD this script is going to be our items database and now we're going to delete all of this and we can give it a class name so we can use it in other scripts so let's call it items now we create a dictionary which we call database and this dictionary is going to be our data model so let's add an item to the dictionary the first item would be our pickaxe and we need to give this item an identifier or ID so we can later refer to that item now we want to store a bit of information that describes our pickaxe and for this we can just put a dictionary inside of our dictionary and now let's think about which data would be interesting here well the first really obvious thing is that we need a name for the thing so let's add this information and the name of this item is going to be pickaxe so this should be enough information for now we can go back to our pickup code and try to give this item to Mr G so how does Mr G actually pick up the item but currently only the pickup knows that Mr G has entered its area so it somehow needs to tell Mr G hey there's a new item for you would you please pick this up and we can implement this by Def finding a contract for the pickup and the contract could be if you want to be able to pick up items but you need an on item picked up method so in our code for the pickup we can just check if the body that has just entered this area in our case Mr G has an on item picked up method and if this is the case well then we call this method and we give it the ID of the pickaxe as a parameter so Mr G knows what he has picked up and this is the ID that we have specified in our items database okay so now we need to add an on item picked up method to Mr G's code so we open the player GD file and then we add a new method here on item picked up and this method takes a string as a parameter which is the ID of the item Mr G currently does not have an inventory so we are just going to print out the name of the item that we picked up so we can see that it worked print I got a and then we can access our items database and we use the ID that we have received as a parameter up here to find the matching item in our items database so items database and then we give the item as a key and now we can get its name by just typing do name okay let's try this out we walk over the pickaxe and we can see down here it nicely prints I got a pickaxe okay great so now let's also make the pickup disappear when Mr G walks over it so we go back to our pickup code and after we have informed Mr G that he has now picked up a shiny new pickaxe well we can just Q free the whole pickup and then it will disappear also right now this code only works for pickaxes so maybe make this item configurable let's go up here and we add a new export variable for our item id this is going to be a string and now we can go to the inspector and type pickaxe into our new item id field right and now we have a configurable pickup and then we can use this item id down here in our script where we give it to Mr G so we change this on item picked up and instead of the hardcoded string we put in the item id okay this is great but in our 3D World we still show the pickaxe no matter which item id we have configured here in the inspector and it would be really nice if our pickup would automatically show a 3D rep representation of the item that we have configured here in our inspector so how do we tell our pickup which 3D Scene It should show we could make another export but then we would need to configure two things and is very easy to mess this up so a better way would be to add the 3D scene as some information to our items database so let's go back to items GD and here we add a new property to our pickaxe which we call scene and then we can just drag in the pickaxe scene and gdau will automatically create a string with the path to the scene so now we can go back to our pickup code and use this information we add a ready method and in there we first load the 3D scene from our item database and we can do this very similar to how we got the name of the item so war scene is load and then we go items database we give it this item ID from our export and then we load the scene and now we have the scene in our hands and we can create an instance from this so scene instantiate and then we can add this instance as a child of the pickup node okay great so we can kill this pickaxe model from ourc because it's now automatically created in our ready method and let's see if that works and yep our pickup shows a nice 3D model of the pickaxe great so maybe let's try to add a second item to our item database so we can see if this also works if we use a different item we go back to our items GG script and we add a new entry here and we give it the ID sword and of course it has the name sort and we also add a reference to the sword scene so we drag in the sword scene okay so we can now go back to our main scene and let's reconfigure our pickup so it shows the sword instead of the pickaxe and then we can run the game okay something is not working it looks like we have a typo here in our Item ID well this is not great it would be better if there was no way to mistype this but yeah for now let's just correct the typo and see if that works so we restart the game and now we can see that our pickup shows a nice sword instead of a pickaxe and if we walk over the sword we can see that now Mr G prints out that he has picked up a sword so you can see that representing items as a data mod model is really powerful because we can now easily add new items to our database and all the game systems will be able to just use our new item immediately so our pickup will be able to show these items in the 3D World and our player will be able to pick them up but our approach also has some drawbacks well first of we have the obvious drawback that it is very easy to introduce a typo here we have just seen this when we configured the sword but it's also easy to make typos in our item database itself because there's a lot of strings in there a second problem is that we have hardcoded the paths to our 3D seams into our items database and if we now move a scene to some new place or maybe we decide to rename it well then our items database will just silently break finally if we think about it this dictionary will be really hard to maintain once we add add a few hundred items to it so we would need to have a better way to structure our data that fixes all of these problems Gau has a built-in feature for modeling all kinds of static data resources everything that is static data in gdau is a resource for example scenes textures 3D meshes audio samples animations they are all resources Gau also allows us to create custom resources so we can model data that is interesting for our game so let's create a new resource type for an item we create a new script and we name it item. GD and then we're going to delete all of this now we give our new script Class A Class name and we name an item and then we let the script extend the resource class so nowo knows that this is a custom resource just like notes resources can export variables that we can add it in the inspector so let's add a few variables for our item we already know that we're going to need a name and the scene that we want to use as a 3D representation for the pickup so let's add an export for the name export or name and this is a string and and the second export for the scene and for the scene we are going to use the packed scene type instead of a string and using the pack scene has a few advantages which we'll see in a minute let's save this and then we can create a new resource in the editor so we right click new resource and now we can search for item and we can see that there is a new entry in this tree which represents the new item resource that we have just created created so let's select this item and then click create and then we can give it a name in case we want to create an item for the pickaxe well we name it pickax dotres and now we can edit this resource in the inspector here we can give it a name pickaxe and we can select the 3D scene that should represent this pickaxe in our world and because we made this field a pack scene we can now use this quickload option here to quickly select s our pickaxe scene also gdau will automatically fix the scene path if we move around the scene or if we rename it now we have a resource that represents a pickaxe but how do we use this resource in our pickup well let's go back to our pickup script and instead of using a string here with the item id we can now refer to our item directly so we change the name to just item and the type goes from string to item we also need to change the rest of our code so it works with our new item resource so first we go to our ready function and we do no longer need to load the scene here anymore because the scene is already part of our item so we can delete this line which loads the scene and here in the second line we can just use the scene from the item and call instantiate on the scene and down here where we talk with Mr G we modify our contract so that our on item picked up function now takes an item instead of a string and if we now go back to the inspector we can use the quickload option to select the pickaxe resource that we have just created and this is a lot easier and there's no way to introduce a typo we also need to update our player script so let's move over there and find the on item picked up method and now this parameter here is not a string anymore but it is an item and instead of accessing our item through the item database well we can just use the name directly from the item that we have been given as a parameter and this also means that we no longer need our items database so we can delete this whole script okay let's try out if everything still works we start the game and we can see that our pickaxe appears in our pickup and if we walk over the pickaxe we get our print out so now we have a reusable pickup and we can save this out as a separate scene so we right click the note and then we select export branches scene and we can name this pickup. tscn and to keep being AIT organized let's also create a folder named pickup and then we drag the pickup script and the pickup scene into this new folder so now it's very easy to add more items that Mr G can pick up so let's create a new item for a sort and then we click create and name this sort. toras and here in the inspector we can give it a name and we select the sorts seen as a 3D representation of the sword in our world now we can duplicate the existing pickup and change its item from a pickaxe to a sword and let's try if that works we start the game and Mr G walks over the sword and he also walks over the pickaxe and we can see that he always picks up the correct item the this is nice but it's not really terribly useful because we just print out the item and then forget about it so let's give Mr G an actual inventory and show the inventory contents to the player in some kind of inventory dialogue so let's start with the inventory we create a new script right click new script and we name this in inventory. GD and then we're going to delete the contents and we can start with our inventory first let's add a class name inventory and an inventory well it could be a node but we really don't need any node functionality here so we make it a simple object instead so extends ref counted and because ref counted is the default we can just leave it out so let's delete this line now we need a place where we store all the items that are into inventory so we're going to create a new array so War content this is an array of items and we are going to initialize this with an empty array so we don't need to do any kind of null checks we also need a function to add an item to the inventory and this takes an item as a parameter and in here we can just append this item to our content array a function to remove an item from the inventory would also be nice so let's add another function remove item this also takes an item and in here we just remove the first occurrence of this item here that we get from our content array and finally we add a function that just gives us the contents of the inventory and we call this get items and this returns an array of item and we just return this content array that is a very simple inventory we don't have any Stacks or slots but for now this is good enough and now we can add this inventory to our player so let's go back to our player script and here we create a new variable War inventory and this is of type inventory and we just make it a new inventory great now our player has an inventory and we can use this in our pickup function so let's go down there to on item picked up and here we just add the item that we picked up to our inventory with the new add item function that we just wrote now it would be really nice if we could actually see what is inside of our inventory so let's create a very simple inventory dialogue we make a new scene and this is going to be a user interface scene and we save this as inventory dialogue. TSN let's rename the root note to inventory dialogue and we also change its type to be a panel container let's first add a little title bar and a close button so that we can close the sty loog so we create an hbox container to get a horizontal title bar and inside of this hbox container we add a label let's call this title label and a button for closing the dialogue and let's call this one close button now we can set up the label let's change its text to something like Mr G's stuff and we want to Center this label and the label should also take all horizontal space so we go up here and we take the Align with expon checkbox and then we horizontally expon the label to fill all the available space if you don't know how container layouting Works in gdau I recommend that you have a look at my UI Basics video there's a link to that down in the description okay so now let's configure the close button we're just going to give this one a little X as a label and our title bar is done and next is the part that actually shows the inventory contents a lot of games use some kind of grid to show inventory items so let's do that as well we add a grid container coner and we want this grid container to be below our title bar so let's add a vbox container and now we can just drag the hbox container with the title bar and the grid container into our vbox container and the vbox container will just stack them on top of each other now inside of this grid container we want to show the inventory content so let's first add a panel container into the grid container so we have some kind of background and inside of this panel container we put a texture act which is going to show an icon of the item that is in our inventory well let's quickly load an icon here maybe this sord icon and that looks pretty nice now if we duplicate this panel container a few times we can see how this is going to look when we have a filled inventory our grid container only has one column and that looks a bit odd so let's increase The Columns of the grid container to maybe five and that looks a lot more like an inventory dialogue nice but how would we show the actual contents of our players inventory and not just a dummy like this well we can do the same thing that we just did here in the editor but we do it in code so we walk over the inventory contents and then for each inventory item we create one copy of this panel container and then we set the icon to some icon that matches the inventory item and finally we put our finished item slot into our grid container and this way we can build up our inventory step by step so first let's extract our item slot here into a separate scene so we can quickly make copies of it and we don't need to build and arrange the panel container and the texture R in our code so we right click this note and then we select Save branch as seen and we name this item slot. TSN okay now let's clear our grid container and then we can start writing a script so we add a script to this inventory dialogue note and we name it inventory dialog. GD and we're going to delete all of this let's give this a class name inventory dialogue okay first let's make the close button work so we select this button and then we go to the noes signals and then we can connect the Press signal to a new function on close button press and inside of this function we just hide the dialogue the next thing we want to do is to fill this grid container and for this we need to have access to this grid container in our script so let's right click it and then select access as unique name and then we can control drag this grid container into our script and we get a nice onready variable so why did we do it with a unique name well the reason for that is that unique names have the advantage that we can move our noes around and we don't need to change our script all the time because this unique name is going to be the same no matter where in the tree this node is going to be so if we decide to rearrange items in our UI a bit well we still don't break our script now we need a function that opens this dialogue and shows the inventory contents so let's make a new function and we call this function open and because we don't want this dialog to be concerned with where the inventory is actually stored we will just give the inventory as a parameter to this function and then whatever code tries to open the inventory dialogue it needs to to supply the inventory to our dialogue and this way we can keep the dialogue independent of the rest of the game so first we show the dialogue and we just call show and now we can walk over the items in our inventory so four item in inventory get items and for each item we want to create a new item slot inside of our grid container we already made a scene for this item slot but we don't want to hardcode the path to that item slot scene so let's export this as a variable let's go up and we write an export or slot scene and this is a packed scene here in the inspector we can just drag the item slot scene into this new field and this way gdau will automatically fix the path to the scene in case we reorganize our proaching now we can go back to our Loop and here we can instantiate our slot scene now we can add this to our grid container but we still just have an empty slot without an icon but where do we get this icon from well we can add it to our item description just like the 3D scene that we have added before so let's go to our item script and there we can add an export variable for the icon so export bar icon and this is a texture 2D and now we can add an icon to the resources that we already created for the pickaxe we use this pickaxe icon here and for the sword well we get the sword icon now we can go back to the inventory dialogue and we can use the icon and put it into our item slot but how do we get it in there well let's have a look again at the item slot scene so we can see how it is built up we have a panel container at the top and a texture rack directly below that but this item slot really is its own component so the inventory dialogue should not know how this is built up internally so maybe let's add a script to our item slot and we're going to delete these two functions and then we can add a new function that will actually show an item show is already taken as a name so let's call this function display and this function is taking the item that it should display as a parameter now we need to access this texture and we already know Senor nickname all the way to go so right click access as unique name and then controll drag this into our code so now we have an onready variable which is of type texture we can use this to show the icon of our item so we write texture rag. texture and this is item. icon great now we can go to the inventory dialogue and use this new function so inside of our Loop here we first add the slot to our tree and this is important because the unready variables of our item slot are only initialized after it has been added to the tree so we really need to add it to the tree first and then we can call our display function so slot display item that should do it so let's add our inventory dialogue to the game our game does not have any UI elements yet so let's start by adding a canvas layer and this canvas layer will contain our user interface and we name this canvas layer UI root technically we don't need a canvas layer in 3D games but I still like to add it because this gives us a nice separation between the 3D part and the 2D stuff and let's switch to 2D mode so we can actually see what we're doing and now we can drag our inventory dialogue into this canvas layer and to keep our inventory dialogue always centered we go here to anchoring and then we pick the center anchoring preset and now gell will make sure that this dialog is always centered no matter which resolution or aspect ratio we have let's also hide the inventory dialog so it only shows up when we press the inventory key we're almost done but we still need to add some code that actually opens this inventory dialogue up now where should we put this code our inventory is a component at the player so we could open up the inventory dialogue directly from the player but then the player needs to know about our game's user interface and I don't really like that we want our components to know as little as possible about each other and I think in this case it is probably better if we have a third component that brings our player and our inventory dialogue together so let's add a script to our UI root here and we call this UI root. GD now our UI root script needs to know about the player and the inventory dialogue we already know how to do that so we make them SE unique notes and then we can just control drag them into our script now we want to be able to press a key to open the inventory so we need to create a key binding in the project settings let's go to project project settings and up here we select the input map tab now we can add a new action let's call this inventory and then we scroll down and we add a key binding to this action which is I for inventory and now we can use this key binding in our script let's go back to our UI root script and we add a new function unhandled input so this is called for all input that is not handled anywhere else and in here we can check if the inventory key has just been released so if event is action released inventory and if this is the case then we open the inventory dialogue and show the inventory of the player okay that was a lot of stuff so let's try if this actually works so we start the game and then we pick up our pickaxe and we press I to show the inventory dialogue and great our pickaxe has appeared in the inventory dialogue unfortunately we cannot click on our close button because our Mouse is captured because we're playing a 3D game we would need to show our Mouse when we open the dialogue and then we need to capture it again when we close the dialogue so let's add this to our inventory dialogue script so here after we call show we make the mouse visible so we say input Mouse mode is input Mouse mode visible and down here where we hide our dialogue well we just set the mouse mode back to captured okay let's try this again so we walk over the pickaxe now we press I and our inventory dialog is showing and our Mouse is also showing and we can actually click the close button awesome so now let's pick up our sword and then let's open up the inventory dialog again and well we seem to have two pickaxes now in our inventory doog why do we have a second pickaxe now now let's look again in the open function of our inventory dialog and we can see that whenever we call this function we just add more and more items to our grid container so when we open the dialogue the first time we add the pickaxe and when we then picked up the sword and opened it a second time well we added the pickaxe and the sword again so now we have two pickaxes and one sword but well this is easily fixable we can just clear out our grid container before we add new contents and then we shouldn't get any duplicate entries so let's add a loop for child in Grid container get children and in this Loop we can just delete each child so we call Q3 for each each child okay let's try this again we walk over the pickaxe and we open the inventory dialogue pickax is there we close the inventory dialog and we walk over the sword and then we open the inventory dialog again and this time everything R is correctly this is nice let's quickly have a look at what we have built so far we created a data model that represents our items it holds the name the 3D scene and the icon of our item we also build a second data model our inventory it just holds a list of items and provides a few useful functions to manage this list but it isn't really concerned with how the items get in there or how they are rendered on screen and because we have these data models the rest of our game code becomes really simple simple adding an item to the inventory is one line of code in the player script showing the inventory items in a dialogue is four lines of code in the inventory dialogue and because we can simply give the data model to any component each component only needs to know about the data model but is independent from other components and this helps keeping our game manageable and now let's see how we can use this data model to build additional systems on top of what we already have and to do that we're going to build a very simple crafting system in general a crafting system works like this we have a recipe and this recipe has some ingredients and we get something produced from from these ingredients we currently don't have any kind of ingredients so let's create a few more items that we can use as ingredients let's first create some iron ore so we create a new resource and we select item and we call this one iron or. TS and now we can give it a name iron ore and select an icon and we can also select a 3D scene for that and now we have an item that represents iron ore let's make a second item which represents an iron ingot and this time we do it by duplicating the iron ore that we just created so we select it and press contrl D to duplicate it and we name it ironing. TS we also change the name to iron ingot and pi pick a new icon and we also pick a different 3D scene great now we have a few items that can represent ingredients for our recipes and we can continue with making a data model for our recipe so let's create a new script and we call this one recipe. GD and we're going to delete all of this so let's first give this Clause a name we call it recipe and like our item this is a resource and now we need to think about what kind of data are we going to need in our recipe well we'll probably need some title or name that describes what this recipe is going to produce so we give it a name and this is a string and we will also need a list of ingredients that go into the recipe so let's add a a variable for that as well this is an array of items finally we need to have a list of stuff that is produced by this recipe and this is very similar to the ingredients it's just an array of items so let's just copy this line and rename it to let's say results now we can create recipes so let's create a new folder that we call recipes and inside of this folder we create a few recipes so let's first make a recipe for an iron ingot we give this a name let's call it iron ingot TRS and now we can edit it here in the inspector it's called iron ingot and let's say that we need to have three iron ore to create two iron ingots so let's drag in our iron ore item here into the inspector and we need three of those so we just create two more entries here and then we can just drag down the iron ore into these two new slots and for the result we create two slots because we want to have two iron ingots and now we can just drag in the iron ingot here and again we drag it down like we did for our iron ore and this easy we have created a new recipe let's add another one to create a pickaxe we can duplicate this one and change its name to pickaxe and as ingredients we take two iron ingots and as a result we want to have a pickaxe how can we now use these recipes in our game we can build a simple crafting dialogue similar to the inventory dialogue that we already built and then we can craft in this Stog so let's create a folder for our craft crafting dialogue and we name this crafting dialogue and to save some time let's use the inventory dialogue as a starting point so we duplicate this inventory dialogue scene here and we name it crafting dialog. TSN and then we drag this into our crafting dialog folder let's first rename the top note here to crafting dialogue then we can change the title label to something like crafting and then let's think about how this dialogue could look like I like to draw a little mockup before I go into making any complex UI so this is how a crafting dialogue could look like so we have a list of recipes here on the left side and then the user can select an entry in this list and this would show the ingredients and the results of the recipe here over on the right side and then the user can click this craft button down here to craft recipe so let's get rid of this grid container and build this let's first have a look at The rooad Strokes here we have basically two sections the left section with the list and the right section with our ingredients and results so let's add an hbox container so we can split things up into a left and a right section this hbox container should fill the whole vertical size of the dialogue so we set its vertical alignment to export and then we can click the fill button and you can see it expon to fit the whole height of this dialogue now on the left hand side we have a little label on top of our list of recipes so we're going to need a vbox container which will stack the label and the recipe list on top of each other now we can add the label and we set its text to recipe recipes and then we can add an item list which is going to hold our list of recipes let's name this recipe list and we want this list to fill the remaining vertical space here so let's set its vertical alignment to xon and then click the fill button okay that looks like we're getting somewhere let's add a few dummy items here so we can see how this actually looks when there's something in the list so we go over here to the inspector to the item section and then we can add an item first recipe and maybe another one second recipe okay so now we see that the text of our items is cut off which is not good it looks like that the item list does not request any minimum size to actually fit its items so so we will have to set a minimum size ourselves now we can do this here in the layout settings and we set the minimum horizontal size to well let's say 250 pixel but that looks somewhat okay and now we can go to the right hand side and here in our mockup we can see that we have another vertical structure so there's a label there's a list of icons and there's another label and another list of icons so we start with a v box container and we want this vbox container to fill the remaining horizontal size of this dialogue so we set its horizontal alignment to expand and then click the fill button now let's add two labels one label for the ingredients and the other one for the results and finally we add a grid container container for our ingredients let's maybe drag in a few item slots from our prepared item slot scene so we can see how this will look and we see again that we need to increase the columns in our grid container so it renders the items nicely next to each other let's also go with five here and yeah that looks okay good now we can delete our item slots again and then we can press contrl D to duplicate this grid container and this time we drag it below our results label so we have the ingredients and results grits and all that is missing is the crafting button so let's add a button and we name it craft button now this button currently takes all horizontal space which is not what we want so we change its horizontal alignment to shrink and and that will make it shrink and move it to the right I also want the button to be at the bottom of our dialogue but because there's currently nothing in our grid containers the button has moved up here we can fix this by adding a spacer control so contr a to add a new note and then we select control this is really just an empty control and we drag this between our second grid and the CFT button and now we can set its vertical layout to expand and press the fill button and we see that this control will grow to fill any space between our grid container and the crafting button and this way it pushes the crafting button down this still doesn't look super nice but I think at this point it is workable so let's cut it here and get to the implementation as a basis we're going to use the inventory Dot dialog script that we already have so let's quickly duplicate that and we name it crafting dialog. GD and then we can drag it here into our folder for the grafting dialogue and we can also drag it up here on our crafting dialogue root note so then let's first fix up the class name it's now named crafting dialogue and we need to access the recipe list in our script so let's make this a SC unique node and control drag it over into our script we also need these two grid containers for our recipe ingredients and results so let's first give them a proper name first one is going to be our ingredients container and the second one is our results container and then we can also control drag them into our script okay so now let's have a look at the function that is going to show this dialogue what information do we need here first we need a list of recipes for our recipe item list here on the left hand side we're also going to need a reference to the inventory because when the player clicks the craft button then we want to remove the ingredients from the inventory and put the crafted results back into our inventory so let's add these two things to our open function as parameters so first the recipes and this is an array of recipe and second the inventory now when the dialogue is opened we want to add all of the recipes to our recipe list so that the player can select one and craft it and we first need to clear the recipe list just like we did in our inventory dialog so recipe list do clear and then we can just walk over the recipes that we get as a parameter and for each item we add the title of the recipe to our list let's also remove this grid container code here so we keep things nice and clean and now when the player select a recipe we want to fill our ingredients and results containers so the player knows this is what goes into the recipe and this is what comes out so the recipe list would need to inform us when a user changes the selection and we can do this with a signal so let's check the signals of our recipe list we go to note and this item selected signal looks about right so let's connect this one to our script and we connect it to a new function called on recipe list item selected great it's a small problem though this signal only gives us the selected index but this is not enough because we want to update our ingredients and results containers and for this we don't need the index we need the actual recipe in our hands so how do we get the selected recipe into this function well the item list has a functionality that allows us to attach additional data to each item in the list and we can use this to attach our recipe to the list item so up here where we add the recipes to the list we can call a function called set item metadata and in the autocomplete we can see that this function requires the in index of the item to which we want to attach our metadata in this case our recipe so where do we get this index from well lucky for us the at item function that we just call above Returns the index of the item that we have just added so we can just save the return value of this function into a variable and now we can attach our recipe to the item in the list so set item metadata and we give it the index and the recipe and down here in our on recipe list item selected function we can now get the recipe from the list by calling the get item metadata function so recipe list get item metadata we give in the index and this gives us back the recipe okay now we need to fill the ingredients and results into our grid containers and this is going to be very similar to how we did this in our inventory dialogue so this is something that we could extract into a separate component and then reuse let's save our ingredients container as a new scene and let's also create a new folder here item grid and we put the new scene into this folder let's open it up we rename our root note here to item grid and then we can attach a script and we name this item grid. GD and all of this goes away let's also give this a class name so we get nice autocomplete later so this is going to be an item grid we already wrote the code for filling items into a grid container so let's copy that over from our inventory dialogue so we copy this and we paste it over here and now we just need to do a little bit of fix up we're going to need the slot scene and we don't need this grid container variable because this is already attached to a grid container so we delete this and now we can change the function here first let's rename it to display and instead of an inventory it just takes an array of items and this way we can use it for both our inventory and our recipes and we don't need this line that shows the dialogue because it's just a component and we also don't need this mouse handling code so all of this goes away and now we can just fix up our Loops here so we remove the children from the grid container and because this is attached to the grid container we can just remove this grid container variable reference and here in the second Loop we go over the items that we get as a parameter and then we can just instantiate the slot scene and add it to our grid container that would it be for the code and all that is left is to drag this slot scene into the inspector field and now we have a nice reusable item grid so let's first put that into our inventory dialog so we can delete this grid container node and then we can drag in our new item grid let's make this a scene unique node and we rename it to grid container so it matches what we have in our inventory dialogue script let's also change the type of this variable to item grid so we get nice order complete and now we can simplify our open function here right we we don't need these two Loops anymore and we can just call the display method on our new item grid and we give it the items that are in the inventory let's quickly test if our inventory still works and we walk over the pickups and then we press I and it looks our inventory dialog is still f functioning great now we can continue with the crafting dialogue the ingredients container is already an item grid because yeah we created it from this ingredients containers but our results container is not so let's delete this old results container and then we can drag in our new item grid we name it back to results container and we make it a scen unique name and now we can go back to our function where we fill our ingredients and results containers and this is really just a oneliner we can call the display function on our item grid and give it a list of ingredients and then we can do the same thing for our results container so now I think it's time we test this out so let's add this new dialogue to our game scene so we move over to our game scene and then we can switch to 2D mode again so we can see what we're doing and now we can drag in our crafting dialogue again we Center it with the center anchor preset and we hide the dialogue so it is Invisible by default then we can use our UI root script to open up this dialogue we need to have a reference to the crafting dialogue in our UI script so like always we make it a scene unique note and we can control drag it in here we also want to open the crafting dialogue with the key press so we need to add a new key to our input mapping so we go again to project project settings and then to the input map and here we can add a new input mapping well let's call it crafting and we bind this to the c key so back to our script here we can check if the player has released the crafting button and if this is the case we can open up our crafting dialogue and now we need a list of all recipes we don't have this list right now so let's put in an empty array here and we also need the inventory which we can and grab from the player like we did up here in the inventory dialogue okay so how can we get hold of a list of all recipes this a simple way that we could use we can just control drag our recipes up here into our script and this will create some constants that we can use to fill our array this is not really scalable because if we have like a 100 recipes we really don't want to have 100 constants in our script here but for now we just want to see whether or not our dialogue works so let's roll with that so we can just fill the two constants here into our array so iron ingot and pickaxe and that should do the trick so let's try it out and start the game and now we can press the c key and our crafting dialogue is actually showing we have our recipes in the list which is good so let's see what happens if we click on a recipe and yes the ingredients and results are also nicely updated well let's quickly check out the other recipe and this seems to work just fine fantastic now we can implement the actual crafting so let's go back to the crafting dialogue and to actually craft something we need to know that the player has pressed this craft button so let's connect it to a function so we select the button and then we go to Noe signals and there we have the Pressed signal and we connect this to a new function on Craft button pressed implementing this crafting function is pretty easy we can just remove all the ingredients from the inventory and then we put all the results back into to the inventory we currently don't have access to the inventory in this function so we need to store it in a variable when the dialogue is opened so let's do that let's first go up here and create a variable for the inventory and when the dialogue is opened we store the inventory to our new variable for crafting we also need to know the currently selected recipe and we already extract this recipe when the player selects an item in our recipe list so let's also write this to a variable so we create another variable up here for our currently selected recipe and this is a recipe and then whenever the player selects a recipe we just update this variable and then we can also use this CLA variable here and here now we have access to both our inventory and the currently selected recipe and we can actually craft something so let's go back to our crafting function and now we can walk over our ingredients so four item in selected recipe ingredients and then we can just remove each ingredient from the inventory so inventory remove item and for the results we do a similar thing we walk over all the results or item in selected recipe results and then we add each result to the inventory inventory at item item so let's give this a try and see if it works we open the crafting dialogue and then we select the recipe for the iron ingot then then we press craft and now let's close the crafting dialog and open up the inventory and we have two new iron ingots in here fantastic now you have probably noticed that there is a bit of a problem here because we just crafted two iron ingots out of thin air it would also be nicer if the first recipe was automatically selected when we opened the crafting dialogue so let's fix these two things selecting the first recipe in our list is actually pretty easy so we can call Select on our recipe list and this will select the first item when we select an item through code then the item list will unfortunately not send a signal so we need to call our on recipe list item selected function so that this function updates our ingredients and results list and now for the more interesting problem we need to check that the player actually has all of the necessary ingredients in the inventory before we allow the CRA button to be pressed so let's add a function to our inventory that can check this we go to the inventory script and we add a function named has all and this takes an array of items and it returns a Boolean value value that tells us whether or not all the items in the given array are in our inventory but how can we check this well let's see we need three iron ore and this is what is in our inventory now we can walk over the content of our inventory and we check is this an item that we need and if this is the case we remove this item from the list of items that we need so we start with an ore and we need an ore so we can remove the first ore from the list the next one is an inot and we don't need an Ingot so we skip to the next one which is a pickaxe we also don't need a pickaxe so we can skip to the next item which is another ore we need this ore so we remove it from the list of items that we need and then we have a sword we don't need that so skip to the next item and there we have another ore so we remove this ore from the list of items that we need and we're done and if we now look at the list of the items that we need we can see that it's empty so we know that we have all the items that we need and if this list were not empty when we're done with our little Loop here well we know that we don't have all the items that we need so let's put this into code the items array that we give into this function is is the list of items that we need now when our crafting dialogue will later call this function it will give us the ingredients array directly from our recipe and it would be really bad if we deleted items from this array because then we would change the recipe so let's make a copy of this array and we delete the items from the copy so we make a new variable VAR needed and this is also an array of items and we call items. duplicate and we get a copy of the items array and now we can walk over our inventory contents so four available in content and then we remove the item that we found in our inventory from the array of items that we need so we call needed. erase available and the erase function is is actually smart about this and will only remove an item if it actually exists and then we can simply check if the needed array is now empty now we have a function that allows us to check if we have all the necessary ingredients so let's call this in our crafting dialogue so when the player now selects a recipe we can ask the inventory if it has all the necessary ingredient s and only then we enable our crafting button we need to have access to the crafting button so let's make this a scen unique note and control drag this into our script and then we can disable our button when the inventory does not have all the necessary ingredients we're also going to have to check this after we have crafted a thing because then we have used up items in our inventory and we may no longer have enough items to craft this recipe so let's copy this line into our crafting function as well let's give this a try we open the crafting dialogue and now our first recipe is automatically selected which is great and also the craft button is now disabled because we don't have the necessary ingredients so we need to add a bit of iron ore to our world so we can actually craft something let's do that we take this pickup here and we duplicate this and we change the item to be an iron ore and then let's create two more copies of this pickup so we have three iron ore in total now that should do do it let's start the game again and then we can pick up our three iron ore and now let's try to craft something and we can see that we can now craft an iron ingot because we have all the resources but if I switch over to the pickaxe recipe and we can see that we cannot craft it right now because we don't have any iron ingots so let's then craft the iron ingots and now our craft button has been disabled because we no longer have the necessary iron ore but if we switch over to the pickaxe we can actually craft this because we have converted our iron ores into ingots so let's craft this one and then let's have a look into our inventory and there we can see that all the crafting has actually worked and we are left with a pickaxe great okay that worked fantastic but we still still have a little problem left over remember when we wrote the code for opening the crafting dialogue that we needed to get all the recipes in our game we postponed this for later and later is now so how can we actually get a list of all recipes without having to create a constant for each of them if we look at our folder structure here we can see that all our recipes are inside of this recipe folder so we could load all the resources that are inside of this folder unfortunately Gau does not have a built-in way to load all resources inside a folder so we need to do this ourselves let's first create a variable where we are going to put all the recipes so War all recipes and this is an array of recipe and we initialize this with an empty array now we can create a ready function and to list all files in a folder we create a loop for file in dur xes get files at then we point to rest data recipes so this will look for all files inside of the data recipes folder in our current project this file variable will contain the name of the file so we can now combine the folder name and the file name to get the full name of the file now we can ask Gau to load the recipe from here so we say War recipe equals load resource file as recipe and finally we add the recipe to our list so all recipes pend recipe okay great so now we can get rid of these constants and down here where we open our crafting dialog we can use the new array that we have just built okay that wasn't actually so hard so let's try if this works so we open up the crafting dialogue and it looks like our recipes are here fantastic we can ship our game now so let's export our game and see if everything still works after we have exported it so we go to project export and I have already installed the Windows export templates so let's export this to the desktop and we're going to ignore all of these warnings for now because this is really just a test and if we now look at our desktop we can see that we have a new test executable well actually we have two one that opens up a console and another one that doesn't so let's use the one with the console so we can see what's going on so we start the game and we are already greeted with two errors well that doesn't look good so it looks like our game is not able to load the resource files which contain our recipes let's open up our crafting dialogue to check this and indeed we don't have any recipes in our crafting dialogue why is this happening if worked in the editor well when Gau exports our files then it will do some reorganization and optimization of the file structure you see here on our desktop we actually don't have any folders for our exported game we just have this pck file which contains everything neatly packed together there's a tool called pck Explorer and we can use this tool to have a look inside of these pack file files there's a link down in the description if you would like to try it out yourself so this is the pck Explorer and we can open our pck file by just dragging it in and well there seems to be a lot of stuff inside our PC file so let's use this filter function up here to find our recipes so we type recipe in here and press enter and now we can see all the files that have recipe in their name so it looks like our resource files which should end in TR s have disappeared and instead we got some do remap files well this is really not great because it totally breaks our loading we could of course do some kind of hack and say okay we know that all our resource files are getting renamed to. remap and then account for this when we load them but this is really a hack because this packing is an implementation detail of how Gau creates an export and we really don't want to rely on this Behavior because it can change at any time and then our game silently breaks so what can we do then to solve this problem I have created a small plug-in called gdau resource groups let's install this plug-in and then let's see how it can help so we go to the asset library and we search for gdau resource groups click on the link here and then press the download button we don't need the examples that come with it so let's click up here and now we can choose which parts we want so let's uncheck this examples folder and then click install then we need to enable the plugin so we go to project project settings plugins and here we take the checkbox to enable it and finally after installing a new plug-in it's always a good idea to reload the project so let's do a project reload current project okay so with the plug-in we can create a new kind of resource which is called a resource Group let's add one so here in our data folder we right click new resource and then we search for Resource Group we want to access all our recipes so let's name this Resource Group all recipes. TRS and now we can set up our Resource Group first we need to give it a folder where the resource Group will look for resources we want all our recipes so let's pick the recipes folder here now we need to tell the resource Group which file files we are interested in we want to load all the TRS files inside of that recipes folder so here in includes we add an element and then type in star. TRS and if we now save to project with contrl s we can see that this paths property here now contains all the paths to all the recipes in our recipes folder and the talk will keep this list up to date at all times so whenever we add remove or rename a recipe in this folder then this Resource Group will automatically pick it up now we can use this in our UI root script to load all the recipes let's remove this Loop over the file system which didn't work and instead we get our Resource Group so we can load our recipes let's use an export for this because we don't want to hardcode the path so export bar all recipes and this is a resource Group and now we can select our Resource Group here in the inspector back to our script here and ready we can now call the load all into function of the resource Group and then we give it the list of recipes and now this function will fill all the recipes from our Resource Group into our re a piece array and that's pretty much all we have to do so let's start our game and see if this works let's press C to open the crafting dialogue and all our recipes are there so this works fine but yeah we already know we need to export it to see if it really works so let's export the game again so project export and then we export our project Okay so let's now go to the desktop and start our exported game we again use the console version and there are no errors in the console which is promising so let's press C to open the crafting dialogue and all our recipes are there fantastic over time your game will evolve and you may need to add or change data in your resources for example let's assume we want to add a feature that allows the player to buy and sell items from a merchant in game for this we would need to have a price for each item we're not going to implement the merchant because this video is already quite long but let's add a price so we can see how this affects the data that we already have in our project so let's open up our item script and here we add a new X export for the price and this is going to be of type int because we charge in coins and they can only be full coins and we give this variable a default value this is going to be the value that all the existing items will get so if we now save this and then maybe open up our pickaxe item we can see that this has now a price of five so adding new Fields seems to be quite quite easy and because we have a default value we know that all the items at least have some price set but let's say we have 100 items and we want to set a custom price for all of these items well then we would need to double click each item and set a price and then double click another one and set a price and this is kind of not fun also it's really hard to get an overview on what the prices currently are which is really potential for balancing your game it would be really nice if we could edit this in some kind of spreadsheet so I had a look around and I found that a person made a plugin that allows us to edit resources in some kind of spreadshe so let's install this plugin and then let's see how this can help us to edit our item prices we go to the asset Library again and then we search for resources which will bring up this plugin called addit resources as table 2 so we click the link and we press download and this plugin also comes with some example data which we don't want to use right now so we again click up here and then in the tree we deselect this example folder now we can install the plugin and then we need to enable it so we go to project project settings plugin and we enable the plugin here just like with the other plugin it's a good idea to reload the project before we use the plugin so project reload current project and now we have an additional tab up here which is called resource tables and in this tab we can edit our resources in a table View and the first thing we need to do is to tell the plug-in which resources we want to addit we want to edit our items so we open our data items folder and now the plugin collects all the resources in our items folder and is showing them in this nice table this is great because now we have a good overview on what items we have in our project and what their prices are we can sort them by clicking on the table headers so we could sort them by Price or by name or any other information and the really cool thing is that we we can actually edit this so say we want to set the prices for the iron ingot and the iron ore to seven coins well I can just select these two and here over in the inspector I can type A7 into the price field press enter and boom we have added it two resources at the same time the plugin also has a filtering functionality so let's say we want to find all the items that cost less than 7 coins well then we can click here on the filter process Tab and this brings up the filtering functionality and here on the left hand side we can type a filter expression and this can be just any GD script expression and inside of this expression we can use the name r to identify the resource so let's type rest. price is less than 7even and if we press enter we now only see the resources that have a price below 7even coins so with this plugin we get a lot of control over all of our game data and this really helps maintaining a larger database and we can do this All directly in gdo in this video we explored how data models can help us to make our game more extensible and manageable we started with a very simple items database that was just a dictionary and then we switched over to resources to represent the items and crafting recipes in our game we learned that resources have quite a few advantages over our previous approach we can edit them nicely in the Gau inspector so there's no syntax to follow we can easily load them with the build and load function and they can directly refer to other resources like scenes or other items and gdau will keep these references up to date which eliminates any chance for typos and also allows us to reorganize our project without breaking things we then have built a simple inventory and crafting system to see our data model in action and we learned how we can use our data model to represent the same item in a 3D World our game's user interface and the games systems like the inventory or the crafting system finally we had a look at how we can dynamically load our resources in a way that works both in the editor and the exported game and we had a look at a plug-in that allows us to manage a large database of items so we can easily tweak and balance our game according to player feedback inventory items and crafting recipes are only two of the things you can represent with a data model the same approach can also be used to Model A lot of other things for example cards in a card game quests and Quest rewards in an RPG dialoges unit types in any kind of strategy or shooter game weapon types and a lot more I hope this video has been helpful and maybe has given you an idea on how data models could work for your game if you have any questions or want to share your approach of working with data in your game please post them in the comments if you like this video please give it a thumbs up and maybe consider subscribing to the channel so you get notified when new videos are posted thank you very much and happy Goen earing
Info
Channel: Godotneers
Views: 50,432
Rating: undefined out of 5
Keywords: cards, crafting, data models, database, dialogue, game engine, gamedev, godot, inventory, items, quests, resources
Id: 4vAkTHeoORk
Channel Id: undefined
Length: 89min 29sec (5369 seconds)
Published: Sun Jan 28 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.