Game development on .NET

Inventory and Store System – Part 4.1 (Wiring up the UI)

dotGame
Inventory and Store System – Part 4.1 (Wiring up the UI)
5 (100%) 1 vote
(Video Transcript)
Hi guys, welcome to the next episode of .GAME. This is going to continue our inventory and store system project. So in the last one, we built up the UI for the store system. And this one, we’re gonna hook up the store with our are scriptable objects that we can kinda start to populate data and then we’ll work in a little bit of game logic in terms of when we show and hide the UI. So let’s get started right away, I have made a few changes since the last project, nothing tremendous. You can see that the UI is just a little bit different in terms of coloring and then I’ve also added this little x button. I realized we had no way to actually close the UI. So we’ll hook that up but really to show you the close button is on the same level as the header. And then it uses the same button that we saw in the store container for the by button, it’s that same brown button. It’s that same brown button the text just a little smaller and the text I put is the x. You’ll just want to create a button which I think I’m just realizing we didn’t really talk about in the last one but if you right click UI, and button is just another component that you can work with.

You just kinda create that in, you don’t have to worry about hooking it up, we’ll talk about that in this one, and just getting the image size set, and your text set, and then the positioning, and then you’ll be all caught up. The other thing that I did. Was if we take a look at the store item container, I went through and reworked the layout a little bit. I did the things I mentioned in the end of the last video, where I added kind of an image inside of an image. It will actually populate the child image. It’s like its image inception. [LAUGH]

>> Image inside of an image inside of another image. But we’ll hook up the child image, and then of course we still have our same text and stuff. And then we’ve got the same area for our currencies, so it’s really just laid out a little bit better in terms of the sizing and the positioning, not too much changes. So go ahead and delete that off. So like I said, actually the other thing that I did, was I went ahead and I created the data. So two videos ago we talked about scriptable objects, and we worked together on defining really what the item would look like if we wanted to create this object. We defined the armor, the consumable, the generic and the weapon. So all of this, as well as the currency. All of this is the same step that was defined in part two. The only thing i did was go ahead and created some of those items. So, I think actually might have everything here we can take a look. But really, you just go create, item. I reorganized this. But you just pick one of these.

Let’s just do. Where am at. I’m at armour. Let’s do another hat. I don’t know. Actually, I gotta delete that, I didn’t mean to have that there. But basically, so you can just right-click, Create, and then define your properties like we talked about before. It’s all pretty standard. And just build out a few different items. The organization of how you store the data is totally up to you. We’re gonna create to start we’re gonna basically create an inventory scriptable object that is going to be used to define what a merchant has in terms of their inventory items. So I actually accidentally had that left in from when I was walking through. So again just create out some data elements based off of that and you’ll be really caught up to our deviated [INAUDIBLE]. So. To do this, we’re just gonna create a new Inventory class, and then drop the namespace. And we’re just gonna derive, UnityEngine, from scriptable object, very similar to what we did when we defined the armor consumable and other items.

And then we’ll just do a public list. And then the last thing is we do wanna do a we wanna have another, jeez, my words are failing me today, a Asset menu item. So, we wanna be able to pick this from the menu, so create Asset. I’ll do menuName. I’ll go Item/Inventory. And filename, we’ll do “Inventory data”. So, again what this line does is this puts it as a item in the menu. So when we go here we go Create > Item, save it, there you go. Saw Unity load it, item. Now we have the inventory item there. So, what we’ll do is we’ll create the inventory data and then we’ll just call this general merchant inventory. And what we have is there’s a list. I think I’ve created, I want to say four items. You can just expand the list, basic staff so you can pick our objects. And see I defined the staff, a health potion, a mana potion and wizard hat. And then that’s it. So now, we basically have our database. And we can tie this to any merchant that we want to create kind of an instance of this if we wanted to.

So, what we can do is start to write the code to hook this up. So the first thing that we’ll want to do let’s actually change our merchant up a bit. So, we’re gonna, one of the problems with how this was built originally was when we’re doing a check to see whether or not we’ve clicked on the merchant. Click owner that check actually hits this outer sphere. And the problem is we might be navigating around the merchant or near the mechant but we didn’t actually click on him so we really don’t want the store to pop up. So it’ really, really weird Player experience when you click right here, just to move, and then the dialog pops up. So, what we basically needed to do, is we need to separate out this sphere for proximity check from this kind of box sphere that we have. Really, if you’ve clicked anywhere close enough in this box sphere, it’s so close it counts in my mind. So, the first thing that we have to do is really kind of just adjust the Merchant, which apparently I forgot to delete out.

So, I’ve already done this. So, the Merchant originally had a box glider and then this sphere. This sphere glider. And so really all I did is I created an empty game object and I moved the sphere collider, which you can do if you click on the little gear, and click on it and do copy component, and then if you go to another game object, you can click on this again, and do paste component as new, or if you already have a component that’s like that, you can paste the values to adjust it. Is also actually super useful if you’re trying to align stuff up in your transform or your rotation and things like that. You can really just copy these values out and then paste them there, or copy a script to another script. So, I just kind of copied both this spherical lighter and then the general interaction script and put them on this empty game object that’s a child at the merchant. The other thing that I did is I made sure that the Layer tag was set to Default and that’s because we’re actually gonna do a check.

Actually, I don’t know that that’s necessary. I think this might not be necessary. I think I might have come up with another solution, so we’ll see as we as we go down we’re hitting uncharted territory now as we’re coming along for the journey. But, so I did set this to default cuz I think I was planning on doing a different ray cast, I ended up doing it a little differently. And then, the other thing is, so the layer for the merchant as mpc. The tag was empty, so I just added a tag. Hit the plus button, typed merchant, and then was using this for a check a little bit later that you’ll see. So, the top level merchant, you wanna change the tag to say merchant. Make sure the layer says NPC. And then, it should only have the box collider, and the nav mesh obstacle, and then the animator tied to it. The sphere collider and the general interaction script are on an empty game object that you can call whatever you want. I called proximity check, that’s a child of the merchant and those are just kinda required again for the reasons that I had explained so to have this work right.

We can go ahead and update the general interaction script to start, I think that was here, this guy. Close out. And, actually, I’ll close this up. Okay. I didn’t clear it out, I am so sorry, guys. So, the first thing that we’re gonna do is do a _parentTransform. So, we’re adding a new variable, global variable For the parent transform, and this is because, so the general action script was originally written with the intent of it being on the merchant game object. So anywhere we had transformed dot whatever, it was doing that on and that’s a spot I missed a change in it. It was doing that on whatever object it existed on so it was doing it on the merchant. The problem is now if we do transform.rotation it’s doing it to this child object which has no effect, right? It’s not gonna control the model, it’s only gonna control really technically I guess maybe the spherical rider as it rotates around. But not the right interaction, so what we need is to have a reference of its parent, which is the merchant.

So we created a private variable that’s a transform type called _parentTransform. I did do it, I think I might need to clean this up a little bit, so parent transform is basically saying, you can get the parent by doing transform.parent. So this is basically saying, hey tie me to the parent’s transform, so that just gets added in start And then throughout here what I ended up doing is, anywhere that had transform.rotation. changed to be _parentTransform.rotation in the RotateTowards, so if we highlight that, you can kinda see I did it up in our directions a couple of spots throughout. So really just wanna reset that so that it’s always adjusting and pulling the values off of the parent’s transform and not it’s own transform. Again, just because logically we’ve moved where this game object exists. Okay, so with that fixed, you can see as you move, good tests to make sure everything is as if she ends up rotating. I don’t know why she didn’t rotate, I know why she didn’t rotate.

I think she might have some bad logic in hers, so I’ll have to take a look and see. So that was working before anyway, you can see the most important part in the change that we’ve made though that would affect the merchant is that the merchant is rotating and rotating back. She’s not rotating, the player 1 isn’t, which we’ll have to take a look and see if it’s a quick fix as we start to build this out. Okay, so now we can add a MerchantInteraction class, so. All right, this is gonna inherent from, This is gonna inherent from MonoBehavior over here. Okay, and the point of this class is to really handle whether or not we want to have the UI pop up, and then this is where we would put any merchant specific behavior. So as we start to build out the logic for maybe removing an item or buying and selling some of that logic will probably be in this class. For now, this one’s primarily gonna handle the showing of the UI, so to do that, we can do private inventory. We’re also going to define the list, so we’re gonna create a variable that holds that data list that we had created a little bit earlier, that ties it to the merchant, storeUI.

So the thing about this is, I wanna create a reference to the storeUI. The reason that I’m going to do it in this manner is because we’re gonna start out with the stuff deactivated. So doing a hierarchy traversal can be a bit tricky and there is a way where you can traverse down and find inactive objects. But it’s gonna through every single inactive object on top of the active objects which can be a little bit costly. So what I’m gonna do is I’m actually gonna set these up so that we can add them in the inspector and drag and drop them. Now, if we go to the merchant and we add this script You’ll see that there is no properties to do, and that’s because I’ve set these as private. Now, there are two ways around this. You can either make everything public or you can serialize the field for the private variables that you want to see. So if we add that to both and we let unity do it’s thing, we can now see those in the list, so we could populate the data. Here we can give a reference to the store ui which is somewhere.

Here it is. All to our private variables. Alternately, we could’ve again done the on wake or on start. We could’ve done some sort of a game object reversal if we wanted to. There’s lots of different ways you can approach something like this. Okay, so the other thing that we’re going to learn about today. Oops, IEnumerator, is coroutines. So these are super handy. So a coroutine is basically a really handy way that lets you perform an action over multiple frame updates. So usually when you have a method it’s gonna execute everything in that method and then it’s gonna give control back to unity when it’s done. With a coroutine, you can specify certain criteria that have the routine itself pause and hand control back to Unity. In which case Unity will, for the next frame, update and then it will come back and check. And if the criteria’s been met, it’ll continue, if it hasn’t been met, it’ll pause and give control back. And so it’s a great way to do coded animations, if that’s what you’re doing.

It’s also a really great way to like wait for certain things to change, so a good example of this is, actually one of the games that I’m working on right now. We have game modes tied to it, and there are certain criteria that needs to happen for the game mode to progress. And so we’ll do a wait to see whether or not that criteria has happened, and if so it will continue down the game mode logic. So it can be very, very handy. Now, the reason we’re erroring out is because it requires yield return type of statement. So to show you this, we’ll do yield return and you can do a couple different types of these. There’s actually, I wanna say it’s like four or five, maybe? There’s a few. So if I do, we’ll do, I might have to fix something to make this actually happen because I don’t think the other one has it, but we’re gonna do a delegate. It basically waits for move controller, and I’m gonna make the IsMoving property that’s already there public. Oops, Sorry. Let’s try that again [LAUGH] not public, false.

All right, I’ll explain this in one second. Let me go fix the movement controllers code. So we already had this property defined as a private which is is moving, so we’re just gonna turn that public, public apparently What did I mess up on my syntax here. I know, new, missed my new keyword. Okay, so basically what we’ve done is we’ve said, okay, when this coroutine gets called. The [LAUGH] first thing it’s gonna do is it’s gonna yield return and it’s gonna wait until IsMoving is set to false. So, the idea behind this is, if we click on the merchant, and our player starts to move. What’s gonna actually happen is the storeUI would pop up right away if we didn’t wait until they at least made it to our person, right? The actual behavior that we would want is, our player navigates to the person. And then once it’s reached its destination, and again assuming that they’ve actually clicked the person, not clicked around it. After it’s hit its destination, then the UI would pop up.

We need a good way to be able to tell whether or not that’s happened. And so I went with coroutine and then we’ll just check to see if IsMoving is false. And so technically we could have stuffed some of this logic in, we could have not stuffed this particular logic. But we could have probably done something, an update that triggers it but the reason I went coroutine is because I kinda wanted to do this monitoring of a specific variable. It just seemed like the easiest way to tell when the movement has stopped. It does create a couple of complications, which we’ll go over very shortly. The other thing that I noticed with this behavior was, even when the movement stopped, they were still rotating. So in some scenarios it was like it happened, the UI would pop up a little bit too quickly. Now, I could do the same thing where I do some checks against whether or not anybody’s moving, or rotating, if nobody’s rotating, do it. Instead, what I noticed timing wise is we could actually just pause it for a second or two and then everybody was done rotating and everything was good.

So that actually has another type of, way to check it, which is waitForSeconds, so you can specify a certain amount of seconds. So basically what we’re gonna do is we’re gonna wait until we’re done moving and then, when we’re done moving, we’re gonna wait another second. And then when that second is passed, that is when we will do, we will surface up the UIs. So the first thing I wanna do is make sure that the parent, which is that canvas, is set to active, just to be safe. And then the second thing is we’re gonna set the actual store portion of the UI. So we’ve created a reference to the store but, just because the store is turned on, which you can see it actually is right now, doesn’t mean that the canvas, you can see it, because the canvas is shut off. So, actually, what we probably want is the reverse of this. Which we could leave the canvas on, might have some click through stuff, depending on how you’re doing it. So it’s up to you on if you wanna shut the canvas off versus leaving it on.

And what the UI has inside of it, and then we’ll shut off the store and then really this is the most important one that ends up getting toggled. So, again, kinda looking through the code just to do a quick review, we have an enumerator, or coroutine. That coroutine is actually gonna take in movement controller, which is this script, and this script is what has the reference to IsMoving. And then we’re gonna wait until the player has finished moving, so they’ve reached their destination. Once they finish we’re gonna wait for another second, just to make sure everyone’s done rotating. And then we’re gonna make sure that the canvas or, really, the parents of the story UI is active. And then we’re going to make sure the store UI is active, and then the coroutine is done at this point. So, to start a coroutine, you actually have, technically, three different options. Start my UI coroutines, so [LAUGH] I’m skipping words, I can’t talk today, I don’t know what’s wrong with me.

So, you can do it in a few ways, you can just type StartCoroutine, and then you can see there’s a couple of different overloaded methods, so you can provide a routine directly. You can provide it as a string, and then you can pass it and stuff, and the two typical are you’d either pass in the routine or you pass it in in quotes. Now, the caveat behind these is, with StartCoroutine, comes StopCoroutine, so you have StopCoroutine and you have StopAllCoroutines. Now, for the most part, coroutines have been fairly reliable but, the couple of areas that I’ve run into where they haven’t been, is really in the stopping of the coroutines. Most of the time I think they always start, but the stopping can be a little bit tricky. So, for example, as I was running through this project originally, I had written this up so that the movement controller started the coroutine and then another area did the stopping. And they both did it in, I think, at least, they both had done it in the same way where they were referencing the method directly.

But my StopCoroutine was getting completely and utterly ignored, so then I started to walk through a few tests, I tried StopAllCoroutines, it still wasn’t stopping it, it still would execute. And so then I started to do some research and some digging because I’d done it awhile ago but I couldn’t remember exactly why, and there are a couple of little mishaps that can happen. So, for example, if you start a coroutine and, let’s say, you pass in the method directly and then you do StopCoroutine and you pass it in in quotes, that provides this weird mismatch where in some scenarios it won’t actually stop the coroutine. So you have to start and stop in the same method that you do it in. And there are other kind of weird nuances behind it, so the most [LAUGH] longest explanation ever, the most, Not common, reliable, I guess reliable is the word I’m looking for. The most reliable way that I’ve found to do this is to store a reference to the coroutine and then use that reference to stop it later.

So that’s what we’re gonna do. So we’re gonna do, let’s see, what did I call this? Yeah, we’re gonna do, I guess, Store, oops. So what we’ll do is, so if storyline does not equal null. So we’re gonna do a check to make sure that the coroutine has been stopped before it starts. So what could happen is we could have multiple of these that are running. Because maybe we started it several times and then the UI runs into some weird behavior if we decided to expand this beyond more than what it is. Right now, with how it is, you probably really wouldn’t notice if it was running multiple ones cause it’s not like it’s setting it off and then turning it on or doing anything. But you still kind of run the risk of triggering it multiple times, so in this scenario, what I’m gonna do is I’m just gonna check if it’s null and, if it’s not, we’re gonna stop it. There we go. So we’ll stop it first and then we’ll do start, or actually, we’ll do, Actually I need to do MovementController moveController.

So basically, we’re just gonna set this coroutine to the variable and then we’ll do StartCoroutine, and then _storeUI. Oops, _storeUICoroutine. There we go and then this will be StopCoroutine storeUICoroutine. Pretty simple. I’ll zoom out just a hair, hope you can still see that. Again, so to kinda take a look, we’ve got our coroutine, we’ve already gone through that. We have a method to start the coroutine and that is going to check to make sure that there’s not one already running, if it is, then it’s gonna stop it and then it’ll start it again. Okay, so that’s really what we need for this, the other side that we have to do to make this fully work. Is back over in the MovementController, we need to add some logic to actually trigger that we’ve clicked on the merchant. So, there are a few things that we can do, we’re actually gonna do it in this section here. So, basically, we’ve clicked on an NPC, this is where that merchant tag that I described earlier comes into play.

So leave all of this logic the same, but we’re gonna do another check that says, if hit.transform, so remember hit is whatever object was hit by array cast, at tag.Equals. We can check to see if the tag is equal to merchant. And then, this is the other neat thing, so we could do, I think this part, technically, isn’t needed but I wanted to show it to you. We can do a check to see what collider was actually hit. So when you’re doing collision detection, it’s really just detecting, okay, actually, [LAUGH] let me show this to you. So, remember, we had originally on the merchant, we had two, we had the box collider and then we had the proximity check. If you have a scenario where you have a different type of collider, cuz you can’t have the same collider on the same object. We can have multiple sphere colliders, but we can’t have a sphere and a box collider, and I think there’s one more, on the same object. And if you hit that, you can basically check to see if it was a box collider, or sphere collider, anything.

So, if it had a different behavior that you wanted to check for, you can do that, which is a pretty handy little trick. So, again, I don’t actually think that it’s needed in this scenario, but I’m gonna leave it. So the other thing to make this work is we’re gonna get the MerchantInteraction component. And then we’re gonna start that StoreUI Coroutine and we’ll pass in this class. I think that will work, famous last words, let’s see. No build problems, I like that, we’ve got our icon next to it. No UI, I didn’t click on her, so that’s expected, let’s click on her. We’re taking the long way, very long way, not sure what we’re doing, there we are [LAUGH]. She was really taking the long way. All right guys, we’re gonna go ahead and stop this part here, we took a look at coroutines and kind of set up the starting behavior. On the next episode, we’ll go ahead and finish out the UI in terms of closing it, locking out movement and then, of course, the most important thing, which is populating our data into that UI.

So there’s no challenge for this episode, at the end of the next one, we’ll have two challenges that’ll cover what we’ve looked at in the coroutines and then cover some of the stuff that we’re gonna look at in the next episode. So, thanks for joining, and I’ll see you next time.

 

Read the video

In this episode, we will continue our project by hooking up basic mechanics to the store UI. We’ll cover the concept of coroutines, as we incorporate logic for showing the dialog. We will also create an inventory database for our merchant which sets the stage for the next part of the series: populating the data.

Resources:

  1. GitHub Repo
  2. Coroutines

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.

    Comments to Inventory and Store System – Part 4.1 (Wiring up the UI)

    • Nice nive nice love love love 

      lucaskuatt March 19, 2017 9:57 pm Reply

    Leave a Comment

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

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