Posts Tagged rubymotion

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

Banana Breakers: Indie Dev Learnings

Before trying a more ambitious game on mobile, I wanted to do a series of smaller experiments to learn a little more about the app submission / marketing process. I’ve got a few apps out already, but those were mostly hobby-fun-tinkering projects and not built with *serious face* revenue in mind. Experiment is probably the wrong word, since good little children who paid attention in science class know that a good experiment is designed to test a specific hypothesis, whereas with these first few games I’m mostly taking stabs in the dark to see what I can learn. What I’m hoping to learn, though:

  1. What tech should I build my games with?
  2. What platforms should I support?
  3. How can I get some exposure without spending too much?
  4. Which third-party ad/analytics providers should I use?
My first game, Banana Breakers, has been pretty helpful so far.

1. What Tech Should I Build My Games With?

I’ve been working on Banana Breakers (link to game site) on and off for probably four years, but in terms of actual complexity it’s a really simple game. I originally prototyped it in Flash a few years back (just the core mechanic of 4/5/6 words hidden in a grid), but it was Too Damn Hard. It was such an easy prototype, though, that any time some shiny new technology came out I would re-implement it to test out that tech. I have a Haxe version. I built an Enyo (javascript) version a few years back when I got a Touch Pad. I built a native iOS version using RubyMotion when that came out last year. When my friends at Spaceport.io needed beta testers, I re-built it once again in Flash–but this time thinking of it as a mobile app. Eventually I ran into technical problems with Spaceport (they didn’t have 3rd-party code support yet), so I switched over to Adobe Air. When I heard about Futile (a 2d plug-in for Unity) and Loom, I almost built new versions… I may have a problem.

Banana Breakers was also a departure from my earlier games in that it would be free, but with ads and the ability to buy more coins. I also wanted to support incentivized video as a way to get more coins without paying, as those always converted fairly well back in my Facebook days. Finding a tech that supports all of those (well) turned out to be more challenging than I thought.

Adobe Air and Unity both support native extensions, but Air’s implementation is god awful. I lost an entire week just trying to get the “Hello World” of native extensions to compile with my setup before saying “screw it” and just going with off-the-shelf ANEs (some of which I had to buy). Because I needed so much 3rd-party support, I crossed Unity off my list pretty early in the development process. They have even fewer native extensions than Adobe Air, and at the time they were still charging for the iOS and Android plugins. Even now, the free indie license requires you to use a Unity splash screen and doesn’t come with access to native extensions. I could probably get over the splash screen, but the lack of extensions would probably limit Unity to only paid-download games for me.

So what tech did I end up going with? For Android and Kindle Fire, I used Adobe AIR (since I already had an AS3 version ready to go). I could have re-written using Starling to get better performance, but at that point I was ready to release something and get some data. I wasn’t happy with the performance of AIR on iOS, so I converted everything to bitmaps and build a native iOS version using RubyMotion. I’ll do another post later about how I’m using RM to build games, but for now my tech stack is pretty much RubyMotion and Photoshop (with some custom scripts to help speed up UI development). And it’s a lot of fun. I don’t know if it’s the right choice (iOS only), but so far I’m really happy with it.

2. What Platforms Should I Target?

There’s two ways to think about this:

1) Supporting multiple platforms is expensive and only worth it for a successful game.
2) It’s easier to be a big fish in a small pond–targeting less successful platforms might be a way to get traction/cheaper users/less competition.

My original thought was pretty much #2, assuming I could settle on a tech that was cross platform. In practice, Banana Breakers has pretty much made me change course entirely back to #1. Even though I originally built the game to be cross-platform, the amount of work needed to set up in-app-purchases, ads, and other native “touches” turned out to be pretty nontrivial (especially when you throw in device testing). At least for me, building a game cross-platform means it will take probably twice as long to build… and at this point I’d rather make more games.

I’ve also been disappointed with download numbers on both Kindle and Android. For Kindle, it seems as though free games don’t even appear in the “new games” section of the app store. That makes sense in hindsight (their marketing engine is designed entirely around promoting things that cost money), but it was still a bit of a shock. Android was slightly better (3-4 downloads a day), but nowhere near the 500-1000 downloads I got while on the “new games” sections of iTunes. Having a game out on multiple platforms would also mean (theoretically) that my marketing efforts would need to be split between the platforms. Realistically, though, I’ve been focusing all my efforts on the iOS version and completely ignoring the Android versions.

If I have a game that is a monster success, I’ll consider looking at other platforms. For now, though, the decision to go iOS-only for future games is an easy one. If anything, I’d consider doing desktop-PC on top of iOS before I would consider doing android or kindle. If I were to do a native version for any other platform (Windows Phone 8 is tempting, since I’m one of the few users), I would just do a native build for each platform.

3. How Can I Get Some Exposure Without Spending Too Much?

Distribution is probably the single biggest hurdle to making a living as an indie developer right now. I’m nowhere near figuring out, but I can run through what I’ve tried so far:

1) Release the game. Free. I got ~500 downloads just for releasing the game on iOS.

2) Review site blitz. Free (ish). ??? downloads. I sent out ( slash-filled-out-contact forms) somewhere in the neighborhood of 150 emails to various mobile review sites. The vast majority of them did not respond, and those that did were offering paid reviews. I got a nice write-up from JayIsGames (they’ve written up some of my flash games in the past as well), but nothing else. So far this seems like a giant waste of time, though I’m sure bigger sites do create a nice download bump. I think it’s worth to build relationships with sites that aren’t too scuzzy, but at this point I think efforts spent on this type of PR would be better spent doing blog posts and engaging on twitter / forums.

3) Gnome Escape. $250, ~200 downloads? I’ve read a lot about how shady pay-for-review sites. Gnome Escape was on one of the giant lists of publishers to contact for reviews, though, so I gave them a look. They say all the right words–authentic reviews, etc… but ultimately it’s just incentivized installs (with incentivized reviews on top of the incentivized install). I got a nice bump of 50-60 people a day for a few days (along with several who monetized) and some good reviews, but most of the reviews were spam-bot level in quality (just regurgitating my app description). My thinking was that 200-250 users for $250 is about $1 a user and not too bad… They delivered what they offered, but I don’t think I would use the service again.

4) AppFlood. $250 each, cancelled. Just to get a sense for how they worked, I dropped $250 into my AppFlood account and set about driving some paid installs. To get any sort of volume in the US, I would’ve had to up my bid to the $3-$4 range, and there’s absolutely no way Banana Breakers could recoup that. I want to try ChartBoost later (they have a lot more volume), but so far these seem pretty overpriced.

5) Free App Magic. $1000, ~8000 installs. The last thing I wanted to try was some way to get burst downloads (and hopefully make it onto the charts). There are tons of free-app-a-day apps that promote an app or two a day, but most of the big US ones cost thousands for a feature. I set out to find a slightly smaller one with a more reasonable intro rate, and FAM definitely fit the bill. The intro rate I got is probably not repeatable (I took the place of a game that cancelled at the last minute), but the results were great. They estimated that they drove ~4k installs, while the other 4k were organics from hitting the top ten in word games in the UK (most of their traffic is UK). The game stayed on the charts for a few days, but is now slowly dropping out. The 25-30 installs per day I’m getting now (a week+ after the promotion) is slightly better than the 5-10 I was getting before the promotion, but I’m not sure how permanent that will be. I consider this to be the only successful bit of marketing I’ve done (twelve and a half cents-per-user would be a phenomenal rate for a better-performing game, and if I could get similar CPIs at other daily download sites they’d be worth the higher fees).

(UPDATE)
6)  My Chartboost campaign was finally approved and I was able to run $250 through it very quickly, even at bids of $0.50 for US installs. I’m not sure how many installs are available at this price (I would guess that as you start trying to drive more volume the price would have to go up), but as an initial test Chartboost is another promising way to get users at a good price.

My original goal was to only spend $1k on marketing Banana Breakers, so at this point I’m $300-$400 over. It doesn’t perform well enough to keep spending, but hopefully I can take some of that knowledge on to better-performing games.

4. Which third-party ad/analytics providers should I use?

This has probably been the biggest shock with releasing a game. At Crowdstar we had an entire dedicated Business Intelligence department, a massive Vertica database to warehouse game event data, and dedicated analysts to help sift through the data. I’d always heard good things about Flurry’s event tracking, but from my point of view the data is sorely lacking. The install, retention, and session charts are pretty good… but there’s no easy way to hook it up to purchase data. And it’s not realtime. The data they provide seem like an okay way to track your installs and active users, but I don’t see how anyone could take specific in-game actions based on this granularity of data. I wanted to go entirely server-free for Banana Breakers (mostly because I’m cheap, and nothing wipes out meager indie game profits like server fees), but for future games I’m thinking I’ll roll my own. Helios (by the Heroku guys) looks strong, but doesn’t do exaaactly what I want. I’m leaning towards a super-simple redis-backed logging system with built in a/b testing, but it’s also tempting to abstract a little more and see if I can come up with a generic service for the things I want to do.

Chartboost > All Others

Ads have been a little better. Banana Breakers has interstitials (AppFlood & ChartBoost), banners (Flurry and AdMob), and incentivized videos (HyprMX and AdColony). So far ChartBoost is the clear winner–interstitials are blowing all the other formats out of the water. Banners are probably not worth having in the game. While their annoyance might drive players to upgrade, the game would have to be a total smash hit for the ad banners to pay for the extra time it took to make home screen layouts that support banners. I’ve been really surprised at how poorly the incentivized videos have done. I’m guessing that means either (a) most users don’t know they’re there or (b) the word puzzles aren’t hard enough to warrant users needing extra coins (which would also lead to low coin sales). Once I throw in in-app-purchases, the graph looks more like this:

So ads are actually outperforming coin sales by about 3:1. The numbers here aren’t huge (~$51 so far for coin sales, ~$136 for ads), but I think the trends are still pretty useful. If I’d had a back-end server set up, I would be able to tweak what portion of each type of ads go to each provider (home brew mediation). I’ll hopefully get that set up for future games.

Overall the budget for Banana Breakers was about $2600 + dev time, so it’s unlikely at that point I’ll make back the development costs, but it’s been a fun game to work on.

, , , , , , ,

1 Comment

RubyMotion, SublimeText, and Breakpoints

RubyMotion released a new build today which supports GDB debugging. I did my early Flash games with just a text editor, the command-line compiler, and FDB, so the concept of a command-line debugger isn’t totally foreign. Still, I’ve gotten pretty used to nice GUI debugging tools. Those are hopefully on the way for RubyMotion, but in the meantime I wanted to see if there was anything I could do. The debugger in RubyMotion supports a simple debugger_cmds file with breakpoint commands, so the first thing I looked for was a way to set breakpoints in TextMate (even keeping them in a file somewhere). At worst, I figured I could put some comments (“#BP:blahblahblah”) and do something similar to the TODO viewer. Cumbersome, annoying to disable… not the best idea.

While looking around, I stumbled across the SublimeGDB package for Sublime Text 2, along with a couple of RubyMotion bundles for making builds easier (a syntax bundle and a build helper called SublimeRubyMotionBuilder). That was enough to give it a shot. I’m pretty new to Sublime, Python, and GDB–so I had no luck trying to get RubyMotion to connect with it out of the box. I imagine RubyMotion is doing some alchemy under the hood, but I was willing to settle for visual breakpoints.

The SublimeGDB has a “view breakpoints” action, but this doesn’t map exactly to a file. There’s probably a cleaner way to access the data directly, but here’s what I settled on:

Within RubyMotionBuilder.py (in SublimeRubyMotionBuilder), I duplicated the “RubyMotionRun” action into “RubyMotionDebug” (along with creating a corresponding rubymotion_debug.sh and adding entries to the command/menu/keymap). That function already finds the Rakefile for the RubyMotion project, then calls out to a shell script. Here’s my RubyMotionDebug function:

[gist id=3759265]

The sleep is a little dirty, but I kept ending up with an empty paste buffer because of the time needed to render the BreakpointView. There’s probably some way in Python to check if gdb_open_breakpoint_view has been defined (i.e. the SublimeGDB package is installed), but I’m pretty content with it for personal use. I’ll probably map the Toggle Breakpoint command to something a little easier (currently you have to right click and select the menu item), but it’s a pretty compelling reason to use SublimeText for doing RubyMotion development (also the autocomplete seems a lot better).

RubyMotion + Break Points

 

Update: I put all my tweaks in a fork over at github (https://github.com/SimianLogic/SublimeRubyMotionBuilder). Just add a package repository in sublime, delete the old SublimeRubyMotionBuilder, and install the one from my fork. I don’t want to submit it as an actual Sublime Package because (1) I don’t know how (and am lazy), (2) there’s still a dependency on SublimeGDB which means it can’t stand on its own as a package, and (3) I’m sure the guys at RubyMotion are working on better tools anyway. This is a temp hack at best!

, ,

1 Comment