Access variables or methods from another class (or gameObject) [C#]
Hi all,
I am new to Unity, and wasn't able to find a straight answer to this question, I'm looking for general guidelines instead of a specific "fix my code" (e.g., learn to fish rather than get a fish).
I wanted to know how to access variables or methods from another class or gameObject. Specifically, up to this point, I've been able to access variables from other classes on the same gameObject by typing something to the effect:
//setting variable to equal variable of another class within the game object
new_variable = anotherclass.anotherclass_variable;
However, this same approach does not work if I it for methods, I get the following error from the same code for a method:
anotherclass.anotherclassmethod();
error CS0120: An object reference is required to access non-static member `Spawn_FoodSpawner.anotherClassMethod()'
In terms of solutions
I don't want to use a find method looking for a tag; I'd prefer to use an approach that either:
1) is able to specify the gameObject the script is currently attached to (tried "this.gameObject" which does not work) 2) is able to specify another gameObject by collision detection or some other effect.
Any suggestions are most welcome and appreciated. Happy New Year!
Answer by KoenigX3 · Jan 07, 2017 at 10:22 PM
Accessing the variables and functions of an other script depends on the access modifiers they have, and finding the right reference to the script.
What you want to do is to find the other gameobject, get the script component it has, and access its variables and methods.
Lets start from this scenario: you have a 'Ball' gameobject with a 'BallScript' component attached to it, and you have a 'Cube' gameobject with a 'CubeScript' component attached to it. If you type 'this.gameObject' or 'gameObject' into 'BallScript', you will get a reference to the 'Ball' gameobject, since the 'gameObject' variable always refers to the gameobject the script is attached to. If you want to have a reference to the 'Cube' gameobject in the 'BallScript', you have to call GameObject.Find("Cube"), or create a public GameObject typed variable, compile it, and assign the 'Cube' gameobject from the Scene Hierarchy to the Inspector.
So far, we know how to get reference to any gameobject in the scene. Note, that the GameObject.Find() method is for runtime use, and it should be only used if there are only a few gameobjects in the scene. There are various other methods for this purpose, like GameObject.FindWithTag(), or creating a new variable, and assigning the gameobject to it when you are instantiating the object. If the gameobject is always in the scene (from the beginning), you can use the public variable method described above.
Now we have to get the script component. If you use GetComponent, you can get a reference to the script named 'Type' on the gameobject this script is attached to. So, if you write GetComponent in the 'BallScript', you will get the 'Ball' gameobject's 'BallScript' component - which obviously makes no sense, since you are in that script. If there is an other script on the 'Ball' gameobject, for example 'Ball2Script', you can use GetComponent to access the 'Ball2Script'. But the most important thing is, that if you use a gameobject reference before GetComponent, you can get references to the script on the gameobject you refer to. For example, if you type this in the 'BallScript': GameObject.Find("Cube").GetComponent, you will have a reference to the 'CubeScript' component. Note that you have to use () after the type of the GetComponent (Ex.: GameObject.Find("Cube").GetComponent().variable).
One more thing to remember is that variables and methods have access modifiers like 'private', 'public', 'protected', 'internal'. You will most likely only meet the first two of them. If you want to access the variable or method from an other script, you should always tag the variable or method as 'public'.
Now we are ready to deal with any gameObject and component references. Objects can only collide with each other, when they both have colliders attached to them. When this situation happens, the method OnCollisionEnter is called on the scripts of both gameobjects (OnCollisionEnter2D in 2D worlds, and OnTriggerEnter if the collider is set to be a trigger in the Inspector).
void OnCollisionEnter(Collision collision) {
// This code will run when the gameobject detects collision
}
When this method is called, the collision variable is filled with data about the collision, which contains a reference to the gameObject we are colliding with (the variable is named as gameObject).
So if you insert the following lines into 'BallScript', and the 'Ball' and the 'Cube' collides, you will get a reference to the 'CubeScript', and you can modify or use its variables and methods.
void OnCollisionEnter(Collision collision) {
collision.gameObject.GetComponent<CubeScript>().someVariable = 0;
}
I hope you will find the answer in this 'short' tutorial. Happy New Year!
This is very excellent. A quick addendum for clarification:
in your example:
void OnCollisionEnter(Collision collision) {
// This code will run when the gameobject detects collision
}
Can you elaborate on what Collision collision is? Is that declaring a variable of type "Collision", and somehow Unity knows to reference that to the collided game object (i.e., the cube in your example)?
Thanks!!
The Collision class holds variables that can describe the collision itself, like a reference to the collider it has met, an array of the contant points, reference to the other gameObject and so on. For more information, read this:
https://docs.unity3d.com/ScriptReference/Collision.html
When a collision is detected between two colliders, both gameobject receive an OnCollisionEnter call, as i described above. The function also gives you a 'collision' named instance (which has a Collision type). This variable is filled with various information (see the Collision class) about the collision, which has just happened right now. The purpose of this is that you can use it to make difference between collisions (you can check if you have collided with gameObject A or gameObject B in the scene), or to use the data for further calls (for example, you can Debug.Log() the magnitude of the impulse).
Or - if we stay at our first scenario - you could add a Light component to the 'Ball' and 'Cube' gameObject, and write this into the 'BallScript':
void OnCollisionEnter(Collision collision)
{
GetComponent<Light>().intensity = 2.0F;
collision.gameObject.GetComponent<Light>().intensity = 2.0F;
}
Now, whenever there is a Cube and a Ball in the scene, and these two objects collide at runtime, the first line will set the intensity of the Ball's light to 2 (since GetComponent will get the Ball's Light component by default, because the script is attached to the Ball gameObject, and not the Cube), and the second line will set the intensity of the Cube's light to 2, since it was the gameObject we have collided with.
EDIT: In short, yes. Sorry for the long answer, but i think this will help you with your further problems.
I gave you all my points for this answer. Thanks, was exactly what I was looking for, and you gave a very in depth answer. Cheers!
Your answer
Follow this Question
Related Questions
How do I reference an Instantiate object? 1 Answer
Having referencing Problems while creating a tile brush for an editor in unity 0 Answers
How to track variables by reference.. 0 Answers
Accessing a variable from another script (Bomberman Bomb Limit) 1 Answer
Unity 5 Accessing other scripts problem 2 Answers