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);
Related
looking for some help with adding mesh colliders in Unity via script. For example, I want to select GameObject and have script add mesh colliders to each other child gameobject, with exception of said gameobject of having Mesh Filter.
Any help would be appreciated. I'd like to be able to use the script in Editor mode, so I don't have to manually select gameobjects and set colliders to them.
I'm not really too sure how to go about that at the moment.
public GameObject object4col;
public void AddMeshColliders(){
if (object4col.GetComponent<MeshFilter>() == null)
{
object4col.AddComponent<MeshCollider>();
}
}
Thanks!
You can iterate through recursively of child objects and add the component.
You can add the method to the context menu, so when you right click on the script's header or click on the three dots on the header's right side, the option will be there.
[SerializeField] private Transform _target;
[ContextMenu("Add MeshColliders")]
private void AddMeshColliders()
{
if (_target == null) _target = transform;
AddRecursively(_target);
}
private void AddRecursively(Transform parent)
{
for (int i = 0; i < parent.childCount; i++)
{
Transform child = parent.GetChild(i);
if (child.GetComponent<MeshFilter>() != null) child.gameObject.AddComponent<MeshCollider>();
AddRecursively(child);
}
}
Instead of ContextMenu, you can write an Editor script, add a button for it and move the whole logic there.
Can be done this way: Import Linq
using System.Linq;
Select all the child objects of parentObj (say) that do not have a mesh collider
public Transform[] object4cols = parentObj.GetComponentsInChildren<Transform>().Where(x => x.GetComponent<MeshCollider>() == null).ToArray();
Iterate over the child objects and add a mesh collider to them
foreach(Transform object4col in object4cols) {
object4col.AddComponent<MeshCollider>();
}
I am making a kids educational game.
I have 20 panels of questions. If answered correctly, A button is activated. If clicked on Button, next panel should be active and the last active panel should be deactivated. This should happen with all 20 panels.
The Code is as follows:
public class PanelChanger : MonoBehaviour
{
public GameObject nextButton;
public GameObject[] QuestionsPanel;
public GameObject wellDonePanel;
// Start is called before the first frame update
public void Start()
{
QuestionsPanel[Random.Range(0, QuestionsPanel.Length)].SetActive(true);
}
// Update is called once per frame
void Update()
{
}
...
Here I want to place the code to activate the next panel and deactivate the active panel. In this code I am able to Set active random panel, but not able deactivate the current panel.
...
public void ShowNextQuestion()
{
wellDonePanel.SetActive(false);
QuestionsPanel[Random.Range(0, QuestionsPanel.Length)].SetActive(true);
}
}
Either store the current panel in a field
private GameObject currentPanel;
and always do
// If a previous panel exists deactivate it
if(currentPanel) currentPanel.SetActive(false);
// Store the new panel
currentPanel = QuestionsPanel[Random.Range(0, QuestionsPanel.Length)];
// Activate the new panel
currentPanel.SetActive(true);
Or alternatively simply iterate the entire array and do
// Get the tendon index
var randomIndex = Random.Range(0, QuestionsPanel.Length);
// Iterate all panels
for(var i = 0; i < QuestionsPanel.Length; i++)
{
// Set the matching panel active, all others inactive
QuestionsPanel[i].SetActive(i == randomIndex);
}
Note though: Currently you might get the same panel twice in a row. If you only want to do all the panels in random order and then be finished rather randomize the array once and then simply iterate it in the randomized order sequentially like e.g.
using System.Linq;
...
private GameObject [] randomizedQuestions;
private int currentIndex;
private GameObject currentPanel;
private void Start ()
{
Shuffle ();
ShowNextQuestion();
}
private void Shuffle()
{
randomizedQuestions = QuestionPanel.OrderBy(p => Random.value).ToArray();
}
public void ShowNextQuestion ()
{
if(currentIndex >= randomizedQuestions.Length)
{
// Up to you. You can either just stop
Debug.LogWarning("No more questions available", this);
return;
// Or you could just start over
Shuffle();
currentIndex = 0;
}
if(currentPanel) currentPanel.SetActive(false);
currentPanel = randomizedQuestions[currentIndex];
currentPanel.SetActive(true);
currentIndex++;
}
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
}
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.