views:

1325

answers:

2

How would I go about telling certain events/animations to fire at a certain time?

I'm trying to make an animated fight scene between a few characters, so what would be the best way to script out their actions like who attacks next and so on?

Here is my sandbox where you can see the 2 left dummies move towards the dummy on the right: http://vilegaming.com/sandbox.x

How would I make the right dummy attack one of the dummies on the left after they attacked him?

I think what I'm really looking for is how would I setup a schedule of events based on time because not all attacks/animations will be right after each other.

+2  A: 

Look into a combination of callbacks and setTimeout. Basically after one attack has finished you can invoke a callback which would invoke a function to fire after x milliseconds.But keep in mind that you only have a single thread to play with therefore timings will be approximate depending on what else is playing out.

For more complex sequences you will need to build some form of event queue (essentially an array that you push and pop event objects) The event object you add to the array can define an event, its timeout, a callback and a callback timeout.

//invoke attack
attack( callbackEvent );

function attack( callbackFn ){

   //attack code

   //invoke callback
   callbackFn && callbackFn()
}

function callbackEvent(){

   //next attack in 5 seconds
   window.setTimeout( function(){
         attack(callbackEvent);
   }, 5000);

}
redsquare
+5  A: 

Given the complex animation behavior you're looking for, I would definately limit rampant callbacks and timeouts.

I would do something like this:

// first define the atomic animation effects

function first_figure_moves_towards_second_figure() {
    // animation calls
}

function first_figure_attacks() {
    // animation calls
}

function second_figure_blocks_attack() {
    // animation calls
}


var animation_script = [
    {
         at_time: 30 * 1000, // 30 seconds
         animation: first_figure_moves_towards_second_figure
    },
    {
         at_time: 31 * 1000, // 31 seconds
         animation: first_figure_attacks
    },
    {
         at_time: 32 * 1000, // 32 seconds
         animation: second_figure_blocks_attack
    }
];

Then have a master function with control of the animation script, like this:

var current_time = 0;

function animate_next() {
    var next = animation_script.shift(),
        time_between = next.at_time - current_time;
    setTimeout(function () {
        current_time = next.at_time;
        next.animation();
        animate_next();
    }, time_between);
}

With this you can define your animations free from a jumble of callbacks, timeouts and intervals - and instead focus on the animation script and the atomic animation building blocks.

Edit after comments:

Note that the names of the functions in the animation script (eg. first_figure_attacks ) are function references - stored for later execution. Adding parameters will make them function calls - executing them immediately.

You can use anonymous functions to add parameters like this:

var animation_script = [
    {
        at_time: 5 * 1000,
        animation: function () { doAttack('left', '#char1', '#char2', 2000); }
    }
];

or maybe more aesthetically pleasing, you can wrap doAttack to return a function reference, like this:

function doAttack(side, c1x, c2x, speed) {
    // animation calls
}

function attackAnimation(side, c1x, c2x, speed) {
    return function () {
        doAttack(side, c1x, c2x, speed);
    };
}

var animation_script = [
    {
        at_time: 5 * 1000,
        animation: attackAnimation('left', '#char1', '#char2', 2000)
    }
];
Magnar
This looks like it works, but I have ran into a problem.. when setting the function to run for "animation", for example "first_figure_moving_towards_second_figure", if the function contains variables it won't run. Or more simply.. "animation: first_figure_attacks" works, but "animation: first_figure_attacks(variable)" does not work.
krissauquillo
I have your script live on the link I posted earlier:http://vilegaming.com/sandbox.x
krissauquillo
adding (variable) to the function name, makes it run immediately - it is no longer a function reference, but a function call. To use parameters, you can wrap an anonymous function around it: function () { first_figure_attacks(variable); }
Magnar
Also note that I edited the animate_next-function to use setTimeout correctly - I somehow always put the time first..
Magnar
Ah, thanks much for clearing all that up. I also noticed another minor bug in your example. The pop() should be replaced with shift(). If I use pop() it goes through the animation_script array in reverse, which results in all the animations happening at 20 seconds (instead of 5, 10, and 20).
krissauquillo
Ahh yes, quite an important detail there. Thanks for a fun brain exercise. :-)
Magnar