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!
Related
New to coding here, setting up a UI in unity and having a visual issue where the back button appears until I hit options and back on the start up page, any reccomendations for a fix?
Image showing back button behind the quit button
Settings of the image on the right
You can use Gameobject.setactive(true/false) and try to manage the panel by making empty game object inside UI Canvas and name it as a panel so the whole button became a child and you can easily manage it
for example like this one
public Gameobject startPanel;
public Gameobject optionPanel;
public void Startpnl()
{
//deadActive optionPanel and Activate startPanel
startPanel.setActive(true);
optionPanel.setActive(false);
}
public void optionpnl()
{
//deadActive starPanel and Activate OptionPanel
startPanel.setActive(false);
optionPanel.setActive(true);
}
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 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.
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);
}
}
}
I am creating a small application which is instantiated by a client. In my application I have 2 classes MessageQueueSingleton.cs and DataObject.cs
MessageQueueSingleton is a singleton class which contains a static Dictionary of the objects of DataObject class. MessageQueueSingleton has some methods which will manipulate the attributes of the DataObject class according to the instructions from the client.
My problem is I also need a Unity GUI which can call few methods of MessageQueueSingleton, i.e. if I press a button on UI, a method will be called from the MessageQueueSingleton.
I am new to unity programming and I tried to look the examples which shows how to connect scripts to buttons, but I still can't see my method in the "Inspector" onClick() section. I am using Unity 5.5.1f1
Any small example or link describing the process to do it would be helpful.
Thanks.
On your GameObject with a Button component you can add a script component with the following code to set up a listener and method for that button:
void Start() {
var button = GameObject.Find("GameObjectWithMyButton").GetComponent<Button>();
button.onClick.AddListener(MyMethod);
}
void MyMethod() {
// Do something when button is clicked.
}
And if you want to drag & select it in the inspector, make sure the methods you want to select in the inspector button onclick GUI thing are public methods! To make the public methods of a script shows up in the Inspector Button Onclick GUI you place the script on a GameObject then drag that object to the button onclick GUI and select them from the dropdown. They won't show unless they're public methods. (public void DoSomething() { })