- Home /
Is it good practice to keep a reference to an GO to avoid having to instantiate it?
I have a base item class:
public abstract class ItemBase { #region Private Fields private int id; private ItemType itemType; private Transform transform; private GameObject item; #endregion
#region Public Fields
public GameObject prefab;
#endregion
#region Public Properties
public GameObject Item
{
get
{
if (this.item == null)
InstantiateItem();
return this.item;
}
}
public Transform Transform
{
get
{
return this.transform;
}
set
{
this.transform = value;
}
}
public ItemType ItemType
{
get
{
return this.itemType;
}
set
{
this.itemType = value;
}
}
#endregion
#region Constructor
public void Initialize(int id, ItemType itemType, Transform transform = null)
{
this.id = id;
this.itemType = itemType;
this.transform = transform;
}
#endregion
#region Private Methods
private void InstantiateItem()
{
if (prefab == null)
{
throw new Exception("Item prefab not defined.");
}
if (this.transform != null)
{
this.item = GameObject.Instantiate(this.prefab, this.transform);
}
else
{
this.item = GameObject.Instantiate(this.prefab);
}
}
#endregion
}
This structure allows me to create new instances of my items without having to instantiate GO's.
Usually you would add an "Item" component to a GO (above example does the opposite).
I have managers which have references to these items which create, remove, etc.
I plan on using a database to read the item information and create references to them (only instantiating the item GO's when needed).
My goal is to only instantiate GO's when they physically need to be in the game.
Is this architecture/structure/implementation common, or am I going to be running into a lot of problems in the near future?
Answer by Xepherys · Sep 02, 2017 at 03:16 PM
Well, a commonly held best practice for instantiation is to keep a pool of objects that are called on as needed. This has the benefit of objects typically already being loaded into memory, preventing slow-downs during instantiation and also allowing more direct management of memory and the object pool as a whole. Personally, I feel there are some downsides to this, but I can also see the benefits.
As to your implementation, just to make sure I understand it correctly, you'll have a DB of items. When an item is needed, you'll create a new ItemBase()
and then Initialize()
it with the appropriate data, then Instantiate()
the item into existence? The only issue I can see is that this is a lot of work to create an item. The implementation itself doesn't seem like it would cause any headaches, but if this is something that will happen a lot, I'd throw it through the Profiler to see how performant it actually is.
How does the code know what object to create? In other words, I'm imagining this as "I need object #42, create it" is called by some other script, so a new ItemBase() is generated, Init is called for object #42 (which ties in with additional information in the DB), then it's instantiated at a location (or local to the script if no Transform is provided). Seems like a lot of overhead to call an object into existence.
How does the code know what object to create?
I have other classes that inherit from ItemBase. An example structure is:
Rifle > GunBase > WeaponBase > ItemBase
Rifle has a Initialize()
method which tells the object what type of rifle it is (e.g. a $$anonymous$$4A2). GunBase has a Initialize()
method which tells the object what type of gun it is (e.g. a Rifle). WeaponBase has a Initialize()
method which tells the object what type of weapon it is (e.g. a Gun).
You get the idea?
This way I know what item of what type to create.
Note: I only need to call Instantiate()
when I need to have a reference to the GO.
I only need to call Initialize()
every time to create a reference.
In this case, I think there's going to be too much overhead. Inheritance shouldn't require method calls up the chain.
For instance, Rifle should simply override the Init() of GunBase (or even ItemBase).
Are you using actual inheritance? In other words, does your WeaponBase class inherit from ItemBase like this:
public class WeaponBase : ItemBase
then
public class GunBase : WeaponBase
It may be worth looking into composition over inheritance. This is something that I've had a hard time with. While your method is, mostly, in line with OOP, it's important to note that even though Unity is best used with C#, which is object-oriented, Unity itself is GameObject driven and it's easy to fall into a trap trying to implement fuller OOP concepts in Unity.
However, even in an OOP manner, a derived class should be able to initialize and function without calling into parent classes directly. In other words, Rifle()
should be a fully functional class because it inherits all previous methods and implementations of it's parent classes.