Go to Top

A tutorial and video showing you how to use GetComponent to interact between scripts.

In this tutorial

  • Accessing another script from inside the object
  • How does GetComponent work?
  • Getting many components
  • Interaction between objects.
  • Interaction between objects within the hierarchy
  • SendMessage and BroadcastMessage
  • Interactive functions

You can find the exact same tutorial using UnityScript here or using Boo here .

Introduction

One recurrent issue when starting with Unity is how to access the members in one script from another script. Many would think that dereferencing from the script name would be enough, they quickly realize it is not.

When developing a program, variables are stored in the memory at different locations. If an object could see any other object members, there would a risk to modify them even though it was not intended. If for instances two objects hold the same script with the same variable names, the compiler would not be able to figure out which one we are referring to.

To prevent this issue, each object in memory cannot see other objects. It is then necessary to tell one object where the variable it needs is in memory. The whole pointer principle has been dropped long ago and now we are using reference instead (which actually uses pointer internally).

There are actually various way to access variables, some are better than others and some are simply to be used in particular situations.

To summarize, there are three ways:

  1. GetComponent, the most common, also the one that confuses most at first
  2. SendMessage, it might look easier to grasp but it is also less efficient.
  3. Static variables, the easiest to use but also the most complicated to fully understand at first.

In this tutorial we will cover the GetComponent section using C#.

Create a new scene and add an empty game objects and name it “StormTrooper”. Create two scripts named “Health” and “Force”. Add both scripts to StormTrooper.

Open up both scripts in the editor and add these lines:

Health.cs

using UnityEngine;
using System.Collections;
public class Health : MonoBehaviour
{
	public int health = 5;
        bool hasForce;
	void Update()
	{
		if (Input.GetKeyDown(KeyCode.Space))
		{
			hasForce = Force.ReportForce();
			if(hasForce)health = 10;
		}
	}
}

Force.cs

using UnityEngine;
using System.Collections;

public class Force : MonoBehaviour
{
	private bool force;
	void Start()
	{
		force = true;
	}

	void Update()
	{
		if (Input.GetKeyDown(KeyCode.P))
			print("I have" + (force?" the":" no") + " force");
	}

        public bool ReportForce()
	{
		return force;
	}
}

Trying this code will simply return error “An object reference is required to access non-static members”.

We need to tell Health where is Force so that it can access its members. Since our scripts are both on the same object we simply need to declare a variable of type of the script we wish to access and use GetComponent to find the script.

Accessing another script inside the object

Modify Health with:

using UnityEngine;
using System.Collections;

public class Health : MonoBehaviour
{
	public Force script;
	public int health = 5; 
        bool hasForce;
        void Start(){
            script = GetComponent<Force>();
        } 
        void Update() { 
             if (Input.GetKeyDown(KeyCode.Space)) { 
                     hasForce = script.ReportForce(); 
                     if(hasForce)health = 10; 
             } 
        }
}

With the modifications, run the game, press Space and then press P, your StormTrooper now has 10 of health (Note that a StormTrooper does not have the force, this is only for the example). You access variables the same you accessed methods. Just make sure the members you are trying to reach are declared public or you will get an error.

If the members were private, it would not be possible to access them.

How does GetComponent works?

First we declare an object of the type of the script we want to reach.

Force script;

Force is our type and script is just a name we provide for using the reference in the script. We could give it any name.

The GetComponent function will look inside the object (the StormTrooper instance) to find a component corresponding to the type we passed. If none is found a null reference is returned and our script variable will not do anything. If a component of type Force is found then the address of that component is passed to the variable script, the variable now points to the Force component stored somewhere in memory. In order to access the public members of Force, we just need to dereference the script variable using the dot operator.

script.PublicMembers;

Private members will remain inaccessible.

Reference

So I can cache component with GetComponent?

Yes, and it is recommended to do so for some regularly used component like the Transform.

When accessing built-in component such as Rigidbody, Transform, Renderer,...etc, Unity allows "direct" access like this:

void Update(){
    transform.position += transform.forward;
}

But what Unity does behind is actually:

void Update(){
    GetComponent<Transform>().position += GetComponent<Transform>().forward;
}

GetComponent should be avoided inside Update so cache with a few simple lines of code like:

Transform _transform;

void Start(){
     _transform = GetComponent<Transform>();
}

void Update(){
     _transform.position += _transform.forward;
}

This will save some computation.

Getting many components

What if our StormTrooper has many Force within itself (not likely though). Duplicate the Force twice so StormTrooper has three of them.

Health becomes:

using UnityEngine;
using System.Collections;

public class Health : MonoBehaviour
{
	private Force [] scripts;
        public int health = 5;

	void Start()
	{
		scripts = GetComponents<Force>();
	}

	void Update()
	{
		if (Input.GetKeyDown(KeyCode.Space))
		{
			for (int i = 0; i<scripts.Length; i++)
				if(scripts[i].ReportForce())health+=5;                                
		}
	}
}

Run the game, press Space, our StormTrooper is becoming a Jedi.

Interaction between objects.

We can also get two objects to interact in a similar way. Create a new object named “Sith”. Remove the duplicated component from the StormTrooper.

using UnityEngine;
using System.Collections;

public class DarkSide : MonoBehaviour {
	const bool force = true;
	Force script;
	void Start () {
		script = GameObject.Find ("StormTrooper").GetComponent<Force>();
	}
	void Update () {
		if(Input.GetKeyDown (KeyCode.Space))
			UseForceToControl ();
	}
	void UseForceToControl(){
		if(!script.ReportForce())
			print ("Do as I say.");
	}
}

Modify the force script of the StormTrooper so that he does not have the force (The Sith would find this suspicious...)

Below is the line that finds the StormTrooper and get its Force component.

void Start () {
     script =GameObject.Find ("StormTrooper").GetComponent<Force>();
}

GameObject.Find() first finds the object passed as parameter and then looks for the required component inside of it. It is recommended to perform those actions in the Start or at a time of the game where lags will not affect the gameplay. GameObject.Find and GetComponent are expensive functions since they need to iterate through the whole Hierarchy. If your scene only includes 10 objects, it will be fine but if it holds thousands of them (an army of clone) you will surely see a bad effect. Consider calling these in the Start function.

Interaction between objects within the hierarchy

Consider a vehicle, the character is attached to it when driving it. Let's think the vehicle has special feature if the driver has the force (better handling, faster and so on). As the driver is attached, he is below in the hierarchy.
The vehicle can find the Force component of the driver with the same principle we used previoulsy but we can make it happen faster by indicating to the vehicle that the driver is in its hierarchy.

Force script;
void Start () {
    script =transform.Find ("Sith").GetComponent<DarkSideForce>();
}

GameObject is swapped for transform. Indeed, a child object belongs to the transform of the parent so we need to look into the transform to find our object.

Even better, we can use:

void Start () {
     script =GetComponentInChildren<DarkSideForce>();
}

Now our vehicle can know that our Sith has the force and apply special feature.

In this example, we need to check for each kind of driver if it is a StormTrooper or a Sith. A better approach would have been to use inheritance so that the top  base class would hold the force variable and one single function would be used for all type of driver. But inheritance and efficiency were not our main issue here.

SendMessage and BroadcastMessage

We have seen different ways toget two objects or scripts to interact. SendMessage and BroadcastMeassage are two other possibilties that may be simpler but also more expensive. The principle remains the same, we have a reference to an object and we want to modify a script it contains.

With SendMessage, you can call a function on an object without having to find a reference to the script. Now you tell me: "What is all this confusion ride if you can make it simple?"

SendMessage is extremely slow and should only be considered in cases where it will not affect the game

And that you should seem logical, with GetComponent we indiacte exactly where the script is located in memory. With SendMessage, the compiler knows the object, but it will go through all the scripts and functions until it finds the lucky winner. This may affect your game if you use it often on multiple objects adn if the object has a lot of components and scripts (which are components by the way).

SendMessage seeks only the object to which the call is made, BroadcastMeassage launches a search on the target object but also on all of its children. Research will be even longer if the object contains a large hierarchy. A newcomer appeared with Unity4 SendMessageUpwards which you should have guessed does the same as BroadcastMessage but upwards so all of the parent of the object until root.

Ok let's consider our Stormtrooper has a function for receiving order

//Order.cs

using UnityEngine;
using System.Collections;

public class Order : MonoBehaviour
{ 
    void ReceiveOrder(string order){
        switch(order){
            case "Fetch":
                 //Action
                 break;
            // other cases            
        }    
    }
}

Now let's consider our StormTrooper meets a commander from the Empire:

// Commander.cs

void Update(){
   if(Input.GetKeyDown(KeyCode.Space))
       GameObject.Find("StormTrooper").SendMessage("ReceiveOrder","Fetch");
}

As you can see, the principle remains the same, I need a reference to the target object and then I send a message to it. Just like GetComponent it is better if you have cached the object reference. Also, I simplified the implementation but an enum would go way  better than a string for the function (faster and less prone to error).

It is also possible to add a parameter to make sure the message finds a receiver or not.

Note that it is not possible to use a function returning a value. You would then have to go back up and use GetComponent.

Interactive functions

Unity uses many features that make two or more objects interact. The advantage of these functions is that they store a lot of information on the other object.

  1. Collision functions OnTriggerXXXX/OnCollisionXXXX
  2. Physics functions XXXXcast

Here it is for collision declaration:

void OnCollisionEnter(Collision colReference){}
void OnTriggerEnter(Collider colReference){}

The call of the function creates a variable of type Collision or Collider. The function will fill this instance with information on the collision and will hold a reference to the other object we are interacting with.

void OnCollisionEnter(Collision colReference){
   if(colReference.gameObject.tag == "StormTrooper"){
       Health script = colReference.GetComponent<Health>();
       script.health -= 5;
   }
}

Notice that I do not need to look for the other object as colReference as a reference to that object as member. Now I can perform my GetComponent as usual and access my public health variable.

Functions from the physics class have a similar principle. The data are not stored in a Collision/Collider instance but in a RaycastHit instance:

using UnityEngine;
using System.Collections;

public class CheckFlat: MonoBehaviour {
    void Update() {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit)){
            float result = Vector3.Dot(hit.normal,Vector3.up);
            if(Mathf.Abs(result) > 0.9)print ("Flat Enough");
            else print ("Not Flat Enough");
        }
    }
}

I declare a variable of type RaycastHit, I pass it to the function. RaycastHit is a structure and then a value type, I need the out keyword to create a reference to that structure so that the function can modify the structure. What I am doing here is check how flat is the surface I am hitting. This is useful for strategic games where you want to build but not on a cliff.
I use the dot product of the terrain normal with the Vector3.Up and if the result is close enough to 1 meaning they are aligned, the ground is flat enough for construction.
Obviously, some more calculation are needed as this is only for one point and you would need to check the normal around but you get the idea. I created interaction between my mouse and the terrain using a raycast.

Interaction in action

In order to give a visual and practical representation, the video below summarizes some of the uses for GetComponent.

,

15 Responses to "Script Interaction – GetComponent in C# – v2.0"

    • fafase
      October 21, 2012 - 11:49 am Reply

      Yes, it is coming within a few minutes. Fact is I am working on it as you are trying to access it and I already modified the rest of the pages (which I shouldn’t).
      Please forgive my lack of professionalism on this issue…

  • Memory management
    October 27, 2012 - 6:57 am Reply

    [...] using GameObject.Find() for instance will return a reference to the object in any scripts. See our GetComponent tutorial for more details on finding instances of classes during game [...]

  • Basics of AI-Character | Unity Gems
    January 5, 2013 - 6:14 pm Reply

    [...] fetch the CC so that you can manipulate it. For  a tutorial on how and why fetching component, see here. We also make sure our object contains a CC using an attribute placed before the [...]

  • Greg V.
    February 2, 2013 - 12:16 pm Reply

    Great work. The basic things that looked complicated for me like Shaders, Delegates etc are now much more clearer for me.

    p.s. ScriptA.cs might be named Health.cs

    • fafase
      February 3, 2013 - 8:20 am Reply

      Thanks I will got through it again. I changed the script names to make it easier than ScriptA ScriptB but it seems I forgot some…

      Cheers

      Fafase

  • vijay
    February 14, 2013 - 11:55 pm Reply

    Thanks a lot, You solved all my queries.

  • nekoneko
    March 14, 2013 - 8:56 pm Reply

    Lets say, i have a lot of statements in OnCollisionEnter function, we’ll be better to cache collider data and say:
    void OnCollisionEnter(Collision colReference){
    TAG = colReference.gameObject.tag

    if(TAG == “StormTrooper”){

    else if TAG ==

    else if TAG ==
    }

    or not? :)

  • Chris
    July 10, 2013 - 2:35 pm Reply

    Hi Fafase,

    I wonder if you can tell me what would be preferred method to use (with regards to performance) if I have one instance of a script to reference from many other scripts.

    For example, if I have a Movement script, would you recommend using GetComponent to cache in each script’s Start/Awake or instead create a public static reference inside the Movement script to use in other scripts, like so; Movement.reference.variable

    Also, can you point me in the right direction on how I might be able test the execution speed of each of these to see the difference (as well as generally testing individual functions for speed) using Profiler, for instance?

    Excellent tutorials, some of the best I’ve seen – Keep up the good work!

    Thanks,
    Chris

    • fafase
      July 10, 2013 - 10:01 pm Reply

      Hi Chris,

      Because of your question, I made an article http://unitygems.com/quick-benchmark/. It does not compare static and GetComponent but just the various way of accessing a component.

      But I just run the test of static vs GetComponent and they appear to give the same performance. That is if you do not respect the principle of encapsulation, meaning your variable is exposed and accessible.

      If you go with pure OOP and encapsulation then you go via a method and it looks almost double time.

      Do your own test and see :)

      Fafase

  • Chris
    July 11, 2013 - 12:23 pm Reply

    HI Fafase,

    I was surprised when I saw it appear in my inbox this morning :) Thanks for taking the time to write it.

    The article is very informative, I can see how using those methods will be useful come the optimisation stage, or even just to test some new way of doing something. So my tests show that caching is about 1.6 times quicker than not caching, and although is only a few milliseconds when you think about the number of references used in a game, that really does add up.

    Yes, completely agree with you there, encapsulation is obviously very important. I usually steer clear of statics unless totally necessary (usually only in storing persistent game data / game saves, usually).

    While we’re on the subject, I wonder if you might be able to demonstrate how to display/serialize? the contents of a static variable/List in the Inspector. I have read that this can be achieved using a Singleton class but I don’t have too much experience with this.

    Thanks again,
    Chris

    • fafase
      July 11, 2013 - 1:23 pm Reply

      To expose static members I recommend this link: http://wiki.unity3d.com/index.php?title=Expose_properties_in_inspector

      That allows you to expose properties.
      Then you can “link” a property with a static value like this:

      public class Test : MonoBehaviour {
      public static int myStatic = 10;
      [ExposeProperty]
      public int MyProp
      {
      get
      {
      return myStatic;
      }
      set
      {
      myStatic = value;
      }
      }
      void Update(){
      if(Input.GetKeyDown(KeyCode.Space)){
      print(myStatic);
      }
      }
      }

      Then when you modify your static var you can see it in the inspector assign a value in the Inspector and voila.

      There are other ways to do this but I find this one easy and working.

      Fafase

  • Nick Hester
    August 9, 2013 - 3:49 pm Reply

    At first, I was stuck, but then I realized that there was a step missing from your description that was stopping me. Maybe this is obvious to experienced users, but it would be nice if you added this step to your article here:

    In the “Accessing another script inside the object” section, after the code is modified, you said “With the modifications, run the game, press P, your StormTrooper now has 10 of health.” This is not correct.

    According to the code, firstly, it’s the Spacebar that will set your health to 10.

    And second, before this will work, if you look at your StormTrooper, the script field that was created with the code “public Force script;” must be set in the Inspector. By default, it will say “None (Force)”. You must set this to the StormTrooper by selecting the little circle icon to the right of this field.

    Then it will work correctly.

    I know, it’s possible that this changed in the new Unity version. I just hope it can be corrected so that other beginner users can follow this tutorial without problems.

    Thanks for the great tutorials!

    -Nick

    • fafase
      August 9, 2013 - 6:37 pm Reply

      Hi Nick,

      To your two mentioned problem I say yes and no.

      Yes, the press space was missing and I added it, thanks for that.

      No, your public Force script will not show none, since there is GetComponent in the Start that will find the script and assign it.
      You probably missed the start part.

      • Nick Hester
        August 10, 2013 - 6:53 pm Reply

        You’re right, I just started over and tried again. Not sure what the problem was. Thanks for the great tutorials!

Leave a Reply