27th September 2009

Game Input: Polling vs. Events

posted in ActionScript, Flash |

As mentioned, the single "controversial" part of my talk at Flash on the Beach this year was in questioning polling for input in Flash games. In truth, it was hardly controversial. No death threats. No twitter-based lynch mobs. Just that a couple of guys came up to me and politely expressed disagreement later, and we had a conversation about it. But, as said conversations were done later in the evening at the Old Ship, I thought it might be worth discussing in a clearer state of mind.

So the idea is that I said I thought it was better, i.e. more efficient, to use events for keyboard and mouse input, rather than polling. A few people have made keyboard manager classes which allow you to check which keys are down. You can then poll this class to see if the navigation / action keys you are interested in are currently down, and act accordingly. If you are doing this in the game loop, this is going to happen on every frame or interval, and to me, this does not make sense.

To demonstrate this kind of setup, here is a bare bones game class. It's using Richard Lord's KeyPoll class.

Actionscript:
  1. package
  2. {
  3.     import flash.display.Sprite;
  4.     import flash.display.StageAlign;
  5.     import flash.display.StageScaleMode;
  6.     import flash.events.Event;
  7.     import flash.ui.Keyboard;
  8.    
  9.     import uk.co.bigroom.input.KeyPoll;
  10.  
  11.     public class KeyboardGame extends Sprite
  12.     {
  13.         private var keyPoll:KeyPoll;
  14.        
  15.         // view
  16.         private var character:Sprite;
  17.        
  18.         // model
  19.         private var xpos:Number = 200;
  20.         private var speed:Number = 0;
  21.         private var direction:Number = 0;
  22.        
  23.         public function KeyboardGame()
  24.         {
  25.             stage.scaleMode = StageScaleMode.NO_SCALE;
  26.             stage.align = StageAlign.TOP_LEFT;
  27.            
  28.             keyPoll = new KeyPoll(stage);
  29.            
  30.             character = new Sprite();
  31.             character.graphics.lineStyle(0);
  32.             character.graphics.drawCircle(0, 0, 10);
  33.             character.graphics.lineTo(20, 0);
  34.             character.x = xpos;
  35.             character.y = 200;
  36.             addChild(character);
  37.            
  38.             addEventListener(Event.ENTER_FRAME, gameLoop);
  39.         }
  40.        
  41.         protected function gameLoop(event:Event):void
  42.         {
  43.             input();
  44.             update();
  45.             render();
  46.         }
  47.        
  48.         protected function input():void
  49.         {
  50.             if(keyPoll.isDown(Keyboard.LEFT))
  51.             {
  52.                 direction = 180;
  53.                 speed = -5;
  54.             }
  55.             else if(keyPoll.isDown(Keyboard.RIGHT))
  56.             {
  57.                 direction = 0;
  58.                 speed = 5;
  59.             }
  60.             else
  61.             {
  62.                 speed = 0;
  63.             }
  64.         }
  65.        
  66.         protected function update():void
  67.         {
  68.             xpos += speed;
  69.         }
  70.        
  71.         protected function render():void
  72.         {
  73.             character.x = xpos;
  74.             character.rotation = direction;
  75.         }
  76.     }   
  77. }

For the sake of simplicity, this is all in one class, with the view being a sprite with some graphics, and the "model" being a few class variables. The game loop runs on every frame and polls for input, updates the model, and renders the view.

The input method polls the keyPoll class, checking to see if the left or right cursor keys are pressed. If so, it adjusts the direction and speed in the "model". If neither is pressed, direction is unchanged and speed is 0.

The update method simply updates the xpos based on the speed and the render method moves and rotates the character based on the model. Run it, press the left and right keys and the character turns and moves in the right direction. Yay.

So what was I proposing instead? To cut out the polling part. The idea being that the only time you need to handle input is when a key goes down or up. Not on every single frame. So you do something like this:

Actionscript:
  1. package
  2. {
  3.     import flash.display.Sprite;
  4.     import flash.display.StageAlign;
  5.     import flash.display.StageScaleMode;
  6.     import flash.events.Event;
  7.     import flash.events.KeyboardEvent;
  8.     import flash.ui.Keyboard;
  9.  
  10.     public class KeyboardGameNoPoll extends Sprite
  11.     {
  12.         // view
  13.         private var character:Sprite;
  14.        
  15.         // model
  16.         private var xpos:Number = 200;
  17.         private var speed:Number = 0;
  18.         private var direction:Number = 0;
  19.        
  20.         public function KeyboardGameNoPoll()
  21.         {
  22.             stage.scaleMode = StageScaleMode.NO_SCALE;
  23.             stage.align = StageAlign.TOP_LEFT;
  24.            
  25.             character = new Sprite();
  26.             character.graphics.lineStyle(0);
  27.             character.graphics.drawCircle(0, 0, 10);
  28.             character.graphics.lineTo(20, 0);
  29.             character.x = xpos;
  30.             character.y = 200;
  31.             addChild(character);
  32.            
  33.             addEventListener(Event.ENTER_FRAME, gameLoop);
  34.             stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
  35.             stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
  36.         }
  37.        
  38.         protected function onKeyDown(event:KeyboardEvent):void
  39.         {
  40.             if(event.keyCode == Keyboard.LEFT)
  41.             {
  42.                 direction = 180;
  43.                 speed = -5;
  44.             }
  45.             else if(event.keyCode == Keyboard.RIGHT)
  46.             {
  47.                 direction = 0;
  48.                 speed = 5;
  49.             }
  50.         }
  51.        
  52.         protected function onKeyUp(event:KeyboardEvent):void
  53.         {
  54.             if(event.keyCode == Keyboard.LEFT || event.keyCode == Keyboard.RIGHT)
  55.             {
  56.                 speed = 0;
  57.             }
  58.         }
  59.        
  60.         protected function gameLoop(event:Event):void
  61.         {
  62.             // input by events
  63.             update();
  64.             render();
  65.         }
  66.        
  67.         protected function update():void
  68.         {
  69.             xpos += speed;
  70.         }
  71.        
  72.         protected function render():void
  73.         {
  74.             character.x = xpos;
  75.             character.rotation = direction;
  76.         }
  77.     }
  78. }

Here, we add event listeners for key up and key down. On key down, we check which keys is being pressed, and update the model accordingly. When either of the special keys is released, set speed to 0.

So, no input method, but update and render are exactly the same.

Now, when a key is being pressed, it's going to get multiple, repeated key down events, so you might say this is basically just polling anyway, even if only when the key is down. Yes, but it's not like that is just a substitution for the polling in the first version. Actually, if you look in the KeyPoll class, or any other similar keyboard manager class, you are going to find an event listener for key up and key down. And just like this version, those are going to be run repeatedly when a key is held down. So the polling in the first version is ON TOP of that repeated key event stuff, which is going to happen regardless.

Problems, and a Comprimise

Even in this simple example, however, a problem can soon arise: in the non-polling version, you could run into this situation:

1. User presses right key and holds it. Character starts moving right.
2. User presses left key and holds it, while still holding right key. Character starts moving left.
3. User releases either key, while still holding the other. Character stops, even though one of the action keys is still down.

This would not happen in the polling version.

If this kind of problem happens in such a simple example, you are bound to run into it in many other forms in more complex input schemes. So it's likely that you will have to start adding some additional logic to address it. My initial response was to create a leftKeyDown and rightKeyDown property, set these to true in the key down handler, and false in the key up handler and check the value of both to see if speed should be 0:

Actionscript:
  1. protected function onKeyUp(event:KeyboardEvent):void
  2. {
  3.     if(event.keyCode == Keyboard.LEFT)
  4.     {
  5.         leftKeyDown = false;
  6.     }
  7.     else if(event.keyCode == Keyboard.RIGHT)
  8.     {
  9.         rightKeyDown = false;
  10.     }
  11.     if(!leftKeyDown && !rightKeyDown)
  12.     {
  13.         speed = 0;
  14.     }
  15. }

Unfortunately, this still breaks. If the user presses and holds right, and taps and releases left, the character will continue to move left. So you could do something ridiculous like this:

Actionscript:
  1. protected function onKeyUp(event:KeyboardEvent):void
  2. {
  3.     if(event.keyCode == Keyboard.LEFT)
  4.     {
  5.         leftKeyDown = false;
  6.     }
  7.     else if(event.keyCode == Keyboard.RIGHT)
  8.     {
  9.         rightKeyDown = false;
  10.     }
  11.     if(leftKeyDown)
  12.     {
  13.         direction = 180;
  14.         speed = -5;
  15.     }
  16.     else if(rightKeyDown)
  17.     {
  18.         direction = 0;
  19.         speed = 5;
  20.     }
  21.     else
  22.     {
  23.         speed = 0;
  24.     }
  25. }

But this is just duplicating what's going on in the key down handler. So I could extract the duplicated code into another method, but I'm starting to feel like I'm unnecessarily complicating the code for the sole reason of avoiding key polling. I don't want to be that guy. There's a beautiful simplicity in the polling version. My main concern is over performance, since the keyboard managers I've seen usually involve array lookups. But looking at Richard's, it's using byte arrays and liberal bitwise operators (almost to the point of obfuscation). So my initial guess is that's not too inefficient. Even so, something about it doesn't sit well with me.

What seems to make sense to me is to create a sort of custom keyboard handler for each game. I've done this in other games and it worked out pretty well. The thing about keyboard managers is they are generic and reusable, and thus have to be able to take note of, store, and retrieve the state of any possible key. So some type of an array or collection is always needed. But for your specific game, there probably at the most a half dozen keys you are really interested in. These can be stored as class properties with getters (or public properties if that's not too taboo for you). These properties can also be named something logical to the game, such as moveLeft, moveRight, jump, shoot, etc. rather than Keyboard.LEFT, Keyboard.SPACE, etc. which makes for more readable code. This also abstracts away lower level stuff into whatever you are interested in. If you wanted to change your keyboard mappings you could do it right there, without changing your external code. Something like this:

Actionscript:
  1. package
  2. {
  3.     import flash.display.Stage;
  4.     import flash.events.KeyboardEvent;
  5.     import flash.ui.Keyboard;
  6.  
  7.     public class InputLayer
  8.     {
  9.         private var stage:Stage;
  10.         public var movingLeft:Boolean = false;
  11.         public var movingRight:Boolean = false;
  12.        
  13.         public function InputLayer(stage:Stage)
  14.         {
  15.             this.stage = stage;
  16.             stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
  17.             stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
  18.         }
  19.        
  20.         protected function onKeyDown(event:KeyboardEvent):void
  21.         {
  22.             if(event.keyCode == Keyboard.LEFT)
  23.             {
  24.                 movingLeft = true;
  25.             }
  26.             else if(event.keyCode == Keyboard.RIGHT)
  27.             {
  28.                 movingRight = true;
  29.             }
  30.         }
  31.        
  32.         protected function onKeyUp(event:KeyboardEvent):void
  33.         {
  34.             if(event.keyCode == Keyboard.LEFT)
  35.             {
  36.                 movingLeft = false;
  37.             }
  38.             else if(event.keyCode == Keyboard.RIGHT)
  39.             {
  40.                 movingRight = false;
  41.             }
  42.         }
  43.     }
  44. }

And the final class implementing it:

Actionscript:
  1. package
  2. {
  3.     import flash.display.Sprite;
  4.     import flash.display.StageAlign;
  5.     import flash.display.StageScaleMode;
  6.     import flash.events.Event;
  7.     import flash.ui.Keyboard;
  8.    
  9.     public class KeyboardGameCustom extends Sprite
  10.     {
  11.         private var inputLayer:InputLayer;
  12.        
  13.         // view
  14.         private var character:Sprite;
  15.        
  16.         // model
  17.         private var xpos:Number = 200;
  18.         private var speed:Number = 0;
  19.         private var direction:Number = 0;
  20.        
  21.         public function KeyboardGameCustom()
  22.         {
  23.             stage.scaleMode = StageScaleMode.NO_SCALE;
  24.             stage.align = StageAlign.TOP_LEFT;
  25.            
  26.             inputLayer = new InputLayer(stage);
  27.            
  28.             character = new Sprite();
  29.             character.graphics.lineStyle(0);
  30.             character.graphics.drawCircle(0, 0, 10);
  31.             character.graphics.lineTo(20, 0);
  32.             character.x = xpos;
  33.             character.y = 200;
  34.             addChild(character);
  35.            
  36.             addEventListener(Event.ENTER_FRAME, gameLoop);
  37.         }
  38.        
  39.         protected function gameLoop(event:Event):void
  40.         {
  41.             input();
  42.             update();
  43.             render();
  44.         }
  45.        
  46.         protected function input():void
  47.         {
  48.             if(inputLayer.movingLeft)
  49.             {
  50.                 direction = 180;
  51.                 speed = -5;
  52.             }
  53.             else if(inputLayer.movingRight)
  54.             {
  55.                 direction = 0;
  56.                 speed = 5;
  57.             }
  58.             else
  59.             {
  60.                 speed = 0;
  61.             }
  62.         }
  63.        
  64.         protected function update():void
  65.         {
  66.             xpos += speed;
  67.         }
  68.        
  69.         protected function render():void
  70.         {
  71.             character.x = xpos;
  72.             character.rotation = direction;
  73.         }
  74.     }
  75. }

Furthermore, you could perform other basic logic on the input before setting the input layer properties. For example, shift plus left key might set a runLeft property to true. Not the greatest example, but the point being you don't need a one to one mapping of keys to Boolean values like you do in a generic manager.

So, am I eating crow? Yes, I guess I am. I still think the event method I originally described would be best, but the complexity you'd need to introduce to make it robust enough to handle all the intricacies would soon outweigh the potential performance benefits. And I'm also saving a bit of face by maintaining my opinion that generic keyboard managers are not a good idea, and offering a bit of a better solution.

Let the discussion begin.

Post to Twitter

This entry was posted on Sunday, September 27th, 2009 at 10:33 am and is filed under ActionScript, Flash. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

There are currently 18 responses to “Game Input: Polling vs. Events”

  1. 1 On September 27th, 2009, Iain said:

    Yummy crow :) I like your new approach much better, but swap movingRight for an x value between 0 and 1, and you can kill the if statement entirely:

    character.x += input.x * 5;
    character.y += input.y * 5;
    character.rotation = input.angle * (180 / Math.PI);

    I’m going to open source my gamepad class very soon so hopefully nobody will have to think about this stuff again!

  2. 2 On September 27th, 2009, Iain said:

    sorry x value should be between -1 and 1 to handle both directions.

  3. 3 On September 27th, 2009, kp said:

    Yeah, Iain, that’s essentially what I meant by saying the properties didn’t have to be key mapped Boolean properties.

    I used something very similar to this on an iPhone game but incorporated touch and accel. So rather than getting a raw touch location, I was able to read the touch as an angle offset from a specific point. Very useful.

  4. 4 On September 27th, 2009, Andreas said:

    Disappointing lack of crow to be eaten actually ;) You make a fair point, and i get it now, but i can’t help but feel that the polling overhead is something worth learning to live with. From my (admittedly simple) performance tests, you’ll need more than a thousand dictionary lookups per frame before you even come close to noticing any actual impact, and dictionary lookups can obviously be replaced for more optimized methods.

    I suppose i want to separate input management from directly altering the model for the sake of order if nothing else, but also for the sake of flexibility. One thing is directional input, where setting properties on a velocity vector on keydown/up is totally doable, but storing things like input buffers for fighting game type applications practically demands a manager of some sort. Esoteric example, but can you handle the Konami code with a purely event based system?

    I suppose it feels as though this event based approach would be something you’d implement as an optimization at the far end of development if you desperately needed those cycles, rather than something you base your entire workflow on.

    Overall, for me at least, a keyboard manager with a fair suite of methods, such as getting a unit vector for the arrow keys and an input buffer of a specified range, as well as aliases for common button functions (jumpButton, fireButton, actionButton, whatever), simply feels more natural to work with during game development. If at any point during the game loop i want to see if conditions for an action are met, i’m free to do so. With your event-driven approach, i get the feeling i’ll constantly be rewriting similar code to solve slightly dissimilar problems.

    So, er, a generic manager i feel is good for general development; a more specialized performance-focused implementation if that level of optimization is needed.

  5. 5 On September 27th, 2009, Key polling, part deux : Electronic Space Nintendo said:

    [...] Peters put up a comprehensive blog post on why he disagrees with generic keyboard managers. It’s well worth reading. I have to admit, i couldn’t even conceive of input events [...]

  6. 6 On September 27th, 2009, Al said:

    I’ve always used something like this, which, when both keys are pressed results in no input:

    function gameLoop(event:Event):void {
    var rotationInput:Number = Number(movingRight) – Number(movingLeft);
    trace(rotationInput);
    }

    Perhaps a bit dirty with the casting (not required in AS2).

  7. 7 On September 28th, 2009, Chris Griffith said:

    Nice post – I’ve always tended towards an approach like you developed with your InputLayer for any kind of action game where you are expecting simultaneous, and possibly conflicting, input. For simpler stuff, like puzzle or word games, I stick with events – it’s way cleaner and easier to disable keyboard input without tampering with any game loops.

  8. 8 On September 28th, 2009, Richard Lord said:

    An independent input layer is definitely the way to go. It’s not just easy for the developer to change the key inputs, but also easier to allow the user to do so.

    However, I would still use the KeyPoll class in my input layer -

    public function get moveLeft():Boolean {
    return keyPoll.isDown(Keyboard.LEFT);
    }

    public function get moveRight():Boolean {
    return keyPoll.isDown(Keyboard.RIGHT);
    }

    It’s just a stylistic preference – the interface to the input layer class is the same so the principle doesn’t change at all.

  9. 9 On September 28th, 2009, Devon O. said:

    Funny – I thought the most controversial part of the presentation was suggesting that model and view should be one and the same for Flash games (at least when dealing with Sprites/MovieClips). Maybe another post…
    Personally speaking, I find polling to be more responsive and use it for more time critical games and save event listening for the less “gotta move now to get outta the way” moments. I wonder though, if you go for the InputLayer approach (as would probably be best), is it really more CPU efficient? Either way, you’re testing for a Boolean during the game loop (inputLayer.movingRight OR keyPoll.isDown(Keyboard.RIGHT)).

  10. 10 On September 28th, 2009, Owen said:

    My keyboard class uses a third approach, in which you register each key and give them callback methods to run when the key is first pressed, when it is held down (the class can be set to handle its own timing or use the game loop) and when it is released. Keys can be grouped in order to allow mutually exclusive inputs, eg left and right. Keys can be disabled individually, by groups or all at once and re-registered easily at runtime. Of course it still uses the keyboard events to detect when keys are pressed and released, but there’s really no way round that!

    I kind of made it as an experiment and it seems to work pretty nicely, but if you can think of any problems with this approach I’d love to hear them :)

  11. 11 On September 28th, 2009, Keith Peters said:

    Devon, yeah, I thought the view/model combo would be more controversial as well, but everyone I talked to was glad I brought it up as a possibility.

    As far as the polling vs. events stuff, I knew I was on shaky ground there, but felt it was worth bringing up. If I had had more time to spend on it, I’m sure I would have presented what I did in this post. Not even sure why I went down that path, as I’m always one to fight back against premature optimization. We all have our fixed ideas I guess.

    But overall, I’m glad it worked out as it did. I have more certainty, a clean architecture, and lots of agreement now. :)

  12. 12 On September 28th, 2009, Keith Peters said:

    Also, if you didn’t see the presentation, just the slides, they may be a bit misleading.

    I’m not out and out advocating collapsing the view and model in games. Just pointing out that it might not be such a sin in many cases. Flash’s rendering system is quite different from something like OpenGL or DirectX. If you are using Sprites or Movie Clips, you just put some content in them and position them and leave them there, move them as needed, etc. So in this case you can wind up with a hierarchy of model objects that has to remain in sync with a nearly identical hierarchy of display objects. Adding new objects or removing them from the model creates complexity in updating the display side of things, and if you are using any kind of display object or bitmap hit testing, then the model has to know about the view, anyway. Thus, having the Sprites and MCs BE the model objects can significantly simplify your architecture. It was mentioned as an idea to consider and not to shy away from it because it’s “wrong” to do that.

  13. 13 On September 29th, 2009, Itai said:

    Why not combine the best of both worlds? you could use the KEY_DOWN event and KEY_UP events to create a count — if that count is greater than 0, run the poll; otherwise, ignore it completely. This way, you don’t need to create a custom keyboard handler for each game like you mentioned above… something like this:

    public class KeyboardGameNoPoll extends Sprite
    {
    // view&model code hidden
    keyPoll = new KeyPoll(stage);
    addEventListener(Event.ENTER_FRAME, gameLoop);
    stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
    stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
    }

    protected function onKeyDown(event:KeyboardEvent):void
    {
    keyCount++;
    }

    protected function onKeyUp(event:KeyboardEvent):void
    {
    keyCount–;
    }

    protected function gameLoop(event:Event):void
    {
    if (keyCount>0) input();
    update();
    render();
    }

    protected function input():void
    {
    //calculate speed for each direction, and combine to get
    //sum of directional speed
    }

  14. 14 On September 30th, 2009, stevenvh said:

    Wouldn’t it be an option to combine polling and events?
    As soon as the user hits the keyboard you catch the event and set the key as pressed. Your controller can catch the same event (or one dispatched by the keyboardmanager). There you can poll what keys are down and update the model/view.

    1. User presses right key and holds it.
    ==> Character starts moving right.
    2. User presses left key and holds it, while still holding right key.
    ==> Left and right are down so character stops.
    3. User releases either key, while still holding the other.
    ==> Character will continue the opposite way

  15. 15 On September 30th, 2009, Grimnick said:

    I usually use something like this:

    if(int(movingLeft) ^ int(movingRight)){
    if(movingLeft) {
    // move left
    } else {
    // move right
    }
    }

    Instead of your suggestion:

    if(movingLeft) {
    // move left
    } else if(movingRight) {
    // move right
    } else {
    // dont move
    }

    I don’t know, maybe your approach has better performance because of my int-casts… I just think it’s cleaner that way :)

  16. 16 On September 30th, 2009, Grimnick said:

    By the way, in your example the left-button has priority over the right-button.
    If you hold down both buttons the player will walk left and skip through the rest of your if-statement.
    This is not an issue in my approach, if you hold down both buttons the player wont move at all (which seems pretty logical to me).

    Oh and sorry for the double-post!

  17. 17 On January 21st, 2010, ben said:

    have you ever programmed games before? it doesn’t look like it. in my experience, polling and events are generally used for different things, becase they each have strengths and weaknesses and neither implementation can solve all possible problems/uses for detecting input. for example in an rpg game i’m making with a friend (in java btw, so sorry, no flash/actionscript here, but the idea is the same) and we use both polling and events for detecting keystate and mousestate changes. without going into to much detail, in java the only way to get input it by events, so we use keylisteners for all keyboard input. then for example toggle buttons, like in our editor, pressing the tilde key toggles rendering the entire map or the current layer we are on. if we used polling here, the toggle button would (and it does, ive tried it) switch back and forth on every call to update(), resulting in flickering as the map changes between rendering modes, and never knowing what state you end up in, as being able to watch and release your finger on the exact 1/60th second interval is rather hard, whereas the key events wait a certain time before repeating the keystroke.
    on the contrary, for moving the map, and by extension, moving ANY player controlled object in ANY game, using events is a poor choice because as we all know (using my rpg as an example, we will assume we are controlled the movement of the characte), if i pushed the up button, the character would jump up the specified player move distance in one frame, which is rather unimpressive and unimmersive. if using an animation between squares, then we are limited to moving to discrete tile square, such as in pokemon and many other games. however, using polling, and checking on every frame which key is pressed down, means we can move the character a little each frame, thus resulting in smooth motion, and all the while we can still play our walking animation if we are so inclined.
    so as you can see, polling and events are used for 2 similar but different things.

    also, the code you posted here (shown below, sorry i dunno how to use code tags here) would never happen, even if you used polling and events simultaneously, like we do in our rpg and other programs. no single key (or any other input event for that matter) should simultaneously use events and be polled. it just makes no sense. even if you needed to use polling and events for the same key, it wouldn’t be in the same part of the program, and so you would write the polling and events parts seperately and not have to worry about clashes.

    protected function onKeyUp(event:KeyboardEvent):void
    {
    if(event.keyCode == Keyboard.LEFT)
    {
    leftKeyDown = false;
    }
    else if(event.keyCode == Keyboard.RIGHT)
    {
    rightKeyDown = false;
    }
    if(leftKeyDown)
    {
    direction = 180;
    speed = -5;
    }
    else if(rightKeyDown)
    {
    direction = 0;
    speed = 5;
    }
    else
    {
    speed = 0;
    }
    }

    nonetheless i program mainly in java and so my comments may not apply to flash/actionscript but looking at your code it is very similar to both the syntax and OO paradigm of java.

  18. 18 On January 26th, 2010, STFU KEY_DOWN! « d-Visions (-o|o-) said:

    [...] I ran into this issue I couldn’t find any information about it, but is partly why Keith is eating crow ;) However in my simple implementation it was easy enough to removeEventListener on KEY_DOWN and [...]

Leave a Reply

Who is reading BIT-101?

Copyright ©2009 by Keith Peters. All rights reserved. This means that you may not reprint or repost the contents of this site without express written permission of the author.


  • Calendar

  • February 2010
    M T W T F S S
    « Jan    
    1234567
    891011121314
    15161718192021
    22232425262728
hoodia order buy Levitra Plus betablockers weight loss information buy pills without a prescription arthritis menopause ambien doses cat's eye health information on cholesterol cialis online order valtrex cheapest phentermine onlin e increase breast size lower blood sugar immediately terramycin which is better cialis or viagra buy cheap cialis reduce cholesterol naturally new blood pressure treatment products for back pain cheapest cialis index will levitra help piroxicam 20 mg order viagra online in germany buy tadalafil online buy levitra onlines how to naturally lower cholesterol buy generic viagra where to buy soma anti allergic drug levothyroxine dogs new hair loss treatmen buy levitra pain meds buy cheap malaria therapy weight loss after baby asthma medications chronic snoring viagra gel prostate cancer cures order viagra cialis alprazolam men health natural cure arthritis immune system support diet medicine cialis approval lipitor effects where can i buy arthritis drugs overactive bladder in men self help weight loss natural cholesterol control ativan medication cialis approval best cure for snoring breast enhancing pills order prozac celebrex pharmacy buy levitra onlines premature ejaculation cure confidence hypnotherapy free stop smoking bust enhance diet weight loss supplements skin fungal infection valium with no prescription viagra with out prescription breast enhancement products alpha blocker medications azithromycin 250mg skin disease chronic heart failure medicines dog care products buying cialis online gerd in children antibiotics to buy my drug store muscle building diet drugs affecting levitra anti anxiety medications really large breast enhancement help for constipation ulcers stomach drugs for high blood pressure selling pet products buy pain medicine viagra online overnight fucidin ointment generic zyrtec prices soft tab cialis smoking treatment dog products online weight loss solution cialis on line blue pills weight loss diet pill nitroglycerin sublingual floxin prevention of heart attack imuran order gasex vermox treatment of depression Viagra On Line buy generic cialis professional tooth whitening kits to buy valium 2mg treatment for hypertension ultram cheapest online stores hair loss products cheap weight loss diovan prescription malaria preventative taurine treating prostate cancer immune system support natural constipation cure phentermine no prescription fast delivery purchase meds without prescription buy plendil diet drug taking viagra after cialis protonix cheapest generic cialis online viagra levitra cialis yohimbe benefits muscle mass gain diet and health products medical treatment for insomnia buy blood pressure meds buy celexa levaquin interactions blood pressure drug skin disorder where can i buy arthritis drugs natural breast enhancer acute pain control online diazepam natural acne remedy antifungal strategies triphala pravachol online how can i stop smoking breast enhancement natural nautral breast enhancement beta blocker medications wellbutrin dosages order viagra cialis lower high blood pressure mass muscle phentermine from canada how to loss weight osteoporosis bone health lipitor use dog medication drug allergies buy diazepam buyviagra cialis phentermine 37.5 mg zestril medication parkinsons treatment generic revatio free nexium cosmetic dentistry tooth whitening avalide generic buy cheap tadalafil uk simvastatin tablets buy cialis online in usa breast pain cat care ovulating clomid medical skin care lines viagra to canada viagra or cialis cheap cialis tramadole buy azulfidine drugs used for cancer ear pain oral ketoconazole raloxifene evista taurine sex with levitra stop smoking today heart failure natural cholesterol control protonix dose oxybutynin 5mg irritable bowel syndrome treatments new treatment for hepatitis c cheap prescription drugs viagra online prescription depression therapy buy sumycin menopause treatment hair loss treatments medication pletal what is a natural antibiotic viagra purchase synthroid tablets generic prilosec lipitor cat health info discount vitamin cholesterol and health bacterial diarrhea weight loss medicine new treatment for depression removing retention fluids diuretic medicines soma 250mg cat anxiety loss weight online pharmacy viagra buy phentermine without a prescription herbs for breast growth cymbalta dosage fast weight loss supplement arthritis menopause levitra online order cheapest place to buy phentermine cold flu medications for nausea buy ultram where pills for acne free weight loss programs help with anxiety improve skin valium 2mg urinary tract health cat urinary tract disease crestor dosage drug zofran calan zyrtec buy nirdosh dosage digoxin buy pain patch acomplia alendronate cialis best price cheap wellbutrin small dog products depression medicine sildenafil dosage dog health depression and anxiety lamictal withdrawal viagra, levitra and cialis online drug buy bone maker strontium cures for hair loss nitroglycerin tablets natural arthritis treatment arimidex buy buy energy patch how to treat a yeast infection viagra herb alternative viagra cialis levitra order sublingual cialis cialis comparison breast lift augmentation seroquel for depression carisoprodol mg new treatment for depression cialis soft tabs safe sleep aid severe leg muscle pain natural weight loss gabapentin medication what is ambien clozapine medication viagra online ordering cures for hair loss free weight loss help buy viagra levitra pet treats order plan b diabetes type 2 phentermine risk ultram er side effects treatment for hepatitis b constipation cures drugs used in treating depression leg pain buy cheap generic cialis anti anxiety meds hypnotherapy for weight loss motilium body building fitness dog skin relieve upper back pain cures for high blood pressure cardura celecoxib Viagra Online Cheap cheap bactrim ambien online lamisil cost infertility meds progesterone clomid osteoporosis hormon urinary tract infection symptoms hypnotherapy for health how to buy viagra online joint pain cure online allegra buy generic cialis uk generic abilify cures for lung cancer new treatments for lung diseases pain meds buy cheap treatment for dry skin disease of the skin nexium drug free stop smoking buy tooth whitening products viagra tablet naprosyn dosage women's fertility male sexual power carisoprodol purchase asthma attack treatment estradiol pills phentermine from canada pet health care hair loss products online astelin generic cheap estrace free weight loss program buy rimonabant relieve lower back pain lexapro prescription new breast cancer drug buying ambien best online viagra scams home scabies treatment hair loss in woman buy generic cialis uk eye drop gabapentin medication amitriptyline uses ultram no prescription natural pain cures buy cla products back pain lowest price generic viagra pain meds buy cheap mg buy phentermine acne skin care cialis rx weight loss and fitness nitrofurantoin buy phentermine without a prescription high blood pressure medicines stop hair loss viagra china use levitra female health coreg dosage carisoprodol price pain relief product breast enlargement depression pills buy how to treat flu home neck pain relief order imitrex online vitamin b-6 cialis soft tabs pharmacy software description of soma buy isoniazid cheap prevacid help ear infections on dog fat burning stop smoking remedies rhinitis treatment chronic pain relief birth control online meds without prescriptions buy lovastatin drug stores penis enlargement without pill cancer medicine buy deltasone cure for throat infection thyroid dogs dosage cipro viagra from uk cheap alcoholism treatment natural cure for constipation paxil cialis 5mg tablets amitriptyline uses topamax drugs lower heart rate drug discount codes dog medicines body fat loss joint pain recurring urinary tract infections ativan information buy drugs online cheap fast valium body building ambien maximum dosage information on valium how to sperm more chlamydia medication dosage buy cialis online viagra chest pain heart fluconazole interaction calcium channel blocker side effects zolpidem dosage online drug stores zelnorm muscle strength fluconazole buy stress gum free weight loss products information on gout low immune system online viagra cialis 20 buy cefixime phentermine from canada gain muscle mass fast lasix side effects buy singulair penis enlargement free natural muscle and joint health viagra online overnight cialis online aceon allergies and asthma diamox side effects weight loss software generic compazine price for tramadol high blood pressure symtoms osteoporosis help treatment severe constipation drug new smoking stop pain relief product xanax online dog health info clonazepam .5mg buy tribulus pregnancy prevention methods allergy hives