Thursday, May 20, 2010

Moving Sets in Raphaël.js

‹prev | My Chain | next›

Things are going fairly well with my (fab) game. My fab.js backend is doing most of what I need it to (keeping track of players, dropping idle players). My frontend is working fairly well in raphaël.js as well. Tonight, I would like to see if I can attached a name to players in the game room (right now, they are just dots).

Raphaël's set() seems like a good option. Currently, the Room is drawing the player with Raphaël's circle() and returning that to be moved as the Player moves about the room:
Room.prototype.draw_player = function(player, color) {
var c = this.paper.circle(player.y, player.x, 3);
c.attr({fill: color, opacity: 0.5});
return c;
};
The set() method groups elements together. So let's try grouping this circle with a text element just below it:
Room.prototype.draw_player = function(player, color) {
var st = this.paper.set();
st.push(
this.paper.circle(player.x, player.y, 3),
this.paper.text(player.x, player.y + 10, player.id)
);
st.attr({fill: color, opacity: 0.5});

return st;
};
Trying that out in the browser it works!:



It works... but only up to a point. When I try to move this set with the same animateAlong() method, nothing happens. Digging through the raphaël.js source code a bit, it seems that only animate() was implemented for sets. I would hazard a guess that it is difficult to animate a bunch of arbitrary objects along a path, which is why this is not part of raphaël.js yet. Still I really would like this feature.

For now, I am going to fall back on a terrible hack. Hopefully I can come up with something better in the future, but...

I revert my set code. Instead, when the Player is handed its "drawable" circle() I add a second object 10 pixels below (y-pixels increase down the page):
Player.prototype.attach_drawable = function(drawable) {
this.drawable = drawable;
this.label = drawable.paper.text(this.x, this.y + 10, this.id);
};
Here, I am using the paper attribute that the cirle() drawable (and any raphaël.js element) has.

With a label now an attribute on Player, I need to animate the label along a path 10 pixels below the path the Player walks:
Player.prototype.walk_to = function(x, y) {
var p = "M"+ this.x + " " + this.y +
"L" + x + " " + y;
this.drawable.animateAlong(p, 3000);

var pl = "M"+ this.x + " " + this.y + 10 +
"L" + x + " " + y + 10;
this.label.animateAlong(p, 3000);


this.x = x;
this.y = y;
};
And, when the Player stops, I need to stop the label as well:
Player.prototype.stop = function () {
this.drawable.stop();
this.label.stop();
this.x = this.drawable.attrs.cx;
this.y = this.drawable.attrs.cy;
};
I am not at all satisfied with this solution but it does work:



I will stop there for the night and ruminate on how I might do this better tomorrow. Maybe onAnimation()?

Day #109

1 comment:

  1. Thanks for posting this, it helped me quite a bit with my own explorations of animating sets.

    ReplyDelete