Beginner's Scripting Guide

From Unify Community Wiki
Jump to: navigation, search

Contents

Introduction

In this portion of Beginner's coding in Unity, we will handle using the CSharp language. This is because CSharp is regarded as one of the more popular programming languages. The terms used in this article will not necessarily be the "correct" or "good" term to use. It will essentially be used to get beginner coders, like you, to understand the idea I am trying to get across.

C# Syntax

The first thing you see when creating a C# script in Unity is something like this:

using System.Collections;
using UnityEngine;

What does this mean? Simply put, there are a TON of methods/functions, classes, namespaces, etc. that are created by Unity Technologies for you. These are helper functions, Math functions, Object classes (GameObject/Transform), and more. These classes were made for Unity. Therefore, they wouldn't be used within another game engine, or if you are creating an application in C#. These classes are specifically for Unity. Therefore, Unity put them in a handy "folder", which we call namespaces. A namespace is a group of classes (or 'files'). Similarly, a class is a group of methods (code). It's just a neat way to keep everything organized. Since these classes are in a namespace (which is 'UnityEngine'), we must tell the C# Script that we want to use the classes that are within that namespace, or that we want access.

On another note, you may be thinking, "Why can't I just have everything I will ever need, and not have to worry about namespaces? Then I wouldn't ever have to use 'using...'!" And the simple answer is 3 things: 1.) MonoDevelop/Visual Studio (or whatever text editor you are using) will crash, because auto-completion will try to load all the possible methods and combinations that you give it. 2.) If you do manage to get it to work, there is a lot of guessing. What if there is a method called "GetInfo()" in a class called "HelperClass", but there is also a "GetInfo()" method inside of a class called "Notifications"? Which one would we use? 3.) Unity could possibly crash. By telling Unity that we want to use those namespaces/classes, as far as I know, memory is being reserved for those classes so we know how to access them. If you have thousands of classes ready, a lot of it is useless if you aren't going to use it. But all of this is simply just a thought. Moving on!


The next thing you see is our class identifier. This tells the script what it is called, and how it can interact. It may look like this:

public class HelloWorld : MonoBehaviour {

Let's break this down: Public tells Unity that the script can be accessed outside of its own script. If we create another script, we can access 'HelloWorld' from it, because it is public. As mentioned before, a Class is a group of methods. That's all it really is. These methods can be used however you want: They could be Object classes (which we will get into later), Helper classes (which usually is an Input>Output, or helps you process information easily), and more. The name of our class must match exactly with the name of our script. If you change it, you will also have to change the name of the script. Finally is inheritance. This is why you see the ': MonoBehaviour'. We are inheriting from MonoBehaviour, which is also a class. It's just like 'HelloWorld' class, except it is packed full with goodies! MonoBehaviour is what gives us access to pretty much everything you need to get scripts to work on objects in Unity. When you inherit from a class, you can see that in Unity. In the Inspector, you may have seen '(MonoBehaviour)' in the inspector before. If you did not inherit MonoBehaviour here, you would not see your script correctly in Unity!

So, let's get to understanding basic syntax in Unity. Below is a list of various tools you will use frequently.

Loops

Loops allow us to repeat statements multiple times without having to type it over and over. The benefit of this is we can also change how many times it loops with a variable.

For Loop

A For loop allows you to loop using an index, then use that within the loop. The index is generally used to access a specific index in an array/list.

for(int i = 0; i < 10; i++) { }

In this example, we are defining our “index” to be an integer. We are calling it i. We then set its starting value to 0. We complete this ‘statement’ with a semicolon, then follow it with the test, where we repeat the loop as long as i is less than 10. Obviously, you could change this to be anything you want. The comparison symbol could be “<, >, <=, >=” and more. The 10 can also be anything, even another variable. Finally, we define the step. i++ means we want to increment i one step each time. So the first time we run through the loop, i = 0. After we reach the end of the for loop code, i = 1, 2, 3, and so on, all the way until 9, when i is no longer less than 10. At that point, the loop breaks.

While Loop

While loops are common when trying to halt your code until a condition is met, or as long as a condition is met. These are most commonly used in Unity within Coroutines. A while loop will take in a condition, and will run the code within as long as the condition is true (Note that this means the while loop will run as long as the condition inside its parentheses is ‘true’).

while(i == 1) { }

In this example, as long as some variable called i is equal to 1, the code below will run. Outside of Unity, most game developers will use a while loop as their “update” function, so code is executed every frame. If you want to execute code all the time in a while loop, no matter what, the most common approach is to do:

while(true) { }
Foreach Loop

A Foreach Loop is similar to a For loop. However, in a Foreach loop, you are not incrementing/decrementing a variable (such as an int i), but you are incrementing through a reference to an array. For example, if I have an array of strings called string[] myStrings, I can access a reference to the elements inside of that array without having to pass in an element.

foreach(string s in myStrings) {
    print(s);
}

In comparison, if we wanted to access an element in an array using a for loop, we’d use something like:

for(int i = 0; i < myStrings.Length; i++) {
    print(myStrings[i]);
}

Essentially, we will increment from 0 to the length of the array - 1 (Because an array of 10 elements has indexes 0-9. We start at 0, not 1, therefore we have 1 less ‘element number’ than the size of 10), then we will access that element by passing it into the myStrings array.

Nested Loops

It is possible to nest loops inside each other. This means we could have multiple loops running inside. This may be useful if you want to mess with a “2D array”, which would look like this:

for(int a = 0; a < 3; a++) {
    for(int b = 0; b < 3; b++) {
        print(a + “, “ + b);
    }
}
 
 
Output:
0, 0
0, 1
0, 2
1, 0
1, 1
1, 2
2, 0
2, 1
2, 2

Unity Essentials

This section is comprised of 'essentials' for understanding how to get basic input/output, and utilize coding features specific to Unity.

Inheritance Tree

Unity has a lot of different classes. Below is a structure of how each of these inherit from one another:

  • Object
    • Component
      • Behaviour
        • MonoBehaviour
        • Terrain
      • Transform
  • GameObject


GameObject

GameObjects are what you will most commonly used to access information from geometry in your scene. If you have multiple scripts on the same object (GameObject) in your scene, you will use methods in the GameObject class to “find” other scripts (MonoBehaviours) on your object.

Often times, you will see GameObject show up 2 different ways in scripts:

GameObject.Find("");
gameObject.GetComponent();

The above 2 example methods that can both be called, both of which are from the GameObject class. There is a difference between the two. The first one has a capital 'C' and the second has a lower-case 'c'. If you are using the first one (GameObject), you are calling static methods. These are methods that are independent on your object. These are methods that you can call at any point of time, because they do not require a reference to the object the script is attached. However, the second script is not a class. The lower-case 'gameObject' is a reference variable. It is assigned to automatically by Unity because we inherit from MonoBehaviour (which is one of those cool features)! So when you use 'gameObject', you are then calling methods that are specific to that GameObject the script is attached to. Therefore, you will not see the methods from the GameObject class that are static, because 'gameObject' is not static, it is a reference.

If this is becoming confusing, then you're on the right track! At least you're getting those brain cells roaring up on speed again. But if you're confused, let's wrap up the last paragraph: GameObject (capital 'C') is a class/CSharp script somewhere in Unity's core. 'gameObject' (lower-case 'c') is a variable which is the "local" GameObject that the script instance is attached to. If you call methods from gameObject (lower-case), you are calling methods on that single specific object.

Now you may be thinking, what is 'gameObject'? How does it compare to anything else? Really, it's the same thing as if you did this:

public class Example : MonoBehaviour {
    public GameObject gameObject;
}

This will not work, however, because 'gameObject' is already a variable because we inherit from 'MonoBehaviour'.


I won't go over the specific methods of each though. That's where you can look at the documentation.

Transform

The Transform component on the objects in your scene have a large amount of importance, just like GameObject. As far as I know, you cannot use GameObjects in your scene without using a Transform component. Now that I've mentioned it, let's talk about what this 'Component' means for Transforms. Just like GameObject, Transform is also a class built into Unity. It's some CSharp script deep inside that you cannot access. It's got methods, variables, etc., just like GameObjects. However, Transform is visible in the Inspector of objects in your scene because it is attached to GameObjects. So even though Transforms are "lower level" than GameObjects, they are usually just as important. GameObjects derives from Object, as we've seen in the Tree structure made above. However, Transform derives from Object>Component. Similarly to GameObjects, you can get a reference of it (thanks to MonoBehaviour) via the transform variable.

Now that we've got that out of the way, there are some key concepts when understanding transforms. The 3 most used features of the Transform class is PSR (position, scale, rotation). Manipulating these properties allow you to change where and how your geometry (GameObjects) appear in your scene. If you've used Unity for a while, you probably already know this. However, there is some confusing bits when we get to rotation. Both Position and Scale are variables that are stored as a Vector3, which is essentially 3 float values. Each value corresponds to the position across an axis in 3D space. Vector3, however, is not a class (Like GameObject/Transform), it is a struct. Structs are a little more confusing, but we may talk about that someday. However, rotation is handled using Quaternions, which is, at its root, a Vector4 (meaning it has 4 float values). I'm not going to go into Quaternion math, but essentially, each value in a Quaternion is interdependent on the other ones. So your best bet is to avoid ever changing 'transform.rotation' manually by setting its value. So, what is 'Rotation' we see in the Inspector? Why is it a Vector3, even though it's a Quaternion/Vector4? It's because it is easier to see as a Vector3. Unity converts it from a Quaternion to a Vector3 so it's more appealing to you. The XYZ values for rotation in the Inspector compare to pitch, yaw, and tilt on their respective axes. To get this rotation the "appealing" way we want to see it (as a Vector3), instead of using 'transform.rotation', we can use 'transform.eulerAngles', which returns rotation as Euler (pronounced oil-er) angles.

One of the biggest problems people run into when trying to change position in Unity (using CSharp) is trying to change individual axes. Without describing it, let's just see the wrong vs. right:


//Wrong
transform.position.x = 10;
 
//Right
transform.positoin = new Vector3(10, 0, 0);

Long story short, we cannot change individual values. This is because 'transform.position' is a struct, not a class. Therefore, we cannot change values of it, we must reassign the transform.position struct via a reference. That's why we type 'new Vector3()' because we are creating a new Vector3 variable (which is just temporary, via the 'new' keyword).

Vector3

Vector3's are, as simply as it is, 3 float values. That is it. In Unity, Vector3's may do some extra work, such as give you helper classes for converting it from this to that, but essentially, it really just is 3 float values. What I am trying to say is you do not need to use Vector3 for just position or scaling. Vector3's can be used if you want to store 3 sets of data, such as score, kills and deaths in a simple structure. It may be easier to create your own data type later on, but if you need something to work quickly to hold 3 floats, that's all you really need!

Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Tools