Affiliate links on Android Authority may earn us a commission. Learn more.
How to create a simple 2D platformer for Android in Unity - Part two
In part one of how to create a simple 2D platformer for Android in Unity, we went over the basics of creating a 2D platformer in Unity for Android. In doing so, we created a very basic little ‘game’ (I use the term loosely) that allowed us to move a character left and right along a platform.
But the project has a little way to go before it can be considered fun, challenging or even worthwhile. So in this post, we’ll be looking at how to add elements like collectibles, hazards and multiple platforms and hopefully something wonderful will emerge…
Jumping
The first thing I want to do is give our man Rushdy the ability to jump. It’s not much of a platformer until we can do that…
So first I’m moving the right arrow closer to the left arrow and anchoring it to the bottom left instead of the bottom right. Then I’ll add a new button (just copy and paste one of the existing ones) and give it a new sprite. This button is called ‘jump’. Can you tell what it is yet?
Next up, open up your control script and create a public bool and a public float called jump and jumpheight respectively. Remember, you can set jumpheight from the inspector in Unity itself (I set it to 8 but you can play around and choose how high you want to jump yourself!). Next, add the following bit of code to the same script:
if (Input.GetKey(KeyCode.Space))
{
rb.velocity = new Vector2(rb.velocity.x, jumpheight);
}
if (jump)
{
rb.velocity = new Vector2(rb.velocity.x, jumpheight);
jump = false;
}
[aa_image src="https://www.androidauthority.com/wp-content/uploads/2016/05/Unity-2-2-840x560.png" alt="Unity 2 2" width="840" height="560" class="aligncenter wp-image-694441 size-large"]
This is going to give us the ability to jump by hitting space and we also have a pubic boolean we can control via our touch screen controls, just like before. We’re simply adding velocity to our rigidbody only this time it’s a little more and it’s affecting the y axis. Now just link the button to that boolean the way you did before by adding this to your ‘touch’ script:
public void Jump()
{
player.jump = true;
}
Then make sure your jump button has one event trigger, that being a pointer-down event that starts the ‘Jump’ function – you can check back over part one if you’ve forgotten how to do this. We don’t need anything for ‘jumpRelease’ because you don’t hold down the jump button!
Now I recommend we remove our touch-screen controls which are kind of in the way right now. You can test the game in Unity itself until it’s finished, so just make sure you remember to turn them back on before creating the APK. For now, switch them off by selecting the canvas in the Hierarchy window and then unticking the blue box in the inspector right at the top left. They’ll then be grayed out in the hierarchy and they’ll disappear from your Scene and Game views.
Grounding the player
At this point, you can hit play and test hitting space button to jump. There’s just one problem: you can jump infinitely! Hold down space or keep tapping the jump button and you can sore into the stratosphere… So we need a way to check if our player is on the ground and then only let him jump when he is on terra firma.
One way to do this is with ray casts. However, the easiest method for now is probably to just check whether the point beneath the player is ground or not. To do this, we’ll need to create a new ‘transform’ in our control script. A transform is simply a point in space with its own coordinates and rotation. We’ll call this groundCheck and add it the way we add any other variable. We’re also going to give that point a radius, we’re going to define a ‘layer mask’ (I’ll get to that) and we’re going to create a boolean called onGround.
To do this, just add the following to your script:
public Transform groundCheck;
public float groundCheckRadius;
public LayerMask whatIsGround;
private bool onGround;
You also need to add the following lines of code below:
void FixedUpdate()
{
onGround = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);
}
FixedUpdate works very similarly to Update except that Update is tied to the refresh rate of the screen, whereas FixedUpdate has a more predictable behavior that makes it better suited to physics-related code. The lines of code we added here simply set the boolean onGround to ‘true’ only when the new circle overlaps with the ‘ground’ layer. But of course we haven’t set the coordinates of the groundCheck transform yet, so to rectify that, go back to Unity and create an empty game object as a child of your player (right click on the player object in the hierarchy and select ‘Create Empty’). Call this Check Ground.
Now if you select your player, you’ll notice you can see that ‘Ground Check’ is currently set to ‘None (Transform)’. Simply drag Check Ground and drop it into that box.
You also need to make sure that you position your new empty object in the right place; so double click on Check Ground in the Hierarchy and then use the move tool to set it just below your player, still slightly overlapping.
You can fiddle with this later. Click on your player again and then be sure to set the radius value to 0.1.
Okay, we’re nearly there! All that’s left to do is to create your ‘ground’ layer and to do that you just need to select the platform game object and then find the drop down menu called ‘layers’.
Select ‘add layer’ and then enter ‘Ground’ into the first empty box.
Head back to your game object and click on the same menu and you should find that ‘Ground’ is now an option for you to select. You also need to view your player in the Inspector and choose the same layer for whatIsGround (remember, we can see public variables in Unity and set them this way). If you’ve done all this correctly, then you can hit play and you should find the player only jumps once. Win!
Creating platforms with prefabs and effectors
Your game is now functional enough to actually be fun! You’d just need to add a few more platforms for your own amusement and practice hopping from one to the next… You can just copy and paste your platforms and resize/position them as you please. However before you do that we need to talk about prefabs.
A prefab is what it sounds like: a ‘prefabricated’ asset that has multiple properties attached. If we create a prefab, this then allows us to make global changes by simply editing the properties of the prefab rather than each in-game object individually. To do this, simply create a new folder in assets called ‘Prefabs’ (original I know) and then drag your ground object from the Hierarchy and into that folder. Now you can drag and drop copies of your platform out of the folder in order to deploy your prefab as much as you like. Which means you can now design some platforms to jump on!
Here is an example of the power of prefabs. If you play the game you’ll find your character is prone to ‘sticking’ to the sides of walls in mid air which stops him from falling. This is due to the friction on the platform so we need to change that in the prefab and have it reflected on each of our platforms. Just select ground from that folder and then tick the box that says ‘used by effector’ in the Inspector. Then add the component ‘Platform Effector 2D’ which is found under ‘Physics 2D’. Now untick ‘use one way’ – unless you want your character to be able to jump through the floor from underneath. You’ll also notice another option ‘use side friction’ which should be unticked by default. Basically this ‘effector’ makes your platform behave like a platform. Once again, Unity is making things nice and simple for us. You’ll notice there are some other effectors here too which let you alter the behavior of your objects in various other ways.
Adding hazards
Nearly every platformer incorporates some type of enemy or hazard, whether that means spikes, enemies or gun turrets. Let’s start with spikes, which you can create by adding a new sprite to your game and then dropping that into your scene view as you have done with your platforms previously.
Now you’re going to add a collider (probably a polygon collider) but this time you’re going to tick the box that says ‘is trigger’. This means that it won’t act like a platform or a solid object but instead we’ll be able to define the behavior of the game object in our code.
To do this, you’re going to create a new C# script, this time called ‘Hazard’. Now add the following code to it:
public class Hazard : MonoBehaviour
{
private Controls player;
public Transform start;
void Start()
{
player = FindObjectOfType<Controls>();
}
void Update()
{
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
player.transform.position = start.position;
}
}
}
Of course OnTriggerEnter2D fires when something touches the collider. We’re then checking that this is the player (you’ll need to go to your inspector and change the tag for your player to ‘Player’) and if it is, we’re moving them to a new transform. Now don’t forget to add the script to your spikes by selecting ‘Add Component > Scripts > Hazard’. We also need to create a new empty game object called Start which we can use for our new transform. Place this in your scene where you want the player to start each time. Now add your spikes to the prefab and dot them around as you please! (If you find that it looks a bit ugly, you might want to alter the ‘order in layer’ for your prefabs. You want your player to appear behind the spikes and the spikes to be behind the ground.)
You can actually add multiple scripts to an object, which means we can make a simple bad guy.
Just create a new script called ObjectMove and then use this code:
using UnityEngine;
using System.Collections;
public class ObjectMove : MonoBehaviour
{
public float amounttomovex;
public float speed;
private float currentposx;
private float currentposy;
private int facing;
void Start()
{
currentposx = gameObject.transform.position.x;
facing = 0;
}
void Update()
{
if (facing == 1 && gameObject.transform.position.x < currentposx - amounttomovex)
{
facing = 0;
}
if (facing == 0 && gameObject.transform.position.x > currentposx)
{
facing = 1;
}
if (facing == 0)
{
transform.Translate(Vector2.right * speed * Time.deltaTime);
}
else if (facing == 1)
{
transform.Translate(-Vector2.right * speed * Time.deltaTime);
}
}
}
This script lets you choose the speed and distance you want your enemy to move at in the inspector. So add that and the Hazard script to your enemy and he’ll behave like your typical computer game bad guy. Oh and while we’re at it, let’s solve another little issue that may have been bugging you by preventing the player from falling for infinity. To do this, all we now need to do is to create a wide empty object and make it a hazard that will kill our player! Just copy and paste a platform, remove the sprite, drag it wider, tick ‘is trigger’, add your ‘hazard’ script and call it ‘bounds’.
Now our game is starting to look a lot more like an actual platformer! I’ve also added a secondary type of bad guy who doesn’t kill us (there’s no hazard script) but can push us off of platforms (because he has a regular circle collider). The good news – we can also jump off of his head. This means we can create our first puzzle! Remember to make this bad guy ‘ground’ layer.
Adding gore
Right now Rushdy’s death isn’t particularly spectacular. Rushdy just kind of disappears and then appears elsewhere… not cool! What we need is to add an over-the-top death sequence. To do that we’re going to use particle effects, which allow us to blast out pixels in every which way.
Head over to ‘Game Object > Particle System’ to create one and you’ll start to see tiny dots being emitted by said system. It’s basically like a little fountain that endlessly spits stuff. Double click on it in the Hierarchy and you’ll find you’re now able to change all kinds of aspects such as the shape of your particles, whether or not it is looping, the size of the particles over their lifetime, the ‘rate’ that the particles are created, the color and more. Play with these settings and create something that lasts .30 seconds and doesn’t loop. It should probably also be red and you should choose ‘Default Sprite’ under renderer rather than ‘Default Particle’.
You also need to create another new script which is going to destroy the particle system when it’s finished. Otherwise, Unity will create new game objects every time we die without cleaning them up and it will take up a lot of system resources. Create a new script and call it ‘DestroyParticle’. Now add this code:
using UnityEngine;
using System.Collections;
public class DestroyParticle : MonoBehaviour
{
private ParticleSystem thisParticleSystem;
void Start()
{
thisParticleSystem = GetComponent<ParticleSystem>();
}
void Update()
{
if (thisParticleSystem.isPlaying)
{
return;
}
Destroy(gameObject);
}
}
Don’t forget to add the script to the particle effect object. Name it ‘blood’ and put it in your prefabs, deleting the existing copy from your Hierarchy.
Now add this code to your ‘Hazard’ script in the onTriggerEnter before you move the player:
Instantiate(Explode, player.transform.position, player.transform.rotation);
‘Instantiate’ simply means ‘create’ and you’ll use this for lots of other things too, such as spawning bad guys. You also need to create a public game object called Explode and hopefully at this point you know you’re going to need to drag that game object onto the script for each of your hazards (don’t forget your bad guys and your bounds!). I also created a new folder called ‘Audio’ and added an explosion sound effect which I also added to the particle system in the prefab. That way, as long as ‘Play On Awake’ is ticked, the sound will play each time the particle effect gets created!
For those of you who are getting a bit overly perfectionist about all this (like me…), you can swap out your death code for this to polish it up a little:
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
StartCoroutine("respawndelay");
}
}
public IEnumerator respawndelay()
{
Instantiate(Explode, player.transform.position, player.transform.rotation);
player.enabled = false;
player.GetComponent<Rigidbody2D>().velocity = Vector3.zero;
player.GetComponent<Renderer>().enabled = false;
yield return new WaitForSeconds(1);
player.transform.position = start.position;
player.GetComponent<Renderer>().enabled = true;
player.enabled = true;
}
What this code is doing is to move our death animation into a coroutine, which allows us to include a ‘wait’. This is a function that runs in the background and by pausing, we can put a beat in between the death and the respawn. I’ve also added some changes around that to make the player disappear and become unresponsive before going back to normal ready to play again. Lastly. I removed all momentum so it wouldn’t carry over when the player comes back. All this is optional but if you’re playing along you can lift it to add to your own code. And well, why not?
Coming next…
So at this point you know enough to start playing around and making something fun… or horribly punishing it’s up to you. I tend toward the latter. Remember to switch your touch controls back on before you test it on your Android device. I’ve also changed a couple of things behind the scenes: I made the stars pixelated to match the aesthetic of the other sprites, I zoomed the camera out slightly (I set ‘Field of View’ to 70 in the Inspector) and I pasted my background around a little so we wouldn’t run out of stars. I also changed the jumpheight to 8.5. At this point though, you’re free to play around with these sorts of elements and set them however you like.
There’s still a little more to do here though, which is why there will be one more post on this subject to add collectibles, levels and some more sound effects. Stay tuned for that next time and check out all the code and assets on GitHub here. There’s also an APK there again for you to play around with. See if you can spot the additional feature I’ve added. It’s painfully obvious…