Scratch makes it very simple to “do” things with your sprites by stacking a few well placed code blocks. In Unity, you must “script” your actions with a programming language called C# (pronounced ‘C Sharp’). If you’ve never programmed before, then this will likely be the single greatest hurdle in transitioning from Scratch to Unity, but it is well worth the effort. Once you master the basics you’ll be able to express yourself far better than you had been able to before.
Getting Started
Scratch offers multiple categories of code blocks that you can easily drag and drop onto the code editor of a sprite. By connecting the blocks like Lego Bricks, you can create some fairly complex behaviors.
Code is really just text. In fact, some of the things you may write could look a lot like the labels of the code blocks you had been using in Scratch. You can write code even in a simple text editor, though many nice programs exist to help simplify some of the challenges you’ll face as a programmer. There is no “coding” window inside Unity, instead you probably installed a Code Editor along with Unity called Visual Studio, which you will see in a bit.
First, we need to create something called a “script”. It is just a file of code that will live in our project, and it is similar to the workspace of blocks you add to your sprite in Scratch. Create the script by clicking “Create” -> “C# Script” from the “Project” pane’s menu bar.
The script you create will be highlighted in the Project pane, and its name will already be highlighted and editable. Name your script, “Mover”, then apply it by hitting the “return” key on your keyboard. At the moment, our script is merely a project asset, and it doesn’t apply to any of the GameObject’s in our scene. In order to “connect” it to something you have a variety of options to pick from:
- Drag and Drop the script from the project pane, to an object listed in the hierarchy pane.
- Drag and Drop the script from the project pane, to an object you see in the Scene view.
- Drag and Drop the script from the project pane, to the inspector of the currently selected object.
- Scroll to the bottom of the Inspector pane and click the “Add Component” button. Start typing the name of the script and when you see it appear, select it in the list.
By whichever of those methods you prefer, go ahead and add the “Mover” script component to the “Cube” in your scene. You should see it appear as a component at the bottom of our Inspector. With this connection, any code that we write in the “Mover” script will have a GameObject to apply to.
TIP – If you see a “Can’t add script” alert, it is probably because you allowed the script to apply “NewBehaviourScript” as the name of the script and then re-named the file to “Mover”. Unity has a special rule that the name of the class it generates (the text inside the code file) must match the name of the file, or things wont work properly. For now, you can delete the file and try again, or edit the file and replace the text which says “NewBehaviourScript” with the name of your file, “Mover”.
Finally double click the “Mover” file in the project pane, and your script should be opened by your default code editor automatically.
Template Overview
Below, you can see our script has been opened by my default code editor, Visual Studio. The script that we created has some template code already. Take a look:
In English, we often reuse words, and you will only understand the intent of the word by the context in which the word is used. For example, the word “alpha” might be the first letter of the Greek alphabet, it could be a dominant animal or human, it could be a symbal used in math, or it might represent a pre-release version of your next game. In the same way, programmers often reuse words, sometimes even for the same purpose, but the implementation might be different. In order for the computer to know what context it should understand words with, we use something called a “using directive”. Lines 1, 2, and 3 are each a separate using directive, and they each help to define the context and vocabulary with which we will “speak” to the computer in the current script. As a beginner you wont need to use these very often, though occasionally you might need to add another reference for one.
Line 4 is blank. We call this “white space” and it is there only to help with readability. You can add or remove such spaces to your liking and it wont make any difference to the computer.
Lines 5 to 18 make up our “class”. You can think of a class as your attempt to teach the computer to understand a single job. In the case of our “Mover” script, it could be something as simple as “In this class we will teach the computer to move a GameObject.” If you look at the scratch screen shot above, my “Mover” class might hold the whole stack of code blocks from the image. If I had a separate stack of blocks on the same page, it would probably be put in a separate class.
On several of the lines you will see open `{` and close `}` brackets. These mark the “body” of code that belongs to something. They are paired as follows:
- Line 6 and 18 – mark the body of the “Mover” class. Note that this body contains other bodies because they appear between the open and close bracket.
- Line 9 and 11 – mark the body of the “Start” method.
- Line 15 and 17 – mark the body of the “Update” method.
You should be able to see a pattern – every close bracket closes the most recently opened bracket which hasn’t already been closed. To make this more obvious, many programmers use white space such as indentation, new lines, and vertical alignment of the brackets that are paired together.
On lines 7 and 13, you see something called a code comment. Like white space, comments are only there to help the programmer. The computer will completely ignore everything beginning with a double forward slash `//` until the next line begins. I highly recommend you comment your code, because even an experienced programmer may forget what portions of his code do, or why it was done a certain way.
Line 8 holds the definition of the “Start” method. We will add code to the body of this method that should be triggered by a press of the play button in Unity. It is similar to code that is attached to the “when green flag clicked” event block in Scratch
Line 14 holds the definition of the “Update” method. We will add code to the body of this method that we want to run in a loop. In Scratch, this would be similar to code blocks that you embed inside of a “forever” block in the Control category.
Learning to Code
A lot of people say that learning to code is similar to learning a new language, but I think it is easier than that. For starters, most of the words are familiar – you program in English! Perhaps it would be more correct to say that you are really just learning some new grammar and syntax rules that are required in order for your computer to properly understand what you want from it.
In elementary English classes you probably learned rules such as to capitalize the first letter of proper nouns, and that a complete sentence typically contains a subject and a predicate. There will be similar rules in programming that you MUST get right. Some of the rules are only conventions, but some are required, and if you get them wrong, everything will break until you fix it again.
Let’s start with an example. When you created your script, I told you to name it “Mover” with a capital “M”. This capitalization is only a convention in C# – we prefer to think of a class name like a proper noun, and so will capitalize its first letter. However, any further reference to this class in our code MUST continue to use the same letter cases or the computer wont know what we are talking about. “Mover” is not the same as “mover” or “MoveR” to the computer. There are plenty more rules you’ll need to learn, but you don’t have to learn everything all at once. For now, let’s learn about some words that your computer will understand, and see how to tie those words together so we can tell it what to do.
Data Types
To get started, let’s cover how you describe types of “information” to the computer. For this we use something called a data type. In C# many basic data types have been defined and include:
- `int` – this represents whole numbers, such as you would use for counting.
- `float` – this represents real numbers, such as you would use for measuring.
- `bool` – this represents either “true” or “false”
- `string` – this represents textual information, like the characters used to spell your name.
- `void` – this special data type represents the absence of information.
Some complex data types are formed as a group of these simple data types. For example, Unity has defined a structure called a “Vector3” which is really just a group of three named floats: x, y, and z. We can use a Vector3 for a variety of purposes, such as to define the position of an object in 3D space. A class is also a type of data. In fact, the “Mover” class we just created is a new data type “word” we just taught to the computer!
Variables
Now that we know how to “represent” information, we can easily teach the computer many additional words. For example, since we are creating a script to move a game object, we might want to teach the computer the word “speed” so it knows how fast to move things. Because you can “measure” speed, we would define it using a “float” data type. In code it would look like this (but dont add it yet):
[csharp]
float speed;
[/csharp]
This line of code is called a “statement”. This is probably the simplest statement we could have made, but it is powerful. What we have done is called declaring a variable. We taught the computer that “speed” is the name of a variable that can hold information in the form of measurable values. In this case, we didn’t specify what information the variable holds, so the computer will use a default value of `0` until we say otherwise.
If we declare a variable in the body of a class, then it is a special type of variable called a field. A field can be used anywhere inside the body of the class, including inside of any methods that the class contains. If we declare a variable inside of a method, then it is said to have “local scope” and can only be used inside that method.
When declaring a field (a variable in the body of a class), you may also specify something called an access modifier. If no access modifier is specified, the computer will assume you intend to keep the variable “private” which means it can only be used within that script. Use the keyword “public” to allow your fields to be used even outside of your script. As a bonus, the value of a public field can be displayed, and even edited, by the Unity Inspector.
Let’s try that now. Add the following field to the top of the body of our “Mover” class (add it to a new line just after line 6):
[csharp]
public float speed;
[/csharp]
Save your script, then head back to Unity. Make sure your cube is selected, then look in the inspector at your “Mover” script. You should see something like the following:
Feel free to type in the Insepctor’s text field for your speed variable. You can set it to any valid value (digits and an optional decimal point). The value that you specify will be saved with your scene. Give it a try! Set any new number (so that you can tell it isn’t using the default value), then save your scene. Close and re-open unity and the value you set should load back in successfully. For the purposes of the demo later, I would recommend something small, such as ‘3’.
You can even edit the value while Unity is playing. Try that now. Press play, then change the value of your “speed” variable to something else. Note that when you stop the game, the value will revert to the way it was before you pressed play. This way, every time you run your scene you will get the same experience.
Statements
If data types are “words” taught to a computer, a “statement” is a sentence spoken to a computer by using those words. You already used a statement by declaring a variable when you put two words together (a data type and a name for a variable). Another example of a statement could be to assign a new value to your variable. Most of the statements you write will occur inside the body of a method, like the “Start” or “Update” method that were provided for us in the template code.
Here is an example of an assignment statement (but dont add it):
[csharp]
speed = 3;
[/csharp]
In the statement above, we use an assignment operator (“=”) to assign the value of `3` to the `speed` variable. The variable that you want to write to always goes on the left hand side of the operator, and the value to assign goes on the right side of the operator. The value we assign doesn’t have to be a simple constant like this. It could be anything that evaluates to a value, such as the result of another operation, or the result of calling a method with a returned data type. Here are examples (but don’t add them anywhere):
[csharp]
speed = 1 + 2; // assigning the result of an addition operator
speed = Random.Range(1f, 3f); // call a method, and then assign the returned value it provides
[/csharp]
You “could” add one of the above statements to the body of the “Start” method. Consider it an optional step. If you specify the value in code, then it will overwrite any value for “speed” that you set in the Unity inspector. If you prefer to control the object’s speed by the inspector, then do not add either of these statements.
Let’s try writing a couple of statements now. Add the following statements inside the body of the “Update” method:
[csharp]
var offset = new Vector3(0, 0, speed * Time.deltaTime);
transform.Translate(offset);
[/csharp]
In the first statement, I declare a new variable named “offset”. Notice that instead of explicitly stating the data type of the variable, I used “var” which means that its data type is implicitly set. This is possible because I also assign a value to the variable all in the same statement. Therefore, the data type will be determined based on the value I assign. In this case it will be a type of the “Vector3” struct. Remember that because we declare the variable inside the method that it is locally scoped and cant be used outside the method.
Unity creates the illusion of movement by showing a lot of images with small changes between them. There could be 30, 60, or more images presented every single second. The “Update” method is called once for each of these images (also called frames) and is how we control the change that appears between each image. When we created our “offset” variable, we set the “z” axis value to be “speed * Time.deltaTime”. The “deltaTime” property holds the fraction of a second which has passed since the last frame was displayed. The end result is that our speed is treated as unit’s per second. In other words, if your speed is ‘3’, then for each second the game plays, your object’s `z` position will be ‘3’ more than it had been.
The next statement refers to a “transform” property. A transform is the component of a GameObject that controls its position, rotation and scale. “Translate” is a method defined inside of the “Transform” class, and we access it by a member access operator (it looks like a period). The Translate method moves our object by whatever amount we specify.
Methods
If a statement is like a sentence, a method is like a paragraph. In other words a method is a collection of statements. Sometimes you group them for readability, but usually it is because of reusability. For example, “make a peanut butter and jelly sandwich” could be implemented as a method, where each step of the process, like taking slices of bread, and applying the peanut butter and jelly to the bread, would each be statements inside it.
Methods can also call other methods, because calling a method is actually just a statement. For example, you might want a “make lunch” method, and one of the lunch options could end up calling the “make a peanut butter and jelly sandwich” method.
We have already seen multiple method definitions in our template such as “Start” and “Update”. These are special methods Unity provided for us because our class “inherited” that knowledge from its parent class, “MonoBehaviour”. Just like Unity will automatically call the “Start” and “Update” methods at the correct time, there are many additional methods you could use in your class that would also automatically be called if you added them. You can get an overview of what all is available to you by reading the documentation here. Let’s add another one of these methods inside of our “Mover” class, just after the body of the “Update” method:
[csharp]
void OnCollisionEnter(Collision collision)
{
transform.forward = Vector3.Reflect(transform.forward, collision.contacts[0].normal);
}
[/csharp]
This method is called by Unity’s physics engine whenever a “Rigidbody” component first detects a “Collision” with another “Collider” component. This method accepts an input parameter, which is a data type called “Collision” and which is named “collision” (notice one is uppercase and one is not).
Inside the body of the method we have added a statement that is similar to the “if on edge, bounce” code block in Scratch. On the right side of the assignment operator, we are calling a method on the “Vector3” struct called “Reflect”. We pass two input parameters: the forward facing direction of the object (obtained by transform.forward) and the angle of the surface that we collided with (obtained by collision.contacts[0].normal). Using those inputs, the method is able to bounce our vector, and we assign the result of the method back to the `transform.forward` property which causes our GameObject to face a new direction.
Demo
At this point our script is complete. The full script should look something like this:
[csharp]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Mover : MonoBehaviour
{
public float speed;
void Start()
{
// Optional:
// remove next line if you want to control speed via the inspector
speed = Random.Range(1f, 3f);
}
void Update()
{
var offset = new Vector3(0, 0, speed * Time.deltaTime);
transform.Translate(offset);
}
void OnCollisionEnter(Collision collision)
{
transform.forward = Vector3.Reflect(transform.forward, collision.contacts[0].normal);
}
}
[/csharp]
Assuming you have the scene ready, with a Cube created and the “Mover” script attached, you could already press play and see your cube start moving on its own, and at whatever speed you specified.
If you would like to test the ability of our cube to bounce off of walls (a collision) then we will need to do a little more setup. Set the Cube’s transform to position (X: 0, Y: 0, Z: 0), rotation (X: 0, Y: 0, Z: 0).
Add a “Rigidbody” component to the Cube. With the Cube selected, you can click the “Add Component” button in the Inspector and type “Rigidbody” then select the component from the list. Enable the “Is Kinematic” check box on the Cube, so that we are in complete control over its position and rotation at all times.
Next, we need to specify the kinds of collisions we want to enable. From the file menu, choose “Edit” -> “Project Settings…”. In the dialog that appears, choose “Physics” on the left side, and then for “Contact Pairs Mode”, set the value to “Enable Kinematic Static Pairs”.
Next, select the Main Camera and set its transform to position (X: 0, Y: 6.5, Z: -5.5), rotation (X: 45, Y: 0, Z: 0).
Now, create another Cube. It will be named “Cube (1)” but we can rename it to “Wall”. Set its transform to position (X: 0, Y: 0, Z: 5.5), rotation (X: 0, Y: -45, Z: 0), scale (X: 7, Y: 1, Z: 1).
Now, when the cube collides with the wall, it will bounce and have its direction changed so that it now moves sideways. Save your scene, then press play to try it all out!
Summary
In this lesson, we learned about how we are going to use C# scripts to obtain similar functionality to Scratch’s code block editor. We created our first script, and learned about its composition. We learned a lot of important vocabulary related to programming including: class, method, statement, variable, and data type. Along the way, we completed our script which is able to cause a Game Object that it is attached to, to move at a constant speed, and to bounce when colliding with other objects.
If you find value in my blog, you can support its continued development by becoming my patron. Visit my Patreon page here. Thanks!