For the final part of this collectable diamonds system, let’s set up the logic to let the game know whenever a diamond’s been collected, what it’s value is, and display the updated value accordingly 😉
Firstly, we can set up our UI elements by creating a canvas, setting it to scale with the screen size, then creating an Image and Text GameObject and anchoring them to the top left of the screen. Set the sprite of the image to a diamond in our case, and type out some placeholder text and adjust the font and size until you’re happy with it (admittedly, I still need to go back over this and find/use a font that’ll work with the game 😛).
UIManager and GameEvents
Next, let’s create two empty GameObjects for our “UIManager” and “GameEvents” respectively. Create a couple of new C# scripts with the same names and apply these to their GameObjects. We’ll be using the UIManager to handle pretty much any of the code around updating the user interface, while the GameEvents class will store and handle the events we wish to “broadcast” throughout the game.
For the GameEvents script, let’s use the singleton pattern by creating a single, static instance of the class for us to reference (‘current’), and let’s initialise that in the Awake method. Next, let’s create our own type of UnityEvent by creating a class called something like “MyIntEvent” and having it inherit from UnityEvent<int>. We can then create an instance of a MyIntEvent called soemthing like “gemsCollected”, followed by a public method which will invoke this and pass in an integer value:
As we’ve done in previous projects, we’ll be calling this public method from another class in order to essentially broadcast a value to any method that’s listening in. So back in our Diamond class, add in the line “GameEvents.current.GemsCollected(_diamondVal);” to our CollectDiamond method:
If we wanted, we could lose that direct reference to the Player and have that script also listen for the gemsCollected event, but since the Player object is so readily accessible (they’ll need to have collided with the Diamond anyway), we might as well use that.
Next, let’s work on the UIManager class. We’ll need a reference to a Text or TextMeshProUGUI component, a reference to the Player, and a singleton instance of the UIManager. We could equally do this by creating a private instance which can only be accessed through a public field’s property (a getter), which’ll make sure nothing ever tries to reassign the instance of this class.
We’ll need to subscribe to the gemsCollected int event by calling the following: GameEvents.current.gemsCollected.AddListener(LocalMethod) (where “LocalMethod” is a method within the UIManager class which accepts an integer argument). Within that local method, we’ll need to update the text in our text object, and if you’d like we can also have some logic in there to clamp the value between, say, 0 and 999. I also prefer not to actually show “0” to the player, so in that event I’m setting the text to an empty string:
As you might have noticed, we’re admittedly not really using the integer argument all that much at the moment. I’m thinking we could have the diamond’s value pop up on the screen for awhile before getting added to the diamond text, so that’s the reasoning behind having that at the ready 😉
With this all set up, head back into Unity and make sure to assign any of the GameObjects/components to their appropriate public or serialised variables. Our diamond collection system should now be in place and ready for testing! 😄