I’m learning Unity and C# and need some assistance. I have a Gui Menu created and I only want it to show up when I click on the object? Then I have buttons on the Gui, how do get the button to run another script to create another Gui Menu?
Thanks in advance, I’m hoping with this help I can start getting my game working.
For the first part, you can use OnMouseEnter() and Input.GetMouseButtonDown(). There are many ways to do this, but a simple one is to create a selector class with a static variable that keeps track of what’s under the mouse cursor:
public class Selector : MonoBehaviour {
public static Clickable target = null;
void Update() {
const int LeftMouseButton = 0;
if (Input.GetMouseButtonDown(LeftMouseButton)) {
if (target != null) target.Click();
}
}
}
Add Selector to an object in your scene. Then make sure your object has a collider and create a Clickable class that implements OnMouseEnter():
public class Clickable : MonoBehaviour {
void OnMouseEnter() {
Selector.target = this;
}
void OnMouseExit() {
Selector.target = null;
}
public virtual void Click() {}
}
Add this to your object. You could modify Selector to give the user feedback that the mouse is hovering over a Clickable, such as adding a glow effect, or showing some GUI label.
Implement Click() to actually open the menu, such as:
public class ClickableMenu : Clickable {
private bool showMenu = false;
public override void Click() {
showMenu = true;
}
void OnGUI() {
if (showMenu) {
// draw your menu
}
}
}
If you want to position the menu over the object, use Camera.WorldToScreenPoint() to translate the object’s world position into a GUI screen position.
For the second part, you can modify ClickableMenu to keep track of which menu to show:
public class ClickableMenu : Clickable {
private enum Menus { None, Menu1, Menu2, Menu3 }
private Menus menu = Menus.None;
public override void Click() {
if (menu == Menus. None) menu = Menus.Menu1;
}
void OnGUI() {
switch (menu) {
case Menus.Menu1:
// draw menu 1
if (GUILayout.Button("Open Menu2")) menu = Menus.Menu2;
break;
case Menus.Menu2:
// draw menu 2
break;
}
}
}
Ok I got the first part running. Now I don’t understand the second. Do I replace my Gui.Buttton , with the Guilayout.button? Then how do I tell it to run the script for the menu that the button is suppose to bring up and also close the open one? I’ve tried a few different things and nothing worked.
What I want to happen is when I press one of the buttons a new menu pops up and the old menu closes.
edit: figured out how to close the old menu: Destroy(this); Works like a charm.
You can use GUI.Button or GUILayout.Button, whatever works best for you.
The example code I posted assumed that all menus would be in the same script, and the active menu would be specified by the value of the variable menu. They way you’re doing it – in separate scripts – is fine, too.
Wouldn’t it be easier to just enable/disabled the various menu script he has ?
Here’s a simple example with a working chaining workflow
1/ a base class for the GUI script:
using UnityEngine;
using System.Collections;
public class ChainingScript: MonoBehaviour
{
public MonoBehaviour _parent;
protected void ReturnToParent()
{
//call this.ReturnToParent() from derivated scripts when you want to close this one and re-activate the parent, wether it's a gui or a click script...
this._parent.enable = true;
this.enabled = false;
}
}
2/ That you can use this way :
using UnityEngine;
using System.Collections;
public class YourGUIScript: ChainingScript
{
void OnGUI()
{
//put your GUI here
//And when you're done here: (for example)
if (GUILayout.Button("close"))
this.ReturnToParent();
}
}
3/ And a trigger for the clickable object:
using UnityEngine;
using System.Collections;
public class ClickActivator : MonoBehaviour
{
public ChainingScript _target;
void OnMouseDown()
{
this._target._parent = this;
//This way you can toggle a script on/off with your clicks
this._target.enabled = !this._target.enabled;
/* Or another way to always turn on if you want to disable this feature (until the other reactivates this one for example) :
this._target.enabled = true;
this.enabled = false;
*/
}
}
As the very first button drawn, create an invisible GUI.Button that fills the whole screen. When clicked, close the menu. To make the button invisible, use a GUI Style without a background, such as the default GUI.skin.label, and use a single blank character for the button text.
Okay I’m trying to implement this and when I draw my menu and and check my code, it says warning unreachable code. Here’s what I have:
case Menus.Menu2:
// draw menu 2
GUI.Box( new Rect(626, 215, 371, 453), "text" );
someTextFieldebugStringing0 = GUI.TextField( new Rect(640, 244, 345, 52), someTextFieldebugStringing0, 28 , textfield );
if ( GUI.Button( new Rect(711, 315, 198, 52), "text1" ) ) menu = Menus.Menu2a;
break;
case Menus.Menu2a:
//Required Variables:
int someSelectionGridInteger0 = 0;
//This array is the labels for each button in the selection grid
string[] someStringArray0 = new string[4] { "x", "x", "x", "x" };
GUI.Box( new Rect(205, 62, 485, 464), "text2" );
someSelectionGridInteger0 = GUI.SelectionGrid( new Rect(247, 99, 395, 84), someSelectionGridInteger0, someStringArray0, 4 );
break;
if ( GUI.Button( new Rect(711, 465, 198, 52), "S" ) )
if ( GUI.Button( new Rect(711, 390, 198, 52), "T" ) )
if ( GUI.Button ( new Rect (915, 630, 75, 32), "next") )
}
}
}
It’s telling me line 23, the button “S”, is unreachable(it doesn’t show up, when I check). How do I get my other buttons to show up after I create the menu that each button will create?
In case Menus.Menu2a, the break statement will cause execution to leave the switch statement, which means case Menus.Menu2a will never run the 3 GUI.Button statements below break. If you want to run these as part of Menus.Menu2a, put the break statement after the 3 GUI.Button statements.
If, however, you want to run the 3 GUI.Button statements after the entire switch statement, you need to close the switch statement with a right brace after break:
case Menus.Menu2a:
//Required Variables:
int someSelectionGridInteger0 = 0;
//This array is the labels for each button in the selection grid
string[] someStringArray0 = new string[4] { "x", "x", "x", "x" };
GUI.Box( new Rect(205, 62, 485, 464), "text2" );
someSelectionGridInteger0 = GUI.SelectionGrid( new Rect(247, 99, 395, 84), someSelectionGridInteger0, someStringArray0, 4 );
break;
} // <--- ***** Add this. *****
if ( GUI.Button( new Rect(711, 465, 198, 52), "S" ) )
if ( GUI.Button( new Rect(711, 390, 198, 52), "T" ) )
if ( GUI.Button ( new Rect (915, 630, 75, 32), "next") )
}
Thanks for the reply. What I want happen is those three buttons are to be with the button that makes menu2a, when I put them before the break in the menu2 I get an error: CS0163: Control cannot fall through from one case label to another
Here’s my full code:
using UnityEngine;
using System.Collections;
public class MonitorMenus : Clickable {
private enum Menus { None, Menu1, Menu2, Menu3, Menu4, Menu2a, Menu2b, Menu2c }
private Menus menu = Menus.None;
public override void Click() {
if (menu == Menus. None) menu = Menus.Menu1;
}
//Required Variables:
string someTextFieldebugStringing0 = "";
void OnGUI() {
GUIStyle textfield = new GUIStyle(GUI.skin.textField);
textfield.alignment = TextAnchor.MiddleCenter;
switch (menu) {
case Menus.Menu1:
//draw Menu 1
GUI.Box (new Rect (660, 230, 302, 405), "C");
//menu 2 button
if (GUI.Button (new Rect (740, 308, 144, 55), "O"))
menu = Menus.Menu2;
break;
case Menus.Menu2:
// draw menu 2
GUI.Box (new Rect (626, 215, 371, 453), "N");
someTextFieldebugStringing0 = GUI.TextField (new Rect (640, 244, 345, 52), someTextFieldebugStringing0, 28, textfield);
if (GUI.Button (new Rect (711, 315, 198, 52), "G")) menu = Menus.Menu2a;
if ( GUI.Button( new Rect(711, 465, 198, 52), "S2" ) )
if ( GUI.Button( new Rect(711, 390, 198, 52), "T" ) )
if ( GUI.Button ( new Rect (915, 630, 75, 32), "next") )
break;
case Menus.Menu2a:
//Required Variables:
int someSelectionGridInteger0 = 0;
//This array is the labels for each button in the selection grid,
string[] someStringArray0 = new string[4] { "x", "x", "x", "x" };
GUI.Box (new Rect (205, 62, 485, 464), "Genre");
someSelectionGridInteger0 = GUI.SelectionGrid (new Rect (247, 99, 395, 84), someSelectionGridInteger0, someStringArray0, 4);
break;
//if ( GUI.Button( new Rect(325, 279, 144, 55), "S" )) menu = menus.Menu3;
//break;
//if ( GUI.Button( new Rect(325, 364, 144, 55), "G" )) menu = menus.Menu4;
//break;
}
}
}
As you can see in the code I have a two other buttons I have killed from menu1 for the same reason, I want those in menu1. The buttons S2, T, and next are to be in menu2. The code above gives that error code at line 46. Those buttons will also open a menu each, with other stuff in them, haven’t gotten to them yet because of this problem.
As soon as I add the buttons under the menu2b with the code it gives me the error: CS0163: Control cannot fall through from one case label to another from the switch (menu) { line. I don’t know what I’m doing wrong.
Ok, I started over, here is my new code and I still get the CS0163 error.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
//experimental monitor menu
public class MenuMonitor : MonoBehaviour {
public class MonitorMenus : Clickable {
private enum Menus { None, CMenu, N, S}
private Menus menu = Menus.None;
public override void Click() {
if (menu == Menus. None) menu = Menus.CMenu;
}
//Required Variables:
string someTextFieldebugStringing0 = "";
void OnGui() {
GUIStyle textfield = new GUIStyle(GUI.skin.textField);
textfield.alignment = TextAnchor.MiddleCenter;
switch (menu) {
case Menus.CMenu:
//CMenu menu
GUI.Box (new Rect (660, 230, 302, 405), "CMenu");
if (GUI.Button (new Rect (740, 308, 144, 55), "N"))
menu = Menus.N;
if (GUI.Button (new Rect (325, 279, 144, 55), "S"))
menu = Menus.S;
break;
case Menus.N:
//N menu
GUI.Box (new Rect (626, 215, 371, 453), "New ");
someTextFieldebugStringing0 = GUI.TextField (new Rect (640, 244, 345, 52), someTextFieldebugStringing0, 28, textfield);
if (GUI.Button (new Rect (711, 315, 198, 52), "G"))
if (GUI.Button (new Rect (711, 390, 198, 52), "T"))
break;
case Menus.S:
//S menu
GUI.Box (new Rect (626, 215, 371, 453), "S");
someTextFieldebugStringing0 = GUI.TextField (new Rect (640, 244, 345, 52), someTextFieldebugStringing0, 28, textfield);
if (GUI.Button (new Rect (711, 315, 198, 52), "G"))
if (GUI.Button (new Rect (711, 390, 198, 52), "T"))
break;
}
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
//experimental monitor menu
public class MenuMonitor : MonoBehaviour {
public class MonitorMenus : Clickable {
private enum Menus { None, CMenu, N, S}
private Menus menu = Menus.None;
public override void Click() {
if (menu == Menus. None) menu = Menus.CMenu;
}
//Required Variables:
string someTextFieldebugStringing0 = "";
void OnGui() {
GUIStyle textfield = new GUIStyle(GUI.skin.textField);
textfield.alignment = TextAnchor.MiddleCenter;
switch (menu) {
case Menus.CMenu:
//CMenu menu
GUI.Box (new Rect (660, 230, 302, 405), "CMenu");
if (GUI.Button (new Rect (740, 308, 144, 55), "N")) menu = Menus.N;
if (GUI.Button (new Rect (325, 279, 144, 55), "S")) menu = Menus.S;
break;
case Menus.N:
//N menu
GUI.Box (new Rect (626, 215, 371, 453), "New ");
someTextFieldebugStringing0 = GUI.TextField (new Rect (640, 244, 345, 52), someTextFieldebugStringing0, 28, textfield);
if (GUI.Button (new Rect (711, 315, 198, 52), "G")) menu = Menus.CMenu;
if (GUI.Button (new Rect (711, 390, 198, 52), "T")) menu = Menus.CMenu;
break;
case Menus.S:
//S menu
GUI.Box (new Rect (626, 215, 371, 453), "S");
someTextFieldebugStringing0 = GUI.TextField (new Rect (640, 244, 345, 52), someTextFieldebugStringing0, 28, textfield);
if (GUI.Button (new Rect (711, 315, 198, 52), "G")) menu = Menus.CMenu;
if (GUI.Button (new Rect (711, 390, 198, 52), "T")) menu = Menus.CMenu;
break;
}
}
}
}
Notice that on lines 40-41 and 48-49, I added menu = Menus.XXX at the end of the if statement.
In your code, your lines 44-46 read as:
if (GUI.Button (new Rect (711, 315, 198, 52), "G")) {
if (GUI.Button (new Rect (711, 390, 198, 52), "T")) {
break;
}
}
which isn’t what you want.
Also, in my version above, I set the menu to Menus.CMenu because it’s not clear what “G” and “T” are supposed to open. You may need to change this to the right menu.
GUI Window tries to begin rendering while something else has not finished rendering! Either you have a recursive OnGUI rendering, or previous OnGUI did not clean up properly
These have me stumped as well.
EDIT: Got it, I fixed it. I had two public class designations at the top by accident.
So far, still working on it though. The game I’m working on is menu heavy, so I’ll most likely ask for more help. I also found the C# programming guide from Microsoft, that should help also.