- Home /
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
'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
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
y 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 :( thanks in advance.
PD: sorry my english...
Answer by vexe · Dec 22, 2013 at 09:13 AM
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:
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 anInventory
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 aPickup
function? or what if you decided to refactor, and change the name of thePickup
function?... So:var inventory = other.gameObject.GetComponent(); inventory.Pickup(itemInfo);
You don't need to say
if (myBoolean == true)
-myBoolean
is a boolean variable, it returns true or false. Andif
takes a boolean expression as its input (a boolean expression is anything that returns true or false) - in other words, ifmyBoolean
was true, it's like you're sayingif (true == true)
- Redundant, right? If you wanted to see ifmyBoolean
was true, you just needif(myBoolean)
- if you wanted to see if it's false (not true, !true) - doif(!myBoolean)
- makes sense? hope so...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 yourItemClass
- sinceItemClass
is attached to the item, you could just do:myItemGO = myItemInfo.gameObject;
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 variablesprivate
and making public gettersfunction 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 theSerializeField
attribute.
The same for the answer above, the ItemClass.obj does not store the ingame Object, it stores a Prefab in the project assets, but that is a good way (very posibly better way than $$anonymous$$e) to solve that problem. Or most probably i am missunderstanding something about how the gameobjects work.
About the tips:
You are right, but the code i'm using for now works fine, and with my unity xperience, i don't think i can change that without getting confusing, so i will let it be that way xD
I'm felling dumb now, that is actually true, i will change that.
The Send$$anonymous$$essage option doesn't let me send two variables... but you already solved it in the first tip... I think someone is going to rewrite some code here... lol
This is the only tip that i think is not the best option, i made the variables public just because of that: i want to edit them easily in the inspector for each item, even in the inventory for testing pruposes.
Thanks for the help :)
Answer by KellyThomas · Dec 22, 2013 at 09:03 AM
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.
But the ItemData does not have the Gameobject in where is stored, the obj variable is a prefab from the project assets, not the ingame object.
O$$anonymous$$.... scratch that idea then.
Is the obj
property of the ItemClass
's stored in your inventory
list still intact?
$$anonymous$$aybe try commenting out the destroy call and see if your inventory list's obj properties are still missing.
It worked ._. after i replaced the Destroy with a SetActive(false) as sugested by vexe and now is working, but that's not what I want D: Why does this happen?
Answer by Arnaz87 · Dec 23, 2013 at 02:51 PM
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 :)
Your answer
Follow this Question
Related Questions
Can someone help me fix my Javascript for Flickering Light? 6 Answers
Setting Scroll View Width GUILayout 1 Answer
How to tell if 2 blocks are next to each other in a 2d game? 1 Answer
The name 'Joystick' does not denote a valid type ('not found') 2 Answers
It is not possible to invoke an expression of type 'UnityEngine.GameObject'? 1 Answer