Author: Sarah Northway

  • Creating a two-step Flash preloader

    Sarah and two laptops
    500 kbps ain't as fast as it used to be

    I came up with this one in Costa Rica, while consistantly waiting three minutes for a 5 meg Flash game (Rebuild, as a matter of fact) to load. The vector graphics take up very little space so over 4 of those megs were just the music. Since I usually play Flash games muted, I figured it was foolish to make players wait until the music loaded before they could start playing. Enter the multi-part Flash preloader.

    Preloaders in Flash work by putting some content (the loading animation) on Frame 1 of the base MovieClip, and the rest of the content (the game and music) on Frame 2. The first frame loads in its entirety and any actionscript on that frame executes before the second frame starts to load. This makes sense when you consider that Flash was designed for playing movies. So, can you simply move some of the content (the music) to Frame 3? Yes, it’s that easy!

    Well, easy if you’re writing your game on the timeline in the Flash authoring tool. I prefer to use FlashDevelop and the Flex compiler (both free) instead, so my main class is in an AS3 file and the frame metaphor is more obscure. If you start a new project in FlashDevelop using the “AS3 Project with Preloader” template, it creates a Preloader.as class, and a Main.as class with “Always Compile” and the Frame metatag [Frame(factoryClass=”package.Preloader”)]. What this tag does is tell the compiler to put Main.as (and any of its dependancies) on the second frame, and Preloader.as (with its dependancies) on the first frame.

    So, if you stack one more class on top…

    Music.as with [Frame(factoryClass=”package.Main”)] (set to “Always Compile”)
    Main.as with [Frame(factoryClass=”package.Preloader”)]
    Preloader.as with a spinny ball animation

    Flash Frames

    The only catch is you can’t determine how much of Main.as has loaded using loaderInfo.bytesTotal because that will also include the bytes from Music.as. Instead you either need to look at Preloader.currentFrame, or try to instanciate Main and catch an error if it’s not ready yet. You could get fancy and use as many frames as you want to determine load order of all your assets, but if you’re dealing with one very large swf it’s still better to cut it up and stream your assets from outside.

    While South Korea has plans to put 1 gigabit connections in every home, internet speeds in big countries like the US and Canada have been falling behind. Many areas of the world will be running through 3g cell connections before they even have cable or dsl lines. So go easy on them and don’t forget the preloader! :)

    Here’s my example code:

    Preloader.as

    package loadtest
    {
    	import flash.display.MovieClip;
    	import flash.events.Event;
    	import flash.events.IOErrorEvent;
    	import flash.utils.getDefinitionByName;
    
    	public class Preloader extends MovieClip
    	{
    		public function Preloader()
    		{
    			addEventListener(Event.ENTER_FRAME, frameEntered);
    
    			trace("preloader starting");
    
    			// TODO put your spinny ball here but DO NOT reference the Game or Music classes
    			// directly or they will be compiled in to Preloader frame 1
    		}
    
    		private function frameEntered (...ig) :void
    		{
    			// the user can begin playing the game
    			if (currentFrame == 2) {
    				trace("frame 2 finished loading, starting game.");
    				var gameClass :Class = getDefinitionByName("loadtest.Game") as Class;
    				addChild(new gameClass());
    				// TODO remove your spinny ball here because the game has started
    
    			// finally, the music can also start
    			} else if (currentFrame == 3) {
    				trace("frame 3 finished loading, starting music.");
    				var musicClass :Class = getDefinitionByName("loadtest.Music") as Class;
    				addChild(new musicClass());
    
    				// all done loading everything so ditch the preloader
    				stop();
    				removeEventListener(Event.ENTER_FRAME, frameEntered);
    			}
    		}
    	}
    }

     

    Game.as

    package loadtest
    {
    	import flash.display.MovieClip;
    	import flash.utils.getDefinitionByName;
    
    	[Frame(factoryClass="loadtest.Preloader")]
    	public class Game extends MovieClip
    	{
    		public function Game () :void
    		{
    			trace("game starting");
    
    			// TODO put your entire game here but DO NOT reference the Music class
    			// directly, or it will be compiled in to Preloader frame 2
    
    			try {
    				// this is okay, but will throw an error if the Music isn't loaded yet
    				var musicClass :Class = getDefinitionByName("loadtest.Music") as Class;
    				var music :MovieClip = new musicClass();
    			} catch (error :ReferenceError) {
    				trace("music class isn't loaded yet");
    			}
    		}
    	}
    }

     

    Music.as

    package loadtest
    {
    	import flash.display.MovieClip;
    
    	/**
    	 * This file must be marked as "Always Compile"
    	 */
    	[Frame(factoryClass="loadtest.Game")]
    	public class Music extends MovieClip
    	{
    		public function Music () :void
    		{
    			trace("music starting");
    
    			// TODO reference your mp3 or wav classes here so they will be compiled in to
    			// Preloader frame 3.  You can also reference Game since it's already loaded.
    
    			// this is okay
    			var game :Game;
    		}
    	}
    }
  • Rebuild 2: Starting the Sequel

    Rebuild on Kongregate
    #3 on Kongregate with 2,000,000 plays!

    My game Rebuild was more successful than my highest hopes. It’s nearing 2 million plays just on Kongregate alone, and is still the #3 game in their rankings. So there’s no doubt I’ll do a sequel and it’s about time I got started!

    I’ve gotten heaps of suggestions by email, pm, and in the forums at TwoTowers, Kongregate and Newgrounds. I’ve been collecting these and trying to get a feel for how people are playing the game.

    I noticed something interesting: many people play to completion, trying to get all four endings in one game, preferrably on the same turn. This is not at all how I play; I just want to get to an equilibrium where I’m not in constant danger of being wiped out, usually around turn 75. Mopping up the remaining 2/3 of the map isn’t interesting to me, so I didn’t make a lot of content for the lategame. This is how I imagined a game going:

    • Turns 1 – 24: worry about food
    • Turns 25 – 44: worry about zombies
    • Turns 45 – 74: worry about happiness
    • Turn 75: either you’ve stabilized and won, or you’re dead and don’t know it yet

    These numbers are hardcoded: zombie mobs first arrive on day 25, and on day 45 the zombie spawning caps out and new happiness-related events start happening. But people are playing until turn 250 and conquering all 100+ squares. So, my first priority for the sequel is to take this play style into account and make sure the game stays interesting for longer, especially on easy difficulties. There will be many more random events, and branching storyline events where you have to answer yes or no questions which influence future events. Maybe even factions you can effect, or special named npcs that join the fort if you meet certain conditions.

    I was also super pleased to see people swapping stories of their survivors; the funniest names or most eyes lost (I saw 9) and the random stuff that happened to them. So my second goal is to make survivors more customizable and unique, with equipment and skills and levelling. Varying skin and hair color and yes, there will be things to lose other than eyes.

    Zombie Attack Art
    How not to do art: don't draw things for 20px high then stretch them to 150px

    The biggest complaint was the art (though some people liked it’s simplicity), followed by the fact that the zombie attacks weren’t interactive. The art will get some attention (hopefully with help from someone else), specifically the animations which I admit are totally pathetic. No promises, but I also want to replace the attack animation with a minigame that changes your odds by +/- 10%. Skippable of course, and hopefully more interesting than your usual point and click shooter.

    So those are the big 3 (more lategame content, more unique survivors, better zombie attacks), but of course there will be new buildings and effects, improved art all around and I’m going to address some stuff that drives everybody (including me) crazy about Rebuild, like:

    • All the clicking involved in sending 10 guys on a mission in the lategame
    • Having to move people on and off guard duty all the time
    • Squares filling up with zombies the turn after you clear them
    • 20 zombies spawning every turn in the last couple squares on the map
    • Losing a single 3% danger fight in Harder or Nightmare can ruin you

    Of course there are a lot of suggestions that won’t make it in, like I’m not going to attempt multiplayer or add an XCom-style tactical battle system (I wish, that would be awesome!). I’m already starting a list of ideas for Rebuild 3 – hah, we’ll see!

    Rebuild 2 Title
    The new look may be for you to decide!

    I’m looking for a vector artist to help me out this time, so if you’re interested in working on Rebuild 2, drop me a line with your portfolio.

    There are a lot of other little things that may or may not make the cut, and the possibility of versions for iPhone and other platforms. But I’m just getting started, so there’s still time to send me your suggestions!

  • Word Up Dog: Creating Android apps with Adobe Air

    A screenshot of Word Up Dog the game
    Word Up Dog: represent, yo!

    Having already optimized my game Word Up Dog so that it runs relatively well in a browser on an Android phone, I was ready to package it up as an installable app. Adobe Air makes this easy to do with few changes to your original code. Adobe has a Flash CS5 plugin to do it, but I prefer to do things the free-and-open way when I can, so here’s how I built the Android app using only FlashDevelop and other free Windows tools.

    First, I don’t recommend the Android emulator. I struggled with getting emulator-compatible versions of the Air packager and Air runtimes installed. There didn’t seem to be much advantage so use a phone if you can get your hands on one.

    I followed several tutorials and honed the process down to this:

    1. Download the Air 2.5 SDK, paste it into a copy of your Flex SDK directory, and set FlashDevelop to compile using the result
    2. Start a new FlashDevelop AIR AS3 project
    3. AddChild your existing game in Main.as
    4. Add NativeApplication handlers to prevent the phone from idling
    5. Add android-specific settings to application.xml (here, have mine)
    6. Generate a certificate using
      adt -certificate -cn WordUpDog 1024-RSA certificate.pfx yourpass
    7. Build your air project to create WordUpDog.swf
    8. Package the swf into an apk file with
      adt -package -target apk -storetype pkcs12 -keystore certificate.pfx -storepass yourpass WordUpDog.apk application.xml -C . WordUpDog.swf iconsFolder
    9. Upload WordUpDog.apk to your phone and baby, you’ve got a stew going
    Word Up Dog on a Nexus One
    Victory – the Air for Android app is installed!

    I was prompted to install the Air interpreter the first time I ran the game on my Nexus One, then it behaved just like any other app. The performance was about the same as running the SWF through the phone’s browser, but of course there are advantages to being installed. I could force the game to stay in landscape perspective and add a customized handler to deal with incoming phone calls. Not to mention being able to upload and sell it on the Android app store!

    Next I’ll tackle Air on the iPhone.

  • Word Up Dog: Flash optimization for mobile platforms

    Word Up Dog Splash Screen
    Word Up Dog: Yo Diggety.

    I just put my new game Word Up Dog up for bidding on FlashGameLicense. It’s very different from my first game Rebuild (I needed a break from zombies!). In Word Up Dog, you play a dog digging underground for letters to anagram, aided by cute animals who speak in 90’s hiphop lingo. It has a simple interface and can be played in short sessions, so it’s a good fit for mobile platforms like the iPhone, iPad and Android phones.

    When uploading a game to FlashGameLicense, one of the options is a “Mobile-ready” checkbox. Here’s what I did to make Word Up Dog mobile ready…

    I have a Nexus One Android phone, which unlike the iPhone can run Flash in its browser. So as a first test I pointed it at the totally unoptimized game swf. I was pleased to see the game load quickly and error-free, and the graphics looked good on the bright little screen. The SimpleButtons were easy to hit and the mouse over state even showed briefly. Movement using both the trackball (which fires up/right/down/left KeyboardEvents) and touch worked correctly. But the framerate was crappy, and touching even a blank area on the screen brought the game to a crawl.

    First, I looked at how I was rendering the map, a 800×550 sprite containing ~150 vector shape tiles. The tiles had cacheAsBitmap=true which had a noticeable effect on my pc, but it was hard to tell if it was doing anything on Android. Instead I manually drew each of the tiles to a Bitmap, which improved the framerate significantly. Drawing all the tiles onto one huge 800×550 bitmap was even better, but the way my tiles overlap made updating (by blitting) difficult.

    I improved the movement speed by jumping the screen from square to square instead of smoothly scrolling it. I downgraded the target fps from 30 to 24, and simplified the gui animations so that instead of fading in, notice text pops into existance. I replaced contrast, emboss and drop shadow filters with graphical approximations. I cached the dog’s shape tween animations as Bitmaps using TouchMyPixel’s AnimationCache. Each of these things had a small but helpful effect on the framerate.

    Now to tackle the touch issue. Holding down on any part of the screen lowered the framerate by 10fps, even after stripping out all MouseEvents. I couldn’t recreate it on pc (even via air at 250fps) or see evidence of it in a profiler. My guess is that Flash just isn’t very efficient at dealing with touch screens. What finally improved things was setting mouseEnabled=false and/or mouseChildren=false to everything in the game that isn’t meant to be clicked. This seems to be especially important for TextFields.

    Flash Preload Profiler
    Tracking memory with the Flash Preload Profiler

    Finally, memory. The free FlashPreloadProfiler told me I was using 50mb, and showed the number of instances of each class and time in functions. Adobe’s Flash Builder Pro profiler gave me additional info including function stacks and the momeory used by each class.

    I got my memory down to 20mb by instantiating some map-related things when they came into view rather than at game start. I verified that I didn’t have any memory leaks such as objects or handlers left around after exiting to menu and starting a new game.

    To recap my optimizations:

    • Draw shapes to Bitmaps instead of relying on cacheAsBitmap
    • Simplify gui animations
    • Cache character animations as Bitmaps
    • Remove filters
    • Set mouseEnabled=false and/or mouseChildren=false on non-clickables
    • Other best practices I follow include cutting down on EnterFrame events, avoiding masks, and using strongly-typed variables.

    I can now run Word Up Dog on my phone through Chrome at 20-24 fps! Not perfect and it will be slower on older phones, but I’m calling it a success. In my next post I’ll talk about packaging the game up using Air so I can sell it in the Android and iPhone app stores.

  • Oysters & Puppies & Good times


    Shakira & her pups
    Originally uploaded by apes_abroad.

    A couple days ago Colin and I went out with Don and his friend John on an oyster hunt. We crossed the estuary and walked over the rocks on the point to find a place we could enter the water without being chewed up by the waves. It was a low visibility day so we had to dive down to see the rocky floor and searched for crevices in the rocks where a little black slit of a mouth might be hiding. It took me nearly half an hour to finally bag my first one and I shot to the surface holding it high and singing the A-Team theme through my snorkel.

    I found my second and third by turning over rocks, and in the process also uncovered eels, slugs, and a beautiful big cowrie whose shell was at first totally covered by its bumpy grey body. Then came the biggest, most tenacious oyster which all my tugging could not separate from the rock. The current was picking up as the tide came in, so every time I had to come up for breath I was afraid I wouldn’t be able to find him again. My fingers got all cut up in the fierce battle, but after five tries I shot to the surface holding the oyster over my head in victory!

    That night we had ‘pirates’ at the bar, which is an oyster with chili followed by a shot of rum. When I lifted my oyster to my lips (my tenacious opponent perhaps!) I saw a tiny pair of eyes looking back at me. The oyster had been home to a miniature transparent lobster, smaller than a thumbnail with perfect little lobster claws and wavy eye stalks. People eat these guys live as a delicacy that kind of tastes like sweet fish roe (Aaron ate one while he was here!) but I couldn’t do it. A friend took pity and brought it down to the ocean, where I doubt it will be able to find another oyster (I now know from experience, they’re hard to find!) but one can hope.

    While the Mishkins were here we were all placing bets on when the local dog Shakira would give birth. Well, she looked ready to pop for the last two weeks I thought, but Ariel won the bet – she gave birth within 24 hours after they left. Gabe’s wife Natalia had to crawl down under the bar floor to retrieve the puppies. Four.. five… wait there’s two more.. eight.. oh there’s even more over here.. ten.. eleven! How Shakira, who was not a very big dog, fit eleven puppies in her I don’t know, but she is much happier now to have them on the outside (she could hardly walk before!).

    The puppies still haven’t opened their eyes and only have two states: sleeping and hungry. For me they are right on the gross/cute line but quickly tipping over to cute. You can see what I mean in this short video I took of them piling on Shakira to feed.