5th November 2009

Gravity Pods one of the “Best 20 Internet Flash Games” according to Telegraph

Read it here:

http://www.telegraph.co.uk/technology/video-games/6461245/The-20-best-internet-Flash-games-from-Doom-to-Stick-Cricket.html

Coming in at 11:

11. Gravity Pods

A simple concept – use a gun to fire a pellet into a target. But the pellet’s path is deflected by little gravity pods. Use them to guide the pellet around barriers and into the target.
We got stuck on Level 9, but we had other games to review. We’re sure you can do better.

Play the game itself here

And when you are done with that, play Gravity Pods 2 here!

posted in Flash | 1 Comment

1st November 2009

The iPhone App Store Approval Line is Doomed

The first app I submitted to the app store back in January was approved in something like 3 days.

As the year went on, that figure went up to around a week, 10-12 days, two weeks, over two weeks.

I have people telling me now that they are experiencing waits of up to 20 days. So my guess is that by the end of the year, we’ll be topping 3 weeks.

Now, I assume that it doesn’t take 3 weeks of testing to see if an app is approvable. In other words, some QA dude doesn’t sit down with it and work on it every day for weeks. Or it doesn’t go through a line of something like 20 people, who each have one day to do their thing with it. And I doubt they do some kind of stress test where they install and run it on a phone and leave it running for a few weeks to see what happens.

My guess is that it takes maybe half an hour to approve or disapprove an app. Maybe more, maybe less. Even if you are ridiculously gracious and say it takes them half a day per app, what accounts for the 3 weeks wait? It’s obvious – there’s a backlog.

So when you submit your app for approval, it goes into a queue. That queue is so damn big that it takes all the Apple approval techs working full time up to three weeks to even getting around to looking at your app.

Backlogs are funny things. Generally, if you have a backlog, it grows. Why? Theoretically, backlogs can either grow, remain the same, or diminish. But if is diminishing, it’s because you are handling things faster than they are coming in and catching up on the backlog. If it is staying the same, it’s because you are handling things at the same rate they are coming in (but not catching up). But the very fact that you have a backlog in the first place indicates that things are coming in faster than you are handling them. So unless you’ve drastically changed how fast you work, or the amount of things coming in drastically reduces, it’s going to continue to grow.

The app approval backlog has steadily grown all this year. That indicates that it’s only going to get worse and worse, because the fact that it is growing shows they are falling behind more and more. Furthermore, the number of overall apps being submitted is increasing. And even worse, every app in the store means potentially several updates, which go through the same approval line. So I predict it’s going to get exponentially worse.

The only solution is to drastically change the way the approval process works. I don’t know how it works, so I can’t particularly say how to improve it. But I hope Apple is doing SOMETHING. At the rate it’s going it’s going to mean multiple month wait times for app approval by some time next year, which is no way to run a business.

posted in iPhone | 23 Comments

1st November 2009

Ebook Formats

As I’m considering picking up a Nook next month, I’ve been thinking about the possibility of transferring my Kindle books over to it. This has led me to do a bit of research into ebook formats.

First of all, we have the Kindle format, .azw, which is actually just a slightly modified version of the Mobipocket .mobi format with some changes to the DRM and the way the serial number is stored.

And how about the Nook? It supports eReader .pdb and EPUB .epub formats (as well as PDF, but that’s a bit different).

So, how to turn an .azw into an .epub or .pdb ? Well, first you need to turn the .azw into a .mobi. This can be done with the free tool called MobiDeDRM. I have no idea how legal this tool is, so I’m not going to directly link to it or tell you how to use it. But there’s this site called Google that should help you find out all you need to know about it. But I will say that it’s a Python based, command line tool. No fancy UI or anything, but all in all, not too difficult to use. The result is a non-DRM .mobi version of your book.

I’ve actually been using MobileDeDRM for a while, for a couple of reasons:

1. The whole thing where Amazon went and deleted books from users’ Kindles made me want to have a non-Kindle backup.

2. Occasionally I like to use the text-to-speech feature, and this is disabled on many books. By converting it to a .mobi you can get the text-to-speech back, but this sometimes requires some other steps, which I’ll cover below.

Note, I’m not advocating removing DRM for any kind of illegal purposes, such as sharing, torrenting, reselling, or otherwise ripping off the publisher/author/Amazon. But I do believe you have a right to personally use your own purchased content in the way you want, including listening to it, viewing it on another device, and protecting it from being deleted.

Anyway, now you have a non-DRM, .mobi version of your Kindle book. There are two free tools you can use at this point to convert it to something Nook-ready.

1. Calibre. This is a hard core ebook conversion tool. It reads a number of different formats, and though it only ouputs to three (.mobi, .lrf, .epub), it gives you all kinds of options on how to convert, including editing of metadata, look and feel, page layout, chapter detection, and bulk conversion. Generally, the defaults work pretty well. Calibre also deals with images in ebooks pretty well and has some other neat features I haven’t even tried, such as converting RSS feeds to ebooks, and direct device integration.

2. Stanza. This is actually a desktop ebook reader application, but once you load up your ebook into it, you can export it into something like 16 different formats, including .epub and .pdb. The one thing Stanza doesn’t do so well is images. And by “doesn’t do so well” I mean it ignores them. At least in the version I’m using. Not sure if they’ve improved that or plan to. But mainly it’s good for straight text.

So, using either of these tools to convert the .mobi to either .epub or .pdb, you should be able to view these books on a Nook. I did convert a Kindle book down to a .pdb via Stanza and tested it on the Barnes and Noble desktop ebook reader, and that worked fine, which is promising.

As far as enabling text-to-speech, in the few I tested, I converted the Kindle book to .mobi with MobiDeDRM and put that back on the Kindle. While it worked fine, the text-to-speech was still disabled. I think what I did was open up the .mobi in Stanza and re-exported it as another .mobi and put that back on the Kindle, and voila, text-to-speech re-enabled. Unfortunately, this kind of threw off the formatting of the book a bit. The text seemed a lot more squished together. Might want to try that with Calibre, which gives you more control over stuff like that.

At any rate, I think it’s cool to know about all these different formats and how to convert them. Even if you don’t plan to get a Nook or Kindle, you might have another device you want to read books on, with the eReader software, for example. That also takes .pdb files, so the techniques here should work the same way.

More info on various ebook formats here: http://en.wikipedia.org/wiki/Comparison_of_e-book_formats

posted in General, Kindle, Technology | 1 Comment

29th October 2009

Buy me for $10

Well… buy my book.

Today only (Thursday, October 29, 2009). AdvancED ActionScript 3.0 Animation, only $10 (ebook version).

http://www.friendsofed.com/dotw/index.html

posted in ActionScript, Flash | 11 Comments

25th October 2009

Barnes and Noble Nook

It was just about a half a year ago I bought my Amazon Kindle 2. Six months later and I still love it. It’s a one trick pony, but hey, who doesn’t love ponies? Seriously, it’s just great at what it does. My Kindle’s index is about nine pages long, full of books I’ve read, books I plan to read, books that are partially read samples that I might take a look at some time, and articles saved through my own KClipper application. I know there are a lot more features it could have, but when you are reading a book, all those wished-for-but-nonexistent-features just seem to disappear.

So last week I caught wind of the hottest new competitor to hit the market. Or at least to be announced on the market, the Barnes and Noble Nook:

nook_front_view

After laughing a bit about the name, I started watching the videos and checking out the specs. It looks pretty good on paper (or in the web browser to be accurate). If it’s close to as good as it seems to be, I’ll probably pick one up.

Features that have me interested:

  • Additional storage through a micro SD slot. Not sure why this is cool, since I’m nowhere near the 2GB storage on my Kindle. But good to have the option. Also, you can use it to transfer files to the device.
  • Removable battery. Batteries don’t last forever. Nice to be able to replace it without sending the whole unit in. Then again, the way technology moves, battery life probably outlasts how long you own any one device before upgrading to the next big thing. I mean, six months and I’m already considering giving up my Kindle. :)
  • Wifi as well as 3G. I assume that means you can transfer stuff to the device over wifi. Good if you don’t always carry that sync cable with you everywhere. Also cool you live in an area with really bad 3G coverage.
  • Another one of the hooks of having wifi is that if you are physically IN a Barnes and Noble store, you can get access to exclusive content only available on the free B&N wifi. Not sure what that is, but apparently there are also in-store discounts you can take advantage of, and coolest of all is that eventually you will be able to read entire books in-store without buying them. Fantastic if you live near a Barnes and Noble. It becomes a library. [edit - though on second thought, you can just do that with regular books in a bookstore as well. And I've never done it. :) I still think it's cool though.]
  • Personalized screensavers. Not that I don’t respect the selection of famous authors Amazon has supplied us with, but I sometimes get a bit self conscious when I pull my Kindle out on the train and look like some kind of Emily Dickinson and Oscar Wilde fanboy. I know there’s a hack to use your own photos on the Kindle, but from what I understand, all those hacks have to be removed in order to install firmware updates. Too much trouble.
  • Native PDF support. Say no more.
  • And of course that nifty little color touch screen display on the bottom. Gimmicky perhaps, but seriously, anything has to be better than the e-ink/joybutton navigation on the Kindle. Well, who knows. Maybe they screwed it up royally and made something worse, but you have to hope.

Things that I don’t care about so much:

  • The whole lending thing. This also pretty gimmicky. I suppose if I had a bunch of friends with Nooks, and we had similar tastes in books, it could be fantastic. But I’m guessing I probably won’t use that feature very often.
  • They are making a huge deal about the line of covers available for it, but Kate Spade and Jack Spade. Yeah, covers are nice, but they are pushing them way too hard. Wrong focus.

Things that concern me:

  • Performance. Both of the e-ink display and the color touch screen. The e-ink page refresh in the main video (”Hi I’m Katy and this is my Nook”) appears to be noticeably slower than the Kindle. And the scrolling and animation on the color screen looks pretty choppy. Hard to tell though, because all you are seeing is a compressed on-line video of a pre-release device. So I’m trying to withhold judgement there. However, I’ve read a number of blogs and reports from people who were at the event(s) where the Nook was shown, and all said that the B&N people would let no one touch the thing or experience it hands-on. Speculation is naturally that it just wasn’t ready for prime time – either buggy or slow.
  • Um… I guess that’s about it.

So I would say that there’s a good chance that I’ll be a Nook owner come the beginning of December. I’m not preordering though. Still concerned about how the thing actually works in real life. Luckily, Barnes and Noble is a real brick and mortar store and will have displays where you can see and touch and interact with a real Nook in-store once they are released. I’ll hold out til I get my hands on one and read the reports of the early adopters.

posted in General, Kindle, Technology | 7 Comments

20th October 2009

101101 years old

Today is my birthday. I am 101101. How cool is that?

posted in General | 24 Comments

15th October 2009

Comment Policy

This comes up now and then: people think I am not going to post their comment because they disagree with me, or thinking I didn’t post their comment because it didn’t show up after a certain amount of time.

So here’s the deal:

1. I have the Akismet comment spam plugin on this blog. If it thinks your comment is spam, I’ll never see it. Generally I think it’s pretty spot on, and have not heard of a single instance on this blog where someone’s valid comment was incorrectly labeled as spam by Akismet, but I suppose it’s possible.

2. If you have never commented here before, or use a different name / email address on the comment form than you used previously, your comment will be held in moderation. I will get an email immediately. I might approved it immediately. More likely however, it will sit in my in box for a period of a few hours to a day or two. Potentially longer. Sorry. I’m lazy.

3. Once you have had a comment approved, you go into the approved posters list. When you post another comment with the same name and email address, it should go straight through. This is all standard WordPress stuff.

4. Even after Akismet does its filtering, I still get a lot of obvious spam/phishing type comments. Naturally, these get marked as spam manually, by me, not approved.

5. Occasionally there are some comments where I’m not quite sure if it’s a spam/phishing thing, or a real comment. Usually some utterly generic comment on some old post: “Great post. Thanks!” – on something I posted 2 years ago, for example. If I approve something from someone who turns out to be a spammer, then they will be on the approved posters list and will be able to spam the blog, so if there’s any doubt, I usually just delete the comment. That way if the poster was valid, he or she will not be blacklisted and can post again.

6. Other than those cases, I generally approve every post. Even if you disagree with what I’m saying, even if I disagree with what you are saying, even if I think you are an obnoxious jerk, even if you think I am an obnoxious jerk. Obnoxious jerks often have something useful to say, even though they say it obnoxiously and jerkily. In the close to six years I’ve had this blog up, I can only recall two cases where I actually censored someone’s comments. In both cases the comment was just completely abusive and had no editorial value whatsoever.

In short, if you have something to say, and you post it as a comment here, it’s going to appear, eventually. If it doesn’t after a day or two, try again or email me. You don’t have to goad me on with, “You probably won’t post this but…” or repost your comment 3 times because it’s not showing up.

posted in General | 4 Comments

13th October 2009

My thoughts on Flash CS5 and iPhone

I’ve been holding my tongue on this since the announcement, and slowly putting my thoughts together in what I hope is not considered to be a knee jerk reaction.

First of all, a big dose of respect to the engineering team that made this happen. You guys are God-like. I think it’s an amazing feat of technology that you got this working to the point where apps developed in Flash not only run on an iPhone, but were submitted to and accepted by the app store. So anything negative I say is not in any way directed to you guys. Unfortunately, technical awesomeness does not always directly correlate with practical usefulness. God knows I’ve created some things that I considered pretty cool feats of technology, but that were absolutely useless in the long run.

My first reaction on hearing the announcement was that people were going to be awfully disappointed. Yes, it’s an amazing announcement and everyone was very excited about it. But remember when you were a kid and you saw all those commercials on TV for such and such a toy, and you waited and waited for your birthday or Christmas or whatever, tingling with excitement, and then you opened it up and started playing with it and realized that after all, it was just a cheap piece of plastic, with only a fraction of the awesomeness you envisioned? That kind of disappointment. I expected that for one, that disappointment would be in the APIs. The iPhone has a rich set of APIs and Flash has its own rich set. I expected a small subset of both. To my surprise, Adobe has actually done a really good job of getting most of what’s in Flash functioning on the iPhone, and most of what’s natively available on the iPhone accessible from Flash. I haven’t used them yet, but from the way they were described, they seem surprisingly complete. So again, more respect on that end.

However, I still think people are going to experience that Christmas morning disappointment when they start working with this, based on performance. Take a look at the resources Adobe has listed on Labs and the recorded MAX session. And check out the apps that have been released. Almost all of them have comments complaining about performance – slow, choppy graphics and animations, unresponsive UIs, etc. From my own observations, those of others, and even from those who created them, the consensus is that they are very choppy on an iPhone 3G, somewhat better on an iPod Touch 2nd Gen, and “acceptable” on an iPhone 3GS or the latest iPod Touch.

Personally, out of the several apps I have tested on my iPhone 3G, none of them are at the level where I would have released them. Now this isn’t necessarily a bad thing in itself. There are other high performance 3D racing and sports games that take advantage of the advanced features of OpenGL ES 2.0 and therefore require a 3GS. But the things that are choppy and not performing well are the simplest of simple animations and transitions. These are not the kinds of apps and games that should require lots of processing power. If you’re going to specify that your game requires the highest end hardware to function adequately, that carries with it the concept that it is using that hardware’s extra power to deliver an over the top experience. To demand the top end processor just to make simple animations not look like crap is not acceptable.

Now, of course, this is a very early beta or even alpha of a brand new, budding technology. I have NO doubt that it is going to improve. I do have doubts on how much it is going to improve. I would assume or at least hope that it would get to the point where the games such as have been released are at least acceptable on an iPhone 3G.

But my initial point was that people are going to be disappointed. Yes, if Adobe pulls it off, you’ll be able to do some basic animations that perform relatively well, but as soon as you start doing anything remotely complex, you are going to be back in a world of choppiness. That’s my prediction, and I’m willing to eat crow on it if Adobe proves me wrong. But I can imagine people looking forward to converting their PV3D-based stuff to the iPhone, or something with multiple, parallax backgrounds scrolling around and dozens of enemy characters flocking here and there. These are things that perform fine in Flash natively, and things which, if you are using the correct tools, are not a problem at all to accomplish on the iPhone. But I am highly skeptical that the Flash to iPhone route is ever going pull off things like this with any kind of decent performance.

So a lot of people have said stuff like, “Well, yes, I understand this is just for simple, basic games. I’m OK with that.” Well, that’s cool. I’m not going to rain on your parade. If you have a realistic expectation of what you can do, and that’s all you want to do, and you are happy with that, then be happy. Particularly, if you have been developing Flash applications for mobile, you probably have a good idea of what you can do there, and as long as you keep those expectations about the same for the iPhone, you should be pretty happy. However, I will say that a trivial application or game like that is the ideal kind of project to learn Objective-C with. Why not make the leap? You’ll learn something new and useful and when you want to make something more complex, you’ll know how and won’t be arbitrarily stopped.

There’s one thing that really concerned me after the announcement. It was the number of Flash developers in the community saying, “We are all now iPhone developers! Yay!” and “Whew! I don’t need to learn Objective-C now. I’m throwing away all my Objective-C books!” I still believe the bottom line is, if you are serious about developing for the iPhone, you must learn Objective-C. For God’s sake, it’s NOT THAT HARD! Be a professional. Learn a new language. If you are even moderately skilled with AS3, you will be able to pick up Objective-C inside a week. Yeah, the memory management stuff will probably continue to challenge you for a while – I’m still coming to terms with it – but in general, you can be up and running in Cocoa in no time.

OK, so you are a Windows person and don’t have a Mac. So what? Get a Mac. If that’s your sole reason you are holding yourself back from doing iPhone development, and you think that Adobe has solved that for you, I’m sorry, but you are delusional. I wanted to play with Silverlight a bit. What did I do? I bought a PC. Hell, if you are developing for Flash, you are developing for both platforms and you really should have access to both platforms anyway.

Moving past performance issues, there is a huge amount of control you lose in the Flash to iPhone flow. Yes, memory management is a pain in Objective-C, but it has to be done. How does the Flash compiler do it? No idea. Hopefully really well, because that’s what you are stuck with. And it’s not just memory management. Every aspect of an application gets filtered through the conversion process and the Adobe API. There are only a handful of developers using it on just a handful of games so far, but wait until it gets into the real world. I can imagine major pain. As an example of what I mean by this, and one I made on Twitter, check out any of those apps or services that make Flash web sites for you – you know, where you drag and drop some media, and fill out some forms in some wizards and it spits out a Flash web site. There are plenty of them. If what you want is exactly what it spits out, or the changes you want to make are part of one of the wizard forms, you are all set. But the moment you want to have ANY further control over it, you are out of luck. Granted, you will have more control in Flash to iPhone, but I have no doubt there are going to be major points where you wish you had more control. At any rate, if someone came to you claiming to be a “Flash Developer” and showed you a site made with one of those templates, you would either be pissed off, or just laugh at them. And I think this is essentially why some members of the established iPhone development community are pissed off or laughing at this announcement.

Then there is the Apple reaction. As of yet, completely undefined. There has been speculation about the legality of what Adobe is doing, whether it breaks the developer agreement, whether Adobe reversed engineered anything, whether they are using non-public APIs, etc. Of course, Adobe’s stance is that it’s not a problem. But it’s really up to Apple to adjudicate what a problem is. I’m not even saying that Adobe has done anything illegal or even unethical, but I expect that if Apple can find ANY reason whatsoever to stop it, legally, technically, or otherwise, they will. Yes, several apps got approved under Apple’s nose. I’m interested to see how many will get approved now that Apple know’s what’s what. Some say that they won’t care – that they still get the revenue from the sales, so they will be happy to have more apps coming in. I don’t know. Time will tell. Especially if this does result in a flood of low quality apps, as many are predicting. They have many options. They can just disapprove any app that is made by Flash – maybe let the odd one through here or there to appear fair (and don’t think they can’t tell which apps are made with Flash and which aren’t). Or they could attempt outright legal action against Adobe. Or they could just change some API or app signing procedure or whatever, causing Flash based apps to not be submit-able, and forcing Adobe into a constant game of catch up. Or any number of other responses. I don’t think they will simply do nothing.

Finally, this is just my personal speculation, but I somewhat feel that this is more of a political move against Apple, to somehow force some kind of action on getting the Flash Player onto the iPhone. I don’t know how that is supposed to work, but progress on that front seems to be at a standstill now, and this is no doubt going to stir things up at least. So as technically amazing as this is, I predict that this technology is not a long term strategy for Adobe and I doubt it will be part of CS6.

posted in Flash, iPhone | 82 Comments

2nd October 2009

Component Based Game Architecture

I touched on Component Based or Entity Based Game Architecture very briefly in my FOTB talk. This video covers a bit more, but same basic principles. It then goes into some of the specifics of the Push Button Engine, but even if you don’t go with that engine, it’s a pretty good intro to the concept.

posted in ActionScript, Flash | 8 Comments

27th September 2009

Game Input: Polling vs. Events

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.

posted in ActionScript, Flash | 16 Comments

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

  • November 2009
    M T W T F S S
    « Oct    
     1
    2345678
    9101112131415
    16171819202122
    23242526272829
    30