- Home /
How to Instantiate objects that are Scriptable Objects
Hi I am trying to follow this tutorial (http://toqoz.fyi/unity-painless-inventory.html) as a reference for my inventory system. I am not implementing the exact same way due to some design considerations so am trying to adapt it to my situation.
My previous issue was that game objects were not persisting between scenes. the game objects that I wanted to persist, I added a DontDestroyOnLoad() into their scripts awake() methods and then that allowed me to then have the items I wanted in the next scene, but then I had to write code to manually delete the game objects from the 2nd scene that I did not want to be there as they ALL came over and it doesn't make sense for context of game. This is extra work and I see a lot of talk about Scriptable objects that as I understand should allow me to have a "static" inventory and then independent of which scene I am in, I can just instantiate items from the inventory in the scene I am in as needed. Also I want to be able to save player game data in-between play sessions and I hear that the Scriptable Objects will allow me to do this easier so anticipating this work I am trying to set myself up for success later there.
So to avoid having to manage the clean up effort of deleting game objects that do not belong between scenes I tried to implement Scriptable Objects with a Item.cs : ScriptableObject (similar to tutorial above) for all items that essentially then are purchased from a vendor in one scene, are then added to a ScriptableObject Inventory system and then I wanted to then instantiate an object for every item in the inventory in the next scene. The problem is I want to now instantiate these items but I cannot put a position or rotation on a scriptable object, so I have been trying to in code, create an instance of an Item.cs class and then use its associated GameObject field to show its physical representation. The problem then is I have to set each of its components (Box Collider, OVRGrabbable, etc..) and all the values I want them to have so I tried using a method I found on here for deep copy of component values (https://answers.unity.com/questions/530178/how-to-get-a-component-from-an-object-and-add-it-t.html?_ga=2.9981105.527810571.1592029078-1716816744.1582330304) and it is complaining about:
"Can't add component 'Component' to NewGameObject because such a component is already added to the game object!" and also
NullReferenceException UnityEngine.Component.get_tag () (at :0) System.Reflection.MonoMethod.Invoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at :0) Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation. System.Reflection.MonoMethod.Invoke ...
So I don't know that I am going the best away about this but I don't know any better at the moment so I understand its a lot to digest and this points at bigger architectural/design questions in the game so I would love help with talking through these considerations and changing to what is better implementation but if not, then making it work and maybe I learn more later and refactor again..
SpawnSaleItems.cs
...
void Start()
{
GameObject go = new GameObject("NewGameObject");
go.transform.position = new Vector3(1, 1, 1);
//gameTemplate is a prefab GameObject that has all the components and values I want to copy over for each instance of an Item
foreach (Component comp in gameTemplate.GetComponents(typeof(Component)))
{
Component c = new Component();
c.GetCopyOfComponent(comp);
go.AddComponent(c);
}
...
commonGames = new List<Item>();
commonGames.Add(new Item("Super Mario Bros", References.Console.NES, Resources.Load<Sprite>("NES/SuperMarioBros"), 8, References.ItemCondition.Great, References.ItemState.Functional, go));
....
Item.cs
using System.Collections; using System.Collections.Generic; using UnityEngine;
[System.Serializable] public class Item : ScriptableObject { int autoIncrementIdCounter = 0;
public int rowItemId;
public Sprite itemImage;
public string itemName;
public int itemPrice;
public References.Console itemConsole;
public References.ItemCondition itemCondition;
public References.ItemState itemState;
public GameObject physicalObject;
public Item(string name, References.Console console, Sprite img, int price, References.ItemCondition cond, References.ItemState state, GameObject phys)
{
rowItemId = autoIncrementIdCounter++;
itemImage = img;
itemName = name;
itemPrice = price;
itemConsole = console;
itemCondition = cond;
itemState = state;
physicalObject = phys;
}
}