1

I have an array of buttons being created and I want to make it so when I click on a button the texture of the button changes. The code I have changes the texture of all the buttons when I click any of the buttons.

Is there a way to code it so that if I click a button then the texture of that buttons changes from texA to texB and the rest of the buttons stay as texA?

public Texture texA;
public Texture texB;
static Vector2[] loc = new Vector2[25]; 
bool visited = false;

void Start () {
    int i = 0;
    while (i < loc.Length){
        loc [i] = new Vector2 (Random.Range (Screen.width * 0.1f, Screen.width * 0.9f), Random.Range(Screen.height * 0.1f, Screen.height * 0.9f));
        i = i + 1;
    }
}

void OnGUI(){
    for (int i = 0; i < loc.Length; i++) {
        if (GUI.Button (new Rect (loc [i].x, loc [i].y, Screen.width * 0.025f, Screen.height * 0.05f), visited ? texA:texB, "")) {
            visited = !visited;
        }
    }
}
Zoolar
  • 15
  • 4

2 Answers2

1

There are many ways to do this. You cab use data structure to store info about buttons that are clicked. The easiest method would be to use array.

Simply make the visited variable into an array and replace everywhere you used it with visited[i]. That's it.

public Texture texA;
public Texture texB;
static Vector2[] loc = new Vector2[25];

bool[] visited = new bool[25];

void Start()
{
    int i = 0;
    while (i < loc.Length)
    {
        loc[i] = new Vector2(Random.Range(Screen.width * 0.1f, Screen.width * 0.9f), Random.Range(Screen.height * 0.1f, Screen.height * 0.9f));
        i = i + 1;
    }
}

void OnGUI()
{
    for (int i = 0; i < loc.Length; i++)
    {
        if (GUI.Button(new Rect(loc[i].x, loc[i].y, Screen.width * 0.025f, Screen.height * 0.05f), visited[i] ? texA : texB, ""))
        {
            visited[i] = !visited[i];
        }
    }
}

That solves your problem but you need to abandon your current code and use Unity's new UI system with the Button component and its event system. You can learn more about the new UI events here.


With The New UI:

public Texture texA;
public Texture texB;

const int buttonCount = 25;

public GameObject buttonPrefab;
public Canvas canvasForButtons;

Button[] buttons = new Button[buttonCount];
static Vector2[] loc = new Vector2[buttonCount];
bool[] visited = new bool[buttonCount];


void Start()
{
    int i = 0;
    while (i < loc.Length)
    {
        loc[i] = new Vector2(Random.Range(Screen.width * 0.1f, Screen.width * 0.9f), Random.Range(Screen.height * 0.1f, Screen.height * 0.9f));
        i = i + 1;
    }

    createButtons();
}

void createButtons()
{
    for (int i = 0; i < loc.Length; i++)
    {
        //Instantiate Button
        GameObject tempButtonObj = Instantiate(buttonPrefab, canvasForButtons.transform) as GameObject;
        Button tempButton = tempButtonObj.GetComponent<Button>();
        buttons[i] = tempButton;

        //Create rect for position
        Rect buttonRect = new Rect(loc[i].x, loc[i].y, Screen.width * 0.025f, Screen.height * 0.05f);

        //Assign Position of each Button
        buttons[i].GetComponent<RectTransform>().position = buttonRect.position;
        //buttons[i].GetComponent<RectTransform>().sizeDelta = buttonRect.size;

        //Don't capture local variable
        int tempIndex = i;
        //Add click Event
        buttons[i].onClick.AddListener(() => buttonClickCallBack(tempIndex));
    }
}

//Called when Button is clicked
void buttonClickCallBack(int buttonIndex)
{
    Debug.Log(buttonIndex);

    //Get Texture to change
    Texture textureToUse = visited[buttonIndex] ? texA : texB;

    //Convert that Texture to Sprite
    Sprite spriteToUse = Sprite.Create((Texture2D)textureToUse, new Rect(0.0f, 0.0f, textureToUse.width,
        textureToUse.height), new Vector2(0.5f, 0.5f), 100.0f);

    //Change the Button Image
    buttons[buttonIndex].image.sprite = spriteToUse;

    //Flip Image
    visited[buttonIndex] = !visited[buttonIndex];
}

That's the output:

enter image description here

Community
  • 1
  • 1
Programmer
  • 121,791
  • 22
  • 236
  • 328
0

You should avoid the use of the OnGUI, as stated by the Unity team themselves, and rather rely on the new UI.

To solve your problem, you should do this:

  • Create a Canvas, and attach to it the script CreateButtons;
  • Create a Button inside the Canvas, attach to it the script ChangeButtonSprite, and give the proper A and B sprites to it in the inspector fields.
  • Create an OnClick event on the Button, pass to it the script ChangeButtonSprite, select the ChangeSprite() method, and select the Image component of the button itself as the argument
  • Make this button a prefab, and then delete it from the hierarchy;
  • In the Button Prefab field of the Canvas, put the Button prefab
  • That's it, you may want to change/expand on how the positions are generated, the starting image of the buttons, etc., since this was just an example on how to use the Unity UI OnClick embedded events (you can even intercept the OnClick events directly from script ofc, by using the onClick.AddListener)

CreateButtons.cs

using UnityEngine;

public class CreateButtons : MonoBehaviour {

    public GameObject ButtonPrefab;
    public int NumberOfButtons;

    void Start () {
        for (int i=0; i<NumberOfButtons; i++) {
            Vector3 buttonPos = new Vector3 (Random.Range(0f, Screen.width), Random.Range(0f, Screen.height), 0);
            GameObject buttonSpawned = Instantiate(ButtonPrefab, buttonPos, Quaternion.identity, gameObject.transform) as GameObject;
        }
    }
}

ChangeButtonSprite

using UnityEngine;
using UnityEngine.UI;

public class ChangeButtonSprite : MonoBehaviour {

    public Sprite TexA,TexB;

    void Start(){
        GetComponent<Image>().sprite = TexA;
    }

    public void ChangeSprite(Image image){
        if (image.sprite == TexA) {
            image.sprite = TexB;
            return;
        }
        image.sprite = TexA;
    }
}
Galandil
  • 4,169
  • 1
  • 13
  • 24