Thursday, June 10, 2010

Functional Troubleshooting

‹prev | My Chain | next›

Up tonight, I need to fix a bug when multiple players are in the room. When I first log in as a new player, my avatar has wandered off:



If I click to move in the room, my player zips up from the bottom right corner. Oddly enough, the first player to enter the room, and hence the first player broadcast by the server, is drawn correctly. All other players wander off. Again, oddly, their labels, which should be tied to their positions are where they are supposed to be.

After much searching I track the problem down to the Player.walk_to client side method. I suspect that the distance calculation that I added recently is throwing off the timing of various callbacks, resulting in an incorrect value:
Player.prototype.walk_to = function(x, y) {
var p = "M"+ Math.floor(this.x) + " " + Math.floor(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;
};
To try to prove it, I add some console debugging to see what the Player thinks its x-y coordinates are and what the raphaël.js circle / avatar thinks the center x-y coordinates are:
Player.prototype.walk_to = function(x, y) {
var p = "M"+ Math.floor(this.x) + " " + Math.floor(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 );
console.debug("id: " + this.id + ", x : " + x + ", y: " + y);
console.debug("id: " + this.id + ", x : " + this.x + ", y: " + this.y);
console.debug("id: " + this.id + ", cx : " + this.avatar.attrs.cx + ", cy: " + this.avatar.attrs.cy);
console.debug("id: " + this.id + ", x_diff : " + x_diff + ", y_diff: " + y_diff);
console.debug("walk: " + p + ", distance: " + distance + ", time: " + time);
this.avatar.animateAlong(p, time);

this.x = x;
this.y = y;
};
Unfortunately, this tells me nothing of use. The Player and raphaël coordinates always match up.

I struggle with for a long time (the sheer number of debug statements already in there should be a indicator for that) before realizing that the coordinates might align when the code is first evaluated, but could change very shortly thereafter. So I add a setTimeout to evaluate the same debugging after 100 milliseconds:
Player.prototype.walk_to = function(x, y) {
var p = "M"+ Math.floor(this.x) + " " + Math.floor(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 );
console.debug("id: " + this.id + ", x : " + x + ", y: " + y);
console.debug("id: " + this.id + ", x : " + this.x + ", y: " + this.y);
console.debug("id: " + this.id + ", cx : " + this.avatar.attrs.cx + ", cy: " + this.avatar.attrs.cy);
console.debug("id: " + this.id + ", x_diff : " + x_diff + ", y_diff: " + y_diff);
console.debug("walk: " + p + ", distance: " + distance + ", time: " + time);
this.avatar.animateAlong(p, time);

var self = this;
setTimeout(function() {
console.debug("id: " + self.id + ", x : " + x + ", y: " + y);
console.debug("id: " + self.id + ", x : " + self.x + ", y: " + self.y);
console.debug("id: " + self.id + ", cx : " + self.avatar.attrs.cx + ", cy: " + self.avatar.attrs.cy);
console.debug("id: " + self.id + ", x_diff : " + x_diff + ", y_diff: " + y_diff);
console.debug("walk: " + p + ", distance: " + distance + ", time: " + time);
}, 100);

this.x = x;
this.y = y;
};
With that, I finally find my discrepancy. That is one of the troubles with heavily functional code, sometimes problems are not immediately evident. I do think I will add the setTimeout debug statement to my bag of Javascript tricks.

I devise a simple hack to resolve this issue, but I think a bit of refactoring is in order to make the code less susceptible to woes like this in the future. I will pick up with that tomorrow.

Day #130

No comments:

Post a Comment