Often the simplest inventory situation is to display text to tell players if they are carrying a single item (or not).
This recipe assumes that you are starting with the project Simple2Dgame_SpaceGirl
setup from the first recipe in this chapter. So, either make a copy of that project or do the following:
Simple2Dgame_SpaceGirl
package.Scenes
folder).For this recipe, we have prepared the font you need in a folder named Fonts
in the 1362_02_02
folder.
To display text to inform the user about the status of carrying a single object pickup, follow these steps:
Simple2Dgame_SpaceGirl
.Text-carrying-star
. Change its text to Carrying star: false
.Fonts
folder into your project.Text-carrying-star
to Xolonium-Bold (folder Fonts
), and set its color to yellow. Center the text horizontally and vertically, and set its Height to 50
, and set the Font Size to 32
, as shown in the following screenshot:50
, as shown in the next screenshot:Player
to GameObject player-SpaceGirl
in the Hierarchy:using UnityEngine; using System.Collections; using UnityEngine.UI; public class Player : MonoBehaviour { public Text starText; private bool carryingStar = false; void Start(){ UpdateStarText(); } void OnTriggerEnter2D(Collider2D hit){ if(hit.CompareTag("Star")){ carryingStar = true; UpdateStarText(); Destroy(hit.gameObject); } } private void UpdateStarText(){ string starMessage = "no star :-("; if(carryingStar) starMessage = "Carrying star :-)"; starText.text = starMessage; } }
player-SpaceGirl
. Then, from the Inspector, access the Player (Script) component and populate the Star Text public field with UI Text object Text-carrying-star
, as shown in the following screenshot:The Text
variable starText
is a reference to the UI Text object Text-carrying-star
. The bool
variable carryingStar
represents whether or not the player is carrying the star at any point in time; it is initialized to false.
The UpdateStarText()
method copies the contents of the starMessage
string to the text property of starText
. The default value of this string tells the user that the player is not carrying the star, but an if
statement tests the value of carryingKey
, and, if that is true, then the message is changed to inform the player that they are carrying the star.
Each time the player's character collides with any object that has its Is Trigger set to true
, an OnTriggerEnter2D()
event message is sent to both objects involved in the collision. The OnTriggerEnter2D()
message is passed a parameter that is the Collider2D
component inside the object just collided with.
Our player's OnTriggerEnter2D()
method tests the tag
string of the object collided with to see if it has the value Star. Since the GameObject star we created has its trigger set, and has the tag Star, the if
statement inside this method will detect a collision with star and complete three actions: it sets the Boolean variable carryingStar
to true
, it calls the method UpdateStarText()
, and it destroys the GameObject it has just collided with (in this case, star).
NOTE: Boolean variables are often referred to as flags.
The use of a bool (true/false) variable to represent whether some feature of the game state is true or false is very common. Programmers often refer to these variables as flags. So, programmers might refer to the carryingStar
variable as the star-carrying flag.
When the scene begins, via the Start()
method, we call the UpdateStarText()
method; this ensures that we are not relying on text typed into the UI Text object Text-carrying-star
at design time, but that the UI seen by the user is always set by our run-time methods. This avoids problems where the words to be displayed to the user are changed in code and not in the Inspector panel—which leads to a mismatch between the onscreen text when the scene first runs and after it has been updated from a script.
A golden rule in Unity game design is to avoid duplicating content in more than one place, and, therefore, we avoid having to maintain two or more copies of the same content. Each duplicate is an opportunity for maintenance issues when some, but not all, copies of a value are changed.
Maximizing use of prefabs is another example of this principle in action. This is also know as the DRY principal - Do Not Repeat Yourself.
Some details you don't want to miss:
A game design pattern (best practice approach) called the Model-View-Controller pattern (MVC) is to separate the code that updates the UI from the code that changes player and game variables such as score and inventory item lists. Although this recipe has only one variable and one method to update the UI, well structured game architectures scale up to cope with more complex games, so it is often worth the effort of a little more code and an extra script class, even at this game-beginning stage, if we want our final game architecture to be well structured and maintainable.
To implement the separation of view pattern for this recipe, we need to do the following:
PlayerInventoryDisplay
to GameObject player-SpaceGirl
in the Hierarchy:using UnityEngine; using System.Collections; using UnityEngine.UI; public class PlayerInventoryDisplay : MonoBehaviour { public Text starText; public void OnChangeCarryingStar(bool carryingStar){ string starMessage = "no star :-("; if(carryingStar) starMessage = "Carrying star :-)"; starText.text = starMessage; } }
player-SpaceGirl
. Then, from the Inspector, access the PlayerInventoryDisplay
(Script) component and populate the Score Text public field with the UI Text object Text-carrying-star
.Player
and replace it with this C# Script PlayerInventory
containing the following (simplified) code:using UnityEngine; using System.Collections; public class PlayerInventory : MonoBehaviour { private PlayerInventoryDisplay playerInventoryDisplay; private bool carryingStar = false; void Start(){ playerInventoryDisplay = GetComponent<PlayerInventoryDisplay>(); playerInventoryDisplay.OnChangeCarryingStar(carryingStar); } void OnTriggerEnter2D(Collider2D hit){ if(hit.CompareTag("Star")){ carryingStar = true; playerInventoryDisplay.OnChangeCarryingStar(carryingStar); Destroy(hit.gameObject); } } }
As can be seen, the
PlayerInventory
script class no longer has to maintain a link to the UI Text or worry about changing the text property of that UI component—all that work is now the responsibility of the PlayerInventoryDisplay
script. When the Player instance component detects a collision with the star, after changing the carryingStar
bool flag's value to true
, it just calls the OnChangeCarryingStar()
method of the PlayerInventoryDisplay
component.
The result is that the code for the script class PlayerInventory
concentrates on the player collision and status variables, while the code for the script class PlayerInventoryDisplay
handles the communication to the user. Another advantage of this design pattern is that the method in which the information is communicated to the user via the UI can be changed (for example, from text to an icon), without any change to the code in script class Player
.
3.21.43.26