Creating 2D platformer game in Unity3D
Hello! My name is Wojciech Bilicki and I am frontend developer in OKE Software. I specialize in ReactJS and web development. Last year I picked up a new hobby: game development. I fell in love with Unity3d. Currently I am hosting a workshop where I teach people how to write games in C# using Unity3D. Therefore I decided to write and article showing you how can you start with your own 2D platformer game in Unity :).
First off you need to have Unity3D and IDE of your choice installed. Go to: https://unity3d.com/get-unity/download and click Download Unity Hub
.
Once that’s done. You need to use Unity Hub to download Unity Editor itself:
When choosing the Unity version to install I would stick with LTS (Long Term Support) for now.
After the installation we can finally start working on our platformer game. One thing that we’ll definitely need will be some 2D assets to build our world. You can find many free assets pack on the internet. Good places to search are for example:
https://www.spriters-resource.com/
Yet definitely the best place to look for assets when it comes to Unity is:
So go ahead and create your account there:
You can use the same account inside Unity Hub:
Going back to Unity Asset Store you can choose 2D
and then on the left side filter by the pricing. Select Free Assets
and you should see Free Platform Game Assets
Next step is to actually adding selected assets to your asset library:
Now we should be set up to actually start working on our platformer game. So go ahead and start new Unity project with 2d preset.
First thing we have to do is to actually import the Free Platform Game Assets
. So in the top tool bar go to:
Window -> Package Manager
from there look to the left upper corner and you’ll find a drop down:
Click on it and choose My Assets
. If you did not sign in previously (in Unity Hub) you’re gonna be asked to do it right now. After that you should see a list of all of your assets from Asset Sto re ready to import into project. You should see Free Platform Game Assets
your assets list:
Click Download
and once it’s done Import
.
In your Project
window you should see new folder with imported assets. The folder will be named Bayat Games
and will contain all assets from the package:
To keep our project organized we will create separate folder in which we’ll hold stuff related to our game. I named it PlatformerGame
.
That is the end of our setup. We can finally start adding elements to our scene. We’ll need to things player character that we can control and a floor for him to walk on. Let’s start with the floor.
In platformer games it is common to build the environment using tiles. You can think of them as reusable blocks that player can interact and collide with. If you’ll think of Mario game you can see that whole world is built from these reusable blocks:
We definitely want to do the same. In your project window if you’ll go to:
BayatGames -> Free Platform Game Assets -> Tiles -> Spring -> 256x256
you’ll find a tileset we’ll use to create our world.
Now we make sure that our tiles are properly configured before we start using them in our scene. So Shift-Click all the tiles in the 256x256
folder and you should see the inspector panel pop up on the right side of the editor. First thing we need to do is to adjust the size of our tiles. We already now that their dimensions are 256px for both width and height. Make sure that Pixels Per Unit
value in the inspector is set to that value exactly:
Remember to hit Apply
after you adjust settings.
I copied all the sprites to PlatformerGame -> Tiles
folder just to keep things clean.
Form there we can go to our Hierarchy
window and create in our scene. So right click in the Hierarchy
and choose 2D Object -> Tilemap -> Rectangular
. That’s going to create a grid game object with tilemap as its child. Grid game object divides the scene into blocks of given size. The size can be changed by the use of inspector:
The tilemap is the concrete graphical representation of blocks seen in the scene. To actually start painting the tilemap and adding blocks to the scene we need to use Tile Palette
window. So go to the Window -> 2D -> Tile Palette
. It will probably popup as a new window in the center of your screen so reasonable thing to do is to grab it and dock it next to your inspector tab on the right:
Click Create New Palette
and then drag all the tile sprites into the Tile Palette window. You will be asked to select folder in which you’d like the tile palette to be.
You’d probably like to rename it from New Palette
. You can do it in hierarchy or project panel.
If you click on the palette in the hierarchy and press F2 it will allow you to rename it and also the popup should show whether to rename the file.
Important thing to note that now the editor is working in the tile palette context so you don’t see the full hierarchy of your scene. You can always go back to the full context by clicking the back arrow in the hierarchy (marked red in screenshot above).
Go back to the full hierarchy by clicking the arrow and select the Grid
from the hierarchy. Then from Tile Palette
select the paint brush tool and select the tile you’d like to paint. Now you can finally paint the tile into the scene.
You should end up with simple floor painted into the scene similar to this:
Next thing we can do is actually to add our player to the screen. To do that we have to prepare some kind of player 2d sprite representing our player. If you’ll go to the Project
window at the bottom and go to BayatGames -> Free Platform Game Assets -> Character -> Character Animations
you’ll find the folders showing possible states for our player: Idle, Jump, Run
. The problem is that we need to prepare them a bit for use in Unity.
Let’s start with Idle
animation. In the Idle
folder click 2x
. This should show the Inspector on the right for the Texture 2D we selected. What we’re actually working with here is called sprite atlas. This is the texture where different images are jammed together in one image. It is done for efficiency and optimization (it’s alway faster to load only one image instead of many into the memory).
We need to adjust the import settings for the texture atlas as we’d like to use it for animation (or if we’d like to use just one tile of given atlas). First thing that we need to do is to inform the Unity that we’re working with multiple sprites in sprites atlas:
This will enable us to use Sprite Editor
and cut the atlas into pieces:
In Sprite Editor
simply click Slice
make sure that Type
is set to Automatic
and Pivot
is set to Center
and press Slice
again. That’s gonna allow us to work separately with each sprite in the atlas. To keep things neat I’m gonna move the sprite atlas from the Bayat Games
location into the Platformer Games -> Player Sprites
. In this location I’m going to keep all sprites atlases that I’ll splice.
With that we can finally create our player. Let’s go to hierarchy and add two new objects:
We create Player
and Spirtes
as a child of Player
. This will allow us to keep the physics of the player and its representation separated.
So in Sprites
object add Sprite Renderer
component and we can choose 2x_0
sprite just to see our player on the screen. You should see something like this in your scene:
If you run your game right now you’ll see that nothing actually happens. What we actually need to do is to add rigid body and collider to our player and floor.
Let’s start with our player. One thing to note is we’ll be adding our rigid body and box collider to the Player game object and not it’s sprite child:
We will be using Box Collider 2D
as collider and Rigidbody 2D
as rigid body. The default settings for Box Collider 2D
are fine so we don’t need to change anything there.
Fortunately the same goes for Rigidbody 2D
for our case use of Dynamic
body type is fine since we’ll be moving our character using physics by applying forces and modifying velocity.
Now let’s take a look at our Grid -> Tilemap
add we need add two colliders two it . First is going to be the Tilemap Collider 2D
. If we take a closer look we’ll see that the collider is added to every single tile of our tilemap:
This isn’t the best way to handle collider. Calculation for colliders tend to be resource heavy and as your level will grow so also the computational requirements. Fortunately there’s a way to optimize it.
We can add Composite Collider 2D
which will merge the colliders in the continuous tiles into one. This will dramatically decrease amount of collider objects in the scene. This will also automatically add Rigidbody 2D
to our Tilemap
. That’s because Composite Collider 2d
needs it to work.
If you play your game right now you’ll see that our floor falls to the ground. This is because Rigidbody 2D
has its Body type
by default set to Dynamic
. Whenever we deal with stuff like floors or walls or other obstructions we should set the Body type
to static since we don’t expect it to move.
To make our Composite Collider 2D
work we also must tell our Tilemap Collider 2D
to actually allow Composite Collider
to merge it. You can find option Used by composite
on Tilemap Collider 2D
. So finally our options for our Tilemap
object should be:
Next thing that we need to set up is how our game uses user input. We could read the input directly into code using Input
class but this approach is rather rigid. What we’ll use is Input System
the special additional package that allow is easily configure how we translate user inputs into functional calls in our code.
In the project window use right-click and choose Create -> Input Actions
and name it Platformer.
This is what you’ll see if you click to open it:
This is the reasonable defaults provided by Unity. We have different set of maps actions maps we are like super sets of actions (for example for player in game and for UI controls).
Then for each super set we can define actions groups that allow to perform actions for different type of inputs (i.e. keyboard and gamepad both can trigger action fire weapon action). Then pressing onto each action definition for given input we can define which button triggers the action.
Let’s start working on that. Press on +
next to Action Maps
:
Let’s name that Player
and then let’s name our Action
Move
.
Then click +
next to Move
and choose Positive/Negative binding
. We will use this binding to define horizontal movement of our player. Name that binding Horizontal Movement
and then we can finally add the keys on which we’d like to listen.
So select the Negative
binding. Next click on path
. After that you can find the A
key in keyboard section or you can just click on Listen
and then press A
.Set the Positive
value for D
key,
Now we must add those Input actions
to the object that we’d like to control. Select our Player
and add Player Input
component to it. We need to provide Platformer Input actions
as Actions
to it.
Ok finally we can start coding. Let’s create Scripts -> Movement
C# script where we’ll add possibility to move for our player.
We will start by defining some class variables that we’ll use in our class and we’ll get reference to Rigidbody 2D
:
Next let’s create a function that we’ll be called by our Input System
public void OnMove(InputAction.CallbackContext ctx)
{
}
The function has to be public so that can be called from Unity. It also has to correctly defined arguments so that we can use it with Input System
. After we have that definition in place we can plug it into the Input System
.
Go to Input Actions
component of our Player
and unfold Events
and Player
at the bottom. Then drag Player
into the Move (Callback Context)
and then select On Move
function from it on the right side.
Now we should read the velocity value in OnMove
function and store it. We will also apply this velocity to our RigidBody
each frame in Update
function:
This actually makes our player move across the screen. Unfortunately this does not look to good as we’re not animating our movement yet. Let’s figure that out now. First let’s start by creating Animations
folder in our Project
. We’ll need to create both Idle
and Move
animations.
To do so we need to slice that Run
and Idle
sprites in Bayat Games -> Free Platform Game Assets -> Character -> Character Animations
. Make sure to set the Sprite Mode
to Multiple
and use Sprite Editor
to slice the sprite into frames. My suggestions is also to copy Move
and Idle
sprites to Platformer Game -> Player Sprites
.
Easiest way to change them into animations is to simply drag them into the scene. This will show you a file explorer window where you can set the location where to save the animations. It will automatically create .anim
file that we can use to play animations.
So drag both sprites into the scene and save the files into Animations
folder with Idle
and Run
animations.
To play and control our animations we need Animations Controller
. Let’s create one in Animations
folder and name it Player
:
Next in our hierarchy select Player -> Sprites
and add Animator
component and set Controller
to Player
. If you double click on Player
animation controller it should open the Window
. It works using state machine pattern.
Meaning we will be changing the state of our character animation. Whenever the player is moving we will change the state to Run
and when he’s not we’re going to move to Idle
. What we can do is drag our animations into the Animator
window.
Next right click on the Idle
animation and select Make Transition
and connect the output to Run
animation. We also need to create the transition from Run
to Idle
. We should end up with something like this:
After that we can switch to Parameters
tab. Here we can set up some parameters for our state machine that will drive the transitions between our state. So let’s click +
and choose Bool
parameter and name it IsRunning
.
Next click on the arrow that is transitioning from Idle
to Run
. We need to uncheck Has Exit Time
checkbox and set the Transition Duration
to 0. We also need to add transition condition so let’s click +
next to conditions
tab. It will automatically populate with the parameter we have created:
We need to configure the transition back with the same settings. Only difference of course is that IsRunning
parameter is going to be set to false
.
Ok the last thing is to trigger our transitions with code. Let’s start by grabbing the reference to the Animator
in our Movement
class.
[SerializeField] private Animator animator;
Since we serialize it we can pass it via Unity Editor
we can get it from the Sprites
child object:
The other option would be to use GetComponentInChildren
function in Awake
callback in our Movement
class.
Now we can finally trigger our transition using code. What we’ll do is check for the value of _currentVelocity
to trigger the parameter. We can improve our code by caching our parameter value first with:
static readonly int IsRunning = Animator.StringToHash("IsRunning");
Added at the top of our Movement
class. With that we need to add some if
checks to OnMove
function:
This will make our animation works. Well, almost… it works if we move our character to the right. Unfortunately if we move to the left he is still looking right. We can fix it by switching the localScale.x
value to make our character turn the other way.
We just need to check whether our currentVelocity
is greater than zero and reassuring the transform value.
That should make our character animate properly.
This concludes the first part of creating 2d platformer game in Unity3D engine. I hope you enjoyed article and stay tuner for more :).
— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —
Would you like to join our team? See our open positions here:
https://oke.pl/career/#current-job-offers