It’s Friday, and you know what that means, it’s time for another edition of Feature Fridays! I’m excited to break down another feature of the Unity Game Engine for you this week.
This week we are going to be talking about another core part of Unity, one that you will use just about every time you use Unity, and that is: components.
Components are the building blocks of GameObjects and are what give them their behaviors and properties. So today we will discuss:
- The Basics You Must Know about Components
- Creating and Customizing Your Own Components
- Components Interacting with Each Other
And make sure that you do read all the way to the end to see this awesome next gen Xbox game that was made with Unity, by a solo developer.
1. The Basics You Must Know about Components
In Unity, individual objects are referred to as GameObjects. By default every GameObject has one component associated with it that you cannot remove – this is called the Transform component. Even when creating an empty GameObject by right clicking in the scene hierarchy and selecting “Create Empty,” a Transform component is applied.
The Transform component tracks the 3D position, orientation (rotation), and scale in the game world. If something exists in our game, it needs to physically exist somewhere even if we can’t see it.
Also when we set one GameObject as a “Child” of another GameObject, this is tracked in the Transform component. The reason being is that the Transform component tracks the GameObject’s position relative to its parent. If a GameObject has no parent, the Transform values are relative to the game world space.
When you move a parent GameObject, the child moves along with it, as the child’s relative values do not change. The same is true for rotation.
The one you need to watch out for is the Scale property. Scaling a GameObject will expand or contract the size of that object along a specified axis. I say you should watch out for this because it is a best practice to keep the scale of all GameObjects at the default of (1, 1, 1).
This is mainly a performance optimization as the physics system takes the scale factor into account, and it is significantly more costly with a non-default scale. Ideally you would want to create your 3D models in the proper size for your game. If that’s not possible, you can set the “Mesh Scale Factor” in the Import Settings of the 3D model.
But most of the time our GameObjects are much more than just a Transform component. Luckily adding new components is as simple as clicking the “Add Component” button in the inspector window with the GameObject selected.
Click here to learn more about the Inspector window
We can add all sorts of components to customize the GameObjects in our game. If we want to see it, we can add one of many various render components. If we want it to collide with other GameObjects, we can add a Collider component. There are way too many built in components to go over today, but I encourage you to start to play around with them and figure out what they do.
Once the Component is added to a GameObject, you can configure various properties in the Inspector window. Most of these options are pretty clear at what they do and how you can change them at first glance; but for more of the complex ones, the developers add in “Tooltips” that can be seen by hovering the property in question. These Tooltips provide helpful guidance of what impact modifying that property has.
One final thing to note for the basics of Components is the Context Menu. The Context Menu is a menu that can be accessed on every component by selecting the icon of the three vertical dots.
From here, you can select “Reset” to reset the component to the default values – useful for moving a GameObject back to the origin position in the world.
Move Up/Down will move the position of the Component in the Inspector.
The rest of these options are fairly self explanatory and will just make sense if you use them.
I do want to point this out, because there is a way that we can add custom things to the Context Menu when we create our own custom Components.
2. Creating and Customizing Your Own Components
Creating custom Components is easier than it sounds. To create a custom Component all you need to do is create a new C# script either in the scene hierarchy or in the Add Component menu.
Doing that will create a new C# script that inherits from the MonoBehaviour class. This means that this script can now be assigned to any GameObject in our project.
Click here to learn more about the MonoBehaviour class
If we want to add editable properties to our custom component, the easiest way to do this would be to add a public variable to our script. Public variables of most common C# and Unity types are available to be assigned in the Inspector window.
To add some functionality to our components, we can simply add a few methods to take in input, perform some actions, and return output. (We’ll dive deeper into scripting in future editions of Feature Fridays)
The way that components appear in the editor can be customized using custom inspectors, which is another concept we will delve into later. However attributes can be used as an easy way to customize the look of the component in the editor.
For example, if you have a value that you would like to stay between 40 and 65, then you can add a [Range]
attribute to your code above the variable declaration. The result is that this value will be editable in the inspector with a slider with a min value of 40 and a max value of 65.
[Range (40, 65)]
public float _distanceOffset;
Click here to learn more about C# attributes
Another attribute that I use quite heavily is the [RequireComponent]
attribute, which applies to the class itself. Passing in the type of another component means that the required component must also be on the GameObject that this component is on.
For example, let’s say we have a custom enemy controller class that needs to access the Rigidbody component attached to the GameObject. To guarantee the existence of a Rigidbody on the GameObject we would do this:
[RequireComponent(typeof Rigidbody)]
public class EnemyController
{
// Character controller code using Rigidbody
}
If we were to add this enemy controller component to a GameObject that did not already have a Rigidbody component, then one would be added at that time. Later, if we were ever to try to remove the Rigidbody component, we would see a warning message and not be allowed to remove the component.
And those are the basics you need to know about creating and customizing components. Now let’s dive a bit deeper and talk about how to access different components from your custom components.
3. Components Interacting with Each Other
There are a number of ways to reference other components in your code. The easiest and preferred method of referencing another class if to have a public field (or better yet, a private field with a [SerializedField]
attribute).
[SerializedField]
private BoxCollider _collider;
The above code will display an empty field in the inspector – we can populate this field by dragging in a GameObject that has the component type attached to it or by using the selection icon to select a GameObject from the scene or project hierarchy.
The other commonly used method of accessing components is by using the GetComponent<T>()
method from the MonoBehaviour class. The T inside of the angle brackets is a generic type, so when we want to get a component of a specific type, we replace the T with the type of the component that we want. For example:
BoxCollider curCollider = curEnemy.GetComponent<BoxCollider>();
It is preferred to have a serialized reference as shown above as the GetComponent<T>()
method can be quite costly. But sometimes serialized fields are not always an option – if you do have to use GetComponent<T>()
, then it’s best to cache the value in the Start or Awake function so you don’t need to make frequent calls to GetComponent<T>()
. If you do need to dynamically get components at runtime, it’s best to keep the GetComponent<T>()
calls to a minimum.
Once you do have a reference to the component you need, you can access its public properties and methods as you’d expect with any regular C# class.
var colliderCenter = curCollider.center;
rigidbody.AddForce(Vector3.Up * 5f)
And that is how you can access other components from your custom component in Unity.
Featured Unity Game of the Week: The Falconeer
The featured game made with Unity this week comes from solo developer Tomas Sala. The game he created, The Falconeer, is not your typical air combat game. Instead of piloting an attack plane, you pilot a war bird with a massive weapon strapped to its back.
This game has fast and fluid gameplay. Not only is it a visually impressive game, but it is a technically impressive one. This game runs at a smooth 120 frames per second, even in the most incense parts of combat, on the next generation Xbox consoles.
Check out some of this epic gameplay here:
And those are that basics of working with components in Unity. Again, components are such a key part of the Unity game engine as they are the literal building block for everything in our game projects. Please do let me know if you have any questions or if there are any other topics you’d like to learn about.
Anyways I hope you are all staying well, and as always, keep on creating!
-Johnny Thompson
Turbo Makes Games
Recent Comments