I wanted to make a game where you click a button and it affects another button. I made a grid. If I click a button in this grid I want to have it affect another button's image. However I need some sort identifier which tells me which button is which.
I'm used prefabs for a button, then made a 5x10 grid prefab of those prefabs. Any guidance towards the right direction would be helpful even if it does not answer the question thank you.
This can be done easily
First lets make a script
GridController.cs
Add a reference to the UI namespace at the top using UnityEngine.UI;
Now place all of your grid items in a parent container(can be an empty gameobject)
Now lets start coding
//Reference parent gameobject
[SerializeField]
private GameObject gridContainer;
//List of all child elements
private List<Button> gridObjects = new List<Button>();
private void Start(){
//Loop through all children
for(int i = 0; i < gridContainer.transform.childCount; i++){
//Add button to list
gridObjects.Add(gridContainer.transform.getChild(i).gameObject.GetComponent<Button>());
}
//Set listeners for buttons
for(int i = 0; i < gridObjects.Count;i++){
gridObjects[i].onClick.AddListener(delegate{
DoSomething();
});
}
}
private void DoSomething(){
//Do Something
}
Related
I am instantiating a prefab thru a script in Unity. It's kind of working but not really.
The prefab shows up in the hierarchy with the correct name but in the scene, it cannot be seen.
I have looked through every question I saw, that was similar but unfortunately, I couldn't solve my problem. I tried changing the Vector in the script and the position of the prefab itself.
I appreciate any help.
public class ButtonControler : MonoBehaviour
[SerializeField] private Button[] buttonsList;
public GameObject button;
public void Awake()
{
InitializeButtons();
}
private void InitializeButtons()
{
for (int i = 0; i < CsvManagerDownloader.experiments.Count; i++)
{
string buttontext = "Experiment" + i;
GameObject newButton = Instantiate(button, new Vector3(0, 0, 0), Quaternion.identity);
newButton.GetComponentInChildren<Text>().text = buttontext;
}
(This script can only be called after CSVManagerDownloader, since the number of buttons is gathered from that script.)
It seems that you are trying to instantiate an object that is supposed to be used inside Canvas (unity UI system) in the world space.
Canvas component on the root object is needed to render all child UI elements like Button, Text, Image, etc.
So, if you want your instantiated object with the Button component to be visible, make sure, that you place it in the hierarchy with the Canvas component attached to any of its parents.
Also, make sure that the EventSystem component is present at the scene to make Buttons work.
I'm attempting to make a level select that requires as little upkeep as possible as I intend on adding updates to add more levels (Unity Scenes) in unity.
To account for this I'm attempting to get the level select to create buttons for each level in the Unity Build settings, and then create a template object from a prefab in which it can map buttons it creates onto.
I have it mostly working, but for some reason, it's mapping the buttons in the wrong order, I'm trying to go down to up and Unity appears to be grabbing the Gameobjects is a random order.
Here is my code:
private Scene[] levels;
private int currentButtonId = 1;
public Transform buttonsHolder;
public GameObject buttonPrefab;
public GameObject buttonSlotsPrefab;
private GameObject[] levelButtonSlots;
private int currentLevelSlot = 0;
private int numSlotsToMove = 0;
private void Start()
{
var sceneCount = SceneManager.sceneCountInBuildSettings;
levels = new Scene[sceneCount];
for (var i = 0; i < sceneCount; i++)
{
// Beginning Setup
levels[i] = SceneManager.GetSceneByBuildIndex(i);
// Look for Level Placement Slots
levelButtonSlots = GameObject.FindGameObjectsWithTag("Level Slot");
// If there aren't enough Level Placement Slots make more by creating a template
if(levelButtonSlots.Length < levels.Length)
{
GameObject buttonSlots = Instantiate(buttonSlotsPrefab);
buttonSlots.transform.position = new Vector2(0, 10 * numSlotsToMove);
numSlotsToMove++;
}
// Go get those new placement slots
levelButtonSlots = GameObject.FindGameObjectsWithTag("Level Slot");
// Create Button
GameObject currentButton = Instantiate(buttonPrefab, buttonsHolder);
// Move it to the next slot
currentButton.transform.position = levelButtonSlots[currentLevelSlot].transform.position;
currentLevelSlot++;
// Add Text to a new button
TextMeshProUGUI buttonText = currentButton.GetComponentInChildren<TextMeshProUGUI>();
buttonText.text = (currentButtonId.ToString());
// Setup what which scene clicking a button will do
ButtonManager buttonScript = currentButton.GetComponentInChildren<ButtonManager>();
buttonScript.sceneToLoad = currentButtonId;
currentButtonId++;
}
}
The buttonsHolder variable is set in the editor and is the canvas.
The buttonPrefab is a TextMeshPro button prefab I set in the editor, it has the level Buttons tag and a simple script that loads the specified scene when clicked.
And the buttonSlotsPrefab is a gameobject prefab that I set in the editor, it has the Button Placement Slot tag and it contains 8 other empty gameobjects each with the level slot tag, I use these 8 objects as the guides as to where the buttons should be placed on runtime.
Again, my goal is to place the buttons going from bottom to top, but instead, Unity spits out this on runtime for no apparent reason:
I'm sorry about the naming convention some variables have, I'm tired and stressed as I've been at this 2 two days straight. I will fix those up once I get things working.
After further testing, I have noticed that when I first create buttonSlotPrefab, everything works perfectly, however, after restarting Unity (Not changing any files) when I run the game again after a restart the order gets randomized. Could this be a bug in the Unity Engine?
If i understant your problem, you have a problem between number of button and slot: you have slot spaced on axis y and you havent always the levelsolt[0] at the bottom of screen, so
you could order (ascending or descending i dunno) the levelslot on y axis before creating button: i am using Linq so add using System.Linq;
if (levelButtonSlots.Any())//Same thing than levelButtonSlots.Length > 0
{
levelButtonSlots = GameObject.FindGameObjectsWithTag("Level Slot").OrderBy(go => go.transform.position.y).ToArray();
}
or
levelButtonSlots = GameObject.FindGameObjectsWithTag("Level Slot").OrderByDescending(go => go.transform.position.y).ToArray();
I have added a test if no value in array, but maybe the error doesnt exist, i havent tested that
Trying to delete the items from the panel (empty it) and then repopulate the panel with new items (buttons)
I've already tried to delete each element with the foreach you see below with no luck
public GameObject Button;
public Transform buttonContainer;
public void create_buttons(Orbital o)
{
GameObject go = Instantiate(Button);
var panel = GameObject.Find("station_panel");
//Destroy(GameObject.Find("station_panel"));
foreach (UnityEngine.UI.Button b in panel.GetComponents<UnityEngine.UI.Button>())
{
//Destroy(b.gameObject);
b.enabled = false;
}
go.transform.position = panel.transform.position;
go.GetComponent<RectTransform>().SetParent(panel.transform);
//go.GetComponent<RectTransform>().SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, 0, 10);
go.GetComponent<UnityEngine.UI.Button>().onClick.AddListener(() => onClick());
go.GetComponentInChildren<Text>().text = o.name;
}
void onClick()
{
Debug.Log("aaaaaaaaaaaaaaa");
canvas.enabled = false;
}
The panel's transform hierarchy contains a reference to them.
Transform panelTransform = GameObject.Find("station_panel").transform;
foreach(Transform child in panelTransform) {
Destroy(child.gameObject);
}
Make a List and add any button you create for your panel.
Once you want to clear it, clear this list, but GetCompoenents will not return all the buttons in your Panel gameobject as you cant add 2 button component to a single gameobject.
Also add -using UnityEngine.UI- to the top of your script to be easily read for to be like
foreach (Button b in list)
{
Destroy(b.gameObject);
}
DestroyImmediate(i-am-gameobject);
So Im trying to make an UI list with buttons to change color in Unity. In this script I have 2 lists 1 for Color and 1 for the name, for the buttons I try to spawn. To spawn these buttons i use foreach loops. Yet If I put the for each loop in an other, I get way more buttons than wanted. Or I get the right amount of buttons, but the buttons will have the last name in the list.
In the script i have commented out the thing i tried..
public GameObject ContentPanel;
public GameObject ListItemPrefab;
// List
public List<Color> ColorOptions;
public List<string> ColorNames;
// Use this for initialization
void Start () {
foreach(Color color in ColorOptions){
//Too much buttons
//foreach (string name in ColorNames){
//Spawn button
GameObject newButton = Instantiate(ListItemPrefab) as GameObject;
// Get button component
ButtonController controller = newButton.GetComponent<ButtonController>();
// Give button the color from the list
newButton.GetComponent<Image>().color = color;
controller.Name.text = name;
newButton.transform.SetParent(ContentPanel.transform);
newButton.transform.localScale = Vector3.one;
//List with the names
//Buttons get the same name
/*foreach (string name in ColorNames){
controller.Name.text = name;
}*/
//}
}
}
In the buttoncontroller is a var Name for the button text. Anyway my question is then: How do I get the names from the list without multiplying the buttons ? I hope you guys can help me with this !
Following code will create as many buttons as the ColorOptions will be available with corresponding names -
public GameObject ContentPanel;
public GameObject ListItemPrefab;
// List of color option and corresponding names
public List<Color> ColorOptions;
public List<string> ColorNames;
// Use this for initialization
void Start () {
for(int count=0;count<ColorOptions.Count;count++){
//Spawn button
GameObject newButton = Instantiate(ListItemPrefab) as GameObject;
// Get button component
ButtonController controller = newButton.GetComponent<ButtonController>();
// Give button the color from the list
newButton.GetComponent<Image>().color = ColorOptions[count];
// Give button the name from the list
controller.Name.text = ColorNames[count];
newButton.transform.SetParent(ContentPanel.transform);
newButton.transform.localScale = Vector3.one;
}
}
So, if you have 5 color options and their corresponding names then you'll get 5 buttons.
I am trying to add items to my Canvas dynamicly in C#.
Here is what I am trying to do
public class MyScript : MonoBehaviour
{
private List<GameObject> _buttons;
private GameObject _canvas;
public MyScript()
{
_buttons = new List<GameObject>();
}
// Use this for initialization
void Start()
{
for (int i = 0; i < 3; i++)
{
var button = Instantiate(Resources.Load("myButton", typeof(GameObject))) as GameObject;
if (button == null) continue;
button.GetComponent<RectTransform>().position = new Vector3(i, i, 0);
}
}
}
I have my buttonPrefab which is inside of Canvas. After debug I see my new buttons created but they are not in Canvas and its normal because I didnt add them there in code. The point is that I dont have any idea how to add new buttons to Canvas.
Also how I can add OnClick event if buttons are GameObjects and I cant cast it to Button?
Can someone help me ?
Answering how to instantiate: when doing so, you need to rember about few things.
But first lets show some code:
for (int i = 0; i < 3; i++)
{
var button = (GameObject)Instantiate(Resources.Load("myButton", typeof(GameObject))) as GameObject;
if (button == null) continue;
button.transform.SetParent (referenceToCanvas.transform);
button.transform.localScale = Vector3.one;
button.transform.localRotation = Quaternion.Euler (Vector3.zero);
button.GetComponent<RectTransform>().anchoredPosition3D = new Vector3(i, i, 0);
}
When instatiating GameObjects Unity3D creates them in world space with given scale and rotation. When you set the canvas as parent sometimes the scale is set to zero or just not what you want. The same applies to rotation. So that is why I add these lines of code everytime I dynamicaly populate UI.
Of course referenceToCanvas is reference to canvas object ;)
1-) In order to make new buttons added in Canvas you need to make your canvas object parent of these buttons, you need to use setParent method take a look at here
http://docs.unity3d.com/ScriptReference/Transform.SetParent.html
2-)For your second question you can easily achieve that just add a collider to your object which you want to click and add a script to the object as well. And add OnMouseDown() method to this script, whenever you click this object this method will be called.
For 1 see Burak, use Transform.SetParent.
For 2 I'd recommend creating an empty GameObject and add a UI Button to it and what ever you need in addition. Make this a prefab and instantiate it.