Wednesday, September 29, 2010

Workaround and Hacks

‹prev | My Chain | next›

Tonight, I continue working through a new feature in animate-frames plugin for raphaël.js. This plugin iterates through a series of raphaël/SVG frames as the frames move about the paper. I am using this in my (fab) game to draw and animate players as they move about the game room:



I found last night that it is not possible to animate position changes of elements drawn from the path() method (which my players are). I would like to animate collisions between elements.

My plan tonight is to hide all of the frames, then draw a replacement circle that bounces. At the end of the bounce, I will remove the bounced circle and re-show one of the frames. To accomplish this, I add a third parameter to the animate() method in animate-frames—the same parameter that is in core raphaël describing the easing:
    animate: function(new_attrs, ms, easing) {
}
If that argument is not present, I will fallback to the old behavior (strict translation of coordinates). If that argument is present, then I do as I describe above:
    animate: function(new_attrs, ms, easing) {
if (new_attrs.cx || new_attrs.cy) {
var x = new_attrs.cx || this.getCenter().x
,y = new_attrs.cy || this.getCenter().y;
if (easing) {
this.hide_all_frames();
// replace the frames with a circle at the same location
var c = this.paper.circle(this.getCenter().x,
this.getCenter().y,
20);
var self = this;
c.animate({cx: x, cy: y}, ms, easing, function () {
// when the animation of the circle is done, remove
// the circle, move the frames to the end point and show
// the first frame again
c.remove();
self.translate(x, y);
self.show_frame(self.list[0]);
});

}
else {
this.translate(x, y, ms);
}
}
}
That almost works.

The circle appears, but the frames do not disappear. They stick around and keep moving.

After a bit of a search, I track the problem down to the stop() method in the Player class. Specifically, when a player stops (e.g. when it is about to bounce), the raphael object is not being told to stop:
Player.prototype.stop = function () {
//TODO -- re-enable
// this.avatar.stop();

this.x = this.avatar.getBBox().x;
this.y = this.avatar.getBBox().y;
};
Hunh. That's weird. I wonder why it is disabled....

After re-enabling, I find out why it was disabled—there is no stop() method in animate-frames. So I add one:
    stop: function() {
var frames = this.list;
for (var i=0; i<frames.length; i++) {
for (var j=0; j<frames[i].length; j++) {
frames[i][j].stop()
}
}
I really need to break down and create a Frame class. I iterate over frames and frame elements far too often.

I will leave refactoring for another night. For now, I would be happy just to get things working.

Happily, that was the last change needed:

video

I could definitely make that animation a little nicer, but, for a proof of concept it will suffice. Tomorrow, I will prettyfy things a bit—both the animation and the code.


Day #241

No comments:

Post a Comment