- Home /
Loot code Modification
Hi guys,
I'm an artist making a demo level with some of my assets. I've been "programming" (following tutorials) for like two weeks now so I only know enough to make slight modifications to code. The following works, but I'd like to add functionality, which is a little beyond what I'm capable of right now.. I don't expect anyone to write anything for me, but some solid guidance would be greatly appreciated!
First, where would I stick a Random.Range in here? I'd like to enter my entire loot table into the array and have the script choose from the items.
Second, how would I tell it to only drop a specific number (or even better, a random range) of items.
 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;
 
 public class ItemDropper_Death : MonoBehaviour
 {
     public List<GameObject> objectsToDropOnDeath;
     public int offSetWidth = 10;
     
     public void AddItemToDrop(GameObject newItem)
     {
         if (newItem != null)
         {
             if (!objectsToDropOnDeath.Contains(newItem))
             {
                 objectsToDropOnDeath.Add(newItem);
             }
         }
     }
     
     public void OnDeath()
     {
         if(objectsToDropOnDeath.Count > 0)
             DropItems();
     }
     
     private void DropItems()
     {
         foreach (GameObject myObject in objectsToDropOnDeath)
         {
             if(myObject != null)
                 InstantiateNewObject(myObject);
         }
     }
     
     private void InstantiateNewObject(GameObject objectToDrop)
     {
         Instantiate(objectToDrop, GetPosition(), GetRotation());
     }
     
     private bool offsetLeft = true;
     private Vector3 GetPosition()
     {
         Vector3 newPosition = new Vector3();
         
         int randX = (int)Random.Range((offSetWidth / 1.5f), offSetWidth);
         int negRandX = (int)Random.Range(-offSetWidth, -(offSetWidth / 1.5f));
         
         int xOffset = 0;
         
         if (offsetLeft)
             xOffset = negRandX;
         else
             xOffset = randX;
         
         offsetLeft = !offsetLeft;
         
         newPosition = new Vector3(this.transform.position.x + xOffset, this.transform.position.y, this.transform.position.z);
         
         return newPosition;
     }
     
     private Quaternion GetRotation()
     {
         Quaternion rot = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f);    //rotation of 0, needed for instantiation
         
         return rot;
     }
     
 }
 
Answer by supernat · Mar 31, 2014 at 03:40 PM
I would replace lines 29-33 with something like this:
 // Random.Range, when passed two integers, returns a number >= start and < last
 // That's confusing, because when you pass two floats, you get >= start and <= last.
 // The reason they did that is because most of the time when you pass ints, you want between 0 
 // and an object's count as an index, but the max index has to always be object count - 1
 int index = Random.Range(0, objectsToDropOnDeath.Count);
 GameObject obj = objectsToDropOnDeath[index];
 // then instantiate it
To do something like limit the drops, it depends on if you are okay with a specific drop being repeated, i.e. the code I just wrote could be called twice but would potentially give the same game object twice. To avoid that, the pattern I always use is to create a temprary list of potential drops, then run the code above but remove that drop from the list. Then run it again with the smaller list. For instance, to get a random number of drops (between minDrops and maxDrops):
 int minDrops = 1;
 int maxDrops = 5;
 int numDrops = Random.Range(minDrops, maxDrops + 1);  // Remember, Range() with ints is always < last, so add 1 to make it return maxDrops occasionally
 // This list will always contain indices into the objectsToDropOnDeath array that have not been used
 List<int> dropsLeft = new List<int>();
 for (int i=0; i < objectsToDropOnDeath.Count; ++i)
     dropsLeft.Add(i);
 // Create drops the random numDrops times
 for (int i=0; i < numDrops; ++i) {
     int index = Random.Range(0, dropsLeft.Count);
     GameObject obj = objectsToDropOnDeath[dropsLeft[index]];
     // instantiate etc
     // We used this drop object already, so remove it from the list for next iteration
     dropsLeft.Remove(index);
 }
You could go even further and limit just the number of drops for a single game object, like allow up to 10 arrows but never more than 1 bow. I would also implement a probability scale so some items are more likely to drop. There are two ways I know of to do this. One is to add multiple items to the temp list, like you would add the index for an arrow 10 times and index for a bow only once, then you have 1 in 11 chance to drop a bow, etc.
The List class may not support this because it's Remove() method works by passing in the value that is being stored (what I mean is you aren't removing index 0, index 1, etc of the temp list. You're telling it remove object that equals 5 or equals 10, where 5 or 10 is the index you pushed into the array from objectsToDropOnDeath initially.
The other approach is to pick a random num between 1 and 100 floating point and establish buckets for the likelihood of an object to land in a given range, I.e. 1 to 89 is an arrow and 90 to 100 is a bow.
At some point, it becomes such a complex thing it makes more sense to just create a LootableItem class which provides the min loot, max loot times, the probability of looting it, etc.
!!! Thank you so much for your answer, Supernat. I'm heading back home in a bit and will get to working your suggestions in.
I've actually got the beginnings of a dictionary for my loot. Just the major armor, weapon and story items. It was a bit of a tangent at the time though so I set it aside to work on other functionality. I'll have a look at it again and add $$anonymous$$, max and probability there.
Your answer
 
 
              koobas.hobune.stream
koobas.hobune.stream 
                       
                
                       
			     
			 
                