Saturday, June 5, 2010

Constant Speed Raphaël.js Animations

‹prev | My Chain | next›

Today, I would like to make player movements in my (fab) game a bit more consistent. Raphaël.js allows you to set the duration for an animation, but not the speed. This means that it takes a player 3 seconds to walk from the top left all the way to the bottom right and it takes a player 3 seconds to walk 2 pixels to the left. That's just annoying.

The maximum distance a player can walk in my (fab) game is from top-left (0,0) to bottom-right (500,500). According to Pythagoras:



Or:



I am not going to bother calculating the square root, however. Instead, I will calculate the sum of the squares and compare that to the sum of the squares of the maximum walking distance that can be traveled (from 0,0 to 500,500). The percentage is then multiplied against the maximum walk time (3 seconds):
Player.max_walk = 500*500 + 500*500;
Player.time_to_max_walk = 3 * 1000;


Player.prototype.walk_to = function(x, y) {
var p = "M"+ this.x + " " + this.y +
"L" + x + " " + y;

var x_diff = x - this.x;
var y_diff = y - this.y;
var distance_squared = x_diff * x_diff + y_diff * y_diff;
var time = Player.time_to_max_walk * ( distance_squared / Player.max_walk );

this.avatar.animateAlong(p, time);


this.x = x;
this.y = y;
};
Nice, right?

Well no. The movement is completely wrong. Long distance motion seems OK, but short distance moves way too fast. Sigh. Maybe I do need the distance rather than the sum of the squares. Let's see how the percentages compares:e
(x,y)x2 + y2Percentage of 102 + 102Distance from (0,0)Percentage of Distance to (10,10)
(1,1) 2 1% 1.41 10%
(5,5) 50 25% 7.07 50%
(10,10) 200 100% 14.14 100%
Well, that explains it. The (5,5) point should be half-way to (10,10), but it is only 25% of the way along the sum of the squares.

Sadly, I will have to incur the overhead of calculating the square root each time the player moves. Yeah, yeah, it is not much overhead. At the risk of over analyzing here, I am not sure if this counts as premature optimization as the square root would have been an extra code. I think I will give myself a pass on this one, especially since I legitimately did not think it was needed.

So I switch to using the actual distance when calculating the time:
Player.max_walk = Math.sqrt(500*500 + 500*500);
Player.time_to_max_walk = 5 * 1000;

Player.prototype.walk_to = function(x, y) {
var p = "M"+ this.x + " " + this.y +
"L" + x + " " + y;

var x_diff = x - this.x;
var y_diff = y - this.y;
var distance = Math.sqrt(x_diff * x_diff + y_diff * y_diff);
var time = Player.time_to_max_walk * ( distance / Player.max_walk );

this.avatar.animateAlong(p, time);

this.x = x;
this.y = y;
};
With that, my player moves around the room at a nice, constant speed:

video

Up next: something small. I think tomorrow may be a busy one for me.

Day #125

No comments:

Post a Comment