I'm becoming more and more of a coffee enthusiast in my old age. Probably because, unlike other hobbies that require a lot of time, enjoying coffee can be done every day in just a few minutes. The caffeine boost is also a big plus, especially when dealing with a daughter who likes to wake up screaming multiple times during the night.
I've gone through phases in my modes of coffee preparation. Of course, my first experience was simply making drip coffee with a traditional coffee maker. My first upgrade was using a French press. After that I started buying whole beans and grinding them myself with a blade grinder. Using a French press and grinding your own beans are regarded as the most important first steps you can take to make your coffee taste better: using a French press means you have to heat the water yourself, and can get it closer to the optimal 200 degrees Fahrenheit, while grinding at home means less time for coffee beans to go stale.
The next coffee upgrade I wanted to make was to switch from a blade mill to a burr mill. The difference is that a blade mill cuts your coffee, while a burr mill crushes it. In addition, blade mills have a hard time grinding coffee beans evenly — you have to grind your beans down to a fine powder before you'll get a consistent particle size. Blade mills can also make the ground coffee slightly more bitter, due to heat from the friction of the blades.
Unfortunately, blade mills are also way cheaper than burr mills. An electric blade mill might set you back $50, while the burr equivalent might be more in the $200 range. I wasn't sure I wanted to pay that much for an electric burr mill, so I set my sights on a hand-operated (!) mill from a company named Hario, the "Skerton." It was priced at a much more reasonable $40. Luckily for me, I got one for my birthday last month, so thought I'd share my experience of using a hand-operated coffee mill for the past two months.
It's not as annoying as you might think to have to grind coffee by hand. I kind of enjoy using the mill while waiting for my kettle to boil... it adds to the preparation ritual. That being said, I only have to grind enough coffee for a two-cup French press. If I needed to brew a pot of drip coffee, I would definitely be using the electric mill.
The Skerton produces a pretty even grind... basically it'll look like what you get buying pre-ground coffee. You can adjust the coarseness of the end result, but the mill doesn't handle very coarse grinds very well; you'll get some large chunks of coffee bean here and there.
The construction of the device is pretty good. The top of the mill consists of a plastic hopper with a metal crank and ceramic burr. You can adjust the coarseness of the grind by unscrewing the crank and adjusting a metal washer that controls the height of the burr. The top screws into a heavy glass container, used for catching the ground coffee. As a nice touch, Hario includes a rubber bottom for the glass jar, which makes it easier to use the mill: it sticks to flat surfaces, making it less likely to slide around.
All told, I'm happy with the Skerton so far. My electric mill has been put out of sight, and I've even gotten the wife to use the Skerton a few times. It's helped me elevate my coffee snobbery to the next level.
One thing that’s been on my mind recently is the cost of gaming; specifically the
pricing of digitally-distributed games. The reason I’ve been thinking about it is
because one of my favorite PlayStation games, Final Fantasy Tactics, was just
re-released for iPhone. I was excited about this remake, simply because I always
have my iPhone on me, so any iOS game is much more accessible. It’s much easier to
play a quick game before bed when the phone is sitting on the nightstand right beside
me. However, when the game was finally released yesterday, I was a bit disappointed
to see the initial price set at $16.
Now, don’t get me wrong, $16 is not too much to pay for a quality game. However,
I decided not to buy the FFT remake for a number of reasons.
$16 is too much for an impulse purchase, which is what most iOS apps target.
Final Fantasy Tactics is a 15 year old game. I would say that the majority of
customers those who have already played it on the PS/PSP (and they probably own
it for one of those platforms as well). It rankles to pay what is viewed as a
“premium” price for something you already own in a different format.
Like it or not, game prices are trending downwards. Look at the average buying
price for the Humble Indie Bundle to see what
many people will pay for games given the ability to set their own price. In
some cases this downward trend is mitigated by increased distribution scope,
but not always. I appreciate the effort to show that some games have more content,
and therefore can command a higher price. However, riding the nostalgia wave
off the backs of loyal players probably isn’t the best way to go about it.
I feel like I can pay more when I get some sort of physical artifact to add to
my game collection. For instance, $16 for a Nintendo DS version of Final Fantasy
IV? I can do that. Digital distribution still feels too ephemeral to me.
From what I’ve seen of previous Square Enix iOS releases, it seems that their
development staff doesn’t have a very good understanding of touchscreen input.
Instead of re-working an older game’s UI, they keep it the same and have some
awkward touch controls. In the reviews for FFT, there were a number of comments
about non-Retina graphics as well. I can’t decide if they just don’t take the
platform seriously, or don’t know any better, or don’t care.
I’m appreciative of Squeenix’s entry into iOS publishing, but I think that they
need to get their act together a bit more before I’ll consider (re)purchasing games from them.
So (for those of you who have been living under a rock) Apple has baked a "social" gaming service for iOS into recent releases called Game Center. Game Center allows its' users to see what games their friends are playing, as well as their own progress in the Game Center-enabled games they own.
For developers, the main advantage to Game Center is that it simplifies the creation of leaderboards and achievements for your game. Prior to Game Center, if you wanted to keep a global list of high scores, you had to write your own web service. Not only did this require a lot of extra work, but it also relied on your users creating an authenticated account with said service. Some dedicated users might create an account that they could only use with your game, but most would not. Game Center helps alleviate this problem by providing a single set of credentials that all games can use. Other services such as OpenFeint did this as well, but OpenFeint had some annoying terms of service (such as requiring their logo in your app icon). Plus, Game Center has kind of an unfair advantage, seeing as how its' a first-party offering integrated into the OS.
An additional advantage of Game Center is that it's dead easy to use. If a mouth breather such as myself can figure it out, then I guarantee that you can too. You create your leaderboards and achievements through a web interface in iTunes Connect; no coding required. All you have to do is wrangle the example code provided by Apple into something that works for your game. Here I'll show you my example of how I implemented leaderboards into Revolve Ball.
I decided that I would make a "GameCenterManager" singleton class, which would then be able to be accessed from anywhere in my game. I also chose the singleton because I had pre-existing code that I could use to save/restore the object's properties in case the app was terminated. Apple recommends that you save any scores/achievements that don't get successfully sent to the Game Center servers, so that you can try sending them again at a later time; being able to save/restore the singleton fit right in with that recommendation.
Apple also provides a reference implementation for creating a singleton instance, but in my web searches I found a nice singleton helper which automatically creates the code necessary to turn your custom object into a singleton. I'll leave it as an exercise for the reader to download that file and include it in your project.
Let's begin. Take a look at the header file for my GameCenterManager object. I'll keep the extraneous commentary to a minimum, and focus on explaining the code with inline comments.
#import <GameKit/GameKit.h>
#import "SynthesizeSingleton.h"
// Subclass our object from NSObject - allow it to be serialized, and make it the delegate for the leaderboard view
@interface GameCenterManager : NSObject <NSCoding, GKLeaderboardViewControllerDelegate>
{
// Boolean that is set to true if device supports Game Center and a player has logged in
BOOL hasGameCenter;
// An array that holds scores that couldn't be sent to Game Center (network timeout, etc.)
NSMutableArray *unsentScores;
// The view that shows the default Game Center leaderboards
UIViewController *myViewController;
}
// Create accessible properties
@property (readwrite) BOOL hasGameCenter;
@property (readwrite, retain) NSMutableArray *unsentScores;
// Time-saving singleton generator - see http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html
SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(GameCenterManager);
// These methods are all provided as examples from Apple
- (BOOL)isGameCenterAPIAvailable;
- (void)authenticateLocalPlayer;
- (void)reportScore:(int64_t)score forCategory:(NSString *)category;
- (void)showLeaderboardForCategory:(NSString *)category;
- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController;
// Serialize/store the variables in this singleton
+ (void)loadState;
+ (void)saveState;
@end
You can see that this class is pretty basic. All the class methods (except loadState and saveState) were taken from Apple's Game Kit documentation. They include determining if Game Center is available on the device, authenticating a player, sending a high score, and showing/dismissing the leaderboard view. I added two additional properties, hasGameCenter and unsentScores. The first is a boolean that is true if the device supports Game Center and a player is logged in. Since I weak link Game Kit framework, none of the class methods actually do anything if it is set to false, and I can support the original iPad version of iOS (3.2) which doesn't have Game Center. unsentScores holds any high score that wasn't successfully sent to the leaderboards. The next time the player logs in to Game Center using my game, it tries to send each score again.
Now let's look at the class implementation. Again, most of this is from Apple's reference code. The only bits I added were checking against the hasGameCenter boolean, and the re-sending of any saved scores upon successful authentication. Make sure to read through the documentation to get a better idea of what the Game Kit classes are doing under the hood.
#import "GameCenterManager.h"
#import "cocos2d.h"
@implementation GameCenterManager
@synthesize hasGameCenter, unsentScores;
// Time-saving singleton generator - see http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html
SYNTHESIZE_SINGLETON_FOR_CLASS(GameCenterManager);
- (id)init
{
if ((self = [super init]))
{
// Initialize any class properties here
if ([self isGameCenterAPIAvailable])
hasGameCenter = YES;
else
hasGameCenter = NO;
}
return self;
}
/**
Check to see if installed OS supports Game Center
*/
- (BOOL)isGameCenterAPIAvailable
{
// Check for presence of GKLocalPlayer class
BOOL localPlayerClassAvailable = (NSClassFromString(@"GKLocalPlayer")) != nil;
// Device must be running 4.1 or later
NSString *reqSysVer = @"4.1";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending);
return (localPlayerClassAvailable && osVersionSupported);
}
When the class is instantiated, the singleton runs the isGameCenterAPIAvailable method, which ensures the OS supports Game Center. If true, it sets my own hasGameCenter boolean to true. The rest of my Game Center methods check that boolean, so I can call those methods at any time and not have to worry about device support. If the device doesn't support Game Center or the player can't be authenticated, the leaderboard/score reporting methods just don't do anything.
/**
Attempt to authenticate a Game Center user. Will automatically present a modal login window.
*/
- (void)authenticateLocalPlayer
{
if (hasGameCenter)
{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
[localPlayer authenticateWithCompletionHandler:^(NSError *error) {
if (localPlayer.isAuthenticated)
{
/* Perform additional tasks for the authenticated player here */
// If unsent scores array has length > 0, try to send saved scores
if ([unsentScores count] > 0)
{
// Create new array to help remove successfully sent scores
NSMutableArray *removedScores = [NSMutableArray array];
for (GKScore *score in unsentScores)
{
[score reportScoreWithCompletionHandler:^(NSError *error) {
if (error != nil)
{
// If there's an error reporting the score (again!), leave the score in the array
}
else
{
// If success, mark score for removal
[removedScores addObject:score];
}
}];
}
// Remove successfully sent scores from stored array
[unsentScores removeObjectsInArray:removedScores];
}
}
else
{
// Disable Game Center methods - player not authenticated
hasGameCenter = NO;
}
}];
}
}
This method presents the player with a modal window to log in to Game Center. If they are already logged in, they'll see the "Welcome back, so-and-so!" notification pop down from the top of the screen. If the player doesn't get authenticated for some reason (i.e. they dismiss the modal), hasGameCenter is set to false, and Game Center-speicific methods are ignored for the rest of the game session.
/**
Send an integer score to Game Center for a particular category (set up category in iTunes Connect)
*/
- (void)reportScore:(int64_t)score forCategory:(NSString *)category
{
// Only execute if OS supports Game Center & player is logged in
if (hasGameCenter)
{
// Create score object
GKScore *scoreReporter = [[[GKScore alloc] initWithCategory:category] autorelease];
// Set the score value
scoreReporter.value = score;
// Try to send
[scoreReporter reportScoreWithCompletionHandler:^(NSError *error) {
if (error != nil)
{
// Handle reporting error here by adding object to a serializable array, to be sent again later
[unsentScores addObject:scoreReporter];
}
}];
}
}
This is the method used to report a high score to Game Center. However, before you can use it, you'll need to bust out of XCode and go to iTunes Connect to set up the leaderboards your game will use. The first step is to create a new app entry, with an icon, description, screenshots, etc. Go ahead and use placeholder or WIP artwork; you can change all that info later before you upload your first binary. Make sure that the "Enable Game Center" option is checked. When you're finished, navigate to the main app page (the first one that appears after you click the app's icon on the "Manage Your Apps" page). On the right side of the screen, there'll be some buttons for setting up In-App Purchase, Game Center, and iAd. Click the Game Center button, then click the "Set up" button under the Leaderboards header. From there, you'll be able to configure your leaderboard, including setting up a unique string to be used as the leaderboard ID. When you report a score to Game Center, you'll use that string as the "category". For example, I use the above method like this in Revolve Ball:
Next, let's look at actually displaying the leaderboard. There are two ways you can do this: use the default Game Center-themed view controller provided by Apple, or get the data and insert it into your own UI. I'm lazy, plus UI programming takes forever, so I opted for the easier method.
/**
Show the "green felt" leaderboard view for a particular category
*/
- (void)showLeaderboardForCategory:(NSString *)category
{
// Only execute if OS supports Game Center & player is logged in
if (hasGameCenter)
{
// Create leaderboard view w/ default Game Center style
GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];
// If view controller was successfully created...
if (leaderboardController != nil)
{
// Leaderboard config
leaderboardController.leaderboardDelegate = self; // The leaderboard view controller will send messages to this object
leaderboardController.category = category; // Set category here
leaderboardController.timeScope = GKLeaderboardTimeScopeAllTime; // GKLeaderboardTimeScopeToday, GKLeaderboardTimeScopeWeek, GKLeaderboardTimeScopeAllTime
// Create an additional UIViewController to attach the GKLeaderboardViewController to
myViewController = [[UIViewController alloc] init];
// Add the temporary UIViewController to the main OpenGL view
[[[CCDirector sharedDirector] openGLView] addSubview:myViewController.view];
// Tell UIViewController to present the leaderboard
[myViewController presentModalViewController:leaderboardController animated:YES];
}
}
}
/**
Since this singleton is the GKLeaderboardViewControlerDelegage, it intercepts this method and removes the view
*/
- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController
{
[myViewController dismissModalViewControllerAnimated:YES];
[myViewController release];
}
I'm leaving out the overview for the loadState and saveState methods; an NSCodingtutorial would probably be a better place for that. However, you can download the complete GameCenterManager class and study them on your own.
The final thing I'll mention is how to instantiate the Game Center singleton when your app starts, and then serialize its' unsentScores array before the app quits (so data doesn't get lost). In your app delegate file, in the applicationDidFinishLaunching method, add this line anywhere to init the object and load any saved data:
[GameCenterManager loadState];
Then, to save before your app quits, put this line in the applicationWillTerminate method in the app delegate file:
[GameCenterManager saveState];
This is just a starting spot for what you can do with Game Center. Hopefully you can take this code to the next level by adding achievement reporting and whatever new gimmicks iOS 5 has in store. Problems or suggestions? Let me know in the comments!
So, after about two months, I'm finally getting around to showing the current project I'm working on. This is an idea that I've had since before actually learning iOS development. To be honest, it's not very original, but it's kind of a fun diversion. Since I knew that I wouldn't have to create levels, I thought it would be a good test of a two-month development cycle. Unfortunately, due to some other circumstances (namely, a baby that likes to wake up at 5 in the morning), I'm not going to be able to keep that schedule (although it will be pretty close).
My game is going to be entitled color + shape, and is (obviously) a color/shape-matching game. If you've played something like Bejeweled, the concept will probably be pretty easy to understand. The object is to line up four or more blocks with the same color or the same shape on them. A successful match makes the matched blocks disappear, and new random blocks fall to take their place. You only have 30 seconds to make as many matches as you can, but each match puts a small amount of time back into the time limit. If you're quick, you can keep playing (almost) indefinitely.
The puzzle blocks are moved around the screen by using your finger to slide entire rows and columns. The twist is that when a block disappears off one edge of the screen, it re-appears on the opposite side, which creates kind of an infinite scrolling effect. I think that I learned a lot more about grid-based games while trying to make this feature. Sadly, it was a lot of work for a such a trivial effect!
The goal of the game is to get a high score, and the way that is accomplished is by increasing the game's "combo" meter. Whenever you make a match, the combo meter is increased by one. Making quick sequential matches (or positioning blocks so that one match automatically triggers another) will increase that meter. The points you get for a match and the time added to your limit are multiplied by the combo meter, so you obviously want to keep it as high as possible. However, if too much time goes by without a match, the combo meter will quickly count itself back down to zero.
There will be two game modes, "Normal" and "Time Attack." Normal lets you play as long as you can, while Time Attack gives a set time limit within which you have to get the highest score possible (I haven't decided on the limit yet, but it'll probably be one or two minutes). Of course, there will be Game Center support, so you can compare your scores against friends and other internet crazies.
Right now I'm working on creating the game soundtrack. Music composition is the area of game making that I'm weakest in, but I'm going to try to get better! I have about a bazillion music-making programs; I just need to pick one, hunker down, learn it, and churn out some cool-sounding tunes. Easier said than done, of course. While my two-month deadline is rapidly approaching, I'm definitely going to have it done by the three month mark. Watch this blog or follow me on Twitter to keep updated!
I first saw Gears on the top 10 list in iTunes. The icon was unique, colorful, and featured a ball (hmm, sounds familiar). And it wasn't Angry Birds, so I was intrigued. Not intrigued enough to actually click on the icon, though. It wasn't until I got an email newsletter from Unity3D mentioning the game that I finally clicked through and bought it. See, Gears was developed in Unity, and I've been interested in finally learning Unity development. I've got one more game in the works that I'm going to make with cocos2d, and after that I'm going to give Unity a shot. Anyway, I was curious to see what this dev team was able to create, so I nabbed their app.
Gears, despite the name, is a regular "labyrinth"-type game, where you roll a ball around various obstacles in an attempt to beat the clock in each level. The "gears" moniker fits in because a large component of each level are spinning gears that the player must navigate. Each maze consists of said gears, plus other elevated platforms. Of course, there are obstacles that you must confront, such as locked gates and exploding boxes. There are a number of collectable tokens strewn throughout each level as well; you've got to collect them all in order to get the best possible score.
The graphics are good, but a bit dark. Sometimes it's hard to appreciate the detail that obviously went in to the art assets. Each game world is set underground, so there's not a whole lot of variation. I'm kind of a fan of "blue sky in games", so I wouldn't have minded some different environments.
The physics are also good, of course, since the game is made with Unity. Each maze is truly three-dimensional, so you might have to make the ball fall downwards, or have to confront sloping platforms. There's even trampolines in a few of the levels. If your ball falls off the maze, you're able to try again from the most recent checkpoint you passed. If you fall off more than once or twice, the level is then almost impossible to complete (due to not having enough time), necessitating that you navigate to the menu to manually restart the stage. At least the developers had the foresight to include a "swiping" style control method as well as accelerometer control, otherwise the game would be unplayable (I hate accelerometer-based games).
On the whole, I think Gears is a decent title. What it lacks in originality, it makes up for in presentation and accessibility.