In this post, I’ll go over the most commonly used scripting concepts in Unity, and give a brief introduction what they are and how they work in relation with the engine.
What is a MonoBehaviour
If you’ve gone through my previous posts, you will come accross a basic introduction to scripting in Unity. If you haven’t gotten familiar with the Unity interface, the gameObjects and its components, I advise you to start with those posts.
In my basic introduction, I have not fully explained how the scripting works, just what it is and what it’s for. This post will dive deeper into what the code means. Now if you don’t have any experience coding yet, don’t worry, there’s a basic introduction into coding in C# as well [here].
Now what is this MonoBehaviour?
Shortly put, a MonoBehaviour is a script that is attached to an object in the scene, and invoked by Unity. It provides the developer with a way to attach behavior to a gameObject.
For example, if you’ve followed the previous example in the introduction post, we’ve attached a script called a CubeController to the default cube.
If you look closely at the code for that CubeController, you’ll notice this line:
public class CubeController : MonoBehaviour
This means that the CubeController is a class, that “inherits” its behavior and properties, from the class MonoBehaviour. If you want to know more about inheritance, and the basics of programming in C# and Object Oriented Programming, read this post.
You’ll come across some of the concepts of the previous posts as well when looking at the properties of this MonoBehaviour, such as the gameObject and the Transform.
What is the Update loop
When you look at the script you started with, a few methods are already present, and one of those methods is:
void Update()
Don’t worry about the “void”, it just means that this method does not return anything to the calling method. The Update method is called on each frame. This means that if your game is running at 60 frames per second, the code in that block will be executed 60 times per second. This seems like a lot, but luckily, computers are really powerful these days. So unless you have 1000’s of these, it will not impact the performance all that much.
Let’s test it out. Between the 2 brackets { and } that make up the update method block, let’s add a line like this:
Debug.Log(“This is invoked from the Update method”);
Now go back to Unity and hit the play button. Remember the console window I talked about in this first post? You’ll notice that on each frame, it’s printing that message there.
What is the Start method
Now stop the game and go back, and add a similar line to the Start method like this:
Debug.Log(“This is invoked from the Start method”);
Now if you hit the play button, you will see that this is only printed once, just before the updates.
The reason for this is quite simple: The start method is run before the first frame update.
There are a few methods like this that behave in a similar way, namely:
- Awake()
- OnEnable()
- Start()
I’ve mentioned that Start is run before the first Update. In a similar way, OnEnable is run just after an object is enabled, for example when an object is created (when a level is loaded or a gameObject with a script is instantiated). Awake is called in first, so before the OnEnable is called.
It’s important to remember this order in case you are writing more complicated scripts, that might reference other scripts or are using properties that are initialized in any of the other methods.
Manipulating an object through code
Well now, this is all interesting, but it’s not quite that spectacular to see messages appear in the debug window. So let’s look at what else we can do. For now, we’ll keep it simple and move the cube around a bit.
Remember earlier in the post, I mentioned that you have direct access to some of the components in the MonoBehaviour? Let’s take some components, and put those in a Field.
Above the Start method, let’s define some fields like this:
public Vector3 Direction;
public float Force;
If you now go back to Unity, on the Cube where this script is attached, you’ll see that the script now has 2 new properties, corresponding to these fields. Fill in whatever value you like, we will use those later.
Let’s go back to the script and type some more code.
We want the object to move whenever we hit a key, so let’s add something to the Update method to listen to our input.
In the Update method, add this code:
if(Input.GetKey(KeyCode.Space)){
transform.Translate(Direction);
}
It’s always interesting to look at the official Unity documentation for this. Although it’s not too difficult to interpret this code, I’ll leave the links to the documentation here:
https://docs.unity3d.com/ScriptReference/Input.GetKey.html
https://docs.unity3d.com/ScriptReference/Transform.Translate.html
Now go back to Unity, and hit the play button. If everything went right, you should see the object moving when you hold down the space-bar. If it’s not moving, make sure you assigned a value to the Direction property of the script in the inspector, you can play around with that while the game is running. Also make sure that the debug window is not warning you of any errors that indicate the code is wrong. If that’s the case, you might want to check the code for syntax errors, such as missing brackets.
Let’s make it a bit more interesting and add a force to our Rigidbody.
Add another field for the rigidbody, below the Direction and Force like this:
public Rididbody Body;
I’ll leave the link to it’s documentation as well so you can check it out:
https://docs.unity3d.com/ScriptReference/Rigidbody.html
Now in the Update method, change “GetKey” to “GetKeyDown”, so it looks like this:
if(Input.GetKeyDown(KeyCode.Space)){
transform.Translate(Direction);
}
The GetKeyDown method will only be triggered once when you push down the space bar, this will make the Cube move only once.
Now in the Update method, let’s change the transform.Translate to something else. Let’s add a force to the Rigidbody.
Body.AddForce(Direction * Force);
This will add a force in the direction you specified, but multiplied by the force.
Now when going back to the Unity editor, beware that this will result in an error, and I’m doing this on purpose now, because I see this often in questions by beginners.
Try and run it, and you’ll notice in the debug window that a “NullReference Exception
” is being logged whenever you hit the space bar.
This exception indicates that there is no reference to the Body property, and thus it cannot execute the AddForce method.
There are 2 ways to fix this:
- Either assign the Cube to the Body property of the script in the inspector, by dragging and dropping it from the hierarchy to the script, OR:
- in the Start method, add this line of code to assign a reference to the component:
Body = GetComponent<Rigidbody>();
This line of code will execute before the first update, and will look through the gameobjects components, so find a Rigidbody component. If there is no Rigidbody component, it will result in the same error you saw earlier.
If you did not yet know about this, I would advise you to have a look at the OOP basics, or Object Oriented Programming basics in my other post [link].
Showing properties in the inspector
One thing that I have not yet talked about here, is the “public
” modifier that I put in front of each of the fields in the script. This public modifier makes those fields visible for every script that has a reference to the CubeController, and it will show those fields in the inspector as well.
Now as you progress, you’ll have scripts with lots of fields, and it will become cluttered and difficult to read. So I advise you to only use public for fields that you want to reference from another script.
Mark each field as “private
” instead, and if you want to show it in the inspector, use the
[SerializeField]
attribute so Unity knows it should show it. Like this:
[SerializeField]
private Rigidbody Body;
Troubleshooting for beginners with the console window
If you’ve followed along perfectly, you will have used the console window a few times already.
This is good, it will help you understand what’s going on in the code. You’ve seen the Debug.Log statements that we’ve added, and you’ve seen the exception that was thrown.
This is a very powerful tool, and it should be used when you are developing and learning. For example, try adding a null check in the start method for the Body, and use the Debug.LogWarning("")
method to inform you if it has not been assigned.
This can be done in a few ways, for example
if(Body is null)
or
if(Body == null)
I’ll leave the rest up to you, have a look at the documentation for the Transform, the Input and the Rigidbody, and see if you can write your own script to move the cube based on the input.
I’ll always recommend to read through the documentation, you’ll find plenty of inspiration there to try out for yourself:
https://docs.unity3d.com/ScriptReference/index.html