How to get GameObject references - c#

Hi i was wondering if there are other ways to set a GameObject active through code in c#
the only one i know is to do this:
public GameObject box;
box.SetActive(true);
which really great, you can just drop of the object on the inspector but i was wondering if there are other ways
like using a specific name of an object or turning GameObjects into active with a certain tag. I'm having a hard time trying to find an example whenever i google it or maybe i'm searching it wrong
any advice?

Did you have a look at the GameObject API or the Manual?
There are Find, FindWithTag, FindGameObjectsWithTag
or also methods like GetComponentInChildren, FindObjectOfType, FindObjectsOfType
(those you can use to find a certain type of component and thereby there according gameObject you can than set (in)active)
but since you requested activateing multiple objects by tag:
var targetObjects = GameObject.FindGameObjectsWithTag("YourTag");
foreach(var obj in targetObjects)
{
obj.SetActive(true);
}
note however that this is a lot more expensive than having the references from the inspector. So in general try to avoid using these FindXY methods if possible.
And yes how remy_rm pointed out correctly in the comments you definitely should not use them in any update loops, or other methods that get called regularly. You should always call them e.g. in Awake, Start etc and store the references for later
Update
If I understand your comment correctly you additionally have some children in those tagged objects that you also want to set active:
var targetObjects = GameObject.FindGameObjectsWithTag("YourTag");
foreach(var obj in targetObjects)
{
obj.SetActive(true);
// also activate all children
foreach(Transform child in obj.transform)
{
child.gameObject.SetActive(true);
}
}

Related

GetComponentsInChildren by name

I'm searching for the best way to GetComponentsInChildren by their name. The case is like this, in my GameObject I have a couple of gameobjects that all are named the same.
I want to access all of them by searching for the name and then changing the material of them. The changing material part is already done in the code further down.
gameobject.GetComponentInChildren<Transform>().Find(Name).GetComponent<MeshRenderer>().material = newMaterial;
The upper code worked for getting one of the gameobjects and changing the material. My question is how to get all of the gameobjects and change the material.
(There are not always the same amount of gameobjects)
As you have it now it makes little sense.
GetComponentInChildren returns exactly one single object -> the same this is called on since GetComponentInChildren also looks for the component on itself!
Find again only returns one single object that is somewhere nested below this object.
Why even use GetComponentInChildren<Transform> when you later anyway rather want a MeshRenderer reference?
I think what you are trying to do is rather get all MeshRenderer components, then filter them by name.
foreach(var meshRenderer in gameobject.GetComponentsInChildren<MeshRenderer>(true))
{
if(meshRenderer.name == Name)
{
meshRenderer.material = newMaterial;
}
}
Note the s in GetComponentsInChildren -> This returns ALL MeshRenderer references nested under this object (including this one). By passing in true as parameter this also includes inactive GameObjects and disabled Components.
You could also use Linq Where like
foreach(var meshRenderer in gameobject.GetComponentInChildren<MeshRenderer>(true).Where(meshRenderer => meshRenderer.name == Name))
{
meshRenderer.material = newMaterial;
}

Spawning gameobjects relative to the position, width and length of another gameobject?

I'm currently developing a game in Unity using C# and I've run into a small problem.
I need to spawn a certain gameobjects relative to the Spawnposition and length of another game object. Now I figured that bounds.size would be the best function to use in this instance. As shown bellow I declare first the variable that uses this in my start method:
public void Start()
{
GameObject PointBar = (GameObject) Resources.Load("PointBar Horizontal");
PointBarVectorLength = PointBar.GetComponent<BoxCollider2D>().bounds.size.x;
PointBarVectorConv = Camera.main.WorldToViewportPoint(new Vector2(PointBarVectorLength, 0f));
}
However, the gameobjects in question are inactive at start's call and thus I presume don't return any value for bounds.size when called.
Does anyone know how I can access the bounds.size or equivalent of an inactive gameobject or is there something else I'm missing here?
As noted in the documentation for the Collider.bounds property, bounds "will be an empty bounding box if the collider is disabled or the game object is inactive". So your assumption was pretty much right. Since the object doesn't exist in worldspace that makes sense.
I'm not sure about the most elegant solution for your use case but two options spring to mind.
Calculate the object's spawn dimensions by accessing its transform.localScale and factoring in the scale of prospective parent objects. That could get messy but you could probably also write a helper method to make it more manageable.
Instantiate the object somewhere off screen after you load it, access its Collider.bounds property to get the information you need then move it where ever you want it or store the information for later.
There may be better solutions but that's what leaps to mind for me.
I solved the issue by using GetComponent().bounds.size.x;
instead of BoxCollider. This component can get accessed when the game object is not active.

How can I destroy multiple game objects at once?

I am trying to figure out how I can basically stand on a pressure plate and have something that's in the way disappear. I have it working to destroy the object you interact with but not finding any solution to make another object be destroyed.
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("PressurePlate"))
{
Destroy(collision.gameObject.CompareTag("tree"));
}
}
Destroy(Object) takes in an Object, more specifically, a component or a game-object;(Though nothing would happen if you attempt to destroy a boolean, like what you did in this case; Someone can correct me on that though.)
If you want to destroy the game-object that it has collided with, Destroy(collision.gameObject) would do it.
If you want to destroy all GameObjects with a specific tag, you can do GameObject.FindGameObjectsWithTag(tag), like so:
foreach (var gameObj in GameObject.FindGameObjectsWithTag("Your target tag")){
Destroy(gameObj);
}
There are a few other methods like Object.FindObjectsOfType(Type) which you can use to fetch all game-objects with a certain type.
But since they are generally slow, I do not highly recommend using those unless you need to;You can consider caching the respective game-objects somewhere first, and destroying them later.

How to reach to the child of a game object using FindGameObjectWithTag

In the hierarchy, I have a parent Game Object (named "parent"), which has a child (named "child" and tagged "John"). Initially, The parent is active but the child is inactive.
The parent has a script component, in the Update() function of which I have:
GameObject go = GameObject.FindGameObjectWithTag("John");
go.SetActive(true);
It doesn't work and I get "NullReferenceException: Object reference not set to an instance of an object" in the console. Even if the child is initially activated and I want to deactivate it, it still doesn't work and I get the same error. Why? And is it a good idea to use FindGameObjectWithTag() in Update() in the first place?
In Unity, you can't get an inactive GameObject using any Find function unfortunately.
If you're not creating your GameObject go dynamically, use a public variable and assign it via inspector, it's way better performance wise (as Unity probably uses references), and it's easier (imagine you change a tag, you won't need to check in all your code references to that tag)
As pointed out by Jichael, you cannot use Find functions to get inactive gameobjects.
You can however use:
var yourComponent = GetComponentInChildren<YourComponentType>(true);
If your child object has any component attached to it, you could easilly get it like this. Note the true (boolean) parameter. This is used to indicate that you want to check for inactive gameobjects.
A more detailed example:
var spriteRenderer = GetComponentInChildren<SpriteRenderer>(true);
spriteRenderer.Sprite = yourSpriteVariable;
spriteRenderer.gameObject.SetActive(true);
This is also better performant than using Find functionality, since you only need to look through the child objects of the calling behaviour.

Multiple Checkpoints / Respawning Zones

Basically I have three classes to try and collect the checkpoints and respawn at the last one reached. The code seems fine, however I'm getting a null reference error upon reaching the checkpoint during runtime. The problem seems to be inside Unity.
private CheckPoint cp;
I can't get anything to go into the inspector section for this instance. Granted, I do a call upon start
cp = GameObject.FindGameObjectWithTag("Checkpoint").GetComponent<CheckPoint>();
I've tired an empty object and I've tried placing one of my checkpoint objects but nothing seems to work. Any advice?
1. Check if you have multiple gameObjects tagged "CheckPoint".
cp = GameObject.FindGameObjectWithTag("Checkpoint").GetComponent<CheckPoint>();
is going to find the first gameObject with that tag and try to get your component, if there is no component, you will get null reference
2. Use this instead
FindObjectsOfType<Checkpoint>();
for more: https://docs.unity3d.com/ScriptReference/Object.FindObjectsOfType.html
3. Use a list/array/any other container in your "CheckpointManager" class and into Start() method of each Checkpoint do:
CheckpointManager.container.add(this);
this should be much easier to manage and you will not have to use tags.

Categories