AN1001 - Animation in SHIP

From Serious Documentation
Jump to: navigation, search

Animation in SHIP

Animation is a common element of many GUIs. Whether a rotating fan, slowly filling indicator, or a glowing element, subtle animations can enhance a GUI and make it more professional and modern.

At the core of every animation is a series of images that, when rotated through in-place one after another, form the impression of an animated object.

Animation in SHIP is the process of cycling through a series of images at a certain rate, making each one visible in sequence with the others invisible.

SHIPTide Project Files for AN1001

Assuming you've downloaded and installed the SHIPTide Rapid GUI Development Environment, download the following zip file. Unzip the projects to a directory of your choice and open up the project corresponding to your target platform in SHIPTide.

There are many ways to implement animation in SHIP; the attached project uses the concept of "grouped images" and demonstrates 4 different timer modes.

Animation Images

Just like the cartoon drawings you might have drawn as a child on a corner of a book and "flipped" through to animate, these images will be sequentially shown within the runtime SHIPEngine environment. Therefore, as you create the images in Photoshop or your graphics design program of choice, ensure that each image transitions to the next in exactly the right location within the borders of the image boundary.

Creating a set of Animation Images

Each animation image should be exactly the same size -- in this example project the fan images are all exactly 75 pixels square. Here they are, all in fully transparent alpha-blended .png format:

Example Rotating Fan Image, Part 1/3Example Rotating Fan Image, Part 2/3Example Rotating Fan Image, Part 3/3

In this example the three fan images are not only the same size (75 x 75 pixels), but the actual drawings within the image boundaries are in exactly the same location just rotated. If one of the fan images were shifted to the right (for example) you would see horizontal jitter in the animation.

This may be a desired effect, for example if you wish to animate an arrow moving from left to right towards a target. But for many animations you will want to pick a drawing center-point and ensure the various versions of the image are centered on that point within the image boundaries.

Image Formats and Optimizations

In SHIPTide, look in the Project Resources pane and find the three fan images. Click on one of them and examine the properties of the image in the Properties pane:

AN1001 - Examining an Image

All images in SHIPTide need to be pre-scaled to the desired size for the GUI. SHIPTide does not scale images because on small LCD screens generic auto-scaling algorithms rarely produce attractive results. Edges often get very jagged and distorted.

SHIPTide does not attempt to replace high-end graphics design tools -- you will want to use tools like Adobe Photoshop, Fireworks, or Illustrator to develop your icons, backdrops, and images. You can even use Microsoft PowerPoint to generate some images -- beveled buttons are surprisingly easy to create and export in PowerPoint! Illustrator is particularly powerful as you can create your source images in vector format, scale them well, export them to a fixed size and then use an image editing tool like Photoshop to clean up any residual issues.

Small image and icon creation is an art. Sites like Icojam, IconFinder, DryIcons, and many, many more (browser-search for "icons" and you will see!) feature innumerable talented small-image artists -- many can be contracted to develop your images and ensure you have sufficient legal rights to use them.

You will typically use .png or .gif images with transparency so that the animation can alpha-blend on top of any background. While the example project uses a fixed color background, you can change this background color or even layer a background image underneath the fan animation and the fan will rotate and "float" over the background with the background showing through the non-blade part of the fan images. Here is the same fan image over top of an image where you can see the underlying image coming through:

AN1001 - A PNG Image with Transparency on a Background

In almost all graphic design tools images can be saved with an 8- or 32-bit color depth, with or without alpha-transparency. Here is a brief chart of the various image formats and their capabilities:

Format Color Depth (Bits) Alpha Transparency
BMP 8,32 No
JPG 24 No
GIF 8 Yes
PNG 8,32 Yes

SHIPTide can read and use all these formats. At Serious we generally prefer 8- or 32-bit PNGs -- PNGs are a superset of the other formats.

Try creating your images with 8-bit color depth (with alpha transparency) and see if there is sufficient color depth to create a viable result -- the memory requirements and access times of these smaller 8-bit images are generally advantageous in your runtime GUI environment. For even more speed-sensitive applications, you can pre-blend the image(s) onto the single desired background and save the image as a non-transparent png/gif/jpg/bmp. These image, while not as flexible since they cannot be dropped on top of various backgrounds, will have no transparency channel and will not require run-time alpha blending -- a faster and simpler operation.

Grouping the Images

The three fan images, instead of being placed directly in the resources/images area, are placed in a named group. Exploring the project in SHIPTide the group looks like this:

AN1001 - Grouped Images

We'll explain why this is important when we demonstrate how the images are assigned to a container visually. A group of images can function as a basic indexed array and there are functions that can extract and assign these to visual containers.

Creating the Visual Container

To display an image, one simply needs to add a box to the layout and set the object property to point to the image. After doing this, you can easily adjust the image's position and other characteristics by manipulating the corresponding properties on the box.

Here is an enclosing animation box from the example project:

AN1001 - Enclosing Image Box

Notice it is simply a horizontally and vertically centered box within it's parent box, with the first of the three images attached to its object property. This sets up the box's width/height/position at build time (vs. run time) to match the images we're animating.

When the GUI runs, this first image will be displayed statically in the page. If you do not want this image visible at all until some signal or condition, just hide the box by setting its visible property to false in SHIPTide, then set it to true in a SAIL script when you want the image displayed.

The Animation "Engine"

To animate the image, we need to rotate the object property of the box container through the various images in the group.

This requires only a four basic elements:

  • a variable that continuously counts up so we can index, modulus the number of images, what image we want to display in the sequence
  • a timer that runs the animation frame rate
  • a listener that watches for the timer to alarm,
  • a script that increments the variable, switches the image, and restarts the timer

Here are those 4 elements from the example project:

AN1001 - The Animation Engine

In this example, the fanValue variable has data type Integer. Every time the timer's alarm goes high (indicating the timer has expired), the listener wakes up. Notice how the listener's condition is set to filter the event only when the alarm is high.

The script, well documented right in the code in this example, increments the fanValue variable every time the script is executed.

At the heart of this script is this expression:

box.object = getChild(fanGroup, fanValue % getChildCount(fanGroup));

This fetches the image node from the fanGroup group based on the index in the second parameter. In this case, the script takes the current value of fanValue modulus the number of images.

If you examine the getChild() function parameter reference, the function automatically does this modulus. So the script can be written simply as:

box.object = getChild(fanGroup, fanValue);

The result of getChild() is assigned to the box's object property. The LCD display will automatically be refreshed if the image is a different one than prior assigned.

Finally, the script restarts the animation timer. See the timer reference for information on the 4 different timer operating modes and how to restart the timer in each mode. The example project not only shows how to animate an image, but also demonstrates all 4 timer modes.

Starting and Stopping the Animation

You can start and stop the animation simply by starting and stopping the animation timer. In the example project, touching the touchscreen in the containing box enables the timer:

AN1001 - Starting/Stopping the Animation with a Touch

In this case, the script just inverts the timer's enabled property, pausing/resuming the timer.

Optimization and Performance

There are several factors to consider to ensure the animation is as light-weight as possible.

Enable timers and listeners only when Needed

Ensure your timers and listeners are disabled when the animation is not required. Setting the enclosing box's enabled property to false will turn off all listeners inside that container. However, the timer will still run, so make sure the timer's enabled property is also set false.

Use a Global Animation timer and Counter variable

To minimize resources, declare a global variable/timer/listener/script set that can drive all animations. For example, the following structure:

AN1001 - Setting up a Global Animation Engine

is a single global structure that could drive the animations for the whole GUI.

Each animation, then, would only have a single listener/script pair listeningto the global variable animEngine.

For example, if we modified one of our fans in the demo to use this global counter, the listener/script pair would look like this:

AN1001 - Using a Global Animation Engine

Notice how much simpler the structure is. Also, enabling/disabling the animation only involves turning on and off the variable listener.

image Types and Construction

Image rendering speed factors in to the overall performance of the animation and the GUI, especially on larger images or more limited hardware platforms without hardware graphics controllers.

Pixels are rendered on these software-rendered platforms one by one. In order of overhead/complexity:

  • fully transparent pixels are very fast -- they do nothing!
  • fully opaque pixels are fast -- they are just written to the frame buffer
  • alpha blended pixels (partly opaque) are the slowest -- the current frame buffer value needs to be read, blended with the new color value, then written back

Therefore the fastest animations will come from images that are (a) fully opaque, or, (b) have pixels that are either fully opaque or fully transparent.