While the previous recipe worked fine, any old text might have been typed into the description for a pickup or perhaps mistyped (star, Sstar, starr, and so on). A much better way of restricting game properties to one of a predefined (enumerated) list of possible values is to use C# enums. As well as removing the chance of mistyping a string, it also means that we can write code to appropriately deal with the predefined set of possible values. In this recipe, we will improve our general purpose PickUp
class by introducing three possible pickup types (Star, Heart, and Key), and write inventory display code that counts the number of each type of pickup being carried and displays these totals via a UI Text object on screen. We also switch from using a List to using a Dictionary, since the Dictionary data structure is designed specifically for key-value pairs, perfect for associating a numeric total with an enumerated pickup type.
To display multiple pickups of different objects as text totals via a dynamic Dictionary
, follow these steps:
PickUp
with the following code:using UnityEngine; using System.Collections; public class PickUp : MonoBehaviour { public enum PickUpType { Star, Key, Heart } public PickUpType type; }
Player
with the following code:using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Collections.Generic; public class Player : MonoBehaviour { private InventoryManager inventoryManager; void Start(){ inventoryManager = GetComponent<InventoryManager>(); } void OnTriggerEnter2D(Collider2D hit){ if(hit.CompareTag("Pickup")){ PickUp item = hit.GetComponent<PickUp>(); inventoryManager.Add( item ); Destroy(hit.gameObject); } } }
PlayerInventoryDisplay
with the following code:using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Collections.Generic; public class PlayerInventoryDisplay : MonoBehaviour { public Text inventoryText; private string newInventoryText; public void OnChangeInventory(Dictionary<PickUp.PickUpType, int> inventory){ inventoryText.text = ""; newInventoryText = "carrying: "; int numItems = inventory.Count; foreach(var item in inventory){ int itemTotal = item.Value; string description = item.Key.ToString(); newInventoryText += " [ " + description + " " + itemTotal + " ]"; } if(numItems < 1) newInventoryText = "(empty inventory)"; inventoryText.text = newInventoryText; } }
InventoryManager
to the GameObject player-SpaceGirl
in the Hierarchy:using UnityEngine; using System.Collections; using System.Collections.Generic; public class InventoryManager : MonoBehaviour { private PlayerInventoryDisplay playerInventoryDisplay; private Dictionary<PickUp.PickUpType, int> items = new Dictionary<PickUp.PickUpType, int>(); void Start(){ playerInventoryDisplay = GetComponent<PlayerInventoryDisplay>(); playerInventoryDisplay.OnChangeInventory(items); } public void Add(PickUp pickup){ PickUp.PickUpType type = pickup.type; int oldTotal = 0; if(items.TryGetValue(type, out oldTotal)) items[type] = oldTotal + 1; else items.Add (type, 1); playerInventoryDisplay.OnChangeInventory(items); } }
enum
type are automatically restricted to the set of possible values as a combo-box drop-down menu in the Inspector panel.Each pickup GameObject in the scene has a scripted component of class PickUp
. The PickUp
object for each Pickup
GameObject has a single property, a pickup type, which has to be one of the enumerated set of Star, Key, Heart
. The Player
script class gets a reference to the InventoryManager
component via its Start()
method, and each time the player's character collides with a pickup GameObject, it calls the Add(…)
method of the inventory manager, passing the PickUp
object of the object collided with.
In this recipe, the inventory being carried by the player is being represented by a C# Dictionary
. In this case, we have in script class InventoryManager
a dictionary of key-value pairs, where the key is one of the possible PickUp.PickUpType
enumerated values, and the value is an integer total of how many of that type of pickup is being carried. Each InventoryItemTotal
object has just two properties: a PickUp
type and an integer total. This extra layer of the InventoryManager
has been added between script class Player
and PlayerInventoryDisplay
to both separate the Player
behavior from how the inventory is internally stored and to prevent the Player
script class from becoming too large and attempting to handle too many different responsibilities.
C# dictionaries provide a TryGetValue(…)
method, which receives parameters of a key and is passed a reference to a variable the same data type as the value for the Dictionary
. When the Add(…)
method of the inventory manager is called, the type of the PickUp
object is tested to see if a total for this type is already in Dictionary items
. If an item total is found inside the Dictionary
for the given type, then the value for this item in the Dictionary
is incremented. If no entry is found for the given type, then a new element is added to the Dictionary
with a total of 1.
The last action of the Add(…)
method is to call the OnChangeInventory(…)
method of the PlayerInventoryDisplay
scripted component of the player's GameObject to update the text totals displayed on screen. This method in PlayerInventoryDisplay
iterates through the Dictionary
, building up a string of the type names and totals, and then updates the text property of the UI Text object with the string showing the inventory totals to the player.
Learn more about using C# lists and dictionaries in Unity in the Unity Technologies tutorial at https://unity3d.com/learn/tutorials/modules/intermediate/scripting/lists-and-dictionaries.
3.15.31.22