So I have a 2D platform game where a player goes around collecting fruit but currently I only have one icon. Currently I use an image on a canvas to display the fruit image. How can I make the UI image change based on what fruit the player collects?
1 Answer
First, let's make a simple data container to put on our fruit items. For now, this will contain just the image we want to display when we collect it.
public class Collectable : MonoBehaviour { public Sprite sprite; public void Collect() { // Here you can spawn a collection effect or play a sound, etc. Destroy(gameObject); } } You could expand this to contain an enum of the different fruit types so you can react differently to them, or maybe make a ScriptableObject to hold the fruit's properties and gameplay effects, and hold a reference to that (ie. the Type Object pattern).
Next we'll make a script that detects when we've collided with a collectable. Put this on your player character.
public class Collector : MonoBehaviour { // Here I assume you're using Unity 2020 or higher. public UnityEvent<Sprite> onCollect; // On older versions, declare public class CollectionEvent : UnityEvent<Sprite>{} // then make this a public CollectionEvent onCollect; void OnTriggerEnter2D(Collider2D collider) { // Ignore any trigger collisions that aren't collectables. if (!collider.TryGetComponent(out Collectable item)) return; // If anyone is listening to our collection event, // tell them what we collected. if (onCollect != null) { onCollect.Invoke(item.sprite); } // Collect the item so it disappears. item.Collect(); } } Lastly, we can have an inventory script that tracks what collectable(s) you're carrying and updates the UI accordingly.
public class PlayerInventory : MonoBehaviour { public Image itemSlot; public void AddItemToInventory(Sprite sprite) { itemSlot.sprite = sprite; // Do other things you need to do with the collectable, // like applying gameplay effects or updating a counter. } } This can sit in your HUD. In the Collector script's Inspector, set the onCollect event to call the PlayerInventory script's AddItemToInventory() method. Or you can wire up this link after (re)spawning the player character with collector.onCollect.AddListener().
If different items have different properties, then you might want to send the Collectable itself through this event instead of a Sprite, or a CollectableType data structure that has the properties you need.
scoreIcon.GetComponent<SpriteRenderer>().sprite = fruit.sprite, for example. Ofc you can also just store a reference to said sprite renderer, so you don't have the GetComponent<...>() every time. (dont store the whole thing if you only need one component) \$\endgroup\$