Go to Top

Learn how to get components on other objects and interact with them using Boo

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

You can find the exact same tutorial using UnityScript here or using C# 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:

-GetComponent, the most common, also the one that confuses most at first

-SendMessage, it might look easier to grasp but it is also less efficient.

-static variable, the easiest to use but also the most complicated to fully understand at first.

In this tutorial we will cover the GetComponent section using Boo.

The code samples on this page are indented with spaces. In Boo, every indent level should be a tab OR the same number of spaces. If you get "unexpected token" warnings or "expecting 'DEDENT'" warnings or similar, then you have a mix of spaces and tabs somewhere at the beginnings of your lines.

Create a new scene and add an empty game objects and name it “ObjectA”. Create two scripts named “ScriptA” and “ScriptB”. Add both scripts to ObjectA.

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

ScriptA.boo

import UnityEngine
import System.Collections
class ScriptA (MonoBehaviour): 
   public varBinA as int
   public otherBinA as int

   def Update ():
      if Input.GetKeyDown (KeyCode.Space):
         varBinA = ScriptB.GetVarB()
         otherBinA = ScriptB.varB
         if varBinA > 0:
            ScriptB.AddVarB(10)

ScriptB.boo

import UnityEngine
class ScriptB (MonoBehaviour):
   public varB as int
   def Start ():
      varB = 20

   def Update ():
      if Input.GetKeyDown(KeyCode.P):
         Debug.Log ("varB in ScriptB $varB")

   def GetVarB () as int:
      return varB

   def AddVarB (num as int):
      varB += num

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

We need to tell ScriptA where is ScriptB 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 ScriptA with:

import UnityEngine
class ScriptA (MonoBehaviour):
   public scriptB as ScriptB 
   public varBinA as int
   public otherBinA as int

   def Start ():
      scriptB = GetComponent[of ScriptB]()

   def Update ():
      if Input.GetKeyDown (KeyCode.Space):
         varBinA = scriptB.GetVarB()
         otherBinA = scriptB.varB
         if varBinA > 0:
            scriptB.AddVarB(10)

With the modifications, run the game, press P, it should show 20 in the console, press Space and then P again, the value is now 30. It was also possible to access varB and assign it directly to varBInA since varB is public.Note that accessing methods  is done the same as for variables.

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.

ScriptB script;

The GetComponent function will look inside the object 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 ScriptB is found then the address of that component is passed to the variable script, the variable now points to the ScriptB component stored somewhere in memory. In order to access the public members of ScriptB, 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:

def Update():
   transform.position.x += 10

But what Unity does behind is actually:

def Update():
   GetComponent[of Transform]().position.x += 10

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

trans as Transform

def Start():
   trans = GetComponent[of Transform]()

def Update():
   trans.position.x +=10

This will save some computation.

Getting many components

What if our ObjectA has many ScriptB within itself. Duplicate the ScriptB twice so ObjectA has three of them.

ScriptA becomes:

import UnityEngine
class ScriptA (MonoBehaviour):
   public scriptB as (ScriptB)

   def Start ():
      scriptB = GetComponents[of ScriptB]()

   def Update ():
      if Input.GetKeyDown (KeyCode.Space):
         for i in range(scriptB.Length):
            scriptB[i].AddVarB(i)

Run the game, press P, the console prints out three 20. Press Space and P again, the console should look like this:

Console

Because I used the value of i in the loop as parameter of the function, each script has received a different value. Note that since the loop starts from 0, one script does not change.

Interaction between objects.

We can also get two objects to interact in a similar way. Create a new object named “ObjectB”. Remove the ScriptB component from ObjectA and add it to ObjectB.

Run the game, you can print but pressing Space will throw a Null reference exception. This is due to the fact that the ScriptB is no more on ObjectA so GetComponent simply does not find it. We need to find the ObjectB first using GameObject.Find(“ObjectB”).

You only need to add the line below in the ScriptA:

def Start ():
   scriptB =GameObject.Find ("ObjectB").GetComponent[of ScriptB]()

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 you will surely see a bad effect. Consider calling these in the Start function.

Interaction between objects within the hierarchy

Drag ObjectB into ObjectA.

Run the game and you will notice it works fine. Still, we can make it happen better by using commands that tell the compiler that ObjectB is a child of ObjectA. Hence, no need search all the objects of the scene.

def Start ():
    scriptB =transform.Find ("ObjectB").GetComponent[of ScriptB]()

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:

def Start ():
   scriptB =GetComponentInChildren[of ScriptB]()

Note that it also works if you have children of children holding the script. Create an “ObjectC”, add ScriptB to it and add the object to ObjectB. Now A has B which has C.

Change ScriptB for:

def Update():
   if Input.GetKeyDown (KeyCode.P):
      Debug.Log ("$gameObject.name $varB")

Run the game, you will see that both scripts are found and altered.

GetComponentsInChildren will work the same if all children have many instances of one script.

Interaction in action

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

, , ,

Leave a Reply

%d bloggers like this: