I have a gameObject 'gm' which has a script. That script has a reference to Transform parentFoo, and needs to access a non-static, public int 'x', which exists and is defined in a script attached as a component to multiple children 'bar', which are all children of parentFoo. I'm then trying to throw all these ints into a list, but the issue is with actually getting them. What's the simplest way to get this done?
The following code demonstrates what I'm trying to get done, but it doesn't work at all.
//defined in UnityEditor:
public Transform fooParent;
void blah () {
List<int> list = new List<int>();
for (int i = 0; i < fooParent.childCount; i++) {
Transform tempChild = Players.GetChild(i);
list.Add (tempChild.x);
}
}
Any theoretical discussion on why and how your answer works is more than welcome :D ("teach a man how to fish...")
EDIT: specifying title, copied text to stackoverflow; removed link from Unity Answers b.c. question was fully addressed here
New Code:
public Transform fooParent;
public void blah () {
List<int> list = new List<int>();
for (int i = 0; i < fooParent.childCount; i++) {
Transform tempChild = fooParent.GetChild(i);
list.Add (tempChild.gameObject.GetComponent<ScriptName>().x);
}
}
This is because .GetChild returns a transform so from there you must use .gameObject to get the GameObject that that transform is attached to. From there you can access the components attached to that gameobject (Scripts, Transforms, etc...) by using .GetComponent<>() where inside the <> brackets you input the name of the component (in this case the script) you want to access. Now in control of the script you can access its variables by using .variableName. Lastly the void blah should be public void blah. Unless of course you want it to be a private or static method.
Related
I want an array of game objects, each game object has a simple script to move it. I want a controlling script to be able to trigger the remote script by referencing the array coordinates / game object at that point.
I am missing something basic in referencing a "global" variable - so apologies in advance. I have spent several hours now reading and trying things out.
Example questions like here Accessing a variable from another script C#
or
https://answers.unity.com/questions/42843/referencing-non-static-variables-from-another-scri.html
I believe the array should be static as there is only one set of data, however I don't care if it isnt
CreateGrid.cs
public class CreateGrid : MonoBehaviour
{
public static GameObject[,] gridArray = new GameObject[5, 5];
public GameObject gridSpace;
// Start is called before the first frame update
void Start()
{
GenerateGrid();
}
void GenerateGrid()
{
for (int x = 0; x < 5; x++)
{
for (int z = 0; z < 5; z++)
{
gridArray[x, z] = Instantiate(gridSpace, new Vector3(x, 0, z), Quaternion.identity) as GameObject;
}
}
// test grid works
// gridArray[2, 2].transform.Translate(0.0f, 3.0f, 0.0f);
}
}
test code
public class Pulse : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
for (int x = 0; x < 5; x++)
{
CreateGrid.gridArray[x, 3].GetComponent<MoveObject>().StartBounce(5.0f);
}
}
}
The grid of objects works.
However the test code errors with Object reference not set to an instance of an object from the line
CreateGrid.gridArray[x, 3].GetComponent().StartBounce(5.0f);
specifically CreateGrid.gridArray
Given that I seem to be really struggling with a concept, please explain clearly.
Thanks
Unless you don't clearly define otherwise, you don't know when the Start method of two MonoBehaviours will run.
In your case, the Pulse's Start method is called before CreateGrid's.
To fix your problem, I advise you to call CreateGrid's Generate method inside the Awake method of the class.
I often use this method to initialize members of the class not relying on other classes instances and use the Start method to initialize members needing other instances to be self-initialized.
I'm setting up a GameObject pool in unity and i have encountered an error.
I am trying to save an object from a Dictionary to a new gameObject.
Please bear in mind i simplified the code for the post.
public class Pool
{
public string tag;
public GameObject prefab;
public int maximumSize;
}
public List<Pool> pools;
public Dictionary<string, Queue<GameObject>> poolDictionary;
private void UpdatePool()
{
var objectPool = new Queue<GameObject>();
for (int i = 0; i < pool.maximumSize; i++)
{
GameObject obj = Instantiate(pool.prefab);
obj.SetActive(false);
objectPool.Enqueue(obj);
}
poolDictionary.Add(pool.tag, objectPool);
}
public void SpawnFromPool(string tag)
{
// the error is present here:
GameObject objectToSpawn = poolDictionary[tag];
}
If i type:
GameObject objectToSpawn = poolDictionary[tag].Dequeue();
It works just fine, i can dequeue and Enqueue but this isn't the method i want to use. I would highly appreciate any help.
Error type: Cannot implicitly convert type 'System.Collections.Generic.Queue>UnityEngine.GameObject> to 'UnityEngine.GameObject'
As already said the problem is that poolDictionary[tag] is of type Queue<GameObject> not GameObject.
If what you want is retrieve the first element in that queue without using Dequeue (which removes the element from the queue) you can simply use Peek instead
GameObject objectToSpawn = poolDictionary[tag].Peek();
This method is similar to the Dequeue method, but Peek does not modify the Queue.
To retrieve them all without removing them from the queue you can use e.g. ToArray() and run through the elements in a for or foreach loop or simply access a specific one e.g. an equal (not in terms of overhead ofcourse) call to Peek might be
GameObject objectToSpawn = poolDictionary[tag].ToArray()[0];
What I don't understand yet is why using a Queue if you don't want to Dequeue it ...
you could probably simply use a List<GameObject> than since the order of a List is also not changed (at least not without doing it actively)
If this is explicitly for object pooling (what it seems to be from the naming and spawning) you maybe should watch the Tutorial on Object Pooling .. spoiler: They use a List ;)
I'm trying to create a search interface similar to Facebook's. That is, you type in all or part of a name, and the matches are displayed in a list below.
I know how to extract the input from the InputField (SearchBar) but I don't know how to display the matching results in the panel below during runtime.
Create a new label/button for each match and append to... the panel?
What container should I use?
How do I actually "add/append"?
Any help would be much appreciated.
Here is my scene:
And here is my code:
using UnityEngine;
using UnityEngine.UI;
using System;
public class SearchScript : MonoBehaviour {
public InputField SearchBar;
public GameObject Panel;
public List<String> myList;
public void Start() {
myList = new List <String>();
myList.Add("Andre");
myList.Add("Angela");
myList.Add("Temi");
myList.Add("Tupac");
myList.Add("Graham");
myList.Add("Grandpa");
myList.Add("Michael");
myList.Add("Miguel");
SearchBar.onValueChanged.AddListener(delegate {ValueChangeCheck(myList); });
}
public void ValueChangeCheck(List<string> myList) {
string contents = SearchBar.text;
List<String> outList = new List <String> ();
for (int i = 0; i < myList.Count; i++) {
if (myList [i].Contains (contents)) {
outList.Add (myList [i]);
}
}
for (int i = 0; i < outList.Count; i++) {
>>HELP<<
}
}
}
This page in the Unity manual describes what you'll need to do in general terms. The first thing you'll want to do is (in the editor) make a blank button/label or whatever it is you want your final product to look like. For this example, I'm going to act like it's going to be a button. Once you've got the button looking the way you want, set the position to (0,0) and make it a prefab. Make a public field in your MonoBehaviour and drag the prefab into it in the editor. That will look like this:
public GameObject ButtonPrefab;
Next, in your loop, you'll need to instantiate each button, making sure that you parent the new object to your canvas (which is your SearchBar's parent, so we have an easy way to get at it). Then assign your text and shift it down and you'll be golden!
for (int i = 0; i < outList.Count; i++) {
var newButton = Instantiate(ButtonPrefab,SearchBar.transform.parent,false) as GameObject;
// This assumes you have a Text component in your prefab
newButton.GetComponent<Text>().text = outList[i];
// You'll just have to experiment to find the value that works for you here
newButton.transform.position += Vector2.down * 20 * (i + 1);
}
Hi guys i'm trying to drive in the my GameObject (The Player) in my Project, I want a script to navigate to a var in a script that is on another GameObject. It's not easy because there is Parents and children... Here is my tree:
>PlayerEntity
>Canvas
Gun_Name_Text
Gun_Ammo_Text
>Player
Sprite
I want a script attached to 'Gun_Name_Text' to fetch a var in a script attached to 'Player', so i didnt manage to do it with :
var ammo1 = GetComponentInParent<GameObject> ().GetComponent<weapon> ().weaponOn.Ammo1;
PS: I prefer not to use GameObject.Find()
Thanks in advance
As I said in the comments, the easiest way to do this would to be to just assign the variable in the inspector. However if you can't do this then you could simply use:
OtherScript otherScript = null;
void Start()
{
otherScript = transform.root.GetComponentInChildren<OtherScript>();
}
Note: This will set otherScript equal to the first instance of the OtherScript that it finds in the child objects though. You will have to use GetComponentsInChildren if you have more than one OtherScript object in the children.
For your specific example you could use:
var ammo1 = transform.root.GetComponentInChildren<weapon>().Ammo1;
If you are calling this often then it would be wise to cache a refrence to the weapon script though. You will also have to do this if you want to modify the Ammo1 variable that is a member of the weapon class as it is passed to the var ammo1 by value and not by reference.
There are cases where my game object does not know everything that interacts with it. An example would be a destructible object. If I wanted to know so what I'm hitting that was destructible I'd have all destructible objects inherit from a base type or interface and search on that type. Here is an example:
private void CheckForDestructables(Collider2D c)
{
this.Print("CheckForDestructables Called");
string attackName = GetCurrentAttackName();
AttackParams currentAttack = GetCurrentAttack(attackName);
D.assert(currentAttack != null);
this.Print("CheckForDestructables Called");
if (currentAttack.IsAttacking && c.gameObject.tag == "Destructable")
{
List<BaseDestructibleScript> s = c.GetComponents<BaseDestructibleScript>().ToList();
D.assert(s.Any(), "Could Not find child of type BaseDestructibleScript");
for (int i = 0; i < s.Count(); i++)
{
s[i].onCollision(Movement.gameObject);
}
}
}
I would like to change the color of multiple gameobjects in Unity using a single script. I'm kinda lost in the way how to do it. I'm new to Unity and this is some sort of basic training for me.
Unity version: 5.3.4
Observed Behavior:
Added the same script to the other gameobjects and all change to the same color
Expected Behavior:
Change the color of the gameobjects individually
List of things tried:
Using the -FindGameObject-
Tried to acces the materials using the -GameObject-
Tried both at the same time
Thinking in multiple scripts to achieve the results I want
Here's the code
C#:
using UnityEngine;
using System.Collections;
public class ChangeColor : MonoBehaviour
{
//If I change these variables to -GameObject-
//It blocks me to access the renderer
//Making the variables public doesn't work either
private Renderer cube;
private Renderer sphere;
void Start ()
{
//Tried here the -FindGameObjectWithTag-
cube = GetComponent<Renderer>();
sphere = GetComponent<Renderer>();
}
void Update ()
{
if(Input.GetKeyDown(KeyCode.A))
{
//Tried here the -FindGameObjectWithTag-
cube.material.color = Color.red;
}
if(Input.GetKeyDown(KeyCode.S))
{
//Tried here the -FindGameObjectWithTag-
sphere.material.color = Color.green;
}
}
}
Maybe I'm doing something wrong, as I said I'm new to Unity, I kindly accept any help, if it is noobfriendly the better.
Thanks
There are a couple different ways you can go about doing this.
If they are all under the same parent without other objects there too you could loop through the children and change their colors
GameObject Parent = GameObject.Find("ParentObject");
for( int x = 0; x > Parent.transform.childCount; x++);
{
Parent.transform.GetChild(x).GetComponent<Renderer>().material.color = Color.red;
}
If there are less than say 20ish, you could create a list and simply drag and drop each transform into the inspector after changing the list's size to the number of objects you have.
/*Make sure you have Using "System.Collections.Generic" at the top */
//put this outside function so that the inspector can see it
public List<Transform> Objs;
// in your function put this (when changing the color)
foreach(Transform Tform in Objs){
Tform.GetComponent<Renderer>().material.color = Color.red;
}
Similarly to 2, if you want to do it all in code you can do
//Outside function
public List<Transform> Objs;
//inside function
Objs.Add(GameObject.Find("FirstObject").transform);
Objs.Add(GameObject.Find("SecondObject").transform);
//... keep doing this
//now do the same foreach loop as in 2
You could search by tag (if you have a lot of objects) (i would imagine that this would take a bit longer just because it is going through each component but I have no evidence to back that up)
//Outside function
public GameObject[] Objs;
//inside function
Objs = GameObject.FindGameObjectsWithTag("ATagToChangeColor");
foreach(Transform Tform in Objs){
Tform.GetComponent<Renderer>().material.color = Color.red();
}
And about this comment:
//If I change these variables to -GameObject-
//It blocks me to access the renderer
//Making the variables public doesn't work either
If you make them of type GameObject then you should easily be able to access the renderer simply by doing this:
public GameObject cube;
public void Start(){
cube.GetComponent<Renderer>().material.color = Color.red();
}
And making the variables public allows unity's inspector to see the variables so that you can change them in the unity editor without having to open the script.