- Home /
What's the best way to use prefabs as Dictionary values?
This is a bit of a complicated question. I have a set of items with unique behavior, and my classes refer to them using the values in an enum called TileItemType
. I want to associate them with prefabs using a dictionary like this Dictionary<TileItemType, GameObject> dict;
. To set those values I'm thinking I'll need to use ISerializationCallbackReceiver
and create a custom property drawer. But before I get too deep into it I'm wondering if maybe there's a better way to go about all this.
Answer by PizzaPie · Oct 15, 2017 at 11:47 AM
If your prefabs match the number of associated enum values that s too complicated for no reason, as the match is 1-1 just directly refer to the prefabs. If you have more than one prefabs associated with a single TileItemType then the dictionary should be
Dictionary<TileItemType,List<GameObject()> dict;
and one way to serialize/ create custom editor would be this. On the other hand you could create a class
[Serializable]
public class ItemTileData{
public TileItemType type;
puclic GameObject prefab;
}
To make the association and use a "database class" to pick them.
public class TileDataBase /* : ScriptableObject // the easiest way to serialize it */
{
public list<ItemTileData> tileList;
}
But that wouldn't be that performance efficient. And lastly you could just directly create a "database" class
public class TileDataBase : ScriptbleObject
{
List<GameObject> myTypeAPrefabs;
List<GameObect> myTypeBPrefabs;
//and so on for each type
public GameObject GetPrefabOfTileType (TileItemType type){
switch(type){
case TileItemType.TypeA :
return (someObject from myTypeAPrefabs);
//...}
}
but with this it is a pain to add more TileItemTypes as you need to add a new List and new case to switch but it is quite performance efficient regarding previous solutions (in the first the Serializasion/Deserializasion of the dictionary is quite heavy but look ups are fast/ second one look ups are quite slow) Cheers.
Yes, the match is just 1-1. I seem to be missing something here. How do you directly refer to prefabs? The prefabs are just in my assets folder. I thought they didn't even exist in the compiled application unless I set them as values in the inspector.
I'm now guessing you mean that my public TileItemType
fields could just be GameObject
fields ins$$anonymous$$d. This was the route I was going at first. However, once I start instantiating the game objects I won't be able to compare them effectively, because two instances of the same prefab don't equal each other. Using an enum to uniquely identify the "types" of objects seems effective and lightweight, though it certainly does complicate things when it comes to custom property drawers and such. I could just put an enum as a property in a script on each prefab, and now that I think of it that may be the best solution. However, this whole project is mostly for practice and now that I'm going down this route I kind of want to see if I can get custom property drawers to work.
What do you mean by "But that wouldn't be that performance efficient"? In the examples I've seen, dictionaries are serialized using two separate lists: one for keys and one for values. It makes more sense to me to just use one list of key/value pairs. Why would that be worse for performance?
The dictionary can find an item with O(1) using hash value. Your two lists of $$anonymous$$ey/Value, you 'd have to iterate the keys to find the match, that is O(n). So dictionary will find right away, your double list system will have worst case as the size of the collection.
You misunderstand. I'm not talking about the performance of dictionaries versus lists. I'm talking about, specifically in a "serialized dictionary," the performance of two lists versus one list.
Answer by fafase · Oct 15, 2017 at 06:48 PM
First, you create a script that you attach to the prefabs. This script is used to define the type of your prefabs. For each of the prefab, attach and set it to the needed value.
public class PrefabType:MonoBehaviour{
[SerializeField] private TileItemType tileType;
public TileItemType TileType{ get { return this.tileType; } }
}
Second, you drag all your prefabs in a collection and create a dictionary for storage. Notice the type of the collection, it is PrefabType as the above class.
[SerializeField]private PrefabType [] prefabs = null;
IDictionary<TileItemType, GameObject> dict = null;
Then in the start, you populate the dictionary and get rid of whatever is not needed.
void Start(){
this.dict = new Dictionary<TileItemType, GameObject>();
foreach(PrefabType pt in this.prefabs){
this.dict.Add(pt.TileType, pt.gameObject);
Destroy(pt);
}
}
Finally, you have a method for access.
public GameObject GetPrefabByTileType(TileType tileType){
GameObject result = null;
this.dict.TryGetValue(tileType, out result);
return result;
}
if all keys are there then you can just do:
public GameObject GetPrefabByTileType(TileType tileType){
return this.dict[tileType];
}
Your answer
Follow this Question
Related Questions
Dictionary Keys to Stack Enemy Types 1 Answer
GameObject.FindGameObjectsWithTag() to find Prefabs which are not in the scene 1 Answer
Whats the best way to populate a Dictionary with multiple Prefabs? 0 Answers
Prefab, referencing them, using their methods:bug or intentional? 1 Answer
file sizes of prefabs 0 Answers