Category: Development

  • Rebuild 2: Playtest and Playtomic

    The Rebuild 2 main menu
    The Rebuild 2 main menu may be the creepiest art in the game.

    The Rebuild 2 playtest is over and was a huge success. I sent the test out to 63 applicants, and of those 45 played at least once and 21 sent me some sort of useful feedback (and get their names in the credits – thanks guys!). A couple shared their access despite being explicitly asked not to, but it was worth the risk and I had some security to impede ne’er do wells. So far my faith in humanity is intact!

    Some testers were above-and-beyond awesome, playing lengthy games on multiple difficulties, finding all the endings and rooting out my many grammatical errors. They found dozens of bugs I’d missed, and helped me make Nightmare difficulty (now called Impossible) harder than ever.

    Being fans of Rebuild 1, they weren’t as good at finding noob issues, so I did some extra tests with people who’d never seen the original. In person is best for this, although I find it nerve racking to watch people play my games. Like every other aspect of the game, the tutorial got an overhaul.

    Stats broken down by day and difficulty
    Playtest stats broken down by day and difficulty

    I collected stats using Playtomic (formerly SWFStats), including the fact that a few games went 300, 500, even 800 days. That’s dedication!

    Playtomic wasn’t ideal for such a small test. I broke down the survivors, squares, and food by day and difficulty, but when I added map size it all got out of order and became a wall of numbers. I needed more options to sort and filter, or download the data in an xls. I also logged any errors as custom metrics, but without room for stack traces all I knew was how often each error happened. Again, not what Playtomic was designed for, but it would have been useful.

    What Playtomic does do well is analytics for published games, like Google Analytics but simpler and more game-centric. I wish I’d put something like it in Rebuild 1 so I could at least know how many plays that game has. 6 million confirmed on the big portals… maybe another 2 or 3 from the hundreds of smaller sites?

    Anyway, with help from my army of volunteer playtesters, Rebuild 2 is now (just about) finished, and is off to sponsors for bidding. The process usually takes a month, so you’ll finally all be able to play the new game in September!

    Until then, here’s a very brief Rebuild 2 trailer I cut together:

  • Rebuild 2: Progress Continues

    EvilKris and I have been working hard on Rebuild 2. Skills and plots are in with about 30 other changes, and there’s another 20 to go. Recent additions include renaming survivors, saving in multiple slots, shotguns, helicopters, prostitution, and more kittens.

    There are also new buildings and I tweaked the map art to use more gradients and textures. I’m still working on the blood bar; need to make room for more information up there. It’s still pretty similar but here’s how it looks today:

    New buildings in Rebuild 2
    New buildings in Rebuild 2

    EvilKris is nearly done the new attack screen art, small illustrations to go with various events and possible outcomes. These will be in a kind of a comic book style, hopefully not too gruesome for the squeamish but showing a more realistic depiction of life in the land of the dead. He has more art on his blog.

    EvilKris's attack screen vignettes
    EvilKris's attack screen vignettes
  • Word Up Dog: Creating iPhone apps on Windows with Adobe Air

    Word dog on the iPad
    Word Up, iPad!

    I’d already optimized my new Flash game Word Up Dog to run on mobile phones, and used Air to package a version that I could sell in the Android app store. Now for the next challenge: the iPhone.

    Shortly after Adobe announced the tools for compiling Flash code into iOS apps, Apple banned the process as part of their ongoing spat with Adobe. Happily they retracted this bit of bs six months later, so we are free to experiment with Air for iOS once more. God knows if we’ll ever view Flash websites on an iPad browser, but this is a start.

    Building Air for the iPhone is similar to the Android process, but generating the security certificate requires paying Apple $99 for a developer license (Android is free), then dancing back and forth uploading and downloading files from their website. Although you need a Mac to write iOS apps in Objective-C, you can compile Flash AS3 code into iOS using Mac, Windows, or Linux. I used Windows, along with OpenSSL (instead of Keychain) to generate the security bits, and iTunes (instead of Xcode) to install the app onto my phone.

    Here are the steps:

    1. Download the Air 2.6 SDK, paste it into a copy of your Flex SDK directory, and set FlashDevelop to compile using the result
    2. Download OpenSSL
    3. Start a new FlashDevelop AIR AS3 project
    4. AddChild your existing game in Main.as
    5. Add NativeApplication handlers to prevent the phone from idling
    6. Modify your application.xml to add iPhone-specific settings
    7. Sign up for a $99 iOS developer account
    8. Generate a key by calling
      openssl genrsa -out SarahNorthway.key 2048
    9. Generate a certificate signing request with
      openssl req -new -key SarahNorthway.key -out WordDog.certSigningRequest -subj “/emailAddress=youremail@domain.com, CN=Your Name, C=US”
    10. On the Apple website, upload WordDog.certSigningRequest, create a provisioning profile for your iPhone and download WordDog.mobileprovision and developer_identity.cer
    11. Generate a pem file with
      openssl x509 -in developer_identity.cer -inform DER -out developer_identity.pem -outform PEM
    12. Generate the p12 certificate with
      openssl pkcs12 -export -inkey SarahNorthway.key -in developer_identity.pem -out WordDog.p12 -passout pass:yourpass
    13. Build your air project to create WordDog.swf
    14. Compile the final ipa file using
      adt -package -target ipa-app-store -provisioning-profile WordDog.mobileprovision -storetype pkcs12 -keystore WordDog.p12 -storepass yourpass WordDog.ipa application.xml -C . WordDog.swf Default.png iconsFolder (this takes a few minutes)
    15. In iTunes, drag WordDog.mobileprovision and WordDog.ipa into the library
    16. Find your game in the iTunes library apps, drag it onto your phone and sync

    Wheuf! A few extra steps and security files in there, but it’s all worth it, so we can sleep safe knowing nobody is installing homebrew apps on their own iPhones without paying Apple first.

    Sarah Working
    Me hard at work… or trying to beat Fate of the World?

    Unfortunately Air 2.6 only supports iPhone gen 3 and above, but this is probably for the best considering how much more processor intentive the Flash code seems to be compared to Objective-C code. Word Up Dog runs well on a 2nd gen iPad, but it still drops to 15 fps when moving the map around, so I’m going to have to go back to optimization before I can release it on the app store.

  • Rebuild 2: let’s get this arty started

    Characters Before
    The androgynous stickmen of Rebuild 1

    A couple weeks ago I posted looking-for-artist requests on Newgrounds, DeviantArt, TIGSource and FlashGameLicense, and got a couple dozen responses. I was kind of expecting more, seeing as it was a paid contract to work on the sequel to a popular game, and I was surprised at how many of the responders hadn’t even looked at the original game. I did however get a few very exciting responses from people who had played the game and were – bonus – great artists.

    Insanity 2 screen
    Insanity 2, now THAT's horror

    I chose EvilKris, creator of the Insanity and Insanity 2 point and click horror games. He works with 3D models and layers of texture to produce some truly dark, creepy images, far more realistic and disturbing than my clean and cutesy vector art from the first game.

    EvilKris's character art in progress
    EvilKris's character art in progress – the one on the left uses my actual face!

    To start with he’s been working on characters and equipment to replace the old faceless stick figures, so you can really see the fear in your scavenger’s eyes as you equip her with a pistol and send her off alone to desperately scrounge for food at an Allmart teeming with the living dead.

    Next will be the gory stuff for the zombie attack sequence, which I’ve decided is not going to be a minigame after all. I’m going to spend more time instead expanding the strategic game, adding plot and NPCs, equipment resources, new buildings and new endings. I hope the sequel will have more replayability, but one thing is for certain: it’s going to have a more a darker more engrossing (and also more gross) visual style, which will fit better with the storyline.

    In other news, I recently did an email interview with Ethan Moses of HorribleNight.com where I talked a little about my inspiration for the game and the relative merits of zombies vs hive-minded insect aliens.

  • 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;
    		}
    	}
    }