Learn to communicate
Sometimes I wonder how I remain friends with Matt and others when I am so bad at communicating. I mean seriously. I think poor Matt went through 8 game board designs because I wasn’t being clear enough about what I was looking for. He even managed to do it in about 7 hours time (between two evenings).
Truth be told, the game board we ended up with is much better than it would have been originally – and that isn’t a slam on his original design. We both threw out ideas that he mocked up. And we both threw those ideas back into the dumpster. Some of them stuck and made the final cut, many didn’t. In the end we had something that looked pretty darn good and actually gave us more empty real-estate on the 4s than we thought we would have.
I know, I’m the programmer so why am I talking about communication? It makes sense, trust me. Matt mentioned last week the communication tool, Slack, that we have been using. This has been an exceptionally useful tool for me personally as a programmer. Because we are doing this on the side I can’t just walk over to Matt’s office and talk through some issues with the design. E-mail is no good because it is too bulky for quick back and forth chats and text messages get lost too quickly. Slack has met that in-between for us quite nicely. We can stay up to date on different topics as time allows without, in Matt’s case, taking time away from family.
Why that is helpful to me is that I can post a question about UI and pause my UI work while I wait for an answer. In the mean time I can work on the AI, Game Center, inter-app communication, etc.. Then when the response comes in we can chat briefly about the solution and then I can move on to implement it. Here is where things get really nice. Our back and forth about the game board layout happened during a two-day-7-hour period of time. There were numerous screen shots posted. Days later I am still referencing those conversations while I implement all those UI changes.
So one of the things we need to figure out is storage. We don’t need lots of space, but we do have lots of little things to keep track of. Achievement progress, high scores, in-game currency, etc.. Well, this isn’t really stuff we can store on the local device. If I store on the local device then the player cannot go between his iPhone and iPad seamlessly. We need a way to keep things centralized for all users across all devices. And that means – sticky notes!
Okay, actually it means a database. Here is the problem. Our budget for this kind of stuff is next to zero. Seriously, it’s right next to zero. It’s that little minus sign on your keyboard. One way to solve the storage problem is to host a server with a database on it, but that costs money. Money we don’t have, and don’t want to commit to if this game flops and doesn’t go anyway. Neither of us wants to commit to paying for a server to run for the next 4 or 5 years if we don’t make any money to offset the costs. We also decided that we don’t really want to just pull the plug on the server if things don’t go well, since that would mean anybody who has the game couldn’t player anymore.
Well, the search for DBaaS begins – DataBase as a Service. Basically that means somebody else hosts the database for us. The good news is that usually these are free to start out with and you only have to pay if you generate over a certain amount of traffic. So we can launch for free and if the game gets popular enough that we have to pay, we probably have some money coming in to cover it too. My initial search led me to three possible providers.
Apple’s Cloud Kit
It’s completely free, always a big bonus. There are two major downsides to Cloud Kit.
The first is that it requires iOS 8 or later, which means we wouldn’t be able to support iOS 7 devices. While that isn’t a deal breaker, I am a big fan of supporting one version back. Heck, today I setup mail settings for our staff and did about 10 iOS devices. I think 4 of them were still on iOS 7. Thats a pretty big percentage. I would really hate to lose 40% of our potential players just because they haven’t gotten around to updating their phone yet. By the time we actually launch this may not be as big of an issue, but it’s still something we have to consider.
The second downfall to Cloud Kit is that Apple is being extremely tight lipped about the specific limits. One of the big questions around seems to be what happens when you go over the limit. Do you get charged? Do you get errors and nobody can play for the rest of the day? How is the traffic quota calculated, is it based on data stored or data (including overhead) transferred? These are all huge issues to consider, and Apple ain’t talking. I e-mailed their support asking for clarification, specifically stating that I had already read the docs at various URLs. I got a response saying I could “find out more info at the URLs below”, which happened to be the same URLs I sent them originally.
I replied and told them as much and said that I needed more clarification than what is in the docs because the documentation is not answering those basic questions. After a few days they finally replied and told me I would have to escelate my question to Apple Developer Technical Support, which requires the purchase of a support incident. Really guys? So helpful.
The second possibility we found was App42. Their solution is based upon the number of API calls per month. The free tier (for indie developers) provides 1 million API hits per month. If averaged out assuming 4 API calls per game (one for each of 4 players), that means roughly 8,333 games per day. That doesn’t seem like a lot, but if we assume each player only plays 20 games per day (that is probably a lot), then we can handle 416 players playing very heavily each and every day of the month.
The next tier up from free is $50/mo and takes the number of API calls up to 6 million. That means we only need one out of every 16 players to make a $2 in-app-purchase to cover the costs. And those same costs would scale all the way up to 2,500 players.
Realistically, I don’t expect most people to play that many games a day. And in truth we can probably find a way to reduce the number of API calls. I could probably devise a way to only update the server every n number of games or something like that and cache the information locally for a bit.
Downsides? Well, the biggest downsides I have seen so far are slow development of new features / bug fixes and a dashboard interface that looks like it was designed in the early 1990’s. The dashboard design just looks, old. Period. My reference to slow development time is because of one glaringly large oops on their part. They also have a low burst limit of 40 API calls per second.
Okay, so as a new developer here are the steps I take with a new product like that: First I create my app so I can look around the dashboard. The next thing I do is create a test database for data so I can again look around, run some tests, see how it feels. Boom, problem. Each app can only have one database – ever. You cannot delete a database, nor can you rename a database. So guess what? My “Mealtime Sabotage” app on App42 is forevermore locked to a database called “test”. Back in October of 2014 there was a thread discussing this, with a few people having the same issue, and App42 stated they would be working on fixing this and it should be done in the “next few weeks.” It’s now March of 2015 and still no update on this issue.
The third option I found was GameSparks. I haven’t done much research on them yet, in terms of how their dashboard looks or their API or anything, but they have an interesting (though somewhat confusing) pricing structure. Frankly I can’t figure out how much we would have to pay. They list everything in Daily Active Users and Monthly Active Users, but numbers don’t really match up. They say on the left you pay $0.02 per user, but then when you set their slider to 200,000 users it says you will be charged $200/mo… umm. that just doesn’t add up at all.
Okay so I was about ready to wrap up this section an hour ago and then I stumbled across this thread on the unity forums which kind of blew up all my thinking on 3rd party solutions. I’m currently still leaning towards Cloud Kit, but the 5KB/user/day limit has me concerned for the reasons stated above. If I am storing 5 bytes of data per “api call”, does that mean I can make 1,000 API calls per day per user, or is there a bunch of overhead calculated into that bandwidth and I’m down to 10-20 API calls per day, or worse. This will be an ongoing research topic I think.
Xcode / API Oddities
So lastly, because I want to go to bed and it’s past midnight already, I ran into a few oddities this week. The first is with color calibration. I’m a simple guy. When I want red I put in [255, 0, 0] for the RGB values. So I did that in code then ran the program… Wait a second, that’s not the same red as I’m looking at in Photoshop. Yea, so… it seems on iOS you have to deal with color calibration profiles.
They have about 15 to choose from in Xcode, for each color you enter. This would truly explain why things haven’t exactly looked right, but I hadn’t paid it any mind until this week. At some point Matt and I will need to wort through all our images and pick a single color profile so I can use that in code as well to match colors. We have some things that are partially drawn with images and partially drawn in code. This is how I noticed the color mismatch, my gray was not matching what the image had, even though they had the same RGB values.
Secondly, for our turn based game I need to track the players and their specific order. Well I initially did this as a strong reference to the GKTurnBasedParticipant objects. Never had a problem until I tried to “end” my first Game Center game. To end the game you need to set the outcome (won, lost, first, last, etc.) for each participant. No problem. Access my saved participant variables and set the outcome, which did not work at all. Apparently at some point, or various points, in the GKTurnBasedMatch’s lifecycle, the participant objects are re-created. So even though all the data in my participant objects was valid, the objects themselves were not valid.
I will have to rework some internal code and instead of storing references to each player’s object statically, I will instead need to store an index number (thankfully the order doesn’t change) and access all the data dynamically. It’s a bit of a pain because I can no longer have a self contained “player” object. My “player” object will now need to reference the “game” object to obtain all the information about the players.