How to Create a 2D Game in Unity
To create 2D games, we need to use Unity Hub. Unity Hub is a standalone management application that enables you to download, install, and manage multiple Unity Editor versions. In Unity Hub, choose your version of Unity and select a 2D template project. Give it a name and choose a location for your files. Click “Create,” and Unity Editor will open.
Organization and planning
Making a game can be time-consuming, so make sure you make the most of your time by creating a roadmap and planning your steps. Also, it’s good to know something about game design when working on ideas, so take the time to view some tutorials and general information about game design before you start creating your own game.
As your project gets bigger and more complex, getting lost is easier lost. You’ll need to keep an eye on the organization of your assets (sprites, scripts, prefabs, audio clips, and so forth). To organize the project, let’s create folders for assets. In the Project window, Right click>Create>Folder. To start, we need one folder called “Scripts” and another called “Sprites.”
Sprite creator and scene setup
Unity has a built-in sprite creator so we can create simple geometric shapes for our game objects in a few clicks. Usually, we use those sprites as placeholders. Placeholders are dummy sprites that we will replace with real sprites later. By doing things this way, we don’t need to wait for an artist to finish sprites, and that speeds up the project.
Let’s start by creating a square and circle. In the Project window, open the folder “Sprites,” Right-click>Create>2D>Sprites. Drag and drop the created square sprite into the Scene view. This will create the GameObject that you can see in the Hierarchy window. Details about the GameObject are in the Inspector window. Also, here we can rename the object to “Player.”
Add another square to the scene. In the Inspector, we can use the Transform component to change the position, rotation, and scale of the object. Decrease the scale on the X- and Y-axis to 0.3 and change the color to green using Sprite Renderer. Sprite Renderer is a component responsible for the visual presentation of a game object.
Place the square on the right edge of the Player sprite. We need to make it a child object of the Player so it follows the Player’s position and rotation. In the Hierarchy, select the green object and drag and drop it on the Player. Now the Player is considered a parent object.
Make sure that a child game object is rendered in front of the Player by changing the sorting layer order to 1.
The next step is to add another square GameObject called “Ground” to the scene. Change the color to grey and move the Ground below the Player. Then increase the X scale to get a nice long line. Also, we can select the Main Camera and change the background color. You can see the final result.
Collision and Rigidbody 2D
If we press the Play button, nothing will happen. There is no collision, gravity, or other Physics forces. That’s why we need to add colliders and the Rigidbody2D component to objects. To do so, follow these steps:
- Select the Player. In the Inspector, click on Add Component and find Rigidbody2D. The Rigidbody2D component will put the Player under the influence of the Unity Physics Engine and forces like gravity.
- Next, add BoxCollider2D to the Player and Ground. A box collider enables collisions between objects. If we press the play button now, Player and Ground will collide. In other words, Player will stand on the Ground.
Package Manager and Input
To receive input and control the Player, we will use the new input system and do the following:
- First, open the Package Manager (Window>Package Manager).
- In the upper left corner, set Packages to “Unity Registry.” That will open a list of all available packages, which includes the Input System package.
- Find the Input System and click “Install.”
Let’s create the first script in the folder Scripts (Right click>Create>C# Script). Name it “PlayerControls.” Select the Player and use the Add Component button to add the script, or just drag and drop it on the Player from the “Scripts” folder. It’s important to add the script to the game object. Double click to open it in Visual Studio.
using UnityEngine;
using UnityEngine.InputSystem; // InputSystem namespace
public class PlayerControls : MonoBehaviour
{
// call function Flip every frame in Update
private void Update()
{
Flip();
}
// flip the player using the left or right arrow key
void Flip()
{
if (Keyboard.current.leftArrowKey.wasPressedThisFrame )
{
transform.rotation = Quaternion.Euler(0, 180, 0);
}
if (Keyboard.current.rightArrowKey.wasPressedThisFrame)
{
transform.rotation = Quaternion.Euler(0, 0, 0);
}
}
}
In the script, we’ll include the Input System namespace to get access to some input functions and properties. Then we’ll make the Player rotate/flip by pressing the left or right arrow keys on the keyboard. It’s important to call the function “Flip” in the Update.
Enemies and Spawner
Let’s use another square sprite to create an enemy object. Change the color to red, add Rigidbody2D, BoxCollider2D, and the script “Enemy.”
using UnityEngine;
public class Enemy : MonoBehaviour
{
public float health;
public float speed;
private Rigidbody2D rb;
public void TakeDamage(float damage)
{
health -= damage;
if (health <= 0)
{
Destroy(gameObject);
}
}
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
rb.velocity = new Vector2(speed, rb.velocity.y);
}
}
We move the enemy in Fixed Update using Rigidbody2D. It’s important to move the enemy in Fixed Update to have smooth and frame-rate independent movement. Remember, all movements with the Rigidbody component should be done in Fixed Update.
There is also the “TakeDamage” function that we can use later for damaging the enemy.
Drag the Enemy object from the Hierarchy to the Project window to create a Prefab. Prefab is like a copy of an object that we can spawn in the game. You can delete the enemy in the scene.
To create a spawner, right-click on the Hierarchy and create an Empty Object. Create and add the script “Spawner.”
using UnityEngine;
public class Spawner : MonoBehaviour
{
private float timer;
[SerializeField]
private GameObject enemyPrefab;
[SerializeField]
private Transform[] spawnPoint;
private int i;
void Start()
{
timer = Time.time + 1;
}
void Update()
{
if (timer < Time.time)
{
// choose random number “i” (0 or 1) for shooting point
i = Random.Range(0, 2);
// instantiate enemy prefab on spawn point position with index i
GameObject enemyObject = Instantiate(enemyPrefab, spawnPoint[i].position, Quaternion.identity);
// if “i” is equal to 1 (which is the index of our right spawn point) multiply
// speed with -1 so that enemy goes to the left
if (i == 1)
{
Enemy enemy = enemyObject.GetComponent<Enemy>();
enemy.speed *= -1;
}
timer = Time.time + 0.8f; //spawn delay
}
}
}
As you can see, the spawner has a timer, array of spawn points, and a reference to the Enemy prefab. We spawn enemy prefabs with the Instantiate function. Then we multiply the speed with -1 depending on the spawn point. The enemy will move left or right.
From the Project window, drag and drop the Enemy prefab into the Spawner script.
Create two more Empty Objects that we use as spawn points. Drag and drop them into the array field in the Spawner script.
Shooting
To shoot, we need four things:
- Shooting Point from which we shoot
- Bullet Prefab
- Bullet Script to define its behavior
- Shooting script to receive player input
For the shooting point, create one Empty Object that will be a child object of the Player.
Next, we need to make a prefab projectile. Use the circle sprite to create a GameObject. Change the color to green and the scale to 0.2 on the X and Y-axis. Add the Rigidbody2D component, change gravity to zero, add CircleCollider2D, and enable the “Is Trigger” option.
Next, add the “Bullet” script to the bullet prefab.
using UnityEngine;
public class Bullet : MonoBehaviour
{
public float speed;
public float damage;
private Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
rb.velocity = transform.right * speed;
}
private void OnTriggerEnter2D(Collider2D collision)
{
Enemy enemy = collision.GetComponent<Enemy>();
if (enemy != null)
{
enemy.TakeDamage(damage);
}
Destroy(gameObject);
}
}
In the function OnTriggerEnter2D we can check if the bullet hit the enemy, then damaged him and destroyed the bullet.
Now we need to add the Shooting script to the Player.
using UnityEngine;
using UnityEngine.InputSystem;
public class Shooting : MonoBehaviour
{
public Transform shootingPoint;
public GameObject bulletPrefab;
void Update()
{
if (Keyboard.current.spaceKey.wasPressedThisFrame)
{
Instantiate(bulletPrefab, shootingPoint.position, transform.rotation);
}
}
}
As you can see, we Instantiate the bullet prefab on the shooting point position. Don’t forget to assign them in the Inspector window.
End game and restart
Let’s end and restart the game when an enemy touches the Player. Create and add the script “GameControl” to the Player.
using UnityEngine;
using UnityEngine.SceneManagement; // namespace
using UnityEngine.InputSystem; //namespace
public class GameControl : MonoBehaviour
{
private void OnCollisionEnter2D(Collision2D collision)
{
// check if the player collided with an enemy
if (collision.gameObject.GetComponent<Enemy>() != null)
{
// restart level
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
private void Update()
{
// press ESC to exit the game
if (Keyboard.current.escapeKey.wasPressedThisFrame)
Application.Quit();
}
}
Notice that we use the two namespaces: “SceneManagement” and “InputSystem.” “SceneManagement” gives us access to the “SceneManager” class that is responsible for loading levels and restarting. Next, we’ll exit the game by pressing the escape key.
Build/make a game
In order to finish the game, we need to build it. Go to File>Build Settings, and a new window will pop out.
Now we can choose our target platform. In this case, it’s Windows with 64-bit architecture. Of course, you can choose any other available platform. Click on the “Build” button and wait for Unity to finish the task.