I ended up with an uglyish solution for mapping arrow keycodes to movement directions in some Dart code:
HashMap<int, String> _dir;
String keyDirection(int dir) {
if (_dir) return _dir[dir];
_dir = {};
_dir[37] = 'left';
_dir[38] = 'up';
_dir[39] = 'right';
_dir[40] = 'down';
return _dir[dir];
}The private variable _dir was bad form on my part—I was trying to avoid a perceived initialization penalty before I was actually affected by it. So I should have done something like:String keyDirection(int dir) {
var dir = {};
dir[37] = 'left';
dir[38] = 'up';
dir[39] = 'right';
dir[40] = 'down';
return dir[dir];
}In all honestly, even that is not terribly satisfactory. I would prefer to declare dir as:var dir = {
37: 'left',
38: 'up',
39: 'right',
40: 'down'
};Dart, however, does not allow object literal syntax to use integers as keys, so I am stuck with the individual assignments of the directions. And that continues to bother my sensibilities.An astute reader suggest that I forgo the
keyDirect() method entirely. Embracing the object-literal-with-string-key syntax, my key down handler can be written as: document.
on.
keyDown.
add((event) {
String direction = {
'37': 'left',
'38': 'up',
'39': 'right',
'40': 'down'
}[event.keyCode.toString()];
if (direction == null) return;
event.preventDefault();
me.move(direction);
draw(me, context);
});That works and is better than what I had. Still, the actual lookup is obscured too much for my tastes. I would rather it be done via: document.
on.
keyDown.
add((event) {
String direction = _dirMap[event.keyCode.toString()];
if (direction == null) return;
event.preventDefault();
me.move(direction);
draw(me, context);
});I cannot simply declare _dirMap as a global variable:// Fail: not a compile time constant
HashMap _dirMap = {
'37': 'left',
'38': 'up',
'39': 'right',
'40': 'down'
};
attachMover(me, context) {
// ...
}
To make that work, I can make the left hand side of the _dirMap assignment a compile time constant with the simple addition of the const keyword:HashMap const _dirMap = {
'37': 'left',
'38': 'up',
'39': 'right',
'40': 'down'
};
attachMover(me, context) {
// ...
}
This brings me to another facet of the update Dart language spec: lazy evaluation of static variables.In order to try this, I convert my entire game board into a
Room class that includes a static variable version of _dirMap:class Room {
Player player;
CanvasRenderingContext context;
static HashMap _dirMap = {
'37': 'left',
'38': 'up',
'39': 'right',
'40': 'down'
};
Room.play(this.player, this.context) {
this.draw();
this.attachMover();
}
draw() { /* ... */ }
attachMover() {
document.
on.
keyDown.
add((event) {
String direction = _dirMap[event.keyCode.toString()];
if (direction == null) return;
event.preventDefault();
player.move(direction);
draw();
});
}
}My board is still working on load:So maybe this works?
Uh, no. When I make my first move, I am greeted with the follow exception:
Internal error: 'file:///home/chris/repos/dart-book/book/includes/animation/main.dart': Error: line 37 pos 28: initializer must be a compile time constant
static HashMap _dirMap = {
^So it seems that despite the spec, static variables are still unlazily evaluated. I add const to the Room class:class Room {
// ...
static HashMap _dirMap = const {
'37': 'left',
'38': 'up',
'39': 'right',
'40': 'down'
};
// ...
}And call it a night.I am not too fussed by this. I would have been cool if this had made it into Dartium, but this means less work is needed to make a proper first release of Dart for Hipsters.
Day #398

No comments:
Post a Comment