Showing posts with label animation. Show all posts
Showing posts with label animation. Show all posts

Monday, May 16, 2016

CSS3 Smoke Animation Effect

The comic today uses quite a bit of CSS3 animation. This is a rather new thing for me - I've been using mostly JavaScript-powered animations on Amphibian.com since it started. But after I did the rain animation using CSS back in March (see the comic here), I've been warming up to the idea of more CSS and less JavaScript to move things around.

For this task, I wanted to make some animated smoke come out of the frogs' rocket ship before the launch. My style is mostly just simple geometric shapes arranged to look like things, so using circular DIV elements to look like puffs of smoke was fine with me. I found a great starting point by Andrea Verlicchi on CodePen, and then modified it for my comic.

Here's the basic idea - puffs of smoke emanate from a given source element. They move downward and off to the side while fading away.

The puffs of smoke will be represented by rounded SPAN elements, with this CSS applied to them:

span.smokepuff {
    display: block;
    position: absolute;
    bottom: -35px;
    left: 50%;
    margin-left: -20px;
    height: 0px;
    width: 0px;
    border: 35px solid #4b4b4b;
    border-radius: 35px;
    left: -14px;
    opacity: 0;
    transform: scale(0.2);
}

The above styling just makes them round, grey, and positioned absolutely in their container. I also have two animation keyframes defined, one for the down-and-left movement and one for the down-and-right movement:

@keyframes smokeL {
    0% {
        transform: scale(0.2) translate(0, 0);
    }
    10% {
        opacity: 1;
        transform: scale(0.2) translate(0, 5px);
    }
    100% {
        opacity: 0;
        transform: scale(1) translate(-50px, 80px);
    }
}

@keyframes smokeR {
    0% {
        transform: scale(0.2) translate(0, 0);
    }
    10% {
        opacity: 1;
        transform: scale(0.2) translate(0, 5px);
    }
    100% {
        opacity: 0;
        transform: scale(1) translate(50px, 80px);
    }
}

The above keyframe definitions define an animation that will move the smoke puffs lower by 80 pixels and 50 pixels to either side while at the same time scaling them up and fading them out. It defines 3 steps: 0% (the start), 10% (moved a little down), and 100% (moved completely down and over). There's one for the left, smokeL, and one for the right, smokeR.

Note: if you care about being compatible with slightly older browsers, you would want copies of these with @-moz-keyframes and @-webkit-keyframes as the names as well as adding -moz-transform and -webkit-transform to them all! I left that out here to keep the example simpler!

I said this was pure CSS3 animation, but there's still a little JavaScript involved. It doesn't really do the animating, but I use some code to generate the puffs in the first place. Something like this:

function createSmoke(time, num) {

    var timeGap = (time / num); 

    for( var i = 0; i < num; i++) {

        var delay = (timeGap * i) + 's';

        var aniName = "smokeL";
        if (((i+1) % 2) == 0) {
            aniName = "smokeR";
        }

        var aniStyle = "animation: " + aniName + " " + duration + " " + delay + " infinite";
        $('#smoker').append('<span class="smokepuff" style="' + aniStyle + '"></span>');

    }

}

When this function is called, you give it the length of the animation and the number of puffs of smoke you want. It figures out how much of a delay there should be between each puff's animation starting based on those two values. For example, if you want the animation to run 5 seconds and have 10 puffs of smoke, the first puff would have no delay, the second would have a delay of ( 5 / 10 ) * 1, the third a delay of (5 / 10 ) * 2, and so on. In this example, that just means add a half-second delay for each puff you generate. Also, each time through the loop, it alternates between the smokeL and smokeR animations so that every other puff moves in the opposite direction. One final piece of the total animation style is to set the repeat-count to infinite, so the puffs keep on coming! The function generates new SPAN tags with these animation styles applied and appends them to the parent element, which here is named smoker. It's just a DIV somewhere on the page - all the puffs of smoke will appear to come out of it.

The finished animation. Don't miss it!

I think the effect turned out great. Even though I used a little JavaScript to create the elements, doing all the animation with JavaScript would have been much, much more complicated. I may consider replacing all the old JavaScript-powered animation on Amphibian.com with CSS animation, and fix up my animation editor to go with it!

Now don't miss the smoke effect in today's comic! If you're reading this on the publication day (16 May 2016) the countdown to launch will be live! That means the last frame of the comic will change and do different things right up to the launch time! Keep watching it!

Amphibian.com comic for 16 May 2016

Friday, March 11, 2016

A Rain Effect Using Only CSS

Today's comic contains something that I've never used before in a comic - CSS3 Animation. The rain effect in the first 3 frames is done purely with CSS! Here's how it works.

All the raindrops in each frame are just DIVs with a color gradient background.

<div class="drop></div>

The CSS style for a drop contains a special property, animation. The browser-specific versions, -webkit-animation and -moz-animation, are also specified to catch older browsers.

.drop {
    -webkit-animation: fall .68s linear infinite;
    -moz-animation: fall .68s linear infinite;
    animation: fall .68s linear infinite;
}

The format of the animation property's value is: <name> <duration> <timing function> <iterations>.

The name of the animation is whatever you want. Mine is called "fall" because that's what raindrops do. I specified a duration of 0.68 seconds, because I played around with it and just liked that duration the best. The timing function here is linear. That means there is no easing of any kind; the drops always move at a constant speed. Finally, I specified "infinite" for the number of iterations. The reasons for these values should make sense shortly...

I gave my animation a name, but I also need to specify what an animation with that name actually does. To do that, you use another CSS directive called @keyframes. (you can also use @-webkey-keyframes and @-moz-keyframes for older browser support)

@-webkit-keyframes fall {
    to {margin-top:700px;}
}

@-moz-keyframes fall {
    to {margin-top:700px;}
}

@keyframes fall {
    to {margin-top:700px;}
}

Here I am specifying that an animation named fall should alter the margin-top property until it reaches a value of 700px. Once that value is reached, one iteration of the animation is considered to be finished. Since I specified infinite iterations above, it means that every time the animation ends it will just reset to the original value and run again. The time it will take to change the margin-top value from whatever it starts at to 700px will be equal to the duration specified earlier.

All I had to do was give the raindrops a random position when I created them, and by animating an increase in their top margin they appear to fall past the bottom of the frame before being reset.

The end result is the beautiful rain effect you can see by clicking the link below and reading today's comic! CSS3 animations can be an easy alternative to JavaScript based animations. They're actually very well-supported by most browsers, even IE 10.

Amphibian.com comic for 11 March 2016

Monday, October 26, 2015

Animate Colors with jQuery

While working on an upcoming comic, I wanted to add a color-change effect to an element. I soon learned that jQuery's animate() function doesn't support animation of non-numeric CSS properties. So while I can animate a width between 100px and 200px, for example, I can't animate a color between #000000 and #FF00FF.

But all is not lost! There is a plugin, appropriately named jQuery Color, which adds the color animation feature. It is trivial to use and extremely small to download.

To start using it, just download the .js file from their GitHub page. I am using the minified version. Include it in your page after jQuery. Then, just animate colors the same way you would animate other CSS properties and it will magically work!

In the following example, the page starts out containing a DIV with a black background. As soon as jQuery is ready, an animation changes the background color to purple over a span of 10 seconds.

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Color Animation</title>
</head>

<body>

  <div id="test-div" style="width: 500px; height: 300px; background-color: #000000;"></div>

</body>

<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="http://code.jquery.com/color/jquery.color-2.1.2.min.js"></script>
<script>

$(function() {

    $('#test-div').animate({backgroundColor: '#FF00FF'}, 10000);

});

</script>

</html>

It doesn't get much easier than that! But what comic prompted me to use this? It's not for today's. You'll just have to wait to find out (or look in the repository on GitHub).

Amphibian.com comic for 26 October 2015

Monday, August 17, 2015

Frog Animations with Phaser

I'm still putting the finishing touches on my 404-page Frog Soccer game. One of the things that I've been putting off is doing the animations for the frogs themselves. I didn't think the code changes would be that difficult, but drawing the frogs in all those positions could be very time consuming. I didn't already have images for the frog jumping toward the viewer and away from the viewer, but now I do. Three hours later...


Anyway, once I had these awesome sprite sheets of frogs jumping in every possible direction, it was time to use them with Phaser. Setting up sprite sheets in the preload function is easy.

function preload() {

    // ... load other stuff ...

    // spritesheets for frog animation
    game.load.spritesheet("frog", "images/frog_ani.png", 79, 60);
    game.load.spritesheet("frog2", "images/frog_ani2.png", 79, 60);

    // ... load some more stuff ...

}

The last parameters to the function calls are the width and height of each image in the sheet. The images actually contain four rows of three frames each, each 79x60, while the overall image size is 237x240. Phaser will break it up for me into individual frames that I can reference in the code.

Also note that I have two separate sheets. In one all the frogs are green and in the other they are all orange. This is another change I am making so it's easier to tell which frog is yours while playing. It could get confusing sometimes.

Now I can add the animations in the create function.

function create() {

    // ... do other create stuff ...

    frog = group.create(940, 400, "frog");
    // ... other frog setup here ...
        
    frog.animations.add("left", [0, 1, 2], 10, true);
    frog.animations.add("right", [3, 4, 5], 10, true);
    frog.animations.add("front", [6, 7, 8], 10, true);
    frog.animations.add("back", [9, 10, 11], 10, true);
    frog.animations.currentAnim = frog.animations.getAnimation("left");
        
    otherFrog = group.create(720, 400, "frog2");
    // ... other otherFrog setup here ...

    otherFrog.animations.add("left", [0, 1, 2], 8, true);
    otherFrog.animations.add("right", [3, 4, 5], 8, true);
    otherFrog.animations.add("front", [6, 7, 8], 8, true);
    otherFrog.animations.add("back", [9, 10, 11], 8, true);
    otherFrog.animations.currentAnim = otherFrog.animations.getAnimation("right");

    // ... more create stuff ...

}

For each color frog, I create four animations. Each row of images in my sprite sheets represents the three frames of a frog jumping while facing a particular direction. The left-jumping frames are in the top row, positions 0, 1, and 2. The right-jumping frames are in the second row, positions 3, 4, and 5. And so on. You get the idea. When adding the animations, the array specifying which frames make up your animation is the second parameter. If your sprite sheet ran up-and-down instead of left-to-right like mine does, you'd just use a different set of numbers. It's flexible. The particular frames that make up a single animation could be mixed up all over the place in your sprite sheet - that would be confusing but you could handle it just by listing them all in the array.

The third parameter is the animation speed in frames-per-second. I am making the opponent a little slower than you in the game, so I use a slightly slower animation speed. The fourth parameter, which I set to true, is whether or not the animation should loop.

Also note that immediately after creating the animations, I set currentAnim to a specific one. If I don't do this, the animation starts out with whatever one was the last created. That could mean my frogs would have their backs to me instead of facing the ball!

Making a particular animation loop play is easy. I could just call frog.animations.play("left") to play the left-jumping loop, for example. It would place until I call frog.animations.stop(). But of course I want the animation to match the direction in which the frog is actually travelling!

The first thought is to set the animation based on which arrow key the user is holding down. That works, but can get tricky. For example, what if both the up and left keys are being held down? Down and right? Down and left? There are a lot of potential combinations and the logic gets deep. And there's one other consideration - the opponent frogs needs animation set and I definitely can't use the arrow keys for that one.

The solution I came up with was to create a function that I could call from within update and pass both frogs as parameters. Using the physics velocity of the frog, I decide if animation should be completely stopped, or which set to play. If the frog is moving diagonally, it will set based on which cardinal direction has the higher velocity.

function update() {

    // ... lots of other stuff ...

    setAnimation(frog);
    setAnimation(otherFrog);

    // ... still more stuff ...

}

function setAnimation(f) {

    if (f.body.velocity.x == 0 && f.body.velocity.y == 0) {

        f.animations.stop(null, true);

    } else {

        if (Math.abs(f.body.velocity.x) >= Math.abs(f.body.velocity.y)) {

            if (f.body.velocity.x > 0) {
                f.animations.play("right");
            } else if (f.body.velocity.x < 0) {
                f.animations.play("left");
            }

        } else {

            if (f.body.velocity.y > 0) {
                f.animations.play("front");
            } else if (f.body.velocity.y < 0) {
                f.animations.play("back");
            }

        }

    }

}

One thing to note about the animations.stop(null, true) function above - the first parameter, where I send null,represents the name of the animation to stop. It is supposed to be optional. The second parameter indicates if the animation should reset to the first frame, and defaults to false. I wanted the frog to go back to the first frame (sitting) but I didn't need to specify an animation name - I just wanted to stop whatever might be playing. Like I said, the first parameter is supposed to be optional according to the documentation, but it didn't work for me unless I explicitly provided the null first argument. Could be a bug.

In the end, I was happy with the results. Both frogs look better jumping around instead of just gliding across the field. You'll be happy with yourself if you read today's comic...and try clicking (or tapping) on the "naked" frog in the third frame.

Amphibian.com comic for 17 August 2015

Friday, July 17, 2015

Speed Based Animation with Phaser

I'm still working on my game for the Amphibian.com 404 page. Initially I had an idea of where I wanted to go with it, but after making a demo of the frog kicking a soccer ball my daughters decided that a frog soccer game would be awesome. Since they outnumber me, I have decided to go with their idea and implement the rest of the game as frog soccer.

The goal for this weekend: add goals.

But before I get to that, I wanted to add a simple animation to the soccer ball. I want to add animation to the frog too, but it's been a busy week. Anyway, I just wanted the ball to spin when the frog kicks it, and the speed of rotation to slow down as the forward motion of the ball slows down.

Here is an animated GIF I created of the game to illustrate what I mean.


So it behaves like a real soccer ball - it appears to roll in a more-or-less realistic manner.

Here's what I had to do in order to achieve this effect.

First, I needed to create a sprite sheet of all the frames of the ball's rotation. I used Inkscape and the GIMP to create a 45x360 pixel image of the ball at different phases of spin. A single frame of the animation is 45x45.

soccer ball spritesheet
Going back to my game code from Wednesday, I replaced the image load for the ball with a spritesheet load which specifies the frame size (line 5 below).

function preload() {

    game.load.image('tree2', 'images/tree2.png');
    game.load.image('frog', 'images/frog.png');
    game.load.spritesheet('ball', 'images/ball_animation.png', 45, 45);

}

I then added another variable for the animation, and put it in the proper scope to be referenced by both the create and update functions. After creating the ball sprite like normal, I create the animation named "roll" by calling ball.animations.add("roll").

var frog;
var tree;
var ball;
var group;
var cursors;
var anim;

function create() {

    group = game.add.group();

    // ... create other sprites ...

    ball = group.create(300, 300, 'ball');
    game.physics.enable(ball, Phaser.Physics.ARCADE);
    ball.body.bounce.set(1);
    ball.body.drag.set(20);
    ball.body.allowGravity = false;
    ball.body.setSize(45, 35, 0, 8);
    ball.body.collideWorldBounds = true;

    anim = ball.animations.add("roll");

    // ... other stuff ...

}

The tricky part comes in the update function. I check and use the velocity of the ball to determine if the animation should be playing and how fast it should run. Look at the code below:

if (ball.body.velocity.x == 0 && ball.body.velocity.y == 0) {
    anim.stop();
} else {
    var speed = Math.min(1, Math.max(Math.abs(ball.body.velocity.x),
                Math.abs(ball.body.velocity.y)) / 200) * 9;
    if (anim.isPlaying) {
        anim.speed = speed;
    } else {
        anim.play(speed, true);
    }
}

If the ball has no velocity on either the x or y axis then it is not moving at all. In that case, stop the animation. Otherwise, I calculate the animation speed. In Phaser, animation speed is specified in frames per second and has a minimum value of 1. I want the maximum frame speed to be 9, and I want to use that when the velocity of the ball is equal to or greater than 200. Velocities under 200 will calculate an animation frame rate as a ratio, but not go under 1. A velocity of 100 will result in a frame rate of 4.5, for example. If the animation is already playing, I just change the speed. If the animation is not currently playing, I start it at the calculated speed.

I am very happy with how it turned out.

I know I haven't made this code available on GitHub yet, but I will soon. Like tomorrow. For today, though, just read the comic.

Amphibian.com comic for 17 July 2015

Wednesday, September 17, 2014

Simple Animation

In my web comics, I wanted to be able to take full advantage of the web as a medium. Not like the size between small and large, medium like the singular of media. Like the stuff we use to communicate.

I just wanted a simple and extensible way to make some parts of the comic cells move or change color or things of that nature. I use jQuery which has some animation features, but they are mostly geared towards the changing of CSS properties. I may want to do that sometimes, but not exclusively.

Here's what I came up with.

When I set up a type of animation on an img object, I set a few attributes on it. First, I set animated = 'true' to flag the animated images in a way that's easy to grab them using jQuery. Then I set another attribute that specifies the animation function to use. Something along the lines of animationType = 'flicker' for example. Then I set other attributes specific to that type of animation.

I might end up with some HTML like this:

<div>
    <img src="something.png" />
    <img src="frog.png" animated='true' animationType='flicker' flickerSpeed='1.5' />
    <img src="whatnot.png" />
</div>

I then have a setupAnimation function which performs the initial setup for my animated images. Here is a simplified version of what I use.

function setupAnimation() {

    window.animated = [];

    $("img[animated='true']").each(function(idx, elem) {

        var aType = $(elem).attr('animationType');

        if (aType === 'flicker') {

            // assign a function here. function must
            // be defined somewhere. we can also perform
            // any necessary initialization here.

            elem.aniFunction = flicker;

        } else if (aType === 'something else') {

            // other types can go here

        } else {

            // unknown animation type value
            elem.aniFunction = function() {
                // no op
            };

        }

        window.animated.push(elem);

    });

}

In this function, I am basically searching for all the animated elements, setting their animation functions, and performing any initialization that may need to happen. Then I save them in an array which I can later use to find them without having to use the jQuery selector again. I call this setupAnimation function once when the page is done loading.

As you see above, when the animation type is "flicker" I set the element's animation function to be "flicker." This implies that I have a function named flicker defined somewhere. I like this simple method of assigning a method to perform a certain type of animation because it allows me to easily add new types or modify the internal workings of existing types independent of the HTML. If tomorrow I want the "flicker" animation type to use a new "flicker2" function that I make, I can do that. If I want to totally change how the "flicker" function works, I can do that too.

As a future enhancement, I could have animation types self-initialize and put themselves in a map or something so I could get rid of the if...else if...else block here. Writing code that does not contain if...else statements should be the ultimate goal of every programmer, but I prefer to keep things simple at first and then refactor to better patterns later. I know it might sound like procrastination, but it works. It's a thing I do.

Anyway, once I have the animation set up, I have to kick off some kind of animation loop.

$(function () { 

    var lastTime = null;

    function run(timestamp) {

        window.requestAnimationFrame(function(e) { run(e); });

        var elapsed;
        if (lastTime === null) {
            lastTime = timestamp;
        }
        elapsed = timestamp - lastTime;
        lastTime = timestamp;

        animated.forEach(function (elem, idx) {
            elem.aniFunction(elapsed);
        });

    }

    window.requestAnimationFrame(function(e) { run(e); });

});

I leverage the window.requestAnimationFrame function to ensure smooth animation. The general contract of requestAnimationFrame is that it calls the given callback function and passes a really really accurate timestamp in milliseconds as the parameter. And if you want it to run again, you have to call it again from within the function that it calls. That's why I define a run function that takes the timestamp as a parameter and then call it from an anonymous function declared as the parameter for requestAnimationFrame.

In my run function, I use the timestamp argument to calculate the elapsed time since the last call, and pass that to the aniFunction of the elements in the animated array. The general contract of one of my animation handler functions is that it will receive a single argument indicating the elapsed time in milliseconds since the last call. This elapsed time value can be used to calculate how far an element should move, how much it should change color, if it should toggle its visibility, if it should change to a different image, or whatever else imaginable.

Here is my flicker animation function, so you can get an idea of what I am talking about.

function flicker(e) {

    if (typeof this.timespan === 'undefined') {
        this.timespan = -1;
    }

    if (typeof this.counter === 'undefined') {
        this.counter = 0;
    }

    if (this.timespan === -1) {
        // pick a new timespan value, based on speed
        this.timespan = Number($(this).attr('flickerSpeed')) * 1000 * Math.random();
    }

    this.counter += e;
    if (this.counter > this.timespan) {
        this.timespan = -1;
        this.counter = 0;
        $(this).toggle();
    }

}

It is a fairly simple animation that produces a flickering effect like an old fluorescent light bulb. After making sure that the timespan and counter properties are initialized, I check to see if I need to calculate a new wait time before toggling. It will be a random number between 0 and flickerSpeed seconds. In all cases, I add the current elapsed time to the total counter. If the counter is greater than the last calculated timespan, the element's visibility is toggled and timespan is set to -1 in order that a new timespan will be calculated the next time through.

It all works great, with one small catch. There are still web browsers out there that don't support the window.requestAnimationFrame function. I've found that at the very least, iOS Safari prior to version 6 does not. Since iPhones still running iOS 5 are not that uncommon, I needed to do something to provide them with animation.

The answer was to include a polyfill. A polyfill? Like pillow stuffing? Not quite. Polyfill in this context means "a piece of code that provides the technology that you, the developer, expect the browser to provide natively". That definition is from Remy Sharp, who explains the origin of the term on his blog. I basically had to check to see if the browser already had a requestAnimationFrame function defined, and if not, define it myself. The backwards-compatible solution is to use window.setTimeout and call the given callback function with a single argument representing the current timestamp in milliseconds. Here is what I use:

if ( !window.requestAnimationFrame ) {
 
    window.requestAnimationFrame = ( function() {

        return window.webkitRequestAnimationFrame ||
               window.mozRequestAnimationFrame ||
               window.oRequestAnimationFrame ||
               window.msRequestAnimationFrame ||
               function( callback, element ) {
                   window.setTimeout( function() { callback((new Date()).getTime()); }, 1000 / 60 );
               };

    } )();

}

I originally found that in a Gist written by Paul Irish, but it didn't pass the current timestamp to the callback function. So I added that part and we're all good now. Try it on your first-generation iPad. It will work. I have one. I tried it.

And that, my friends, is how I do simple animation in my web comics. It doesn't actually seem that simple now that I've written it all up, and I even simplified it for this post. Maybe I should refactor?

Amphibian.com comic for September 17, 2014