Tutorial : Platform game physics in Unity – part 1

Hi folks.

I’ve written my share of platform game engines, both in Flash and Unity. So I know a little something about how it works. I recently started writing a new engine, improving on the techniques that I previously used. And I figured I’d share the info with you guys.

Here’s what we will be creating :

 

Use the arrow keys to control the character. You can walk, jump and double-jump. I might be adding other features like floating, wall jumping etc later.

Instead of just giving you a complete working solution, I’ll give you bits and pieces on how it all works. It’s better for you to understand how it all fits together. At the end of the series, I will post full source code.

Note : I use Unity, but the same concepts probably apply to other game engines.

It is perfectly possible to make a platformer with Unity’s built-in physics, but in my experience, it causes a lot of headaches, which is why I prefer rolling my own solution. I do all my code in Update / LateUpdate instead of FixedUpdate, but I achieve framerate independency in other ways.

BaseClass

In most of my projects, I have a BaseClass which caches certain references the first time they are requested, for performance reasons. For instance, calling this.transform is a bit slow (or at least it used to be – things might have changed). This is my BaseClass – it’s off course possible to add other cached references to it.

So instead of calling this.transform, you now call this.tc, which will cache the reference to the transform so it doesn’t have to be done every time you need it. Fyi, tc is short for “transform cache” – I made it very short because I’m lazy.

Time-independent movement

First, let me explain something that’s quite basic. Most of you will already know and understand this, but I’ll explain it anyway.

The main idea of time-independency is that your game plays the same at – for instance – 30fps as it would at 60fps. For most cases, what you do is you multiply your values by Time.deltaTime. For instance, let’s say we want a character to move 100 units in a second. This can be achieved like this :

Simple enough. Time.deltaTime is the length in seconds of the previous frame. At a framerate of 60fps, it will be roughly 0.0166666f, so each frame it will move 1.666666f. Doing that above 60 times, will move the object 100 units.

However, I like to add some limitations to this. There are cases when a device lags for a while (for instance, on iOS it can happen when GameCenter is starting up), in which cases Time.deltaTime will be quite big, and it may not be desirable to move things that much in one frame. That’s an easy fix – let’s make 15fps the lowest acceptable framerate (any lower and the game will slow down too) :

If instead of saying “I want my character to move 100 units every frame” you’d rather say “I want my character to move 100 units every frame when it’s 60fps”, you can achieve that like this :

The reason I add this is because the next section will have some code that uses this “fs” (frameSpeed) variable.

Note : moving a character in this way will feel very rigid. We’ll talk about smooth horizontal movement in a future instalment, the code above was just to demonstrate how to achieve time independency in its simplest form.

 

Time-independent jumping

This all works quite well with linear movements. But what about jumping? When a character jumps, not only does his position change, but his velocity changes too. At first he’s going up fast, but that speed decreases, and after a while he will be going in the opposite direction. We still want this to work perfectly regardless of framerate.

How do we achieve that? Well, I have a magical formula for that. Years ago, when I was still dabbling in Blitz3D, I was trying to figure out how to do this, but couldn’t find any information on the subject. So I opened up an excel sheet and started experimenting with numbers until I found the correct formula. Now I’m not saying I’m the first person to figure this out (most likely I’m not). What I am saying is that I no longer really understand how the formula works. I’ve used it countless times, and it works perfectly, but I no longer know why it works.

I’m not claiming that this code is physically accurate. But platform games don’t need to be – if you want physical accuracy, you might be better off using Unity’s built-in physics engine(s).

The code uses these variables :

ySpeed is the speed at which the character currently moves, gravity is the speed at which ySpeed decreases, and terminalVelocity is the maximum speed the character can have when going down.

And here’s the formula that does the magic :

The first two lines are fairly straightforward. Decrease the vertical speed using the gravity, and make sure the character isn’t moving downwards too quickly.

The last line is a bit more complex. As I said before, I don’t really understand the math behind it anymore, but I do know that it does what it needs to do – the character will jump just as high at 60fps as it would at 30fps (or any fps) – give or take some floating point inaccuracies.

And in order to make the character actually jump – just do this :

Now, if you add all that code to a component and add it to a GameObject, you will probably just see that GameObject fall down. There’s no code to make the character land on a floor, no code to check if the character is grounded, etc. We will be doing that later.

Slower characters

One advantage of this time independency is that we could also create characters that move slower (or faster) but that can still jump exactly as high. So it would be possible to create two characters that feel differently, but who can still make all the jumps in the level.

Here’s an example of the character at half speed :

This is achieved by multiplying our dt variable by 0.5f. The same technique could be used for bullet time or other effects.

 

That’s it for now.

Part 2 will go into using RayCasts to detect collisions and reacting to them.

 

1-Bit Hero

Retro junkies, platform fanatics and game enthusiasts in general, rejoice!

In 1-Bit Hero, you take the role of an unnamed hero who can’t stand still. Featuring unique gameplay mechanics and graphics that are about as retro as it gets.

Warning : this game is difficult, and could cause seizures.

 

Out on Android – get it here : https://play.google.com/store/apps/details?id=com.mudloop.onebithero
Coming soon to iOS!

 

Bye Bye Kitty

Yikes! The neighbourhood has gone to hell. Literally.

Demons, sewer creepers, robots, giant spiders and other minions of evil have emerged from the depths of hell, and have taken over the streets that were once the home of Peanut the cat. Luckily he has his trusty skateboard to aid him in escaping this apocalyptic nightmare.

Out on Android – get it here : https://play.google.com/store/apps/details?id=com.mudloop.byebyekitty
Coming soon to iOS!

 

Coming soon : 1-Bit Hero

1-Bit Hero is a platform game with retro graphics. Very. Retro. Graphics. The game is pretty difficult, but that also makes it very rewarding. Almost done, should be released soon.

screen1 screen2

 

Physics outside of FixedUpdate

Unity’s physics are great. We get to chose between Physx (for 3D) and Box2D (for 2D), and they are integrated quite well.

However, real-world physics are not always what you want for games. For instance, making a platform game with Unity’s physics can be quite a challenge (but not impossible off course). You’ll most likely run into problems when dealing with slopes and moving platforms, among other things. Maybe even objects falling through other objects.

Here’s a good article on the subject : http://www.learn-cocos2d.com/2013/08/physics-engine-platformer-terrible-idea/

Another problem you may run into is if you manually want to move an interpolated rigidbody around. In a game I did for a client some years ago (which is no longer available), the character needed to walk and jump around a tube (think old school Nebulus). I tried with constraints and joints, but it never worked right, so I had to move the character manually.
The problem with this is that if you do it in the FixedUpdate cycle, the interpolation will stop working, which can cause camera jitter. And the docs say “you have to do physics stuff during FixedUpdate”…

I’d like to bust that myth, that you should put all your physics code in FixedUpdate, and not in Update. Sure, that’s the best idea if you want physical reactions and forces, otherwise you’ll run into a lot of problems. But if you want to use the physics engine for just collision detection, that’s fine. So it’s perfectly safe to move your objects around in Update (make sure you make your code time-independent though), and use RayCasts (or even OnTriggerEnter) etc to detect collisions. I do it all the time, and so far haven’t run into any problems with it. Often it’s a far easier solution than trying to make it work with the physics engine(s).

BTW, I’ve so far made two platform game engines in Unity, and will be sharing my knowledge on the subject in future posts.

 

Creating resolution-independent 2D games

Creating a 2D game or UI that works across multiple devices can be a bit tricky. There are many approaches to this problem. I have a pretty neat one for y’all. It’s quite flexible and is pretty much a drop-in solution. But first, let me give a bit of background information. The solution only takes about a minute to set up, but I want to make sure you understand how to set it up.

Note : This article talks a lot about mobile, but the solution works for other platforms too.

Note 2 : This is focused on Unity. The same principles could be useful to other environments, but the code will obviously need to be changed.

As many of you probably already know – and if you don’t, hey, you’re already learning! – in Unity, to get a one pixel to one unit mapping, you set the camera to orthographic and set the orthographic size to half the screen’s height. Basically the orthographic size setting is how much of the scene your camera will show (divided by two – not sure why).

Back in the good old days, there was only one mobile device that mattered. Well, multiple devices, but only one screen size : 480×320 (or 320×480 off course). So to set things up so that one unit meant one pixel, you set the orthographic size to 160 or 240. Or, you could be a little smarter about it, and you could set it to Screen.height / 2. Off course not everybody wanted a 1 unit to 1 pixel mapping, you could divide / multiply that number any way you wanted, but let’s just stick with that for simplicity’s sake.

But as it turned out, that wasn’t so smart at all. What happened? iPads happened. Retina displays happened. Let’s just take a retina display iPhone screen as an example. If you set the orthographic size to half the screen size – ie in this case 320 or 480, one Unity unit now became a very small retina pixel on the screen, and the camera was now displaying a lot more of the game scene. You actually wanted the same orthographic size as the non-retina screens. So what I used to do – and I’m willing to bet a lot of other people as well – is hack in some conditions. If the screen is larger than a certain size, instead of dividing the screen height by 2, you divide it by 4. But off course, you had to take iPad retina into account as well. Blimey.

Well, that was not too bad actually, quite manageable. But then there’s also Android with it’s plethora of screen sizes. And now there’s an iPhone 6 and an iPhone6+ too. Needless to say, this solution doesn’t really cut it.

So what now?

Before I go into my solution, let me say that in many cases, you could just have a static orthosize. This would mean that the same amount of units are drawn vertically on any screen, and the horizontal part will vary. But sometimes you may wish to “lock” it in the horizontal direction, and let it vary vertically. Luckily all you need for this is some basic math. But what if you don’t want your graphics to be scaled too much? What if you want to achieve pixel perfectness (off course divided by two on some screens etc)? This is where my solution comes into play.

The way it works is this. You basically give it a minimum visible area and a maximum visible area, and the code will figure out an optimal orthographic size between those bounds. Obviously it may not always be possible to find a fit, so it’s good to have enough margin. Let me explain.

Note: I talk about iOS screen sizes a lot, but the same principles apply to Android. This is just to illustrate.

I personally like to work at “iPad retina” scales. So if we only do landscape, that would be a 2048×1536 area (shown here at 1/4th size).

ipad-landscape

 

Now let’s use the iPhone’s size as the minimum area. So that’s either 960×640 or 480×320 – but let’s supersize that to 1920×1280 and put it in our beautiful image.

But what about iPhone5(s)? Those devices have a 1136×640 resolution. Supersized x2, that would be 2272×1280. Our image is too small! So let’s resize it so it’s 2272×1536, and add borders for all the screens sizes.

all-sizes

Green is iPhone4, yellow is iPhone5, and red is iPad. The idea now is to find an orhtographic size (for any screen) that fits within the image, and that keeps the entire green part visible, and it should preferably be as pixel-perfect as possible.

All graphics should be designed while keeping in mind that the parts outside of the green border could get cut off. Off course things could still be anchored to the corners.

So we know that our minimum area is 1920×1280 (the green box), and the maximum area is 2272×1536. If we want to support both landscape and portrait, it will look like this :

all-sizes-and-orientations

So now our maximum area is 2272×2272, and our minimum area is 1280×1280. You can off course add some margins to it if you want to support screens with even bigger resolutions. You don’t have to use these numbers at all, but just decide on a minimum and a maximum size that work for your situation.

Now what you do is you add the code at the end of this post to a GameObject (possibly the camera), and enter the minimum and maximum areas. You can enter different areas for landscape and portrait, or enter just one of them if you only need one orientation. The script has a cameras array, in which you drop the cameras you which to affect. So it can work for multiple cameras, or you can have multiple instances of the script for different cameras that need to show different things.

So all you do is set up you areas and tell it which cameras to affect, and the script does the rest. It even shows some boxes in your game scene for reference.

Note: The area sizes can’t have decimals, so use integer values. However, since Unity’s default mapping for sprites is 1 unit = 100 pixels, you most likely will want to divide your area by 100. That’s why there’s a scale property. Just set it to 0.01 and presto.

In cases where you want to always show the same amount horizontally (for instance, if you have a couple of lanes on the screen and don’t want to show more or less than that), you can just set the minimum and maximum width to the same value, and set the min and max heights to extreme values.

 

And here’s the code

First, let me say that it works well, but it uses a bit of brute force because I couldn’t figure out a more elegant algorithm, but the brute force is really limited, and it only does it at the start and when changing orientation, and you won’t be able to notice it. Still, if anyone feels inclined to optimize it or clean it up, be my guest!

In a follow-up post I will share my solution for anchoring GameObjects to the sides or corners of the screen, which can be used together with this code (or separately).

 

I am the walrus.

I’m not really a walrus (at least not as far as I know), but what better way to start my new blog than with a line from a Beatles song?

Maybe I’ll make a game about a walrus at one point. Who knows.