You may have seen my recent post about porting the Flixel based demo game ‘Mode’ to various devices. (If not I suggest you check it out as it has some photos of Mode running on a selection of different platforms). One of the things that became apparent was that even though I saved a massive amount of time deploying to Android, iOS, and TabletOS (BlackBerry PlayBook) by leveraging the new mobile workflow in Flash Builder 4.5, there were a few things that I’d not considered.
A Bit Of Background
Before I get in to the 10 most important ones (in my opinion anyway), let me first provide a bit of background. Mode is an ‘8bit’ style platform game. It uses a camera and viewport metaphor for displaying the game levels. So only a certain amount of the game area is visible at anyone time and as you move around the camera pans with you to expose new areas of the current level.
If you want to try out the web based version of Mode you can play it here: http://www.flixel.org/mode/. The actual game mechanics are fairly simple. You control your hero with the arrow keys and use the X and C keys to jump and fire. The object of the game is to destroy the bases of the alien craft; however, if you cross an alien your gun jams. Once you kill something your score ticks down to 0 (zero). Once it reaches 0 you die – so there is a certain level of urgency to keep shooting the bad guys. To jump to higher platforms that are out of reach with a normal jump you can point your gun downwards and use it as a sort of ad-hoc thruster, the faster you fire the quicker and higher you rise.
Now it is obvious that something needed to be done about the keyboard controls – after all the majority of smart devices (phones or tablets) tend to come with only a touch screen. This I opted to map to a set of virtual controls (you can read more about the ones I used and download the source to experiment with) and map the keyboard calls to the direction controller and the required buttons.
While I did perform a few bits of optimisation, I haven’t spent a vast amount of time fine tuning the game so there is room for a performance boost there I am sure. Regardless it performs very well on the target devices. With that bit of background info out of the way here is my list:
10 Tips When Developing For Multiple Devices
Please note these are in no particular order.
- Check screen dimension on initialization
- Optimise your assets. Then optimise some more
- Use a lower resolution and scale up (if applicable)
- Make sure UI or controls don’t impact playability
- Embed assets, don’t load content if possible
- Only include what your game needs
- Test on as many actual devices as possible
- Be prepared for the (un)expected
- Work with the hardware not against it
- Don’t “fire and forget” when exporting
Check screen dimension on initialization
If you are targeting a specific screen orientation make sure you check the default screen width and height of the display on initialization. This isn’t just useful if you are looking to target a landscape layout either, as a lot of the newer tablets are now landscape by default (for example, BlackBerry PlayBook, Motorola Xoom, etc.). You can do this as part of your game initialization routine. I tend to store these values in case I need them later on. The code below illustrates the process:
_screenWidth = (stage.fullScreenWidth > stage.fullScreenHeight) ? stage.fullScreenWidth : stage.fullScreenHeight;
_screenHeight = (stage.fullScreenHeight > stage.fullScreenWidth) ? stage.fullScreenWidth : stage.fullScreenHeight;
By checking the fullScreenWidth and fullScreenHeight of the stage object you can easily determine if you need to transpose the values – especially useful if you are scaling your game or creating a viewport (both processes are used in Mode)
Optimise your assets. Then optimise some more
Optimising assets isn’t just about compression. It is also about only using those assets that you have to. Now this may sound obvious as of course you’d only use the assets that you have to and you’d be right if you were targeting a single deployment platform. But take this example. I have a game that uses some beautiful bitmap backgrounds for each levels, but I want to target a selection of devices – each with differing resolutions. So, do I:
- Create a selection of backgrounds for each resolution and determine which to load when my games starts up
- Opt for a happy medium and scale up or down as required
- Only include the backgrounds designed for the target device
Actually it is a trick question as you can do any or all of the above. However, I would avoid the first one unless you have a low impact, low performance game (e.g. a puzzle or turn based game) as you really want to make the most of the available memory; and on devices such as smartphones and tablets that currently don’t have anywhere near as much memory as you may be used to on the desktop. For example, if a tablet says it has 1024MB of RAM, you can almost guarantee that you will have less than half of that to work with (if you’re lucky) and given that most of these devices can multitask it will probably be a lot lower. Now you may be thinking well I can run my game in 256MB of RAM easily and you probably can but make sure you consider not just your games running memory footprint, but also how much memory is taken up by loading assets in to RAM (a potential downside of large sprite sheets). If you’re not too careful you can easily run out of memory and this is true for any application, native or not.
Use a lower resolution and scale up (if applicable)
This is an old school technique when hardware was expensive and custom made. Resolutions were low because the manufacturing costs were prohibitive to make anything close to the resolutions that our phones can now display (most arcade games in the 1980s and early 1990s had a video resolutions of 256×224 or 320×224 – Sonic the Hedgehog was 320×224). By using a lower resolution and scaling it up you can optimise your bitmap assets as they will be smaller overall. However the pay-off is that at higher resolutions any Bitmap assets will likely pixelate. That pixelated look though lends itself well to certain types of games that are looking for that retro “8-Bit” feel – Flixel is a fine example of this.
Obviously this type of process doesn’t lend itself well to fixed resolution games, or those that rely on higher quality visuals, but you can still tap in to this even then — even if it’s just to scale up or scale down by providing a resolution that is a happy medium between your target device resolutions. One thing to mention though is that while the resolutions may be similar the pixel densities may not so do some tests before opting for this approach if visual quality is a requirement.
Make sure UI or controls don’t impact playability
This one fails a bit on the Mode demo I created, mainly because it uses a viewport and camera and therefore you can walk to the edges of the screen. When you do this the thumb stick controller or jump / fire buttons can obscure your hero character. I haven’t adjusted the camera pan to take this in to consideration, so it is fixable. However, it does illustrate how important the game UI can affect how a user interacts with your game; especially on a touch based device where any form of user interaction is going to be on the actual screen and, as in my case, risks impinging on the game area.
Embed assets, don’t load content if possible
There are a couple of reasons you don’t want to be loading assets; and by loading assets I mean via a file or URL call. Firstly, if something fails to load your game fails (or you’ll need to add logic to handle this issue). Secondly, some device platforms won’t allow you to load certain content types. The best approach is to embed your resources, however as I mentioned earlier that could increase your overall memory footprint if you’re not careful. If you DO need to load items — e.g. if you have large levels in separate SWFs or other assets that are specific to certain sections of your game — you can also embed those in a SWC and link that to your game. You can then access those items only when required and destroy them once no longer needed.
Only include what your game needs
This is similar in nature to the tip on optimising assets, but this one focuses on ancillary items like game icons. When you finally export your game, in the AIR app-config.xml file you will likely have set a selection of icons. I suggest you only include those that you require for the platform you are targeting.
While the BlackBerry PlayBook uses it’s own config.xml file to set TabletOS specific properties (including the icon of your game), if you have any other icons declared in your main app-config.xml file that are smaller than the 86×86 icon required by the PlayBook, it will use that one instead. So for example iOs uses a 29×29 or a 57×57 icon and Android uses a 36×36 or a 48×48 icon. All of which are smaller than the PlayBook’s 86×86 icon. The unfortunate side affect is that it doesn’t scale them up – so you end up with a incorrectly sized icon aligned to the top middle. The way to resolve this is to comment out all of the icon entries in the main app-config.xml file and just target the PlayBook on that export. Once it is exported uncomment the icon entries again and export as required for the remaining platforms. This has been fixed in the latest Blackberry Tablet OS SDK update.
I personally comment out all of the icons that I’m not using in a particular platform export as you can see below:
<!-- The icon the system uses for the application. For at least one resolution,
specify the path to a PNG file included in the AIR package. Optional. -->
<!-- REMEMBER TO COMMENT OUT ALL OF THESE ICON ENTRIES IF DEPLOYING TO PLAYBOOK -->
<!-- iOS -->
<!-- <image29x29>assets/icons/mode_29.png</image29x29> -->
<!-- <image57x57>assets/icons/mode_57.png</image57x57> -->
<!-- <image114x114>assets/icons/mode_114.png</image114x114> -->
<!-- <image512x512>assets/icons/mode_512.png</image512x512> -->
<!-- Android -->
By doing this I avoid adding additional (albeit minor) weight to the overall game package by including unnecessary icons and I also avoid the BlackBerry issue I mentioned above. Remember that you also need to uncheck those icons that are not required in the export settings for that particular device platform (see the image below)
One thing I do omit from certain target platforms is the BlackBerry config.xml file – after all it isn’t of use other than for the PlayBook, so it makes no real sense to include it in with the other device platforms.
Test on as many actual devices as possible
This one is pretty much a no-brainer. However, not everyone is as fortunate as I am to have all of these devices to test on. That said the device emulators / simulators can only get you so far. So if you don’t have the device that you’re targeting to hand, try to find a trusted friend or peer that is willing to test it for you. It is important to test on an actual device because of the hardware limitations and operating profile. For example, what does the app do if a lot of other apps are running as well as mine? Or what does my app do if the user get a phone call? Unfortunately not all simulators / emulators provide exactly the same functionality as the actual device. Testing multitouch can be tricky (if not near impossible). Likewise, cameras, the accelerometer, and GPS are all a bit hit-and-miss.
Be prepared for the (un)expected
The title may be a bit over the top, but the sentiment is valid. There are only some many things you can be mindful of, unlike developing for the web or desktop in AIR, developing for devices requires a bit more forward planning, both in the running and exporting of your game.
For example, what is your game going to do if the user receives a phone call while playing your game, or switches to another app or game? Does it just exit? Does it pause? Or does it exit and retain state, so when the user comes back to it at a later point in time they can pick up where they left off? Whichever you opt for make sure your save / cleanup routines don’t take too long as some platforms will only allow a certain amount of time for these processes to run before suspending them or flagging them for garbage collection.
Another thing to watch out for are devices that have soft buttons. Most Android devices have both a Back button and a Home Button and you can choose to implement a response to these or not. Depending on how you want to handle the events dispatched when either of these buttons are pressed. At the very least I would suggest you add listeners and pause your game by using the following code.
protected function addNativeSettings():void
NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE , onDeactivate);
protected function onDeactivate(e:Event):void
// Flixel specific call to pause the game engine
FlxG.paused = true;
If you don’t want to pause the game and instead want to exit it when the user opens another app / answer the phone just replace the code in the onDeactivate() method so it looks like the following:
protected function onDeactivate(e:Event):void
At least that way your game is paused or exiting gracefully. If you don’t, it may continue running in the background using up resources that it doesn’t really need. I speak from personal experience after draining my battery on my phone by forgetting to turn off the GPS in an app I was testing on it. The upshot was the app “closed” (switched to a background process) but didn’t exit, so while in the background it continued to pinpoint my location via GPS (which, as I’m sure you are aware is a bit of a battery hog).
Work with the hardware not against it
This isn’t one of those “them or us” discussions about hardware limitation. It is more about thinking differently about device development when compared to web or desktop capabilities. Firstly there are consistent features on most devices that you can leverage to add new dimensions to your games. The accelerometer is one that always springs to mind as an alternative form of input control to using virtual thumbsticks.
One key thing to remember, and this applies doubly to smartphones, is that the hardware is being used by a lot of other operations. As I have mentioned throughout this post, you may not have as much resources as you expect. Plus if you’re app is running on a phone it is a second class citizen – the ability to receive and make calls always comes first; so keep that in mind
Don’t “fire and forget” when exporting
While in some use cases you can just select all of the platforms you wish to deploy to and click the export button, much of the time this won’t be the case. The advantage of developing with the Flash Platform is to allow the reuse of your code without having to rewrite your game in another language to target a specific platform. When it comes to game development, we all know it is about optimisation and performance (good gameplay doesn’t go amiss either :p). Therefore you will likely want to tweak your code (as much as is possible) so it performs at its best on the device you have released it for. That said, beyond minor configuration tweaks as listed above, I didn’t have to do much ‘per platform’ optimisation to get good results, but I did still export for each platform one at a time. The reasons for this are as laid out in the earlier points; plus I could test each device build before moving on to the next device platform.
As I said at the beginning of this post, these are things I found important. Obviously you may find other items equally if not more important than some of those I have listed.