3

Programming

Welcome to Chapter 3! We are going to cover all the basics of C# and how to use it in Unity. We’ll go over the primary chunk of programming knowledge required for most projects. This chapter should serve as a referenceable chapter throughout the rest of the book when we get into scripting in each future chapter. We will first need to begin by ensuring that your computer’s environment is set up to start programming with Unity and then flow into the fundamentals of programming. This chapter will serve as a foundational lynchpin to your Unity projects. Topics include:

  • Setting up the environment
  • Variables
  • Data types
  • Programming logic
  • Methods

Setting up the environment

Programming environment specifically refers to the Integrated Development Environment (IDE) that you will use, and the dependencies associated with it. C# is part of .NET Framework from Microsoft, which needs to be installed on your machine to work. Luckily for us, many of the IDEs in the world will install that for you when you start working in C#. Even more luckily for us, Visual Studio, if installed from Unity Hub, is preconfigured and you can get right to developing your project straight away! Let’s go through the steps to see how you can set up your environment.

The Unity environment

Microsoft Visual Studio is free, directly connects to Unity, and comes with tools to help you right off the bat! This is like needing to work on your car and someone just hands you the right tool for what you need as you put your hand in the engine bay.

There are some steps to ensure that every application is talking to each other. Let’s walk through them together so we can ensure we’re on the same page moving through the book as well as the rest of this chapter; we will work through small snippets of code right away. No need to check the water’s temperature, let’s dive in!

  1. Install Unity Hub by googling Unity Hub and selecting the top link. This will take you to the official Unity webpage where you can download Unity Hub. After installing the hub, you will need to install a version of Unity to use.

As the previous chapter explained the version of Unity, we are going to recommend production using the latest LTS version. In Unity Hub, when you’re installing a version of Unity and if you do not have Visual Studio installed, there will be an option to install it for you preconfigured. In Figure 3.1 below, you can see that we already have Visual Studio installed, however, if you do not, there will be a checkbox next to it to select it. It will then install the application for you ready to go!

Graphical user interface, application  Description automatically generated

Figure 3.1: Unity Hub Install Unity modal

  1. If you didn’t have Visual Studio installed, then this will take care of configuring Unity and Visual Studio for you. If you did already have it installed, you will need to check to ensure the connection between the programs is ready for them to work together. Let’s connect Unity to it and start learning.

To begin, close Visual Studio and open the Unity project we created in the previous chapter. If you didn’t make one, no better time than now.

Navigate to these respective menus to connect Visual Studio to Unity:

Mac: Unity (Top left of the screen) -> Preferences -> External Tools tab

PC: Edit -> Preferences -> External Tools tab

In the external scripting tool dropdown, choose Visual Studio. After this has been selected, go to your Assets folder in the project window and right-click in the gray open space. Following Figure 3.2, you can create a script by choosing: Create -> C# Script. Name it ScriptingLesson and double-click it to open it. This should open Visual Studio with the proper hooks from Unity. This means that Visual Studio will read in the project file and Unity will keep it up to date with any changes.

Graphical user interface  Description automatically generated

Figure 3.2: Creating a C# script in the editor

Now we can get started on scripting! In the next sections, we will be working through the fundamentals. These will stick with you and be part of every project that you work on in the future. This would be a good section to put a sticky note in to come back to for reference.

Before we get too far, we wanted to make a point here. There may be a spot this and other chapters where the code will get unruly. Your script may not work due to a single line difference or a forgotten semicolon. This happens very often. There is no need to worry; we will have all the scripts in the project safely set up for you to recover from. However, a note is that we have heavily commented on the lines for readability. This may result in different lines being stated in the chapters than you see in the code. We will try to be as accurate in the book as possible, but sometimes a single line comment can cause this. Be flexible with us as a comment can make the difference in understanding the entire script’s inner workings and is more important than a single line number being accurate.

Fundamentals

With Visual Studio installed and connected to Unity’s editor, we should go over the basics. In this section, we will talk about data types, variables, logic or code flow, methods, classes, and MonoBehaviour. There is a lot of knowledge in this section of the chapter, but it is meant to be referenced. If you have a sticky note, it might be a good idea to place it in this chapter to easily be referenced. When you open the file, there will be autopopulated C# that we will not need for this part. For now, delete the extra parts so that it looks like this:

using UnityEngine;
 
public class ScriptingLesson : MonoBehaviour
{
// Data and Variables
// Logic and Flow
// Methods
}

The code here is doing two primary tasks. The first line imports the UnityEngine library so that we can use types and methods from the UnityEngine namespace for our game. This is called the “using directive”. Inside the UnityEngine namespace, we have access to all of our game types, such as GameObject. Since we will be working in the editor to manipulate these GameObjects, we should be using this namespace in our class.

The next portion is a class named ScriptingLesson that inherits from MonoBehaviour. Inheritance is part of Object Oriented Programing. This class needs to inherit from MonoBehaviour as it’s directly affecting objects in the game. During the Programming logic portion below we will explain how we utilize inheriting from MonoBehaviour.

The // means comment. Anything on that line will not be compiled by the IDE. You can use this to help yourself out with pseudocode or by adding some defining words to your code to help other programmers that may work with your code. We’re using it for organization purposes.

After you make the change to the script, save it by pressing Cmd + s or Ctrl + s.

If you then go back to Unity, you will see that Unity will compile the scripts. Every time we make a significant change to the script, we will go back to Unity and check on how we are doing. There will be times that the Unity Editor will not like the code we are working with, but Visual Studio doesn’t get these editor warnings or errors.

In the Scene, add an empty GameObject. Name it Scripting Lesson and then select it. In the Inspector, click Add Component and type scriptinglesson in the search bar. Left-click the script to add it to the empty GameObject. There is another way to add the component. If you have the scripting lesson selected, you can also click and drag the script onto the inspector to add the script onto the component section of the GameObject. Both ways are commonly used. Smaller projects may drag more than larger projects. Where there are many scripts and you know exactly what you’re looking to add, you may use the Add component button and type in the script name to add it. Now, when we make changes, you will see them on this GameObject.

Before we get into any data types, we should have a small discussion about variables.

Variables

Just like in algebra, variables are named containers for something. C# is a strongly-typed programming language. This means that each variable needs to have its own data type associated with it when it is declared. There are guidelines on how to name your variables and which data type to use for certain situations. We will go into detail on this within each section. Naming conventions are case sensitive, and each type of naming has its own set of rules that need to be followed.

Data types

There are 10 Unity data types that are utilized in C#, however, in Unity, we will primarily need to know 4 well. They are bool, int, float, and string. We will be creating each of these data types in the ScriptingLesson.cs file that we created.

Bool

This stands for the Boolean data type, which is designed for either true or false variables. These values are also represented by a 1 (True) or 0 (False).

As an example, this could be used when your character enters an area that they shouldn’t have to trigger something to happen, like a SPIKE TRAP!

On line 5 add:

public bool isActive;

There are four parts to this line and all of them have specific purposes:

  • public allows Unity to access the item we are creating for use in the editor.
  • bool is the data type of the item we are creating.
  • isActive is the name of the bool data we are creating. It will default to false as a value.
  • The semicolon (;) is being used here to denote that it’s the end of the instruction.

If you save and go back into the Unity Editor, you will now see there is a checkbox in the inspector named Is Active. It should look similar to this:

Figure 3.3: “Is Active” checkbox visible

Int

An integer, or int, is a whole number such as 1, 100, 200, -234571, or 0. It cannot take decimal places. This is used, for example, if you have a discrete value needed to count up or down. How many points are gathered in a play session is a great place to use ints.

On line 6 add:

public int myInt;

This is very similar to the bool. We are declaring that myInt is a publicly accessible integer data type variable. When you save and go back to the Unity Editor, you will now notice a text input to the right of a variable named myInt. Since it is an integer, you cannot put a period (.) in there to make a decimal as it’s an int and only whole numbers are allowed.

Float

You might be asking, how can I get decimal places in my numbers? The answer you seek is the almighty float! With a float, you can get decimal places such as 1.3 or 100.454.

There is a small unique factor to the float. When you are scripting, you must put a small f after the value to help the compiler know the value is a float. C# assumes that any number without f at the end, such as 3.14, is a type of double. We won’t be using a double for our scripting, so we need to remember to add the little f after our floats.

On line 7 add:

public float myFloat = 3.14;

When you tried to enter this, there was an issue with the number and there was a red line underneath the 3.14, right? If you hover over the red-underlined area, you will get an error. It might look something like Figure 3.4:

Graphical user interface, application  Description automatically generated

Figure 3.4: CS0664 error display

Visual Studio is trying to tell you that the number you entered will be thought of as a double, so let’s make a bit of a change to help the IDE.

Change line 7 to:

public float myFloat = 3.14f;

There we go. Now we have a float declared and initialized. We declared it as myFloat and initialized the value as 3.14. The default float is 0, but when you tell it to assign a value as you are declaring it, the IDE overwrites that default 0 with the value you set it to. When you go into Unity and look at the inspector, you will now see the value starts out as 3.14.

String

We’ve been working with numbers this whole time. Now it’s time for letters to shine. Strings hold the values of characters. An example of this could be the character’s display name.

On line 8 add:

public string mystring = "Myvari";

This looks the same as well, but now you can add letters! The interesting point to be made here is that these public values’ inputs all look the same, so we need to make sure our variable names are unique.

GameObject

This is an interesting data type as it’s unique to Unity. Its reference is to a GameObject that you place in it from the scene or prefab. This is extremely powerful as the item you place in here has components and we can access them from the script to do a great many things.

On line 8 add:

public GameObject myGameObject;

Save your code and head back into the editor. You will notice this time, instead of an input field, it is wanting a GameObject to be placed here. In our scene, there is a directional light. Let’s drag that light from the hierarchy and into that spot. You now have a reference to a scene GameObject! Let’s continue a bit further to logic and flow to see what we can do with our initial variables.

Programming logic

We’ve created some amazing variables filled with such fantastic data. The only problem is that we aren’t doing anything with it. Why don’t we start working some logic into our little script to start making some connection as to why we would need to program in the first place? For this, we are going to go into if statements and while loops.

Before we get to do some runtime work, we need to add MonoBehaviour to our class. The term for the actions we’re about to take is inheritance. We will derive our class from MonoBehaviour, which will give us access to its class by inheriting them! To do this is very simple.

Remembering line 3:

public class ScriptingLesson : MonoBehaviour

We are inheriting properly by adding : MonoBehaviour after our class name, and now we have access to any of the methods inside the MonoBehaviour class. There are quite a few methods we are able to use from MonoBehaviour. For now, we will use the Start() and Update() methods that are inherited from MonoBehaviour.

If statements

We’re now going to set up some simple code to turn a GameObject off and on according to the state of the isActive bool we’ve defined. To do this, we will need to check it on an update method, which is part of MonoBehaviour.

Starting with line 13, we made these changes:

private void Start()
{
    isActive = true;
}
 
private void Update()
{
        if (myGameObject != null)
        {
            if (isActive)
            {
                myGameObject.SetActive(isActive);
            }
            else
            {
                myGameObject.SetActive(isActive);
            }
        }
}

Inside the Start method from MonoBehaviour, we are setting isActive to true. This was added here to set the Boolean to be considered regardless of what was set in the editor.

After that, there is an update method. The update method from MonoBehaviour will do a check of the entire code inside the curly braces in every frame. Initially, we check out the GameObject we defined by comparing it to a null. This is a validity check. Null is a special keyword that denotes the lack of type or data. If you do not perform these checks, your editor will not be able to play as there will be a null exception. An example of this is if you have a public GameObject that isn’t assigned in the inspector, this will throw a null exception as the GameObject is null!

Inside the validity check, we have an if/else statement. It’s currently saying if the isActive variable is true, then set myGameObject to active. For anything other than true, set myGameObject to inactive.

If you save and press play, you will be able to select the scripting lesson GameObject and then uncheck the isActive boolean checkbox. It will turn off the light. Since this is checking every frame, you can do this forever and it will turn on and off until your heart’s content.

Before we move on to while loops, we wanted to do a bit of a refactor of our block above. This is a good time to learn about this as well. We went through this if block to learn the syntax, but we could’ve made it better! We are running this check every frame, so the if block isn’t needed here as we have a Boolean to compare it with. You could instead write the following code to refactor this down, saving compute time:

private void Update()
{
        if (myGameObject != null)
        {
            myGameObject.SetActive(isActive); 
        }
}

How this can be read is, every frame, if myGameObject isn’t null, set its active state to either true or false depending on what the Boolean is set to. We don’t have to ask it if it’s true or not since the data type only has two states! This is awesome.

Let’s move on to while loops for a take on looping code.

While loops

An if statement is a simple branching pattern checking for a true or false to execute something. while loops will continually run code until the statement is true or false. This can cause issues – as you can imagine, some tasks could go on forever. This is called an infinite loop and can hang your application indefinitely or until it’s forced to close. For the most part, we catch infinite loops quickly and they don’t cause much of a fuss. We should still pay attention to our criteria when creating a while loop.

On line 32, add these lines to the update method:

while (MyInt > 0)
        {
            Debug.Log($"MyInt should be less than zero. It's currently at: {MyInt}");
            MyInt--;
        }

There are several new things we’re doing here in this while loop. We are doing a debug log, string interpolation, and a decrementer. Let’s go through those.

Debug log

Debug.Log allows us to pass in a string and it will be written out in the console inside Unity. This is very helpful if there are strange things happening and you want to get some runtime information out to the console.

String interpolation

Inside the log, we are performing an action called string interpolation. This is a very handy way to add your variables into a string. This is started off with a $ followed by double quotes. Inside this is a string that you want to write out. It is a literal string to include spaces. The interesting thing is that there are curly braces {} inside the string! If you place the variable name inside the curly braces, you will get the data passed into the string. In the while loop just slightly above you can see us performing this in the Debug line.

Decrementer

The next line is a decrementer. This is an efficient way to write this line:

MyInt = Myint – 1;

If you save this and then run it, there will be nothing in the console. This is because we haven’t set MyInt to anything, so it defaults to 0. The while loop will not run because MyInt is not greater than 0 – it is 0. Let’s make this change:

On line 16, add this:

MyInt = 10;

Save and run the game. Now if you look at the console, it will quickly decrement MyInt down to 0 and print out the line letting you know its current value. If you look in the inspector, you will see that MyInt is showing 0 as well.

Now that we have an idea about programming logic, let’s add some functionality.

For loops

Like while loops, for loops are an iteration over a set number of items. for loops are most used if there is an idea of how many times the iteration will need to run. We will do a simple for loop to show the syntax of it and go over it below:

First, let’s comment out line 35 as we don’t need the while loop debug log cluttering up our for loop debug lines.

Then, on line 39, add this block of code:

for (int i = 0; i < 10; i++)
        {
            Debug.Log($"For Loop number: {i}");
        }

for loops tend to be more common, but let’s go over a bit of reasoning as to why you would want to use one or the other.

Choosing between for and while

for and while loops are similar in function. They are designed to iterate over some set of items. The rules on this aren’t written in stone. They are interchangeable technically, but there is some nuance to readability. The for loop reads as if there is a set number to iterate over. This value doesn’t need to be known to the for loop, but an example of this is a group of GameObjects. If you needed to iterate over all of them and perform logic on all of them, you wouldn’t need to code the number of items to iterate over as the grouping has a count. You can iterate over this count. We will see an example of this in Chapter 6, Interactions and Mechanics.

The difference between this and the while loop is that the while loop reads as follows: Do something until a condition is set to true. It doesn’t matter how many items need to be iterated on as it will go until the other condition is met. while loops have an inherent issue in them for making infinite loops. If you don’t 100% understand what you are looping over or accidentally use the wrong symbol (< instead of >) for your condition, you can run into that infinite loop explained in the while loop section. while loops aren’t used as much as for loops, but they do have a good place in programming.

Methods

If logic is the butter of programming, this is the bread. The purpose of a method is to perform actions in a concise manner. A very simple example of a method is a basic calculator function called Add. To perform this function, we will do three things: Create some public variables to add with, have a way to trigger the method, and the method itself. We decided to use the input system for all our inputs. To get this working, there are a few new concepts to add here as well. Previously, we asked you to insert code into specific lines. We will now just ask you to insert the code into the specific sections instead.

At the top, we need to let the program know we want to use the input system. To do this, we will add a using statement:

using UnityEngine;
using UnityEngine.InputSystem;

In the class’s variable section, add these lines:

public int addA;
public int addB;
public int totalAdd;
private InputAction testInput = new InputAction("test", binding: "<Keyboard>/b");

We’re making the int variables public so we can make changes to them and see that they are able to be changed during runtime when we run the method. The input system is private as it doesn’t need to be affected by any other scripts. This is a good practice to think about when writing your code. If a variable will not be changed from another script, then keep it as a private variable. Though it may not adversely influence the current working environment on a small project, there could be conflicts later on when projects get more fleshed out. We want to keep the code clean from the beginning.

InputSystem requires the input to have listeners turned on and disabled when not being used. We will create two methods that are native to MonoBehaviour; OnEnable and OnDisable.

private void OnEnable()
    { 
        testInput.performed += OnTestInput;
        testInput.Enable();
    }
private void OnDisable()
    {
        testInput.performed -= OnTestInput;
        testInput.Disable();
 }

These methods automatically fire during runtime. OnEnable is directly after Awake on initialization. Do not worry if this is a little bit much, we will go over them multiple times throughout this book for different perspectives.

For now, the reason these methods are here is to add the method OnTestInput when testInput is performed. We bound the letter B to our input in the variable portion, now we’re adding a method to be performed when it’s pressed.

Below and outside the update method let’s add our addition method.

    private int IntAdd(int a, int b)
    {
        totalAdd = a + b;
        return totalAdd;
    }

This is a method that is private, which means outside of this class, we can’t access this method. This is going to return an int and its name is intAdd. Inside the parenthesis after the name are arguments for the method. We have two ints: a and b. We need to define their data types and their names. When the method is running, our method makes two ints with the values at that time and assigns them to variable a and b. We made totalAdd equal to it so we could show the values change in the inspector as well as in the console to debug it even further.

To bring this all together, we need to create the OnTestInput method. This method has new terms, but for this instance, we will give them to you to get the test going for a simple button press. Later on, in the mechanics portion of the book, we will need to have more logic involved with our input. Having this system set up early allows for quick iteration and scalability with new input schemes, such as controllers.

Create a new method below the intAdd method:

private void OnTestInput(InputAction.CallbackContext actionContext)
    	{
       // If the action was performed (pressed) this frame
            if (actionContext.performed)
            {
                    Debug.Log(IntAdd(addA, addB));
            }
   }

The magic here is that this method is placed on the performed of the testInput we enable in this script. This script gets called with the action assigned to that input. Currently, we are only running simple logic to allow for the debug log to print out if the actionContext is performed.

In our case, this will be true when the method is called. If we needed other logic, such as if a cooldown for a skill wasn’t completed yet, we could tell the user they can’t perform that skill within this method. This is a very powerful system that can be built to be extremely robust.

Back in Unity, click on the script in the hierarchy and then put some values in the addA and addB variables in the inspector. Start the game and press b. You should see totalAdd change as well as the console print out the number from the Debug line.

Summary

This may have been your first time reading anything about programming. Going through these small examples is going to provide you with strong fundamentals. Take your time to fully understand what we went over in this chapter as it will be the glue holding together the rest of the chapters. We will be using all these features when programming later as well as adding new libraries and different implementations of classes. These are the foundations of programming; we will build upon them thoroughly throughout the book. If you ever get lost, refer to GitHub where you’ll find these scripts in their completed form, which you can reference if something isn’t working correctly.

This is the end of the foundations that we will build upon greatly over the next five chapters. Part 2: Build and Design will add onto everything you’ve learned so far, answer even more questions about building the design of our prototype, and show you how Unity can help you create games with as much ease as possible. Let’s move on to building out the character and put some of these programming skills together to get Myvari moving around with input.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset