Using Creative Cloud and CSS Translate3D to Create an 8 Way Character Animation

Posted on March 25, 2013 | Comments Off

Creative Cloud Workflow:

In this video I am demonstrating one way of creating an 8 way character animation. Moving a character up, down, left, right, and along all the diagonals is a common task in creating games. In this workflow an 80x80px character is animated over 8 x 8 frames. This resulted in a 640x640px png file that I modified in Photoshop. Using a new feature in Photoshop from the Creative Cloud edition called smart filters I modified my previously generated green blob spritesheet. The changes gave it a nice effect seen below:
Photoshop Creative Cloud Smart Filter feature changes

The video (at the end of the post) explains how I used the smart filter feature in Photoshop from the Creative Cloud.

Photoshop Creative Cloud version and new smart filters feature

For rendering the 8 way character animation I wanted to try out the DOM HTML5 way–no canvas or WebGL. I learned this technique from Andy Trice, who also built a demo game with the same approach called PhoneGap legends. It works nicely but there are GPU memory considerations you have to be aware of. Depending on your content this approach could work for your game.

The idea is to use CSS spritesheets to load the different animation frames from one image. Then force hardware acceleration by using the CSS translate3d property to move the images around (in this case we are not moving but it forces the image on to the gpu). Here is what the CSS looks like for the spritesheet:

#hero{
        width: 80px;
        height: 80px;
        overflow: hidden;
        position: absolute;
        top:0px;
        left:0px;
    }
    .hero_0_0{ background: url('images/8way.png'); background-position:0px 0px;}
    .hero_0_1{ background: url('images/8way.png'); background-position:0px 80px;}
    .hero_0_2{ background: url('images/8way.png'); background-position:0px 160px;}
    .hero_0_3{ background: url('images/8way.png'); background-position:0px 240px;}
    .hero_0_4{ background: url('images/8way.png'); background-position:0px 320px;}
    .hero_0_5{ background: url('images/8way.png'); background-position:0px 400px;}
    .hero_0_6{ background: url('images/8way.png'); background-position:0px 480px;}
    .hero_0_7{ background: url('images/8way.png'); background-position:0px 560px;}
    .hero_1_0{ background: url('images/8way.png'); background-position:80px 0px;}
    .hero_1_1{ background: url('images/8way.png'); background-position:80px 80px;}
    .hero_1_2{ background: url('images/8way.png'); background-position:80px 160px;}
    .hero_1_3{ background: url('images/8way.png'); background-position:80px 240px;}
    .hero_1_4{ background: url('images/8way.png'); background-position:80px 320px;}
    .hero_1_5{ background: url('images/8way.png'); background-position:80px 400px;}
    .hero_1_6{ background: url('images/8way.png'); background-position:80px 480px;}
    .hero_1_7{ background: url('images/8way.png'); background-position:80px 560px;}
    .hero_2_0{ background: url('images/8way.png'); background-position:160px 0px;}
    .hero_2_1{ background: url('images/8way.png'); background-position:160px 80px;}
    .hero_2_2{ background: url('images/8way.png'); background-position:160px 160px;}
    .hero_2_3{ background: url('images/8way.png'); background-position:160px 240px;}
    .hero_2_4{ background: url('images/8way.png'); background-position:160px 320px;}
    .hero_2_5{ background: url('images/8way.png'); background-position:160px 400px;}
    .hero_2_6{ background: url('images/8way.png'); background-position:160px 480px;}
    .hero_2_7{ background: url('images/8way.png'); background-position:160px 560px;}
    .hero_3_0{ background: url('images/8way.png'); background-position:240px 0px;}
    .hero_3_1{ background: url('images/8way.png'); background-position:240px 80px;}
    .hero_3_2{ background: url('images/8way.png'); background-position:240px 160px;}
    .hero_3_3{ background: url('images/8way.png'); background-position:240px 240px;}
    .hero_3_4{ background: url('images/8way.png'); background-position:240px 320px;}
    .hero_3_5{ background: url('images/8way.png'); background-position:240px 400px;}
    .hero_3_6{ background: url('images/8way.png'); background-position:240px 480px;}
    .hero_3_7{ background: url('images/8way.png'); background-position:240px 560px;}
    .hero_4_0{ background: url('images/8way.png'); background-position:320px 0px;}
    .hero_4_1{ background: url('images/8way.png'); background-position:320px 80px;}
    .hero_4_2{ background: url('images/8way.png'); background-position:320px 160px;}
    .hero_4_3{ background: url('images/8way.png'); background-position:320px 240px;}
    .hero_4_4{ background: url('images/8way.png'); background-position:320px 320px;}
    .hero_4_5{ background: url('images/8way.png'); background-position:320px 400px;}
    .hero_4_6{ background: url('images/8way.png'); background-position:320px 480px;}
    .hero_4_7{ background: url('images/8way.png'); background-position:320px 560px;}
    .hero_5_0{ background: url('images/8way.png'); background-position:400px 0px;}
    .hero_5_1{ background: url('images/8way.png'); background-position:400px 80px;}
    .hero_5_2{ background: url('images/8way.png'); background-position:400px 160px;}
    .hero_5_3{ background: url('images/8way.png'); background-position:400px 240px;}
    .hero_5_4{ background: url('images/8way.png'); background-position:400px 320px;}
    .hero_5_5{ background: url('images/8way.png'); background-position:400px 400px;}
    .hero_5_6{ background: url('images/8way.png'); background-position:400px 480px;}
    .hero_5_7{ background: url('images/8way.png'); background-position:400px 560px;}
    .hero_6_0{ background: url('images/8way.png'); background-position:480px 0px;}
    .hero_6_1{ background: url('images/8way.png'); background-position:480px 80px;}
    .hero_6_2{ background: url('images/8way.png'); background-position:480px 160px;}
    .hero_6_3{ background: url('images/8way.png'); background-position:480px 240px;}
    .hero_6_4{ background: url('images/8way.png'); background-position:480px 320px;}
    .hero_6_5{ background: url('images/8way.png'); background-position:480px 400px;}
    .hero_6_6{ background: url('images/8way.png'); background-position:480px 480px;}
    .hero_6_7{ background: url('images/8way.png'); background-position:480px 560px;}
    .hero_7_0{ background: url('images/8way.png'); background-position:560px 0px;}
    .hero_7_1{ background: url('images/8way.png'); background-position:560px 80px;}
    .hero_7_2{ background: url('images/8way.png'); background-position:560px 160px;}
    .hero_7_3{ background: url('images/8way.png'); background-position:560px 240px;}
    .hero_7_4{ background: url('images/8way.png'); background-position:560px 320px;}
    .hero_7_5{ background: url('images/8way.png'); background-position:560px 400px;}
    .hero_7_6{ background: url('images/8way.png'); background-position:560px 480px;}
    .hero_7_7{ background: url('images/8way.png'); background-position:560px 560px;}

And the snippet of JavaScript (using JQuery) to animate and force hardware acceleration with translate3d:

   function animate() {
        var animationAgeInMs = new Date().getTime();
        var animationFrame = (Math.floor(animationAgeInMs / msPerFrame)  % walkCycleFrameCount);
        if (isMouseDown) // do animation
        {
            hero.el.style["-webkit-transform"]="translate3d("+ hero.x +'px,'+ hero.y +"px,0px) ";// scale("+hero.scale+")";
            hero.$el.removeClass().addClass("hero_" + animationFrame +"_"+ hero.direction);
        }

        requestAnimFrame( animate );
    }

Adobe Creative Cloud Products Used:

Photoshop from the Adobe Creative Cloud

Other Technology:

CSS translate3d and CSS spritesheet, thanks to Andy Trice

Demo:

Live Demo

Source Files:

Source Photoshop source file and CSS Translate3D/Spritesheet HTML/JS files

Video: