Key Rebinding with Unity's New Input System and Generated C# Code

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
kiwi binding is a nice to have it in game and for some players it's a must-have in a game so in this video we're going to look at creating a key rebinding system that's going to work with unity's new input system and in particular it's going to work with the c-sharp generated class if you're not using the c sharp generated class and you're using the scriptable object that unity generates the input action asset then i would encourage you to go look at unity sample package their system works really nicely with that scriptable object it does not work with the c-sharp generated class and also one other caveat the system that i'm going to build here is going to have more functionality than that system but an awful lot of what i'm going to do here can be applied to their system as well so before we get started i also want to point out one major issue that i ran into or a confusing point and that being that when you create an input action asset unity is creating a scriptable object and then when you generate c sharp code or unity generates that c sharp code from that input action asset that's c-sharp class and that scriptable object do not talk to each other at edit time or in run time and so that does cause some problems and we need to be really clear which one we're using when we're going to be using the scriptable object in our inspector to be able to pick our exact action and binding and then during run time we're going to be rebinding on the c sharp generated class because that's what our game objects are going to be using so before we get started let's take a quick tour of the scene you can see down here i have my input action asset i've called it rebind jumping and it has just one simple action that's a jump and it's got two bindings one for the keyboard and one for the gamepad you can also see up here in my canvas that i have these two prefabs let me go take a closer look at these here you can see here that we've got this action text a rebind button and a reset button so again this is going to allow us to display to the player exactly what action we're rebinding the rebind button itself will display the current binding for that action and then the reset binding will allow the player to reset whatever they may have done back to what you as a developer set by default this ui prefab is pretty simple so i'm not going to take the time to build that up in this video but what's going to be happening here is that this ui prefab is going to have a component that we will be building up and it takes input from both you the developer when you create it and the player as they're rebinding their keys it's then packaging up that information and sending it off to an input manager which is going to have a static reference to the input action asset and that's where the rebinding is actually going to happen that's the big picture of how our system is going to work here before we get in too deep i do want to also look at the jump controller and this is just a very very simple implementation of unity's new input system so what we have here we have an instance of the rebinding jumping input action asset and then on the on enable function we create an instance of that we subscribe to one of the events we enable that action and then down here in the do jump we're just applying a add force so that we get this appearance of the object jumping up and down and again that's applied just to this red capsule here in the game view and again if you're not familiar with unity's new input system uh check out my earlier video that covers the basics of that and it very much explains what's going on in this script we will have to come back to this jump controller and change one line there to make use of our key rebinding functionality okay so enough intro first thing we need to do is create a new c sharp class for our ui component and i'm going to call it rebind ui so in this class first thing we need to do is add in a few namespaces most importantly we need to add in the input system we're also going to need to add in ui system so we can reference our text and our buttons and if you're going to use text mesh pro which looks much nicer you're going to want to add in that tm pro name space as well i'm not going to do that right now i'm just going to work with the built in text component but nothing changes if you're going to use text mesh pro other than it's going to look nicer i'm going to get rid of the start and update and then we need to add in several fields here and i'll try to explain them as we go along first one going to be private serialized input action reference now this was a little bit new to me this is not something we've looked at in earlier videos but this is going to allow you as the developer to select not only the input action asset but the action that you want to rebind which is pretty convenient it's also really important so this reference that we're getting is part of the script of objects so again we're going to be going back and forth between the scriptable object we're going to be pulling information on that so that you can choose the correct action binding then we're going to be sending that information to the input manager which has reference to the generated c sharp uh input action asset so we're playing a little bit of a shell game getting data from one sending it to another one but it works pretty well next thing we're going to do is create a boolean here that is going to allow us to exclude the mouse i'm going to set it equal to true again that gives you the developer some flexibility to say hey this binding i don't want the player to accidentally assign the mouse to it so they're not moving left when they push the right mouse button just by accident i totally did that when i was doing some testing next thing we're going to do is add in a slider and have it go from 0 to 10. it's also going to be serialized it's going to be a private integer now the this is where it gets a little bit janky so without creating a custom inspector whether that's with unity's built-in tools or something like odin we got to be a little clever here what we need to be able to do is select the actual binding so i'll put it up on the screen but you can see that each action can have multiple bindings below it and we need to select which one we want to do the re-binding to and this is the least janky way i've found to do it so i'm going creating a slider that's going to go from 0 to 10. for some reason you have more than 10 bindings you're going to need to make that value bigger and this is going to be the selected binding like so then we're going to have yet another serialized field all these fields are going to be private and serialized so we're going to have an input binding display string options and we're going to call that display string options like so and this is just a nice built-in enum that'll allow us to format the binding name so the player can see something that looks nice and is fairly human readable it's just a nice to have type of thing so far we're able to select the binding but you as the developer it's tricky to know which binding you selected so i'm going to create a new field here and i'm going to put a header on it call it binding info info do not edit and this is again for your use it'll allow you to see what binding you have selected so input binding like so and lastly we're going to have one more integer here and this is the binding index and we have another integer here that sounds very similar to our selected binding but this is going to be the actual binding of the index because in the inspector you can move that slider wherever you want it's possible that you could choose a value such that that binding does not exist whereas this variable is going to store the actual binding we're going to have a little bit of idiot checking to make sure that if you have 9 in the inspector we're not trying to change binding 9 if that binding doesn't exist hope that makes sense we're also going to have a private string this does not need to be serialized because we don't need to see it we don't want to change it this is going to be the action name and this is again key here we're going to be storing the action as a string now the reason we're storing the action as a string and not the action itself is because the action that we're finding is on the scriptable object but we don't want to rebind that action so what we're going to do instead is take this action name send it over to the input manager the input manager is going to then look up that action on the c-sharp generated class and then return and cache that action because that's where we want to do the re-binding last thing we're going to do i'm going to put in another header just to make it look nice and easy to read and use i'm going to add in a bunch of uh ui fields here i have a text here that's going to be our action text i have a button this is going to be our rebind button we're also going to have a rebind text this is the text that's on that rebind button that'll allow the player to know what has been what is assigned or what has been assigned when they changed it and the last one is another button this is going to be the reset button so the player can press a button and again go back to that default binding that you the developer have set now one of my goals here is to make this as user friendly as possible again without a custom inspector or using something like odin so we're going to add in a on a validate function now if you've never used the on validate function this is a function that gets called whenever something in the inspector changes now it doesn't get called when you go into play mode or anything like that like that but anytime you change something in the inspector this function is going to get called and what that's going to allow us to do is you the developer or me showing you how my system works when i choose an input action reference we can then update the rest of the inspector with the appropriate values just makes it feel good and it's a whole lot easier to use so we're going to call two functions here and we're going to have to create those functions but we're going to create we're going to get binding info and we're going to update ui so anytime any something changes we're going to go get the binding info and update the ui so first off we're going to create this get binding function like that and in here again what we need to do is so you've selected this action in the inspector now we need to go get the binding make sure that it actually exists first thing we're going to do we're going to check to make sure that the action actually exists if it does we're going to set the action name like that so now we're storing the action name not the action itself and then we need to go see if this binding that you've selected with the slider exists so input action reference action bindings this is an array of all the bindings we're going to check the count of this and make sure that it's bigger than the selected binding so this is where we try to make it a little bit idiot-proof again so if you slide it all the way over to 10 and there isn't a 10th binding keeps it a little bit safer we're going to set input binding to input input action reference action bindings selected binding like so and again that's for your visual update or visual feedback binding index equals select binding so here's where we are setting the actual index that we're going to be sending off to input manager to the value that you selected in the inspector all right so let's make our update ui function something like that we're going to check and see if the action text is is not null if it's not null we're going to update it with the action name remember same kind of idea we're going to check if the rebind text is not null and if it's not we're going to do some stuff here so what we want to do here is we want to keep the text on the rebin button up to date now when we're in edit mode we want to grab that information off the scriptable object when we're in play mode we're going to grab it off the c-sharp generated class let's just make sure we're always dealing with the correct information the player and or the developer you can see the same incorrect information so we're going to check if application is plain if it is we're going to grab info from input manager we don't have that functionality right now we're going to create that later when we get to the input manager otherwise we're going to say rebind text equals input action reference action get binding display name which is a nice uh extension given to us by unity to create a nice human readable version of the binding name and we're gonna pass in the binding index so always a good habit let's go back into unity and let's make sure this is working and you can see how this all plays out in unity i'm going to go to my prefab here and i'm going to add this rebind ui to it so at the top here you can see the input action reference so if i click the circle here you can see all the various actions that i have in my project from past videos and tutorials i'm going to choose this top one which is my games control or game controls jump like so and then if i open up the input binding you can see the binding here i can see that it's right now we're talk we're going to be rebinding the keyboard space bar and if i move that you'll see that that'll update but if i slide it over and that binding doesn't exist nothing gets updated also we've got our display string options here for what i found none works pretty well but you can play around those and get exactly what you want then let's assign our ui elements here so i'm going to drag in the action text rebind button text on that button and the reset button as well now this is working right if i slide this back and forth you can see the ui over there in the game view is changing and reflecting which uh button or which binding we're going to be doing the rebinding for so here's the keyboard so it says space slide it over it's a which is the south button on the gamepad that's pretty slick i really like how well this works the slider's a bit janky but it does work and it's pretty easy to use as a developer all right so let's go back into our rebind code and add a few more details to it and more or less polish that up we'll have to come back to it towards the end but let's go do that so a few things here you may have seen a warning or error came up i'm going to go back here to my onvalidate and we need to check and make sure that our input action reference if it's null we just want to return we don't want to update these other bits and pieces it's not a big deal but if you don't have that it will throw errors in edit mode as you may have noticed next thing we need to do is set up our buttons so they actually do something so i'm gonna do rebind button on click add listener and then we're gonna feed in our delegate and this is gonna be do rebind like so and we're gonna do the same thing for a reset button on click add listener and this will be reset binding like so and extra parentheses and it's just objecting here because those functions have not been been defined we'll do that here in just a bit so the other thing we want to do is when we go into play mode we want to make sure that our ui and all our values in the inspector are reflecting the correct values sometimes when you go into play mode you can lose those so we're going to check and make sure that our action reference is not null and if it's not we're going to get our binding info and update ui like so we'll come back and we're going to add again a little bit more functionality to it that is the bulk of what we want to do then we're going to come and deal with these create these functions here so private do rebind like so and private void reset binding and for now i'm going to leave those two functions blank because we need to create the functionality in the input manager and we're going to call some of those functions from this component but we don't have those yet so we're going to leave it as is so like a lot of things that i like to do i want to build this up in levels of functionality we're going to start with the base level of functionality so that if that's all you need you can stop the video and take it and implement it if you want to keep going further keep watching more and we'll keep implementing new functionality so what we're going to do we're going to start off with obviously implementing the basic rebinding functionality we're then going to add the ability to rebind composites again so that's like wasd if you have a composite input you can have just one ui element the player can press it once and then rebind all the pieces of the composite which is nice we're going to add in c-sharp events so that when you start the rebinding process or cancel the rebinding process or complete the rebinding process an event can get called and other parts of your system or other parts of your game can be notified that that happens so if you want to play a sound effect maybe you want to trigger some ui so there's an overlay whatever you need or want to do will be pretty easy to do we're also going to add in the functionality to save a binding so if the player changes something we can save that value and then reload it the next time they play so they don't have to set up the bindings every time they play the game so here in the input manager we're going to get rid of the start and update functions we just don't need them but what we do really need to create is a public static reference to our input action asset and in my case i've called that rebind rebind jumping and you're going to need to put in the type and the name of your class in there i'm going to call this input actions like so next i'm going to add an awake function and in here i'm going to check and see if input actions is null and if it is we're going to create a new instance of it like so now the reason i'm checking to see if it's null is i've ended up with some race conditions and some functions we're going to create later down um where it's dependent that function is dependent on this static instance i'm not sure why i'm getting race conditions with an awake but this is just a little bit of a safety check and i don't want to accidentally create multiple instances of this input action asset i want to make sure there's only one and i don't want to override it because if i rebind to input action asset and then create a new instance of it it's going to get rid of all those bindings and it's going to be really hard to not hard to debug necessarily but confusing and just not work the way we want it to next thing we're going to do is we're going to create a private static function and this is going to be the do rebind now i am creating this as a private function because i'm going to have another function that actually going to call this one we're going to have some other kind of like pre-sorting that's going to help us do with deal with composite bindings if you don't want to do composite functions make this function public and this is what you're going to call from the rebind ui component that we just created but before we get too much further here i forgot to add in some name spaces so i'm going to add in using unity engine dot input system i'm gonna add in using unity engine dot ui and because we're gonna add in um actions or events i'm going to add in using system like so that just allows us to use that shortcut of creating an action rather than having to create a delegate and then an instance of that delegate okay so back to the uh do rebind we're going to add in an input action this is going to be the action to rebind we're going to have a binding index this is the binding that we are redoing and we're going to pass in status text or so this is the text of the button that the player is pressing just giving them a little bit of feedback as to what's going on as we progress through this we are going to come back and add some more parameters here as we add more functionality but for now this is going to do it so first thing we want to do we want to make sure that this action to rebind is not null and we also want to make sure that our binding index is valid so it's got to be greater than zero if either of these aren't true we're going to return we're done next thing we're going to do is just a little bit of quality of life for your players i don't think this is a fully developed idea here uh but it is kind of nice we're going to update the text on the button so when you press it you give the player some feedback hey we're looking for a button we're looking for the kind of control type that we're telling them what kind of control type should go in there add in a string press and then we're going to do action rebind expected control type and again i really think this piece could use some refinement but it's a good start and a little bit of feedback to the player also as soon as they press the button the text on it changes which is a nice again just feedback for the player in order to do rebinding we need to disable the action that we're rebinding really important and we'll re-enable it when we're done with the rebinding so disable it like so and then we need to create an instance of this rebinding action and so to do that we're going to create a new variable rebind action to rebind and then we're going to make use of a extension function that unity has for us which is perform interactive rebind and we're going to feed in this binding index like so now it's important to know that this command this function does not start the rebinding it just creates an instance of this process or this object that's going to be doing the rebinding for us and the vast majority of that work is going on behind the scenes created by unity but we do need to create an instance of it the next thing we need to do is we need to create the behavior of this rebind process most notably we need to define uh how what it does when that rebind process is complete and when it's canceled so we're going to do rebind dot on complete and this is where we get a little bit of complex notation if you're not used to delegates we're going to have uh open parentheses operation and then we're going to assign this delegate like so and make sure we put a just to avoid there we're gonna put a semicolon at that end so what we need to do here is on when this operation is complete when the rebinding is complete we need to take this action and we need to enable it we also need to get rid of this operation so if we don't call this dispose function unity is not going to get rid of this operation and we can have a memory leak generally unity and c-sharp they do all the garbage collection for us in this case we need to tell it hey we're all done clean this up we're also going to define the on cancel and we're going to do the same thing like so and for right now i'm actually going to copy these exact same lines and copy and paste them in there we are going to come back to the on complete in particular and add some functionality as we go but in both cases when we've completed or cancelled our rebinding we want to re-enable action and we want to get rid of the rebind operation itself so we clean out our memory the last thing we need to do here we need to do rebind we're going to do rebind start and this actually starts the re-binding process so if you just want a bare bones rebinding system this function is most of what you need you would need to change it to a public function and call it from the rebind ui and you also need to actually get a reference to this input action remember our ui component only has the name of the action whereas this function is taking in the actual action so there's a little bit of work that you need to do but we're going to do that in the next function which is also going to add in functionality to deal with composite inputs so the next function we're going to add in is actually going to start the rebind process and what it's going to do is check and see if we're rebinding a composite binding and i have more or less stolen this straight from unity's sample it works it's great so i'm going to create a new public static function this is going to be called start rebind and in this thing we're going to take in the action name we're going to take in the binding index and we're going to take in the text a status text again this is the function that's actually going to get called from our ui component first thing we need to do is we need to get this actual action so input input action action and the way we get that action is we look at our input action asset we go to the asset part of it and find action and we can look it up by name so again i've said it a whole bunch of times but what we're doing here is getting that action off of the c-sharp generated script not the scriptable object which is what the ui object has reference to next what we're going to do we're going to check and make sure that this action isn't null we're also going to check and see if this binding index that we've sent in here is valid the way we do that we go to action.bindings which is an array we check the count of it and we make sure that it's less than or equal to the binding index if that's not true we're gonna print a warning that's a log couldn't find action or binding and return again that's just to help you as the developer the likely cause of running this problem is that you have dropped in the wrong input action asset into your ui component and your input manager here is referencing a different input action asset if that's not true if we're good to go then what we need to do is we're going to check and see if this action or more particularly the binding so action dot bindings at that particular binding index and see is it a composite if it is we're going to do a bunch of stuff if it's not what we're going to do is we're going to call this do rebind and we're going to pass in the action we're going to pass in the binding index and the status text so if it is a composite we've got to do a little bit of tricky work and i'll put this up on the screen here so a composite binding is actually a whole bunch of bindings put together so if you look at the wasd binding that's the first binding but the up down left right our bindings after it so if we're going to rebind a composite what we're actually feeding in is the binding for that wasd binding and what we need to do is do multiple rebindings for each of the sub bindings and to do that we've got to do some work with our indices so we're going to create a variable first part index and this is the binding index plus one so again we don't want to be doing the rebinding for the wasd part we want to be doing it for the up or the down or whatever binding comes after that which is why we're adding one we didn't want to check and see is this index does it exist for a new action bindings count and we also want to make sure that that binding is in fact a composite so we do action bindings feed this in first part index is composite so we're making sure that that binding exists and then it's composite if neither of those are true we don't want to do anything more if those are both true we just want to do our to rebind we're going to pass in our action our binding index and our status text like so but here's the problem we need to differentiate between this call here and this call here and we're going to do that by creating a new boolean so down here in our do re-bind we're going to create a new boolean and we're going to do all composite parts like so and then up here we're going to do true and here we do false which is great so now we're telling our do rebind function whether it's a composite or not but our do rebind isn't doing anything different so down in the do rebind in the on complete behavior we're going to expand that and check if it's all composite parts and if it is we need to do some more work with our indices create a new variable and call this next binding index and this is going to be the binding index that we sent in plus one and then we're going to check and see next binding index make sure that that binding exists and we want to make sure that that binding is in fact a composite that's true we're going to call do rebind again we're going to pass in the same action we're going to pass in this new binding index and pass the status text and we're going to pass in all composite parts just like we did before so we're playing with indices here we're calling functions from within functions but what we're really doing here is working our way down this binding list increasing the binding by one checking to see if that next binding is a composite if it is we send that binding into this do rebind function to rebind that and again what this allows our player to do is click on that composite button once and then rebind the up down left right without having to click on the ui again which is pretty nice nice quality of life thing for your player so with that done we should be able to jump back into our rebind ui call this public uh start rebind function and test this out and see if this is working we're going to come down here to the do rebind and here we're going to do call input manager start rebind we're going to pass in the action name the binding index and the rebind text like so then to really test this we're going to come back to our jump controller here and this is where we're going to do some changing here this is the kind of the one thing that i need to change with this jump controller rather than create a new instance of this rebinding input action asset i'm going to reference the input manager input actions like so and that's it let's go back into unity and see how well this works the thing i always forget to do and we're not going to talk about how often i did it while i was trying to film this tutorial we need to put our input manager into the scene i'm going to create a new empty object i'm going to name it managers and i'm going to drag the input manager onto it like so we go into play mode we should be able to test this out so if i press the spacebar or jumping like so if i click on the ui object up here to rebind it it says press a button which is that feedback so i'm going to press b to jump now notice here that the ui is not updating we don't have that functionality in there quite yet but if i come back to my game i can now press b and i'm re-jumping and if i press space nothing happens at all so our re-binding is working other thing to note and we're going to fix this if i come back into play mode my rebinding is once again set to the space bar not to that rebound button we're going to fix all that as we go along so next thing i want to add in is those c-sharp events and that's going to allow us to update the ui when the rebind is complete so i'm going to scroll up here at the top and we're going to create those new actions i'm going to create three actions first one is static event action rebind complete like so and then likewise another public static event rebind uh cancelled and the last one is going to have some parameters in it and what we're going to send here is the input action we're actually this is the action that had something done to it we're going to send out the integer as well the binding for it and this is going to be the rebind started so if you want to say have an overlay that pops up uh that blocks all the other input and tells the player what's going on hey you're rebinding this action and this is what's currently assigned this is the event that would be helpful because we're going to send out that action and the integer for the binding index so you'll be able to access all that in the ui or whatever else you might want that to be accessed from so we're going to come on down here to our rebind function here and we're going to put these events or rather going to invoke these events in here so on completed we're going to have rebind complete and check and see if anybody subscribed to it if they are we're going to invoke like so and then same kind of idea down here rebind cancelled check to see if anybody subscribed and invoke and lastly down here rebind started we're going to the same kind of thing this time we're going to pass in the action that to be that's being rebound along with the binding index like that so with those events put in place we now can make use of them we can tie into them so we're going to come back to our rebind ui in the on enable we're going to subscribe to the rebind complete and we're going to add in the update ui like so and then just to be nice and tidy we're going to make sure we unsubscribe from that so i'm going to copy that line and we're going to unsubscribe like so again if you're not used to uh c-sharp events check out my earlier video on that um walk through this whole idea of what events and actions and delegates are and how to subscribe and unsubscribe so now we're subscribed to those things we can update our ui but we have a problem here this is it's right here so when the application is in play mode we need to grab the information off the c sharp script not off the scriptable object and we can only do that from the input manager so we need to create another static function where we can go grab that information so let's jump back over to our input manager come here down to the bottom i'm going to create a public static string so we're going to be returning a string get finding name and we're going to do that by passing in the action name and the integer for the binding index like so and again we're going to check and see here if our input actions is null and this is where i mentioned before i was getting some race conditions i'm not entirely sure why but it was so we're going to check and see if that input actions is null if it is we're going to create a new instance of it we're then going to go see if we can get our action so input actions asset find action and we're going to pass in that action name like so and then we're going to return this action but we're going to use an extension function of get it bindings display string and we're going to pass in the display or sorry we're going to pass in the binding index little brain part there like so going back and forth pretty quickly here but back to the rebinding and in here we're going to say rebind text dot text equals input manager get binding name and we're going to pass in the action name and the binding index like so so if we go into unity here let's test that functionality i click here i press spacebar and i'm jumping if i do my rebinding press it to b i press b and we're jumping and one thing you should note here now if i press that rebinding button and i press one of the buttons on my gamepad it's going to rebind it to that and which which is totally fine i can now jump using my gamepad but in some cases you may want to have keyboard specific bindings and game pad specific bindings so let's set that up it's not that hard so if you don't want the functionality of being able to rebind either a keyboard or a gamepad to a particular binding you want to keep them separate it's not a bad idea to do that we need to create a control scheme we do that here in the input action asset you can see here mine says no control schemes i'm going to add a control scheme i'm going to call the first one keyboard and then i'm going to add in the devices i'm going to add in a keyboard and i'm going to add in a mouse as well like so and i'm going to save that and then i'm going to also create another control scheme i'm going to call this gamepad and likewise i'm going to add in a gamepad to that and then here in my bindings i need to assign which control scheme so on the space bar that's going to be part of the keyboard and you'll notice that disappears because over here i'm filtering by which uh control schemes to show so i'm gonna come back here to all control schemes and then i'm gonna come down to the south button and that's gonna be part of the game pad now if we come back up here and go into play mode we have we have all the same functionality i can i can rebind the keyboard no problem but if i get my gamepad and i rebind it doesn't work and that's because the binding that we originally set up was set up for the keyboard which is now part of a different control scheme and so it's only going to allow devices from that particular control scheme i can actually click my mouse button and now it says left mouse button and now i jump every time i click the left mouse button the next thing we're going to do is we're going to allow the player to cancel the rebinding and we're going to allow you the developer to exclude particular devices from a rebinding operation so back here in the input manager i'm going to be working here in the do rebind function and what we need to do is add in a functionality to our rebind operation so i'm going to come down here towards the bottom and what we're going to do is add in a rebind with canceling through so here's again where i don't love some of the design choices of unity maybe it was the only way to do it we have to type in a string we need to tell it which input to cancel so i'm going to type in for my use case the keyboard important that the keyboard is capitalized forward slash escape like so so this way when you're in the middle of a uh rebind you press escape cancel it hey i didn't want to do that makes a lot of sense if you want to use a button on the gamepad to cancel a rebinding you're going to have to add in another one of these lines or have some additional logic to add that device or that input to cancel it then we're also going to add in the ability to exclude particular devices in my case i'm just going to exclude the mouse again if you want to exclude other things like the left stick or the right stick or sticks in general or buttons that works very much the same you're just going to put in a different string so i'm going to check and see here if we're excluding include the mouse which is not defined yet but we'll go up and define this and then we're going to do rebind with exclude or with controls excluding i always get it wrong and in here we're going to put in mouse again it's capital m for the name of the device and that will allow us to exclude the mouse so that you can't accidentally rebind the jump to one of your mouse buttons so what i want to do next is define this variable exclude mouse and i'm going to do that by creating a new parameter in the do rebind function here it's going to be a boolean exclude mouse like so and that's going to throw an error down here where we are calling the dewbry bind for a composite so we're going to add that parameter to that function call and then of course that causes problems up here on our start rebind so we're going to add another parameter to that function as well and then copy and paste that down into it here so we're just passing that value along as we go but this of course is going to cause a problem over on our rebind ui where we're calling the start rebind function so i'm going to come over to the rebind ui come down here and here we're going to pass in the exclude mouse which was already defined when we started all of this the other issue that we have is that when we cancel a rebind action we need to refresh the ui we need to update it so i'm going to come up here to the on enable we're going to add in input manager rebind cancelled plus equals update ui i copy that down here to the on disable and unsubscribe like so so let's go into unity and see how well that's working i go into play mode i can jump i start the rebind process and press escape you can see my ui is refreshed and i'm still using my space bar to jump if i start the rebind process i can still assign a different button i can jump if i do it uh and click my mouse you can see i'm clicking my mouse it doesn't rebind it because over in our prefab in our rebind ui we have the exclude mouse option toggled on okay so i know this is getting long and maybe i should have broken this up into chunks but we're going to add in one more chunk of functionality and that is saving our binding and then reloading it when the player comes back so that their preferences get saved and they don't have to redo the bindings every time they play your game so we're going to do the majority of that work over in our input manager i'm going to scroll down to the bottom and we're going to create two new functions the first is going to be a private static function this is going to be save binding override and we're going to input the input action itself and again we're not inputting the name of the action this is again private it's internal to input manager so we're going to have reference to the actual action a lot of whack there there we go fix that so here what we're going to do i'm going to use player preps now if you're using a more sophisticated save system like like your own or easy save or something like that you can adapt this to work uh perfectly well with that but for me it makes sense to use player preps so what we're going to do is we're going to loop through all the bindings on this action and save them to player prefs so for loop and we're going to loop through actions bindings which is an array count and then for each one of these we're going to do a player player prefs set string because we're going to be saving the binding which is just a string and we're going to give this a name of action action map plus action name plus i and the reason i'm including the action map in there is just in case you have the same action on different input action assets or different action maps i want to make sure that there's a bigger string here so if you have like move in a boat action map and move in a car action map they don't override it you may or may not need that and then what we're going to save is the action bindings from that index the override path so the way unity does this is that there is a path there's a default path that has the value you as a designer set in the input action asset and then there's an override path which is what it looks for during runtime and so we're going to grab that path and save that as a string then in our next function which is going to load the binding we're going to go grab that path and set that as the override path hope that makes sense all right so this one's going to be public static void and the reason is public is this is going to get called from the rebind ui we're going to do load binding override and we're going to pass in the action name again this time we're using the action name because it's going to get called from the ui which only has reference to the name just like before we're going to do check and see if the input actions is null it is we're going to create a new instance of it again i've just got some race conditions i'm not entirely sure why but this solves it we're going to have to get a reference to that action input actions asset find action and we're going to pass in that action name like so then what we're going to do is we're going to loop through all the bindings in that action so action bindings count like so and the reason we're going to loop through all of them is it's just easier rather than having to pass in the binding index and find that exact one it just it's just simpler maybe not as efficient but i don't think that's a major concern so what we're going to do is we're going to check and see if um we have a saved value so we're going to do uh string is empty or null and we're do player prefs get string and we're going to grab this thing up here that we saved it as and stick it in there and i'm copying and pasting it just so i don't make a mistake it's a really easy way to get an error so if it's not null or empty then we're going to override it so action apply binding override this is going to be we pass in the binding index and then we pass in the binding path which is this player prefs string right here and that's it even if it doesn't feel like a that's it moment these are the functions we need to save and load our bindings now we just need to call those functions so i'm going to scroll up here to our adobe rebind if our operation is complete we're going to save our binding i'm going to come down here and we're going to call save binding override and i'm going to pass in the action to rebind simple as that then to load this we want to be loading it from the ui because that's the piece that's associated with the actual action i'm going to come back to the rebind ui and here on on enable we're going to check here if the input action reference is a null and if it's not we're going to call input manager load binding override and we're going to pass in the action name like so all right so we're gonna go back into unity and see if this all works we go into play mode we still have the space as the default key if i override that to b that works we go out of play mode and you'll notice the ui goes back to that spacebar that's that's okay go back into play mode and we should load up there's our b and if i press b it's working our binding has been saved all right so we're almost done and i actually thought we were but when i sat down to edit this video i realized we i missed one of the steps which was to create the reset binding function so let's do that now we're going to jump back in to the input manager add a function and then call that function from the rebind ui so what we're going to do here is create another public static function return void and this one's just going to be reset binding and then we're going to pass in string for the action name since this is getting called from the rebind ui we're also going to pass in the binding index now really what we need to do here is simply for each binding we need to call a remove override binding extension function and that just the unity then just sets the binding back to whatever you the game developer set in unity it's pretty straightforward but there are a few things that we need to do first so since we're passing in the action name we need to get the actual action just like we've been doing so far so it's input actions asset find action we find it by name and then we're going to check and see if this action is null or we also want to make sure that the action um the or the binding index exists so we're gonna do just like we did before and check and see if the count is less than or equal to the binding index if either of those are true that means we can't find the binding we're just gonna print you the developer a message not 100 necessary but i kind of like to do it reminds me it lets me know something's going wrong and then what we need to do we need to check and see if this action binding the binding index is a composite because again remember that these composite bindings are a series of bindings and so if we're going to reset a composite binding we need to loop through we're going to use a for loop loop through and reset each individual binding if that is true we're going to loop through and we're going to go from i equals binding index to action bindings count and now this is a little bit different because we're going to do something i haven't really seen before but this second piece of the for loop is actually a boolean statement evaluating whether this is true usually we're just talking about numbers but we can make it a more general boolean so we're also going to check and make sure that this action binding at i is a composite if it's not a composite we want to stop we're all done with our for loop then all we need to do is call action remove binding override and feed in the index of what we want to override if it's not a composite we're going to do something very similar we're just going to use the binding index that gets sent in when this function gets called so again we're playing around with indices a little bit because we have a composite but not terribly complex again the idea is we're just going through every binding that's associated with uh this action this binding that we want to reset and calling this extension function of remove binding override last step is to hop over to the rebind ui and here in the reset binding we need to call that new function that we just created so input manager reset binding we need to pass in the action name and the binding index and one last step i'm going to call update ui when this binding has been reset now you could create another action in the input manager whenever a binding gets reset that action gets invoked this feels pretty clean to me as well so let's go back into unity and see how well this works going into play mode you can see here that currently the jump is set to h i can press h i can jump if i press reset it goes back to space or and then i can press the space bar to reset it so not only are we resetting the ui we're actually resetting the binding itself so there you go it's definitely long no matter how i choose to edit this up i hope this was interesting and better yet useful for you and your project it was check out these other videos that unity thinks you should watch and until next time happy game designing
Info
Channel: One Wheel Studio
Views: 20,396
Rating: undefined out of 5
Keywords: Unity3d, Indie Game, Game Development
Id: TD0R5x0yL0Y
Channel Id: undefined
Length: 51min 3sec (3063 seconds)
Published: Wed Aug 25 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.