Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Question Clearing and recreating Lists for Inventory System.

Discussion in 'Scripting' started by JeaNiX, Jun 9, 2022.

  1. JeaNiX

    JeaNiX

    Joined:
    Oct 31, 2016
    Posts:
    20
    Hello,
    I'm learning to code and working on a project of mine, where I implement a inventory system, which stores all the items in a scriptable object, and the inventory controller then displays them in the UI.
    There are no functions working on Update, so the UI is updated On Awake and whenever I change something in the main List of items.
    So, for example if I add a item. While adding an Item to the list, I also check if the inventory does already have an item of that type, is that item stackable, can I add it or should I create a new slot etc.
    So, basically everything works fine. But after all this is done, I inform the controller that the UI needs to be updated. And here is what I do.
    I clear the list which I currently have in the UI, and pass the UI a new List of Items, and foreach item I add them to the UI List and display it. So, this works well, but...
    If I add one or two items its not bad. If I add 3000 there is a microshutter. And also I have only two variations of items. What if there be more items, different types etc.
    So basically I clear a whole list of UI Items and create a loop to recreate a new updated List.
    Maybe there is a way to optimize this? Or am I just overthinking things?
    Thanks.
     
  2. JeaNiX

    JeaNiX

    Joined:
    Oct 31, 2016
    Posts:
    20
    I was thinking about passing a Dictionary with the updated item state to the UI, and then just check if there are more or less items already in the UI. If less then I update the ones I already have and after that, for each "new" item from the dictionary, I create a new one in the UI and just pass it the data from the dictionary.
    But If there are less items in the Dictionary than in the UI, I just update the ones there are, and remove all other items form the end of the UI list.
    Maybe that would be more efficient?
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,780
    Here's my optimization blurb:
    DO NOT OPTIMIZE "JUST BECAUSE..." If you don't have a problem, DO NOT OPTIMIZE!

    If you DO have a problem, there is only ONE way to find out. Always start by using the profiler:

    Window -> Analysis -> Profiler

    Failure to use the profiler first means you're just guessing, making a mess of your code for no good reason.

    Not only that but performance on platform A will likely be completely different than platform B. Test on the platform(s) that you care about, and test to the extent that it is worth your effort, and no more.

    https://forum.unity.com/threads/is-...ng-square-roots-in-2021.1111063/#post-7148770

    Remember that optimized code is ALWAYS harder to work with and more brittle, making subsequent feature development difficult or impossible, or incurring massive technical debt on future development.

    Notes on optimizing UnityEngine.UI setups:

    https://forum.unity.com/threads/how...form-data-into-an-array.1134520/#post-7289413

    At a minimum you want to clearly understand what performance issues you are having:

    - running too slowly?
    - loading too slowly?
    - using too much runtime memory?
    - final bundle too large?
    - too much network traffic?
    - something else?

    If you are unable to engage the profiler, then your next solution is gross guessing changes, such as "reimport all textures as 32x32 tiny textures" or "replace some complex 3D objects with cubes/capsules" to try and figure out what is bogging you down.

    Each experiment you do may give you intel about what is causing the performance issue that you identified. More importantly let you eliminate candidates for optimization. For instance if you swap out your biggest textures with 32x32 stamps and you STILL have a problem, you may be able to eliminate textures as an issue and move onto something else.

    This sort of speculative optimization assumes you're properly using source control so it takes one click to revert to the way your project was before if there is no improvement, while carefully making notes about what you have tried and more importantly what results it has had.

    Here's some general info about inventories:

    These things (character customization, inventories, shop systems) are fairly tricky hairy beasts, definitely deep in advanced coding territory. They contain elements of:

    - a database of items that you may possibly possess / equip
    - a database of the items that you actually possess / equip currently
    - perhaps another database of your "storage" area at home base?
    - persistence of this information to storage between game runs
    - presentation of the inventory to the user (may have to scale and grow, overlay parts, clothing, etc)
    - interaction with items in the inventory or on the character or in the home base storage area
    - interaction with the world to get items in and out
    - dependence on asset definition (images, etc.) for presentation

    Just the design choices of an inventory system can have a lot of complicating confounding issues, such as:

    - can you have multiple items? Is there a limit?
    - are those items shown individually or do they stack?
    - are coins / gems stacked but other stuff isn't stacked?
    - do items have detailed data shown (durability, rarity, damage, etc.)?
    - can users combine items to make new items? How? Limits? Results? Messages of success/failure?
    - can users substantially modify items with other things like spells, gems, sockets, etc.?
    - does a worn-out item (shovel) become something else (like a stick) when the item wears out fully?
    - etc.

    Your best bet is probably to write down exactly what you want feature-wise. It may be useful to get very familiar with an existing game so you have an actual example of each feature in action.

    Once you have decided a baseline design, fully work through two or three different inventory tutorials on Youtube, perhaps even for the game example you have chosen above.

    Or... do like I like to do: just jump in and make it up as you go. It is SOFT-ware after all... evolve it as you go! :)

    Breaking down a large problem such as inventory:

    https://forum.unity.com/threads/weapon-inventory-and-how-to-script-weapons.1046236/#post-6769558

    "Combining a bunch of stuff into one line always feels satisfying, but it's always a PITA to debug." - Star Manta on the Unity3D forums
     
  4. dlorre

    dlorre

    Joined:
    Apr 12, 2020
    Posts:
    700
    Well, to optimize a list you need to only add/remove what has changed. For that you need to insert the new elements and delete the old ones. It is not too hard to do but you need to be careful that if you maintain indexes for selection or something else they may change after insertion/deletion. That's basically your dictionary idea.

    You can also optimize further by only displaying what should be visible, so if your list contains 10 visible elements then you create only 10 and when the user scrolls you make the changes. Or rather you create 30 elements: 10 for display, 10 above and 10 below for smoother scrolling. It is much harder to make, the ListView component in UI Toolkit does that if you want to see how it works (it is done with a bindItem and a makeItem methods).
     
    Last edited: Jun 10, 2022
  5. JeaNiX

    JeaNiX

    Joined:
    Oct 31, 2016
    Posts:
    20
    Hello.
    Thank you very much for the reply!
    I did used the profiler. Learned to use it a bit. Also I changed the logic, so it would not delete the whole list once something is changed, but i send a dictionary with the current inventory state to the ui, and the ui updates itself depending on the count of the items it needs. Also i restricted the slots to 42 which is enough for me. On start its 24 slots, but if its getting out of space it will add a new row line to a maximum of 42. And also delete not needed rows in the oossit case.
    Anyway, using the "dictionary and update method", i mean, not deleting the inventory, but only .add and .remove form the list, i jumped to 2 ms while doing so, so adding 2000 healing potions would need me 2ms to stack them 15 per slot and add them to the list. Also, before this change, for opening the inventory containing 2500+ items i would need like 700ms as it showed in the Profiler, and I do experience a shutter while rendering it. But changing to Dictionary->UI Modification reduced the delay to 50ms, still the rendering needed some time. Of course there will be no way to get such many items, but I do wanted to test it.
    Thanks for the replay. The inventory in its state currently is working as intended, while only using one List of an "InventoryItem" stuct in the Scriptable Object for the state of the inventory, and on list for the UI. And its working with adding and removing items on a basic level. I will continue my work on this system now.
    You do are right. Best way to learn is to experiment and overcome! :D
    Have a nice weekend!
     
  6. JeaNiX

    JeaNiX

    Joined:
    Oct 31, 2016
    Posts:
    20
    Hello!
    Thank you for your reply!
    I changed it to only .add and .remove and you are right. It helped.
    About the scrolling. This seems like a really good idea, displaying only what should be visible, and adding new items on scrolling. I will do keep it in mind. It would indeed fix the problem of long loading an inventory UI with 2000+ items in it.
    Thank you.
    Wish you all the best! :D
     
    dlorre likes this.
  7. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,887
    Do you know that most inventories would store 2000 potions as just one element with a number, not 2000 instances?
     
    Kurt-Dekker likes this.
  8. JeaNiX

    JeaNiX

    Joined:
    Oct 31, 2016
    Posts:
    20
    Thats true, but what if I want to stack them in stacks of 15 potions per slot? One index of the list would contain one item, which would have the information about the item from the scriptable object, and the quantity from the item. Stacking 2000 items in one slot would be easy, but I group them in stacks. 15 is just an example.