So I didn't find something useful, to solve my problem. My script is downloading an JSON Array from my Server and fills some text with that informations.
Thats the part of code:
void DrawUI()
{
GameObject buttonObj = transform.GetChild (0).gameObject; //Gets button to clone it
GameObject g;
int N = allCars.Length;
for (int i = 0; i < N; i++)
{
g = Instantiate(buttonObj, transform);
g.transform.Find("name").GetComponent<Text>().text = allCars[i].carName;
g.transform.Find("type").GetComponent<Text>().text = allCars[i].type;
g.transform.Find("price").GetComponent<Text>().text = allCars[i].price+ "€";
if(balance < int.Parse(allCars[i].price))
{
g.transform.Find("price").GetComponent<Text>().color = Color.red;
} else if (balance >= int.Parse(allCars[i].price))
{
g.transform.Find("price").GetComponent<Text>().color = new Color32(53, 140, 3, 255);
}
g.GetComponent<Button>().AddEventListener(i, OpenBuyDialog);
itemIndex = i;
}
Destroy(prefab);
}
This code loops and creates clones of my buttons, all fine. When user confirms the Buy Dialog, it should reload/refresh the list, but for that I have to delete the old clones. I can't find how to do that properly.
Assume the transform has only one child (buttonObj) at the beginning, then you can delete the clones with this code.
var count = transform.childCount;
for (var i = 1; i != count; ++i)
Destroy(transform.GetChild(i).gameObject);
Add your instantiates objects to a member:
private List<GameObject> buttons;
On refresh, iterate through buttons and call Destroy on each GameObject.
Since you said:
g = Instantiate(buttonObj, transform);
Your clone object is = g.
So you can basically say:
Destroy(g.gameObject);
Related
I declared my Button[] public so i can reference it from my inspector
but it does not appear in my inspector. Please help!!!
I tried restarting the C# as well as re-importing everything in unity....
public rocket rocket;
public Button[] levelButtons;
void Start()
{
for(int i=1 ; i<levelButtons.Length ; i++)
{
// if(i + 1 > rocket.level)
levelButtons[i].SetEnabled(false);
}
}
Button actually is GameObject include Component Button. And you should init size for Array you want to create before using it. I had edited code for example:
//Your array
public GameObject[] levelButtons;
//Object to attach Button
public GameObject panelShow;
//Size for Array
public int sizeArrayButton = 5;
void Awake()
{
//Init size for Array
levelButtons = new GameObject[sizeArrayButton];
for (int i = 0; i < levelButtons.Length; i++)
{
//Create new Object and random for position of Gameobject
GameObject button = new GameObject();
button.transform.parent = panelShow.transform;
button.AddComponent<RectTransform>();
button.AddComponent<Button>();
button.transform.position = new Vector3(Random.Range(100, 50), Random.Range(100, 26), Random.Range(-25, 26));
button.AddComponent<Image>();
button.GetComponent<Button>().onClick.AddListener(() => { Debug.Log($"Button: +{i}+ was clicked"});
levelButtons[i] = button;
}
}
And in Unity, you also make it by using List and Prefabs.
so the issue is solved...so basically what i did was just update my unity version and then it allowed me to use UnityEngine.UI and the issue is now fixed...
Thank you everyone for your time...much apppreciated
I want to instantiate new prefab in array and delete the old one when user click on the next button or on previous button.
I have the array of gameobject prefab something like this:
public GameObject[] prefabMoles = new GameObject[3];
GameObject[] moles = new GameObject[3];
void Start () {
for(int i = 0; i < prefabMoles.Length; i++)
{
moles[i] = (GameObject) GameObject.Instantiate(prefabMoles[i], new Vector3((i-1)*5, 0, 0), Quaternion.identity);
}
}
So now I want to add button on canvas which will be next character and previous will return back one number in array.
For example:
I have Moles array and i instantiate moles[2];
On click on next button I want to destroy moles[2] and instantiate moles[3].
When we are on moles[3] and when we click previous we must destroy moles[3] and instantiate moles[2].
It would be great to have some effect of spawn new one but doesn't matter.
And then when instantiate the new the button must popup for unlock or for select if the character is unlocked.
Thank you so much community for help if that is possible.
If what you want to do is have your button create a new and destroy the old you can do this one function that can be added to the button's action.
It will look something like:
int currentIndex = 0;
GameObject currentObject;
void Start()
{
//Instantiate initial object
currentObject = Instantiate(Moles[currentIndex]);
}
public void Previous()
{
Destroy(currentObject);
currentIndex --;
currentIndex = currentIndex < 0 ? Moles.Length : currentIndex;
currentObject = Instantiate(Moles[currentIndex]);
SpawnEffects();
}
public void Next()
{
Destroy(currentObject);
currentIndex ++;
currentIndex = currentIndex > Moles.Length ? 0 : currentIndex;
currentObject = Instantiate(Moles[currentIndex]);
SpawnEffects();
}
void SpawnEffects()
{
//put your desired Effects
}
Essentially you are keeping track of what has been created and what is the next item that you want to make.
I am trying to create a list of buttons using information collected from www forms in my program. The problem I am having is that when I create the buttons, it infinitely creates them, and thusly unity crashes. I have two theories as to why this is happening, the first being that the function is being called each frame and is therefore creating too many buttons and the second is that for some reason when I check the length of a multidimensional array it has a length of 33 when it should only have a length of 3 (it should have 3 arrays of arrays). The whole script is below.
using Boo.Lang;
using System.Collections;
using SCG = System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using System;
public class MeetingRequestViewer : MonoBehaviour
{
//This script contains the code on how to display information about the students to the staff
//it displays each student in a different row
private Rect windowRect = new Rect(0, 0, Screen.width, Screen.height);
public Vector2 scrollPosition = Vector2.zero;
private int BSpace;
public string[,] SortedStudentArray;
private int j;
private string[][] MeetRequests;
private string[] temp;
private SCG.List<string> H_Priority = new SCG.List<string>();
private SCG.List<string> M_Priority = new SCG.List<string>();
private SCG.List<string> L_Priority = new SCG.List<string>();
private SCG.List<string> FullList = new SCG.List<string>();
private SCG.List<string> UAList;
private SCG.List<object> StudentButtonList = new SCG.List<object>();
private string[] Holding = new string[5];
private string[] SearchTerms;
public int ButtonSpacing = 10;
public int ButtonWidth = 80;
public int ButtonHeight = 30;
public void OnGUI()
{
//create a window
GUI.Window(0, windowRect, WindowFunction, "Meeting Request Viewer");
}
public void WindowFunction(int windowID)
{
//Fetches all user Data
string[][] userArray = GetComponent<Userdata>().CallDetail();
string[][] StudentArray = GetComponent<Userdata>().UserSorting(userArray);
//Calls the SortStudentArray method
string[,] SortedStudentArray = SortStudentList();
//Creates a box with a scrolling bar to taverse the y axis
scrollPosition = GUI.BeginScrollView(new Rect(Screen.width / 6, Screen.height / 6, 350, 250), scrollPosition, new Rect(0, 0, 300, 40 * SortedStudentArray.Length));
//for each row in the sorted student array
for (int x = 0; x < SortedStudentArray.Length - 1; x++)
{
//This keeps the gap between each button consistent
var y = ButtonSpacing + ButtonHeight;
//Regular Meeting Request
if (SortedStudentArray[x, 7] == "1")
{
//Urgent Meeting Request
if (SortedStudentArray[x, 8] == "1")
{
Debug.Log("Even Here");
//Create Button coloured red
GUI.backgroundColor = Color.red;
}
//Regular Meeting Request
else
{
//Create Button coloured yellow
GUI.backgroundColor = Color.yellow;
}
}
//No Meeting Request
else
{
//Create Button coloured green
GUI.backgroundColor = Color.green;
}
GUI.Button(new Rect(ButtonSpacing, ButtonSpacing + x * y, ButtonWidth, ButtonHeight), SortedStudentArray[x, 6]);
}
GUI.EndScrollView();
ButtonsCreated = true;
}
private string[,] SortStudentList()
{
//This method is used to fetch the meeting request data, split it into a jagged array and then again so that each
//row is a new user and each item in the row is a different peice of information relating to the user
//The Jagged array is then sorted using the bubble sort algorithm so that the students that require urgent meetings
//appear at the topo of the request table
//call website with the data store
WWW MeetReqData = new WWW("http://localhost/Wellbeing/meetingrequest.php");
//until WWW is finished do nothing
while (MeetReqData.isDone == false)
{
}
//convert the returned value into a string
string MeetReqString = MeetReqData.text;
//split the text into a string list
string[] mrq = MeetReqString.Split(';');
//convert the string list into a jagged array
MeetRequests = new string[mrq.Length][];
int i = 0;
//for each item in the list
foreach (string s in mrq)
{
//split it into its individual peice of information
string[] g = s.Split('|');
//store the information about a user on a new line
MeetRequests[i] = g;
++i;
}
for (int n = 0; n < MeetRequests.Length - 1; n++)
{
if (MeetRequests[n][1] == "1" && MeetRequests[n][2] == "1")
{
H_Priority.Add(MeetRequests[n][0]);
}
else if (MeetRequests[n][1] == "1" && MeetRequests[n][2] == "0")
{
M_Priority.Add(MeetRequests[n][0]);
}
else
{
L_Priority.Add(MeetRequests[n][0]);
}
}
//Combines all lists into a larger list of priorities
FullList.AddRange(H_Priority);
FullList.AddRange(M_Priority);
FullList.AddRange(L_Priority);
//convertFullList into an array for easier mainpulation and comparisons
string[][] feelingsArray = GetComponent<Userdata>().CallFeelings();
//FullList only contains 3 values
Debug.Log(FullList.Count);
//Info array about each user
string[,] SortedStudentArray = new string[FullList.Count, 11];
//SortedStudentArray contains 33 rows
Debug.Log("This thing Here");
Debug.Log(SortedStudentArray.Length);
//Line Counter
int SSAPos = 0;
// For every element in FullList
foreach (var item in FullList)
{
Debug.Log(FullList.Count);
//For each user in userArray
for (int y = 0; y < Userdata.userArray.Length; y++)
{
if (Userdata.userArray[y][0] == item)
{
for (int n = 0; n < Userdata.userArray; n++)
SortedStudentArray[SSAPos, n] = Userdata.userArray[y][n];
break;
}
}
Debug.Log(SortedStudentArray.Length);
//For each user in userArray
for (int y = 0; y < MeetRequests.Length; y++)
{
if (MeetRequests[y][0] == item)
{
SortedStudentArray[SSAPos, 7] = MeetRequests[y][1];
SortedStudentArray[SSAPos, 8] = MeetRequests[y][2];
break;
}
}
Debug.Log(SortedStudentArray.Length);
SSAPos += 1;
}
return SortedStudentArray;
}
// Update is called once per frame
void Update ()
{
//if (GUI.Button(new Rect(Screen.width / 4, Screen.height / 7, Screen.width / 2, Screen.height / 8), "Log Out"))
//{
// Debug.Log("Logged Out");
// SceneManager.LoadScene("Login");
//}
}
I did try to use a while loop around the section of code however it made no difference to the creation of buttons, they were still created more times than were needed
FullList is continually being populated which will eventually lead to a crash.
Call SortStudentList in Awake, such as;
string[,] SortedStudentArray;
void Awake ()
{
//Calls the SortStudentArray method
SortedStudentArray = SortStudentList();
}
Then;
public void WindowFunction(int windowID)
{
// Prevent further execution until SortedStudentArray is ready
if (SortedStudentArray == null) return;
...
}
From the documentation:
OnGUI is called for rendering and handling GUI events.
This means that your OnGUI implementation might be called several
times per frame (one call per event). For more information on GUI
events see the Event reference. If the MonoBehaviour's enabled
property is set to false, OnGUI() will not be called.
You need to reevaluate how you're doing your GUI. As mentioned in their GUI scripting guide you should probably use their UI system.
You especially don't want to be making one or more WWW calls per frame, or doing a bunch of sorting every frame.
https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnGUI.html
OnGUI is called for rendering and handling GUI events.
This means that your OnGUI implementation might be called several times per frame (one call per event). For more information on GUI events see the Event reference. If the MonoBehaviour's enabled property is set to false, OnGUI() will not be called.
You should probably use another way to call your method, or use a boolean value to check whether or not it has already been called.
Please refer to the image below to better understand the Unity lifecycle methods.
More information about Unity's Lifecycle can be found at: https://docs.unity3d.com/Manual/ExecutionOrder.html
I have 4 objects each located in a corner of a square. I wish to move these objects clockwise, 1 position per method call.
With the code I have atm, they all just complete the entire loop on 1 method call instead of moving only one position...
My code so far:
void SwitchPositions()
{
tempPosition1 = parent.transform.GetChild(0).GetComponent<Transform>().position;
tempPosition2 = parent.transform.GetChild(1).GetComponent<Transform>().position;
tempPosition3 = parent.transform.GetChild(2).GetComponent<Transform>().position;
tempPosition4 = parent.transform.GetChild(3).GetComponent<Transform>().position;
parent.transform.GetChild (0).GetComponent<Transform> ().position = tempPosition2;
parent.transform.GetChild (1).GetComponent<Transform> ().position = tempPosition3;
parent.transform.GetChild (2).GetComponent<Transform> ().position = tempPosition4;
parent.transform.GetChild (3).GetComponent<Transform> ().position = tempPosition1;
Debug.Log (tempPosition1);
}
If anyone has any ideas how to fix this or at least explain to me why it-s completing the entire loop in 1 method call...
Thank you!
I am really not sure how your timer works or for that matter anything wrong with your code. But I have used the coroutine where after every two seconds the blocks get switched and it happens continuously. I think this should be somewhere close to what you need.
//Predefined positions where objects to place
public Transform[] Position;
//The objects that will will be swapped in coroutines
public Transform[] ObjectsToMove;
private int ObjectIndex = 0;
private bool startupdate = true;
void Update () {
if(startupdate)
StartCoroutine(SwitchBlocks());
}
IEnumerator SwitchBlocks() {
startupdate = false;
int tempIndex = ObjectIndex;
for(int i = 0; i < ObjectsToMove.Length; i++) {
tempIndex = ObjectIndex + i;
if(tempIndex > ObjectsToMove.Length - 1)
tempIndex -= ObjectsToMove.Length;
ObjectsToMove[i].position = Position[tempIndex].position;
}
ObjectIndex++;
if(ObjectIndex > ObjectsToMove.Length - 1) {
ObjectIndex = 0;
}
yield return new WaitForSeconds(2.0f);
startupdate = true;
yield return null;
}
Hope this helps.
Alright I'm stumped here, I can usually figure out most bugs, through use of Google or common sense but this one has me stumped!
I'm trying to load textures to an array of enemies (Like a row in space invaders) within my struct, however when I go to debug it throws a Null Reference, I know this means that I'm trying to access something that isn't there, I believe it's because i am calling this:
Inside Initialize I call my method:
Targets.setupSprite(this);
This is the actual method from inside the struct:
public void setupSprite(Game1 g)
{
widthFactor = 0.05f;
rowSize = 15;
spriteSpacingY = spriteRectangle.Height + 5;
for (int i = 0; i < rowSize; i++)
{
if (i < 15)
spriteSpacing = 10;
sprites[i].spriteTexture = g.texture;
x = 0 + (i * spriteSpacing);
y = spriteSpacingY;
visible = true;
}
}
Before the Textures can be setup by Content Loader.
It recommends using 'new' but I'm not sure how to use it here.
The line that throws the error as you may have guessed is:
sprites[i].spriteTexture = g.texture;
g.texture is the texture for the enemy and is located in load content.
Any help would be greatly appreciated!
Additional Code:
protected override void Initialize()
{
displayHeight = GraphicsDevice.Viewport.Height;
displayWidth = GraphicsDevice.Viewport.Width;
new TargetRowStruct();
BreadBat.setupSprite(this);
CheeseBall.setupSprite(this);
Targets.setupSprite(this);
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
texture = this.Content.Load<Texture2D>("Handsome");
swag = this.Content.Load<Texture2D>("swag");
back = this.Content.Load<Texture2D>("Backdrop");
font = this.Content.Load<SpriteFont>("FontA");
backRect.Width = (int)displayWidth;
backRect.Height = (int)displayHeight;
BreadBat.loadTexture(this);
CheeseBall.loadTexture(this);
Targets.loadTexture(this);
BreadBat.scaleSprites(this);
CheeseBall.scaleSprites(this);
Targets.scaleSprites(this);
}
Relevant Code within Targets Struct:
public void scaleSprites(Game1 g)
{
for (int i = 0; i < rowSize; i++)
{
sprites[i].spriteRectangle.Width = (int)((g.displayWidth * sprites[i].widthFactor) + .25f);
sprites[i].aspectRatio = (int)(sprites[i].spriteTexture.Width / sprites[i].spriteTexture.Height);
sprites[i].spriteRectangle.Height = sprites[i].spriteRectangle.Width;
}
}
public void loadTexture(Game1 g)
{
for (int i = 0; i < rowSize; i++)
{
sprites[i].spriteTexture = g.texture;
}
}
public void drawSprite(Game1 g)
{
g.spriteBatch.Draw(spriteTexture, spriteRectangle, Color.White);
for (int i = 0; i < rowSize; i++)
{
if (sprites[i].visible)
{
g.spriteBatch.Draw(sprites[i].spriteTexture, sprites[i].spriteRectangle, Color.White);
}
}
}
public void setupSprite(Game1 g)
{
widthFactor = 0.05f;
rowSize = 15;
spriteSpacingY = spriteRectangle.Height + 5;
for (int i = 0; i < rowSize; i++)
{
if (i < 15)
spriteSpacing = 10;
x = 0 + (i * spriteSpacing);
y = spriteSpacingY;
visible = true;
}
}
P.s It should be noted that the bread and cheese struct which are almost identical (except for being one sprite instead of an array) work fine.
I still suspect, that inside Target struct You don't initialize this sprites[] array;
So, either at the execution time sprites == null or sprites[i] = null;
As I can see, there are three methods invoked on Targets, one is Targets.setupSprite(this); called inside Initialize.
Targets.loadTexture(this); Targets.scaleSprites(this); => those two are called inside LoadContent.
Now, as msdn states, Initialize method is "Called after the Game and GraphicsDevice are created, but before LoadContent."
If, after removing problematic line (which I see You did in the code You added in edit), NullPointerException isn't thrown in relation to sprites[] array, it means, the array is initialized but somewhere after Targets.setupSprite(this);.
If it is thrown, it's probably that You didn't initialize it at all.
The exception is pretty clear, sprites is null. Instantiate it using sprites = new Sprite[100] (or whatever class and size you require) and you're good to go.