- Home /
How to change Menu Buttons to a Selected Image and Deselected Image
Hello!
My goal is to be able to click on a Menu UI Button (1, 2 or 3) which changes their image to be Selected and clicking on another Menu UI Button or the Close(X) Button changes their Image to be De Selected.
I was able to accomplish this using SetActive(true); and SetActive(false); but its very messy and I was wondering if there is a better way to accomplish this using less code.
Here is the code that I am using on my GameManager script.
Any advice you could offer would be greatly appreciated.
Thank you :-)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
// ---------------------------------------------------------------------
// Variables
// ---------------------------------------------------------------------
public GameObject[] panelArray;
public PanelColour currentPanelColour;
// * VARIABLES FOR SELECTED AND DE-SELECTED STATES
public GameObject menu1Selected;
public GameObject menu1Deselected;
public GameObject menu2Selected;
public GameObject menu2Deselected;
public GameObject menu3Selected;
public GameObject menu3Deselected;
// Start is called before the first frame update
void Start()
{
SetPanelColour(PanelColour.Panel0); // initialize with a value
}
// ---------------------------------------------------------------------
// Menu Array
// ---------------------------------------------------------------------
public enum PanelColour
{
Panel0,
Panel1,
Panel2,
Panel3,
}
public void SetPanelColour(PanelColour newPanelColour)
{
panelArray[(int)currentPanelColour].SetActive(false); // deactivate the old panel
panelArray[(int)newPanelColour].SetActive(true); // activate the new one
currentPanelColour = newPanelColour; // remember the new one
}
// ---------------------------------------------------------------------
// Menu Buttons Swap Panel
// ---------------------------------------------------------------------
// Menu button 1
public void SwapPanel1()
{
SetPanelColour(PanelColour.Panel1);
// * SET MENU1 TO SELECTED SPRITE
menu1Selected.SetActive(true);
menu1Deselected.SetActive(false);
// * SET MENU2 AND MENU3 TO DESELECTED SPRITE
menu2Deselected.SetActive(true);
menu3Deselected.SetActive(true);
menu2Selected.SetActive(false);
menu3Selected.SetActive(false);
}
// Menu button 2
public void SwapPanel2()
{
SetPanelColour(PanelColour.Panel2);
// * SET MENU2 TO SELECTED SPRITE
menu2Selected.SetActive(true);
menu2Deselected.SetActive(false);
// * SET MENU1 AND MENU3 TO DESELECTED SPRITE
menu1Deselected.SetActive(true);
menu3Deselected.SetActive(true);
menu1Selected.SetActive(false);
menu3Selected.SetActive(false);
}
// Menu button 3
public void SwapPanel3()
{
SetPanelColour(PanelColour.Panel3);
// * SET MENU3 TO SELECTED SPRITE
menu3Selected.SetActive(true);
menu3Deselected.SetActive(false);
// * SET MENU1 AND MENU2 TO DESELECTED SPRITE
menu1Deselected.SetActive(true);
menu2Deselected.SetActive(true);
menu1Selected.SetActive(false);
menu2Selected.SetActive(false);
}
// Close button on Panel
public void SwapPanel0()
{
SetPanelColour(PanelColour.Panel0);
DeselectAllMenuButtons();
}
// ---------------------------------------------------------------------
// Menu Buttons Selected & Unselected States Activate On & Off
// ---------------------------------------------------------------------
public void DeselectAllMenuButtons()
{
// * SET MENU1, MENU2 & MENU3 TO DESELECTED SPRITE
menu1Deselected.SetActive(true);
menu2Deselected.SetActive(true);
menu3Deselected.SetActive(true);
menu1Selected.SetActive(false);
menu2Selected.SetActive(false);
menu3Selected.SetActive(false);
}
};
Answer by evskii · Nov 08, 2021 at 03:46 PM
You can just have a reference to the selected and deselected sprites in the script, and then create a reference to the buttons as an array.
public Sprite selectedSprite;
public Sprite deselectedSprite;
public Button[] buttons;
and then you create a method that each button calls in their OnClick event to set the correct sprites for each button. (When you set the method in the OnClick event you can also input an int since we added that argument to the method, and let this int reference the buttons position in the buttons array).
public void ButtonPressed(int buttonNum){ //Gets sent the int index of the button from the OnClick()
for(int i = 0; i < buttons.Length; i++){ //Loop through the array buttons
if(i == buttonNum){ //This will be the button that you sent the index of
buttons[i].GetComponent<Image>().sprite = selectedSprite;
}else{ //this is every other button
buttons[i].GetComponent<Image>().sprite = unSelectedSprite;
}
}
}
Code might not be the exact capitalization since I'm not writing this in my IDE so I don't have those lovey autocompletes. You can do whatever you want then inside of that loop since you have references to each button.
Answer by TinyTurnip1 · Nov 09, 2021 at 01:32 AM
Hi Evskii
Thank you so much for your help, I feel like this is getting so close to working perfectly.
I have attached the public Button[] topButtons;
script to my GameManager Script and drag and dropped the 3 menu buttons in the topButtons Array.
I then created a new Script called Section so that I could drag and drop each individual TopBar Menu's Img-Deact (unSelectedSprite) and Img-Act(selectedSprite) sprites into the Array. I had to change those variables to GameObjects rather than Sprites to drag and drop them directly from the Hierarchy.
This is my Section script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class Section : MonoBehaviour
{
// ---------------------------------------------------------------------
// Variables
// ---------------------------------------------------------------------
public GameObject deselectedTopIcon;
public GameObject selectedTopIcon;
public GameObject gameManager;
private GameManager gameManagerScript;
// Start is called before the first frame update
void Start()
{
// Get the GameManager script topButtons variable
gameManagerScript = gameManager.GetComponent<GameManager>();
}
public void ButtonPressed(int buttonNum)
{ //Gets sent the int index of the button from the OnClick()
for (int i = 0; i < gameManagerScript.topButtons.Length; i++)
{ //Loop through the array buttons
if (i == buttonNum)
{ //This will be the button that you sent the index of
// ***what should i do here?
// gameManagerScript.topButtons[i].GetComponent<Image>().gameObject = selectedTopIcon;
}
else
{ //this is every other button
// ***what should i do here?
// gameManagerScript.topButtons[i].GetComponent<Image>().gameObject = deselectedTopIcon;
}
}
}
}
My question is: From here, what should I do with this part in the script to swap between the deselectedTopIcon (Img-Deact) and selectedTopIcon (Img-Act) states?
// gameManagerScript.topButtons[i].GetComponent<Image>().gameObject = selectedTopIcon;
Would something like this work?
selectedTopIcon.SetActive(true);
deselectedTopIcon.SetActive(false);
Thank you so much and sorry for the huge wall of photos/text I was trying to explain everything the best that I could. I'm really looking forward to having this working! :-)
@TinyTurnip1 [Reply to this message so we don't have to fill up the entire page getting this to work!]
I don't know why you cant reference the Sprites directly from your assets folder, that shouldn't be an issue. You should just be able to drag and drop the Sprite from your asset folder onto the slot if its data type is a Sprite!
How and ever, if you want it to work with the GameObjects you have, you need to use GetComponent like it looks like you have, but instead of saying .GetComponent().gameObject you should be saying .GetComponent().sprite. The sprite is the actual image that is being rendered by the game, whereas the GameObject and even the Image component on a GameObject is just a container for this sprite to be in.
@evskii Thank you for the reply! :-) Ahh yes, forgive me for my noob-ness! It probably makes sense to just use Sprites from my asset folder but I like having them the images visually in the Hierarchy. This is purely just because I'm learning and this was the easiest way for me to make things work.
I tried using this: gameManagerScript.topButtons[i].GetComponent().gameObject.sprite = selectedTopIcon;
But the script had an error. Maybe because I am using Images for the selectedTopIcon rather than sprites?
"Severity Code Description Project File Line Suppression State Error CS0411 The type arguments for method 'Component.GetComponent()' cannot be inferred from the usage. Try specifying the type arguments explicitly. Assembly-CSharp D:\Github\Test-Dress-Up-2\Dress Up Test 2\Assets\Scripts\Section.cs 35 Active"
Thanks again for your help!
From what I can see, for each button you have two children that contain the sprites of the active and deactivated buttons. This makes things a little more complicated for you, and I didn't understand fully how you had it set up before. Here is something that you can do with your current setup to make it run a little easier!
Make a script called ButtonController.cs and put it on each of your buttons (Top-Hats, Top-Shirts etc..) and then inside of that script do this: public GameObject activeSprite; public GameObject deActivesprite;
public void ActiveButton(){
activeSprite.SetActive(true);
deActiveSprite.SetActive(false);
}
public void DeActiveButton(){
activeSprite.SetActive(false);
deActiveSprite.SetActive(true);
}
and for each button, reference the children under it for the activeSprite/deActiveSprite slots.
Then in that original for loop where we referenced the buttons, and where the buttons OnClick event references, do this instead!
public void ButtonPressed(int buttonNum){ //Gets sent the int index of the button from the OnClick()
for(int i = 0; i < buttons.Length; i++){ //Loop through the array buttons
if(i == buttonNum){ //This will be the button that you sent the index of
buttons[i].GetComponent<ButtonController>()ActiveButton(); //This calls the method inside of the button to activate the sprites gameobject
}else{ //this is every other button
buttons[i].GetComponent<ButtonController>().DeActiveButton();
}
}
}