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