« Posts under behind the scenes

How Many Pages of Code in an Indie Game?

FLUTTERFLY is done and launches for iOS this week! And after almost nine months of non stop work, it’s time to reflect. How much work did I actually do? With an app it’s tough to tell sometimes. You bang on your keyboard typing code at the prompt… then you compile… and then an app appears as a single icon on a device you can put in your pocket.

Unlike a novel, you can’t flip through it and feel the pages. Unlike a movie, you can’t scroll through the timeline to get a sense for every frame. It’s a game! It has no real physical mass, as it were.

So I decided to convert EVERY PAGE of code I personally wrote into a pdf, then in photoshop, shrink them down into little jpegs and line them all up. It’s a fascinating way to get a sense of the over all work involved in an indie game.

So: HOW MANY PAGES OF CODE IN AN INDIE GAME?

The answer?

An astonishing 1,266 PAGES OF CODE in Flutterfly that I wrote myself.

(SCROLL DOWN TO SEE ALL THE PAGES!)

A few big caveats:

1. There is obviously WAY more code in the app than just the stuff I wrote myself. There are tons of amazing plugins that I bought and used. And of course the Unity3d game engine which the whole thing is built on probably has enough bits to fill a library. But for this experiment, I think the page count of the stuff I wrote personally is a pretty cool metric.

2. Pages of code are generously spaced. It’s not like this stuff is packed in there. You’ll see from the images below that code, in this case C#, is not very dense when it comes to the amount of space it takes up. So take those 1,266 pages with a grain of wide-margined salt.

3. Code is repetitive. There’s a lot of code that repeats. For instance, almost every class I wrote starts with
using UnityEngine;
using System.Collections;

It’s part of the lexicon. So it’s not like every line of code is completely unique necessarily.

4. A lot of code gets deleted. The game evolved a lot over nine months. So entire sections were ultimately zapped. I’d estimate that at least a good 10-15% of the final product were axed and aren’t pictured below.

5. There is a lot of work that goes into a game that is NOT CODE. There’s animation and sprite sheets and models and sound and camera work. So the code is maybe half of the whole story. At most.

6. A lot of programmers pride themselves on writing super condensed, tight and streamlined code. The less code the better! I’m not one of those guys! I’m more from the literate school: lots of comments and notes to myself. Just fyi.

7. I’m seeing now that a couple blank pages snuck in there. Whoops. Converting over a thousand pages of code into little thumbnails is no easy task unto itself. I highly recommend this little photoshop script if you’re interested in trying the same for your game!

So without further ado, here are the 1,266 pages of code I wrote for FLUTTERFLY over the last nine months. I’ve colored some of it RED and have annotated those sections. Figured it’d be interesting to get a sense of how much of the code did what exactly. Who knew powerups were so complicated?

See you after the long scroll!

code
code
code
code
code
code
code
code
code
code
code
code
code
code
code
code
code
code
code
code
code
code
code
code
code
WindManager

Whew! I feel exhausted just looking at all of that.

And sometimes writing code is like creating music– it just flows out of you. But more often than not it can be a very exacting and painstaking process where you battle through mazes of logic to just write a single line.

Mostly though, I’m excited about starting the next project! Time to open up a new blank page one.

PS: I did a similar experiment with my previous, smaller app SPIDER PRANK. If you’re curious, you can check it out here!

Leveling Up Your App: 3 Lessons I Learned the Hard Way

So I’m about to launch FLUTTERFLY — a brand new side-scrolling color matching game. Guide colored butterflies as they migrate and match colored blocks.

For those of you who’ve been following this blog or who follow me on twitter, you might know that FLUTTERFLY actually started as FLUTTER. Flutter was a previous incarnation that was a simple endless game. There were no levels. No powerups. No stages. Just one endless side-scroller that went on and on.

I started work on the original Flutter in Feb 2014, and working in Unity3D, quickly got something up and running. The original core concept was to take a fun color-matching / tetrisy mechanic and make it a side-scroller. Could I combine two genres to make the whole greater than the sum of its parts?

It took another few months to polish the game into something I considered finished. And I uploaded Flutter to the app store in mid-May 2014 to (drumroll)… the sound of crickets! Flutter opened with a whimper. Despite some nice feedback from some folks in the community, sales were pretty non-existent. So… game over??

But I still believed there was something great at the core of Flutter. I thought the gameplay was original and fun. The app, however, had a long way to go. For the past five months I’ve been working non stop to make Flutter better. In fact the new version has evolved so much that it’s really an entirely new game. So goodbye Flutter and hello FLUTTERFLY!

In the meantime, here are THREE LESSONS I learned the hard way that I’ve worked very hard to fix.

 

1. PLAYERS WANT TO WIN

I created Flutter originally as an endless side-scroller mainly because I wanted to finish an app quickly and not spend five years on it. Why design 100 levels when you can design 1, amIright? And of course the endless platformer/flappy/runner is a tried and true genre all unto itself. But there’s just one problem. You never win. It’s not a problem for games like Flappy Bird. I think the frustration of dying repeatedly is what spurs players on in a game like Flappy. It’s addictive masochism.

flappy fun

But that sort of hardcore die, die, die experience flew in the face of my app. I discovered too late that people really liked these butterflies. They didn’t want them to die! And when they died, they felt bummed and didn’t want to play anymore. I needed to let people win. So I’ve spent a big part of the last several months developing levels.  I added a FLOWER object that served as a goal for players to reach.  Now players could actually win!

Now players can WIN

Now players can WIN

It has been a lot of extra work, but I think the results have been worth it. Playtesters are experiencing joy with the app finally. Saving butterflies is compelling. Winning is compelling. And it keeps people playing. Besides, I don’t want to be the guy forcing people to kill all their butterflies, right? Because that’s what an endless game is. It’s inevitable death. The lesson for me is that I had a happy game on my hands—not the casual equivalent of Team Fortress 2 (God, but I do love me some Team Fortress 2).

LESSON #1: If losing your game isn’t fun, players better be able to win it.

 

2. SCREENSHOTS MATTER

FLUTTER 1.0 looks great in motion. I made a trailer that I think showcases it nicely. But stills? Not so much. I had this idea I’d be Jony Ive and use this minimalist solid color approach. Helvetica everywhere. The problem is this makes for really, really boring screenshots. So I’ve gotten to work adding particles, flares, glow effects and a nice handwritten font. It makes a world of difference. The game is much more beautiful, both in playmode and in a still screenshot.

Which game would you rather play?

Which game would you rather play?

When you’re an indiedev and no one’s heard of you or your game, screenshots are THE first thing people will look at. I’ve learned the hard way that your screens gotta be amazing. There’s a chance no one will watch your video, not least of all give your game a try.

LESSON #2: If no one wants to play your screenshot, no one will want to play your game.

 

3. ONE MECHANIC AT A TIME

At its heart, Flutter is a pretty simple game. Or so I thought. Match butterflies with colored blocks. What’s so hard about that?

But sometimes as a dev it’s hard to see your own game clearly. If I’d been honest with myself I’d have admitted that there are actually many different kinds of blocks to match: avoid black ones, match identically colored ones, and hit the correct side of a dual colored block. In Flutter I’d spent a good deal of time on a lengthy tutorial hoping this would be enough to get players comfortable. But it wasn’t and they weren’t. They were confused.

I failed to realize that my game really had more than one mechanic. In a way it’s semantics, but I think it’s helpful to think of a mechanic as any one thing a player does that gets a unique result. Matching a black block is DIFFERENT than matching a colored block: it’s a different mechanic. As a result, people were confused playing Flutter. There were too many mechanics thrown at them all at once.

Flappy Bird can get away without a tutorial and without levels. Press the screen once and the bird goes up. That is the ONLY mechanic in the game. But even an ostensibly simple game like Angry Birds has several mechanics happening. If you think about it, the game is more than just a slingshot. Tap the yellow bird and it goes quicker. Tap the blue bird it splits apart. Hit ice and it shatters. Hit wood and it breaks. Pigs with helmets are harder to kill than pigs without. Etc. And the player has to learn and master each one of those new elements. And if you don’t want a frustrated player, introduce new mechanics ONE AT A TIME.

In FLUTTERFLY, what was once a one shot tutorial is now a series of 15 levels (There are over 70 levels in Flutterfly, but the first 15 probably cover what was in the original Flutter tutorial).

Learning is now spread out over many levels

Learning is now spread out over many levels

The player learns the same tutorial content, but it’s spread out over time. Now the player is engaged and having fun as they learn. Moreover they have time to master each new mechanic before moving on to the next. It’s no fun trying to learn to ride a bike and swim at the same time. (For more on this, see Daniel Cook’s amazing presentation on feedback loops.)

LESSON #3: Players can only master one mechanic at a time.*

* notable exception being if the mechanic is so well known it’s part of the vernacular—like running and shooting in an FPS. WASD. We all know that.

FLUTTERFLY launches in a matter of days and so far reactions have been extremely positive. It’s also just super fun and rewarding to see an app you’ve put a lot of love into get better and better! Mainly though, it’s a reminder to me that sometimes you gotta just keep grinding to level up.

Make an App to Make an App (plus how to get Dirty in Unity)

Sometimes you end up making code that no one will ever see. Case in point: FLUTTERFLY has a bunch of different levels made up of different colored boxes. Several boxes put together make what I’ve dubbed a ‘Glow Box Set.’

A picture speaks a thousand words so here’s what the glow box sets look like in-game:

set01

set02

And here’s a glimpse at the Unity3D inspector window for everything that goes into one set:

glowboxset

There are a ton of parameters to keep track of: position variables for all the boxes, what type of box each one is, are we raining? Is this the last set in the level? etc. etc.

For a while I was tweaking all this manually. Now you can imagine that for a game with over 100 levels, where each level consists of 6-20 sets, the work becomes unmanageable real quick.

So I took a few days to design an app for my app. I created a new blank scene and set up a tool for level creation.

It seemed like a big pain in the arse at first, but it honestly went quicker than expected. And now that the tool is done, designing levels is a breeze– and even fun!

Here’s a look at my nifty new tool at work:

tooldemo

Much, much better than manually entering Vector3 position values one at a time.

Getting Dirty in Unity3D

So here’s a bonus PRO TIP for you Unity guys/gals out there. So you have your awesome level editor working and you make your tweaks in playmode, hit stop and WAIT! Where’d all my changes go?

As every Unity dev knows, changes made in Editor in playmode are not persistent. It has to do with serialization which is a huge topic unto itself. But I don’t want a seminar in serialization– I have a game to make! To get my level editor working I just needed to know one thing: How do you programmatically change prefab parameter values in Editor during runtime and have them stick around when you hit stop?

Easier than you might at first think. You just have to GET DIRTY.:)

Add a

using UnityEditor;

to the top of your class, and then call

EditorUtility.SetDirty(yourObject);

to save changes to values you tweak in Editor playmode. With my tool, I call SetDirty when I press the ‘Save’ button (shown above).

Now you can write a ton of values quickly and procedurally at the click of a button (ie– where should all these boxes go? well here’s 100 Vector3’s generated by code). Just be sure to comment the above two lines out before building, because as far as I can tell Unity won’t build if any of your scripts have a UnityEditor ref.

With the tool, now at least I have a fighting chance to finish this thing! Plus it has made level design quite enjoyable– a nice change from the torturous process of manual tweaking.

Odds Are

Okay so Flutter 1.0 landed with a dull thud in the app store. But THAT’S OKAY! It has only encouraged me to make it better.

So I’ve spent the last few weeks adding POWERUPS.

Boy are these fun to play with! More on those soon.

powerup

But in the meantime, I was thinking the other day about games and apps and what if you could pull back their skin and see their guts. Like what if you could take a game and strip it of all the design and particle effects and fancy graphics etc. What would be left?

I think it would look like this basically:

odds

These are ODDS. Aren’t they beautiful?

Specifically, these are the odds that specific powerup types will occur depending on our current difficulty level.

You can see from the array setups that there are 8 levels of difficulty (top to bottom), and 11 powerup types (left to right).

At difficulty 0, when a game first starts, the odds are 80% you’ll get a powerup type 0 (the most basic and rudimentary powerup type), and a 20% chance you’ll get a powerup of type 1.

Looking at the numbers feels like peeking into the Matrix to me. I find it fascinating that looking these over you can almost get a kinetic sense of the gameplay. This is the soul of the machine.

As a developer, odds are always top of mind. And of course with something like powerups, this is just the tip of the iceberg. There are other things to consider.

My coding style is pretty verbose. I comment the hell out of stuff to make sure I don’t get confused later. Apparently this is called Literate Programming. Here’s a snippet of comments outlining some of the odds logic at work:

// *** THIS IS WHERE THE MAGIC HAPPENS WHERE WE PICK WHICH POWERUP TO MAKE THIS ***
// need to consider a few things like:
// 1. have we already used this powerup recently? for some powerups that matters a little
// 2. certain powerups should be more prevelant at higher difficulty levels
// 3. of course only pick from powerups that are unlocked/available
// 4. if we *just* unlocked a powerup, we should probably use that one at least once in the following game
// 5. blackopolypse requires a lot of black blocks in the glowboxset
// 6. flutterworks requires a lot of colored blocks in the glowboxset


Isn’t life itself just an infinite array of odds?

Now that’s an odd thought!

T-Minus

FLUTTER is launching this Thursday at 12:01am… which ostensibly means tomorrow night.

05

So what does a solo developer feel on the night before launch?

FEAR
EXCITEMENT
ANXIETY
NERVOUSNESS
IMPATIENCE
EXHAUSTION
HOPEFULNESS
DREAD
TERROR
LIKE I WANT TO HIDE
LIKE I WANT TO JOYFULLY SHOUT
PRIDE
CHAGRIN
ANTICIPATION

There’s a large moon rising out the window. Tomorrow night it will be full. A sign? Who knows. As always with these things it could be a huge embarrassing bellyflop. At the same time, I’m very proud of it. I think it’s a very good game. Maybe even a piece of art.

As a solo dev I don’t have the resources of a studio to, say, throw a fancy launch party or do extensive beta testing. I showed it to some friends and they liked it. I know some of you might say- ‘hey! actually even indie devs have the ability to a/b test and get surveys filled out and do pr and marketing…’

You’re right. I’m very aware of that. But I’m also very aware of the opportunity cost. I’m an indie dev. I am one solo dude. Every second I spend sending out some pr email is a second I COULD BE SPENDING DEVELOPING THE NEXT APP.

And that is what I’ve been doing instead.

I’m already working on the next one.

I have a lot more control over making a game as amazing as I possibly can than I could ever have trying to market to a global audience for zero dollars. And maybe it’s naive. But I pride myself on stubbornly clinging to the belief that great art– great product– great entertainment– is the absolute best marketing there is. Build a great app and they will come. Apple has made that at the very least feasible.

Thanks for reading! I hope very much that if you purchase Flutter you enjoy the experience and have way more than $1.99 worth of fun with it! I hope it makes you smile. And curse. :)

Whether the masses take a shining to it or not, I’ll be dusting off the keyboard and working furiously on the next one. Perhaps by the light of that full moon.

Sebastian

New App!

Wow– it has been a long time since I wrote! I have been extremely busy– and I’m proud to announce that a new app of mine is about to… take flight. :)

I spent the last two months in a very harrowing Snake Plissken like Escape From New York. Packed up all my belongings, said goodbye to all my friends, office coworkers, neighborhoods, coffeeshops, bars and jumped a plane for California. All in the midsts of the worst Winter I’ve ever experienced in the Big Apple (40 degrees in late April– WHAT??!) and sneaking in coding and design every chance I had.

I arrived in CA two days ago (finally on Apple time!), and uploaded my new app yesterday.

uploading

Somehow screengrabs of this beautiful moment in Xcode never get old. :)

The journey to the completion of this particular app was particularly harrowing because of all the above stated hurdles.

And after reaching the finish line, I indulged in a little nap at the parent’s house. My mom snapped a pic and added some embellishments in photoshop– a little hint at the new app along with a clue as to where I inherited my photoshop skills:

20140501SebastianButterfly_w

More details coming very soon! For now, I’m going to enjoy some well deserved sunshine.

It’s good to be home.

How Many Pages of Code in an Indie App?

I was curious! So I just finished my iphone/ipad app: Spider Prank. How much work had I actually done? I know I’d worked like a dog for almost a YEAR on nights and weekends. But how much code had I actually written?

Well, there was only one way to find out. I saved all my code as pdfs, then opened in photoshop and saved each page as a tif. Then using some neat Photoshop actions, I shrank the images down and tiled them. I basically made sprite sheets out of them.

The result?

424 PAGES of C# code that I had personally written.

A friend joked that I had written the Great American Spider Prank novel. She wasn’t far from the truth. When you’re deep in development it’s hard to tell how much work you’re actually doing. There’s no such thing as ‘page count’ in scripting. And all your work is broken up into different classes of differing lengths.

But that’s a lot of writing!

Now granted, every page isn’t totally filled in. And it’s at least double spaced I’d say. But as a former screenwriter, I can safely say that I wrote the equivalent of at least 3 movies.

A few other notes– this is all the code that I wrote personally. But there’s a TON of other code in the app in the form of plugins I bought, cool license-free snippets I found online, and of course the huge C# and Unity3d libraries I built the whole thing on. So my code that you see below is just the tip of the iceberg when it comes to the bits in the game (gfx & sound aside).

Also I thought it’d be neat to highlight portions of the code to get a sense of how much code it took to create a specific result. In my app, I have a semi-intelligent spider that crawls around and reacts to swipes, gravity, taps etc. So in the code below, I’ve highlighted in RED all the portions that control the spider alone. All the rest is UI, photo import, saving/loading, localization etc etc etc. But the spider is quite a large chunk. Almost feels like peeking at a decrypted genome.

If you ever wanted a look at how much code goes into a little app, check out the code below and make sure to keep scrolling! If you’re a developer, how much code did you write for your game? I bet it’s more than you think!

code01

code02

code03

code04

code05

code06

code07

code08

code09

Forever Alone

Zbrush is one of those software apps I absolutely love. I first encountered it wayyyy back in the early 2000’s or something at a WWDC SF. It was sorta new at the time but was doing crazy things with organic 3D sculpting no one had ever heard of. I was hooked.

It’s come a long way since then (although the interface is still as bizarre as ever). Over the years I’ve poked around in it and watched it develop. I don’t consider myself a master by any means, but as someone who loves design and 3D and now app development, it’s a tool that’s hard to ignore.

So recently I gave myself a learning challenge to dive in deeper. The challenge? Recreate the infamous rage comic “Forever Alone” as a 3D rendering.

Forever_Alone

His face is just perfect for modeling, wouldn’t you agree?

Here is the final result (click to enlarge). Stay tuned for a behind-the-scenes recap of how it was made!

Forever Alone

REJECTION – part 1

Okay– so what is every developer’s worst nightmare? Finishing a long, arduous development process only to get your app REJECTED by Apple! That’s exactly what happened to me.
rejection01
Owtch!

Hopefully Apple won’t mind if I share a few of the details just so others may learn to avoid my mistakes.

The whole point of my app was to allow users to prank their friends by putting a ‘real’ spider on their phone. To this end, I added a bunch of device screenshots to the app that simulated an ios desktop. Apparently this is a no-no.

rejection02

So according to bylaw 8.3 (which I had not read), it’s against Apple’s rules to ‘simulate an ios behavior’. Including still screenshots of ios backdrops qualified and my app was rejected.

Should I have seen this coming? I suppose so. I was caught with my pants down, that’s for sure. I thought I’d seen apps that had done this sort of thing before… ie simulated stuff that appeared to be on your actual device.

Like this one:
Volt

Or this one:
Shake Break Make

But after digging deeper I started to uncover some others who had run into the same roadblock. Specifically, I found this great post from all the way back in 2009. Some guy wanted to simulate an iphone screen like I did. And he paid the price.

I love the evolution of his app design which illustrates his harrowing rejection process (image from www.mani.de):

rejection and iteration

So how come apps like Watchdog and my app got rejected, and other apps like Volt and Shake Break Make made it past Apple’s watchful eye?

It’s well documented that sometimes Apple’s review process is a little random. Get a cranky reviewer on the wrong day and you’re just out of luck (although I can’t blame the overworked review team). But my hunch is that the real difference is that in the apps that made it through, desktop imagery did not ship with the app. Users were instructed to take a screenshot to add as a background… something that should, in theory, be entirely legal.

The problem for me, however, is that without a screenshot shipped with the app to greet the user right away, a lot of the punch of the main concept of having a spider on your phone is deflated.

As a developer, my first reaction was to drink a lot of whiskey. I’d just spent a solid six months working on a project that would never see the light of day. FAIL. It was a brutal disappointment.

BUT, after taking some time to wallow, I picked myself up, dusted myself off, and asked the question that developers MUST ask after app store rejection:

HOW DO I SAVE THIS?

After all, I appealed Apple’s decision and they wrote this:

rejection03

Granted, it seems like a boilerplate, form letter response, but it was still encouraging.

“We hope you will consider revising the app to address the issue…”

Apple WANTED my app– they just needed me to fix it. And all-in-all I think in retrospect it was a pretty fair process. Upon reflection I understood that it made little sense for them to allow apps in their store that made it seem like their devices were busted or inoperable.

So HOW DO I SAVE THIS?

Challenge accepted.

Stay tuned for part 2 where I’ll fill you in on the solution I came up with.

Dumb Coding Mistakes #632

Okay here’s a good one that had me stumped all afternoon.

I must say that as far as collections go, I’m used to using arrays. Arrays are great cuz they’re typed, they’re fast, and they’re relatively easy to set up and iterate through. The problem is they’re not dynamic. So it’s tough to quickly add and delete stuff from an array on the fly.

Enter the List. Lists are typed like arrays, but they are dynamic– meaning you can just add stuff to your List and the list grows. If you zap something from your list the list shrinks.

This is very useful for saving. In my app, users can add photos to use as backgrounds that they either take themselves or pick from their camera roll. Saving this data is great for a List. I don’t know how many different photos they will add over the course of the app’s life on their device and I don’t care. Save and delete your photos as you wish! They’ll all be stored in a List.

The dumb coding mistake is as follows.

In startup, I need to load these photos. So I iterate through the List. I also check to see if there are problems. If there is missing data or null data I simply throw up my hands and zap the thing from the List. Something went wrong, I’m destroying it. The user can import it again if need be. This isn’t like someone’s bank account.

So it goes something like this:

// ON LOAD

for (int i = 0; i < listOfBackgrounds.Count; i++) { if (listOfBackgrounds[i].IsScrewedUp()) { // list item is messed up or corrupted! // zap it! listOfBackgrounds.RemoveAt(i); } else { // everything is fine! load the background listOfBackgrounds[i].LoadBg(); } } Simple enough, right? We loop through all the items in the list. If we detect an error we zap the offending object and remove it from the list. If it's fine, we load it. ERROR! NULL REFERENCE EXCEPTION! Do you spot the mistake? It had my tearing my hair out for quite a while. Having been used to working with arrays instead of Lists, I overlooked an important quality of Lists. They are dynamic. Most of the time this is great. It allows you to add and drop stuff on the fly. But the problem with that, is the List is always CHANGING! Take the following array: myArray = new string[] {A, B, C, D}; It stores four strings. A is in index 0. B is in index 1. C is in index 2. D is in index 3. (both arrays and lists start counting their indexes at 0 -- itself the source of many dumb coding errors) If we DELETED the B at index 1, what would the value of index 3 be? Index 3 would still be D. Index 1 would have a null since we zapped the B. But I would still know what was in index 3 (and all the other indexes for that matter). A LIST on the other hand, continues to resort itself. So for a similar list with values of A,B,C,D in indexes 0,1,2,3... What would be the value at index 3 if we removed the value at index 1? It would be NULL! If we remove the value at index 1-- ie if we remove the B-- then the ENTIRE LIST changes to become: A,C,D in indexes of 0,1,2 Index 3 does not exist anymore! Everything shifts over. And thus my dumb coding mistake. I was iterating through a LIST while removing things from the list. So the list was CHANGING as I was trying to access it. The solution? Store the indexes I wanted to zap in a SEPARATE LIST which I then looped through AFTER the main for loop. After iterating through the main list and storing the numbers, only then was it safe to zap stuff from the original list and feel confident I knew what I was zapping. Even then, I had to loop through the separate list BACKWARDS. Removing index 5 wouldn't have any effect on indexes 0,1,2,3,4. So as long as I removed indexes from highest index to lowest index, even though the List was dynamically shifting, it wouldn't screw everything up. Another brainteaser for the books. I've learned that the only way through this stuff is banging your head against the keyboard until your stupidity gives up and leaves you alone.