Fast platform collisions. Oct
13

With the launch of GameMaker:HTML5, there's one brand new factor that should be at the forefront of any game you now design; speed. You see, moving from a windows executable to HTML5 carries some performance issues, and sometimes, some pretty severe ones. JavaScript isn't as quick as native code, that's obvious, and this means you will have to produce more optimal, streamlined code. This in turn means that there is some adjustment required in the way we now do some things in GameMaker. Platform games are a case in point, for while they work fine under windows, due to the way the original examples demonstrated things, they are far from optimal enough for GameMaker:HTML5. Don't worry though, anything you learn here can be carried over to Normal Windows executables, and you'll still see a speed up there as well, so it's all good.

So, why is this? Why does the current crop of platformers suffer so much in JavaScript? Well, the issue is due to the way commands such as "move_outside_solid()" work. you see, what currently happens when you write a platform game, you ask the system to give you a collision event, and then you use commands like move_outside_solid() to move outside it. The problem with commands like this is the amount of code it has to run through in order to satisfy these seemingly simple actions.

Let's take the command move_outside_solid(), how does GameMaker do this? Well... first, have a read of my collision article, because you'll need to understand how precise collisions work, and how much effort it is for the CPU to do that work. Once you've read that, you'll realise that even one precise collision can take a pretty long time, and you might even now realise that move_outside_solid() will have to do this several times in order to "move outside" the collision that just occurred.

So let's follow through what happens.... First you move the player/object as normal, and then the system throws a collision event (probably using a slow collision test in the process), telling you that your instance has just hit something. You now workout the direction you've just come from, and use move_outside_solid() to "back out" of this collision. If you were deep inside the collision (say several pixels inside the collided block), then it may take several precise collision iterations to actually move your instance back out. Add to the fact that you may also be doing this to baddies as well as the player, then you can see that this is just burning CPU time - lots of it. So, how else could you do this? How could you run around on a platform, and stop the player (and baddies) jumping into walls, or falling through the floor?

First, why don't we have a look back at some old retro systems: NES, C64, Megadrive, SNES - all of these systems are well known for platform games, and did platform collision detection in the same way; tilemaps. Now, these aren't tilemaps as GameMaker defines them, this is because GameMaker uses a somewhat warped version of tilemaps. Most of these old systems used fixed character mapped screens, that is, a screen made up of X by Y characters. (i.e. the C64 had a screen of 40x24 cells, which it uses as characters, and games use as tiles). These characters were then used as tiles, and these tiles were then defined into platforms and background, and simple collisions would occur with them.

C=64 Giana Sisters

The game above (The C64 game, "The Great Giana Sisters") shows how the game would probably tile up it's level. The larger tiles would actually be multiple tiles, chained together to make a large object. This differs greatly from GameMakers tiles, because they aren't really tiles at all, but very simple sprites. This is a problem, because we can't easily detect which tile we've hit - at least, not without extensive checking. So, how did these old - and very slow systems, collide with the background so quickly? Easy, they used a fixed grid of tiles. This meant you could easily tell which tile you hit, simply by dividing down your coordinates (usually by 8, 16,32 etc. in fact, any power of 2 number) and then using these numbers they index directly into the grid of tiles.


10000001
10200101
11111111

So, lets have a look at a simple tilemap. Above you can see a very simple tilemap where 1 is solid, 0 is empty, and 2 is a pickup. This means all we need to do is test the tiles directly under the instance (in this case, the player). So how do we do that? Well, If we're using a 16x16 tileset, and our sprite is a 16x16, then when standing directly on a tile, it's x and y coordinate will be a multiple of 16. So, when checking the tile directly below, we would simply add 16 to Y, then divide the Y coordinate by 16, and flooring it. This gives us the tile index (on Y) for the tile under our feet. If the tile is 1, then we don't fall, if it's 0, we do. 

16x16 tiles

Now that's all well and good, but what if we are falling, and what if we fall INTO a tile? How can we move out of it without commands like move_outside_solid()? This is where we use some old school tricks, and it's how these old 1Mhz systems were able to games like platformers and shooters so easily.

First; time to brush up on some binary maths. Binary is very handy, and you should be a fluent as possible with it and the tricks it allows you to do. Lets have a look at a couple of numbers.


%1     1
%10    2
%100   4
%1000  8
%10000 16

As each bit is set, it adds a power of 2 number to the total. As you can see from the above numbers, they have single bits set, and so are "pure" power of 2 numbers (1,2,4,8,16,32,64,128 etc. are all power of 2. As each number is multiplied by 2, it doubles.)

So, if we have some combinations of these bits... what does this mean?

%110     6
%1101   13
%11      3
%1001   9

Using the table above, you can see when you add the bits together, you get the resulting numbers. So, pretty straight forward so far. This is how computers store numbers, with each BYTE being able to hold 8 bits, allowing for numbers from 0 to 255. For larger numbers, the computer simply uses more bytes. 2 bytes allows 16 bits, and a number from 0 to 65535, and so on.

So... why this lesson in basic computing? Ah... well, now it gets interesting. What happens if we shift these bits around? Let's say shift them left or right by a number of bits? Well, %1 shifted left 3 would give %1000, and this gives 8. Also, if we had %1000 and shifted right 3, we'd get %1 (1). In other words, we can do simple multiplication and division by shifting the bits around. (this is again, how the computer does basic binary maths).

So... What would happen if we dropped OFF the lower bits...? Let's say we had %1011 (11), and we AND'd with %1000 (8), we would end up with...8. By removing these lower bits, we have effectively rounded DOWN to the nearest multiple of 8.

collision

Now, that's handy.... What if our tilemap was made from 16x16s, and what if we were 4 pixels into one on Y. So the Y coordinate was 68. How could we move it back out of the tile? Well, since we know all tiles are on fixed pixel boundary's, we know that OUTSIDE the tile coordinate is 64. Using the binary tricks above, we can do a simple AND with Y coordinate (Y = Y & $fffffff0), and this will rid us of the lower bits making the value a multiple of 16, and placing it outside the collision, and back to 64; since %1001000 (68) & $fffffff0 = %1000000 (64).

So, let's look at this again. If we know we have a collision on Y (below), we can simply jump back directly into the empty space by ANDing with $fffffff0, and removing the offending bits.

This collision system is lightning fast, but to use it you must have a FIXED tilemap, not one that places tiles "anywhere". Future versions of GameMaker will remove that ability, but it will also give access to the map for use with collisions, because it's an invaluable tool. Once you collide with the map, you can collide with anything in the level. Pickups, traps, solid objects, triggers, pretty much anything you use an instance for in terms of collision, you can use tilemaps to do it faster. You do have the restriction that your object must be on a tile boundary, but for most things, this isn't an issue. After all, if you want to trigger something when the player walks over it, does it matter if it's a few pixels to the left? The same with power ups... You just get used to placing them in this manner, and then you can use the tilemap to actually collide.

GameMaker:HTML5 comes with a demo of this method, so you can now read over this and then poke around in the source till your hearts content!

 
Mike

YoYoGames.com and GameMaker HTML5 . Aug
3

A few days ago we released the first application that has been created with the new HTML5 GameMaker, and you can now see this on the front page of yoyogames.com. Its a simple animation that replaces the FLASH version, but shows that we can start doing real things with HTML5. This version is for example, visible on iOS and android devices, and while there are still issues (we can't test on everything here!) it's a definite step in the right direction.

Some of you will also have looked and the code and noticed it's basically just mush. GameMaker HTML5 does an obfuscation pass which not only helps protect your (and our) code, but also dramatically reduces the size of it.

We have now started a very limited ALPHA running with some select developers and we are gaining momentum for later this year when it'll be released. We hope to release some demos to the general public soon to show you what you can do with it, and some of this has surprised us - in a good way! However, you should be wary when comparing HTML5 to normal windows code. For starters, HTML5 is still very much a work in progress, browsers are still implementing and changing how things work, and this is changing almost on a daily basis! A browser you used a couple of months ago, may very well be seriously out dated by now. In fact, while we've gotten used to having a version of a browser for a couple of years at a time, the browser wars have kicked off again, and whole new versions are coming out every month or so. So not only do things change, but things change really quickly.

Because of this, don't expect HTML5 to run perfectly on everything. If you have Firefox 3.x, it'll be rubbish, and it won't work at all on IE8 or below. Firefox are currently on version 5, and version 6 and 7 are in beta and alpha!

The pain doesn't stop there either, iOS is about to undergo a major update to it's web performance, and this will change the face of Apples Appstore and the web. HTML5 allows you to have "offline" versions, and Apple allow you to install "bookmarks" to your desktop so it looks like any other app. This means when iOS5 comes out, you will be able to write slightly more limited iOS games without having to go through the Appstore. Of course, doing native apps for iOS will reap huge performance gains, and for some games this will be a must. But if your doing a simple puzzle game, then you will soon have the choice of allowing your app to run not only on windows, but Mac, Linux, iOS and Android devices - all from a single build.

There are some limitations obviously. HTML5 does not allow for texture mapping (properly), so that means we won't be doing 3D initially. However a little later on after launch, we will start to support WebGL and this means all this becomes possible again, and pretty much anything you do in the windows version of GameMaker, will be availbale to the web version.

On the subject of what's missing, you obviously can't use normal extensions; these are windows specific and native code to boot, and browsers simply won't allow you to run this. So the HTML5 version will allow you to use JavaScript extensions. This will allow you to do pretty much ANYTHING you want, from networking, to database to Facebook and beyond, and this will make GameMaker HTML5 incredibly powerful.

Lastly.... HTML5 is obviously slower than native apps, so the current rule of thumb is that you will have to write specifically for the web. Of course, this isn't to say that this code won't run great on windows/mac natively, but it does mean some things you did in the past, simply aren't a good idea now. Some of the ways GameMaker did it's collision for example, really suck. So now you'll have to take more care when bolting your games together.

We'll talk more about this and other optimsations you can make in the future, but rest assured, it's looking like a particually exciting time to be a GameMaker developer!