This tutorial shows basics for Unity 2D Game Development concepts like adding custom components to Game Object, fundamental Unity scripting with C#, 2D Game Object movement in Unity, how to handle inputs in Unity, and how to instantiate Game Object in Unity.
Disclaimer
Due to this course’s intention, we will not cover basic knowledge in programming with C# in Unity but rather provide info with complex terms in this language or Unity Scripting API.
To get more info and learn about these topics, you can refer to:
- Microsoft’s .NET C# Documentation
- Unity’s Manual section “Creating and Using Scripts”
- Unity API Scripting Reference
- Codecademy’s Learn C# Course
- Unity Learn
Requirements
- Complete “Getting Started in Unity 2D Game Development” or checkout the code from Genoma Invaders’ Github repository, branch
tutorial/01
- Have basics knowledge in programming with C#
- Visual Studio Editor (you should have installed it when installing Unity) or another code editor of your preference
In the previous tutorial, “Getting Started in Unity 2D Game Development”, we walk through basic concepts about developing 2D games in Unity, ending up with a scene with some still Game Objects. It’s time to give them some movement logic starting by the Player.
This time we will learn to move 2D Object in Unity by scripting in C# using Game Components.
Custom Components
To move our Player, we will need to add some logic to its dumb Game Object. We will do it by creating a Custom Component containing C# code and adding it to the Player Game Object.
Select the Player Game Object and press the “Add Component” button in the Inspector window. Then, write in the search input Player
, select New Script
, and press the “Create and Add” button.
Note: checkout Unity’s Manual section “Creating components with scripting” for more info.
This action will create a C# file under /Assets/Player.cs
that defines a component named “Player”, and then it will add this Component to the Player Game Object. Move the Player.cs
file to /Assets/Genoma Invaders/Player/
folder using the Project window to maintain the project’s files organized.
Player Controller
The Player component will be the Player Controller or, in other words, the Component in charge of handle the player’s logic.
If you open the file you’ll see this:
Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
That is the basic code structure Unity Editor creates for every script/component created in the project.
Now we are going to make de same, and create an Enemy Custom Component for the Enemy Game Objects. This time we are using a different technique. On the Project window, go to /Assets/Genoma Games/Enemy
right click on it to open the contextual menu and select Create > C# Script
, then name the file Enemy
.
When Enemy.cs
file is created, Unity reloads for a sort time and will register a new component to be added to Game Object named Enemy
. Go ahead and add it to both Enemy Game Objects.
Note: Remember to add the Enemy component to both enemies.
Game Object Movement
To make the Player Game Object move, edit Player.cs
file. First, we will clean it up a bit, so it doesn’t have unnecessary code:
Player.cs
using UnityEngine;
public class Player : MonoBehaviour
{
private void Update()
{
}
}
Now, we will add some logic into its Player Controller’s Update
loop method.
Player.cs
using UnityEngine;
public class Player : MonoBehaviour
{
private void Update()
{
// https://docs.unity3d.com/2020.1/Documentation/ScriptReference/Vector3-right.html
Vector3 right = Vector3.right;
// https://docs.unity3d.com/2020.1/Documentation/ScriptReference/Time-deltaTime.html
float timeSinceLastFrame = Time.deltaTime;
Vector3 translation = right * timeSinceLastFrame;
// https://docs.unity3d.com/2020.1/Documentation/ScriptReference/Transform.Translate.html
transform.Translate(
translation
);
}
}
Note: Visit any of the links in the code’s comments for more info.
This code is creating a Vector3
pointing to the right (1, 0, 0) and multiplying it by time elapsed since the last frame, and then calls Transform.Translate
method with the resulting Vector3 which will move the Game Object that distance.
TL;DR; This will make the player move 1 Scene unit per second to the right.
To see the result go to Unity Editor and press the “Play” button (You can use the keyboard shortcut Ctrl/Cmd+P).
It’s alive!!! But we need to be able to control this little guy.
Detect Player Input
To control the Player, we need to use Unity’s Input Manager. With the Input.GetAxisRaw
method, you can retrieve the corresponding axis input value, in this case, if some left or right key is pressed.
Player.cs
using UnityEngine;
public class Player : MonoBehaviour
{
private void Update()
{
// https://docs.unity3d.com/ScriptReference/Input.GetAxisRaw.html
float rawHorizontalAxis = Input.GetAxisRaw("Horizontal");
// https://docs.unity3d.com/2020.1/Documentation/ScriptReference/Vector3-zero.html
Vector3 direction = Vector3.zero;
direction.x = rawHorizontalAxis;
// https://docs.unity3d.com/2020.1/Documentation/ScriptReference/Time-deltaTime.html
float timeSinceLastFrame = Time.deltaTime;
Vector3 translation = direction * timeSinceLastFrame;
// https://docs.unity3d.com/2020.1/Documentation/ScriptReference/Transform.Translate.html
transform.Translate(
translation
);
}
}
Now you can control the player.
The problem is, it is a bit slow. To fix this, we are going to add one more value to our player logic. Edit the Player component code, add a speed
property to it, and include this value in the translation
calculus.
Player.cs
using UnityEngine;
public class Player : MonoBehaviour
{
private float speed = 2;
private void Update()
{
// ...
Vector3 translation = direction * speed * timeSinceLastFrame;
// ...
}
}
Note: Some code has been hidden under // ...
to show only applied changed.
Now the Player should move twice as fast if you try it. But there is one small problem here if we want to change our Player speed value we need to open its code and edit the value and then wait for Unity to recompile. Unity provides various ways to allow the exposure of properties in the editor so you can tweak as many values as you want without editing any code. You could set the property to be public
(which I don’t recommend to enforce code cleanliness), or you could add the SerializeField
attribute to the Player’s speed
property, we will do the second.
Player.cs
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField]
private float speed = 2;
// ...
}
Now, if you go to the Unity Editor and checkout the Player Component at the Inspector window, you’ll see that now the Component has a new input called Speed
.
Now the 2
we set for the speed
property will be a default value when the Component is added to a Game Object, and the final used value for the logic will be the one set at the editor. You can edit it even while playing to adjust it to your preferred value.
Note: Properties changed during Play mode will not be saved and will reset to its value before stating Play mode. More info in Unity’s Manual section “Game View“
Instantiate Game Objects
Time to make our Player shoot some bullets. Download this Bullet sprite:
And place it under /Assets/Bullet/
(new folder). Remember to edit the Sprite settings as we did with the Player and Enemy sprites in the previous tutorial. Then use it to create a new Game Object in the Scene called Bullet.
This Bullet Game Object will need custom logic to move and do stuff, so let’s create a new C# Script called Bullet and add its Component to the Bullet Game Object. Edit the file.
Bullet.cs
using UnityEngine;
public class Bullet : MonoBehaviour
{
[SerializeField]
private float speed = 5;
private void Update()
{
// https://docs.unity3d.com/2020.1/Documentation/ScriptReference/Vector3-up.html
Vector3 direction = Vector3.up;
// https://docs.unity3d.com/2020.1/Documentation/ScriptReference/Time-deltaTime.html
float timeSinceLastFrame = Time.deltaTime;
Vector3 translation = direction * speed * timeSinceLastFrame;
// https://docs.unity3d.com/2020.1/Documentation/ScriptReference/Transform.Translate.html
transform.Translate(
translation
);
}
}
We have added similar logic to our Bullet Game Object as we did to the player, but this time it only moves upwards and with a higher speed.
The problem now is that we only have one Bullet, and it appears and starts moving whenever we start playing. We need it only to appear when we are pressing the fire button. To achieve this, we will need to create a Prefab from our Bullet Game Object.
To create a Unity Prefab from an already existing Game Object, you need to drag and drop it to the Project window.
A Prefab is like a blueprint of a Game Object. It allows us to create multiple copies of the same Game Object without having them in the Scene. If you take a look at the Hierarchy window, you will see that the Bullet Game Object now has a different color, icon, and a little arrow to the right, this is the way Unity indicates if a Game Object in the Scene is related with a Prefab. Delete this Game Object from the Scene.
Check the Bullet Prefab properties within the Inspector window and ensure that it has Transform.position to x=0 y=0 z=0
and Bullet speed=0
. We need to update the Player’s logic to instantiate this Game Object whenever we press the “Fire1” button (which is mapped to left ctrl
, mouse 0
and joystick button 0
).
Note: Checkout Unity’s Manual section “Input Manager” to know more on how to configure input mappings.
Player.cs
using UnityEngine;
public class Player : MonoBehaviour
{
// ...
[SerializeField]
private GameObject bullet;
private void Update()
{
// ...
// https://docs.unity3d.com/ScriptReference/Input.GetButtonDown.html
if (Input.GetButtonDown("Fire1"))
{
Vector3 playerPosition = transform.position;
// https://docs.unity3d.com/2020.1/Documentation/ScriptReference/Quaternion-identity.html
Instantiate(bullet, playerPosition, Quaternion.identity);
}
}
}
Note: Some code has been hidden under // ...
to show only applied changed.
We have defined a new Player Component property called bullet
that will store the reference to the Bullet Prefab Game Object. Then we have updated the Update
with more code to check if any input mapped to the button “Fire1” has been pressed down during this frame, if it has, then the script will instantiate a new Bullet Game Object in the Scene at the Player’s position (with no rotation). Select the Player Game Object in the Scene and update its properties in the Inspector window dragging the Bullet prefab to its Bullet property in the Player Component.
Now you are ready to fire!!!
Conclusion
Summing Up we have:
- Add a new custom Player Component made with C# to our Player Game Object
- Implement moving mechanics to the Player and Bullet Game Objects
- Handle Player Inputs to move and shoot Bullets
You can get the code generated by following this tutorial in Genoma Invaders’ Github repository, branch tutorial/02
.
Remember to dig into documentation sites to have more context on what does what:
Happy Game Dev!
Leave a comment