How to Create a Custom Input Manager in Unity C#

kristielAll Topics, Coding & Programming, Tutorial, Unity Game Development

How to Create a Custom Input Manager in Unity C#

Share this Post

Recently, I created a custom input manager for a game I’m making in Unity 3D. Initial research suggested I use Unity’s built-in Input Manager. However, Unity doesn’t have an API to access most of the Input Manager functionality. However, I wanted a menu in my game where the user could set their own key bindings; a common feature in most PC games. Unity’s Input Manager can only be accessed when you first start a game. I found this to be limiting. I want my players to be able to change their bindings whenever they want, during the game. So I decided to create my own input manager. Not much information was available to help me to accomplish this. After a lot of research and piecing things together, I was able to create a slightly rough, but functional, input manager for my game.

So I am sharing what I learned. This blog details how to create a custom input manager. Likewise, the video below provides an in-depth tutorial I made for the project. NOTE: Video assumes a moderate level of Unity experience. If you need to brush up on Unity basics, view here.


Lastly, if you want to check the project out, you can download it from here.

STEP 1 to Create Custom Input Manager: Make a Game Manager

Here is where we begin creating the custom input manager. First, create a Game Manager that will hold keycodes for our character movement. This Manager will load the user’s bindings from PlayerPrefs whenever the game starts.

  • Create an Empty Game Object in your scene. Name it _GM
  • Add a new C# script to the Game Object named GameManager
  • Open GameManager.cs in your IDE (Visual Studio, MonoDevelop, etc.) and copy the below code into your script:
using UnityEngine;
using System.Collections;
 
public class GameManager : MonoBehaviour {
 
    //Used for singleton
    public static GameManager GM;
 
    //Create Keycodes that will be associated with each of our commands.
    //These can be accessed by any other script in our game
    public KeyCode jump {get; set;}
    public KeyCode forward {get; set;}
    public KeyCode backward {get; set;}
    public KeyCode left {get; set;}
    public KeyCode right {get; set;}
 
 
 
    void Awake()
    {
        //Singleton pattern
        if(GM == null)
        {
            DontDestroyOnLoad(gameObject);
            GM = this;
        }
        else if(GM != this)
        {
            Destroy(gameObject);
        }
        /*Assign each keycode when the game starts.
         * Loads data from PlayerPrefs so if a user quits the game,
         * their bindings are loaded next time. Default values
         * are assigned to each Keycode via the second parameter
         * of the GetString() function
         */
        jump = (KeyCode) System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("jumpKey", "Space"));
        forward = (KeyCode) System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("forwardKey", "W"));
        backward = (KeyCode) System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("backwardKey", "S"));
        left = (KeyCode) System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("leftKey", "A"));
        right = (KeyCode) System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("rightKey", "D"));
 
    }
 
    void Start ()
    {
 
    }
 
    void Update ()
    {
 
    }
}

STEP 2 to Create Custom Input Manager: Make the Controller

That’s all we need for the Game Manager. Now, we need to create our character controller that we can move around using our custom Keycodes from the Game Manager.

  • Create a Plane 3D Object in the scene. This will serve as our ground.
  • Create a Cube 3D object and place it on top of the plane.
  • Add a C# Script to the Cube called “Controller”. Open the script in your IDE and copy the below code:

using UnityEngine;

using System.Collections;

 

public class Controller : MonoBehaviour {

 

    void Start ()

    {

 

    }

 

    void Update ()

    {

        /* Basic input logic. GetKey is grabbing

         * the keycodes we created in our Game Manager

         */

        if(Input.GetKey(GameManager.GM.forward))

            transform.position += Vector3.forward / 2;

        if( Input.GetKey(GameManager.GM.backward))

            transform.position += -Vector3.forward / 2;

        if( Input.GetKey(GameManager.GM.left))

            transform.position += Vector3.left / 2;

        if( Input.GetKey(GameManager.GM.right))

            transform.position += Vector3.right / 2;

        if( Input.GetKeyDown(GameManager.GM.jump))

            transform.position += Vector3.up / 2;

    }

}

If you play your game, your character should be able to move and jump using WASD and SPACE.

STEP 3 to Create Custom Input Manager: Make a UI

Now we need to create some kind of menu system that will have a series of buttons on it, which will allow us to set key bindings.

  • Go to Game Object → UI → Canvas
  • Set Canvas to Screen Space – Camera and set the render camera to Main Camera
    Unity C 1
  • Right-click the Canvas in the hierarchy and choose UI → Scale the panel however you like.
  • Right-click the Panel and choose UI → Copy the button and paste it until you have a total of 5 buttons on the panel. Move the buttons so they are all visible.
  • Rename each button. You should end up with buttons named: ForwardKey, BackwardKey, LeftKey, RightKey, and JumpKey.
    Unity C 2
  • Right-click the Panel and choose UI → Copy the text and paste it so you have a total of 5 Text objects in the Panel. Move each text so each one sits next to a button. Here’s how mine looks
    Unity C 3
  • Click on the Canvas in the hierarchy and add a new C# script named MenuScript. Copy the below code and paste it into MenuScript:

using UnityEngine;

using System.Collections;

using UnityEngine.UI;

 

public class MenuScript : MonoBehaviour {

 

    Transform menuPanel;

    Event keyEvent;

    Text buttonText;

    KeyCode newKey;

 

    bool waitingForKey;

 

 

    void Start ()

    {

        //Assign menuPanel to the Panel object in our Canvas

        //Make sure it's not active when the game starts

        menuPanel = transform.FindChild("Panel");

        menuPanel.gameObject.SetActive(false);

        waitingForKey = false;

 

        /*iterate through each child of the panel and check

         * the names of each one. Each if statement will

         * set each button's text component to display

         * the name of the key that is associated

         * with each command. Example: the ForwardKey

         * button will display "W" in the middle of it

         */

        for(int i = 0; i < menuPanel.childCount; i++)

        {

            if(menuPanel.GetChild(i).name == "ForwardKey")

                menuPanel.GetChild(i).GetComponentInChildren<Text>().text = GameManager.GM.forward.ToString();

            else if(menuPanel.GetChild(i).name == "BackwardKey")

                menuPanel.GetChild(i).GetComponentInChildren<Text>().text = GameManager.GM.backward.ToString();

            else if(menuPanel.GetChild(i).name == "LeftKey")

                menuPanel.GetChild(i).GetComponentInChildren<Text>().text = GameManager.GM.left.ToString();

            else if(menuPanel.GetChild(i).name == "RightKey")

                menuPanel.GetChild(i).GetComponentInChildren<Text>().text = GameManager.GM.right.ToString();

            else if(menuPanel.GetChild(i).name == "JumpKey")

                menuPanel.GetChild(i).GetComponentInChildren<Text>().text = GameManager.GM.jump.ToString();

        }

    }

 

 

    void Update ()

    {

        //Escape key will open or close the panel

        if(Input.GetKeyDown(KeyCode.Escape) && !menuPanel.gameObject.activeSelf)

            menuPanel.gameObject.SetActive(true);

        else if(Input.GetKeyDown(KeyCode.Escape) && menuPanel.gameObject.activeSelf)

            menuPanel.gameObject.SetActive(false);

    }

 

    void OnGUI()

    {

        /*keyEvent dictates what key our user presses

         * bt using Event.current to detect the current

         * event

         */

        keyEvent = Event.current;

 

        //Executes if a button gets pressed and

        //the user presses a key

        if(keyEvent.isKey && waitingForKey)

        {

            newKey = keyEvent.keyCode; //Assigns newKey to the key user presses

            waitingForKey = false;

        }

    }

 

    /*Buttons cannot call on Coroutines via OnClick().

     * Instead, we have it call StartAssignment, which will

     * call a coroutine in this script instead, only if we

     * are not already waiting for a key to be pressed.

     */

    public void StartAssignment(string keyName)

    {

        if(!waitingForKey)

            StartCoroutine(AssignKey(keyName));

    }

 

    //Assigns buttonText to the text component of

    //the button that was pressed

    public void SendText(Text text)

    {

        buttonText = text;

    }

 

    //Used for controlling the flow of our below Coroutine

    IEnumerator WaitForKey()

    {

        while(!keyEvent.isKey)

            yield return null;

    }

 

    /*AssignKey takes a keyName as a parameter. The

     * keyName is checked in a switch statement. Each

     * case assigns the command that keyName represents

     * to the new key that the user presses, which is grabbed

     * in the OnGUI() function, above.

     */

    public IEnumerator AssignKey(string keyName)

    {

        waitingForKey = true;

 

        yield return WaitForKey(); //Executes endlessly until user presses a key

 

        switch(keyName)

        {

        case "forward":

            GameManager.GM.forward = newKey; //Set forward to new keycode

            buttonText.text = GameManager.GM.forward.ToString(); //Set button text to new key

            PlayerPrefs.SetString("forwardKey", GameManager.GM.forward.ToString()); //save new key to PlayerPrefs

            break;

        case "backward":

            GameManager.GM.backward = newKey; //set backward to new keycode

            buttonText.text = GameManager.GM.backward.ToString(); //set button text to new key

            PlayerPrefs.SetString("backwardKey", GameManager.GM.backward.ToString()); //save new key to PlayerPrefs

            break;

        case "left":

            GameManager.GM.left = newKey; //set left to new keycode

            buttonText.text = GameManager.GM.left.ToString(); //set button text to new key

            PlayerPrefs.SetString("leftKey", GameManager.GM.left.ToString()); //save new key to playerprefs

            break;

        case "right":

            GameManager.GM.right = newKey; //set right to new keycode

            buttonText.text = GameManager.GM.right.ToString(); //set button text to new key

            PlayerPrefs.SetString("rightKey", GameManager.GM.right.ToString()); //save new key to playerprefs

            break;

        case "jump":

            GameManager.GM.jump = newKey; //set jump to new keycode

            buttonText.text = GameManager.GM.jump.ToString(); //set button text to new key

            PlayerPrefs.SetString("jumpKey", GameManager.GM.jump.ToString()); //save new key to playerprefs

            break;

        }

 

        yield return null;

    }

}

 

STEP 4 to Create Custom Input Manager: Set up the Buttons

At this point, we need to make sure our buttons are doing something when we click them.

  • Left-click on ForwardKey button in hierarchy. In the inspector, click the + icon under the OnClick() section two times.
  • Drag the Canvas object from the hierarchy and into the object field for each behavior.
  • Drag the ForwardKey child Text object to the Text object in the OnClick() function.
  • Type “forward” in the string field for the second OnClick() behavior in the list.
    Unity C 4
  • Repeat this for the next 4 buttons. Be sure that each Text component is the child Text component from the button you are modifying. Likewise, each string for the second behavior should reflect a case from the MenuScript script. Example: forward, backward, left, right, jump. Ideally, the BackwardKey button should send backward in the StartAssignment call. LeftKey should send left, RightKey should send right, etc.

Once that’s all done, you should be able to play the game. Press Escape to open the panel. Left click on any of the buttons and then press a key to change the assigned Keycode. You should see the text on the button change to the new key and your new key should control the aspect of the movement that you changed. Example: If you change jump to Q, you should now be able to jump using the Q key.

Conclusion

In conclusion, I realize this may not be the ideal way to create a custom input manager. The functionality works fine if you have few commands. However, if you have a game with, say, 30 commands, it would be incredibly tedious and hard to keep track of all the code, buttons, and parameters you would be sending. In general, this tutorial covers the basics of setting up your own keys for your custom input manager. I figured that anybody reading this would likely be good enough with code to be able to figure out a more dynamic alternative using Arrays or some other variable that can be more readily automated. Hopefully this provides you with the basic groundwork to make your custom input manager more complex to fit the necessities of your game.

If you come up with a more efficient way of doing things, feel free to contact us and let us know. Be sure to check out our other blog articles. Looking to take your game development to the next level? Consider the Unity 5 Pro Student and Teacher Suite. Learn more about this offer and its benefits.

Blogger: Mark Philipp, Application Engineer at Studica

Share this Post