How do I get the text from a button after clicking it? - c#

I am trying to get the text of the button clicked to compare it to a string.
public void clicked()
{
Debug.Log("Timer done");
secondsLeft = 0;
timerOn = false;
questionUI.SetActive(false);
Paused = false;
//turns off the question screen
string answer = GetComponentInChildren<TMPro.TMP_Text>().ToString();
if (questions[0] == answer)
{
PlayerQuests.points += 1000;
}
}
This is the code I made which the button runs after being clicked. This should get the text inside the button which is a TextMeshProUGUI and compare it to another string.

If you add using TMPro; at the top of your class, you should be able to get the text of the TextMeshProUGUI component by writing:
var answer = GetComponentInChildren<TextMeshProUGUI>().text;

Related

Only use button every few seconds in Unity [duplicate]

This question already has answers here:
How to make the script wait/sleep in a simple way in unity
(7 answers)
Closed 1 year ago.
I am trying to make it so that a button in Unity that can only be pressed and activated every few seconds. I have an array with famous quotes and when I press my button it does display these quotes, but if you press the button continuously then it will cycle through all of the quotes without the ability to be thoughtful and read through them. Now, I have tried something like below, but it did nothing (as in the button still was able to be pressed and no effect was apparent):
Bool pressed;
void Function () {
if (pressed) {
//code to call array
}
}
I thought that a simple combination of bool and an if loop would be sufficient, but this does not work. Am I close to this concept? What would need to be changed to get this operating?
There are a few things you can do to achieve this. Your current code is never toggling the bool pressed. You can just catch the unwanted button presses with a localized bool like you are doing now, but there might be a better approach.
I would consider changing the intractability of the button to also show the end-user that they can not press the button for a short amount of time.
using UnityEngine.UI;
// button that will be pressed
[SerializeField] private Button btn = null;
// time until the button is re-enabled after being pressed
private float timeToWait = 5f;
// reference to the coroutine that toggles our button
private Coroutine buttonDisabled = null;
private void Start()
{
// you can either add the OnClick in the inspector, or you can programmatically add it here
btn.onClick.AddListener(ClickButton);
}
public void ClickButton()
{
// if we have an ongoing coroutine do not start another
if(buttonDisabled != null)
return;
// start our coroutine to re-enable the button
buttonDisabled = StartCoroutine(DisableButtonForSeconds(timeToWait));
// put any other code needed here such as displaying a new quote
}
private IEnumerator DisableButtonForSeconds(float seconds)
{
// disable the button
btn.interactable = false;
// wait for our amount of time to re-enable
yield return new WaitForSeconds(seconds);
// re-enable the button
btn.interactable = true;
// reset our reference to be called again
buttonDisabled = null;
}
Assign the button in the editor to btn and set whatever time you want to wait between button presses for timeToWait. You will also need to assign the button's OnClick to ClickButton, either in code or in the inspector. With this solution the function will not be able to be called as the button itself will be grayed out and not be able to be clicked. After the timeToWait duration is over, the button will reactivate. Place whatever other code you need in the ClickButton method that drives your quote cycling.
Edit: Here is similar code but using an Invoke instead of Coroutine as requested
using UnityEngine.UI;
// button that will be pressed
[SerializeField] private Button btn = null;
// time until the button is re-enabled after being pressed
private float timeToWait = 5f;
private void Start()
{
// you can either add the OnClick in the inspector, or you can programmatically add it here
btn.onClick.AddListener(ClickButton);
}
public void ClickButton()
{
// do not start the function if we are already in the process
if (IsInvoking("ReEnableButton"))
return;
// disable our button interactability
btn.interactable = false;
// call our function ReenableButton in timeToWait seconds
Invoke("ReEnableButton", timeToWait);
}
private void ReEnableButton()
{
// re-enable the button
btn.interactable = true;
}
Edit 2: There are a few ways you can go about having one button disable all four buttons. In general practice, you do not want these buttons knowing about each other, so it would be a good idea to make a button manager that handles the OnClick now and sends the event to all Buttons it knows about.
using UnityEngine.UI;
public class ButtonManager : MonoBehaviour
{
// assign these button references in the inspector by dragging them into the list
[SerializeField] private List<YourButtonScript> YourButtons = new List<YourButtonScript>();
private void Start()
{
// assign the onClick of each button here INSTEAD of the Start() in the button class
// you can still have an onClick in the Button itself, but do NOT have it do the disabling
foreach(YourButtonScript btn in YourButtons)
{
// assign our onClick to callback to disable all buttons
btn.SetDisableOnclick(DisableAllButtons);
}
}
public void DisableAllButtons()
{
foreach(YourButtonScript btn in YourButtons)
btn.DisableButton();
}
}
public class YourButtonScript : MonoBehaviour
{
using UnityEngine.UI;
// button that will be pressed
[SerializeField] private Button btn = null;
// time until the button is re-enabled after being pressed
private float timeToWait = 5f;
// reference to the coroutine that toggles our button
private Coroutine buttonDisabled = null;
public delegate void DisableButtonCallback();
public void SetDisableOnclick(DisableButtonCallback callback)
{
// add the callback to the manager
btn.onClick.AddListener(delegate{callback();});
}
private void Start()
{
// do NOT call the ClickButton anymore from here as the manager handles it
// if you have other button specific data put it in HandleSpecificButtonQuoteData() now
btn.onClick.AddListener(HandleSpecificButtonQuoteData);
}
private void HandleSpecificButtonQuoteData()
{
// put whatever code here that is specific to JUST this button
// if it handles the quotes or what not, display it here
}
public void DisableButton()
{
// if we have an ongoing coroutine do not start another
if(buttonDisabled != null)
return;
// start our coroutine to re-enable the button
buttonDisabled = StartCoroutine(DisableButtonForSeconds(timeToWait));
}
private IEnumerator DisableButtonForSeconds(float seconds)
{
// disable the button
btn.interactable = false;
// wait for our amount of time to re-enable
yield return new WaitForSeconds(seconds);
// re-enable the button
btn.interactable = true;
// reset our reference to be called again
buttonDisabled = null;
}
}
Let me know if you have issues with this.

Any clues on this Unity code not working?

I have this function here to duplicate a UIPanel(Prefab) and its components. It duplicates, then succesfully assigns a objectname and enable/disable the Interactable setting of the button component. But the part where it sets the ''OnClick'' on my button does not work. I dont understand as I can play with other options of this button component...
Yes the function Click exists.
Yes I included my using using System.Collections.Generic; using UnityEngine.UI;
Any Help? Thanks.
public Text Title;
public Button Btn;
public void CreateEventSquares(string keyval, string valueval)
{
string Event = (keyval);
string Link = (valueval);
Debug.Log("Event :" + Event + "Link is :" + Link);
NewPanel = Instantiate(Event0);
NewPanel.transform.SetParent(EventPanel.transform);
NewPanel.transform.localScale = new Vector3(1.0f, 1.0f, 1.0f);
NewPanel.name = keyval;
//Sets the button action to trigger Click function (Not Working)
Btn = NewPanel.GetComponent<Button>();
Btn.onClick.AddListener(Click);
Btn.interactable = false;
//Sets the title same as keyval (This Works)
Title = NewPanel.GetComponentInChildren<Text>();
Title.text = keyval;
}
Click
public void Click()
{
//do This
}
I've re-created this in Unity with your code and it's working perfectly fine for me! I think it's highly likely you are being thrown by the fact that the function is not showing up in the on click portion of the button in the Unity Inspector.
Try putting a debug.log in your click function and see what happens.
If you wanted to still define functions in the inspector you would have to use a Unity Event and then subscribe it to the onclick.
[Serializable]
public class ButtonClickedEvent : UnityEvent { }
[SerializeField]
public ButtonClickedEvent m_OnClick = new ButtonClickedEvent();
Btn.onClick.AddListener(Click);
void Click ()
{
m_OnClick.Invoke();
}

How do I close a UI element when a tap occurs outside of it?

There are a lot of solutions to this problem floating around, but none of them seem to work properly for me. I have a button that opens a list of selections in a UI element, and I want it to close when clicked outside of it. I currently have this:
private void OnEnable()
{
EventSystem.current.SetSelectedGameObject(gameObject);
}
public void OnDeselect(BaseEventData eventData)
{
//Close the Window on Deselect only if a click occurred outside this panel
if (!mouseIsOver)
gameObject.SetActive(false);
}
public void OnPointerEnter(PointerEventData eventData)
{
mouseIsOver = true;
EventSystem.current.SetSelectedGameObject(gameObject);
}
public void OnPointerExit(PointerEventData eventData)
{
mouseIsOver = false;
EventSystem.current.SetSelectedGameObject(gameObject);
}
Which works fine on a PC, but unfortunately due to there not being an actual pointer on mobile, it closes the panel even if clicked inside. I have tried using something like this:
foreach (Touch touch in Input.touches)
{
int id = touch.fingerId;
if (EventSystem.current.IsPointerOverGameObject(id))
{
isClicked = true;
}
if (Input.GetMouseButtonDown(0))
{
// Check if the mouse was clicked over a UI element
if (EventSystem.current.IsPointerOverGameObject())
{
isClicked = true;
}
}
}
But that has not worked either. This seems like an incredibly simple problem and I don't understand why I can't find a simple solution to it.
I recomend using Unity technic when dropdown is created.
Look at this link
The main idea is to create blocker behind your button and the other ui elements.
Your open panel funcion should look something like this:
private RectTransform gameObjectTransform;
public void OpenPanel()
{
CreateBlocker();
gameObjectTransform = transform.parent;
transform.SetParent(GetComponentInParent<Canvas>());
transform.SetAsLastSibling();
}
Create blocker method like in docs:
private GameObject currentBlocker;
public void CreateBlocker()
{
GameObject gameObject = new GameObject("Blocker");
RectTransform rectTransform = gameObject.AddComponent<RectTransform>();
rectTransform.SetParent(ChatGraphics.Instance.mainCanvas, false);
rectTransform.anchorMin = (Vector2)Vector3.zero;
rectTransform.anchorMax = (Vector2)Vector3.one;
rectTransform.sizeDelta = Vector2.zero;
Canvas canvas = gameObject.AddComponent<Canvas>();
canvas.overrideSorting = true;
canvas.sortingLayerID = component.sortingLayerID;
canvas.sortingOrder = component.sortingOrder - 1;
gameObject.AddComponent<GraphicRaycaster>();
gameObject.AddComponent<Image>().color = Color.clear;
gameObject.AddComponent<Button>().onClick.AddListener(delegate { Hide(); });
currentBlocker = gameObject;
}
And last is Hide method which should be called every time (even if blocker does not triggered)
public void Hide()
{
if (currentBlocker != null)
Destroy(currentBlocker);
if (gameObjectTransform != null)
transform.SetParent(gameObjectTransform);
// Your code to hide your panel
}

How do I save and load the value of a text in Unity? [duplicate]

This question already has answers here:
What is the best way to save game state?
(2 answers)
Closed 3 years ago.
I have a code where there is an experience bar, and below it there is a level textbox and an experience textbox. Here is the code:
public Slider barraExperiencia;
public Button botonManzana;
public Text txtNumeroNivel, txtNumeroExperiencia;
void Start()
{
barraExperiencia.value = PlayerPrefs.GetFloat("Experiencia");
nivel = PlayerPrefs.GetFloat("Nivel");
botonManzana.onClick.AddListener(ButtonAlimentoClicked);
}
void Update()
{
PlayerPrefs.SetFloat("Experiencia", barraExperiencia.value);
PlayerPrefs.SetFloat("Nivel", nivel);
txtNumeroExperiencia.text = barraExperiencia.value.ToString() + "/" + barraExperiencia.maxValue.ToString();
if (barraExperiencia.value >= barraExperiencia.maxValue)
{
barraExperiencia.value = 0;
nivel += 1;
txtNumeroNivel.text = nivel.ToString();
barraExperiencia.maxValue += 100;
}
}
void ButtonAlimentoClicked()
{
barraExperiencia.value += 10;
}
In the code, when the button botonManzana is pressed, it increases the value of the bar. When the value of the bar reaches its max value, it returns to 0 and the variable nivel (the level) is increased.
I want to save and load the value of the bar and "nivel", and I have done it with PlayerPrefs like it's shown in the code, but it doesn't work. If someone can help me, please.
You need to call Save() to save your changes on PlayerPrefs. See https://docs.unity3d.com/ScriptReference/PlayerPrefs.html
It might not be called automatically if OnApplicationQuit is not called, e.g. if your application is a WebGL app. See https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnApplicationQuit.html for more info.

c# panel image only updates half the time

For my programming class we are required to make a memory match game. When the player clicks on a panel an image is displayed. The player clicks on two panels, if the images match they are removed, if they are different they are turned face down.
The problem I am having with this is that only the image from the first panel gets displayed, even though I am using the same line of code to display the images from both panels, and use Thread.Sleep to pause the program after the second tile has been picked. I don't understand why this is happening, any help would be appreciated.
private void tile_Click(object sender, EventArgs e)
{
string tileName = (sender as Panel).Name;
tileNum = Convert.ToInt16(tileName.Substring(5)) - 1;
//figure out if tile is locked
if (panelArray[tileNum].isLocked == false)
{
pickNum++;
//although the following line of code is used to display the picture that is stored in the tile array
//what is happening is that it will only display the picture of the first tile that has been picked.
//when a second tile is picked my program seems to ignore this line completely, any ideas?
panelArray[tileNum].thisPanel.BackgroundImage = tiles[tileNum].tileImage;
if (pickNum == 1)
{
pick1 = tileNum;
panelArray[tileNum].isLocked = true;
}
else
{
pick2 = tileNum;
UpdateGameState();
}
}
}
private void UpdateGameState()
{
Thread.Sleep(1500);
if (tiles[pick1].tag == tiles[pick2].tag)//compares tags to see if they match.
{
RemoveTiles();
}
else
{
ResetTiles();
}
pickNum = 0;
guess += 1;
guessDisplay.Text = Convert.ToString(guess);
if (correct == 8)
{
CalculateScore();
}
}
try this:
(sender as Panel).BackgroundImage = tiles[tileNum].tileImage;
you have to be sure that your tile_Click method is associated to both panel...

Categories

Resources