- 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.