How to Get UI button to Stay in a Pressed State in Unity 3D - unity3d

In Unity 3D, when you select a button, it will stay pressed until you click outside the button and basically goes back to its Normal Color. The problem is, I want the button to stay pressed (color-wise) when I click outside the button or scene. Does anyone know how to keep a button pressed or "selected" after clicking it?

You can use Unity UI Toggle (as said by Muhammad). Change the design to remove the checkmark and make it looking like a button.
With this component you have the state 'isOn' that you can use and change the color when selected for example.

public class Button_Stay_Pressed : MonoBehaviour
{
private Button btn;
[SerializeField]
private Sprite normal_sprite;
[SerializeField]
private Sprite pressed_sprite;
void Awake()
{
btn = gameObject.GetComponent<Button>();
btn.image.sprite = normal_sprite;
btn.onClick.AddListener(TaskOnClick);
}
void TaskOnClick()
{
btn.image.sprite = pressed_sprite;
}
}

Here is the C# script using delegate that'll (toggle between buttons) set clicked button to "on/pressed" (custom) colour and change the other button(s) with this script attached to them to deselect colour, Copy & paste solution(attach this script to buttons you want to toggle between):
using TMPro;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// Functionality: Control UI Button clicks selected colour
/// Author: Akrima Huzaifa
/// Date Created: 1st-December-2022
/// </summary>
public class BtnClickHandler : MonoBehaviour
{
public delegate void OnBtnClick(BtnClickHandler obj);
public static event OnBtnClick onBtnClick;
public Button poleBtn;
public Image poleImage;
private void Awake()
{
if (GetComponent<Button>())
{
poleBtn = GetComponent<Button>();
poleImage = GetComponent<Image>();
poleBtn.onClick.AddListener(delegate { OnBtnClick(); });
}
}
private void OnEnable()
{
onBtnClick += SelectDeselectBtn;
}
private void OnDisable()
{
onBtnClick -= SelectDeselectBtn;
}
public void SelectDeselectBtn(BtnClickHandler obj)
{
if (obj == this)
{
OnClick_ObjButtonSelected();
}
else
{
DeselectBtn();
}
}
public void OnBtnClick()
{
BtnClickHandler.onBtnClick.Invoke(this);
}
//---For UI---
public void OnClick_ObjButtonSelected()
{
if (!poleImage.fillCenter)
{
print("if color");
poleImage.fillCenter = true;
poleImage.color = new Color32(230, 230, 230, 255);
poleImage.transform.GetComponentInChildren<TextMeshProUGUI>().color = new Color32(255, 115, 0, 255);
}
else
{
DeselectBtn();
}
}
public void DeselectBtn()
{
print("else color");
poleImage.fillCenter = false;
poleImage.color = new Color32(178, 178, 178, 255);
poleImage.transform.GetComponentInChildren<TextMeshProUGUI>().color = new Color32(255, 255, 255, 255);
}
}

Related

How to make button image change with on click anywhere on screen?

I am very new to Unity and I have trouble understanding on click possibilities with my UI buttons etc.. In my project, I have a button which changes its image whenever I click on it and the way I made it is: I created this script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(Button))]
public class OnClickScript : MonoBehaviour
{
public static int spritenumber=1;
public Button mybutton;
public Sprite square;
public Sprite circle;
public Sprite triangle;
public int counter = 1;
void Start()
{
mybutton = GetComponent<Button>();
}
public void changeButton()
{
if (PAUSESCRIPTE.isPaused == false)
{
counter++;
if (counter == 1)
{
mybutton.image.overrideSprite = square;
spritenumber = 1;
soundmanagerscript.PlaySound("buttonpress");
}
if (counter == 2)
{
mybutton.image.overrideSprite = circle;
spritenumber = 2;
soundmanagerscript.PlaySound("buttonpress");
}
if (counter == 3)
{
mybutton.image.overrideSprite = triangle;
spritenumber = 3;
counter = counter - 3;
soundmanagerscript.PlaySound("buttonpress");
}
}
}
}
I attached this script to my button, selected sprites which I want to use and I added on On Click() function to the button.
Afterwards I decided that I no longer want to change the sprite of my button by clicking on the button itself but rather by clicking anywhere on the screen. I tried using Input.GetMouseButtonDown(0) but got no results since I used it incorrectly. Any help on, how to achieve what I want, is very welcome. Thanks in advance.
Here's how I'd do it:
using UnityEngine.UI;
using UnityEngine;
public class ButtonScript : MonoBehaviour
{
// Public objects
public Sprite[] sprites;
//Private objects/variables
private Image buttonImage;
private int spriteIndex;
void Start()
{
buttonImage = GetComponent<Image>(); // Get the image component of your button
spriteIndex = 0; // Set the index to 0
buttonImage.sprite = sprites[spriteIndex]; // Set the image to the first image in your sprite array
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
spriteIndex++; // Increment the index
if (spriteIndex > sprites.Length - 1) // Ensure that you stay within the array size
{
spriteIndex = 0;
}
buttonImage.sprite = sprites[spriteIndex]; // Set the image
}
}
}
However, you need to change the image settings to:
Image Type: simple
Use Sprite Mesh: true
(maybe) Preserve aspect: true
As an answer to your comment above, I will suggest you to have a button in the background and your pause button above. Then, replace your Update() method with an event OnClick() as you did before.
Your pause button will catch the left click and your background button will not.
Be sure to tick Interactable in the Button component.
Then you can safly remove the Image component of your background button, if you don't need it.
What it means is you can create (or modify) a class for your pause button
using UnityEngine.EventSystems;
public class PauseButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public bool IsMouseOver = false;
public void OnPointerEnter(PointerEventData eventData)
{
IsMouseOver = true;
}
public void OnPointerExit(PointerEventData eventData)
{
IsMouseOver = false;
}
// --
// Your OnClick method
// --
}
Note: the using eventSystems.
Now you can use this bool value within a code like amengelbrecht send you.
I'll will copy and paste his code from his answer, and add the bool value based on the previous class above.
public class BackgroundButtonScript : MonoBehaviour
{
// Public objects
public Sprite[] sprites;
public PauseButton pauseButton;
//Private variables
private Image buttonImage;
private int spriteIndex;
private void Start()
{
buttonImage = GetComponent<Image>(); // Get the image component of your button
spriteIndex = 0; // Set the index to 0
buttonImage.sprite = sprites[spriteIndex]; // Set the image to the first image in your sprite array
}
private void Update()
{
if (Input.GetMouseButtonDown(0) && !pauseButton.IsMouseOver)
{
spriteIndex++; // Increment the index
if (spriteIndex > sprites.Length - 1) // Ensure that you stay within the array size
{
spriteIndex = 0;
}
buttonImage.sprite = sprites[spriteIndex]; // Set the image
}
}
}
This will allow you to click anywhere on your screen except if the mouse is over your pause button. In this case, OnClick from the pause button will be called.
Be careful
If your game is is pause and the user left click anywhere but the pause button, depends on how your pause works, the Update() method of BackgroundButtonScript will be called and can lead to if (Input.GetMouseButtonDown(0) && !pauseButton.IsMouseOver).

Gun should shoot only when button is touched instead of entire screen

I've made a 3d game and I have a first person controller, control by a joystick. I want my player to shoot only when I touch a button on the screen, but now my player shoots if I touch anything on the screen. This is the script for the shoot function:
using UnityEngine;
using UnityEngine.UI;
public class Gun : MonoBehaviour
{
public float damage = 10f;
public float range = 100f;
public Camera fpsCam;
public Button button;
// Start is called before the first frame update
void Start()
{
//Calls the TaskOnClick/TaskWithParameters/ButtonClicked method when you click the Button
button.onClick.AddListener(TaskOnClick);
}
// Update is called once per frame
void Update()
{
Vector3 forward = transform.TransformDirection(Vector3.forward) * 10;
Debug.DrawRay(transform.position, forward, Color.green);
}
void Shoot()
{
RaycastHit hit;
if( Physics.Raycast(fpsCam.transform.position, fpsCam.transform.forward, out hit, range))
{
Debug.Log(hit.transform.name);
Target target = hit.transform.GetComponent<Target>();
if(target != null)
{
target.TakeDamage(damage);
}
}
}
void OnCollisionEnter(Collision collision)
{
Debug.DrawRay(collision.contacts[0].point, collision.contacts[0].normal, Color.green, 2, false);
}
void TaskOnClick()
{
Shoot();
}
}
Your Shoot() method runs whenever you press the "Fire1" button, since the only check you are doing is if (Input.GetButtonDown("Fire1")).
If you want to depend on a button to fire you need to take this part of the code out and call Shoot() whenever you click the button.
You can add the event to the button using code, as explained here
public Button m_YourFirstButton;
void Start()
{
//Calls the TaskOnClick/TaskWithParameters/ButtonClicked method when you click the Button
m_YourFirstButton.onClick.AddListener(TaskOnClick);
}
void TaskOnClick()
{
//Output this to console when Button1 or Button3 is clicked
Debug.Log("You have clicked the button!");
}
or you could call it from the inspector by referencing your Gun monobehaviour.

Unity3D GUI.Label is not displayed

I am currently trying to make "Welcome!" string and a button appear on screen by using the GUI Label and GUILayout Button, but it does not appear and there are not any errors that I know of. Unity emulator is ok, but the "Welcome!" string is not displayed in android.
Here is my code, can someone please tell me my problem and if I might have forgotten to do something.
public class MainMenu : MonoBehaviour
{
public GUISkin Skin;
public Texture btnTexture;
public void Awake() { }
public void OnGUI()
{
if (this.Skin != null)
{
GUI.skin = this.Skin;
}
GUI.skin.button.fontSize = 30;
Rect content = new Rect(30, 100, Screen.width-60, Screen.height-200);
GUILayout.BeginArea(content);
GUILayout.BeginHorizontal();
GUIStyle TextStyle = new GUIStyle(GUI.skin.label);
TextStyle.fontSize = 50;
// Load and set Font
Font myFont = (Font)Resources.Load("font/stingray", typeof(Font));
GUI.skin.font = myFont;
// Set color for selected and unselected
TextStyle.normal.textColor = Color.yellow;
TextStyle.hover.textColor = Color.yellow;
// Display and set the style in string
GUI.Label(new Rect(50,50,300,70), "Welcome!", TextStyle);
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Join", GUILayout.Width(300), GUILayout.Height(80)))
{
SceneManager.LoadSceneAsync("SingleMenu");
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
void Start () { }
void Update () { }
}

Unity-How to stop a moving object when the Camera sees it

This is just a simple thing I want to do. I have my cube gameobject rotating and I want to make it so when the camera sees the cube, it stops rotating. If you could steer me in the right direction, I'd appreciate it. thank you
public class cubeMove : MonoBehaviour, MoveObject
{
public Renderer rend;
public void Update () {
rend = GetComponent<Renderer>();
stopWhenSeen();
}
public void move()
{
transform.Rotate(new Vector3(15, 30, 45) * Time.deltaTime);
}
public void stopWhenSeen()
{
if (rend.enabled == false)
{
move();
}
}
}
Implement the OnBecameVisible and OnBecameInvisible MonoBehaviour's message :
private visible = false ;
// OnBecameVisible is called when the renderer became visible by any camera. INCLUDING YOUR EDITOR CAMERA
void OnBecameVisible()
{
visible = true ;
}
// OnBecameInvisible is called when the renderer is no longer visible by any camera. INCLUDING YOUR EDITOR CAMERA
void OnBecameInvisible()
{
visible = false;
}
void Update()
{
if( !visible )
move() ;
}
public void move()
{
transform.Rotate(new Vector3(15, 30, 45) * Time.deltaTime);
}
https://docs.unity3d.com/ScriptReference/Renderer-isVisible.html
You could try the .isVisible bool in your update method.
Here is a thread with other suggestions:
http://answers.unity3d.com/questions/8003/how-can-i-know-if-a-gameobject-is-seen-by-a-partic.html

How to bind ngui events in StrangeIoC in unity3d

I have some problem with binding ngui events in the StrangeIoC framework.
This is an unityGUI sample:
public class TestView : View
{
private readonly Rect buttonRect = new Rect(0, 0, 200, 50);
public Signal buttonClicked = new Signal();
public void OnGUI()
{
if (GUI.Button(buttonRect, "Test"))
{
buttonClicked.Dispatch();
}
}
}
This is the NGUI version:
public class NGUIView : View
{
public UIButton Button;
public Signal buttonClicked = new Signal();
private void Start()
{
if (Button != null)
{
EventDelegate.Add(Button.onClick, buttonClicked.Dispatch);
}
}
}
In the NGUI version, the the buttonClicked is never dispatched. I noticed in the scene the Notify property on that button has an empty value.
This one works, but the buttonClicked is triggered several times :(
public class NGUIView : View
{
public UIButton Button;
public Signal buttonClicked = new Signal();
void Update()
{
if (Button.state == UIButtonColor.State.Pressed)
{
buttonClicked.Dispatch();
}
}
}
Could you kindly tell me how do you handle this NGUI-StrangeIoC situation?
Thanks!
I finally figured out. Add the delegate in Awake instead of Start.
Now here's the perfect solution(not sure enough):
public class TestView : View
{
private readonly Rect buttonRect = new Rect(0, 0, 200, 50);
public UIButton Button;
public Signal buttonClicked = new Signal();
private void OnGUI()
{
if (GUI.Button(buttonRect, "Test"))
{
buttonClicked.Dispatch();
}
}
private void Awake()
{
EventDelegate.Add(Button.onClick, buttonClicked.Dispatch);
}
}