Posts Tagged iphone

on workflows, flash, photoshop, and rubymotion for games

First, a little background on how I’ve learned to make games.

Phase 1. I tinkered with some games with Macromedia Director as an undergrad, but I literally remember nothing about Lingo or the Director environment. Whatever I was doing, I was probably doing it wrong. I switched to Processing in grad school and loved it. Processing is very powerful (once you take off the training wheels, it’s really just Java), but bare-bones in terms of a display tree. There’s essentially a single canvas and you issue drawing commands to it. The simplest way to build games with Processing is to just keep your game state in various data structures (arrays for everyone! you get an array, and you get an array, and you get an array…). Every frame you clear the screen and draw everything brand new from your data objects. I ended up with lots of helper functions for each screen, things like “drawTimer,” “drawButtons,” “drawGameBoard.” Everything was vector-based using primitive drawing commands, so tweaking your UI layout meant changing some magic numbers in the code and re-running the app. Cumbersome, but not so bad (there’s only one screen, after all).

Phase 2. Some time around 2007 or so, I got an alpha invite to Whirled, a Flash-based game/world/thing by Three Rings. I figured I’d better learn Flash so I could make stuff, so I got to work making weird things using pure AS3 and the free flex compiler (student me: “$800 for Flash Builder? Ain’t nobody got time for that!”). My workflow was essentially unchanged from the Processing days (I was still drawing everything in code), but AS3 has a fricking amazing display tree. A DisplayObjectContainer seems like a “no shit” construct in retrospect, but it sped up development a ton. Even so, tweaking anything UI-based still required changing magic numbers and recompiling. I made a couple of games using embedded bitmaps, but even those were placed by code. After the success of Filler, I picked up a copy of Flash (the program) and used it to make the UI for Filler 2. Again, I did everything wrong. Filler 2 has all the different screens on the main timeline, with the main class a document class. I was using Flash (the program) as my compiler instead of the flex compiler, and it was an absolutely terrible workflow–even worse than laying everything out by hand.

Phase 3. Starting with Color Tangle, I used Flash (the program) the “right” way. Flash (the program) is used to create art, and all the various screens and art pieces are exported in art SWCs. Holy crap-on-a-stick is that faster and more awesome than laying out your games by hand. Instead of focusing your effort on where thing go, almost all of your development time is spent focusing on what things do. This seems like a subtle distinction, but it makes a huge difference. Want to move your HUD from the top to the bottom? Change the position of two text fields? Make a button smaller or larger? No problem! All of your interaction logic accesses things by name (i.e. set the text of “hud.scoreLabel” to be “12345″), without a thought or care to where that thing is on screen.

When people jump through hoops to try to get Flash working on mobile, this is the thing they’re trying to preserve. Don’t get me wrong–I like vector graphics and even prefer them in most situations…  but ultimately how the graphics are stored is much less important to me than how I interact with them in code.

So what are some other things about Flash (the program) that makes it so great for game development?

  • All of your layout and creation tools are in one program. This saves a ton of time. With a bitmap-based workflow, you typically need to export your bitmaps/textures at all the right resolutions, import them into a separate  layout tool, lay them out, and then export that layout. There are lots of tools for this (Spriter for animation, Interface Builder for iOS UIs, etc). Or, worse, take your raw bitmaps and place them via code (which is going to take several iterations of compiling and checking to get right). Basically, every extra step you need to take from asset-creation to running-in-game is going to add workflow delays.
  • Symbol-based workflows more closely match UI paradigms. When using raw Photoshop, there is no concept of a re-usable symbol. You can kind of fake it with layers and groups, but it’s a rough approximation. Having the notion of “this is a progress bar” which you can place on multiple screens is great. Edit the symbol and your changes propagate to everywhere that symbol is used. In a bitmap-based workflow, you need to edit every instance. This can be somewhat mitigated by using an external tool to do your layouts (maybe Spriter?), but I don’t know of any custom-built UI layout tools (other than Interface Builder, which I don’t like).
  • The text engine in Flash (the program) is the same as in Flash (the runtime). I kind of hate bitmap fonts, mostly because of how much of a pain in the ass it is to do text layouts with any accuracy.

There are probably others, but those are my big four (including the name-based access in code). There’s probably a big market opportunity to for someone to write a symbol-based graphics editor, but that’s more than I’m willing to take on. How am I solving those issues?

After bailing on Adobe AIR for RubyMotion (see my last post for why), I was pretty much stuck with a bitmap-based workflow. All of my UI assets were already implemented in Flash, so I mostly just needed to rasterize them. There are a couple of ways to do that–I’ve been following the development of Flump (also by the Three Rings guys), but it doesn’t support text and UI layouts probably benefit the least from things like texture atlases (how do you atlas a 2048×1536 background?). I decided to write a Photoshop script to emulate a lot of what Flash does with SWCs, along with a helper class in RubyMotion to help load and manipulate the graphics.

On the asset exporter side, I found a script on the web that exported every layer to its own image and modified it to:

  • exports metadata for every layer in the photoshop file (depending on naming conventions) — usually just the bounds is enough
  • for images, export the full resolution image as an @2x version, then downsize and export the non-@2x version
  • if I find a matched pair of “btn something up” and “btn something down”, note in the metadata that this is a button
  • if I find a text layer named “text something”, export the font size, color, alignment, and textfield bounds… but not the text
  • if a text layer is not named “text …”, rasterize it and export as static text

On the RubyMotion side, I built a GameObjectView class which is essentially an extension UIView with a bunch of helper methods for standard game variables (x,y,rotation,scale) as well as methods to load from metadata. When loading from metadata, the class automatically turns buttons into UIButtons and text fields into UILabels. What used to be a lot of boilerplate asset loading is now basically the same workflow as in AS3. Whereas before I might type something like:

//SomeGameScreen.as
var bg:BackgroundClip = new BackgroundClip();
addChild(bg).
bg.someButton.addEventListener(MouseEvent.CLICKED, mouseHandler);
bg.someLabel.text = “hello world”;

In my GameObjectView, it goes something more like this:

#some_game_screen.rb      (actually probably something like some_game_screen_controller.rb)
@bg = GameObjectView.alloc.initWithFrame(view.frame)
@bg.load_from_metadata(“some_game_screen”, self)    #self is a tap delegate
@bg.labels["some_label"].text = “hello world”

#later on in code land, our tap delegate
def tap(button)
tap_handler if button.name == “some_button”
end

So, in other words, pretty much my same Flash workflow. It’s not all aces, though–there are a couple of downsides to this workflow. Photoshop has no notion of an empty textfield, so in order to export the bounds of a text field there must be actual text in it… but even then, it exports the bounds of the TEXT and not the text field. The text engines for Flash and iOS are close, but not quite close enough–I find that text gets clipped without a little extra padding (and especially so if your default text is smaller than any dynamic text you shove in later). So I end up “filling” all my text fields in photoshops with ones and lowercase p’s–something like this:

 

It’s certainly in the “I can live with it” category of annoyance. Another annoyance is that the exporter isn’t as solid as Flash’s publish (obviously). Weird things happen sometimes when layers are in groups and it takes a little while to run. If you interrupt it mid-export, your layers could be in a weird state (say, downsized by 50%) which could cause headaches if you don’t catch them (why is my game suddenly rendering at 1/4 the size it was before!!!!!).

Secondly, this is NOT a performant way to store and load images. Ideally these assets would all be texture packed into nice power-of-two images… but my goal was “fast enough for my purposes” and not “best possible solution.” Because assets get re-used in multiple screens (I have different folders for iPad, iPhone, iPhone4, and for landscape variants of each screen), it’s possible that the same image could be used by different screens or devices but bundled multiple times in different folders. Banana Breakers, for instance, has over 2000 images exported using this method. I use a ruby script as part of my build process to compare the bytes of each image and build a lookup table to match duplicate filenames to the kept copy. For Banana Breakers, this de-duping removes 1200 files (~22 megabytes worth).

Likewise, I have to be at least a little careful about how I create my images. Large empty/alpha spaces between assets get exported just the same as filled in spaces, so it’s a balance between having lots of images to load vs minimizing file size.

To re-use assets and closer approximate a SWC library workflow, I usually put multiple assets into each PSD. The only piece of metadata I have to work with is the layer name, though, so I end up using it for a lot of stuff:

  • tagging whether a layer is a button, an image, or a textfield
  • tagging whether this is a button’s down state or up state
  • tagging what “view” this belongs to — I do this with selectors in my load_from_metadata function, something like {:include => “menu”, :exclude => “content”}. So, say I have a popups PSD that includes pieces for a confirm and an alert. A confirm and an alert are pretty much identical (one has an “ok” button, the other has two buttons for “confirm” and “cancel”). All of the shared pieces end up with names like “btn confirm alert down” and “text confirm alert title”. When creating one, I can do things like

    alert = GameObjectView.alloc.initWithFrame(view.frame)
    alert.load_from_metadata(“popups”, self, {:include => “confirm”})

So how does it do overall?

It solves my two biggest needs — asset-name based workflow and and content/layout in a single program. I don’t think there’s a way to make Photoshop suck less when it comes to symbol-based workflows, but I can live with that. The text parts are not perfect, but work well enough that it’s not a huge slowdown. I can write my game screens with code that is essentially blind to differences between devices, and just have a different image folder for each supported resolution.

A couple of people have asked me why I use native views and not Cocos2D, which now has an excellent ruby motion wrapper in Joybox… mostly I never saw the point! Cocos2D has some great features (easy physics integration, node-based display tree, tweens, sound manager), but for simple games the native display tree is more than adequate. Unless you’re blitting hundreds of bitmaps onscreen, the native views are plenty fast for even fairly complex layouts. A sound manager is trivial to write. CoreAnimation is surprisingly good. So, basically, I didn’t see anything in Cocos2D that I wasn’t already getting with native views. Learning and mastering the native view architecture would make integrating third party code easier (as well as writing non-game apps), and I would never run into any weird “how do I make X work with Cocos2d” issues.

, , , , , ,

1 Comment

Filler for the iPhone, ScoreCaching, and Filler 2

Filler for the iPhone

Filler for iPhoneAt long last, Filler is now available on iTunes (you can see my little splash page + iTunes link here) for $1.99. I’ve never outsourced anything before, so it was a bit of a learning experience. I ended up working very closely with the team at ChaYoWo–they’re probably happier to be rid of my long bug reports than they are to actually launch the game (I kid). I’m very satisfied with the final product–even if it doesn’t sell a single copy, there’s a certain joy in being able to play my game wherever I go now. There are a couple of interesting things that happened during the development of the iPhone version.

The first thing I usually hear when people see I’m working on an iPhone version is that I should make it tilt-enabled so you can move the balls around. The problem is… that makes the game stupid easy. It’s not really that hard of a game to begin with (but man is it good to kill 5 minutes while you’re waiting for a bus…), so adding in more mechanics to simplify things just seemed like the wrong direction. Another idea I had was to use the tilt to move around the cursor, and have a button for making filler balls. We actually coded this one up, but… uh… it was terrible. In the end we decided not to use tilt and to keep the gameplay closer to the original Flash version.

One thing I noticed while playing early builds (which I also noticed while playing various clones that are already on sale) is that your fingers really do get in the way of dragging the Filler balls around while they inflate. Most of the strategies for the Flash version involve creating balls near the top of the screen and then using them as shields while they fall. “Finger-blockage” is at its worst when your finger is at the top of the screen, though, greatly diminishing the usefulness of those strategies. While playing those early builds, I did something radical: turned my iPhone upside down. Success! Sure, the balls are floating up instead of falling down–but man it was great to see the whole screen. Asking players to flip their phones upside down is just silly, though, so I did the sensible thing and reversed gravity.

ScoreCaching

While the ChaYoWo guys were coding the app to my demanding specs, I got to work on another integral piece: ScoreCaching (Update: ScoreCaching has been killed). Most of the iPhone games I’ve played with online leaderboards do just that–global online leaderboards. I wanted a little more than that, so I figured I might as well build it myself. ScoreCaching combines the idea of online leaderboards with geographic location (think Geocaching). Instead of comparing your scores to everyone in the world, why not compare your scores against everyone nearby? Even better, why not leave your scores behind as a mark of your achievement? Just as people used to line up at arcade boxes with the hopes of leaving their initials in the number one spot, ScoreCaching will (eventually) allow players to mark specific places. What’s your high score for the Golden Gate Bridge? What about Times Square? How about the pub down the street? Those features are a little ways out still, but for now you can compare your scores with your friends and those around you.

Filler 2 (Flash)

Kongregate!When Shockwave offered to sponsor Filler 2 as a three-month exclusive, it seemd as if the stars were aligning perfectly. That would give me extra time to finish up the iPhone version, ScoreCaching, and the XBox Community Games version (whoops!). I didn’t quite finish the XBox version (though I did write a hell of a lot of reviews over at Worth the Points), but Shockwave’s exclusive is up and now the rest of the internet can finally enjoy Filler 2. Kongregate, the totally-kick-ass sponsor of the original Filler, is reprising its role for the second go-around. You can play it over on Kongregate here or play it on my site with the link on the sidebar–I’ll start spreading it around the rest of the net sometime next week. If you run a flash portal, feel free to snag the SWF off my site (the one on Kong is site-locked until I verify it’s totally bug-free). If you’d like to license the game for your site (ad-free), drop me a line at learnyourabcs@gmail.com.

What’s Next?

On top of everything else, I’m also one of the developers in Mochi’s Brave and the Bold Contest. A $4k (minimum) payout is okay, but let’s get something straight–it’s freakin Batman. I watched the original Batman cartoon every day for years as a kid (I was a Marvel kid when it came to comics, but the Batman cartoon was awesome). Getting to develop an original game concept with one of my favorite characters–that’s a sweet deal.  I’ve also got a handful of other finished prototypes in the pipe that are currently on hold until I can clear some of this development logjam.

As always, stay tuned to this space for interesting facts and figures on how everything is doing.

, , , , , ,

No Comments