missingGameObject problem

Hello!.

I’m relatively new to unity, not sooo new but a bit. I will post my problem in two parts, the long story and the short one:

LONG VERSION

I’m making a game where I can pick some items, that are defined by a ItemClass made in JS. The ItemClass stores the mass, the name, the type, the GameObject etc. The object have a script “when you pick me, i will give you my ItemClass data and i’ll destroy myself” and the player have an inventory script “my function Pickup will take that data and then will store it in my ItemClass list”. I have worked with all of that and everything was going ok until now: I want some items to be “placeables” and when I click, I want to instantiate them, but for some reason when i try to do that, i get an error “wtf, there is no object to instantiate” and after searching for two days i found the error, my “Pickup” function recieved the ItemClass data, all the variables, but stored all the variables in the inventory except one: the GameObject variable.

SHORT VERSION

I have an ItemClass that stores some variables that define items, and some objects that send the data to my player. The player have an Inventory that take that data with a pickup function and then stores it in an ItemClass list. The function takes properly all the variables of the ItemClass and stores almost all but the GameObject variable.

VERY SHORT VERSION

My pickup function don’t want to send the GameObject! >:(

The ItemClass.js script:

public class ItemClass
{
enum ItemType {None, Weapon, Material, Food, Wear, Building, Light, Other}
public var id : int;
public var name : String;
public var obj : GameObject;
public var type : ItemType;
public var icon : Texture2D;
public var mass : float;
public var force : int;
}

The Pickable.js script (the one that sends the ItemClass to the player)

var Pickable : boolean = true;
var itemInfo : ItemClass;
function OnTriggerStay (other : Collider)
{	
if (other.gameObject.name == ("Player")) {
	var Inventory : Inventory = other.GetComponent(Inventory);
	if (Input.GetKey("e")) {
		if (Inventory.isRecieving == true && Pickable == true) {
			//Debug.Log("Sending " + itemInfo.name); works fine
			//Debug.Log("Sending " + itemInfo.type); works fine
			//Debug.Log("Sending " + itemInfo.obj); works fine
			
			other.gameObject.SendMessage ("Pickup", itemInfo);
			
			Destroy (transform.parent.gameObject);
		} else {
			Debug.Log("You can't Pickup this object");
		}
	}
}
}

The Inventory.js Script

import System.Collections.Generic;

var inventory : List.<ItemClass> = new List.<ItemClass>();
var isRecieving : boolean = true;
var inventoryOpen : boolean = false;

var tempObj : GameObject;

function Pickup (itemInfo : ItemClass) {
	inventory.Add (itemInfo);
	
	//Debug.Log("Recieved " + itemInfo.name); works fine
	//Debug.Log("Recieved " + itemInfo.type); works fine
	//Debug.Log("Recieved " + itemInfo.obj);  works fine
	
	var x : int = inventory.Count - 1;
	tempObj = itemInfo.obj; //trying to set a temporal object
	
	//Debug.Log("Saved " + inventory[x].name); works fine
	//Debug.Log("Saved " + inventory[x].type); works fine
	//Debug.Log("Saved " + inventory[x].obj);  works fine
	
	//inventory[x].obj = tempObj; //trying to set the temporal object to the ItemClass
	Debug.Log("tempObj: " + tempObj); //this is to see if the temporal object is being saved
	//and it works fine also, the tempObj is defined
}
function Update () {
	if (Input.GetKeyDown("r")) {
		if (inventoryOpen) {
			inventoryOpen = false;
		} else {
			inventoryOpen = true;
		}
	}
	Debug.Log("tempObj: " + tempObj); //here, after defining the variable in the Pickup function, it returns null. WTF!!!
	
	//And in the Inventory this is what i get:
	//inventory[x].name = works fine
	//inventory[x].type = works fine
	//inventory[x].obj = NULL!!! THIS IS DAMN NULL!!!
}

In the inspector in the itemClass list, the game object is “Missing (GameObject)”

I also tried with sending just the GameObject and then check in the Inventory.Update() if it worked, but always the same. Far as I know the problem is when the pickup function tries to send the data out of the function, like it don’t support sending gameObjects, but I have no Idea.

EDIT: I think this is important and i forgot to say it: the itemData.obj does not store the GameObject in wich the code is, it stores a Prefab in the project assets, so destroying the object is not suposed to destroy the itemData.obj too, i think.

Also, could be interesting information, in the Pickup function, when I set tempObj = gameObject (the player gameObject), it works fine and in the Update function it returns the GameObject properly. It seems like the error just happen with the ItemClass gameObject, it makes no sense.

I need some help please :frowning: thanks in advance.

PD: sorry my english…

From what I understood - You’re attaching ItemClass to your items, and when you pick up an item, you send its data to the player and destroy the item? If so, it makes sense for the GameObject reference to be null cause you nuked it with Destroy (transform.parent.gameObject);

When you make an inventory, you to answer a tricky game design question: “What to do with the item model, after I pick it up?!” - when you pick an item up, most the times you only care about the item data (name, sprite, number of rows/cols required to fit in your inventory, id, etc) - For example, In the good old Resident Evil games (1, 2, 3), when you pick an item like a herb for example, you don’t need its model anymore - cause you never use it, so it makes sense to Destroy the item model when you pick, and send the data over to the inventory. But not all items are like that, for example weapons: when you pick a weapon up, should you destroy its model? if you do, how would you let your player equip it? how would it appear as a physical object on your player’s model?

If you’re not sure what to do with the actual item object, why not just disable it and decide later on? - instead of destroying the item when you pick it up, do:

item.gameObject.SetActive(false);

It’s not clear why are you doing a transform.parent.gameObject in your Destroy call. Why parent? Isn’t the Pickable script attached to your item? if so, and you want to destroy the item on pickup then you only need Destroy(gameObject); - But, if you wanted to Destroy the Pickable script that’s attached on the item, when you pick the item, then just Destroy(this); - this refers to the component itself. (Pickable)

Some other tips:

  1. When you’re picking up the item, you’re doing a other.gameObject.SendMessage(...); - you’re sending a msg directly to that object - which is the Player object. It seems as if there’s no dependency there - but there is, if the player didn’t have an Inventory script on him, it wouldn’t work. So, I would argue that to pick an item up, the player must have an Inventory on him. Why not be explicit in that case? IMHO this is better - what if you had other scripts that also had a Pickup function? or what if you decided to refactor, and change the name of the Pickup function?.. So:
    var inventory = other.gameObject.GetComponent< Inventory >(); inventory.Pickup(itemInfo);

  2. You don’t need to say if (myBoolean == true) - myBoolean is a boolean variable, it returns true or false. And if takes a boolean expression as its input (a boolean expression is anything that returns true or false) - in other words, if myBoolean was true, it’s like you’re saying if (true == true) - Redundant, right? If you wanted to see if myBoolean was true, you just need if(myBoolean) - if you wanted to see if it’s false (not true, !true) - do if(!myBoolean) - makes sense? hope so…

  3. If you decided not to destroy the item’s object, and wanted to get a reference of an item’s object from your inventory, you don’t need to store a GameObject variable in your ItemClass - since ItemClass is attached to the item, you could just do:
    myItemGO = myItemInfo.gameObject;

  4. I really liked the fact that you’re separating responsibilities, thus applying the Single responsibility principle. Also, your approach is component-based, which is good. A Unity-friendly design. However, your data isn’t safe from miss-use. All your item’s data are public. Anybody could come in and change whatever he likes: itemInfo.id = -1; there’s no denying. Consider making your variables private and making public getters function getId() { return id; } and optionally setters with some validation code: function setId(value:int) { if (value > 0) id = value; } - But making a variable private, won’t make it visible in the inspector, to make it visible, give it the SerializeField attribute.

In your Pickable.js you call:

Destroy (transform.parent.gameObject);

This will destroy the gameobject at the end of the current frame.

In your Inventory.js you then call this in Update():

Debug.Log("tempObj: " + tempObj);

However on the next (and subsequent) frames that object has been destroyed.

Problem solved. For some reason the obj propierty was referencing the ingame object instead of a prefab, so i created a gameobject child of the player called backpack and now my Pickable script disable the item and move it inside the backpack instead of destroying it.

I still prefeer store a Prefab in the itemdata but this is ok for now. Thanks :slight_smile: