JPSprite and TexturePacker

Summary

Show code and images as:

Introduction

This tutorial will show you how sprite sheets from TexturePacker can easily be integrated in a game made with ShiVa 3D, by using a simple tool named JPSprite.

This tutorial comes with a demo named JPSpriteSample, you can try it online. The source code is available. It contains everything related to this tutorial and is a great example on how to manage sprites data and movements in a 2D game.

First, please let me introduce myself. I'm Julien Pierron, former employee of Stonetrip, the company that has created the wonderful game development tool: ShiVa 3D.
I have developed many games, both 2D and 3D ones. As we are here to talk about sprites, I will just name 2 of the sprite based games I have developed: Hills of Glory WWII and Babel Rising Cataclysm that are available on iOS and Android. Sprites are the heart of these games, they use and abuse of sprites. With these games I had to create my own sprite animation engine and as we were targetting mobiles, I faced several constraints and I had to work around optimisation.
I now have a great experience and I know how to do things in an optimised way. I have created JPSprite to share this experience to anyone wanting to create a powerful sprite based game, or any game developer trying to optimise its game starting, with 2D elements like menu items or so on.

What is TexturePacker ?

TexturePacker

TexturePacker is a great software that is able to combine several images into a big one, named an atlas or a sprite sheet. This atlas comes with a file that describes the UV coordinates of each sprite that is stored in the atlas. TexturePacker can export that description file in many formats, we will use xml as it is the one that ShiVa is able to read natively.

What is JPSprite ?

JPSprite is a tools that is able to read the atlas and its description file from TexturePacker, and apply the right UV coordinates to a HUD component or object material in a ShiVa game. This part of JPSprite is available for free.
The paid version adds support for sprites animation. While TexturePacker is designed for non animated sprites, JPSprite is able to animate things. You just have to name the sprites of your animation properly, with the frame index as a suffix, and JPSprite will automatically detect these sequences. You can then tell JPSprite "Hey, apply this animation on that HUD component", and the animation will play.

Why using JPSprite and TexturePacker ?

As we use square textures in games, there is often unused space in textures that comes separately. With TexturePacker, you will create a square atlas with all of your sprites inside. As a result, the atlas will be filled with as much sprites as possible, and you will have almost no lost space. What does that mean? That means you will have a single texture that will be ligher that all of the small textures separately. The benefits are :

  • The texture size is smaller, helping you to reduce the total size of your final game.

  • It takes less space in memory when loaded.
  • It is faster to load.
  • Optimised draw calls. Objects sharing the same texture will all be displayed with a single draw call.

JPSprite is very easy to use, you can display a sprite with a single line of code. JPSprite also comes with very powerful and efficient animation engine. The benetifs of JPSprite are :

  • Very easy to use, complexe things can be done in one line.
  • Full featured animation engine
  • Very low CPU consumption thanks to powerful optimisation techniques inside.

  • Lot of development time saved

TexturePacker tutorial

Open TexturePacker and create a new project. In the list of frameworks, select "ShiVa3D (+JPSprite extension)" and click "Create project". Thanks to that profile, all the options are already well set. Everything you have to do now is to drag and drop your sprites in the UI of TexturePacker. You can now publish the sprite sheet. This process will generate 2 files: the image and the xml file that describes the UV coordinates of each sprite.

TexturePacker setup

JPSprite tutorial

Import the atlas in your ShiVa project, reference it in your game

There are 2 files to import, the image and the xml.

To import the image file, clic "Import > Texture" in the Data Explorer and pick your image.
Do the same for the XML file, by choosing "Import > XML".

There are now 2 new files in your project, you can then reference them in your game. Open your game in the Game Editor and open the "Resources" tab. Drag and drop your 2 files from the Data Explorer to the Game Editor, like on the image on the side.

The atlas is now ready to be used, you can start coding...

JPSprite has been designed to be as easy as possible to use. Most of the time, you will only need a single line of code per action. If you need something different than the default setup of JPSprite, it offers several functions to tweak the default behaviour.

Reference resourcesReference resources

Setup the atlas into your game

Call setupAtlas with the name of the atlas and your are done with the setup.

JPSprite.setupAtlas ( "jpspritesample_sprites" )

Display a sprite on a HUD component

This is really easy, give to JPSprite the handle of your HUD component and the name of the sprite you want to set. Here's the example from the demo, with the "plane" sprite.

local hPlaneComponent = hud.getComponent ( this.getUser ( ), "JPSpriteSample.Plane" ) JPSprite.setComponentSprite ( hPlaneComponent, "plane" )

JPSprite will resize the HUD component in order to keep the sprite ratio. By default, JPSprite will set the component size to 1:1 for pixel perfect rendering.

JPSprite is also able to flip sprites coordinates. Our plane sprite is designed to fly from the left to the right of the screen. If your want to create a plane flying in the opposite direction, you can just pass an optional argument to tell JPSprite to flip the UV coordinates on the X axis. This way, no need to create resources for a second plane, we save space on our atlas.

local hPlaneComponent = hud.getComponent ( this.getUser ( ), "JPSpriteSample.Plane" ) local bFlipX = true JPSprite.setComponentSprite ( hPlaneComponent, "plane", bFlipX )

Playing with animations

One of the strenghts of JPSprite is its powerful sprite animation engine.
Just like the rest, you can use it with a single line of code in most of the cases.

local hCharacterComponent = this.getSpriteComponent ( ) local bFlipX = this.nDirection ( ) < 0 local bLoop = true JPSprite.setComponentAnimation ( hCharacterComponent, "walk", bLoop, bFlipX )

As you can see, you can tell JPSprite if you want the animation to play only once or if it is an animation that loops. You can also flip the UV coordinates, this way the character can move to the right or to the left by using the same resources.

JPSprite provides many functions to modify animations, like the framerate of the animation.

JPSprite is strongly optimised

JPSprite embeds a powerful and smart optimisation system.
The base framerate of a sprite animation is generally low, around 12 images per second. That means there's no need to update an animated sprite every frame.

If you decide to enable the optimisation system, JPSprite will change how often sprites are updated, according to how good is your game framerate. If the framerate becomes low, JPSprite will lower its CPU usage, by reducing the update frequency of the sprites, in order to provide more resources to the rest of the game. Here's how to enable the optimisation system:

JPSprite.setOptimizationSystemEnabled ( true )

As an example, in my test project I have created 1200 animated sprites. When the optimisation system is disabled, the script takes 85 ms to execute and the game is unplayable. By enabling the optimisation, JPSprite reduces its update frequency to take only 7ms and the game framerate remains good (30 fps). This is very important because in a game like Babel Rising Cataclysm, the user has to do gestures on the screen and if the framerate of the game is not good enough, gesture animations will lag or even worse, gestures won't be detected properly and the user will feel frustrated.