NPC’s Introduction Part 1

Today I will talk about NPCs.
What are NPCs?
The acronym NPC stands for Non-Player Character, basically an NPC is a character that the Player or User don’t have control, He can have many functions as : to be your enemy, to help you with your tasks in-game, to give a new task, give a reward, talk with you, to present a problem, etc.

For the next articles, I will talk about how to create an NPC for 2D games, and for 3D games, I will also talk about how to think for to create an NPC.

So let’s go to the start.

Firstly, to start the creation We need to think, what is our NPC’s function?
In this case, the NPC’s function is to talk with the user and give a task.
So to start We need to create our Dialog_Controller, this class is very important because She will control all dialogs, in between user and NPC. For this case, I will make this class for having a dialog with user and NPC, but in the next article, I will talk about as to expand this class, for to be used with many NPCs.

Very well, for this class We need these variables:

    public Text _Dialog_Text;
    public Text _Dialog_Name;

    public Dialog_Box _Dialog_Box_Script;
    public NPC_Task _NPC_Task_Script;

    public int _User_Speech_Counter;
    public int _NPC_Speech_Counter;

    private int _User_ID;
    private int _NPC_ID;
    private int _Speeching_ID;

    private float _Time_For_Close_Box;

    private string _Name;
    private string _User_Name;
    private string _NPC_Name;
    private string[] _User_Speechs = new string[5];
    private string[] _NPC_Speechs = new string[4];

As mentioned, all our dialog will be controlled by this class.
Now We need to set some variables in our Start method so, here is our start method:

    private void Start()
    {
        _User_ID = 1;
        _NPC_ID = 2;
        _Speeching_ID = _User_ID;
        _Time_For_Close_Box = 5;

        _NPC_Name = "NPC:";
        _User_Name = "User:";

        _User_Speechs[0] = "Hello !!!";
        _User_Speechs[1] = "How are you?";
        _User_Speechs[2] = "I am fine, thanks for to ask.";
        _User_Speechs[3] = "What do I do?";
        _User_Speechs[4] = "Okay.";

        _NPC_Speechs[0] = "Hello Friend !!!";
        _NPC_Speechs[1] = "I am fine, and you?";
        _NPC_Speechs[2] = "Can you help-me?";
        _NPC_Speechs[3] = "Please press the key F.";
    }

Now We will make our code’s functions.
Starting with Start_Dialog method, this method is public because He will be called in class User_Interaction, is with him that our dialog will start. For this We will set our variable _Name with the value contained in variable _User_Name because the first speech belongs to the user, after this We will call the Dialog method, that needs 2 parameters, an array, and an integer, in this case, I will provide as parameters our array _User_Speechs and our integer _User_Speech_Counter.

So here is our method:

    public void Start_Dialog()
    {
        _Name = _User_Name;
        Dialog(_User_Speechs, _User_Speech_Counter);
    }

Now We will create the method that will open the dialog box, show speeches, who is speaking, increase in the variable _Speech_Counter, that is our parameter, call the function that will to give back the value for the variable that control who is speaking using our parameter _Speech_Counter, and for last, He will close the dialog box after a time with method Invoke, which receives the name of a method, and a time, after this time, the method between ” ” is called, in this case, our method is Close_Dialog_Box and our time is associated in the variable _Time_For_Close_Box.

So here is our method:

    void Dialog(string[] _Speechs, int _Speech_Counter)
    {
        _Dialog_Box_Script.Open_Dialog_Box();

        if (_Speech_Counter < _Speechs.Length)
        {
            _Dialog_Name.text = _Name;
            _Dialog_Text.text = _Speechs[_Speech_Counter];
            _Speech_Counter++;
            Set_Speech_Value(_Speech_Counter);
            Invoke("Close_Dialog_Box", _Time_For_Close_Box);
        }
    }

Now We will talk about our method Set_Speech_Value, this is a very simple method, He receives a parameter sent for our Dialog method, and He sets the value in a variable corresponding to the accountant of who is talking, this is verified for _Speeching_ID.

Here is our method:

    void Set_Speech_Value(int _Speechs)
    {
        if (_Speeching_ID == _User_ID)
            _User_Speech_Counter = _Speechs;
        else
            _NPC_Speech_Counter = _Speechs;
    }

Now We will talk about our Close_Dialog_Box method, this method also is very simple, because He only closes the dialog box using a method that belongs to our class _Dialog_Box and calls the next method.

Here is our method:

    void Close_Dialog_Box()
    {
        _Dialog_Box_Script.Close_Dialog_Box();
        Prepare_Next_Dialog_Or_Finish_Interaction();
    }

Now We will talk about our method Prepare_Next_Dialog_Or_Finish_Interaction, this method is important because He will check if our interaction will continue, or will to finish. We have an IF conditional verifying if our NPC still can to speak, if this condition is true, our method Change_Infos_And_Start_New_Dialog, is called with an Invoke method, after the time of 2 seconds, otherwise our conditional IF will to call the function that will give the task for the user, present in our class _NPC_Task_Script, don’t worry, I will talk about this class in this article.

So here is our method:

    void Prepare_Next_Dialog_Or_Finish_Interaction()
    {
        if (_NPC_Speech_Counter < _NPC_Speechs.Length)
            Invoke("Change_Infos_And_Start_New_Dialog", 2);
        else
            _NPC_Task_Script.Give_The_Task_And_Enable_Scripts();
    }

Now We will talk about our last method of this class, the Change_Infos_And_Start_New_Dialog method is responsible for change our dialog, and restart the cycle, this method has two local variables, and a conditional for to change who will speak, this conditional's structure permit change our variables: _Speeching_ID, _Name, _Speechs, _Speech_Counter (these two, are local variables). And for last He calls our method Dialog using as parameter our two local variables, _Speechs, and _Speech_Counter, after this, the cycle restart.

So here is our method:

    void Change_Infos_And_Start_New_Dialog()
    {
        string[] _Speechs;
        int _Speech_Counter;

        if (_Speeching_ID == _User_ID) {
            _Speeching_ID = _NPC_ID;
            _Name = _NPC_Name;
            _Speechs = _NPC_Speechs;
            _Speech_Counter = _NPC_Speech_Counter;
        }
        else 
        {
            _Speeching_ID = _User_ID;
            _Name = _User_Name;
            _Speechs = _User_Speechs;
            _Speech_Counter = _User_Speech_Counter;
        }

        Dialog(_Speechs, _Speech_Counter);
    }

Here is our class finished:

using UnityEngine;
using UnityEngine.UI;

public class Dialog_Controller : MonoBehaviour
{

    public Text _Dialog_Text;
    public Text _Dialog_Name;

    public Dialog_Box _Dialog_Box_Script;
    public NPC_Task _NPC_Task_Script;

    public int _User_Speech_Counter;
    public int _NPC_Speech_Counter;

    private int _User_ID;
    private int _NPC_ID;
    private int _Speeching_ID;

    private float _Time_For_Close_Box;

    private string _Name;
    private string _User_Name;
    private string _NPC_Name;
    private string[] _User_Speechs = new string[5];
    private string[] _NPC_Speechs = new string[4];

    private void Start()
    {
        _User_ID = 1;
        _NPC_ID = 2;
        _Speeching_ID = _User_ID;
        _Time_For_Close_Box = 5;

        _NPC_Name = "NPC:";
        _User_Name = "User:";

        _User_Speechs[0] = "Hello !!!";
        _User_Speechs[1] = "How are you?";
        _User_Speechs[2] = "I am fine, thanks for to ask.";
        _User_Speechs[3] = "What do I do?";
        _User_Speechs[4] = "Okay.";

        _NPC_Speechs[0] = "Hello Friend !!!";
        _NPC_Speechs[1] = "I am fine, and you?";
        _NPC_Speechs[2] = "Can you help-me?";
        _NPC_Speechs[3] = "Please press the key F.";
    }

    // Called in User_Interaction class for start dialog.

    public void Start_Dialog()
    {
        _Name = _User_Name;
        Dialog(_User_Speechs, _User_Speech_Counter);
    }

    void Dialog(string[] _Speechs, int _Speech_Counter)
    {
        _Dialog_Box_Script.Open_Dialog_Box();

        if (_Speech_Counter < _Speechs.Length)
        {
            _Dialog_Name.text = _Name;
            _Dialog_Text.text = _Speechs[_Speech_Counter];
            _Speech_Counter++;
            Set_Speech_Value(_Speech_Counter);
            Invoke("Close_Dialog_Box", _Time_For_Close_Box);
        }
    }

    void Set_Speech_Value(int _Speechs)
    {
        if (_Speeching_ID == _User_ID)
            _User_Speech_Counter = _Speechs;
        else
            _NPC_Speech_Counter = _Speechs;
    }

    void Close_Dialog_Box()
    {
        _Dialog_Box_Script.Close_Dialog_Box();
        Prepare_Next_Dialog_Or_Finish_Interaction();
    }

    void Prepare_Next_Dialog_Or_Finish_Interaction()
    {
        if (_NPC_Speech_Counter < _NPC_Speechs.Length)
            Invoke("Change_Infos_And_Start_New_Dialog", 2);
        else
            _NPC_Task_Script.Give_The_Task_And_Enable_Scripts();
    }

    void Change_Infos_And_Start_New_Dialog()
    {
        string[] _Speechs;
        int _Speech_Counter;

        if (_Speeching_ID == _User_ID) {
            _Speeching_ID = _NPC_ID;
            _Name = _NPC_Name;
            _Speechs = _NPC_Speechs;
            _Speech_Counter = _NPC_Speech_Counter;
        }
        else 
        {
            _Speeching_ID = _User_ID;
            _Name = _User_Name;
            _Speechs = _User_Speechs;
            _Speech_Counter = _User_Speech_Counter;
        }

        Dialog(_Speechs, _Speech_Counter);
    }

}

Now We will show the class Dialog_Box, this class is used for Open and Close the Dialog Box with methods, Open_Dialog_Box and Close_Dialog_Box.

Here is our class:

using UnityEngine;

public class Dialog_Box : MonoBehaviour
{

    public GameObject _Dialog_Box;

    public void Open_Dialog_Box()
    {
        _Dialog_Box.SetActive(true);
    }

    public void Close_Dialog_Box()
    {
        _Dialog_Box.SetActive(false);
    }

}

Now I will talk about the class NPC_Task, this class is responsible for giving the task to the User.

To create this We will need these variables:

    public bool _Task_Has_Been_Enabled;

    public Text _Task_Text;

    public GameObject _Task_Box;

    public User_Movement _User_Movement_Script;
    public User_Interaction _User_Interaction_Script;

    private string _Task;

After this We will set some values in our variables in our start method:

    void Start()
    {
        _Task = "Press F for finish the task.";
    }

Now We will make our method Give_The_Task_And_Enable_Scripts, He is responsible for to give a task to the User, and also for enabling the User's scripts, responsible for movement action and interaction, the Boolean _Task_Has_Been_Enabled, gives the authorization for the user to finish the task pressing F, the text _Task_Text, will to receive the content of variable _Task, the Task_Box is showed, and for last the User's scripts are enabled.

So here is our method:

    public void Give_The_Task_And_Enable_Scripts()
    {
        _Task_Has_Been_Enabled = true;
        _Task_Text.text = _Task;
        _Task_Box.SetActive(true);
        Enable_Scripts();
    }

Now I will show the method Enable_Scripts, that is a simple method, responsible for enabled the User's scripts.

So here is our method:

    void Enable_Scripts()
    {
        _User_Movement_Script.enabled = true;
        _User_Interaction_Script.enabled = true;
    }

And for the last, We will create the method named Reset_Task, this method will restart the task status, and close the task box, for that be possible to execute the task when the user starts the dialog other times.

So here is our method Reset_Task:

    public void Reset_Task()
    {
        _Task_Has_Been_Enabled = false;
        _Task_Box.SetActive(false);
    }

Here is our finished class:

using UnityEngine;
using UnityEngine.UI;

public class NPC_Task : MonoBehaviour
{

    public bool _Task_Has_Been_Enabled;

    public Text _Task_Text;

    public GameObject _Task_Box;

    public User_Movement _User_Movement_Script;
    public User_Interaction _User_Interaction_Script;

    private string _Task;


    void Start()
    {
        _Task = "Press F for finish the task.";
    }

    // This method is called in class Dialog_Controller

    public void Give_The_Task_And_Enable_Scripts()
    {
        _Task_Has_Been_Enabled = true;
        _Task_Text.text = _Task;
        _Task_Box.SetActive(true);
        Enable_Scripts();
    }

    void Enable_Scripts()
    {
        _User_Movement_Script.enabled = true;
        _User_Interaction_Script.enabled = true;
    }

    // This method is called in class User_Interaction

    public void Reset_Task()
    {
        _Task_Has_Been_Enabled = false;
        _Task_Box.SetActive(false);
    }

}

Now We need to develop the systems that will complement this, User Interaction's System responsible for to call the dialog and for to make the task, Task system for the NPC responsible for to give a task for our user, movementation system for that We can move the user in the environment, Reset_Dialog System, for to reset the Dialog System, and for last the Trigger System that will give the authorization for that We can to make an interaction with our NPC.

Now I will talk about Interaction_Class.

For this, We need of these variables:

    public bool _Is_In_Interaction_Area;

    public NPC_Task _NPC_Task_Script;
    public Dialog_Controller _Dialog_Controller_Script;
    public Reset_Dialogs _Reset_Dialogs_Script;

    private User_Movement _User_Movement_Script;

Now We will set a value in our _User_Movement_Script, with our Start method:

    private void Start()
    {
        _User_Movement_Script = GetComponent<User_Movement>();
    }

So We need to make the interaction, for this let's go for our update method, that will call, our Interaction_Input method, so here is our Update:

    void Update()
    {
        Interaction_Input();
    }

Now We will talk about our Interaction_Input method, this method will to be responsible for start dialog with NPC and finish the task, for this, We will use some conditionals, firstly for to make the interaction with NPC, We need to check if our user is in the interaction area, and also We need check if the task still not is enabled, after this, We check, if the Key E, has been pressed, if all the conditions are true, We start the dialog, and We stopped the movement, case our User is movementing, disabled our Movement_Class for that don’t to be possible to movement, and for Last, We disabled this class.

So here is our conditional:

        if (_Is_In_Interaction_Area == true && _NPC_Task_Script._Task_Has_Been_Enabled == false)
        {
            if (Input.GetKeyDown(KeyCode.E))
            {
                _Dialog_Controller_Script.Start_Dialog();
                _User_Movement_Script.Stop_Movementation();
                _User_Movement_Script.enabled = false;
                this.enabled = false;
            }
        }

Now We will talk about our next interaction, that is responsible, for to accomplish the NPC's task, so We will an conditional IF for to check, if the Key F has been pressed, case this is true, the task is completed, and We will to go reset the task with the method Reset_Task present in class NPC_Task, after this with our method Reset_Dialog that is present in class Reset_Dialogs, We will to reset dialog system.

So here is our next interaction:

        if (_NPC_Task_Script._Task_Has_Been_Enabled == true)
        {
            if (Input.GetKeyDown(KeyCode.F))
            {
                _NPC_Task_Script.Reset_Task();
                _Reset_Dialogs_Script.Reset_Dialog();
            }
        }

For last here is our finished class:

using UnityEngine;

public class User_Interaction : MonoBehaviour
{

    public bool _Is_In_Interaction_Area;

    public NPC_Task _NPC_Task_Script;
    public Dialog_Controller _Dialog_Controller_Script;
    public Reset_Dialogs _Reset_Dialogs_Script;

    private User_Movement _User_Movement_Script;

    private void Start()
    {
        _User_Movement_Script = GetComponent<User_Movement>();
    }

    void Update()
    {
        Interaction_Input();
    }

    void Interaction_Input()
    {
        if (_Is_In_Interaction_Area == true && _NPC_Task_Script._Task_Has_Been_Enabled == false)
        {
            if (Input.GetKeyDown(KeyCode.E))
            {
                _Dialog_Controller_Script.Start_Dialog();
                _User_Movement_Script.Stop_Movementation();
                _User_Movement_Script.enabled = false;
                this.enabled = false;
            }
        }

        if (_NPC_Task_Script._Task_Has_Been_Enabled == true)
        {
            if (Input.GetKeyDown(KeyCode.F))
            {
                _NPC_Task_Script.Reset_Task();
                _Reset_Dialogs_Script.Reset_Dialog();
            }
        }
    }

}

Now let's go talk about Reset_Dialogs class, this is a very simple class, that will reset all values in our class Dialog_Controller, and for last, to close the Dialog Box, She has a method.

So here is our method:

    public void Reset_Dialog()
    {
        _Dialog_Controller_Script._User_Speech_Counter = 0;
        _Dialog_Controller_Script._NPC_Speech_Counter = 0;
        _Dialog_Controller_Script._Dialog_Text.text = "";
        _Dialog_Controller_Script._Dialog_Name.text = "";
        _Dialog_Box_Script.Close_Dialog_Box();
    }

Here is our class finished:

using UnityEngine;

public class Reset_Dialogs : MonoBehaviour
{

    public Dialog_Controller _Dialog_Controller_Script;
    public Dialog_Box _Dialog_Box_Script;

    // Called in User_Interaction class, after the Key F to be pressed.

    public void Reset_Dialog()
    {
        _Dialog_Controller_Script._User_Speech_Counter = 0;
        _Dialog_Controller_Script._NPC_Speech_Counter = 0;
        _Dialog_Controller_Script._Dialog_Text.text = "";
        _Dialog_Controller_Script._Dialog_Name.text = "";
        _Dialog_Box_Script.Close_Dialog_Box();
    }

}

Now We will talk about the class User_Trigger_System, this class is very simple, and she doesn't have anything complex, It is only verification for knowing the user is in the interaction area.

For this We will need this variable:

    private User_Interaction _User_Interaction_Script;

In our method start, We will to set this value:

    private void Start()
    {
        _User_Interaction_Script = GetComponent<User_Interaction>();
    }

And in our trigger methods, We will change the status of variable, _Is_In_Interaction_Area by class User_Interaction.
OnTriggerEnter tells us if our user entered in the area of our NPC, He does this according to the defined Tag, case our user be in NPC area, the variable Is_In_Interaction_Area, receive true.

So here is our method:

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("NPC"))
            _User_Interaction_Script._Is_In_Interaction_Area = true;
    }

Now We will talk about method OnTriggerExit, this method informs us if our user, has left the area of our NPC, He does this according to the defined Tag, if our user is outside the area of the NPC, the variable _Is_In_Interaction_Area, to receive false.

So here is our method:

    private void OnTriggerExit2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("NPC"))
            _User_Interaction_Script._Is_In_Interaction_Area = false;
    }

Here is our class completed:

using UnityEngine;

public class User_Trigger_System : MonoBehaviour
{

    private User_Interaction _User_Interaction_Script;

    private void Start()
    {
        _User_Interaction_Script = GetComponent<User_Interaction>();
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("NPC"))
            _User_Interaction_Script._Is_In_Interaction_Area = true;
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        if (collision.gameObject.CompareTag("NPC"))
            _User_Interaction_Script._Is_In_Interaction_Area = false;
    }

}

So to finish the code creation We will talk about our last class, that is, User_Movement, our User_Movement class is responsible for making the Movement’s Input.

For to start We will need these variables:

    private float _Speed;
    private Rigidbody2D _Rdb;

That will to receive your value in method start:

    void Start()
    {
        _Speed = 5;
        _Rdb = GetComponent<Rigidbody2D>();
    }

In the update method, We will call the Movement_Input, which will be responsible for detecting user input on the keyboard.

So here is our update method:

    void Update()
    {
        Movement_Input();
    }

Now We will talk about our Movement_Input, this method is used for to create User Movementation. We will need two conditionals if for check if the keys are being pressed, and two conditions for check if the keys are were loose.

So here is our method:

    void Movement_Input()
    {
        if (Input.GetKey(KeyCode.A))
            _Rdb.velocity = -transform.right * _Speed;

        if (Input.GetKey(KeyCode.D))
            _Rdb.velocity = transform.right * _Speed;

        if (Input.GetKeyUp(KeyCode.A))
            Stop_Movementation();

        if (Input.GetKeyUp(KeyCode.D))
            Stop_Movementation();
    }

-transform.right is the equivalent of the left side (I used –transform.right because Unity don’t have transform.left)
For last in our Stop_Movementation, We will stop the user character.

Here is our method:

    public void Stop_Movementation()
    {
        _Rdb.velocity = Vector2.zero;
    }

Now, Let’s go to implement this.

This is all our objects in the hierarchy:

So with this overview, is possible to see, where will the objects come from that will fill some of our variables.

Firstly, We will to start with User.

In our user, We need of these components:

  • Rigidbody2D (I recommend that you enable freeze rotation in Z Axis).
  • Box Collider 2D.
  • User_Movement (Script).
  • User_Interaction (Script).
  • Use_Trigger_System (Script).

Now We only need set the variables : NPC_Task_Script, Dialog_Controller_Script, Dialog_Box.

  • NPC_Task_Script - Receive the class NPC_Task that is seted in a GameObject named NPC.
  • Dialog_Controller_Script - Receive the class Dialog_Controller, that is seted in a GameObject named Dialog_System_Controller.
  • Dialog_Box - Receive the object named Dialog_Box.

Now We will to implement our NPC.

For our NPC, We need of these components:

  • Rigidbody2D (I recommend that you enable freeze rotation in Z Axis, and also enable Freeze Position X, and Y in this case).
  • Box Collider 2D (With Is Trigger Enabled).
  • NPC_Task (Script).

After this We only need to set the variables:

  • Task_Text - Receive a Text object named Task_Text.
  • Task_Box - Receive a GameObject named Task_Box.
  • User_Movement_Script - Receive the class User_Movement, that is seted in a GameObject named User.
  • User_Interaction_Script - Receive the class User_Interaction, that is seted in a GameObject named User.

Here We have a important task for to make, that is add a tag in our NPC, for ensure that our code will work, for this We need to click in Dropdown next to the TAG text, after this, Add tag, so this screen will be appears.

In my case I already defined the tag, but you need to click in Plus Icon, and after, write your tag, equal is in code, after this you need to click save.

Now We will to insert the last system, that is the Dyalog System, for this, We will to create a new GameObject, clicking in GameObject in top menu, after We will click on Create Empty, So We will to click in GameObject for to define a new name that is Dialog_System_Controller, after this, We only need to add our scripts:

  • Dialog_Box.
  • Dialog_Controller.
  • Reset_Dialogs.

After this We only need to set the variables:

In Dialog_Box:

  • Dialog_Box - Receive a GameObject object named Dialog_Box.

In Dialog_Controller:

  • Dialog_Text - Receive a Text object named Dialog_Text.
  • Dialog_Name - Receive a Text object named Dialog_Name.
  • Dialog_Box - Receive the class Dialog_Box, that is seted in a GameObject named Dialog_System_Controller.
  • NPC_Task_Script - Receive the class NPC_Task, that is seated in a GameObject named NPC.

In Reset Dialogs:

  • Dialog_Controller_Script - Receive the class _Dialog_Controller, that is seted in a GameObject named Dialog_System_Controller.
  • Dialog_Box_Script - Receive the class Dialog_Box, that is seted in a GameObject named Dialog_System_Controller.

So for this article is this.

I talked about NPCs, and I made a simple example of NPC.

This project is in my github https://github.com/MauroJrDeveloper/NPCs_Introduction_1

Follow-me in Instagram for stay knowing when I create new posts @mauro_developer

You can also leave your feedback, and your suggestion, I will read all, and I will answer for you.

Thank you for reading.