Monday, November 14, 2011

Apple and non-public APIs

We recently got a rejection from Apple for using a non-public API. Google was not a big help on this one, so here's the story of how we tracked it down.

We found that your app uses one or more non-public APIs, which is not in compliance with the App Store Review Guidelines. The use of non-public APIs is not permissible because it can lead to a poor user experience should these APIs change.

We found the following non-public API/s in your app:

Step 1: Find in files

There's a dropdown when typing into the search bar in XCode that lets you search in frameworks. Unfortunately we got no hits with this search, so that tells us the private calls are not in our code.

Step 2: Command line tools
From the rejection mail:

Additionally, one or more of the above-mentioned APIs may reside in a static library included with your application. If you do not have access to the library's source, you may be able to search the compiled binary using "strings" or "otool" command line tools. The "strings" tool can output a list of the methods that the library calls and "otool -ov" will output the Objective-C class structures and their defined methods. These techniques can help you narrow down where the problematic code resides.

otool and strings are tools that seem to be on the global path, so you can type them into the command line from any directory. The trick is you have to figure out what to run them on. XCode 4 tends to put things in strange directories, so here's a shortcut to finding the actual file you want.

Find your app under "Products" in XCode and right click on it to select "Show in Finder". This will open up a finder window where your .app file lives. If you run otool or strings on this file it will not work. Right click on your .app file and select "Show Package Contents". Then find your executable file and copy it to somewhere accessible.

Once in Terminal and in the right directory, the two commands to use are:
otool -ov ScribbleWormHD
strings ScribbleWormHD
These will output a ton of stuff. You likely won't be able to navigate it without using command-F to search for the strings that Apple complained about. In our case otool did not give us anything useful. It would have been easy to track down the problem if it had, because otool will tell you what called the offending function. Strings just outputs a list of every string used in your project. We managed to get a hit with that, so at least we had a way to test if any changes we made would fix the problem.

* NOTE: strings did not work for us at all in Snow Leopard. It only worked in Lion.

Step 3: Head Scratching

So the calls to setAppName were not in our code, and we had no tool telling us directly where the calls were. Sometimes debugging degenerates into informed trial and error. We only have two middleware libraries in Scribble Worm: Flurry and Admob. We started with Flurry on a hunch and removed it from our project as a test before running strings again. This time we were clean.

So we went to the Flurry site and found that they are on version 3.0 while we shipped with 2.8. One upgrade later and another run of strings and we were ready to submit.

Saturday, November 5, 2011

Design Patterns in GHEngine, Part 1

One of the major design goals in our engine is to have as small as a codebase as possible. To do this, we want to re-use as much code as possible. A Golden Hammer in programming is a tool that gets overused and applied to many problems even when it is not a good fit. We have a small set of design tools that are so generic we can use them in all sorts of places. It's a good model if you can have a unified design: avoid duplication by extracting the shared work and making it available to all users. The danger of course is we can end up with the bad definition of golden hammer if we're not careful.

The Controller

class Controller {

virtual update(void);

virtual onActivate(void);

virtual onDeactivate(void);


A Controller is something that updates. Our renderer, physics, and input handling are controllers. We can store these controllers in a sorted list for updating, and we can dynamically add or remove controllers on the fly. Instead of having a big update function where we say "do this, then do this, then….", we have a single function that looks like this:

void runFrame() {

for each Controller, call update();


Note that Controller does not take any arguments at all. Once you start adding arguments, you start making assumptions about all possible Controller subclasses, and that list can grow to the point where you are passing a lot of stuff that most controllers don't care about. If a Controller needs to access something like the current time, we pass in a time value reference in the constructor.

By having this dynamic list we can avoid iterating over objects that don't need to do anything. If an entity like a player needs an update it can add a Controller to the list. If an entity like a tree does not need to do any work, it can avoid the list. Just touching the memory of each entity in a large world can become a serious performance issue even if no work is being done.

State Machine

class StateMachine {

addTransition(trans, state);

removeTransition(trans, state);



class Transition {

virtual activate(void);

virtual deactivate(void);


A StateMachine is used to change behavior based on whatever influences we want. Instead of defining each state as a class, we define a state as a set of Transitions into and out of that state. The most common Transition used is a ControllerTransition, which is used to add Controllers to the update list. An example Transition is a MusicTransition, which plays a song while it is active. We can create one of these and add it to the main menu state, then whenever the main menu is shown music plays.

class MusicTransition : public Transition {

activate() { start playing music }

deactivate() { stop playing music }


Another use for StateMachine is players. We can use a ControllerTransition to have an input handler active while the player is in the alive state. Then when the player dies we shift him to the dead state, and the ControllerTransition removes the input handler from the update list.


class Message {

identifier messageType

payload messageArguments


class MessageListener {

virtual void handleMessage(Message);


class EventManager {

addListener(MessageListener, message identifier);

removeListener(MessageListener, message identifier);



Events are something that happened, that something else cares about. They are an alternative to having a bunch of different managers that know about the inner workings of some set of objects. We also use them for communicating between threads and for sending information over a network, as they can be stored up and sent later. The real flexibility comes into play when we start data driving message loading, adding listeners that change state to state machines, and allowing out GUI to send loaded messages.

Friday, October 28, 2011

Android NDK Crash Logs

So there you are working happily with the Android NDK and get a crash. Instead of a handy breakpoint where you can see the state of all the variables, you get something that looks like this:

10-28 15:31:49.333: I/DEBUG(1010): #00 pc 00557718 [heap]

10-28 15:31:49.333: I/DEBUG(1010): #01 pc 000903e6 /data/data/goldenhammer.scribbleworm/lib/

10-28 15:31:49.333: I/DEBUG(1010): #02 pc 00072a1a /data/data/goldenhammer.scribbleworm/lib/

10-28 15:31:49.333: I/DEBUG(1010): #03 pc 00084222 /data/data/goldenhammer.scribbleworm/lib/

10-28 15:31:49.341: I/DEBUG(1010): #04 pc 00096dfa /data/data/goldenhammer.scribbleworm/lib/

10-28 15:31:49.341: I/DEBUG(1010): #05 pc 0006d578 /data/data/goldenhammer.scribbleworm/lib/

Great! How do I figure out how to turn that into something useful?
~/android-ndk-r5b/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-addr2line -C -f -e
~/src/sb/src/AndroidProjects/ScribbleWormLib/jni/libs/armeabi/ 000903e6
This will spit out something like:
It may be pathetic compared to C++ development on any other platform, but at least that's a starting point to look for problems.

Thursday, August 25, 2011

How to detect a tablet screen in Android

I went to the Android Developer Labs in NYC yesterday. Google talks always kick ass. One of the tips I picked up was how to detect that you are running on a tablet.

We were checking to see if the API level was Honeycomb or newer. This was going to backfire once Ice Cream Sandwich gets released and phones start using newer API levels. It also leaves out the pre-Honeycomb tablets like the popular 7" Galaxy Tab. I'm going to try to push out an update to fix this soon.

The alternative route is a little roundabout but doesn't have either of those problems. You use an id tag in a layout file and only put that tag in layout-large.


xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=""






xml version="1.0" encoding="utf-8"?>





<FrameLayout android:id="@+id/large_screen_flag"

android:orientation="horizontal" android:layout_weight="2"

android:layout_width="match_parent" android:layout_height="0dp" />


Then in your Activity onCreate method:


boolean isTablet = (null != findViewById(;

Monday, August 15, 2011

How to succeed as an independent developer without making any hits

Golden Hammer Software just celebrated our second indieversary! That means we've been happily making games on our own for two years. Not only that, but we've managed to become self-sustaining at least for now. How did we do it and how do we plan on keeping doing it? Find out here!

Defining Success

According to the 2011 game developer survey ( I should be making 100k+/year before benefits by working for someone else. If I were defining success as how much money I could be making in life, we're not a success yet. I'm not sure we ever will be. While money is possible for making independent games there are much easier and safer ways to go about it.

What I don't have and am successfully avoiding is the need to get a job for someone else. I define my own work hours, decide what I'm working on, solve the interesting and boring problems, and make the bad decisions that affect my life. If I'm crunching it's because I want to and feel like it's the right thing to do to move forward. Should we make something super-awesome I'll benefit directly from it.

I don't currently need or want another job. I will turn down any full time job offers. I'd consider the right short-term contract or part time gig if the work is interesting enough and I can still work on Golden Hammer games. For a small company that's a pretty awesome position to be in.

Keep your day job

If you want to make games nothing is stopping you from doing this on the side short of a no-compete, and no-compete contracts are negotiable. Some people seem to have the mentality that the only way to go about it is full time. They are just wrong. I made Bid for Power while working full time jobs, and I made the engine that's the foundation of our games while working full time. I will even go as far as to say if you can't work on a game on the side, don't bother going full time because you probably don't have enough dedication to finish.

I don't mean to say that it's easy. Matter of fact it sucks, especially if your day job is programming games. You get up early and go program games for somebody else, then you go home and program more games for yourself. There's not much time for anything else. However if you have any job at all on the side, congrats your business is now making more than most independent developers.

Scott Macmillan likes to preach that when it comes to starting a business time is money, and money is time. He's absolutely correct, but I will twist that to mean something I don't think he intended. If you have another job on the side that basically gives you infinite time to get something going. Once you find something that works then maybe you can go full time.


Contract work is not something we've done yet, but we are definitely looking into it. The trap people fall into is they end up bouncing from contract to contract and never actually making any games. It is guaranteed money that can help fund the rest of your projects if you can get it and then get back to your original goals. I would love to find a contract that is 3 days a week for 6 months, is an interesting project, and has good people on it.

Do something that other people aren't doing

If everyone is making match3 games for iOS, don't do that! Nobody will care and your time will be wasted. The only exception here is if you just want to polish up your skills and don't care about making something that nobody cares about. Paul Graham said something like 90% of startups fail, so if you want to succeed don't do what everyone else is doing.

If you are a small company of 2-3 people this is even more true. You can't compete directly with World of Warcraft. Don't even try. Find a niche where you don't have to compete with companies spending 20-100 million dollars per project.

This may sound odd coming from a company whose biggest success is a snowboarding game. When we started out there were zero snowboarding games on iPhone. That was a great idea at the time, too bad 15 other companies all had the same idea and beat us to market. Even then, most of the competition is imitating SSX. We went the more realistic route. If we do a Big Mountain Snowboarding 2, we'll go even further towards the sim route in order to differentiate.

This applies to platforms also. If everyone is making iOS games, maybe you shouldn't be putting all your eggs in that one basket. iOS is currently about 20% of our revenue, but that changes on a daily basis and it's a little skewed because we just released on Nook Color and are riding the new release wave. We are succeeding largely because we are getting on to as many platforms as we can. The way I look at it is every new platform we add is a multiplier on the sales of every new game we make. More games + more platforms = more money.

As a side note, I do not consider different Android stores to be new platforms. If a device has the Android Market on it, you are already targeting those users, and being on another store is just additional overhead. For things like the Nook Color which runs Android but has no market support, that counts.

Keep costs low

If you spend $300k while making a game, and make $100k off it, you failed horribly. If you spend $10k and make $100k that's a great success! Maybe you don't need that office. Maybe spending $3k per month on rent isn't the best idea. Maybe hiring a dozen people is not the smartest thing you can do. If you want to do these things, at least do them on someone else's dime by courting publishers or keeping a day job.

Don't be a one man team

Completely the opposite of keeping costs low, don't go it completely alone. Even if the only reason is that you can't slack because your partner is counting on you. There's also a huge motivating factor of always having someone else that can be excited about your latest victory. If you are married, chances are your wife/husband does not care that you just figured out how to get 10 more polygons into the scene. Also, not being a one man team makes the following point easier to deal with.

You will need to do everything, even things you didn't know existed

At a big company you can become the world's foremost expert on rendering nose hair. That's a very zen, comforting luxury that you don't have as an indie. I have so many hats my neck has doubled in size. Programming, design, marketing, art, music, sound effects, production, PR, networking, futurist, UI, tech support, web designer, IT. No one can do everything well, which goes back to don't be a one man team.

However just because you don't do it well doesn't mean you can just not do it. Everyone on the team needs to be prepared to help with everything that could possibly come up. If you really can't do an aspect you need to find someone who can, but then what happens if he loses interest? That's now your job until you can find someone else.

Networking, Networking, Networking

Get out and meet people! Find successful people and learn from them. Find unsuccessful people and learn from them too! Put a face behind your name and surprising things can happen. Just don't be that guy who is only talking to me because you want something from me. Nobody wants to talk to that guy. I am incredibly introverted and still doing this, so you have no excuse.

Find a local group of like minded people. In Boston we have Boston Indies ( and Boston Post Mortem ( If there's no group like this in your area, maybe you should start one. If there's not one for games, then maybe there's one for startups. Go to conferences and find the meet ups.

It seems like the most successful people at Boston Indies are also among the nicest and most outgoing. I don't think this is coincidence.

Don't just network, make something!

You can talk about making something. I encourage you to do this! It does not actually mean you are making something. Without getting products on the shelves, or in the modern world app stores, you have no chance of success. Part of this is picking a project you can actually make, and part of it is following through. The last 10% takes 900% of the time.

If $10/day is repeatable it can become $100/day or $1000/day

There seems to be a myth that games are either huge successes or complete failures with no middle ground. The long tail on app stores does exist and is a totally livable place to be if you can figure out how to keep finding new users. Maybe you show up in common search results. Maybe your games feed players to your other games like Zygna. Maybe you find a way for your users become your evangelists to sell the game to other people. You should try for the huge hit of course, but if you just abandon the project when it doesn't hit #1 you are leaving money on the table.

We have a game that seems to sell mediocre amounts on every platform it arrives on. Porting is very cheap compared to making a game. This gives us the luxury of porting to smaller markets like webOS and have it make sense. Small improvements to income that don't take away from other sources all add up. The same goes for ads. Maybe you have to be chess with friends to get rich off serving ads, but you don't have to be in order to get an extra $10-$20/day out of releasing an ad-supported version as long as it doesn't take away from your sales.

Monday, May 2, 2011

Scribble Worm iPad Post-Mortem

Scribble Worm is our new puzzle game for iPad hitting stores any minute now. It's also our second game after making Big Mountain Snowboarding for iPhone and porting it to Android, iPad, and Mac. It started as an experiment to try to make a small game and get it out quickly, but even small games seem to be much bigger than first expected. It ended up taking us a little over 5 months, and we still have to do a small screen version for iPhone and Android, and a version for Mac.

The Game:

You draw a worm with your finger and it follows your pattern to try to reach the apple. We throw various obstacles in the way such as a wall that worms bounce off of and a wall that kills the worm when touched. We then animate the walls around the screen for an extra challenge.

I've never seen a game like this before, so it's definitely not a "yet another" game. It's not a jumper, an angry animals, a flight control, or a match 3. If we can get people to try it out I think a lot of people are going to like it.

Art Style:

The art is a combination of procedural effects and hand drawn "scribble" images done by myself inside ArtStudio for iPad. It looks a lot like a doodle game, but there's actually a lot of stuff going on behind the scenes to get the crayon and paper look. Neither of us is particularly good at making 3D models without outsourcing, so it seemed like a good approach that we could pull off well.

I'm pretty happy with the end result, but it's going to be terribly hard to stand out among the millions of doodle games out there. I think it's several steps above Doodle Jump when in motion, but it's hard to sell the differences in screenshots. Our next title might have to be more visually unique in order to stand out.

Music and Sound Effects:

All of the sound in this game is created on the iPad. I wrote two songs in Garage Band for the main menu and in-game music. Actually I wrote about a dozen songs while trying to make some cutesy music, but everything kept turning out as inappropriate death metal. The sound effects are also recorded in Garage Band using the sampler feature. The eat apple sound is actually me chomping on a carrot with an iPhone microphone next to my mouth.

Puzzle Design:

Making the actual puzzles turned out to be the single biggest chunk of work in the game. It seems obvious now that making puzzles is going to be a huge part of making a puzzle game, but I underestimated it by several orders of magnitude. Fortunately Katie picked up this ball and ran with it.

We have an in-game editor that lets you drag and drop walls, and then try it out in real time and make adjustments. This WYSIWYG interface was infinitely better than trying to edit the XML files and reload.

Play Testing:

The first line of defense in play testing is yourself and then your friends, but your friends aren't going to be likely to tell you that something sucks. We're fortunate to have the Boston Indies group that meets up nearby to try out each others games. We actually went through at least 3 revisions of show it to lots of people, then tune, then show it again. It really helped us out to both reinforce that we have something cool, and to see where people struggle or do things we don't like. Always try to find some people who don't like you to try out your game before releasing.

Our first version of the game was entirely black and white, trying to look like pencil on paper. One of the big things to come out of play testing was we had to add more color to the game. People were identifying the worms as various bad things. The crayon scribble shader was born and I think the game looks much more appealing now.

Another thing to come out of play testing was we had to fix worm spamming. After a few levels people would stop trying to solve the puzzles and instead just try to make as many worms as possible until one randomly reached the apple. While this may be entertaining for a short period there's not as much gratification as actually figuring out how to solve the puzzles. Our first attempt to fix this had the number of worms limited. If there were already several worms in the world you couldn't spawn a new one. This could get frustrating if worms got stuck anywhere, so we changed it to spawning a new worm removes the oldest worm from the game.


It feels like whispering into a hurricane sometimes to try to get a game noticed. The most effective ways of marketing an iOS game are picking a good name, having a good logo, and having good screenshots. All of these are free. You then hope and pray and try to find ways to stack the odds of making it into the top charts or getting featured, and even then your game could disappear quickly. Ads on big sites run at around $600/month with a waiting list, and seem to have greatly limited effectiveness.

We did make a video as you can see in the section about the game itself. Some of the art and UI is slightly outdated now, but overall I'm pretty happy with it. However, at the time of this writing we only have 28 views of the video! Some of this might be due to embedded views, but youtube by itself is not a great marketing tool. I do plan on linking to this video or a newer one from the app description though.

Twitter is something new that I've been trying out (@DJWGoldenHammer). It's fun, but so far has not been very useful. I have 134 followers, but I think a lot of them are just following me so that I'll follow them, and don't actually care about anything I'm tweeting. It hasn't been a great place for marketing, but it has turned into a really good way for me to find other dev blogs to read.

We have a press release ready to go on Hopefully that will help some, but it's a new thing that we have not tried before. I must admit that getting on any of the big sites is a mystery to me. Even after close to a million copies and steady sales for two years Big Mountain Snowboarding has just been a blip in the blogosphere.

Our ace in the hole is the free version of Big Mountain Snowboarding, which gets 1000-2000 iOS downloads per day. We can use this as an advertising platform for Scribble Worm. The problem right now though is adMob does not support house ads for iPad and iAds does not support house ads at all. We'll run house ads through adMob, but we might need to make a new version of BMS to really push the Scribble Worm ads to the right people. The danger is that BMS Lite currently has a really solid 3.5 star average with over 200 ratings for the current version that I'm a little afraid of jeopardizing with a new version. If all else fails we can put some ads in BMS full and do a free for a day promotion.

For the screenshots, we're trying out the Chillingo approach of having images with extra taglines on them to try to sell it better.

Why just iPad?

I love to talk about how we have a cross platform engine and want to be on every device in the universe, and yet the first release of Scribble Worm is only on iPad. This was mainly in order to limit the amount of work so we can have a high quality focused version. The iPad is a dream to develop for. It has exactly one screen resolution and aspect ratio, all of the hardware supports shaders, and the dev tools are pretty good. To be on iPhone we need to make new versions of most of our UIs for the different aspect ratio, and make a fallback version of the graphics for older devices. The Android port is even more work on top of that. We're planning for OSX as our second release because we don't have to redo most of the UI.

A slightly sneakier reason is that the iPad market is much smaller than iPhone. There are about a dozen new iPad releases per day, compared with more than a hundred on iPhone. If we can manage to get any publicity off the iPad or Mac versions, then maybe it will make the iPhone release a little easier. We're planning on converting the iPad version to universal once we make the iPhone version.

What went right:

It's not a proper post-mortem without a what went right and what went wrong section!

  1. The initial idea was a solid one. I'm very happy with the end result in terms of gameplay.
  2. We made good use of our existing tech. Every project has us expanding the engine, but much of what we developed for Big Mountain Snowboarding and OverPowered applied to this game as well!
  3. Boston Indies was great for play testing, and really helped us refine the game and the look.
  4. Being on iPad exclusively really let us work faster by only having to worry about one set of variables.
  5. Between ArtStudio, Garage Band, Pixelmator, and XCode all of our tools were cheap and awesome.
  6. Somehow we managed to nail the cute factor of the worms. Adding bright colors to the worms and the obstacles seems to have helped a lot.
  7. Having a level editor was essential for making this game.

What went wrong:

  1. Underestimating the size of the game. I've had to revise my definition of a "small game" to not include anything that has proper level design.
  2. Marketing black hole. You probably have not heard of this game unless you know one of us.
  3. Dropping a video on youtube does not seem like a good way to get people to actually watch it!
  4. While the art style may look good and even better in motion, it may end up making it harder for us to get noticed than something more unique.

What we still don't know:

  1. Are our name, screenshots, and icon good enough?
  2. Will linking to a video in the app description help at all?
  3. Is our staggered release plan actually a good one?
  4. Can we get Apple to notice us and show us some love?
  5. What effect will a press release have?

Tuesday, April 5, 2011

Sales per platform - Big Mountain Snowboarding

Big Mountain Snowboarding has been out for a while now on iPhone, iPad, Android, and OSX. I thought it might be interesting to see a breakdown of where the sales are coming from, so without further ado:

I wish I had numbers for iPad vs iPhone, but that's one of the many downsides of releasing a universal binary. We're looking at adding Flurry to future releases to get that kind of info. If you look at our free version, it looks like about 40% of our users are on iPads.

The big surprise to me is iAds. We first ask for an iAd, then if none are available we go to Admob. As you can see, it fails to get an iAd fairly often, and the income wasn't even worth paying attention to. Sometime recently that changed and iAds picked up a huge amount of steam. Here's a picture of the iAds trend.

Additional Platforms:
  • Windows Phone 7 - No C++, so we decided to pass. Reading this link makes me not regret this decision.
  • WebOS - We'll probably eventually port to here.
  • Blackberry - Still waiting to hear details on the NDK and how they support Android apps.
  • Amazon Market - This is looking like it has potential. Once we finish up our current project we'll make the adjustments to get on it.

Tuesday, January 11, 2011

Getting on the Mac App Store

Big Mountain Snowboarding was just released on the Mac App Store, 1 week late for the grand opening. We started on the port as soon as the "within 90 days" announcement was made.

Technical Difficulties

I talked about a lot of the details of the port in a previous blog post.

Playtesting and Revision

Big Mountain Snowboarding was created as a handheld tilt game. Obviously that's not the ideal control scheme for someone on a 27" iMac. I wanted to do something cool with the touchpad so we turned it into a joystick, and made a couple fallback controls for people who don't have a touchpad. We had some back and forth and some revision on some pretty bad early controls.

We then took a macbook over to the bostonindies demo night and got some people we don't know to play it. The people struggled with it. The controls were not good enough to release at that point, so we spent another couple days trying to improve it. They are much improved, but I'm not convinced they are awesome. We'll probably have to make a couple patches before we really get there.

Apple Approval

Our first attempt at submission happened on 11/19/2010. We never left the waiting for approval stage. I had made several improvements and decided to pull the app to upload another attempt on 12/1/2010. After a couple weeks of waiting we got a rejection because the .app name was not the same as the application name, "Big Mountain Snowboarding OSX". I fixed this and resubmitted. About another week later we were rejected for having "OSX" in the name. I think whoever said the names didn't match up could have also mentioned that the name was unacceptable, but ok.

On 12/30/10 we were approved and all set to be a launch title. Then a few days later I noticed a game-breaking bug that slipped in to the game when making the build to remove "OSX" from the name. We share our engine between all of the games we make and we don't branch, so development of one game can cause us some bugs in other games.

I submitted another build at about 3 in the morning of 1/4/2011, with the app store set to launch sometime on 1/6/11.

Actual Launch

We had to make the decision between missing the app store launch or shipping a broken build. We were worried about getting nothing but 1 star reviews early on killing any chance of future sales, so we removed the app from sale before launch. We watched 1 million downloads happen on the store the first day while not being a part of it. It was a tough call, and I'm still not sure which was right. I woke up early on Tuesday to pull the app and we had already sold 4 copies at $4.99 each.

I was getting a little anxious earlier today about whether or not being "developer removed from sale" was preventing our approval so I sent Apple a mail asking about it. I guess someone from Apple liked the game because we were approved shortly after and placed in the "Staff Favorites" section of all games. I also dropped the price to $0.99 for the launch to try to get us some initial chart placement.

I'm hopeful. BMS isn't the game I'd make from scratch for the Mac platform, but it wasn't a viable market back when we started. The more platforms with an audience available for the little guy the better.