Posts Tagged flash

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

Announcing Color Tangle for Flash, FB, and iPhone


I’ve been neglecting my blog even more than usual since joining CrowdStar last February (working on Happy Island and It Girl), but honestly I haven’t had a ton to report for personal projects. Until yesterday, when I finally released Color Tangle as a standalone flash game on Kongregate and Newgrounds, aFacebook app, a standalone website with Facebook Connect, and an iphone app.

I’d played single-color knot games before, but never had any interest in building one. I was actually working on a prototype for an explosive based game using APE (the same physics engine in Filler) when I had the idea to use APE’s grouping system to create collision rules–particles that collide with some but not all of the other “stuff” on the screen. I whipped up a quick prototype, and instantly recalled other knot games I’d played. It seemed like a perfect fit! I had the “first” level up and running in less than a day. I’d been looking for a simple project (and this is a very simple game) to try a multi-platform (facebook, web, iphone) launch, and this seemed like a perfect candidate.

The next task was building an editor–which took about a week. WIth editor complete and a dozen puzzles or so in hand, I next built out the website from scratch (Ruby on Rails hosted on Heroku). I got to play with Sass and Compass (which are awesome), got to play with the Facebook API (not so awesome), and experimented with the blueprint CSS framework (also awesome). I built a widget using LocalConnection so players on external sites could connect to the game via FB connect (which I thought was pretty damn slick). I even started on the iPhone app using OpenFrameworks, getting it to the point where I could play my handful of levels.

It was right about that point that a recruiter pitched me on joining CrowdStar, and the project just… died. In my year and a half plus at CS, I’ve learned more about web programming and games than any other time in my life, and I really haven’t had a lot of time to tinker.

I could’ve just released it–the flash app was working, the website was working, and the facebook app all worked. But I learned from Filler how important it was to be first to market on mobile, so I just let the project sit for a few months while I threw myself into my work on Happy Island. I jumped off of Happy Island and started working on It Girl in June. Between that and getting married last October, I had no free time at all for tinkering. My schedule finally started cooling off around February/March of this year, so I picked the iPhone version up and “finished” it. The only problem was puzzles. Creating a couple puzzles on most nights, it took me roughly 2 months to get up to the 50 puzzles I thought I needed for launch. I submitted the app to Apple in June and it was approved the first time around. I set a release date of August 25 (my birthday) to give me a couple of months to polish up the webiste.

Having not touched the website code for over a year, the FB API was horribly out of date. I got distracted by another project along the way (look for another iPhone app soon), but my self-imposed deadline of August 25 finally gave me the pressure I needed to get my ass in gear. After a couple of weekends to get everything migrated over from FBML to pure iframe Canvas, I invited a few friends to start testing it last weekend and launched it fully yesterday.

I don’t think it will do all that well on FB (I know just a little more about designing for FB now that I’ve been doing it for a year and half), but I wanted to carry the original project vision through to completion. In the end, it was a really fun technical project, and I really enjoy playing it.

, , , ,

3 Comments

Plastic Attack! Post-Mortem

Plastic Attack!

Winners for the Batman: Brave and the Bold game contest were announced back in August, but the individual games were released one-a-week for the 10 following weeks. My game, Plastic Attack! (play it here), launched some time in September, right as I was on my way out to the East Coast for a couple of weeks. Now that I’m back and things are somewhat starting to settle back down to normal, I thought it would be fitting to go back and take a deeper look at the game from start to finish.

The Prototype and the Pitch

When Mochi announced a pitch contest back in March, I was already knee-deep in code for other projects. I had plenty of prototypes lying around, though, so I dusted off one I’d been meaning to expand and built a simple HTML page explaining my pitch. If you scroll down on that page, you’ll see a simple mechanics demo I built in Processing one night while I was at Georgia Tech. The idea was to do a simple platformer starring a ball with realistic squash and stretch animations. As you can tell from the demo, the ball can’t just “jump”–it first contracts down a bit and then flings itself upwards. The other balls were there simply to give the “main ball” something to bounce on, but even there you can see the core idea of “bouncing on things that are destructible.”

The thing I’m most proud of with Plastic Attack!, though, is how similar the end product is to the pitch I delivered. I knew there was a fairly quick turnaround (roughly two months from start to final submission), so I didn’t go crazy. Knowing how much I wanted to deliver was absolutely essential for such a short timeline, and it made it easy to fend off feature creep and even cut some features that would’ve taken too long to polish properly.

Production

Between the time I submitted my pitch and when the “production” phase of the contest actually started, I knew I needed to refine my workflow if I had any chance of finishing on time. Filler 2, though I like the end result, was a jumbled mess of code–after all, it was first time using “real” Flash and not just pure actionscript. To that end, I was able to squeak out Polar Games: Breakdown in April and lay down a fair bit of code that is now sort of my “stock” engine for handling things like data storage, screen management, and other useful bits. The first alpha of the game was pretty rough, though large pieces of the final game were in place: a complex keyboard input manager, a randomly generated “level” (which isn’t always “beatable” in the demo below), parallax scrolling (up & down),  a 2D camera system, and a key-sequence finale. Having planned to use canned Batman animations, the only thing missing (well, the biggest thing missing) is actually the notion of squash/stretch from the original mechanics demo.

After playing the Alpha, the Warner Bros. representatives got back to me with pretty much the best idea ever: instead of trying to shove Batman animations into this game, why not use Plastic Man and stay closer to the original mechanics demo? Brilliant! There’s something to be said for working with established IP–these guys really knew their content. That one piece of advice completely turned the game around for me–not that I would’ve mailed it in with Batman animations, but using Plastic Man realigned the development to be exactly the game I wanted to make. I set out to do just that.

As soon as the alpha was a little more polished, I abandoned the notion of a random level generator entirely. The results just weren’t good enough to warrant spending more time on it, so it had to go. Though it looks like a platformer, in my head the game was supposed to play more like a racing game–where track knowledge is a key component to success or failure. The levels were constructed in such a way as to allow the player to sprint from start to finish, with occasional breaks (like the two-bounce platforms) thrown in to add difficulty. I ended up building ten levels which could be played independently (each taking ~35 to 45 seconds to complete) for medals and a “Marathon Mode” which required you to get through all ten as fast as possible (with deaths resetting you to the current level).

After doing Filler for the XBox, I was really in a “controller” frame of mind. I wrote a KeyboardManager class that basically turns it into a game controller. When you initialize it, you take any keys you like and assign actions to them. The keyboard state is polled during the game loop and builds a corresponding array of everything that happened: new keypresses, keys released, and keys still down. I liked how it worked so much that I made most of the menus respond to keyboard input on top of the usual mouse stuff for buttons. A nice side-result of this approach is that most of the platform code is fairly platform-independent. It would be fairly trivial to take my XBox controller code and plug in into the platforming code with very little effort.

What Went Wrong

Throughout the production of the game, there were only really three curveballs. Soon after reviewing the Alpha, they mentioned that the resolution had to be 688×375, not the 640×480 I was building. The proper resolution was actually in the original email, so it was totally my fault. Much of the features parallax scrolling, how high you can jump, etc. had been tuned to 640×480, so that took a bit of retooling. I should have made it liquid to begin with, though, so in the end it actually improved the underlying code.

The second problem was my grandiose idea of squash and stretch. The problem with forcing the character to press down before allowing a jump is that it created roughly a 100-millisecond delay between when the spacebar was hit and when the character actually left the ground. The Warner guys didn’t like it, so they asked me to cut it. I defended my bouncing, but what I ultimately realized is that it wasn’t so much the bounce code that was the problem but the overall difficulty of the game itself (by this time several players had mentioned that they couldn’t beat the first level–more on that below). There were two options to simplify things: re-design all the levels from scratch to make them easier, or make the controls more responsive. Given the tight schedule, it was a no-brainer. The Warner guys loved it without the delay and I got to keep working on other stuff.

The final issue had to do with high scores. Towards the final Betas, I learned that the game would need to have a single “end point” with one high score. What I had was 10 levels (each with their own “low score”), and several Marathons (my original build had a straight runthrough all 10 levels, a first-5 set, a last-5 set, an odd set, and an even set). Converting the time into a point score is trivial–just take a “max” value and subtract the player’s score. Getting the game down to a single exit point, though, was slightly more worrisome. I ended up cutting all but the “full” Marathon (all ten levels in a row), which I think might’ve been a mistake (I don’t know what the right answer was, either, though). The barrier for entry on submitting a high score is just insanely high in the final build: before playing Marathon mode, you must “complete” (get at least a bronze medal) all ten levels. Though I can beat any of them in under 45 seconds, watching a few first-time players try it I’ve seen them take up to 30 minutes to beat the first level (far longer than a normal user who wasn’t playing as a favor would likely give the game). Assuming that they do finish all ten levels, they then have to finish the marathon itself–my best time is somewhere around 5 minutes, but my worst times are in the 15-20 minute range. That’s just way too long to have to play before being allowed to submit a score.

Besides the three production hiccups, I’ll also toss on a more philosophical issue summed up by a game riddle:

Q: How far can Mario jump?
A: The width of the hole in front of him.

Technically, Mario can jump further if he’s sprinting, but I think the point comes across. In most platformers (including the 2D Marios), a hole is merely one obstacle of many. Jumping is important, but it’s a binary decision. When there’s a hole, you jump over it. You don’t have to think about the hole too much–the combination of pressing the jump button and holding forward will carry you over it. The jump length in Plastic Attack! is dynamic–you move forward only as long as you hold forward down. The amount of time you stay in the air is fixed, and the default length of the jump (assuming you hold forward) is equivalent to the double-jump (it will clear two floor tiles). Whereas the “standard” platformer makes the single-jump the default action, in Plastic Attack! it’s really easy to overshoot your target (and fall to your death). Though I found it very intuitive to just ease off the forward motion when I get to where I wanted to go, it’s actually a LOT harder than I originally thought it would be.

Designing for Failure

My favorite thing about the game, though, is how hard it is. Wait, what?

I like hard games. I don’t want every game to be hard, but every now and then I thrive on a little challenge. Though I may have gone a little too far, difficulty factored into the design of the game from the very beginning. One of my absolute biggest pet peeves when it comes to games like this is what happens when you fail. Typically there will be a transition to a new screen, perhaps with some exposition or animations on how you’ll never save the universe if you keep falling to your death. At that point you’re given an option to give up or try again. In a good game, you can just press space to continue. If you really want to piss me off, you’ll require that the user click on one of the buttons to continue. I’ll put it in bold, because I think it’s that important: if your game is played with the keyboard, there’s no excuse for making your player switch to the mouse to continue playing. This is the number one reason I stop playing a keyboard-controlled Flash game, and I just don’t understand the reasoning behind it. High score submission? Fine, use the mouse. Main menus and instructions? Fine, use the mouse. Once your player commits to the gameplay part of your game, though, do them a favor and let them hang out there on the keyboard until they’re sick of playing.

More than just letting them stick to the keyboard, I wanted to design for failure. In fact, I want my players to fail. If they can play through a whole level the first time and get a medal, then I feel like I did a really crappy job designing that level. This goes back to challenge–I’ve played too many games with 50 or 100 levels that I never finish. If I don’t get a level that I fail on before I get up to level 10 or 15, I’ll stop playing a game. If there’s no difficulty, it’s just an activity–I might as well flip on the TV at that point. It’s by overcoming those failures that getting a bronze, a silver, or a gold medal actually assumes some meaning. There’s a chance that I’ll turn off a lot of players who get frustrated before getting that first medal, but my hope is that those who make it through will feel like they’ve accomplished something.

With my mini-rants out of the way, back to what happens when you die. Because dying happens so much, I felt like the process of restarting a level should be absolutely effortless. No animations that will get annoying by death #137, no waiting for recap screens to finish–I decided to just go ahead and restart the level. If the player doesn’t want to play any more, they’re most likely going to close the window anyway. If they do want to back out, they can always pause the game and exit to the main menu from there. Because the “cost” of failure is so low, I was actually pretty satisfied with the final level of difficulty.

What Didn’t Make It

There’s only one major feature that I ended up cutting: checkpoints. I didn’t want to just do checkpoints, though, I wanted to do checkpoints right. Because the game is essentially a really hard racing game, several playtesters suggested that I add checkpoints to smooth out the difficulty curve. Instead of restarting the whole race from scratch, you’d merely go back to the last checkpoint. Being a racing game, though, I would want to penalize players in some way–tacking on penalty time or just letting the clock continue to run. While this would be a blessing for beginning players just learning the levels, it completely runs afoul of my “design for failure.” Any expert player is going to reset the race as soon as they take any kind of penalty. If you’re going for a high score, there’s just no room for error. By simplifying the game for beginning players, I would’ve reintroduced the “annoying death loop” for expert players: mess up, pause, reset, start again–mess up, pause, reset, start again. In the end I just couldn’t do it.

Now that I’ve had time to think about it, my solution would be to actually commoditize checkpoints within the game world. Instead of having fixed checkpoints, they would be carried with you at all times in limited supply. For a ten-level game, you’d have 10 checkpoints to use… “ever.” If you need five checkpoints to make your way through one of the levels, those five checkpoints would be “left” in that level permanently. Should you manage to play through again and use only three checkpoints, it would free up two of them back into your pool of checkpoints. A beginning player could use as many checkpoints as necessary to beat a level and then work on refining their approach and reclaiming their “lost” checkpoints before moving onto the next level. A pro player, on the other hand, wouldn’t need to drop any checkpoints and thus could play through the entire level without needing to reset should they happen to fall. A similar mechanic was used to great success in a game called SeppuKuties a little while back.

Ultimately I didn’t have time to finish planning and balancing the feature during the hectic production schedule, so I ended up cutting it altogether.

Next Up

I took a break from the world of bouncing to get the XBox version of Filler out, but now I’m in full production on my own version with an artist friend. The game will be called Free Bouncing (think free running). I still have a lot of decisions to make with respect to things like microtransactions (vs just ads) and user generated content. Check out the teaser images below:

characterconceptart

fb_titlefb_gameplay

, , ,

No Comments