Friday, May 14, 2010

Iframe src and a Weird Object

‹prev | My Chain | next›

OK. Let's see if I can get state remembered properly in my (fab) game. Last night I got the fab.js backend ready to accept iframe query parameters describing a player. The first order of business tonight is to get the iframe actually sending said query parameters.

Easy enough. Currently the iframe resource is requested on page load:
<iframe src="/comet_view"></iframe>
I switch to a no-src iframe:
<iframe id="iframe"></iframe>
I only assign a src once the player is identified and when I do so I pass query parameter information that the server can use to link the player with the connection:
  if (kv[0] == 'player' && kv[1]) {
// There is a player
$('#login').hide();

var me = new Player(kv[1]);
$('#iframe')[0].src = '/comet_view?player=' + me.id + '&x=' + me.x + '&y=' + me.y;

player_list = new PlayerList(me);
new Room($("#canvas")[0], player_list);
}
To associate both position and connections with players, I convert the player list to a hash:
var players = {};
I then add players in the fab.js backend (taking advantage of the query-params-to-object app that I wrote last night):
function init_comet (app) {
return function () {
var out = this;

return app.call( function listener(obj) {
if (obj && obj.body) {
out({ headers: { "content-type": "text/html" },
body: "<html><body>\n" })

( // other comet connection initialization );

puts("adding: " + obj.body.id);
players[obj.body.id] = {status: obj.body, listener: out};

}
return listener;
});
};
}
With that working, I would like to keep track of players movements. In the /move app, I add:
  ( /move/ )
( function() {
var out = this;
return function listener( obj ) {
if ( !obj ) out();
else if ( obj.body ) {
broadcast(obj.body);
var status = JSON.parse(obj.body);
update_player_status(status);

}
return listener;
};
} )
Right after I broadcast the new position to all clients, I record it in the fab.js backend with update_player_status. Except I don't. My fab.js server crashes when my player moves:
cstrom@whitefall:~/repos/my_fab_game$ node game.js
HTTPParser.onBody (http:92:23)
Stream.ondata (http:524:30)
IOWatcher.callback (net:307:31)
node.js:748:9
That is not too helpful, but I would speculate that the HTTPParse in the stacktrace indicates that my JSON.parse is failing. With the help of print-stderr debugging, I eventually determine that the obj.body is not a string (although it behaves very much like one). This debugging code:
            puts("typeof"+typeof(obj.body));
puts("id: " + obj.body.id);
for (var prop in obj.body) {
puts("["+prop+"] " + obj.body[prop]);
}
...outputs the following:
typeofobject
id: undefined
[0] 123
[1] 34
[2] 105
[3] 100
[4] 34
[5] 58
[6] 34
[7] 98
[8] 111
...
So obj.body is an object. It is an object but not a player object because it does not respond to id. It also looks like an array... of characters. That is odd. Ultimately, I can cast it into a real string by concatenating it with an empty string:
  ( /move/ )
( function() {
var out = this;
return function listener( obj ) {
if ( !obj ) out();
else if ( obj.body ) {
broadcast(obj.body);
var status = JSON.parse("" + obj.body);
update_player_status(status);
}
return listener;
};
} )
That is a good stopping point for today. Tomorrow, I think I may explore raphaël.js a bit to make the room a bit nicer.

Day #103

No comments:

Post a Comment