Game Dev Prodigy: Journeying into Unity and C# for First-Time Developers

Salome Tchintcharauli
Women in Technology
16 min readJun 21, 2023
Source

Hey, there future Game Developers and curious persons in general, who are eager to start their journey with Unity and C#.

In this story, we will build a 2D driving game called “Delivery Driver”, where we drive around and pick up packages to deliver to a certain location.. we also will be able to increase and decrease the speed of movement when we cross some speed-up points until we bump into the border or other impedance.

We will focus on the basics of C# such as:

  1. Variables
  2. If statements
  3. Booleans values
  4. We will create methods
  5. Colliders
  6. Rigid Bodies
  7. Tags and other small but very important parts of the basics.

I suppose as a curious person or more as a developer you already have the necessary tools such as Unity soft on your computer and IDE in my case it is Visual Studio Code. So without further ado let us open the Unity project. Make sure that you choose a 2D format for the game.

The blank project window

Here we have a starting window. First, we will try to make some Sprite to try and get use to the software. We have to stand on the SimpleScene window and right-click on the mouse to choose 2D objects -> sprites -> Capsule, like it is given in the screenshot below.

After we create the capsule sprite we can click on it and change the name to be more suitable for our game.

Next, we dive into the script itself. We should stand on the assets window and with the right-click on the mouse choose create -> C#

and the document will appear in the assets window. Let us call the document Driver to get together all the driver-related code in it.

To be able to use this document around our driver sprite we can drag and drop it on the right side under the “Add Component”. we can do the same if we click on the Add Component button and search for our document with its name.

Now is the time to learn what is the method in C# and why we need it. By the general definition method is a block of code (AKA Functions) that only runs when it is called. In our case method helps us to make the game dynamic.

There are two way of methods:

  1. Methods that are already available in Unity (so-called build-in methods/functions)
  2. Our own methods (which we can make depending on the staff we want to execute. We will learn more about it soon).

As all the other functions in any programming language methods in C# also has to have a name and a body, a piece that is told what it should do. So we write a code, give it a name and then call it to execute it.

Let us practice on it. When we click twice on the driver document that we created a minute ago, we will relocate in the vs code (in your case in your IDE) and the inside looks like it:

On the top of the document, there is code that starts with the keyword “using”, which basically means that the program is using all the resources contained there.

Then we have public class. Class is the way to group things together. Then we have Start() and Update() methods, they are so-called call-back functions we will not dive deeper into here but the main thing to know about it is that in our case, Unity engine will know what to execute when the game starts and what to update when game will in progress. So to say we have two main parts of the program the beginning and the progress.

When we open Unity and on the upper part in the center we will click the play button it will start the code which is written in the Start() method and will update the code within the Update() method every frame when the game is on.

Let us describe and use some variables to start building our game.

There is common vision that the variables are containers for storing data values, but let me give some example from my favourite book “Eloquent Javascript”

You should imagine bindings as tentacles, rather than boxes. They do not contain values; they grasp them — two bindings can refer to the same value. A program can access only the values that it still has a reference to. When you need to remember something, you grow a tentacle to hold on to it or you reattach one of your existing tentacles to it.

In C#, there are different types of variables (defined with different keywords), for example:

  • int - stores integers (whole numbers), without decimals, such as 123 or -123
  • double - stores floating point numbers, with decimals, such as 19.99 or -19.99
  • float — represents numbers with a fractional part, containing one or more decimals.
  • char - stores single characters, such as 'a' or 'B'. Char values are surrounded by single quotes
  • string - stores text, such as "Hello World". String values are surrounded by double quotes
  • bool - stores values with two states: true or false

Let us declare variables to define speed for our driver.

public class Driver : MonoBehaviour
{
float steerSpeed = 1f;
float moveSpeed = 0.01f;

void Start()
{

}

void Update()
{
transform.Rotate(0, 0, steerSpeed);
transform.Translate(0, moveSpeed, 0);

}
}

With the code above we declare variables steerSpeed and moveSpeed and assigned them to the property of 1f. Then we apply these variables to the build in methods within the Update function. So basically with this, we are saying that the driver will rotate 1f and move with the velocity of 0.01f. If some of the code feels or seems hard to understand don’t panic I got you, we will go through all the necessary details along the way.

Now it is time to use [SerializeField]. this is the automatic process of transforming data structures or object states into a format that Unity can store and reconstruct later. In other words, we assign it to the variable and the variable is visible in the Unity under the driver script.

public class Driver : MonoBehaviour
{
[SerializeField] float steerSpeed = 1f;
[SerializeField] float moveSpeed = 0.01f;

}

Now when these changes are applied the moment we hit the start button and try to use the arrow buttons on our keyboard we should be able to move the driver left and right. Great progress so far.

Let us go further both literally and figuratively. We need the driver to be able to move not only on the right and left side but also to move forward and backward. For this, we will need Unity Input System. But before using it we have to know what the input system is. In Unity input system is the way of converting a player’s physical actions (button press, key press, etc.) into information for the game.

Let us write another variable in our code

void Update()
{
float steerAmount = Input.GetAxis("Horizontal");

transform.Rotate(0, 0, steerSpeed);
transform.Translate(0, moveSpeed, 0);

}

Here we created a variable called steerAmount and assigned it to the value Input.GetAxis(“Horizontal”) where Input is the method we explained above and GetAxis method which will get a particular axis we will pass as an argument inside, in our case it is X axis, and that's why we write “Horizontal” in it. Be aware that the words should be spelled correctly, otherwise, the code will not work. Our newly declared variable we should assign to the rotate function.

void Update()
{
transform.Rotate(0, 0, steerAmount);
}

But here is a trick, if we just assign it will work backward and of course, we don’t want it, so to skip the basic math lesson and explanation we will add minus before steerAmount in the rotate function to make the driver work correctly.

void Update()
{
float steerAmount = Input.GetAxis("Horizontal");

transform.Rotate(0, 0, -steerAmount);
}

Everything works perfectly but now we should control the speed driver is moving, so for that Input method we multiply with steerSpeed. The same steerSpeed variable that is declared at the beginning of our code.

void Update()
{
float steerAmount = Input.GetAxis("Horizontal") * steerSpeed;

transform.Rotate(0, 0, -steerAmount);
}

Now everything works as it should. But we don’t have the input from the vertical axis, don’t we? So let us write it as well.

void Update()
{
float steerAmount = Input.GetAxis("Horizontal") * steerSpeed;
float moveAmount = Input.GetAxis("Vertical") * moveSpeed;

transform.Rotate(0, 0, -steerAmount);
transform.Translate(0, moveAmount, 0);
}

Now we definitely have a working code with all of the necessary directions to move.

Let us learn basics about Colliders and Rigidbodies. Firstly go ahead and test the knowledge we already gain by adding another sprite in the Unity. If you have trouble remembering it scroll up and there are all the details on how to do it. So make the sprite any shape you like and try to go through it with your driver element. Did you notice that nothing has changed? this is because the newly created element has no borders or limits to stop driver passing it. For the game purposes, we need the objects to be rigid and apply the details on both of them.

The first thing is adding Colliders. Click on the driver, then on the right side click on the Add Component button and search Capsule Collider 2D as our driver has the shape of a capsule. This collider means that things can not pass through this object and this is very important. We are doing the same for another object, in my case it is circular, you go ahead and choose your object's shape collider. One more thing we need to apply Rigid Body 2D to the driver and it is added the same as the collider but instead, we search for rigid body 2D. With this, our driver will get additional functions such as gravity scale and when we hit play the object will move without our interaction. so we need to turn it to zero.

Go ahead and change the gravity scale to 0. After that when we start playing our objects will bounce each other. This is exactly what we wanted.

Let us go further and use our already gained knowledge with some additional ones. Now, we want to write code that will tell us when we bump into other things and many more. For that, we need to add another script. So go ahead and create a new script called Collision. Open it and remove everything that’s inside the public class Collision: MonoBehaviour.

We will use the Unity Build-in method that is similar to start and update and that is called OnCollisionEnter2D. It will declare like this:

puclic class Collision: MonoBehaviour 
{
private void OnCollisionEnter2D(Collision2D other){}

}

We can remove the word private from the declaration which is not our concern for now. Let us test if this works. write Debug.Log with the message in it.

puclic class Collision: MonoBehaviour 
{
void OnCollisionEnter2D(Collision2D other){
}
Debug.Log("We bumped into something");
}

To test it we need two more steps. One is to go to Unity and add a collision script to the component as we already know how and the second one to open the console in Unity.

When we bump into something the message will appear here.

Now let’s learn about another method which is OnTriggerEnter2D. This method is to get information when the driver will pass through the trigger element and make some additional things throughout the game-building process.

Go ahead and make another sprite, I am sure you already know how to do it so well. Then add a collider to it, in my case it is a box-collidder cause the shape is rectangular and when you apply collider go and click on collider property to see the properties it has in it. Here you will see Is Trigger value, go ahead and mark it to be able and use this element as a trigger in the future.

One very important note when we start playing and go to the trigger our delivery car will go under the trigger, that is because it is on the low order in the layer.

It is your personal challenge to change the order of the layers so the car will be on top.

I am sure you did it great!

Now it is time to use code to write some messages in the console when the car will pass on the trigger element.

puclic class Collision: MonoBehaviour 
{
void OnTriggerEnter2D(Collision2D other){
}
Debug.Log("We passed through the trigger");
}

With this code, the message will print out in the console window in Unity.

So far we are doing small progress and it feels pretty awesome, isn’t it?

Now is the time to add some assets to our project. There are several resources to download free assets. e.g :

  1. https://unityassets4free.com/ — for educational purposes only;
  2. https://opengameart.org/ — all the necessary assets for small 2D games

Try to look through and find the one you need. When you find and download a desirable one you can simply drag the assets folder and drop it in the project window in Unity. You can also play with the sizes of the elements and adjust them depending on your taste.

Let us assign our driver element to the actual car in our project. When we click on our capsule element and change the sprite as it is given on the photo.

With a click, we can choose any element that is given within our assets. Go ahead and choose your favorite one for the delivery car. 🚗

Now we have a set, the main element and we need the camera to get to the action!
For that, we will learn how to follow the camera in the action. First, create another script called FollowCamera. We will need only Update() method in it. In Unity we will apply this script to the Main Camera, it is in the scene list where the other elements are. We want the position of the camera to be equal to the thing to follow.

puclic class FollowCamera: MonoBehaviour 
{

[SerializeField] GameObject thingToFollow;

void Update()
{
transform.position = thingToFollow.transform.position;
}
}

This basically does what we said above the code to be done, except one thing it will literally be on the gameobject, like super zoomed and we don’t want that do we? For this we use the new keyword the Vector3 to tell Unity that we want to get minus value, so to say get a zoom out from the main camera to be able to see the scene fully. We will write code like this:

puclic class FollowCamera: MonoBehaviour 
{

[SerializeField] GameObject thingToFollow;

void Update()
{
transform.position = thingToFollow.transform.position + Vector3(0, 0, -10);;
}
}

Now the scene and the camera are zoomed out and responsive to the movement.

We already know most parts of the game, we only have to learn several more and our first game will be ready to play.

Let us continue. We need several sprites as packages and one for the user to whom we deliver our goods and more importantly, we need to learn about the statements in C#.
In this project, we will use if statements. If statements let us check if something is true or not and then do something depending on the result.

But before we use if statements we need to check the tags in order to be able to connect elements from the unity with certain code in the C#. In other words with tag, we easily check in code if something belongs to a particular category of thing. Here in the inspector window we click on the tag then add tag as it is shown on the picture below and add the name of the tag. We call it a “Package”.

The tag is created but not assigned yet to assign it we have to click on the object and then click tag property again and in the list, there will be a tag by the name Package already so we will choose it and now the object is assigned to the desired tag.

As for the code let us write the logic.

puclic class Collision: MonoBehaviour 
{
void OnTriggerEnter2D(Collision2D other){
}
if(other.tag == "package"){
Debug.Log("this is the package");
}
}

So with that said when the car will pass on the package object it will display the message in the console. Now it is time for you to practice. Go ahead and make sprite called customer and assign it with the tag “customer” to use it in the code.

Well done! now use it in code.

puclic class Collision: MonoBehaviour 
{
void OnTriggerEnter2D(Collision2D other){
}
if(other.tag == "package"){
Debug.Log("this is the package");
}

if(other.tag == "Customer"){
Debug.Log("this is the Customer");
}
}
  • quick note do not forget to add collision on the customer sprite.

Now one more important part is bools. We already know when the driver takes the package and brings it to the user but, visually nothing changes, we only see the messages printed in the console. For solving this we need to use bools. Bools are types of variables, remember we explained it when we were talking about variables at the beginning. So it can store one of two values, true or false and they are often used with if statements. Now it is time to write some boolean variables.

puclic class Collision: MonoBehaviour 
{
bool hasPackage;
}

So here we declared the boolean called hasPackage which has a false value as a default and we want to assign it to our package, so we change it to true inside the if statement of the package.

puclic class Collision: MonoBehaviour 
{
bool hasPackage;

void OnTriggerEnter2D(Collision2D other){
}
if(other.tag == "package"){
Debug.Log("this is the package");
hasPackage = true;
}
}

So now we have the package and we are going to the user. When we get there we want to give it to the user, that means we want the hasPackage value to be false again, right ? So we write

{
bool hasPackage;

void OnTriggerEnter2D(Collision2D other){
}
if(other.tag == "package"){
Debug.Log("this is the package");
hasPackage = true;
}
if(other.tag == "Customer" && hasPackage){
Debug.Log("this is the Customer");
hasPackage = false;
}
}

Pay close attention to the attribute inside the second if statement, before we change the package to false first we check if it is true in the attribute. Here if(other.tag == “Customer” && hasPackage) && is the “and” notation as it is in every programming language.

Now when we take the package we don’t want the box to be visible anymore do we? And for this, we will use the method to destroy the objects. Sounds fun 🤩

We have Destroy() function to delete the objects from the scene. This function is a call-back function and we need to pass two arguments, first, we tell which game object to destroy, and second when to destroy it. Let’s dive into code.

{
[SerializeField] float destroyDelay = 0.5f;
bool hasPackage;

void OnTriggerEnter2D(Collision2D other){
}
if(other.tag == "package"){
Debug.Log("this is the package");
hasPackage = true;
Destroy(other.gameObject, destroyDelay);
}
if(other.tag == "Customer" && hasPackage){
Debug.Log("this is the Customer");
hasPackage = false;
}
}

To be more professional we first write a variable called destroyDelay and assign it to 0.5f as a time for destroying the object and in the package statements we write Destroy function as it is shown in the code. with that our car 🚘 is able to travel through the scene, collect packages and deliver them.

Almost done! we just need to boost the speed and reset it when the car bumps into something. For this, we need to declare speed variables.

public class Driver : MonoBehaviour
{
[SerializeField] float steerSpeed = 1f;
[SerializeField] float moveSpeed = 20f;
[SerializeField] float slowSpeed = 15f;
[SerializeField] float boostSpeed = 30f;


void Update()
{
float steerAmount = Input.GetAxis("Horizontal") * steerSpeed;
float moveAmount = Input.GetAxis("Vertical") * moveSpeed;

transform.Rotate(0, 0, -steerAmount);
transform.Translate(0, moveAmount, 0);
}

}

Here we declare several variables. Let us now use it in the if statements to finalize the game logic.

But before we use boosted speed you need to make one additional sprite with the name Boost and assign it to the tag Boost which you can also know how to do.

Now let us finish our code.

public class Driver : MonoBehaviour
{
[SerializeField] float steerSpeed = 1f;
[SerializeField] float moveSpeed = 20f;
[SerializeField] float slowSpeed = 15f;
[SerializeField] float boostSpeed = 30f;

void Update()
{
float steerAmount = Input.GetAxis("Horizontal") * steerSpeed;
float moveAmount = Input.GetAxis("Vertical") * moveSpeed;

transform.Rotate(0, 0, -steerAmount);
transform.Translate(0, moveAmount, 0);
}

void OnCollisionEnter2D(Collider2D other){
moveSpeed = slowSpeed;
}

void OnTriggerEnter2D(Collider2D other){
if(other.tag == "Boost"){
moveSpeed = boostSpeed;

}

}

}

In the code above we create two functions and apply all the variables we declare early. To explain we wrote when the car will bump into something the general movespeed will decrease and when the car will pass through the boost element the speed will increase.

With that, we are officially done building our game! Congratulations 🎉 we did a great job!

To wrap up the things we can say that:

  • We learned about unity basics such as how to make a sprites
  • Change and manipulate them
  • How to create C# sripts
  • How to declare and use different data types
  • connect them to the Unity system and
  • write the code which will run in the unity environment.

I think this was quite a journey for us. Let us improve all the knowledge we gained n so far and we will meet with another topic.

  • note As a reference used “Complete C# Unity Game Developer 2D” from Udemy courses.

--

--

Salome Tchintcharauli
Women in Technology

Full stack developer 👩‍💻 curios person 🌀 jazz lover 🎷 perfectionist ⭕️