I’d like to share something I worked on last week. I’m thinking every couple weeks I’ll share stuff I learned through trial-and-error (and lots of research!) and hopefully help another newcomer out there save some time.
Since I learn by trial-and-error I don’t learn things the “best way”, I just learn a way that works in my situation, then I make improvements over time. Criticism/tips are fully welcomed and encouraged, I’m trying to improve as much as I can.
One of the things I learned this week in Unity C# was coding my own custom keybind UI menu without using Unity’s built-in input scripts. My menu lets the user rebind control keys with one mouseclick followed by a single keypress. It hasn’t been rigorously tested but it gets the job done right now.
Here’s how it works:
Clicking on the button next to “Player 1 Move Right” then pressing F1 will immediately set F1 as the move right key.
Now my player can instantly move right with F1, and the UI text is updated at the same time to show my new bound key! This works for any of these 4 buttons and I can bind almost any key I want (Including controller buttons).
I can rebind any keys I want, quick and easy!
So how is this all coded?
There are 11 classes involved in my menu, but 8 of those are just for the buttons & the text. Also I try to keep my classes small (below 100 lines each), so it’s not as hard as it might sound. Here are the classes used in my example:
- The ControlKeybinds class contains the dictionary storing the control Keycode values.
- The “Player1Controls” & “Player2Controls” both contain the inputs for the players. Their controls are stored as KeyCode variables, like GetKeyDown ( variable ). There is a method “RefreshKeybinds” which sets all KeyCode variables equal to the dictionary’s values (picture of this later)
- As for UI, there are 4 classes (one for each bindable action). These are named UIConfigBindPlayer1MoveLeft, UIConfigBindPlayer2MoveLeft etc.
- There are also 4 classes used for the 4 text objects displaying which key is currently bound. I called these UIConfigCurrentlyBoundKeyP1MoveLeft etc. Long names, but at least I’ll always know exactly what these classes are for.
I’ll explain how I made the “player 1 move right” button, and that will be enough info for you to make as many buttons as you want (if I succeed in explaining it well!)
First, I store all of my game’s player controls in a dictionary which is located inside a class I call “ControlKeybinds“. For some reason I couldn’t get a dictionary to be recognized by the compiler, but I fixed it by adding the using statement System.Collections.Generic.
Player 1 has a couple extra controls I’m in the middle of implementing, those aren’t important.
Next, in Player1Controls I store a variable for each keycode I’ll be using. Seen here I have my KeyCode variables for left and right movement.
I then have a method I call “RefreshKeybinds”, which I call in Start(). All this does is fill those movement variables with dictionary values of the correct key. This method gets called as soon as we bind a new key. This is what actually “binds” the new dictionary value to our player.
The bool “refreshKeybindRequest” is what initiates the method. This is controlled by a simple if statement in my update function:
Now for the script the button uses. It begins with an array holding every possible keycode we could want.
This next part is where the dictionary gets written with a new value. When we click a rebind button, the following method is called.
This method removes our dictionary value and turns on 2 bools. The UI bool stops the UIText from trying to display an empty dictionary key (the UI will throw errors like crazy if not in place). The second bool prevents us from binding more than one key in the same instance.
The update method is where the bind overwrite happens. As we press a key, a for loop iterates through the array to check if any values are equal to the key we pressed. If it finds one, it replaces the correct dictionary value with the new key. At the end of the method the Player’s keybinds are refreshed with the new values in the dictionary. Awesome!
I should written this as a separate method that gets called in update for cleaner looking code.
Buttons can only reference methods through objects holding scripts, you can’t directly attach a script or a method to a button. My button keybind scripts are stored in an empty object I just call “RebindKeys” which is held in an empty “system” object. I drag this RebindKeys object onto my button, then I choose the correct script & method.
Drag this onto the button method field
Select the correct script, then method
Finally I just need to display what key we have bound. This script is held by the text directly on the button, updating it in real time except when we have nothing bound to the key (which is when we are currently binding a new key).
Now that I think about it this could be optimized to only update when a key has been changed instead of refreshing every frame. Whoops! Once again I just do things a way, then worry about making improvements later when I try implementing it again in another practice project.
Hopefully I was able to assist someone out there with their code. At the very least I noticed a few of my own mistakes by writing this post because I was forced to organize my thoughts.
If you liked this, please follow me on my social media profiles.