Tuesday, August 28, 2012

Basic animation with NME and drawTiles

In this post I'm going to cover the basics of animation with drawTiles in NME. It builds upon the project in my previous post, Getting started with Haxe and NME.

Source for this example can be downloaded from github.

The fastest way to draw sprites with NME is to use a technique called blitting. This basically means you copy the pixel data from one bitmap into another, and then draw the final composed image to the screen. This is opposed to drawing several bitmaps to the screen, which is generally slower.

In NME this is done via the Tilesheet class and its drawTiles method. (Joshua Granick posted some benchmark numbers, if you'd like to see just how fast drawTiles is.)

Using drawTiles is pretty easy. All we need is a Tilesheet and some tile data, which is an array of Floats telling the Tilesheet what to draw.

First I'm going to declare two instance variables:

Then later I can set them up:

Here I create my Tilesheet with a spritesheet asset, which is basically just an image that contains all my animation frames.

After creating the Tilesheet I tell it the location of my two tiles: The first starts at position 4, 0 and is 8 pixels wide by 16 pixels high. The second starts at position 20, 0 and is also 8x16.

Now I need to set up my tileData, and here's where things get a little more interesting. We're eventually going to ask our Tilesheet to drawTiles using this tileData. The data is formatted as an array of Floats, and each position in the array has a specific meaning. By default, each "tile" is specified by its x position, y position and tile ID. In my array, I'm saying that I want tile ID 0 (the first tile I added to my tilesheet) to be drawn at 10, 10 and also at 20, 10.

So now I've set up my tilesheet and I need a way to draw its tiles every frame. To do that, I set up a listener for the ENTER_FRAME event. The specified method will be called on each frame, allowing me to set up the scene to be rendered.

My onEnterFrame method is going to use a very crude mechanism to change the current animation frame, and I need some instance variables to support it:

OK, here's the method itself:

First we clear graphics. Every Sprite, including the class I'm working with here, has a Graphics member. The tilesheet will draw our tiles to it, and if we don't clear it before drawing then we'll just keep drawing on top of whatever we had last frame.

Next you can see my crude animation mechanism. It's not something I would use in production code, but it's good for this example. Basically, every 500 milliseconds we're going to toggle the tile ID between 0 and 1. Then we specify that position 2 and 5 of our tileData array should be set to this ID. Take a look at the code above, where we initialized tileData, and you can see that position 3 refers to the ID of the first tile and position 5 refers to the ID of the second tile.

Finally, we're ready to drawTiles. We simply provide our Graphics instance and our tileData, and we're set.

drawTiles can do other interesting things too, like scale, rotate or smooth your tiles. Here's the doc, taken from Tilesheet.hx:
Notice how using additional features changes the number of array elements per tile in your tileData.

Here's the complete class:
Run this, and you should be greeted by two happily bouncing chefs:

And there you go. Happy Haxe-ing. :-)

No comments:

Post a Comment