noobtuts

Unity GameObjects and Components

Foreword

Unity is a component based game engine. This article will explain what that is and how to work with it effectively.

GameObjects

In Unity a GameObject is pretty much just an empty object. It's the base for everything else. It's just a raw object that has space for components. A GameObject itself does nothing unless we add components to it.

Components

We want to create a monster in our game. In Unity the way to do this would be the following:

So basically every time we want to add something to our Unity world, we create a GameObject and then add components to that GameObject. In Unity, components can be Scripts, Sounds, Meshes(3D models), RigidBodies, Colliders and more.

In the example above, Health, Skills, Movement, AI and GUI are probably Scripts. This raises the question: why don't we just create a Monster script and put it all into that, instead of breaking everything down into components?

Well, it can be done that way. If you like it, just do it. But imagine the following: we want to create another thing in our game world, this time it's the player. We would do the following:

Now here comes the beauty of the component based system: we can reuse components that we used for the monster! So all we have to do to create a Player is use most of the components that we used for the monster before (like Health), add them to the Player, add a few new components (like Sword and Shield) and then we are done already. This saves us a whole lot of work in compare to creating a single Player script where we would have to program everything again.

That's it, simple as that. It's just a clever way to save us from doing too much work.

Component based development: Tips and Tricks

Accessing Components on the same GameObject

So our Player has two Scripts (also known as components):

A health component with the current and the maximum health could look like this:

using UnityEngine;
using System.Collections;

public class Health : MonoBehaviour {
    public int current = 50;
    public int maximum = 100;
}

A movement component that moves to where the player clicked could look like this:

using UnityEngine;
using System.Collections;

public class Movement : MonoBehaviour {
    void Update() {
        if (clickedSomewhere()) {
            moveToDestination();
        }
    }
}

Then we would drag both scripts onto the Player's GameObject so it looks like this:
Player GameObject

Now apparently dead people can't move, so how do we stop the Movement component from doing its work while the Player is dead? We need a way for the Components to communicate with each other. Obviously they are on the same GameObject (the Player), so there has to be some way.

Good news: there is a very easy way called GetComponent. Here is how we can access the Health Component from within any other Component on the same GameObject:

GetComponent<Health>()

Note: this means 'Get Component of type Health'.

Now that we know that, we can easily modify our Movement Script so it only moves while the player is not dead:

using UnityEngine;
using System.Collections;

public class Movement : MonoBehaviour {
    void Update() {
        if (GetComponent<Health>().current > 0) {
            if (clickedSomewhere()) {
                moveToDestination();
            }
        }
    }
}

That's it. All we have to remember is that Components on the same GameObject can access each other via the GetComponent function.

Accessing Components on another GameObject

Okay so the question is, how can Components communicate with Components on other GameObjects. For example how could we access a Monster's Health from within a Player's script?

Our GetComponent function from above only works for Components that are on the same GameObject, so we need to figure out something else.

Don't worry, it's very easy too. Assuming we have a Monster GameObject that has the Health script from above attached to it:
Monster GameObject

And we have a Test script:

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour {
    void Update() {
        // ToDo: is monster alive?
        // then do something
    }
}

which will be attached to the Player's GameObject:
Player GameObject

So the question is, how do we access the Monster's Health from within the Player's Test script?

It's very easy too. We just have to use a public variable of type Health that can be filled out by any kind of Health component (in our example it will be the Monster's Health component). This is our modified Test.cs script:

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour {
    public Health monsterHealth = null;

    void Update() {
        if (monsterHealth.current > 0) {
            // do something
        }
    }
}

If we look at that for a second, we soon realize that it makes no sense at all. The monsterHealth component is **null*, so accessing it is a bad idea.

But wait... since it's public, we can see a field for it in the Unity Inspector now:
Player monsterHealth

Which means that we can drag something into it so it won't be null anymore. So let's do just that by dragging the Monster GameObject from the Hierarchy into our Test script's Monster Health slot:
Monster Drag&Drop

Now the slot looks like this:
Monster Health Filled

Which means that our public Health monsterHealth variable, points to the Monster's Health now. Hence we our Test script works.

That's how we access Components on other GameObjects!