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.
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);
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
}
I have about 6 GameObjects with Tag (Model) after Move, Scale, Rotate how can I reset them back to start location when I click a button.
I am using Vuforia and Unity.
Any help would be appreciated, Thanks.
I have about 6 GameObjects with Tag (Model)
Find them all and store them into array.
GameObject[] models = GameObject.FindGameObjectsWithTag("Model");
Move, Scale, Rotate how can I reset them back to start location when I
click a button.
Get the position(Vector3), scale(Vector3) and rotation(Quaternion) in the Start() function, with a for loop and store their values to temporary variables. When the Button is clicked, call a function that sets the models position, scale and rotation to those values.
To call a function on a Button click, you can do that from the Editor or from Script. ButtonInstance.onClick.AddListener(() => yourFunctionToCall());
I am a Unity newbie
Nothing complicated here.
GameObject.FindGameObjectsWithTag
C# arrays.
GetComponent
Vector3
Quaternion
Unity Tutorials for beginners
Vector3[] defaultPos;
Vector3[] defaultScale;
Quaternion[] defaultRot;
Transform[] models;
//Attach Button from the Editor
public Button resetButton;
void Start()
{
//Call to back up the Transform before moving, scaling or rotating the GameObject
backUpTransform();
}
void backUpTransform()
{
//Find GameObjects with Model tag
GameObject[] tempModels = GameObject.FindGameObjectsWithTag("Model");
//Create pos, scale and rot, Transform array size based on sixe of Objects found
defaultPos = new Vector3[tempModels.Length];
defaultScale = new Vector3[tempModels.Length];
defaultRot = new Quaternion[tempModels.Length];
models = new Transform[tempModels.Length];
//Get original the pos, scale and rot of each Object on the transform
for (int i = 0; i < tempModels.Length; i++)
{
models[i] = tempModels[i].GetComponent<Transform>();
defaultPos[i] = models[i].position;
defaultScale[i] = models[i].localScale;
defaultRot[i] = models[i].rotation;
}
}
//Called when Button is clicked
void resetTransform()
{
//Restore the all the original pos, scale and rot of each GameOBject
for (int i = 0; i < models.Length; i++)
{
models[i].position = defaultPos[i];
models[i].localScale = defaultScale[i];
models[i].rotation = defaultRot[i];
}
}
void OnEnable()
{
//Register Button Events
resetButton.onClick.AddListener(() => resetTransform());
}
void OnDisable()
{
//Un-Register Button Events
resetButton.onClick.RemoveAllListeners();
}
a very easy way with very little coding is to make a prefab of your gameobject and re instantiate them, in which case prefab has the initial state of the object so every value will be reset.
to make it even easier you can make a parent object and make a prefab of that one.
then simply:
Destroy(Parent);
Instantiate(Resources.Load("Prefabs/Parent"));