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

Question Random Loot Generation in chests

Discussion in 'Scripting' started by KeyboardStudios, Jul 17, 2021.

  1. KeyboardStudios

    KeyboardStudios

    Joined:
    Jul 11, 2020
    Posts:
    9
    Hello! I need help with improving my code for random loot generation. Here is the code:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3.  
    4. public class lootGeneration : MonoBehaviour
    5. {
    6.     bool isFacingChest = true;
    7.  
    8.     public AnimationCurve itemDistribution;
    9.  
    10.     public int amountOfLoot = 10;
    11.     RectTransform chosenSlot;
    12.  
    13.     public List<RectTransform> slots;
    14.     public List<RectTransform> lootItems;
    15.  
    16.     public List<RectTransform> commonLoot;
    17.     public List<RectTransform> uncommonLoot;
    18.     public List<RectTransform> moderateLoot;
    19.     public List<RectTransform> rareLoot;
    20.     public List<RectTransform> legendaryLoot;
    21.     private void Update()
    22.     {
    23.         if (Input.GetKeyDown(KeyCode.E) && isFacingChest)
    24.         {
    25.             generateLoot();
    26.         }
    27.         if (Input.GetKeyDown("f"))
    28.         {
    29.             foreach(RectTransform rt in lootItems)
    30.             {
    31.                 rt.gameObject.SetActive(false);
    32.             }
    33.         }
    34.     }
    35.  
    36.     void generateLoot()
    37.     {
    38.         for (int i = 0; i < amountOfLoot; i++)
    39.         {
    40.             //Getting a random value with an animation curve
    41.             float randomValue()
    42.             {
    43.                 float random = (itemDistribution.Evaluate(Random.value)) * 100;
    44.                 return random;
    45.             }
    46.             //Converting it into an integral value
    47.             int probab = (int)randomValue();
    48.  
    49.             // going through S*** and assigning loot
    50.             if(probab >= 0 && probab <= 30)
    51.             {
    52.                 int random = Random.Range(0, commonLoot.Count);
    53.                 commonLoot[random].gameObject.SetActive(true);
    54.                 putLootInSlot(commonLoot[random]);
    55.             }
    56.             else if(probab > 30 && probab <= 50)
    57.             {
    58.                 int random = Random.Range(0, uncommonLoot.Count);
    59.                 uncommonLoot[random].gameObject.SetActive(true);
    60.                 putLootInSlot(uncommonLoot[random]);
    61.             }
    62.             else if(probab > 50 && probab <= 70)
    63.             {
    64.                 int random = Random.Range(0, moderateLoot.Count);
    65.                 moderateLoot[random].gameObject.SetActive(true);
    66.                 putLootInSlot(moderateLoot[random]);
    67.             }
    68.             else if(probab > 70 && probab <= 90)
    69.             {
    70.                 int random = Random.Range(0, rareLoot.Count);
    71.                 rareLoot[random].gameObject.SetActive(true);
    72.                 putLootInSlot(rareLoot[random]);
    73.             }
    74.             else if(probab > 90)
    75.             {
    76.                 int random = Random.Range(0, legendaryLoot.Count);
    77.                 legendaryLoot[random].gameObject.SetActive(true);
    78.                 putLootInSlot(legendaryLoot[random]);
    79.             }
    80.             else
    81.             {
    82.                 Debug.Log("Something went wrong :( Value generated :" + probab);
    83.             }
    84.         }
    85.     }
    86.  
    87.     void putLootInSlot(RectTransform lootObj)
    88.     {
    89.         //Get a random slot to put loot in
    90.         int randomSlot = Random.Range(1, slots.Count);
    91.         foreach (RectTransform slot in slots)
    92.         {
    93.             int index = slots.IndexOf(slot);
    94.             if (index == randomSlot)
    95.                 chosenSlot = slot;
    96.         }
    97.  
    98.         // Put the loot in
    99.         lootObj.anchoredPosition = chosenSlot.anchoredPosition;
    100.     }
    101. }
    The thing that I have a problem with is the amount of lists used in here. I could not figure how to classify loot objects without having to use all these lists.

    I tried something with scriptable objects being attached to each of the loot items containing the loot type but I could not figure out how it would work.

    Any help would be appreciated. Thanks!
     
  2. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,128
    You could use an Enum for the item quality and do the selection based on that (his could also help reduce your if-else code). How many items do you have? With your current setup all the items (textures on sprites etc.) are loaded all the time. If you have a lot of items then it would be better to load them dynamically via addressables, ressources or scenes.

    As for how to store the config values of your items, SOs are one way to do it. Another would be to define them in an external file (txt, json, xml, csv, ...) and load it. People often call this the "loot table". Imho a spreadsheet is the best format for this (but opinions differ). There are assets in the store to manage this.

    I recently did a loot table. I have an ItemConfig class (plain c#), which contains an enum for the quality and some other fields (whatever attributes your item types need). At the start of the game I create/load a lot of config objects (a list). The item creation code then uses these configs in a factory pattern to create the actual items on demand.
     
    adamgolden likes this.
  3. adamgolden

    adamgolden

    Joined:
    Jun 17, 2019
    Posts:
    1,505
    You can access your lists by index instead of each one by name (though I do the same thing quite often), here's more on how to do it:
    Code (CSharp):
    1. public enum LootType
    2. {
    3.   COMMON,
    4.   UNCOMMON,
    5.   MODERATE,
    6.   RARE,
    7.   LEGENDAY
    8. }
    9. public class ExampleOfIndexingLists
    10. {
    11.   public List<List<RectTransform>> lootLists = new List<List<RectTransform>>(){
    12.     new List<RectTransform>(), new List<RectTransform>(), new List<RectTransform>(), new List<RectTransform>(), new List<RectTransform>()
    13.   };
    14.   public List<RectTransform> GetLootList(LootType type)
    15.   {
    16.     return lootLists[(int)type];
    17.   }
    18.   public void Test()
    19.   {
    20.     List<RectTransform> list;
    21.  
    22.     // to get a single list by type
    23.     list = GetLootList(LootType.COMMON);
    24.  
    25.     // to get a single list by index
    26.     list = lootLists[0];
    27.  
    28.     // to iterate contents of all lists
    29.     string[] lootTypes = Enum.GetNames(typeof(LootType));
    30.     for (int i = 0; i < lootTypes.Length; i++)
    31.     {
    32.       list = lootLists[i];
    33.       Debug.Log("there are " + list.Count + " items of " + lootTypes[i] + " loot");
    34.     }
    35.  
    36.     // convert to int from LootType..
    37.     int x = (int)LootType.LEGENDAY;
    38.  
    39.     // convert to LootType from int..
    40.     LootType type = (LootType)x;
    41.  
    42.     Debug.Log("LootType of integer x was " + type);
    43.   }
    44.  
    45. }
    46.  
     
  4. KeyboardStudios

    KeyboardStudios

    Joined:
    Jul 11, 2020
    Posts:
    9
    @_geo__ , @polemical thanks for the suggestions.

    I think I will do a bit of research on how the external file to store loot data thing works and try to implement it. I completely forgot about enums existing in c#. They would have made it easier to code this but thanks anyways
     
    adamgolden likes this.
  5. wileyjerkins

    wileyjerkins

    Joined:
    Oct 13, 2017
    Posts:
    77
    You want almost endless variety and fun? The way I have done it is in the past is to create base items (swords, bows, shields, scrolls, potions, etc).

    Then I created "effects" that powered up the weapons to make them special. Applying semi-random effects to base items created almost endlessly unique weapons.

    When a player opened a chest, the script knew what type player it was and "leveled up" the loot to be suitable for the player. (applied the random effect to the random but class appropriate weapon)

    Example: A level 10 wizard opens the chest, he is more likely to get a staff than a sword. And the staff is more likely to have effects such as +1 spellpower, +3 to flame spells. A level 3 wizard would have been more likely to get a +1 spellpower, +1 to flame spells staff.

    You can get some zany weapons, stuff like a dwarf hammer that is +3 damage to giants, -1 to dexterity.

    I had a magic blacksmith where the players could remove/change effects for $$ but there was a chance it would ruin the weapon or make it slightly less powerful.
     
  6. KeyboardStudios

    KeyboardStudios

    Joined:
    Jul 11, 2020
    Posts:
    9
    @wileyjerkins great suggestion man but I am going for more of a minecraft like loot generation system independent of level or something else.
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,971
    Oh that's easy. There was a time about a decade ago when fully HALF of the videos being posted every day to Youtube were how to make a Minecraft tutorial in Unity. A lot of those videos are still up for your reference. Nothing has changed in the process. Loot generation is quite well understood!

    Screen Shot 2021-07-17 at 8.25.08 AM.png