Basic Concepts

Learn the basics of scripting in Unity.

Overview

A GameObject is a type of object that can exist inside a scene. Its behaviors can be altered by the use of components. However, most projects require complicated behaviors dependent upon user input and in-game events to alter the component configurations or instantiate new GameObjects. Therefore, scripting comes into play here.

Creating and attaching scripts

Scripts allow us to code our custom behavior for GameObjects. In essence, a script is a custom component defined by the developer.

To create a script, simply right-click the “Project” window and select the “C# Script” option. This will make a file appear in the window as shown below:

The script comes with the following default code:

Press + to interact
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}

Scripts created via this method inherit the MonoBehaviour class. The MonoBehaviour class not only allows the script to be attached with GameObjects inside the Unity Editor, but also provides hooks to several event functions, such as Start and Update (these are generated by default by Unity).

The animation below contains a red ball (sphere GameObject) and a green platform (cube GameObject). The platform is a Dynamic Kinematic Collider, whereas the ball is a Dynamic Collider with the “Gravity” option turned on. Moreover, both GameObjects have the same “Physic Material” attached with properties listed in the table below:

Bouncy Physic Material

Dynamic Friction

Static Friction

Bounciness

Friction Combine

Bounce Combine

0.1

0.1

0.9

Average

Average

Now, let’s rename the script we created earlier to “Platform.cs” and add the following code to enable the user to move the platform along the horizontal axis via the use of the left and right arrow keys.

Press + to interact
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Platform : MonoBehaviour
{
void Update()
{
Vector3 pos = transform.position;
pos.x += Input.GetAxis("Horizontal") * Time.deltaTime * 20;
transform.position = pos;
}
}

If you run your project now, you won’t be able to move the platform by pressing the arrow keys. This is because, in Unity, a script needs to be attached with an active GameObject to be executed. Therefore, we will attach the Platform.cs script to our platform. We can do this by simply dragging the script from the “Project” window and dropping it on the platform in the “Scene” view. However, we can also add it via the “Inspector” window, as shown in the animation below:

As you observed in the animation, every script in Unity (derived from the MonoBehaviour class) is treated as a unique component, thereby being accessible in the “Add Component” menu.

The script above will result in the following behavior:

Variables in the Inspector

Thanks to the MonoBehavior class, there’s a very special relationship between the “Inspector” window and the class variables declared inside the script. Just like components have properties editable in the “Inspector” window (shown below), class variables can serve the same purpose.

Now, let’s say we want to change the color of our platform from green to pink whenever the user hits the spacebar. Since we know that we simply need to alter the “Materials” property of the “Mesh Renderer” for the platform, we alter the Platform.cs script as follows:

Press + to interact
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Platform : MonoBehaviour
{
private Material Color1;
private Material Color2;
private bool ColorMode;
private MeshRenderer mr;
void Start() {
Color1 = Resources.Load<Material>("Materials/Green_Color");
Color2 = Resources.Load<Material>("Materials/Pink_Color");
ColorMode = false;
mr = GetComponent<MeshRenderer>();
}
void Update()
{
Vector3 pos = transform.position;
pos.x += Input.GetAxis("Horizontal") * Time.deltaTime * 20;
transform.position = pos;
if (Input.GetKeyDown(KeyCode.Space))
{
Material[] materials = mr.materials;
if (ColorMode) {
materials[0] = Color2;
}
else {
materials[0] = Color1;
}
mr.materials = materials;
ColorMode = !ColorMode;
}
}
}

Note: For the script above to work, there need to be two materials present with the name “Green_Color” and “Pink_Color” inside “Resources” > “Materials.” As a general rule, the Resources.Load method can only load those resources that are nested under the “Resources” folder.

The drawback of the script above is that if we decide to change either of the two colors in the future, we’ll have to open the script again and edit the asset path on lines 13 and 14. However, if we simply make our Material variables public, we’ll be able to edit them in the “Inspector” Window (as shown below). Consequently, we won’t need to initialize them in the Start method.

private Material Color1;
private Material Color2;
public Material Color1;
public Material Color2;
Script with private variables
Script with public variables

Note: You can also use the SerializeField attribute with private variables to make them visible in the “Inspector” window.

The animation below depicts the color change of the platform when the user presses the spacebar:

Prefab Instantiation

Now, let’s say that we have another use case in our game that requires us to spawn the ball randomly in the scene rather than in the same place. If you are thinking of randomly updating the coordinates of the ball, then you’re right. That’s one way to go about it. However, what if we want to spawn a random number of balls rather than a fixed number?

Our problem will be solved if we attach the script below with any GameObject in the scene. So, let’s create an empty GameObject named GameController and attach the script with it.

Press + to interact
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameController : MonoBehaviour
{
public int MaxBallCount;
public Vector2 LowerBound;
public Vector2 UpperBound;
public PhysicMaterial BouncySurface;
public Material Red_Color;
void Start()
{
int BallCount = (int)Random.Range(1, MaxBallCount);
for (int i = 0; i < BallCount; i++)
{
Vector3 newCoord = new Vector3(Random.Range(LowerBound.x, UpperBound.x), Random.Range(LowerBound.y, UpperBound.y), 0);
SpawnBall(newCoord);
}
}
private void SpawnBall(Vector3 BallPosition)
{
GameObject Ball = GameObject.CreatePrimitive(PrimitiveType.Sphere);
Rigidbody RB = Ball.AddComponent<Rigidbody>();
RB.constraints = RigidbodyConstraints.FreezePositionZ;
SphereCollider Collider = Ball.GetComponent<SphereCollider>();
Collider.material = BouncySurface;
MeshRenderer MR = Ball.GetComponent<MeshRenderer>();
Material[] materials = MR.materials;
materials[0] = Red_Color;
MR.materials = materials;
Ball.transform.position = BallPosition;
}
}

The script above results in the following gameplay:

Although the script works great, a major downside is that we have to write ten lines of code just to instantiate a ball. And what if we want to add more components to our GameObject or alter some of the configurations of the existing components? That would just result in extra lines of code, right? So, Prefabs are here to rescue us!

A Prefab is like any other GameObject, with as many components stuffed in, but it’s not present in the scene; rather, it’s stored in our project directory. It’s pretty simple to create a Prefab; simply drag your GameObject from the “Hierarchy” window into your “Project” window to create one.

Note: The GameObject should exist in the scene while the game is not running for you to drag and drop it to create a Prefab.

Finally, declare a public variable of type GameObject in your script and attach the Prefab you just created.

The script shrinks considerably, as shown below:

Press + to interact
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameController : MonoBehaviour
{
public int MaxBallCount;
public Vector2 LowerBound;
public Vector2 UpperBound;
public GameObject BallPrefab;
void Start()
{
int BallCount = (int)Random.Range(1, MaxBallCount);
for (int i = 0; i < BallCount; i++)
{
Vector3 newCoord = new Vector3(Random.Range(LowerBound.x, UpperBound.x), Random.Range(LowerBound.y, UpperBound.y), 0);
Instantiate(BallPrefab, newCoord, Quaternion.identity);
}
}
}

Congratulations on covering the basics of scripting in Unity!