Thanks! These tutorials are a great source of getting started information (and more…) for UI Toolkit!
@Yecats Hello, its posible to render a gameobject over any visual element?
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:
- Create a new Render Texture ( Create > Render Texture)
- Add a camera to your scene and position it in front of your model.
- Set the camera’s Output Texture to your Render Texture ( Camera > Output > Output Texture)
- Set the camera’s Background Type to Solid color w/ transparency (Camera > Environment > Background Type)
- 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.
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.
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:
var newPos = draggedElement.ChangeCoordinatesTo(ghostElement.parent,@event.localPosition);
ghostElement.style.top = newPos.y - ghostElement.layout.height/2;
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
What is the “draggedElement” in this case?
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.
This was very helpful, so thank you very much!
One question I’m dealing with right now: How do you show/hide the inventory, without losing all of its data?
If I follow your method, where I subscribe to an event which looks through a list of Slots that I saved in the Awake method, then whenever I close (disable) and reopen (enable) the Inventory UI Document component, then the UI document is redrawn, losing all of it’s previous states.
Right now, I save my data in the InventoryUIController, and each time OnEnanble is called, the Inventory UI is re-filled with the necessary Slots, but I’m curious if this is the way to go or not.
You can probably just flip the visibility of root visual element. Probably need to disable any input hooks and similar at the same time.
This tutorial is pretty old though so who knows in what ways it’s out of date. It predates runtime bindings, which makes this sort of system substantially easier to manage.
For some people videos can be more helpful than a written format, because people process information in different ways. I have ADHD and am more visually oriented, so I know that sometimes I prefer to listen to/watch a video than to read text, seeing the “author’s/instructor’s/tutor’s” process can help with understanding what they are trying to express.
So if you do feel inclined to make videos of your tutorial/s, I would encourage you to do so, but please do not neglect the written format, because to create a great video tutorial you should have some form of script so that you know what you are trying to talk about, how you are trying to get from the start to the end and you are less likely to feel like you are stumbling through it at times.
Another benefit of using both video and written formats, is that you will be helping more types of learners (8 Types of Learning Styles | The Definitive Guide)
I found that wrapping up the closestSlot.Hold()
& m_OriginalSlot.DropItem()
calls into an if else
that checked the closestSlot.ItemGuid()
was empty, caused the item to ‘drop back’ into its starting position when the else clause set m_OriginalSlot.HoldItem()
instead of closestSlot
I am working through your tutorial and found that you have some code missing from part of it, where you are talking about “Load the Window”, the void CreateGUI()
is missing a line for initialising m_ItemRowTemplate = AssetDatabase ... /ItemRowTemplate.uxml");
I found it by comparing with the final version of the project. Because without that line Unity was throwing a NullReferenceException
In the tutorial code there was a piece where it showed registering the callbacks for the PointerMoveEvent and PointerUpEvent to the ghost icon. Now, I didn’t follow the tutorial code closely, in fact, mine is quite a bit different, but I used your tutorial as a starting point. So maybe the tutorial code works fine. But in my own setup, if I register callbacks to the ghost icon, it causes a problem where if you move the mouse too quickly, it loses the pointer because the pointer can jump beyond the ghost icon window in a single frame. I found the solution was I could register these callbacks to the top level container instead and get it to work, and then the mouse can never escape the event.
Overall, I love the tutorial to give people a starting point they can grow from.