Hi, can someone post an idea how to make GUI elements (buttons, sliders ets.) to be controlable (selectable) by keyboard or gamepad? I was thinking about add ID property to these elements but I'm not sure how to do this. Maybe is other way to do this? I've made control of 3d objects by asign script to 3d game objects but GUI are created by script so I can'd do this that way. Any ideas? TIA
Hi, welcome to the forum! Do you want all GUI elements to have a keyboard alternative (activated by tabbing through, say) or do you want specific things in your game to have keyboard shortcuts?
I just want menu based on Unity GUI/GUILayout and controlable by keyboard. Simple game menus build using GUI and selectable without mouse.
I came across the same issue recently, trying to control a menu with a gamepad. Here's the roughly code I used (had to piece some of it back together, but you should be able to work with it and automate it some more, maybe). Code (csharp): // Array of menu item control names. var menuOptions = new String[4]; menuOptions[0] = "Tutorial"; menuOptions[1] = "Play"; menuOptions[2] = "High Scores"; menuOptions[3] = "Exit"; // Default selected menu item (in this case, Tutorial). var selectedIndex = 0; // Function to scroll through possible menu items array, looping back to start/end depending on direction of movement. function menuSelection (menuItems, selectedItem, direction) { if (direction == "up") { if (selectedItem == 0) { selectedItem = menuItems.length - 1; } else { selectedItem -= 1; } } if (direction == "down") { if (selectedItem == menuItems.length - 1) { selectedItem = 0; } else { selectedItem += 1; } } return selectedItem; } function Update () { if ([key press down arrow]) { selectedIndex = menuSelection(menuOptions, selectedIndex, "down"); } if ([key press up arrow]) { selectedIndex = menuSelection(menuOptions, selectedIndex, "up"); } } function OnGUI () { GUI.SetNextControlName ("Tutorial"); if (GUI.Button(Rect(10,70,50,30), "View Tutorial")) { //Do tutorial stuff. } GUI.SetNextControlName ("Play"); if (GUI.Button(Rect(10,100,50,30), "Play Game")) { //Do game stuff. } GUI.SetNextControlName ("High Scores"); if (GUI.Button(Rect(10,130,50,30), "High Scores")) { //Do high score stuff. } GUI.SetNextControlName ("Exit"); if (GUI.Button(Rect(10,160,50,30), "Exit")) { //Do quit stuff. } GUI.FocusControl (menuOptions[selectedIndex]); }
Yeah, thanks. That works :> I've missed "GUI.SetNextControlName" function in scripting reference so that's why I couldn't do this.
Despite Being An Old Thread, can I say, nice Code Farfarer (better then mine anyway :/) I need to read the reference more.... EDIT: I'm now stuck with trying to get the user to selected the focused control...My User is taken to a map select screen- part of the initial main menu, so it's a little hard to figure out, then passing an index towards App.LevelLoad....
great script i got it to work with my gamepad but i still don't get how to make the buttons clickable when i press a certain button. does anybody have any ideas?
@Farfarer Thanks for the snippet ..very helpful! This is how i made the buttons clickable: Code (csharp): // Array of menu item control names. var menuOptions = new String[4]; menuOptions[0] = "Tutorial"; menuOptions[1] = "Play"; menuOptions[2] = "High Scores"; menuOptions[3] = "Exit"; // Default selected menu item (in this case, Tutorial). var selectedIndex = 0; // Function to scroll through possible menu items array, looping back to start/end depending on direction of movement. function menuSelection (menuItems, selectedItem, direction) { if (direction == "up") { if (selectedItem == 0) { selectedItem = menuItems.length - 1; } else { selectedItem -= 1; } } if (direction == "down") { if (selectedItem == menuItems.length - 1) { selectedItem = 0; } else { selectedItem += 1; } } return selectedItem; } function Update () { if (Input.GetKeyDown("down")) { selectedIndex = menuSelection(menuOptions, selectedIndex, "down"); } if (Input.GetKeyDown("up")) { selectedIndex = menuSelection(menuOptions, selectedIndex, "up"); } if (Input.GetKeyDown("space")) { handleSelection(); } } function handleSelection() { GUI.FocusControl (menuOptions[selectedIndex]); switch (selectedIndex) { case 0: Debug.Log("Selected name: " + GUI.GetNameOfFocusedControl () + " / id: " +selectedIndex); break; case 1: Debug.Log("Selected name: " + GUI.GetNameOfFocusedControl () + " / id: " +selectedIndex); break; case 2: Debug.Log("Selected name: " + GUI.GetNameOfFocusedControl () + " / id: " +selectedIndex); break; case 3: Debug.Log("Selected name: " + GUI.GetNameOfFocusedControl () + " / id: " +selectedIndex); break; default: Debug.Log ("None of the above selected.."); break; } } function OnGUI () { GUI.SetNextControlName ("Tutorial"); if (GUI.Button(Rect(10,70,170,30), "Button 1 (tutorial,id:0)")) { selectedIndex = 0; handleSelection(); } GUI.SetNextControlName ("Play"); if (GUI.Button(Rect(10,100,170,30), "Button 2 (play, id:1)")) { selectedIndex = 1; handleSelection(); } GUI.SetNextControlName ("High Scores"); if (GUI.Button(Rect(10,130,170,30), "Button 3 (high scores, id:2)")) { selectedIndex = 2; handleSelection(); } GUI.SetNextControlName ("Exit"); if (GUI.Button(Rect(10,160,170,30), "Button 4 (exit, id:3)")) { selectedIndex = 3; handleSelection(); } GUI.FocusControl (menuOptions[selectedIndex]); }
Thanks for your snippet Farfarer. Does anyone knows how can I apply something like that to a gui slider ?
Here's some C# code from this answer: http://answers.unity3d.com/questions/660805/navigating-unitygui-menus-without-a-mouse.html The Dialogue System for Unity maintains a list of navigable controls. It looks something like below (simplified for this answer): Code (csharp): public class GUIButton { public string controlName; public string text; public Rect rect; } GUIButton[] buttons; // Array of buttons to navigate through; could generalize for any control type. int current; // Index into buttons[]. OnGUI draws it like this: Code (csharp): foreach (var button in buttons) { GUI.SetNextControlName(button.controlName); if (GUI.Button(button.rect, button.text)) { // do whatever action is assigned to this button. } } GUI.FocusControl(buttons[current].controlName); But it also checks the value of an input axis (e.g., "Vertical") and changes current accordingly: Code (csharp): float axis = Input.GetAxis("Vertical"); if (axis < 0) { current--; // Move to previous button. } else if (axis > 0) { current++; // Move to next button. } current = Mathf.Clamp(current, 0, buttons.Length-1); foreach (var button in buttons) { GUI.SetNextControlName(button.controlName); if (GUI.Button(button.rect, button.text)) {...} } GUI.FocusControl(buttons[current].controlName); And to check for the gamepad button: Code (csharp): bool buttonPressed = false; void Update() { if (Input.GetButtonDown("Fire1")) { // do whatever is assigned to buttons[current]. } } The actual implementation is quite a bit more sophisticated, but this is the basic idea. Enhancements could include: Record the time when the axis changes from neutral to a direction (up or down) and wait 0.5 seconds or so before changing current. Otherwise when you move up or down it'll flip through the buttons very quickly. If the axis returns to neutral before the 0.5 seconds elapse, move immediately. This allows the user to quickly tap the axis to move between buttons. Check Event.current and set axis to -1 or +1 based on other navigation keys that you define. By default WASD and the arrow keys already set the Horizontal Vertical axes, so you don't need to handle those specially. Instead of comparing the axis value to zero, give it a threshold. Some gamepads might be misaligned and register neutral as 0.001f or so. Note that the code above allows Unity GUI to click buttons using its hard-coded built-in handling of KeyCode.Space to click the currently-focused button, or when button "Fire1" is pressed. You could also check Event.current for a different trigger key.