- Home /
Setting Inventory Reference to a Object For Pickup when the Inventory is a Instantiated Prefab
So, I'm having an issue in my game where the objects I need to pick up require a reference to the Inventory. However, the Inventory attached to an Inventory GameObject that is a child of a Canvas that is instantiated when the game starts. Is possible to get the reference the object to be picked up needs?
Pictures:
Code 1:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PickUpObject : MonoBehaviour {
[SerializeField] Pickup item;
[SerializeField] Inventory inventory;
[SerializeField] AccessInventory access;
private bool hasEntered;
void Update() {
if (Input.GetKeyDown(KeyCode.F) && hasEntered) {
inventory.AddItem(item);
access.accessInventory();
Destroy(this.gameObject);
}
}
void OnTriggerEnter(Collider other) {
if (other.CompareTag("Player")) {
hasEntered = true;
}
}
}
Code 2:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour {
public static Inventory instance;
[SerializeField] List<Pickup> items;
[SerializeField] Transform itemsParent;
[SerializeField] InventorySlots[] inventorySlots;
private void Awake() {
if (instance == null) {
instance = this;
}
else {
Destroy(this.gameObject);
}
}
private void OnValidate() {
if (itemsParent)
{
inventorySlots = itemsParent.GetComponentsInChildren<InventorySlots>();
}
GetUIUpdate();
}
public bool AddItem(Pickup item) {
if (isFull()) {
return false;
}
items.Add(item);
GetUIUpdate();
return true;
}
public bool RemoveItem(Pickup item) {
if (items.Remove(item)){
GetUIUpdate();
return true;
}
return false;
}
public bool isFull() {
return items.Count >= inventorySlots.Length;
}
void GetUIUpdate() {
int i = 0;
for (; i < items.Count && i < inventorySlots.Length; i++) {
inventorySlots[i].item = items[i];
}
for (; i < inventorySlots.Length; i++) {
inventorySlots[i].item = null;
}
}
public void SaveInventory() {
GlobalController.instance.inventory = inventorySlots;
}
}
A item shouldn't exist in your scene, all data should be handled by a "Backend" or core managers.
For instance, you've tied logic to your items and the front end with RemoveItem
what happens if you don't want to have sprites but 3D game objects to display? When all you had to do was remove an item from a "backend" list and have another front end listen to that list to populate your ui.
Answer by asafsitner · Mar 21 at 07:34 AM
Since you have a static reference to the Inventory object, you can just feed it to the PickupObject on Start or OnEnable, e.g.:
void OnEnable()
{
inventory = Inventory.instance;
}
By the way, you don't even have to do that if you have a static reference, since you can just access it directly when you want with Inventory.instance.WhateverPublicMemberHere;
In general, though, even if you didn't have a static reference, you could have searched for the object either by name, or https://docs.unity3d.com/ScriptReference/Object.FindObjectOfType.html.
For example, on the PickupObject you would write (instead of the code above):
void OnEnable()
{
inventory = FindObjectOfType<Inventory>(); // find by type
inventory = GameObject.Find("Name_Of_Inventory_Object_Here"); // by name
}
Note that looking for the object instead of already having a reference to it is obviously more expensive in terms of performance.
I'm sorry if I didn't provide enough context or what, but the GameObject.Find method will not work on this since it cannot convert from GameObject to Inventory.
inventory = FindObjectOfType() does work, however it only works while the inventory screen is open. Meaning that in order for the pickup to actually be put in the inventory, I need to have the inventory be already open, which is the reverse of how I want it.
The Inventory.instance method did work though, so thanks!
Right, so the way you want to work with these conversions is to not convert them at all! Instead, you'll want to use .GetComponent<T>()
to get the type that you need (especially in the case of the GameObject.Find(name)
function since, as you found out, it returns the GameObject and not the component that you really need).
As for why FindObjectOfType<T>()
didn't work, that's probably because the function can't find deactivated game objects by default. If you look at the API reference again, you'll notice that the function can take a bool parameter that allows it to search deactivated objects as well, e.g. var inventoryObject = FindObjectOfType<Inventory>(true);
I also just realized that I need to set the Access for a PickupObject as well and that is more tricky since PickUpObject calls the AccessInventory script via the Global Controller but trying to set it to Global Controller just results in an error since it can't convert from GlobalController to AccessInventory.
Edit: Figured it out,
access = GameObject.FindGameObjectWithTag("Global Controller").GetComponent();
Is AccessInventory a component? If so, you can do GlobalController.instance.GetComponent<AccessInventory>()
to get the "converted" script
Yep, that also works. I'll probably go with that one instead of the one I posted since it looks a bit neater.
Your answer
Follow this Question
Related Questions
I wanna make a simple inventory system that can hold three objects But I can't get it to work. 0 Answers
Do not pick item when item full 2 Answers
Changing the Variable of an objects script, through a different objects event. 1 Answer
saving inventory to database 3 Answers
Inventory Drop Function Problem 1 Answer