Here, we are going to create another kind of customization, different from the previous recipes. In this case, we have an input field that we want to perform checks on, thus not allowing the player (instead of allowing, as in the previous recipes) to do something. Unity already has some of these controls in the Input Field (Script) component, but in this recipe, you will learn how you can create your personal filters. In this example, we will develop a simple filter in order for you to understand the concept of how filters work. For instance, we want the player to insert an identifier, maybe for the score database, and we don't want his name to start with a number — because in many programming languages, identifiers cannot start with a number. We can perform this check at runtime by developing a script.
This filter is a basic filter, since it is static and it doesn't check the input in a dynamic way. "Dynamic" in this context means having some parametric constrains in the middle that depend on the sentence itself (for example, every number has to be followed by the letter "a"). In this case, we need to use loops and for
cycles to perform the check, but how this interacts with our UI is the same for the basic filter. Therefore, you can learn here how to implement personal text validation at runtime inside your UI. However, in the There's more... section of this recipe, you will see that it is possible to find a way to implement the preceding example of dynamic filtering.
Furthermore, the same section describes how we can modify the script to give feedback to the player. This is very important since we need to communicate what the constraints are to the player, if we don't want to frustrate him.
using UnityEngine.UI;
statement at the beginning of the script, since we are going to use the InputField
class. Before the beginning of the class, we can add this line: [RequireComponent(typeof(InputField))]
(without the semicolon at the end). Thus, the script requires an InputField component that is attached to the same game object of it.private
variables: one to keep track of the Input Field (Script) component attached to myInputField, and the other to store the old text of the input field, since it could be needed to reverse the player's changes if he violates our validation format. So let's write these lines:private InputField inputField; private string oldText;
Start()
function, we are going to store the initial values for our private
variables. First is a reference in inputField
, by calling GetComponent<InputField> ()
function, which takes the Input Field (Script) component attached to the same game object in which this script is placed. Then comes oldText
, with the starting text of our input field. So, we have this code:inputField = GetComponent<InputField> (); oldText = inputField.text;
public void Check (string newText) { }
Check()
function; now we have to fill in it. So, let's add the first control through an if
statement. We check whether newText
is an empty string, and if so, we just assign this new value to oldText
and return, since there is nothing to check:if(newText == ""){ oldText = newText; return; }
if
statement is the one that really performs our check: no numbers at the beginning of our string. So, as a condition, we verify that the first character is not a number using a chain of OR operators. We retrieve the first character of newText
by accessing it as an array, and we are sure that here it contains at least one character; this is because in the previous check, we would have returned if the string was empty. So, we can write the following:if(newText[0] == '1'|| newText[0] == '2'|| newText[0] == '3'|| newText[0] == '4'|| newText[0] == '5'|| newText[0] == '6'|| newText[0] == '7'|| newText[0] == '8'|| newText[0] == '9'|| newText[0] == '0'){
oldText
inside the text of inputField
, since this newText
didn't pass our checks. Otherwise, if the condition is not verified, it means that our string has passed the checks. We have to update oldText
with newText
in an else
statement, so let's continue the code of the previous step with this:inputField.text = oldText; }else{ oldText = newText; }
Unity
. The next step is to pass the string
that the player is writing to our script, so we need an event that sends it every time the text inside the input field is changed. If we select and then look inside the Input Field (Script) component, we can notice that there are two events. Let's click on the small + sign on the On Value Change (String) event tab in the bottom-right corner.We started by creating a script in which there is a function that takes the parameter as a string and it checks whether the string starts with a number. If so, it restores the string that was there before to insert the number at the beginning. Otherwise, it doesn't affect the input field. Then, we had to create an event that, every time the string inside the input field changes, it triggers our function by passing to it the string
that the player is typing.
The following sections help us to improve the text filtering and to understand how the dynamic filtering works so that we can implement our own ones.
Sometimes, the design of the game requires that the string checking should happen after the player has finished typing it. In such cases, we don't have to perform the check every time that the string changes, but only when the player completes edit that input field. The easiest way to do this is by changing the event in order to trigger our function, only at the end. We need to change what we did in step 11 Instead of adding an event to the On Value Change (String) tab, we have to create a new one on the End Edit (String) event tab by clicking on the + sign in the bottom-right corner. So finally, we should have something that looks like this:
Our function is called only when the player finishes editing the input field. However, keep in mind that in this way, if the string typed is invalid, the last valid string will be restored — the one that was present before, at the beginning of the last edit session. Giving feedback to the player on why the string he is writing is not acceptable for this input field is important.
It may be confusing for the player when he cannot insert some characters at certain points, for example, inserting numbers at the beginning. Thus, in some way, we should give feedback to the player to make him understand why he cannot use some strings or to indicate what has gone wrong.
To do this, we have to use another Text (Script) component and handle it inside our script. Thus, let's change our script.
First, we need three public
variables. The first one is for storing the reference to the Text (Script) component, and the other two are for customizing it. The second is for the error string to place on it, and the third is for changing its color. We can write the following lines:
public Text feedbackText; public string errorString; public Color newColor;
However, we also need two private variables to store the original values of feedbackText
, like this:
private string originalFeedbackText; private Color originalFeedbackColor;
These variables need to be assigned in the Start()
function by adding the following two lines at the bottom of the function:
originalFeedbackText = feedbackText.text; originalFeedbackColor = feedbackText.color;
Now, we should go through the Check()
function inside the then
branch, which is inside the if
statement. Then we can assign the new parameters, the text and the color, to feedbackText
in this way:
feedbackText.text = errorString; feedbackText.color = newColor;
Next, restore the originals in the else
branch by adding these lines:
feedbackText.text = originalFeedbackText; feedbackText.color = originalFeedbackColor;
After saving the script, we are able to assign a Text (Script) to the Feedback Text component, along with the text (which can be The string cannot start with a number) and a color (which can be red).
We can create another UI text to assign to Feedback Text. In this case, we may create an interesting variation, since this checking is at the beginning of our script. We can assign to it Placeholder, which is one of the children of myInputField. It is the text that there is inside the input field when it is empty.
So, if the player tries to insert a number at the beginning, we should get something like this:
In this section, we will present some basic notions on how a dynamic filter can be executed using for
cycles. We will see that the concept is the same as that which we've used so far. In the introduction, we made the following example: every number has to be followed by the letter "a." In this case, what we need is looping over the string, and every time we find a number, it must be followed by the letter "a." Otherwise, the filter will restore the old string that the player was writing.
The first part of the check()
function is the same:
if(newText == ""){ oldText = newText; return; }
In fact, we always want to check whether the new string is empty. If it is, we return so that we don't waste time in performing a check on an empty string.
Now we will create a bool
variable to determine whether we have a number, from one cycle to the next. To do this, we need to write the following:
bool mustFollowA = false;
Finally, the for
cycle will go through all the characters of the string
. If we find a number, we set our mustFollowA
variable to true
. By doing this, we know that before the next cycle, there was a number. Of course, if we find another number, we can still keep iterating, since the new digit is part of the same number. For example, suppose we have a string bc12a
. When the cycle reaches the number 2
, it knows that before 2
there was a number, 1
in this case. However, the letter a
must follow any number, and 12
is a number. Then, if we find an a
, in lowercase or uppercase, we don't need to be concerned with what was there before. So, we can just deactivate the constraint by setting the mustFollowA
variable to false
. Otherwise, if the character is neither a number nor a
, we check whether the mustFollowA
variable is true
. If so, it means that our test has failed. Hence, we restore the old string and return. Then, if the for
cycle terminates, the test doesn't fail. Thus, we can assign the new string to our oldText
variable:
for(int i=0; i < newText.Length; i++){ if(newText[i] == '1'|| newText[i] == '2'|| newText[i] == '3'|| newText[i] == '4'|| newText[i] == '5'|| newText[i] == '6'|| newText[i] == '7'|| newText[i] == '8'|| newText[i] == '9'|| newText[i] == '0'){ mustFollowA = true; continue; }else if(newText[i] == 'a'|| newText[i] == 'A'){ mustFollowA = false; continue; } if(mustFollowA = true){ //FAIL: There is a number followed by another letter inputField.text = oldText; return; } } oldText = newText;
3.133.133.233