Fire the Photons! Animating Sprites in Sencha Touch 2.2

boldlygo

Sencha Touch 2.2 contains a cross-device compatible canvas/svg drawing package that enables you to easily produce some really nice sprite-based animations.

Instantiating a Draw Component

Instantiate a draw component (xtype: ‘draw’) as illustrated below. Note that while the Ext.draw.Component class inherits from Ext.Container, docking components in a draw component directly exposes an animation bug that I reported to Sencha this morning.

Draw components are transparent by default, so you’ll probably want to set a background color on the parent container as illustrated below.

Ext.define('SpriteTest.view.Main', {
 extend: 'Ext.Container',
 xtype: 'main',
 requires: [
  'Ext.TitleBar',
  'Ext.Toolbar',
  'Ext.draw.Component',
  'SpriteTest.view.Photon' // torpedo to be added later
 ],

 config: {
  style: 'background-color: black',
  layout: 'fit'
 },

 photonTube: 0,

 initialize: function() {
  this.setItems(
   [{
     xtype: 'titlebar',
     title: 'Boldly Go...',
     docked: 'top'
    }, {
     xtype: 'draw',
     itemId: 'space'
    }, {
     xtype: 'toolbar',
     docked: 'bottom',
     layout: { pack: 'center' },
     items: [{
              xtype: 'button',
              text: 'Fire!'
            }]
     }
   ])
 }
});

Extending a Sprite Class

Sencha Touch supports the following types of sprites:

  • Arc
  • Circle
  • Composite
  • Ellipse
  • EllipticalArc
  • Image
  • Instancing
  • Path
  • Rect
  • Sector
  • Text

Sprites use a slightly different class system than the rest of Sencha Touch. You configure default values and custom properties using the syntax described in the following example:

Ext.define('SpriteTest.view.Photon', {
 extend: 'Ext.draw.sprite.Image',
 alias: 'sprite.photontorpedo',

 inheritableStatics: {
  def: {
   processors: { // define custom properties
    photonTube: 'string'
   },
   defaults: {  // configure default properties
     src: 'resources/images/photon.png',
     width: 150,
     height: 150,
     photonTube: '0'
   }
  }
 },

 constructor: function() {
   this.callParent(arguments);
   /* call custom code here */
 }
});

While other classes in Sencha Touch wrap configurable properties in a config block, sprites define their configs and defaults using very different syntax. Also, getters and setters are *not* automatically created in this construct.

Adding Sprites to a Draw Component

Technically, you don’t really add Sprites to a draw component. You actually add sprites to the “surface” that is instantiated by the draw component. The draw component’s surface is either an abstraction of an HTML5 canvas (on iOS platforms) or SVG (non-iOS platforms).

The following code snippet builds out the SpriteTest.view.Main class “Fire!” button described above.

{
 xtype: 'button',
 text: 'Fire!',
 scope: this,
 handler: function(b, e) {

  var surface = this.down('#space').getSurface();

  surface.add({
   type: 'photontorpedo',
   surface: surface,
   photonTube: this.photonTube
  });

  if (this.photonTube == 0)
   this.photonTube = 1;
  else
   this.photonTube = 0;
 }
}

Animating Sprites

You can change the appearance of a sprite in a single frame by modifying its attributes via the sprite.setAttributes() method and then subsequently calling the surface.renderFrame() method as illustrated below:

var component = new Ext.draw.Component();
Ext.Viewport.setLayout('fit');
Ext.Viewport.add(component);
var mySprite = component.getSurface().add({
    type: 'text',
    x: 50,
    y: 50,
    text: 'Fig Leaf Software Rulez',
    fontSize: 18,
    fillStyle: 'blue'
});
mySprite.setAttributes({
    x: 100,
    y: 100
});
component.getSurface().renderFrame(); // apply all changes

What is not generally understood, however, is that you can animate a sprite by modifying a sprite’s fx property, which functions as a pointer to an instance of the Ext.draw.modifier.Animation class. Here you can set a time duration (in ms) over which changes to sprite attributes will be gradually applied. You can also define an event listener that is fired once the animation has completed executing.

This technique is illustrated by the fire() method of the photon torpedo class, listed below:


Ext.define('SpriteTest.view.Photon', {
 extend: 'Ext.draw.sprite.Image',
 alias: 'sprite.photontorpedo',

 inheritableStatics: {
  def: {
   processors: {
    photonTube: 'string'
   },

   defaults: {
    src: 'resources/images/photon.png',
    width: 150,
    height: 150,
    photonTube: '0'
   }
  }
 },

 constructor: function() {
  this.callParent(arguments);
  this.fire();
 },

 fire: function() {
  var surface = this.config.surface;
  var stageWidth = surface.element.getWidth(true);
  var stageHeight = surface.element.getHeight(true);

  var centerX = stageWidth / 2;
  var centerY = stageHeight / 2;

  // start from left or right of the draw component view?
  switch (this.config.photonTube) {
   case 0:
    this.setAttributes({
     x: -150,
     y: stageHeight
    });
    break;

    case 1:
     this.setAttributes({
      x: stageWidth,
      y: stageHeight
     });
     break;
  }
  
  // set animation time to complete (1.5 seconds)
  this.fx.setDuration(1500);

  // set animation transition
  this.fx.setEasing('easeOut');

  // set animation callback
  this.fx.on('animationend',this.onAnimationEnd, this);

  // apply changes to sprite, over 1.5 seconds

  this.setAttributes({
    x: centerX - 20,
    y: centerY - 20,
    rotationRads: 3,
    width: 40,
    height: 40
  });
 },

 onAnimationEnd: function(animation) {
  this.destroy();
 }
});

What are you waiting for? Go get your ‘pew-pew’ on!

And don’t forget to contact Fig Leaf Software for all of your Sencha-related consulting and training needs!

4 thoughts on “Fire the Photons! Animating Sprites in Sencha Touch 2.2

  1. Pingback: Create a Game and Win an all-expenses paid trip to SenchaCon | Druck-I.T.

  2. Pingback: Top 5 Things A Game Can Teach Your Business App | SDK News

  3. Guru

    Nice tutorial… It helps me to do nice gaming animation. But this is failed on some androids phone( eg. Samsung S3). Any idea?

    Reply
    1. sdrucker Post author

      You’ll need to be more specific. How did it fail, exactly?

      Animation performance on Android browsers (even the Galaxy S4) is pretty awful. The iPhone 5S is really the first device/browser combo that gives you near-desktop level animation performance in the browser.

      Reply

Leave a comment