Search Unity

[Tutorial] Create an in-game inventory UI with UI Toolkit

Discussion in 'UI Toolkit' started by Yecats, Feb 4, 2021.

  1. Yecats

    Yecats

    Joined:
    Jul 13, 2014
    Posts:
    69
    Hello!

    I've just put out a new tutorial that covers how to use UI Toolkit and the UI Builder when creating an in-game inventory system with drag/drop functionality.

    Introduction
    A great UI is one of the most important parts of any game. It needs to be responsive and intuitive while looking awesome. In this tutorial, you’ll learn the basics of Unity’s new UI system, called UI Toolkit, by creating an in-game inventory system where your player can drag and drop items to move them around.



    Learning Outcomes
    What is great about learning UI Toolkit is you can apply the same skills to create custom UI and extensions for the Unity Editor, runtime debugging tools, and runtime UI for your games. At the end of this tutorial you will be able to:
    • Design UIs by using the UI Builder tool.
    • Design UIs through C# and USS (for styling).
    • Instantiate your UI at runtime.
    • Manipulate VisualElement styles at runtime, including setting a new position.
    • Register and handle events for the UI.
    Links
     
    Last edited: Oct 13, 2023
  2. MaskedMouse

    MaskedMouse

    Joined:
    Jul 8, 2014
    Posts:
    1,092
    Your Table of Contents links on the introduction page at the bottom are broken.
    On the left side of the page at the top they do work.
     
  3. Yecats

    Yecats

    Joined:
    Jul 13, 2014
    Posts:
    69
    Ah, thank you! I've removed the ToC as it's not needed for the site. That was a port error from GitHub. I really should write an automated tool to handle that for me. :D
     
  4. murtidash

    murtidash

    Joined:
    Mar 7, 2021
    Posts:
    2
    This was super helpful and really well laid out. The two big gotchas that I had to struggle through might be worth adding to the tutorial?

    1) When inserting your inventory container into another visual element the ghost object needs to be reparented to the outer window. In this case I had an inventory container inside a character sheet visual element as a direct child of it (I have not tested if this works when you are using a template), and as soon as I initiated the drag the ghost container would appear in a weird spot and not over the mouse. This was because the x,y that we were setting the ghost container to was being sent relative to the inventory container, not the entire UI. By reparenting the ghost container to the top visual element it started working. I am assuming that because even when the ghost container is in absolute mode it's still absolute in relation to it's parent element. I assume that there's math you can do to figure out the translated x,y but since I'm unsure how the ui will be scaled in every case I went with the easiest option to fix it.

    2) I'm about to tackle it and will add some samples here, but having some info about differentiating between single clicks vs click holds would be useful. My plan is to basically start a timer (maybe 200 or 500ms?) when a pointerdown is sent and if you receive a pointerup in that timespan then invoke the single click event, otherwise invoke the startdrag event. This would be implemented in InventorySlot.OnPointerDown

    3) I also had trouble figuring out that I had to create a new copy of my item scriptable object via list.Add(Instantiate(Item)) to get a copy of my item rather than directly adding the scriptable object itself. I don't think this fits your tutorial specifically but might be helpful to other people reading this thread in the future.
     
    Last edited: Mar 22, 2021
    yafonin20, Kazko and Yecats like this.
  5. Yecats

    Yecats

    Joined:
    Jul 13, 2014
    Posts:
    69
    Thank you for this! I'll work on updating the tutorial this weekend. I'd love to give you credit - do you have a name preference or should I use "will_unity478" ?
     
  6. murtidash

    murtidash

    Joined:
    Mar 7, 2021
    Posts:
    2
    I absolutely don't need to be credited, but you can use murtidash. I had to log out/in for the profile stuff to change in the forums. Glad to help, the tutorial definitely helped me!
     
  7. Yecats

    Yecats

    Joined:
    Jul 13, 2014
    Posts:
    69
    I'm a big fan of giving credit and I really appreciate you taking the time to write back! I've added a note to the Ghost Icon section of the tutorial for your first item:

    upload_2021-3-28_13-7-55.png

    Regarding Single Clicks versus Click Holds - Are you wanting to drag when the player releases their hold? Or start dragging after some period of time has gone by but they still have the element "clicked"?
     
  8. tenukii

    tenukii

    Joined:
    Mar 31, 2014
    Posts:
    12
    Thank you so much for not making a video. Written tutorials are so much easier to follow along and use in general.
     
    Randolphjand likes this.
  9. Yecats

    Yecats

    Joined:
    Jul 13, 2014
    Posts:
    69
    You're welcome! This is great feedback. I have been debating on if I should do videos instead. :D
     
  10. aganm

    aganm

    Joined:
    Sep 25, 2019
    Posts:
    114
    Hey! Thanks so much for this, I have been trying to use the new UI toolkit instead of uGUI but there's so little tutorials for it.

    Would you consider next making a tutorial on how to make a grid based inventory? I'm not sure how to approach that because last time I checked, the UI toolkit does not have a grid layout type. By grid based inventory, I mean something like this
     
  11. Yecats

    Yecats

    Joined:
    Jul 13, 2014
    Posts:
    69
    @aganm This is a great idea! I'm taking a break from UI Toolkit tutorials for awhile as I want to tackle a couple of other subjects (currently Addressables, Timeline, and Cinemachine). I think this would be an interesting challenge, so I have it on my backlog for when I come back to UI Toolkit stuff.
     
    aganm likes this.
  12. Joviex

    Joviex

    Joined:
    Jan 23, 2011
    Posts:
    44
    Thank you very much. There are scant few practical examples. This is excellent. Cheers
     
    Yecats likes this.
  13. tossrock

    tossrock

    Joined:
    Mar 7, 2018
    Posts:
    12
    Thanks for this, very helpful guide. Noticed a potential typo:



    Should the
    .slotIcon
    style say 4px, or should the description in 2. say 15px?
     
  14. binhnguyen991

    binhnguyen991

    Joined:
    Feb 14, 2014
    Posts:
    5
    Very helpful tutorial. Can you update how to use with list view or scroll view?
     
  15. Yecats

    Yecats

    Joined:
    Jul 13, 2014
    Posts:
    69
    Why yes - it should. Great catch and sorry about that! Fixed.

    Thank you! I have been working a lot with the scroll view to create an editor window for managing the in game inventory. I'd originally gone with a list view but I backed it out. However, I would be happy to create a tutorial that covers both of these things + binding. Give me a few weeks and I'll whip something up for ya!
     
  16. Yecats

    Yecats

    Joined:
    Jul 13, 2014
    Posts:
    69
    @binhnguyen991 - I just finished a new tutorial that shows how to make an item manager editor window. The main focus is to teach what scriptable objects are and how to create, delete and bind to one. It also covers ListView and the Object Picker.

    Here's a little teaser / intro video:



    Sorry it took so long. The little one was battling a cold. Hope that helps!
     
    Last edited: Oct 13, 2023
    bb8_1 likes this.
  17. Yecats

    Yecats

    Joined:
    Jul 13, 2014
    Posts:
    69
    Hey! I just wanted to let you know that this tutorial is next on my list, if you still need it. Let me know!
     
    bb8_1 and Randolphjand like this.
  18. aganm

    aganm

    Joined:
    Sep 25, 2019
    Posts:
    114
    I do :)

    I subscribed to your channel to make sure I don't miss it.
     
  19. Yecats

    Yecats

    Joined:
    Jul 13, 2014
    Posts:
    69
    @aganm - I haven't had a chance to post the intro video for the tutorial yet but I wanted to give you a heads up that the first part is done (details below). I have the full demo project complete for the second part, I just need to write the tutorial piece. Hoping to have it ready in the next ~2 weeks. Here's the end result:

    example.gif


    Design a grid style inventory window with UI Toolkit

    Inventory systems are a great way to help facilitate how you want the player to engage in your game. Perhaps one of the most important components to consider are the constraints you want the system to help enforce. For example, many games gate what a player can carry based on the total weight of all the items. A slightly less common way is based on the item size. This has been done by games such as Resident Evil 4 and Dues Ex. In addition to controlling how much a player can carry, it also creates a mini game out of the inventory by requiring them to strategically organize to maximize what they can carry.

    This tutorial is part of a series which will explore how you can create an inventory that requires the player to sort by item size. Part 1 will walk through creating the UI design below.




    Learning Outcomes
    This tutorial will cover the basics of UI Toolkit and how you can create a complex inventory UI. By the end, you will learn:
    • A practical workflow for building up a complex UI with different zones.
    • The basics of using UI Toolkit & UI Builder.
    • How to create and work with a stylesheet.
    • How to add the UI to a scene
     
    Last edited: Oct 13, 2023
    UniqueCode, eses and andywatts like this.
  20. Yecats

    Yecats

    Joined:
    Jul 13, 2014
    Posts:
    69
    @aganm Just posted the second part of the series. Check out the intro video here:



    Hope it helps!
     
    bb8_1, Randolphjand and eses like this.
  21. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    Thanks! These tutorials are a great source of getting started information (and more...) for UI Toolkit!
     
    Yecats likes this.
  22. IEdge

    IEdge

    Joined:
    Mar 25, 2017
    Posts:
    51
    @Yecats Hello, its posible to render a gameobject over any visual element?
     
  23. Yecats

    Yecats

    Joined:
    Jul 13, 2014
    Posts:
    69
    Sorry for the delay! I hadn't done this yet so I needed to look into it. You can render a game object pretty easily over the visual element. I don't have a tutorial for this yet (it'll be in my next one) but in a nutshell:

    1. Create a new Render Texture ( Create > Render Texture)
    2. Add a camera to your scene and position it in front of your model.
    3. Set the camera's Output Texture to your Render Texture ( Camera > Output > Output Texture)
    4. Set the camera's Background Type to Solid color w/ transparency (Camera > Environment > Background Type)
    5. Set the camera's Culling mask to the layer of your game object

    In UI Toolkit, create a new Visual Element and change the type to Render Texture. Then set your render Texture to it.

    Tip: If you do not want to render an object animated, then shut off the camera when you load.

    upload_2021-12-25_19-57-57.png
     
    Rodolfo-Rubens and Randolphjand like this.
  24. petersrin

    petersrin

    Joined:
    Mar 20, 2018
    Posts:
    11
    Thanks for this! Great work, very helpful! I'm going to be trying out the bonus challenge soon, but wanted to note something I noticed: dropping an item back into it's own slot seems to leave that slot empty, because DropItem() is called after the closest slot is filled. Reordering the calls results in a null exception because the GUID of the original slot is accessed after being cleared, so the complete solution here would be to first cache the original GUID, then Drop, and finally fill the closest slot. This seems to work with new slots as well as original ones. You could, instead, introduce some extra control flow logic (if closestSlot == originalSlot) instead, since my solution is pretty temporally coupled. Just wanted to bring it up, as I thoguht maybe I did something wrong.

    Similarly, dropping one item onto an already filled slot deletes (drops) the filled slot's item in favor of the dragged one. I intend to solve this one too, so most likely the entire solution will involve control flow instead of the above solution. Feel free to ignore if you're done making updates to this tutorial.
     
    Randolphjand likes this.
  25. yafonin20

    yafonin20

    Joined:
    Dec 7, 2022
    Posts:
    1
    Tnx for your answer, I was stuck with similar problem for a while and found a solution that works perfectly starting from Unity 2021.3. Code below:

    Code (CSharp):
    1. var newPos = draggedElement.ChangeCoordinatesTo(ghostElement.parent,@event.localPosition);
    2.            
    3.             ghostElement.style.top =  newPos.y - ghostElement.layout.height/2;
    4.             ghostElement.style.left = newPos.x - ghostElement.layout.width/2;
    Same as yours, ghost VisualElement situated higher in hierarchy than inventory container. This method easily converts coordinates from local event target coordinates (let`s say inventory slot) to ghost parent local coordinates.

    https://docs.unity3d.com/Manual/UIE-coordinate-and-position-system.html
     
  26. Odd_Doc

    Odd_Doc

    Joined:
    Jun 2, 2022
    Posts:
    5
    What is the "draggedElement" in this case?
     
    Last edited: Dec 15, 2023
  27. OuterGazer

    OuterGazer

    Joined:
    Jan 13, 2021
    Posts:
    11
    Doing this tutorial I found out the same bug. The solution is quite simple and can be done by checking that the guid of the closest slot found is not equal to "", if that is the case it is only needed to copy and paste the same code line where it takes in account if the item was dropped outside of the inventory space. Otherwise we change icons and call DropItem() as per the tutorial.

    Works both for dropping an item onto another item or onto its original slot.

    On another note, is super confusing to add a CSS called slotContainer when previously it is said to create css styles extracting the inline styles and put the name of the visula element as the class name. Of course, there is an element called SlotContainer we just created and having 2 classes with the same name and different stylings cause weird behaviour, so the second style created through code I called it itemContainer and changed all relevant code accordingly.

    I also don't know why following everything to a T my ivnentory slots didn't fit 6 on each row in a 16:9 aspect ratio and instead put 5 and have big spaces both left and right. I changed the width of the inventory window from 50% to 47% and then my image looked the same as in the tutorial.

    Just as an advice, if in a loop you tell to create 20 slots, don't show later an image with way more slots. That was just confusing.
     
    Last edited: Feb 7, 2024