Pitfalls When Writing a Canvas Game for Android
Recently a client approached Metal Toad to develop a prototype game for Android devices and leaving the option of porting it to other devices open. We decided to develop the game using HTML5's canvas element and wrap it in phonegap to bring it to Android devices. In this post I'll talk about the major pitfalls I encountered while working on the project and provide you with some points to keep in mind while developing canvas games for mobile devices.
Let me speak a bit about the game engine I decided to use: JawsJS. This canvas game engine made development a breeze. It is a lightweight game engine that provides many features to speed up development. Sprites, Spritesheets/animations, collision detection, tile maps, parallax scrolling and viewports are all handled by JawsJS in addition to the basic game loop (setup, update, draw). It also features a nice asset manager that will allow you to preload all the necessary assets for your game before hand.
I had been doing most of my development in my computer's browser, with the mindset of "Hey, if it works in a chrome browser on the desktop, it'll work in a webview on the Android device!" I was so wrong, so very, very wrong. After a while of coding the game and its mechanics, I went ahead and packaged up a test build for an Android tablet. After the app installed and began to run, it quickly threw up some errors in my debug log and proceeded to crash.
Preload *all* the things
Upon further investigation, this error was due to JawsJS attempting to draw the images before they had finished loading. Even though I was using the asset manager, my images weren't being preloaded properly. This only occurred in the webview though. On the desktop and on the tablet's native browser where it would seem more likely to draw before loading has completed, this worked fine! The only way I could fix this was by hacking JawsJS to actually store the image object in memory when the asset manager loaded it.
Android's webview has poor-to-no support for the element
The second major issue I encountered in my journey to Android-land, was the lack of support for the tag in Android. The game has some cut-scenes and a video tutorial. I was creating a video element and displaying the frames onto the canvas to accomplish this. On Android this would not do. When I entered a cut-scene, the app would freeze and I'd see a bunch of "call to OpenGL ES API with no current context" errors in the debug log. Initially I had thought I was generating the video element incorrectly and/or there was some odd encoding setting involved with the video file itself. I decided to make a simple page with a few different videos with varying markup to see if any worked on the tablet. In the tablet's native browser I could get the videos to load fine in a tag, but not in the webview. This seems to be a limitation of the webview itself and I was able to implement a workaround using the Video plugin for phonegap. This opens the video in the native player — removing any status/events I was using to check when the video had ended. This was a bit of a hack, but it worked. There is probably room for improvement here via some hefty phonegap plugin that might be worth researching and developing if support for the element remains minimal in the Android webview.
My tablet can't focus
The game was so close to being in a working state by now. There was one big issue remaining. My touch events seemed to fire only some of the time when I was touching the screen. When they would fire, a large light-blue overlay would envelope the entire canvas for a few seconds. This bug turned out to be focus related. I had to ensure that the webview had the current focus after each video played (since it was now playing in the external media player). To do this I had to extend a small phonegap plugin to call
webView.requestFocus(View.FOCUS_DOWN); when returning to the game from a cut-scene. With that fixed, I had a complete canvas game running both for desktops and Android devices.
I was overly ecstatic that all of the major bugs were resolved finally! I only had a few non-platform related issues to hammer out and the game would be complete. As happy as I was, when I realized the poor performance of canvas on the tablet, my happiness faded away. While the desktop I was testing with made my app seem fast and responsive, the tablet ran like molasses on a cold day. However, after some speed improvements, the prototype ran at a decent speed. If the game were to evolve beyond the prototype stage, it might need some additional hacking, or a different approach to achieve faster speeds.
In brief, here's a few things to keep in mind when developing an HTML 5 application for a mobile device:
- Always test on your device alongside any desktop testing.
- Canvas game engines are very new, they might have a few bugs in them.
- Be prepared for differences even between the device's browser and the device's webview.
- Don't be afraid to write some native code!
- Spend even more time researching the current limitations of your device.
- Run a few small speed tests to see if your game will run as fast as you desire (on both desktop and tablet!).
Good luck and happy coding!