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

How can I go about tracking a large amount of collectible items?

Discussion in 'Scripting' started by AV_Corey, Jan 24, 2017.

  1. AV_Corey

    AV_Corey

    Joined:
    Jan 7, 2016
    Posts:
    122
    I have a series of levels in my game that contain varied amounts of a collectible item, some levels contain ~50 whereas some levels can contain upwards of 100.

    I need to save how many of the collectibles the player has picked up in each level, but more importantly which exact collectibles they have picked up in each level.

    I need to know which exact collectibles have been picked up because I want the 'un-collected' collectibles to still be in their correct position should the user leave and re-enter the level at a later time to collect them.

    I heard 'player.Prefs' is only for things like highscores and shouldn't be used often so I don't think I can use that. If anyone can point me in the right direction with the best way I can go about achieving something like this it would be much appreciated :)

    Thanks,
    Corey
     
    Last edited: Jan 24, 2017
  2. AV_Corey

    AV_Corey

    Joined:
    Jan 7, 2016
    Posts:
    122
    Bumping
     
  3. Joboto

    Joboto

    Joined:
    Sep 12, 2013
    Posts:
    64
    Hi there,

    What you need is:

    A way to creating a unique ID for each collectable;
    A flag to set if the item is collected;
    A position to save where the item is found in the world;
    Data persistence to save and load the state of each collectable.

    In the case where some collectables may be spawned by dynamic actions, you may need further indentifiers, but lets leave that for now.

    These are excellent resources.
    https://unity3d.com/learn/tutorials/topics/scripting/persistence-saving-and-loading-data
    https://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/scriptable-objects


    .........

    I won't suggest my solution to the problem below is the best approach but I will describe it to give you food for thought:

    I have a ScriptableObject that represents each level, this holds different Lists of collectables that can be collected in my game. On Awake my level manager clears any collectables that may be left in the scene then reads the Level data from a text file and loads them into the each level object. I then Instantiate each collectable in the current scene but only the ones that don't have the "isCollected" flag set to true are set to Active (some optimisation could be used here such as pooling).

    Each of my collectables has a component attached to it that holds the unique ID. When ever I collect a collectable I update the list stored in my Level object to reflect the new state by looking up the list by ID and setting the item collected boolean.

    When saving, I just serialize the Levels data using JsonUtility and write it to the text file.

    For editing collectables, I built a little command line interface (this could easily replaced with Unity UI buttons) this allows me to do simple quality of life commands while running the project such as resetting all collectables in the text file, updating the text file with newly added collectables or clearing the data. This involves generating new unique IDs for each collectable, as I detest doing anything manually where i can help it.

    It's worth noting that I also hold a boolean called isUsed because in my game collectables can be used to perform actions such as using a Key collectable to open a door that is then no longer available in the game.

    Separating collectables by level this way makes it easier for me to quickly count how may have been collected or have yet to be collected to display in Menus. I can see that there is possibly more efficient ways of doing the same thing, perhaps storing all collectables in a single list and include IDs for the collectable type and level.

    I hope that gives you a starting point.

    Kind Regards,
    Joe
     
    eses likes this.
  4. AV_Corey

    AV_Corey

    Joined:
    Jan 7, 2016
    Posts:
    122
    I appreciate the detailed response. It has made it a lot more clear to me what kind of processes need to be performed to achieve this kind of tracking system, thanks very much :)
     
  5. elKarkayu

    elKarkayu

    Joined:
    Mar 23, 2017
    Posts:
    18
    Thanks man! It's just the point I was looking for.
     
  6. kimobm

    kimobm

    Joined:
    Dec 20, 2019
    Posts:
    26
    Hello AV_Corey,

    did you manage to find a solution for your Collectibles issue ( after 3 years )?

    I have almost the same question, and reallyt don't know from where to start ?
     
  7. coward

    coward

    Joined:
    Jan 9, 2013
    Posts:
    21
    The original response was helpful I think.

    One key factor for me, is: don't use colliders! They will slow down your game. You could potentially activate a set of colliders in a batch.

    Instead, I use a dictionary that maps positions to collectibles because lookups by key are very fast. (e.g. Dictionary<Vector3, Collectible>). Then you can just use the player's position to query the dictionary for collectibles. I actually use a loop based on the distance from the character, pull out all collectibles in that range (in order to show/hide) and use that newly formed collection to query for the player passing through the location of the collectible.
     
    DiamondEater likes this.