Monday, September 27, 2010

Better Raphaël Plugins

‹prev | My Chain | next›

Up tonight, I try to get a few more raphaël.js methods into raphael-animate-frames. This plugin for raphael.js cycles through a series of frames, giving the appearance of animating. Additionally, the frames can move together and do other things that normal raphael.js objects can. There are many raphaël things that it cannot do. I am going to start tonight by trying to add an animate() method.

The documentation for animate explains that not all attributes can be animated. I will push that to the extreme and say that only 2 elements can be animated: cx and cy (center x and center y).

Some attributes just do not make sense to be animated. Do the attributes apply to all elements in an animation frame or only some? Actually, reading through the list, I ought to be able to support many eventually, but for now, I just need cx and cy:
Player.prototype.bounce_to = function(x, y) {
this.stop();

var self = this;
this.avatar.animate({cx: x, cy: y}, 500, "bounce");
setTimeout(function(){ self.mid_bounce = false; }, 1000);

this.x = x;
this.y = y;
};
I can get a quick and dirty implementation of that by making animate() a simple wrapper around the translate() method:
    animate: function(new_attrs, ms) {
if (new_attrs.cx || new_attrs.cy) {
this.translate(new_attrs.cx || this.getCenter().x,
new_attrs.cy || this.getCenter().y,
ms);
}
}
I will not get easement by using translate(), but it will suffice for tonight.

Up next, I need animate-frames to support a node attribute so that I can get decent collision detection. That turns out to be relatively easy:
    add: function(frame_list) {
for (var i=0; i<frame_list.length; i++) {
this.list.push(this.draw_object(frame_list[i]));
}
this.node = this.list[0][this.list[0].length-1].node;
}
The this.list[0] references the first frame of elements. Using this.list[0].length-1 gives me the last elment drawn in the frame. This seems a reasonable thing—the last thing drawn in a frame is very likely going to be the most prominent feature which makes it ideal to serve at the node attribute.

With that, I can set a boolean on the node indicating that it is the "player" node. If the player node collides with another player node, then collision detection kicks in:
Player.prototype.attach_avatar = function(avatar) {
var self = this;
this.avatar = avatar;

// ...

avatar.node.is_player_circle = true;

// ...

avatar.onAnimation(function(){
// find the colliding element (c_el)

if (!self.initial_walk &&
!self.mid_bounce &&
c_el.is_player_circle &&
c_el != self.avatar.node) {
self._bounce_away(c_x, c_y);
}
});
};
That is a fine stopping point for tonight. I will pick back up with easing tomorrow.


Day #239

No comments:

Post a Comment