segunda-feira, 5 de setembro de 2016

Flying Creatures with Smart


Smart Creatures

In this experiment, I'm going to show you how to use a texture atlas in Smart Mobile Studio, and create the flying sea creatures animations.
Here's an animation I re-created recently using a texture atlas:

Texture Atlas in Smart

I'm going to jump right into how to use a texure atlas for animations in Smart Mobile Studio, but I would say using an atlas is far superior to using a spritesheet.

Using Texture atlas allows you to:

a) Use more animations and sprites: Make your animation run smoother.
Not all frames have to be the same size when using an atlas.
When using an atlas each element is only drawn once. (a spritesheet is redrawn every frame)

b) Save memory: Compress your sprite sheet and drastically reduce memory usage. Reduce memory consumption, not image quality, it packs frame data more efficiently, and reduce memory and bandwidth.

c) Increase framerate: Compute frames faster and ... It's easier to refer to frames by name rather than by index.

d) Make your game start faster: For maximum performance directly export to your target system's image formats.

e) Preserve visual quality: The effect of compression or dithering is nearly invisible on high-resolution devices or moving objects.

Now a little more background on sprites-sheet and texture-atlas.
A sprites-sheet (often refers to a large image that) is supposed to contain the animation frames of a
specific 2d character or projectile in a game. You can almost think of it as the model of a 2d-character.
It stores all the various animations created for a specific character.

A texture-atlas (aka tile map, tile engine) is a large image containing a collection, or "atlas", of sub-images, each of which is a texture map for some part of a 2D or 3D model. The sub-textures can be rendered by modifying the texture coordinates of the object's map on the atlas, essentially telling it which part of the image its texture is in. You can think of these as 2d images "painted" over 3d objects.

Any 3D object (for example a weapon, a garbage can) or character can have a texture applied to it. Especially 3D levels may require multiple different textures for various walls and elements in the 3d scenery. All these textures can be contained accessibly and effectively in a single large image composed of many squares (subregions) devoted to a specific model.

In an application where many small textures are used frequently, it is often more efficient to store the textures in a texture atlas which is treated as a single unit by the graphics hardware.
This saves memory and because there are less rendering state changes by binding once, it can be faster to bind one large texture once than to bind many smaller textures as they are drawn.

Creating a Texture Atlas

I've been using the Texture Packer (this is a paid tool) to create the atlas, there are free tools out there, but in Texture Packer, you just drag 'n drop some pictures and the tool will just re-arrange all the sub-images into a big image.PNG file with a JSON file with the info that describles the coordinates (map) of where each picture begins and ends, it's lika HTML map. This is so nice!

We're going to load a single file (seacreatures.png) in SMS so you should place them both within the www/res folder. The .png file is probably pretty obvious, but let's take a look at the piece of this .json file. It's a very long file.

{
"frames" : [{
  "filename" : "blueJellyfish0000",
  "frame" : {
   "x" : 484,
   "y" : 770,
   "w" : 64,
   "h" : 64
  },
  "rotated" : false,
  "trimmed" : true,
  "spriteSourceSize" : {
   "x" : 0,
   "y" : 0,
   "w" : 66,
   "h" : 66
  },
  "sourceSize" : {
   "w" : 66,
   "h" : 66
  }
 }, {
  "filename" : "blueJellyfish0001",
  "frame" : {
   "x" : 484,
   "y" : 836,
   "w" : 63,
   "h" : 65
  },
  "rotated" : false,
  "trimmed" : true,
  "spriteSourceSize" : {
   "x" : 1,
   "y" : 0,
   "w" : 66,
   "h" : 66
  },
  "sourceSize" : {
   "w" : 66,
   "h" : 66
  }
 }, {
  "filename" : "blueJellyfish0002",
  "frame" : {
   "x" : 322,
   "y" : 1621,
   "w" : 62,
   "h" : 65
  },
  "rotated" : false,
  "trimmed" : true,
  "spriteSourceSize" : {
   "x" : 2,
   "y" : 0,
   "w" : 66,
   "h" : 66
  },
  "sourceSize" : {
   "w" : 66,
   "h" : 66
  }
 },{...}
],
"meta" : {
 "app" : "",
 "version" : "",
 "image" : "seacreatures.png",
 "format" : "RGBA8888",
 "size" : {
  "w" : 1024,
  "h" : 2048
 },
 "scale" : "1"
}
}

The important parts here are that it provides a name for a specific sprite and also provides the coordinates for where it is located in the image. We can refer to a specific sprite by it's frame name.
Basically, I'm going to use the "genFrameNames" function. This function will automatically create an array of names for you if they are in a JSON format. We don't want to write all these spritenames manually.

Of course, you could also just write this out manually if you want but when you've got an animation that's 20 frames long it certainly helps to speed up development and also makes your code look a lot cleaner.

In the creatures example, I'm going to use multi-animations.
For instance, I have 33 sprites that make up my blueJellyfish animation:
'blueJellyfish0000', 'blueJellyfish0001', 'blueJellyfish0002' ... 'blueJellyfish00032'

So rather than write all of these out manually, I use this:

animations.Add( TAnimation.create('jellyfish', genFrameNames('blueJellyfish', 0, 32, '', 4), 60) );

I supply 'jellyfish' as the prefix, and specify the start as 0 and end as 32 so it will generate the following array:
['blueJellyfish0000', 'blueJellyfish0001', 'blueJellyfish0002' ... 'blueJellyfish00032'];

Basically, I've created an array of records to store my animations, and create the sprites, according to the current frame. I ended up creating a function to get the current frame (getCurrentFrame).


JellyfishanimObj := animObj.createSprite( animations[0].getCurrentFrame);

Now, we can render this sprite anywhere:
JellyfishanimObj.draw(ctx, 670, 20);

I really like using the texture atlas approach you don't have to worry about making all of your sprites the same size and it makes it super easy to generate animations by referencing the names of the files using the "genFrameNames" function.

This is actually my swimming creatures animation with Smart, at least but you get the idea!

Nenhum comentário:

Postar um comentário