I have a fadepanel gameobject in my scene that has to sit on top of all the other gameobjects. However, when I click on an object int the editor window, since this gameobject is on top of all, is the one that is automatically selected in the hierarchy.
Is there a way to keep the gameobject on top of the canvas, as it is right now, but make it completely unselectable wIen i click on my scene?
You can use HideFlags on gameobject to make it unselectable:
public class HideFlagsSetter : MonoBehaviour
{
public Component target;
public HideFlags customHideFlags;
public enum Mode
{
GameObject,
Component
}
public Mode setOn = Mode.GameObject;
[ContextMenu("Set Flags")]
private void SetFlags()
{
if (setOn == Mode.GameObject)
{
target.gameObject.hideFlags = customHideFlags;
}
else if (setOn == Mode.Component)
{
target.hideFlags = customHideFlags;
}
}
}
Setting customHideFlags to HideInHierarchy would make it disappear from hierarchy so you won't be able to select it.
Edit: As the object will disappear, there is no way to bring it back if you can't access the script. So this script should be attached to a persistent object and target object should be set in the inspector.
You can use Context menu option by clicking on the gear icon in the top right corner and choose "Set Flags". its the last option in the menu.
Read more
Hope this helps :)
(ADDED BY PERSON WHO ASKED THE QUESTION)
I wanted a way for this to automagically happen on editor mode. So i did the same steps, but i changed the script a bit to work on Editor mode. I added [ExecuteInEditMode] on top of the class and also added an Awake() method that executes the same code as in SetFlags. Seems to work just fine.
Related
I'm looking for a way to add a dropdown box to the OnClick editor in the inspector (circled in the image below)
I would like the dropdown to be populated by a custom enum.
Is this possible at all or do I need to find another way to do this?
Goal:
Have an enum of audio clips and be able to assign a clip to a button all from the inspector without having to go into the code.
Assuming you know how the editor and C# script interface with each other I would simply use:
public static bool DropdownButton(GUIContent content, FocusType focusType, params GUILayoutOption[] options);
More info can be found here: https://docs.unity3d.com/ScriptReference/EditorGUILayout.DropdownButton.html
It is currently not supported and is not that easy to code yourself. It would require some deep hacks into the source code of UnityEventDrawer and UnityEventBase and kind of reproducing the entire UnityEventDrawer (source is avalable though ...)
However there is a very simple workaround (at least if every Button shall playback exactly one sound)
Have a separate component like
[RequireComponent(typeof(Button))]
public class PlayASound : MonoBehaviour
{
// reference via inspector
[SerializeField] private AudioSelector _audioSelector;
// your enum type here
public AudioMessageType MessageType;
public void Play()
{
_audioSelector.PublishAudioMesssage(MessageType);
}
private Button _button;
private void Awake()
{
_button = GetComponent<Button>();
if (!_button)
{
Debug.LogError("No Button found on this GameObject!", this);
return;
}
_button.onClick.AddListener(Play);
}
// Just to to be sure
// usually the button should be destroyed along with this component
// anyway ... but you never know ;)
private void OnDestroy()
{
_button.onClick.RemoveListener(Play);
}
}
attach it to the same GameObject as the Button component, select the according enum value there, done. The Listener to onClick will not appear in the Inspector but will be added on runtime.
If you prefer to add it manually (I sometimes prefer to have it visible) then simply remove the Awake and OnDestroy and rather drag it in manually as usual and select the Play method.
I'm developing a game and I've reached a stage in which I need to dynamically create a list of buttons.
My approach was to create a scroll view and then add the buttons through scripting.
I've already created the button prefab. This button purpose is to open a specific link outside the application, so I created the button prefab with two text components: One saying "Show Path" which is what I want the buttons to show, and the other text component is the link I need to open, which isn't visible to the user.
I'm running into several problems:
I need to create the buttons as I am going through a list of user data. I display the data right beside the button, in another scroll view, correctly. However, only one button is created.
I'm unable to access the prefab link text component to change it to the link I need to open.
Thank you for your time!
What I'd recommend you do is create your own class to handle this, so it's easier to visualise in the inspector.
[System.Serializable]
public class RelevantClassName
{
public string link = "http://defaultbackuplink";
public string text = "Default content";
[Space]
public Transform button;
public Transform contentHolder;
}
And in a seperate class, you use this information to generate your scroll views and buttons:
public class UIController : MonoBehaviour
{
public List<RelevantClassName> contentToDisplay;
[Header("References"]
public Transform buttonParent;
public Transform contentParent;
public GameObject buttonPrefab;
public GameObject contentPrefab;
public void DisplayUI()
{
foreach(RelevantClassName content in contentToDisplay)
{
content.contentHolder = Instantiate(contentPrefab, contentParent);
content.button = Instantiate(buttonPrefab, buttonParent);
// And here you can run any custom changes, for example finding a text
// component on the content holder and changing the description:
content.contentHolder.GetComponent<Text>().text = content.text;
}
}
Naturally I heavily advise you use a pooling system, and if you're planning to access a component, cache it in that class.
Hope this helps!
I'm developing a simple game in Unity 2017 in C#.
In my levels menu I have a Text object with a button component in it, and a script attached to it.
This is what's currently in the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LevelLock : MonoBehaviour {
public bool isLocked = true;
private Button lvlBtn;
// Use this for initialization
void Start () {
lvlBtn = GetComponent<Button> ();
if (lvlBtn != null) {
Debug.Log ("this should be working");
} else {
Debug.Log ("you did something wrong");
}
//if(isLocked){
// lvlBtn.enabled = false;
//}
}
}
The problem is, that GetComponent<Button>() is returning null, meaning it's not finding the button component in the object.
I tried adding an Animator component and perform the same operation just to check and it did work, so I have no clue why it shouldn't find the button component. If anyone could help with this or point out to me something i'm doing wrong, I would really appreciate it
EDIT:
Inspector tab:
Console tab:
Your screenshot shows that you attached the LevelLock script to the Button which is fine.
Possible reasons and fixes:
1.The component/script is not even attached to the GameObject or is attached to the wrong Object.
In, your code, calling GetComponent<Button>(); without finding the GameObject first means that GetComponent should look for a Button component that is attached to this GameObject this script(LevelLock) is attached to.
If the script you want to retrieve, is attached to another GameObject, you can solve this by first, finding the GameObject the Button component is attached to with GameObject.Find then retrieving the Button component/script from it.
Replace
lvlBtn = GetComponent<Button> ();
with
GameObject obj = GameObject.Find("lvl 2");
lvlBtn = obj.GetComponent<Button>();
3.Script is attached to multiple Objects
One of the reasons GetComponent<Button>() might return false is because you mistakenly attached the LevelLock script to another GameObject. It could be an empty GameObject but that GameObject doesn't have the Button component attached to it.
Find this GameObject and remove the LevelLock script from it.
To do that, select the LevelLock script from the Project tab then Go to Assets ---> Find References In Scene. Remove the LevelLock script from other GameObjects.
This will make sure that the LevelLock script is only attached to the "lvl 2" GameObject
3.Multiple scripts with the-same name but in different namespace:
If you have two classes with the-same name but in different namespace and you attached one to the GameObject while trying to access the other one from code, it will be null since they are not the-same. I looked into your project and this was the Problem.
You created a script named "Button" while Unity comes with it's own built-in script/component also named "Button" which is in the UnityEngine.UI namespace.
You attached the Unity's built-in "Button" script to your GameObject but then you are trying to access your own made "Button" script from the script. Supply the namespace which is UnityEngine.UI so that Unity will know that you want to use the Button component that comes with Unity.
Change:
vlBtn = GetComponent<Button> ();
to
lvlBtn = GetComponent<UnityEngine.UI.Button>();
Also change:
private Button lvlBtn;
to
private UnityEngine.UI.Button lvlBtn;
Finally, do not name your script the-same name as any built-in component like Button, Image, Text, Rigidbody and so on. Create a class name and make sure that it doesn't exist with Unity API otherwise you'll continue to run into such issues and even people on SO won't be able to help you unless they have access to your project.
I'm Working on a game, and i want to create a mute button. So i wrote a script for that and i attach this script into a gameObject that don't destroy on load.
I link the script with a UI Button present in a main menu. This UI button is destroy when i'm changing scenes.
when i start my game, and i click on the button, the audio turns off, and when i click back, it turns on.
But when i change to another scene, and i go back to the main menu, my script doesn't have the UI Button attach to it. so when i touch the button the audio doesn't change is behavior
I would like to know if it's possible to maintain the link between the UI Button and the script (attach to a normal GameObject), even if the UI Button is destroyed?
i tried this:
ButtonGameObject = GameObject.Find("UI Button");
but it doesn't work.
How can i fix that?
Thanks a lot.
There are many ways to work around this, but here's one:
Step 1: If you haven't already done so, implement a weak singleton pattern on your mute script (let's call it MuteScript.cs for now).
private static MuteScript singleton {get; private set;}
private void Awake() {
if (singleton == null) singleton = this;
[whatever other stuff you were already doing in Awake()]
}
public static void ToggleMute(Graphic graphic)
{
singleton._ToggleMute(graphic);
}
private void _ToggleMute(Graphic graphic)
{
[whatever code you were running in your original mute method]
}
Step 2: Attach a simple script to your UI button:
public class MuteButton: MonoBehaviour
{
Graphic myGraphic;
private void Awake() {
myGraphic = GetComponent<Graphic>();
}
public void OnClick() {
MuteScript.ToggleMute(myGraphic);
//I assume you want to do something like change the colour of the button when
//the player toggles it. Passing the Graphic to the MuteScript is the easiest
//way of doing this. If you really want to keep your code clean, though,
//I recommend expanding the MuteButton class with methods to take care of
//the UI side of things.
}
}
Step 3: In Unity Editor, setup your button to call its own OnClick() method, not the MuteScript method.
-
Now when you click the button, it will call the static MuteScript.ToggleMute(), which accesses the static-cached singleton reference, which in turn points back to your original object.
Singletons and static accessors are great for efficiency in Unity because they save you from having to call expensive search functions like FindObjectsOfType(). The only gotcha is that you have to be careful about not having multiple copies of a singleton-class object lying around, especially when using DontDestroyOnLoad().
So a better approach rather than having a script search and grab the component is to use a PlayerPrefs class from Unity. Essentially, it will hold onto all important aspects of the game and auto fill information.
This is a great tool for a lot of user customization aspects of a game. When using this, have a script (sceneController would be a good name) that will run when the scene starts (create a blank object at 0,0,0) and then under void Start() have the script grab the mute/unmute button: GameObject.Find("MuteButton") or (my favorite) give it a tag called MuteButton and run: GameOject.FindWithTag("MuteButton"). Also once you get a link to the button, add a listener to it for when the button is pressed.
Also store the sound manager in a gameController that will be passed throughout the game. This would control the soundManager and have access to that. So sceneManager will also need a reference to gameManager.
Using a script that is just for player preferences (a controller if you will) is a better way to organize and contain any preferences for the users. Just better clarity and separation.
Example
SceneController Object Script
class SceneController {
GameObject muteButton;
void Start() {
muteButton = GameObject.FindWithTag("muteButton");
muteButton.AddListener(muteButtonCheck);
}
void muteButtonClick() {
if (PlayerPrefs.GetInt("playerMute")) {
// If 1 (on)
// Set sound off
PlayerPref.SetInt("playerMute", 0);
} else {
// It's 0 (off)
// Set sound on
PlayerPrefs.SetInt("playerMute", 1);
}
}
}
So, i have buttons for my game that include : Main Menu button , Restart button and Play button. Everything works fine, but occasionally one of the button's text doesn't load , one of them doesn't work. I'm not sure how to fix this, because it happens randomly and not every time.
The code for the buttons :
GameObject[] pauseObjects;
void Start()
{
Time.timeScale = 1;
pauseObjects = GameObject.FindGameObjectsWithTag("ShowOnPause");
hidePaused();
}
public void showPaused()
{
foreach (GameObject g in pauseObjects)
{
g.SetActive(true);
}
}
public void hidePaused()
{
foreach (GameObject g in pauseObjects)
{
g.SetActive(false);
}
}
public void LoadLevel(string level)
{
Application.LoadLevel(level);
}
public void pauseControl()
{
if (Time.timeScale == 1)
{
Time.timeScale = 0;
showPaused();
}
else if (Time.timeScale == 0)
{
Time.timeScale = 1;
hidePaused();
}
}
The way your UI is setup is not right. If you have to loop through everything during pause, you are doing it wrong. I have answered a similar question before and will just copy and paste this here.
Use different Canvas to separate your UI and group them depending on when they are displayed. Then you can toggle the whole Canvas on/off. Your [post][1] before this post shows that you are using image as button and you have a different script attached to two images you are using as buttons. Use Buttons for buttons and image for non-clickable objects. Simple as that. So change those images to buttons.
You don't need the GameOver scene. A GameOverCanvas is fine.
The GameObjects in bold are the parent Objects(Canvas). The ones under that starts with '-' are the child GameObjects.
Step 1:
Create Canvas and name it MainMenuCanvas (First UI to display when game Loads).Create each child button and rename them as below(GameObject->UI->Button):
-playButton;
-settingsButton;
-exitGameButton;
Attach the MainMenuCanvas script to the MainMenuCanvas Object.
Step 2:
Create a Canvas and name it GameCanvas (Displayed during game).Create each child button and rename them as below(GameObject->UI->Button):
-pauseButton
-jumpButton
Attach the GameCanvas script to the GameCanvas Object.
Step 3:
Create a Canvas and name it PauseCanvas (Displayed when pause button is clicked).Create each child button and rename them as below(GameObject->UI->Button):
-resumeButton;
-backToMainMenuButton;
-settingsButton;
-exitGameButton;
Attach the PauseCanvas script to the PauseCanvas Object.
Step 4:
Create a Canvas and name it SettingsCanvas (Displayed when settings button is clicked).Create each child button and rename them as below(GameObject->UI->Button):
-backButton;
Attach the SettingsCanvas script to the SettingsCanvas Object.
Step 5:
Create a Canvas and name it GameOverCanvas (Displayed when Game is Over or player is killed).Create each child button and rename them as below(GameObject->UI->Button):
-playAgainButton;
-backToMainMenuButton;
-exitGameButton;
Attach the GameOverCanvas script to the GameOverCanvas Object.
Step 6:
In the Game scene, make sure that only GameCanvas is enabled. The rest of the canvas should be manually disabled.
Step 7:
In the Menu scene, make sure that only MainMenuCanvas is enabled. The rest of the canvas should be manually disabled.
Once you get this setup correctly, the UI code templates I provided should work. No more UI overlapping or text disappearing. You can easily add or remove features.
Your UI setup should look like the image below.