In my game I have a simple loot system implemented. Enemies die and drop items which you can pick up. Picking up an item just draws that item's sprite in an inventory. All of this works properly if my inventory is open on the occasion of killing an enemy. However, if it is closed, i.e., if SetActive is set to false, then I get a strange NullReferenceException which I don't quite understand. Again, this happens if the inventory is closed when an enemy dies and generates an item, not when attempting to pick the item up. Attempting to pick the item up will work regardless of whether or not the inventory is open, insofar as the inventory was open when the enemies died and generated items. Error: NullReferenceException: Object reference not set to an instance of an object ItemPickup.Awake () (at Assets/Scripts/Items/ItemPickup.cs:16) UnityEngine.Object:Instantiate(GameObject, Vector3, Quaternion) ItemGenerator:GenerateItem() (at Assets/Scripts/Items/ItemGenerator.cs:40) ItemGenerator:Update() (at Assets/Scripts/Items/ItemGenerator.cs:32)
Here is the code.
Inventory scripts:
public class InventoryToggle : MonoBehaviour
{
GameObject inventory;
bool inventoryIsOpen;
void Awake()
{
inventory = transform.Find("Inventory").gameObject;
}
void Start()
{
// Deactivate in Start instead of Awake to allow other scripts to cache references beforehand
inventory.SetActive(false);
}
void Update()
{
if (!inventoryIsOpen && Input.GetKeyDown(KeyCode.I))
{
inventory.SetActive(true);
inventoryIsOpen = true;
}
else if (inventoryIsOpen && Input.GetKeyDown(KeyCode.I))
{
inventory.SetActive(false);
inventoryIsOpen = false;
}
}
}
and
public class InventorySlotManager : MonoBehaviour
{
const int numSlots = 100;
Item[] items = new Item[numSlots];
public Image[] itemImages = new Image[numSlots];
public void AddItem(Item item)
{
for (int i = 0; i < items.Length; i++)
{
if (items[i] == null)
{
items[i] = item;
itemImages[i].sprite = item.itemSprite;
itemImages[i].color = new Color(255, 255, 255);
return;
}
}
}
}
Attached to each enemy gameObject:
public class ItemGenerator : MonoBehaviour
{
EnemyHealth enemyHealth;
ItemRandomizer itemRandomizer;
public GameObject itemPrefab;
ItemLabelDisplay itemLabelDisplay;
bool itemGenerated;
void Awake()
{
enemyHealth = GetComponentInParent<EnemyHealth>();
itemRandomizer = new ItemRandomizer();
}
void Start()
{
// Item pool
itemRandomizer.AddItemsToContainer(ItemDatabase.sword, 1);
itemRandomizer.AddItemsToContainer(ItemDatabase.axe, 2);
}
void Update()
{
if (enemyHealth.isDead && !itemGenerated)
{
GenerateItem();
}
}
void GenerateItem()
{
itemGenerated = true;
GameObject generatedItem = Instantiate(itemPrefab, transform.position, Quaternion.identity);
ItemClassAssociation itemClassAssociation = generatedItem.GetComponent<ItemClassAssociation>();
itemClassAssociation.item = itemRandomizer.GetRandomItem();
// Set the text in the item label to display the item's name
itemLabelDisplay = generatedItem.GetComponentInChildren<ItemLabelDisplay>();
itemLabelDisplay.itemName.text = itemClassAssociation.item.itemName;
}
}
Attached to each Item's UI label
public class ItemPickup : MonoBehaviour, IPointerClickHandler
{
GameObject itemOnGround;
ItemClassAssociation itemClassAssociation;
InventorySlotManager inventorySlotManager;
void Awake()
{
itemOnGround = transform.root.gameObject;
itemClassAssociation = itemOnGround.GetComponent<ItemClassAssociation>();
inventorySlotManager = GameObject.FindGameObjectWithTag("Inventory").GetComponent<InventorySlotManager>();
}
public void OnPointerClick(PointerEventData eventData)
{
PickUpItem();
}
void PickUpItem()
{
inventorySlotManager.AddItem(itemClassAssociation.item);
Destroy(itemOnGround, 0.1f);
}
}
Update()
method in yourInventoryToggle
class can be cleaned a bit by only checking theInput
once:if (Input.GetKeyDown(KeyCode.I)) { inventory.SetActive(!inventoryIsOpen); inventoryIsOpen = !inventoryIsOpen; }
– Daevin Jul 28 '17 at 17:47