Game development on .NET

Inventory and Store System – Part 2 (Scriptable Objects)

dotGame
Rate this post
(Video Transcript)
Hi, guys. Welcome to the next episode of .GAME. In this one, we’re going to take a look at something that’s known as scriptable objects. And basically, what we’re gonna do is we’re gonna use scriptable objects to begin to build up the foundation for our items that are in the game. And then ultimately, building out are inventory system along with our merchant store system which is actually the first one that we’re gonna build out. So, we’re gonna get the scriptable objects going, start creating objects for our game and then build out purchasing from our merchants. So it’s gonna be over the course of the few episode. This particular one is gonna go over the foundation of scriptable objects, how that relates to mono behavior, some of the benefits behind it. And before we can really articulate the benefits behind scriptable objects. Can we just take a small kind of brief look at mono behavior. So, I touched on mono behaviors a little bit in the first episodes, the basics of Unity I think it is I ended up calling it.

Towards the end, it looked as I think it was updates, awakes, start, on and able and on disable. So took a look about five of the different event site, Git called this part of mono behavior. What I kind of owe you guys is a better explanation of the events that are tied to it. And I actually gave a talk as part of the .NET conference. This past year, I’d showed it with like a case study and I haven’t really been able to come up with a better way to illustrate some of the more common methods. So what I’m gonna do is I’m not gonna jump into those methods. I’m gonna link towards that talk in the resources section on both the Channel 9 video and then of course GitHub Repo. I recommend if you don’t have a foundation in mono behavior and how all of that works to just stop and go take a look at that talk and then come back. And that’s also gonna give you really good foundation for scripting in general with Unity. But that being said, what I can show you is kind of a list of the different events that a mono behavior class ends up gets in sync.

You kinda see, this is Unity’s documentation. I think, I’ve talked too much about it. But I have been linking towards it. And with this documentation, has this fantastic diagram that shows basically the script’s life cycle through. You can see Scott have said, has the ones we talked about awake, on, enable, start and hoping you can kinda, it doesn’t scale very well. I’m hoping you can see this. But then it jumps into like fixed update, if not of course I’ll have a link to it. And talks about like the physics input events. So, the talk I described takes out some of these. It doesn’t go over all of them but it goes over kind of the more common ones that you tend to run into. These are essentially callback methods that happen to mono behaviors, so really any class inside of Unity that’s inheriting from mono behavior. So even if you’re say not, you don’t have your update logic kind of built in, that class is still getting the callback for updates. So scriptable objects, one of the benefits behind it is, it does not have all of these events.

It actually only has three callbacks. One is OnEnable, OnDisable, and then OnDestroy. That’s it. So, it kinda simplifies your coding. Or, it doesn’t really, simplifying is actually a bad term for it. It better divides kinda your coding practices if you will, in that, mono behavior purpose, it’s really a blue print for, I guess, creating a new component type that can be attached to a game object. Whereas, a scriptural object cannot be attached to a game object. It’s really more of method for data or holding data that you work with, which is fantastic for our problem that we’re trying to solve here which is the inventory system and creating the setup objects. So it can help with the debugging, again because it doesn’t have as many of these event calls that are hit. But then it’s also really good for kind of a separation of duty if you will. So, in smaller projects, maybe you have a bunch of coders but you don’ really have a lot of designers. But as your projects get larger, you might have people who are designing and they do not wanna, they don’t know either want to, or they don’t know how to crack open code and create a new, for currency list or.

You know crack and open I guess in this case is, it’s probably more like a database and go and log in. And it’s, honestly, you can get into some kind of designed debates on whether or not you should do it via a database versus the scriptable objects. And I personally think it just depends on how complex it is. A scriptable objects are not kind of the end-all, be-all for replacing all data in my opinion. But in some scenarios, it can be useful. So with this, what you can end up doing is creating kind of more of a UI, inside of Unity, where your designers can interact with them, as opposed to again, digging into code, or having to push stuff into the database. So, it simplifies the flow a little bit I guess for, lack of a better way to put it. So, what we’re going to build out is basically, a very kinda simple item, item database. So we have our item, the item is gonna have a set of properties, one of them is gonna be known as the CurrencyDefinition. So the illustration that I have for this isn’t the greatest but the reason why I’m breaking currency definition as kind of it’s own area is because there’s a lot of like, RPGs or MMOs where you don’t just have coins as means to purchase something.

In some cases you like, wow, you’ll earn honor points and you can use that to buy like PVP gear or in instances, you start to gain specific currencies tied to that and you can use that to buy other gear. So currency can really kinda be scaled out, which is what I’m using as the example for this. So you have your item, which is gonna have CurrencyDefinition, which will have a currency tied to it. And that’ll make a little bit more sense as we start to dive into the code. Then from there, we’re going to have three kind of classifications of objects that are gonna derive from item. We’re gonna have armor, weapon, and consumable. And I picked these three because they have slightly different nuances behind them. The difference for armor and weapon primarily being the classification, right? Armor’s gonna be chest, legs, arms, things like that. Weapon will be one-handed, two-handed, a staff, whatever, and then consumables kind of its own little random kind of bucket. So this is the structure we’re gonna start out with for the next couple of videos.

And then at some point, kind of down the road we’re going to expand on item a little bit more to build that out the attributes. So strength attributes, things like that and we’re gonna actually use the Unity UI to generate this based off of a curve. So it’s gonna get a little bit more complicated down the road, but for what we’re doing now, we’re gonna stick to this style or this organization if you will. So, we jump into Unity. So we’re kind of left off with the last video which was updating her path themes, so that she would navigate towards a merchant and look at the merchant. What we’re going to do is kinda take a break from the main game part and start to code up our scriptable object. So, if I come into, I come into Visual Studio, I create a new folder, let’s call it item. And we’ll create a new class, and that’s a horrible folder name so I’m gonna name this item too. Well. Okay, so. We need to add that using the Unity engine. So to do a mono behavior, you’ve kind of seen me do that before.

You inherit for a mono behavior. For a scriptable object instead, you just inherit from script object, and really that’s it. Now, you can, again you have the three callback she could work with, so we don’t really have a need to do that. So we’re actually just gonna define a set of properties, essentially. So our first one is, name, and we’re just gonna give this a default of new item. The next is our description, and then we’ll just give this again a default. Item description. So everything in my world of this game is going to have a min, oops. I don’t know if you can tell, I don’t work on this keyboard very often. Everything’s gonna have the notion of a minimum level. So, actually, I wanna call this MinimumPlayerLevel. So this is basically the level the player would have to be in order to use the object. And then we’re gonna have a sprite tied to the object. And then I’m gonna skip currency definition until we actually go to create that. Which I’ll do in a second.

And then the way that I’m gonna do, sell price. Is kind of globally tied to an object, so at this point, you kind of have a decision that you could make with your behavior. A lot of games will have the notion of reputation when it comes to interacting with an NPC or faction, and the higher your reputation, the less that they’ll deduct from a specific item. Other games have the notion of, there’s just maybe a fixed amount that gets applied to a specific object in terms of what you can sell that back to the merchant for. Other games have that same notion, but then they also take into consideration durability. in fact, the example when I was talking with somebody about this, they gave me, I guess, I did not realize this, but in WoW you could repair the durability of an object, old, old WoW. They probably fixed this by now, but you could repair the durability of an object and then sell it back, and you would actually make more money because it had factored in durability. The method that I’m gonna take for this game is just kind of one sale price reduction based of the item, which is what we have here.

The one I’m actually missing, which is our currency definition, so this is what we need for kinda the main scriptable object. I’m gonna go ahead and create a new currency definition class. And this one, so I had debated on switching style of this, but l think what am gonna do is leave it as a challenge and then the one that I end up posting out on GitHub will have a solution. So, for now, what we’re gonna do is we’re gonna rely on an and we’ll do silver, gold, and elemental favor, I guess. Because I want to use this as a way to show that kinda scalability of the currency when it comes to kind of setting up your items. I have something that really isn’t the best of examples, which is I have silver and gold listed, and really what you would do for your coins is, well, what you could do. It ultimately depends on you, but another design would essentially be, you just had coin here, and you had that conversion, right? We were following, I guess, a typical game. 100 copper is 1 silver, 100 silver is 1 gold.

So what you could do is just provide a set coin or value to it, and then do the computing when you go to register on the UI, rather than separating these out. However, I do not have at this point a nice, pretty icon for elemental favor. I only have ones for silver and gold. I have it separated out, but this probably wouldn’t be the design pattern to follow, so that being said, the currency definition is gonna have public currencyType. That will be currency, and then we’ll have, oops, equals one. We’re basically just gonna say we’ll set the currency, and then you search the amount for, now, oops. On items, we gonna turn this into a currency. We’re gonna turn this into an array because we want to be able to support multiple currencies. So, maybe you have an item where they can use their elemental favor instead of their money. They have a choice of maybe which currencies they want to use with it, or not even that choice but maybe possible. Maybe it costs coins and it cost their elemental favor.

So it allows a little bit more flexibility in what you require for it, okay. So that’s purchase price. So, now we have a scriptable objects, or we have kind of our two base, right? We have the item, the currency definition, the currency. Or three I guess I should say. I have this organization chart. That’s fantastic, but how do we actually make a scriptable object? And so, with that you actually have a couple of different options when doing that. So, you can basically do it in code. Which is, I think it’s like scriptableobject.createistance, and that lets you create an instance of the object and then you can bind it to asset files. Or you can take kind of the more UI or designer friendly route and create a menu item within Unity itself so that you can use that to create it. So to do that you just wanna add a tag at the top. So, it’s CreateAssetMenu. And then you pass in menuName, which in this case we’re gonna go Item and then Generic. So maybe we want a generic item that’s not an armor, consumable, or weapon, we just want kinda these base properties.

And then you can specify a filename that it gets created with. So let’s call it Generic File Name. And now what that does, is if you go into Unity after it compiles. I’m gonna create a Folder. We’ll call this Items. And, oops. In the folder, you go under Create. Now we have this new item here called Item. And then we have the generic one that we created. So if we click it and see that file name is there, I don’t know, a TempItem we’ll call it. And you can see over on this side, we have a few things. We have the name, the description, the player level, the sprite and sell price. What we’re missing is actually our currency and that’s because it’s not serialized. So, that’s a quick fix. So, when you’re doing the scriptable objects, these are serialized. The currency definition, it’s not a scriptable object, it’s just a normal one. We can do serializable on it. Now, if we come back over, that should load. And now we can see that we have purchase price. And then we enter 2, we can see that we have elements that we can define.

Still not the most pretty of UIs, right? Cuz you still have to kinda enter it, and then expand, and it’s just kinda clunky. It’s so much nicer if this was maybe in a list format, so we can actually do that by editing the editor inspector stuff. So I’m going to show a kinda brief example, of it, by formatting means, and then towards the end of, after we’ve got kind of a matching set up, what I wanna do is, come back and create a little bit more of robust solution. Where maybe we can auto generate things or auto generate properties that are high to, or I think I called that attributes, auto generate the starts that get high to in attribute. So do kind of more UI friendly stuff that helps maybe our design, or really even us just generate items a little bit quicker, rather than sitting here and manually creating every single one. So, to start what we can do is basically edit the layout of this particular object. So, we are working with anything related to the editor. You need to have an editor.

Which is what we’ll create here. If I come back in It should pick it up, it’s not what you can do is. We get this to read. All right, so I close this, do open it. It should generate the solution file and pull everything in. [INAUDIBLE] It’s because I don’t have a script in there. [LAUGH] Silly, silly me. Okay, so if we add a script and then we do, we’re gonna call this CurrencyDrawer. Now we should see. So while what I did before wasn’t necessary, it is a good thing to kinda keep in mind that if for some reason you see, and this happens pretty infrequently, now. I can’t remember the last time it actually happened to me, but if you happened to see that it’s not pulling anything over, you can force the regeneration of the solution files from it. So we do have it though. It did pop up, yay! Because I created this inside of Unity, it automatically assumed I wanted a mono behavior and that I wanted start and update. I don’t want any of those. Then I see it did give me was my using.

So to expand on the UI, in this case, actually we need. Editor, not the engine so, we actually want to. Inherit from the property drawer. So the documentation has some good stuff on properties we’re working within. Again, I’ll link to that stuff inside the video description. Basically what we want to do, is we’re going to override on. You can use on GUI for both your mono behaviors, and then of course as we’re looking at right now for your editor scripts. OnGui used to be the way that you would create UI inside of Unity. I think pre-Unity 4, I want to say, but I could be wrong. I don’t remember the version that they started to add their UI stuff into, but it used to be you had to draw stuff in the OnGUI. Now you don’t have to for a lot of the UI, they’ve provided a lot of really good assets and functionality around it, but you can still use it as a quick mechanism to build out stuff. When it comes to the editor, this, of course, is the way that you’re gonna end up designing it.

Get rid of this, so we’re gonna do, oops, BeginProperty. Basically, what BeginProperty is doing is, it creates a property wrapper, which is useful for making like GUI controls work with serialized properties. Not everything needs this cuz Unity will provide some functionality out of the box. You wanna take a look and see what it is that you’re creating and whether or not that functionality is provided or not. I wanted to use it as an opportunity to talk, and I didn’t really see much farming including that, which is why I have it for what I’m doing. We’re gonna set the position, so we’re gonna pull the editor, oops, that’s label. It’s here momentarily. Okay, so basically we’re just pulling out a wrecked position based off a prefix label, and you can see we’re actually pulling in the GUI content from here. Then we’re gonna set an indent, so this is really what I found at least. I haven’t done too much of the editor stuff, which is part of why I want to start to build out that area that I was talking about.

Making it so that you kinda auto-generate stuff cuz it’s an area that I wanted to start learning a bit more. For me, where did it go? Yeah, it did work. For me, that’s just a lot of trial and error to kinda get it to work right. Basically, what we’re doing is, we’re kinda setting the indent level for this and that’ll make sense when you can visibly see it on the screen. Then, now what we’re doing is setting basically direct position and the size of the currency, but, and again, we want to kind of illustrate this amountRect shortly. We’re just gonna say 2, so the reason is we have, actually, if we look we don’t have this tied to anything right now, so it won’t override it. Where’s my CurrencyDrawer? I don’t want [INAUDIBLE]. Sorry, where is my item? Duh, no, I’m in the wrong spot. That’s my code, this isn’t what it’s supposed to be. I was trying to look at this item. If we look, each element has the notion of currency and of amount. Basically, what we’re doing is we’re kinda defining the space in which the stuff will live in our kind of new and improved prove you wine were really only targeting this suction that were manipulating with it.

So when we’re defining currencyRect and amountRect, were basically defining it’s position and then which is these first two. And then where position as defining the height and the width. So It’s really kind of the same, except for our, oops. Actually it’s not. So, if I were to do this, these would basically overlap on each other. Their position is exactly the same. Whereas amount, we want to offset And we’re gonna offset this by 110. And then we’re actually gonna provide a different size, because we don’t really need as much space as we do for, say, the currencyRect. So, we’ll do the height. So again, to kinda look at this, we’re basically saying, hey, position.x and y, whatever you are, put this Rect there. And it’s height is going to be a hundred, it’s width sorry, is going to be a hundred and it’s height is whatever the height of it should be. And then for the amount we’re basically saying okay, position x which is the same as the other one. We want that, but we want to offset it by another 110.

We’re going to keep the same why and we’re going to make it 75, because we don’t need it quite as big. You can make it larger if you wanted. And then what we’re going to do, we need to kinda populate this with something. So We’re gonna create a property field. We’re gonna pass in the Rect that we’ve defined up above. We’re gonna pass in property.findPropertyRelative. And then we’re gonna look for the property. And when I hook this up, this will make a little bit more sense, but what this is basically doing is it’s gonna look for the property Called currency which of course is gonna be our So I’m kinda just matching names if you will. So Currency and then, element Dear, content. And then, okay. So I am just going to copy this down and then do the amount track. there we go, amount. So, again, we’re basically just kind of set the field. So we’ve defined everything that we want here and we’ve indented ourselves with this. And then we’ve basically created our new property fields with this.

So the last thing we want to do, well second to last thing. We just want to reset it or do we indent level back to whatever it was. So again, we kind of take a brief look. This has to do with the serialization may or may not be needed depending on what it is that you’re doing. So I recommend reading the documentation around that. We’re essentially defining the position that we want to work with. We’re storing whatever the indent level is normally, so that we can restore it later. Then we’re resetting it to zero so we’re going to kind of bring it back out to be in line with everything else. We’re defining the rectangle so basically the position and the width and height. Of our currency and our amount areas. And then we’re basically creating it by and feeding in our definition that we had before along with what property it’s gonna try to pull off and we still have to tie this to our currency definition. But once it’s tied to it it will kind of look for this by name and then we’re resetting our indent level and then we’re ending.

This call, the begin property call that we did earlier. So the only thing that we’re really missing from here is again tagging that this property or currency belongs to this here, or when it’s registered. And you can do that by basically defining an attribute. So you do CustomPropertyDrawer And then you do typeof and this is typeof CurrencyDeffinition you’re using. All right. So that should be it. So if we come over here we should see that this is gonna do some magic and now we are kind of better Better line. So instead of having that kind of ugly, indented hierarchy, we’ve pretty quickly created just a more friendly view of this where you can kind of select more or less whatever that you want. So you can do even more stuff with kind of cleaning up this editor. A couple of really quick things without digging into having to create a property drawing, is really just adding headers. A things that you can define so, for example. Let’s say we want a header and we’re going to call this general properties.

By defining this here and coming back, you can see once that load, so we have this header here, so this will be nice for when we create the armor and the weapon and the consumable, because they’re gonna have their own properties. So, we’ll do another header down below that’s gonna organize their specific properties. I also like the idea Of doing a header for currency. Then kind of separate this out even more and that we have a currency properties, space that a little better. Another good one is the, what is that called. It gets like, no it’s not header. My brain is just completely leaving me right now. Aah Multiline, I was on the right track. So you can basically define a Multiline box, so for our description as we maybe a little bit larger, we can row that area a bit more. Another is under a minimum level. We can do Range(1,60), though we say we can go as high as level 60. When you define a Range, it adds this nice little slider. And so you can actually do things where you can define a custom range where maybe it has a min or a max.

And it’s got two little circles on the slider and you can kind of define a range [INAUDIBLE]. So you can end up kind of extending this, of course you can kinda mix and match so we could do the header and then of course, we could do a header for the description and then the max range for it. So you can really kinda spruce this up to make entering stuff a little bit more easy to follow. Depending on your style. What we could have done for purchase prices, actually added a button here, where it says like add new, currency, you click it and it adds a new element. And then we could just hide the sides all together. To create again, a little bit more of a friendly UI behind it. So back to, I guess finishing up our scriptable objects. So we have everything, the only thing that we’re missing are the armor, the weapon, and then the consumable. So, go back into item, do a class. So I’ll do, I guess we’ll do armor first. This is going to so let’s see. Armor we’ll do public enum types I don’t know we’ll do head, shoulders, chest, belt.

Feet, wrist and hands. And then we’ll do public Types ItemType. And then we’ll do header Armor. Look at that. So again, we wanna make it so that you can create this particular item. Right now, we only have the ability to create the other one. So, we are gonna call this Item Armor. We are gonna kinda nested under that same spot, and we’ll do Armor Name. So we can actually just create the other two real fast. This next one is going to be weapon. Engine. The item. So again we’ll do Item and then works on Weapon. So, with Weapon, it’s going to be, this is gonna be the same, Weapon actually will have a couple more so, do public enum types. This will be, we’ll just keep it short Sword, Dagger the difference with this is a, we’ll do maybe Hands. And then we’ll do a Range(1,2) and then we’re going to do public types ItemTypes stick with that and then we’ll do the header. And then the last one, I’m kind of jumping through this fairly quickly cuz I think at this point it’s a little self explanatory, and these are last one that we need.

So like consumable. Consumable is different. It’s design just a hair. Actually, I guess the only, I realized my design is a little bit wrong here. Because a consumable item would basically have, ManaPotion, HealthPotion, Poison. It would have an amount that gets applied. Public. And this actually you could definitely see. And we’ll probably will end up. I haven’t built up the logic behind this stuff. But as we build it out, we’ll probably expand this class. You’re not really stuck or tied to just properties. We could add methods in that maybe get called, as well or on it. So this’ll grow over time. Type and then of course we’re gonna give it the usual header. Consumable properties and then. This is going to be consumable. There we go. So I think, just did a whole bunch of coding, so let’s hope that it all works right. So if we right click under items and we go under create, we go under item, we now have multiple. So we have our Armor, our Consumable, our Weapon, our Generic.

I guess let’s take a look at the consumable. So, we can see obviously it’s pulling in the stuff that we defined as part of item, even our currencies. And then, it’s also pulling in our specific properties doing this. So, that’s really it for what we’re gonna tackle in this object, or episode. It was kinda a lot to hit you with in terms of MonoBehaviour and scriptable objects, both very powerful, both have Kind of their place in game development. So the challenge that I want to leave you with in the end of this episode is, taking currency definition and changing the currency item to be a scriptable object. So really what that ends up mean. Is you wanted to find, so currency definition is still have the amount that lives there, but that currency type that enum that should really not be an enum. That should be pointing towards a scriptable object, that has a name and then has a texture or a sprite tied to it. And then, that way when we go to set up the UI, we can just kind of iterate through that.

And then of course, that separates out kind of the code side to the cosigning of it from our design side. And of course, we’re not doing that for the Armor, the Weapon or the Consumable, because each of those individual items that get created will have a sprite item and will have their own data. But you really would only Define a currency type once. W e would only define a gold currency the one time and that’s it, it’s it’s own thing. So like I said, I will build that out myself and I’ll post my solution to that challenge out on GitHub, so thanks for joining us and I’ll see you on the next episode.

 

Read the video

In this episode, we’ll continue our project by building a foundation for our item system using Scriptable Objects. We’ll also look at some of the ways that we can modify the Unity Inspector, such as changing the layout of arrays, adding headers, and altering control types.

Resources


dotGame

dotGame is a blog dedicated to game development with a primary focus on .NET technology. The episodes will focus on tutorials, tips and tricks and interviews. All tutorial project files can be found on the .GAME GitHub repository. Have a topic you'd like to see covered? Great! You can request a topic by opening an issue on the GitHub repository or by emailing dotgame@microsoft.com. General feedback can also be directed to dotgame@microsoft.com.

    Leave a Comment

    Your email address will not be published. Required fields are marked *

    Loading...
    1Code.Blog - Your #1 Code Blog