[Unity Coding Tutorial] Drag & Drop Inventories in Unity! #gamedev #tutorial #coding #unity #indie

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
inventories they're a key part of most item-based games and in almost every single genre and you've probably wondered how you would go about adding one to your game well today let's create an inventory with the ability to pick up drag and drop split and stack and drop items so the first thing we need to do is to set up our inventory menu and to do that we need to create a canvas to act as our player UI on the camera of our example scene here let's add a new canvas and rename it to player UI let's also make sure that when we add our canvas and event system is added to our scene because we will be using events to create our drag and drop system later and they will not work without this in your scene next let's add an image to our game to use as a backdrop for our inventory menu and to do that let's create a folder in our assets folder called UI and let's import an image to use as a backdrop by the way if you would like to use any of the images used in this tutorial there is a link down below to download them now let's set this image as a Sprite and we want to set up the slicing borders for our image to have a clean resizing of the image which is in the Sprite editor but this is grayed out because we need to download the 2DS write package from the package manager let's open the package manager and search for the 2D Sprite package and download it to our project now that we have the package we can now access the Sprite editor let's go back to our image and click on Sprite editor and in there we are going to want to adjust the borders of our image this allows us to scale our image in any direction without causing stretching or squashing by only scaling the area in the middle of the borders and only stretching the areas on the edges and leaving the corners unchanged when we scale our image now let's create our inventory menu in our player UI let's create a new UI image and let's add our backdrop image to the source image and let's name it inventory menu and when we do this we won't see anything show up in our scene because our canvas is gigantic because one square meter in the 3D view is equal to one pixel so in order to work on our canvas let's double click it to focus on it and if we click the cube that's in our 3D Gizmo that's in the top right corner of our 3D scene it'll switch us to orthographic view which makes working with UI stuff a lot easier now let's add our backdrop image to our source image and let's adjust the pixels per unit multiplier to something like 5. this setting adjusts how big each slice or the nine areas made up by our border settings is when scaling our image now let's adjust the size of our backdrop to whatever feels right for the size of our inventory menu now let's create our inventory slots first we need an image to be our slot image let's add it to our UI assets folder and like before let's set it to us right we will only be scaling this image uniformly so we don't need to set up its borders like our backdrop now let's create our new UI image let's name it something like item panel and let's add our panel image to the source image now let's make sure the arraycast target checkbox is checked this will allow us to use the area of this image as a button when we write our code we can also alter the size of this button by adjusting the raycast padding settings here if we want to make sure parts of the element that are supposed to be invisible do not act as a button now let's add another UI image to our panel and this will be our item icon UI let's scale it to fit inside the item slot image and let's make sure to turn off raycast Target to avoid any weirdness with our drag and drop code let's also disable this so we don't have to look at this white box we are going to be toggling this on and off later in our code as we need this anyways now let's make our stack size element let's add a UI text mesh protects and when we try to install this for the first time we will get a pop-up asking to install some needed files for text mesh Pro to work properly so let's click on import TMP Essentials to install the needed files once that's installed we can now adjust our settings let's rename our text to something like Stacks text so let's set our text to a common number that would be used on a stack of items let's adjust our settings to something that looks good to us and also fit it inside of our panel let's also open the extra settings panel so we can uncheck raycast Target to again avoid any weirdness we can also disable this text by default and now that we have our elements in place let's make this a prefab by creating a prefab folder and inside our prefab folder let's create a UI folder for our UI prefabs and let's drop our item panel into our UI prefab folder now to our inventory menu we want to add a grid layout group and we do that by first adding a UI image and removing the image component and then adding a grid layout group component what a grid layout group does is pretty much what it sounds like it will align all the UI elements that are parented to this element to a grid which is what we want to create our inventory slots layout in our grid layout group component let's set our constraint to a fixed column count and let's set our constraint count to something like 8. let's also change the Anchor Point at the top left corner because we want our slots to grow to the right and down let's move our grid layout group to the top left corner of our inventory menu and you might have noticed that after we put in our item panel our canvas seems way too small and that's because it is need to tab over to our game view to force a resize of our canvas and only tab back in it will be much bigger for us to work with and after we do this our backdrop will obviously be too small so let's fix that real quick and let's also remember to name our grid layout group now we can test our grid layout Group by taking our item panel and dropping it onto our grid layout group and when we do this it will snap to the center and if we duplicate our item panel a few times it will all snap into a grid foreign now that we have our base UI set up we can start making our scripts the first thing we need to consider is how we want to handle the items that we're placing into our inventory however we want to keep track of what item we're working with what is our item's name and what's the maximum stack count of set item and what icon should we use for that item well a good way to keep track of this kind of information is to use an abstract class along with many other useful features as I go over in this video about creating roguelite style items so what is an abstract class well it's easiest to think of it as a template class that allows us to have unique code for each individual class that derives from the abstract class but those base classes can all have generic functions that can be called which are created in the abstract class this will allow us to create functions that can do all sorts of things like return or item's name stack size item icon Rarity durability anything you want but today we'll just be doing the basics let's create a new folder named scripts and inside let's create a new c-sharp script let's name it item and let's open it up so first let's remove everything to do with mono behavior and remove the two using systems.collections at the top and then above our class let's put in square bracketsystem.serializable this will make this class or any class deriving from invisible in the inspector let's add the abstract tag to our class inside of our class we are going to make a few methods that we can call that all of our classes that derive from this base abstract class will have access to and these methods can either have an abstract tag or a virtual tag the difference between these tags is that an abstract tag method must be overridden when we derive from this class where a virtual method can be ignored if wanted because if it's not overridden it will default to the code that we place inside the space abstract class so let's first make a public abstract string method called give name and this will make sure because it's abstract that we have to give a unique name for each of our items now let's create a public virtual end method named maxed X and because it's a virtual method we're going to have to add a body so let's create a body and then let's put in return 30. this return 30 will be the default that we can fall back to if we do not override this method and then finally let's create a public virtual Sprite method called give item image and this is how we were going to return a unique item icon for each of our items and the way we'll do that is to use a handy feature called resources.load and the way we do this is we need to create a resources folder any folder that you create within your Unity project called resources will become a resources folder and can be used by resources.load and resources.load gives us access to any of the assets that we place within these resources folders We just need to give it a directory but you should know that any asset that you place with any resources folder must be loaded in at runtime because Unity has to assume that any item that's in a resources folder will be used at any time so only put things inside of a resources folder that will be used often and at random and item icons seem like a good candidate for this so let's create a resources folder in our assets folder let's create a new folder and name it resources and inside let's create a new folder named UI and then inside our UI folder let's also create another folder for item images let's import a few item icons they have an icon for a wood item an icon for a stone item and a question mark icon we'll be using this question mark as our base return for our give item image method this will allow us to not override our give item image method in our base classes and our items will still return this question mark icon letting us know that the item has no icon but still shows up in our inventory and to do that we need to remember this directory back in our item class let's create the return for our give item image method let's put return resources.load as a Sprite and then we need to pass in the directory but because resources.load assumes we are looking in a resources folder we only need to put as a string the remaining directory let's put UI item images no item image icon and now whenever we make a script that derives from this item class if we do not override our give item image method it will just use our question mark icon instead now that we have our item abstract class we need to create an information holder script for our item slots so in our scripts folder let's create a new c-sharp script named item slot info and let's open it up now because this is an information building script we don't need any of the mono Behavior features or any of the using declarations at the top let's also put above the class in square brackets system.serializable this is because we will be using our item abstract class and this will make it visible in the inspector and the information we want to hold is first a public item named item a public string named name and a public end named stacks and now we want to create a method to set that information let's create a public item slot info and then let's first require an item named new item and then an INT named new stacks and then in the body let's put item as new item and stacks as new stacks and then we can save our script now let's create our inventory script in our scripts folder let's right click add a new c-sharp script to name an inventory and then let's open it up so first let's make the list for our items let's put in square brackets serialize reference and then let's put a public list of type item slot info and name it items and then let's put it to equals a new list of item slot info and now we need a few game object references and to keep our inspector tidy let's use in Brackets space to create a space in the inspector between the two references and then in square brackets again we can put header and then in parentheses inventory menu components and this will create a header in our inspector now we need a few references to some game objects so let's put first public game object inventory menu and this will be the reference of the inventory menu we just created and then next let's put public game object item panel and this will be a reference of the item panel prefab we just created and then next let's put public game object item panel grid which will be our grid layout group now let's put space again to create another space within our inspector and then let's put public end inventory size and then let's default to something like 24 and this will allow us to change the size of our inventory from the inspector or if we want to give the player a way to upgrade the size of their inventory we could just increase the size of their inventory from here so now we need to fill our inventory with empty slots and we can do that pretty easily with a for Loop so let's put 4 int I equals zero I is less than inventory size I plus plus and then inside the body let's put items dot add new item slot info and then we can put null and then zero to make this an empty slot now let's create a way to toggle our inventory also I'm going to be using the Legacy input system but the keybinds we're going to be using are going to be pretty simple so it should be easy to update to the new input system so inside the update method let's put if input.getkeydown key code tab or whatever keybind you want to use and first let's check to see if our inventory is enabled and we can do that with if inventory menu.active self and if it is active we want to disable it so let's put inventory menu set active equals false we can also lock our cursor to the center of the screen whenever we're not using our inventory by doing cursor.lock State equals cursor lock mode dot locked and then let's put else and this will be for when our inventory is not active we will set it to active so inventory menu dot set active equals true and then we can unlock our cursor by cursor.lock state equals pressure lock mode confined and this just means that our cursor will be locked to the inside of our game screen and now we can save our script once we're back in unity let's add our inventory script to our player UI in our player UI let's collapse our other components here to make some room and then let's hit add component and then look up inventory and add it to our player UI for our inventory menu component let's just add our inventory menu that we've created in our player UI for the item panel component let's look for the item panel that we have in our prefabs and add it to the reference and then for the item panel grid let's just put our grid layout group now if we hit play and we tap tab we can now see that we can toggle our inventory on and off and we can see in our inventory script that we have 24 empty slots for the next part of our inventory script we're going to need the scripts we'll be using on our item panels so in our scripts folder let's right click create a new c-sharp script named item panel and then let's open it up once we have that open let's remove the start and update function since we won't be needing them at the top let's put in using Unity engine.ui to give us access to the image component using Unity engine.event systems because we will be using Event Systems in the script and then let's put in using it TM Pro to be able to adjust our text mesh protest for now we just need to set up our item panels references so the first thing we need to put in is a public inventory let's just call it inventory a public item slot info for our item slot that this panel will be using a public image for our item image and then a public text mesh Pro ugui then it's way too long for Stacks text and then we can save our script now let's go to our prefabs folder and open up our item panel and then enter item panel let's click add component to add our item panel script and then let's set the item image in the stacks text references we don't need to worry about the inventory reference right now because we will be setting this as we instantiate our panels back in our inventory script the first thing we need to do is at the top we need to add using system.link because we want access to its to list function down in our references let's add in a new private list of item panel and let's call it existing panels and let's set it equal to a new list of item panels now let's set up how we will update our inventory so let's create a new method let's put in a public void and let's name it refresh inventory and the first thing we need to do is check how many panels we already have and we can do that by putting in existing panels equals itempanel grid dot get components in Children of item panel this will return every single item panel component that exists within our item panel Grid or its children as an array and we can convert that array to a list by putting dot to list now let's check if we need to create any additional panels let's put if existingpanels.count it's less than inventory size and then inside the body let's put an INT amount to create equals inventory size minus existingpanels.count to get the difference between the two amounts next let's create a for Loop to create our panels let's put in 4 int I equals zero I is less than amount to create I plus plus and then inside the loop let's instantiate our panels let's put game object new panel equals instantiate item panel and we want to parent this new panel to the item panel grid so let's put an item panel grid.transform and then we want to add this panel to our existing panels list so let's put existing panels dot add newpanel dot get component item panel now I need to Loop through all of the items in our items list and update our panels with the information from our items but first we need to keep track of how many times we have looped so outside of our Loop let's create a new local end called index and let's set it to zero now let's create a for each Loop let's put 4-H item slot info I in items and then inside the body let's first name the elements of our list if you've ever looked at a list before in the inspector you'll notice that they are named stuff like element 0 element 1 element 2 which is not very helpful for a human but there is a way to rename these elements if there is a string anywhere in the information of each element that will be used to name the element this is the reason why we have that name variable inner item slot info we will be using it to name our elements here so let's put it on name equals and then open and close quotation to start a string plus and then in parentheses index plus one this will name our items based on where it is in our items list because each Loop will be increasing index by one this means that the first item in our list will be named one and then the next one will be named two and so on now let's check if our item slot isn't empty because if it isn't empty we can name our item slots based on the item it contains so let's put if I dot item does not equal null i.name plus equals open quotations colon space close quotations plus i.item.givening and this will add on to the name the return of our item.give name and then if our item slot is empty we can put else i.name plus equals open quotation colon space hyphen close quotation and this will name any of our elements that are empty as its slot number plus a dash to let us know that it's empty now that we've named our elements let's update our panels let's first get a reference to the individual panel that we're working with by putting in item panel panel equals existing panels at our index and because we just spent some time naming our item slot info it should be easy to name our panels let's put panel.name equals idot name Plus panel now before we go go messing with a bunch of the settings let's just check to make sure that our panel exists so let's put if panel does not equal null little mistake here we need to check that the panel exists before we change its name if we try and change its name and we don't know it exists it could cause a critical error so make sure that this is inside of there sorry about that now that we've done that let's set our panel inventory to this script so let's put panel.inventory equals this next let's set this panel's item slot to the current item slot in our Loop so let's put panel.item slot equals I and now let's check if this current item slot is empty by doing if I dot item does not equal null and if it does not equal null we want to activate our item icon image and our item Stacks text in the body let's put panel.itemimage.gameobject that said active equals true and to set our item image let's put panel.itemimage.sprite equals i.item.give item image we also want the activator Stacks text so let's put panel.stax.gameobject.setactive equals true and then let's set our Stacks text by putting panel.stax dot text equals open and close quotation marks plus I dot stacks and because we're going to be reusing these panels we need to make sure that we turn off these objects if our slot becomes empty so let's put else panel.itemimage.gameobject that said active false and panel.stax.gameobject.setactive equals false then at the bottom of our Loop we need to put in index plus to make sure that we increase our index number by one every time we Loop now in our update method we want to refresh our inventory whenever we toggle it on so in the section where we enable our inventory let's call refresh inventory now if we go back into unity and hit play and close and open our inventory we can now see that our item panels are renamed to their slot number plus the word panel and then if we look in our list we can see that our list elements are now named their slot number in a hyphen to let us know that it's empty now that we have a way to refresh our inventory we now need a way to add items to our inventory so back in our inventory let's create a new public method with a return type of int called add item and let's require an item called item and an end called amount and first we want to check if any slots in our inventory contain this item and have open slots so let's do for each item slot info I in items and then let's check if I dot item does not equal null and if it isn't let's compare the name let's put if i.item.give name equals the item that we passed in and now that we know that this item slot contains the item that we are trying to fill our inventory with let's check how much we can add to this slot and to do that let's first check if our amount is greater than the remainder in this slot so let's check if amount is greater than i.item.maxx minus I dot stacks and if it is let's reduce our amount by that remainder and then let's set this slot Stacks to Max and if our amount variable is not greater than the remainder let's just increase I dot Stacks by amount and because that means we filled our inventory with the amount that we've passed into this method we need to exit this method so let's first refresh our inventory if it's open so let's check if inventory menu.active self and then let's call refresh inventory and to exit out of our method we need to return an integer because our method is a return type event and the reason our method is a return type event is because we want to be able to return the amount that we weren't able to add to our inventory and because we were able to add everything to our inventory we need to return zero and if we complete this for each Loop that means there is either no slots or inventory that had the same item or there is no space so now we need to go through the empty spaces and fill what we can with our remaining amount so now let's again put for each item slot info I in items and then let's check if this lot is empty so let's put if I dot item equals null and if it is empty let's check if amount is greater than item.maxstax and if our amount is greater we can just fill the slot so let's put I dot item equals item I dot Stacks equals item.maxdax and amount minus equals item dot Max stacks and if our amount is not greater than Max tags we can just fill this last slot with the remainder so let's put I dot item equals item I dot Stacks equals amount and if our inventory is active let's refresh our inventory and then let's again return zero and at this point we will only reach this far down into the method if our amount is greater than zero so that means our inventory is full and we need to return the amount that we weren't able to put into the inventory so let's first call a debug message let's put debug.log and then let's put no space in inventory 4 colon space plus item.give name and then let's again refresh our inventory in case we have filled some slots we just haven't exhausted our amount variable and then let's return amount and before we close our script here let's create a very small helper method let's put public void clear slot and let's pass in and item slot info and let's just call it slot and then inside let's just put slot that item equals null and slot dot Stacks equals zero and then we can use this to clear our slots easily now that we have all of that done let's finally create a bespoke item in our scripts folder let's right click create a new c-sharp script and name it what item inside the script let's first remove the start and update functions and let's change mono Behavior over to our item abstract class and let's also remove the two using system collections declarations at the top now our class name has the annoying red squiggly line and this is because we must override the give name method from our abstract class because it is an abstract method so let's do that right quick let's put public override string give name and then in the body let's return wood let's also change the max Stacks let's public override int Max stacks and then let's return something like 10 and then let's override our gifts right image so let's public override Sprite give item image and change the return to return resources.load as a Sprite and then we need to check what directory we want back in unity let's check our resources item images folder and look at our wood icon and check its directory and then let's return this directory and then let's save our script then let's move over to our inventory script and later on we will be making a proper way to pick up items but now in the start function of let's create a little area for testing purposes let's add a comment saying that this area is just for testing purposes so we remember to remove it later and then let's call add item let's add a new wood item and then let's add 40 to our inventory and now we can save go back into unity and hit play and we can see our items being added to our inventory now we have an inventory system and a way to add items but before we can create our drag and drop system we need to set up one last key UI element the mouse so let's add a new UI image and for this this is what we would want our Mouse to look like if you don't have a Graphic yet for your mouse don't worry there's a good stand-in and unity's built-in images so let's click the little Target button and on our source image let's search for knob this will serve as a DOT style Mouse pointer for us let's also make sure that we turn off raycast Target for this image and this one is very important because this image will be following our Mouse wherever it goes and if this is left check we won't be able to click on any other element as this image would always be in the way and now for our held item element this will actually be very easy since we already basically have this set up with our item panel we created earlier so let's pull an item panel out of our UI prefab folder and attach it to our Mouse element let's also remember to disable the item panel image attached to our Mouse as a raycast Target let's place it somewhere close to our Mouse but off to the side and then for this element let's go in and enable our item icon image and our Stacks text but then disable the item panel itself so we only have to toggle the panel itself on and off now let's create the script for a mouse in our scripts folder let's create a new c-sharp script and name it Mouse and then let's open it up so first we're going to need access to the UI and the TM Pro declaration so let's add them at the top and then now we need some references first we're going to need a public game object of mouse item UI next we're going to need a reference to the image for our mouse cursor so Public Image mouse cursor we're also going to need a reference to the item slot that we are currently holding so we're going to need a public item slot info and let's just name it item slot next we're also going to need the reference to our item icon so let's put in a Public Image item image and finally we need a reference to our stack stack so let's put it in public text mesh Pro ugui Stacks text now down in our update the first thing we want to do is make sure that our Mouse element here is always at the mouse's position which is actually pretty easy all we have to do is change our transform.position equal to input.mouse position now let's check if our cursor is locked and if it is let's disable our UI so let's check if cursor lock State equals cursor lock mode locked let's set Mouse cursor.enabled equals false and then for the item slot image attached to our mouse let's put Mouse item UI dot set active false and then we can use else for when our cursor is not locked and if it is not locked we can set Mouse cursor.enabled equals to true and then we we only want to enable our item panel if our item slot has an item in it so then let's check if item slot that item does not equal null and if it doesn't let's set our Mouse item UI dot set active to true and then when our item isn't all we want to disable it so let's put else Mouse item ui.setactive to false now before we save our script let's create a few helper methods let's first make a public void set UI and then inside let's set our Stacks text.txt equals to open and close quotations plus item slot dot stacks and then our item image that's right equals item slot that item.give item image and then let's create another method to empty our slot so let's create public void empty slot and then we'll split item slot equals a new item slide info of null and xero now back in unity let's add our script instead of references and then if we go in the game we can see our Mouse element following our Mouse position now back in our inventory script let's add a reference to our Mouse and down in our update function we want to clear our Mouse's item panel whenever we turn our inventory off let's also add the same line to the bottom of our refresh inventory method since we will only be calling this method to finalize a change to our inventory so we want to clean Mouse and then let's add our Mouse to our Mouse reference in our inventory script now to finally set up our drag and drop system back in our item panel script let's create a new method called on click so first to avoid in here is let's make sure that our inventory reference isn't null so let's go if inventory does not equal null and this script is going to take a bit of reference diving so to shave down on that a little bit up in our references let's make a new private Mouse reference and just name it Mouse and then let's set our Mouse reference to the one that's in our inventory so Mouse equals inventory.mouse now we want to handle what happens when we pick up an item so let's put if mouse.itom slot that item equals null and to make this a bit more readable and easier to adjust if needed let's break up our tasks into individual functions so let's create a new method called pickup item and then inside let's set the mouse's item slot to this item slot and then let's call our mouse.set UI method back in in our on click method let's first check to make sure that there is an item in the slot to pick up and then let's call our pickup item function it would also be nice to have a little bit of a fade effect on our panels whenever we pick up an item so let's create a new function called Fade Out and inside let's use a handy little feature called Crossfade Alpha so let's call Item image dot Crossfade Alpha and first we have to put in the alpha that we want to set this image to so let's go with something like 0.3 next we need to put in the amount of time it takes for our panel to fade out so let's go with something really small like 0.05 and then we need to put in if we want this effect to ignore the time.scale variable and we do so let's put it in true now back down in our on click method let's also call our Fade Out function whenever we pick up an item now we want to handle what happens when we click on a panel but we already have an item in our Mouse so let's use else and then let's first handle whatever happens whenever we pick up an item and then we drop it right back down into the same slot we picked it up from and to do this let's first check if our item slide is the same as our Mouse item slot and if it is let's just refresh our inventory because this will set our inventory to the Slate it was in before we picked up the item now let's handle what happens when we click on an empty slot so let's do else if item slot that item equals null and then we want to create a new function for dropping an item so let's create a new method called drop item and in here we just want to transfer the information that's in our Mouse to this slot so let's set our item slot item equal to our Mouse item slot item our item slot Stacks equal to our Mouse item slot stacks and then we want to clear our Mouse's item slot so let's call inventory.cleareslot mouse.item slot now back down in our on click method let's call our drop item function and then let's refresh our inventory now let's handle what happens when we click on an item slot that already has an item but of a different type so we would need to swap the item so let's put else if item slot that item.give name does not equal Mouse item slot that item.giftname and if it doesn't let's create a new function for swapping items so let's create a new method called swap item and let's require two item slot infos one called slot a and another called slot B so to swap an item we need to transfer the information from slot a to slot B and then vice versa but if we copy the info from slot a to slot B we have now lost the information we need to transfer back to slot a so before we swap our slots we first need to hold on to the information of one of our slots in a local variable so let's create a local item slot info of temp item and let's make it equal to a new item slot info that is of slot A's item and Slot a Stacks now that we have our information stored we can now safely swap our items so let's set slot A's item to slot B's item slot a Stacks to slot B stacks and then slot B's item to our temporary item and slot B Stacks to our temporary stacks and we have now swapped our items and then back down in our on click method let's now call swap item and then pass in our item slot and our Mouse's item slot and then let's refresh our inventory and now to implement our drag and drop functionality this will actually be pretty easy as Unity handles most of the heavy lifting for us already to start we need to add a few tags to our item Panel class in order to use the Event Systems so after mono behavior let's add ipointer enter Handler I pointer down Handler High pointer up Handler I drag Handler and eye drop Handler in our variables section let's also add a private pool named click we will be using this to keep track of the clicking and holding of our panels now we need to add the methods relating to the event system tags we just placed so let's first add a public void on pointer enter and let's an event data so let's put in pointer event data as event data and this just points to the event data object that is in our scene and the only thing we will be doing with this method is setting our event data.pointerpress equal to this game object because our item panel script here is obviously going to be on every single one of our panels we need to make sure that the event data knows specifically which game object that we're trying to interact with so this makes sure that whenever we hover over one of those panels it is automatically added as the target game object next we want to add our on pointer down method and in here all we need to do is set our click to true and this is how we will be keeping track of clicking and holding and then let's add our on pointer up and in here all we need to check for is if click is true and if it is let's call our on click method and set click to false and then for our on drop method we just need to call on click instead of click to false and then finally our on drag in here we just need to copy what we did in our on pointer up method and then if we hop in game we can now see our drag and drop system in action now our drag and drop system should be working fine but if we pick up an item and place it back down into the slot we picked it up from our Crossfade Alpha is persisting so back in our inventory script where we check if an item is null or not whenever we activate its panels let's Crossfade the alpha back up to one and that should solve our Fade Out issue but we don't have a second item to try out our swapping so let's create a new item real quick to save us a bit of time let's just copy our wood item here let's rename it to Stone item then let's open it up and rename the class the stone item and then let's change the return name to Stone let's change its mag Stacks over to something like 5 and then let's change our resources.load Sprite over to our stone icon now back in our inventory script in the start function where we were adding some test items let's put in a new add item New Stone item and let's set it to something like 20. and because we set our stack size to 5 this should give us four stacks of stone and now if we hop back into game we can test out our item swapping now to flesh out our inventory system further we need to handle item splitting and to do that we need to modify our Mouse script so back in our Mouse script let's add a couple of references to the top first let's add a public item panel called Source item panel and a public int called split size so how do we want to handle our splitting well it would be nice to instead of having a dialog pop-up where we have to choose how much we want to split by before we begin the split or just also just directly splitting it in half always it would be nice if we could use our scroll wheel in order to dynamically change the amount we're splitting our Stacks by as we're holding the item and to do that down in our update function let's first check if our item slot is not null and if it's not let's first check for an input from our Mouse scroll wheel so let's put if input.getaxis and then in quotations Mouse scroll wheel is greater than zero and split size is less than item slot that Stacks because we don't want to try and split our item for more than it actually contains we can then increase our split size by one so split size plus plus and now we want to check the opposite so if input.getaxis Mouse scroll wheel is less than zero and split size is greater than one because we don't want to go below one we can then reduce our split size by one so split size minus minus and then we can set our Stacks text.txt equal to split size now we need to show that difference to our source item panel but before we do that let's first check if we are actually splitting the item so let's check if split size equals item slot.stax and if it is meaning we aren't splitting the item at all let's just turn off the stack stacks of our source item panel so let's put Source item panel Stacks text game objects set active equals false and then we can use else for the opposite so let's put else and in here we would first want to re-enable the stacks text of our source Center panel and then we would want to set its text to the difference and we can do that with Source item panel Stacks text equals open and close quotation marks plus and then in parentheses item slot that Stacks minus split size and this will give us the difference then down in our set UI method let's instead of setting our stack stacks.txt equal to item slot.stax let's set it to our split size now back in our item panel script let's update our pickup item and our drop item methods in our pickup item let's set our Mouse's Source item panel equal to this item panel we can also easily add a stack halfing feature by putting in if input.getkey down left shift or whatever keybind you would like for splitting items and our item slot that Stacks is greater than one Mouse split size equals item slot that Stacks divided by two and because our item slot that Stacks is an integer this will always be floored to the nearest integer and this will split our stack in half and then we can use else to just set our Mouse split size equal to item slot that stacks and then in our drop item method after we set our item slot to our Mouse's item slot let's check if mouse.split size is less than Mouse item slot stacks and if it is let's set our item slot that Stacks equal to Mouse split size let's reduce our Mouse's item slot by that split size so let's do mouse item slot Stacks minus equals Mouse split size and then let's call Mouse empty slot and then we can use else and wrap it around our previous code now if we hop back into game and pick up an item we can use our scroll wheel to start splitting that item or we can use our shift key to just split the item in half directly but now that we have a way to splitter items we now need a way to stack our items so let's hop back into our item panel script so let's make a new method called stack item let's pass in an item slot info named source and other item slot info named destination and an instant for amount now let's create a local int called slots available to check how much space we have in this slot and let's set it equal to destination.item.maxdax minusdestination.stax to give us our difference and now we can use this to check if slots available equals zero we can then return to exit out of this method early because we have no space for the item now let's first check if our amount is greater than the amount of space in the slot so let's check if amount is greater than slots available and if it is let's reduce our source Stacks by the slots available and then max out the stacks of our destination slot and then we can handle what happens when our amount is equal to or less than it's less available so let's check if amount is less than or equal to slots available and if it is let's set our destination Stacks to plus equal amount and then let's check if source.stax equals amount we then want to clear that slot so let's call inventory clear slot source and then we can use else to handle when this is not true like if we were trying to stack an item that has been split let's use else source.stax minus equals amount and now we can set this up in our on click method in our lcf line we already have a stop for if the items null and if the item does not have the same name so because of this all we need to do is ask else if item slot that Stacks is less than item slot that item maxed X and if it is we can call our stack item and set the source to mouse that item slot set the destination to this item slot and then we can just use the mouse split size as the amount and then we can call refresh inventory and now if we hop back in the game we can now splitter items and stack them it would also be nice if we could right-click The Dropper items as a quick bit of Polish let's just go back to our inventory scripts and Insider update let's put if input.getkeydown key code mouse1 and mouse item slot dot item does not equal null let's just refresh our inventory because this will reset us back to the state it was in before we picked up the item and now we have a working inventory system but we're missing an important feature the ability to pick up items our items are all based off our abstract class we created earlier but this has a problem that we need to work around we cannot drop an abstract class or a script deriving from an abstract class into a script reference like we can with a prefab or a component so we need to create our item references since we have our inventory script here it would be nice if our inventory had a reference to all of our items in our project so it knew what to add when we call our add item method and a good way to handle this is with a dictionary so what is a dictionary well it's very similar to a list but with each element there's also a pointer to find a specific entry in the dictionary this is done with a key a dictionary requires both a key and a value the value is the information we want access to and the key is the way to quickly find that information so first in our inventory script let's create a new dictionary that is a key of string and a value of item let's name it something like all items dictionary and let's set it to a new dictionary of string and item and now for getting all of the items in our project it's actually just going to be one method and one line of code but it's a very long line of code so let's create an I enumerable that is a type of item and let's call it get all items and then in the body let's return system.app domain current domain getassemblies dot select mini assembly Lambda that's what that equal sign and a greater than means it's a Lambda expression assembly.getitems dot where type Lambda type is subclass of type of item dot select type Lambda system.activator.create instance type as item and this will go through our entire project and find all of our scripts that are a subtype of item and will return as an array and because it returns as an array we can convert it to a list which will make it easier for us to turn it into a dictionary and to build our dictionary let's first go up to our start function and let's create a local list variable that is the type of item and let's call it all items and let's set it equal to get all items dot to list and this will convert all of the items that return as an array to a list and now we can Loop through that list so let's do for each item I in all items and first let's check to make sure that our dictionary does not already contain this item's name so let's do if exclamation point all items in dictionary dot contains key and then i.give name and if it doesn't let's add it to the dictionary with all items dictionary dot add and then for its key let's use i.give name and for its value let's just use I and then we can use else to handle what happens if our dictionary does already contain that name and if it does we can make it easy for us to make sure that all of our items have a unique name and to do that we can use debug.log open and close quotations plus I plus already exists in dictionary and it shares a name with plus all items in dictionary and then in square brackets I dot give name and this will log both the item that we are trying to add to the dictionary that has the same name and the name that already exists in the dictionary that has the same name and this will make it easy for us to find items that we have accidentally gave the same name to since a lot of our inventory code Works off of our items having unique names this should help us out a lot and to help us understand what is in our dictionary let's create a little debug log that tells us exactly what is in inner dictionary then we can do that by first creating a local string variable the same as something like items in dictionary then let's set it equal to items in dictionary colon space and then down in our for each Loop whenever we add an item let's put items in dictionary plus equals and then a comma with a space plus i.give name and then below our Loop let's put items in dictionary plus equals period to finish our log string and then we can do debug.log items in dictionary and this will give us a log of all the items in our dictionary and now we can update our add item method let's first change over that item that we're passing in over to a string called item name and inside at the top let's first create a local item called item and let's set it equal to null and then let's check our dictionary for the item name so let's put all items in dictionary dot try get value item name and we need to add this to an item so let's add it to our item local variable and now let's make sure that we actually have found an item and if we have endless x with the method so let's do if item equals null debug.log could not find item in dictionary to add to inventory and let's return the amount and then we can update our two test add items in our start function over to their string names and if we hop back in the game we should see that our items are still being added to our inventory and our console will list the items that have been added to our dictionary and now with all that done it should be super easy for us to make an item pickup script in our scripts folder let's create a new c-sharp script and name it item pickup and let's open it up let's first remove the start and update method since we don't need them and then let's put in a public string of item to drop and a public end of a mount and let's set its default equal to one and now let's make our pickup method let's make a public void pickup item that requires an inventory and now because the way we created our add item method Returns the amount that could not be placed into the inventory we can use that return to set our amount in our item pickup script so let's set amount equal to inventory.add item and then pass in item to drop and the amount then we can check if amount is less than one and if it is we can destroy this game object and now if we want to create a simple walkover script we can call on trigger enter check for the tag that we set on our player find its inventory we can do that pretty easily by doing git component in children for inventory and then check if we found our component and if we have call our pickup item and now that we have all that set up all we have to do to create an item is make a game object put on a sphere collider and remember to turn off the trigger give it a rigid body to make sure that the ontrigger interworks and turn off gravity and put our item pickup script on it give it the name of the item we want to pick up and the amount and then we can start picking up items these two items here are wood items and this number shown is the amount that's inside the item and when we walk over one it almost fills up our inventory and because we absorbed all the items inside that item pickup script it deletes the game object but when we go to pick up the second item it fills our inventory but does not delete the item because we have not absorbed all of its contents and because our add item method Returns the amount that was not able to be placed into our inventory the amount inside of our item pickup script is updated appropriately and now for our item dropping functionality we are again going to be using resources.load so we need to create a new folder so let's create a new folder called pickup items back in our item abstract class let's create a new method to give the item that we want to draw for each item so let's create a new method let's make a public virtual with a return type of game object let's call it drop object and let's have it return resources.load as a game object pick up items and because this is our base abstract class let's have it return a default item we will actually be making this item in just a moment but first we need to work around a problem we want our items that we drop to have physics but if we add a new non-trigger collider to our object our player will bump into the side of our object so we need to set up our item so it has physics that does not interact with the player but still allows the player to collect the item to do this we need to update our item pickup script we are going to be nesting our item pickup script into a child object so we need to update our item pickup script to destroy the base root object and not the child object that it's sitting in and to do this it's actually pretty easy we just need to change this.game object over to this transform root game object now for our pickup item we need to think about how our physics layers are organized our player wouldn't normally be a camera like we have in our scene here our camera would normally be attached to other game object and that parent object would either be on the default layer or a layer that we have created name something like player the walkable surfaces of our game would also usually be on their own layer name something like floor or ground because of this we could create a new physics layer that would only react to the walkable surfaces of our game but would not react or affect our player to do this let's create a new physics layer for our pickup items so let's add a sphere to our scene and name a default item this will be our fallback item object and then let's give it a rigid body set the mass to something like 5 and the drag to 1 to make our item physics a little bit less floaty and for this object I'm going to lock the rotation in all axis and this is just a preference if you want your items to be able to roll around just leave these unlocked and let's give it a sphere collider that is not to trigger and let's increase its size to something like two the size and shape of this collider can be whatever you want if you'd like to have your items behave differently now for its layer let's click the drop down and go to add new layer let's create a new layer name something like only collide with ground and let's set our items layer to this new layer now to make this layer only interact with the ground layer in the top left of unity let's click edit project settings and in the physics tab let's scroll down to the triangle of physics interactions under our new only collide with ground layer let's uncheck every layer other than ground and now this layer will only interact with the ground layer now to our default item let's set up our item pickup script let's right click and add an empty to our item and let's name it something like trigger and let's switch its layer back to the default layer let's add a rigid body so our ontrigger enter works properly but turn off gravity and freeze its position and rotation in all axis so it stays locked to our apparent object now let's add a new sphere collider that is a trigger and increase its size and finally let's add our item pickup script we can set its default name and amount here but we'll be changing this in our code as we drop our items and then let's place it into our pickup items resources folder and now to create our drop item functionality back in our inventory script let's create a new method called drop item and let's pass in a string named item name so let's first find our item in our dictionary like we did at the beginning over add item method and to do that let's just copy what we have in our add item method all we need to do is change the debug.log and remove the amount on our return since this method is a void meaning it doesn't return anything we can just use return to exit out of the method now let's get our cameras transformed with transform cam transform equals camera.main.transform and we're going to be using this for the direction that we throw our items and now to spawn our object let's do game objects drop item equals instantiate and for the item let's use item.dropobject for the position let's use this.transform.position plus a new Vector 3 of 0 1.8 and 0. this is just to raise it up off the ground a little bit because often the origin of our player object is the floor and spawning it directly on the floor will often cause it to fall through the floor and then let's put Plus cam transform.forward and this will push our spawn location one meter out in the direction our camera is facing you can also multiply this value to increase or decrease the projection distance but be careful because you can again project it into the floor in for its rotation let's just set it to zero with quaternion.oiler Vector three zero and now for our throwing action let's add a little bit of a velocity to our rigid body so let's first get the rigid body with rigid body RB equals dropped item dot get component rigidbody now let's check to make sure that we've actually found something and if we have let's hit rb.velocity equal to camtransform.forward times 25 and this will give our item a velocity of 25 meters a second in the direction of our camera and now let's set our item pickup scripts information so let's do item pickup IP equals dropped item dot get component in children item pickup and then let's check to make sure that we found something and if we have let's set ip.item to drop equal item name ip.mount equal mouse.split size then finally Mouse item slot dot Stacks minus equals Mouse split size then let's check if Mouse item slot Stacks is less than one because if it is that means our slot is empty so we need to call clear slot on mouse.itom slot and then let's clear our reference with mouse.empty slot and then let's refresh your inventory and to call this we're going to need access to the event system so at the top let's put using.unity engine.evensystems we're going to be using this to check if we're hovering over the UI or not so we can drop our items into our scene and to do that enter update function let's check if input.getkey down key code Mouse 0 and our Mouse item slot item does not equal null and not eventsystem.current DOT is pointer over game object and this will check if our pointer is over a UI element or not and then finally let's call drop item and then let's pass in our Mouse's items give name and that's it we now have a drag and drop inventory where we can pick up split and stack and drop items I hope you enjoyed the video remember to like comment and subscribe and I will see you in the next video later [Music] [Music] thank you [Music] foreign
Info
Channel: Joseph Mask
Views: 10,764
Rating: undefined out of 5
Keywords: Draw, Drawing, Sketch, Sketches, Paint, Painting, Digital sketch, Digital painting, Digital Illustration, Illustrate, Time lapse, Digital Drawing, Photoshop, Art, Digital Art, Unity, Unity3D, UnityVFX, VFX, Visual Effect, Blender, Game, Game Dev, Developer, Game Developer, From Software, Shader, Shader Graph, Game Engine, Software, Tutorial, Guide, How to, Rogue-Lite, Items, Item, how to make a game, gamedev, indie game, unity game dev
Id: VThJYiWrew4
Channel Id: undefined
Length: 44min 30sec (2670 seconds)
Published: Wed Mar 15 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.