greyBow greyBow - 3 months ago 8
C# Question

Most efficient way to script toggle buttons on and off functionality

I wrote a bit of code that changes the visual state of a button (whichever button is clicked gets highlighted blue and returns all other buttons back to their default color). It seems to work fine but it feels cumbersome. Is there a more efficient/succinct way to re-write my code? Many thanks!

using UnityEngine ;
using System.Collections ;
using UnityEngine.UI ;

public class ToolButtons : MonoBehaviour
{
public Color activeColor ;
public Color inactiveColor ;
public GameObject iconBG ;
public Button ink, brush, crayon, pencil, spray, eraser, chnageColor, brushSize, undo, redo, clear, newAnimal ;
public GameObject inkIconBG, brushIconBG, crayonIconBG, pencilIconBG, sprayIconBG, eraserIconBG, changeColorIconBG, brushSizeIconBG ;

void Start ()
{
inactiveColor = iconBG.GetComponent <Image> ().color ;
}

// Use this for initialization
void buttonCallBack (Button buttonClicked)
{
//Change Color Palette Button clicked
if (buttonClicked == ink)
{
inkIconBG.GetComponent <Image> ().color = activeColor ;
} else if (buttonClicked != ink)
{
inkIconBG.GetComponent <Image> ().color = inactiveColor ;
}

if (buttonClicked == brush)
{
brushIconBG.GetComponent <Image> ().color = activeColor ;
} else if (buttonClicked != brush)
{
brushIconBG.GetComponent <Image> ().color = inactiveColor ;
}

if (buttonClicked == crayon)
{
crayonIconBG.GetComponent <Image> ().color = activeColor ;
} else if (buttonClicked != crayon)
{
crayonIconBG.GetComponent <Image> ().color = inactiveColor ;
}

if (buttonClicked == pencil)
{
pencilIconBG.GetComponent <Image> ().color = activeColor ;
} else if (buttonClicked != pencil)
{
pencilIconBG.GetComponent <Image> ().color = inactiveColor ;
}

if (buttonClicked == spray)
{
sprayIconBG.GetComponent <Image> ().color = activeColor ;
} else if (buttonClicked != spray)
{
sprayIconBG.GetComponent <Image> ().color = inactiveColor ;
}

if (buttonClicked == eraser)
{
eraserIconBG.GetComponent <Image> ().color = activeColor ;
} else if (buttonClicked != eraser)
{
eraserIconBG.GetComponent <Image> ().color = inactiveColor ;
}
}

void OnEnable ()
{
ink.onClick.AddListener (() => buttonCallBack (ink)) ;
brush.onClick.AddListener (() => buttonCallBack (brush)) ;
crayon.onClick.AddListener (() => buttonCallBack (crayon)) ;
pencil.onClick.AddListener (() => buttonCallBack (pencil)) ;
spray.onClick.AddListener (() => buttonCallBack (spray)) ;
eraser.onClick.AddListener (() => buttonCallBack (eraser)) ;
}


void OnDisable ()
{

}
}

Answer

Doing this with array would have been better but the problem is that you would lose the names of your Buttons and GameObjects making it hard to modify your code later on.

You can use Dictionary for this. Make a Button--GameObject pair then manually add each Button to match each Icon/GameObject. You can then loop through it when Button is clicked, compare the the Button that was clicked with the key in the Dictionary, then assign activeColor or inactiveColor based on the comparison result.

Note: If you add more Buttons and Icons, you must add them too to the pairButtonIcon() function.

Anyone wondering why I didn't use foreach loop over the Dictionary, that's because it allocates memory in Unity.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.UI;

public class ToolButtons : MonoBehaviour
{
    public Color activeColor;
    public Color inactiveColor;
    public GameObject iconBG;
    public Button ink, brush, crayon, pencil, spray, eraser, chnageColor, brushSize, undo, redo, clear, newAnimal;
    public GameObject inkIconBG, brushIconBG, crayonIconBG, pencilIconBG, sprayIconBG, eraserIconBG, changeColorIconBG, brushSizeIconBG;

    Dictionary<Button, GameObject> buttonIconPair = new Dictionary<Button, GameObject>();

    void pairButtonIcon()
    {
        buttonIconPair.Add(ink, inkIconBG);
        buttonIconPair.Add(brush, brushIconBG);
        buttonIconPair.Add(crayon, crayonIconBG);
        buttonIconPair.Add(pencil, pencilIconBG);
        buttonIconPair.Add(spray, sprayIconBG);
        buttonIconPair.Add(eraser, eraserIconBG);
        buttonIconPair.Add(chnageColor, changeColorIconBG);
        buttonIconPair.Add(brushSize, brushSizeIconBG);
    }

    void Start()
    {
        pairButtonIcon();
        inactiveColor = iconBG.GetComponent<Image>().color;
    }

    // Use this for initialization
    void buttonCallBack(Button buttonClicked)
    {

        //My Code
        for (int i = 0; i < buttonIconPair.Count; i++)
        {
            var item = buttonIconPair.ElementAt(i);
            var itemKey = item.Key;
            var itemValue = item.Value;

            if (buttonClicked == itemKey)
            {
                itemValue.GetComponent<Image>().color = activeColor;
            }
            else
            {
                itemValue.GetComponent<Image>().color = inactiveColor;
            }
        }
    }

    void OnEnable()
    {
        ink.onClick.AddListener(() => buttonCallBack(ink));
        brush.onClick.AddListener(() => buttonCallBack(brush));
        crayon.onClick.AddListener(() => buttonCallBack(crayon));
        pencil.onClick.AddListener(() => buttonCallBack(pencil));
        spray.onClick.AddListener(() => buttonCallBack(spray));
        eraser.onClick.AddListener(() => buttonCallBack(eraser));
    }


    void OnDisable()
    {

    }
}

EDIT: You can also use multiple Lists then store Button and GameObject/Icon on each one.

public class ToolButtons : MonoBehaviour
{
    public Color activeColor;
    public Color inactiveColor;
    public GameObject iconBG;
    public Button ink, brush, crayon, pencil, spray, eraser, chnageColor, brushSize, undo, redo, clear, newAnimal;
    public GameObject inkIconBG, brushIconBG, crayonIconBG, pencilIconBG, sprayIconBG, eraserIconBG, changeColorIconBG, brushSizeIconBG;

    List<Button> button = new List<Button>();
    List<GameObject> iconGameObjects = new List<GameObject>();

    void pairButtonIcon()
    {
        button.Add(ink);
        iconGameObjects.Add(inkIconBG);

        button.Add(brush);
        iconGameObjects.Add(brushIconBG);

        button.Add(crayon);
        iconGameObjects.Add(crayonIconBG);

        button.Add(pencil);
        iconGameObjects.Add(pencilIconBG);

        button.Add(spray);
        iconGameObjects.Add(sprayIconBG);

        button.Add(eraser);
        iconGameObjects.Add(eraserIconBG);

        button.Add(chnageColor);
        iconGameObjects.Add(changeColorIconBG);

        button.Add(brushSize);
        iconGameObjects.Add(brushSizeIconBG);
    }

    void Start()
    {
        pairButtonIcon();
        inactiveColor = iconBG.GetComponent<Image>().color;
    }

    // Use this for initialization
    void buttonCallBack(Button buttonClicked)
    {

        //My Code
        for (int i = 0; i < button.Count; i++)
        {
            if (buttonClicked == button[i])
            {
                iconGameObjects[i].GetComponent<Image>().color = activeColor;
            }
            else
            {
                iconGameObjects[i].GetComponent<Image>().color = inactiveColor;
            }
        }
    }

    void OnEnable()
    {
        ink.onClick.AddListener(() => buttonCallBack(ink));
        brush.onClick.AddListener(() => buttonCallBack(brush));
        crayon.onClick.AddListener(() => buttonCallBack(crayon));
        pencil.onClick.AddListener(() => buttonCallBack(pencil));
        spray.onClick.AddListener(() => buttonCallBack(spray));
        eraser.onClick.AddListener(() => buttonCallBack(eraser));
    }


    void OnDisable()
    {

    }
}
Comments