Review: Super Crate Box · January 13, 2012

Heyooo, time again for me to write another game review instead of actually making games! This installment will cover the “underground” PC hit with the most redundant/nonsensical name ever, Super Crate Box. Super Crate Box (hereafter, SCB) was released a year ago to critical acclaim by Dutch developers Vlambeer. Unfortunately, the first release was Windows-only, so I never actually tried it out (although there’s a Mac version now). Fortunately, Vlambeer decided to cash in a bit on the success of the freeware PC release by porting the game to iOS. So, how is it?

Well, SCB is a single-screen shooting game. The goal, as the name of the game might imply, is to collect “crates.” Nabbing a crate will increase your score by 1. Hey, it’s not quite that easy! To prevent you from becoming a crate-collecting master, baddies stream down from an opening in the ceiling (I don’t know how they got there). You can shoot or avoid the enemies, but if an enemy makes it to the bottom of the screen, they fall into a fire pit. Naturally, this enrages and teleports them back to the top of the screen, where they become even harder to deal with. Fortunately, every time you collect a crate, you get a different weapon to help deal with the hordes of baddies.

Seems simple? Deceptively so. The fun of the game is the balance between killing enemies and collecting crates. While each crate gives a weapon that is better than the pistol you start with, some weapons are certified lemons. The disc gun, for example, will chop baddies in half, but it also ricochets and can slice you in half as well. Dual pistols just means that you can shoot underpowered bullets both left and right. Mines take a second to arm, which doesn’t help when there are enemies right on top of you. An average game means getting a good weapon (such as the grenade launcher) and clearing the screen, then picking up as many crates as you can until another good weapon appears.

SCB uses virtual “buttons” to control the action, and while physical buttons will always be better for playing games, Vlambeer has managed to make the controls not quite as painful as other iOS games. This is because the hit-detection area of each button is much larger than depicted on screen, so even if your fingers move around in the heat of battle, you’ll still usually be able to control the game. Every once in a while I’ll experience a “cheap” death, where my fingers migrated off the buttons, but most of the time my character bites it because I’m too greedy for crates.

The verdict is in, and that verdict is: get it. It isn’t too often that a “simple” game such as SCB provides such a level of addictiveness. And, as always, for $1, you can’t go wrong on price.

★★★★★ — Super Crate Box – Vlambeer

2 comments · Posted by in Games, Reviews · , , , ,

End of 2011: Giving Back · January 3, 2012

As you all may have noticed, it’s 2012 now. The end of every year has its’ share of annoyances, not least of which are people trying to get you to donate money before the end of the year. If you visited Wikipedia at all in the past month, you’ve no doubt completely tuned out the “Read a Personal Appeal!” banners that were strewn across each page. Normally I tune all that stuff out too, but this year I got to thinking a bit about how privileged my life is.

  • Grew up in a solidly middle class family
  • Graduated from both high school and college
  • Have a full-time job with health insurance
  • Disposable income to buy Apple kit
  • Disposable time to program said kit

It’s pretty remarkable, actually. I’m probably in the top 1% of the world in terms of having a comfortable life. So I decided to try to be a little bit less of a selfish prick and donate some of this past year’s gaming income to a worthy cause.

I decided to help the scholarship fund for Harambee Christian School. It’s a K-7 school in Columbus, Ohio, that provides private education to kids who would otherwise not have many opportunities. I figured that since Harambee is a program in my city that tries to give kids something that I take for granted, helping out financially would be the least I could do.

I realize that this post is about a month late to try to convince people to donate to charitable organizations before the end of the year, but you should think about regularly donating to a non-profit regardless. The audience of this blog is primarily people just like me: middle class, with enough income to buy crap we really don’t need. Take a step back and think about how you can really help people, and not just by providing bits of mindless entertainment to smartphone users.

Add a comment · Posted by in Meta · ,

Intermission: The Legend of Zelda: Skyward Sword · December 14, 2011

As you can see, since announcing that I was going to start dabbling in Unity, I actually haven’t done anything! The cause of this is the fact that I’m currently ~20 hours in to the new Zelda game, Skyward Sword. Basically I’m trying to recharge and remind myself why I like games in the first place by actually playing one.

Fortunately, Skyward Sword is pretty good. While it isn’t as purely groundbreaking as Ocarina of Time, it does add a number of new gameplay mechanics that make the game feel fresh. My only criticism so far is that parts of the game are a bit padded (i.e. to progress, you need to fetch an item located in an area you’ve previously completed), but that is almost inevitable with any large-scale adventure game.

I’ve been talking the game up to co-workers, and even though I haven’t completed it yet, I can wholeheartedly recommend that you dust off your Wii and start swinging the remote like a crazy person. It’s a true “Nintendo” game, which is about as high of praise as I can give anything these days. Once I finish, I’ve got a few ideas in mind for new projects to start, so we’ll see where those lead.

Add a comment · Posted by in Games, Productivity · , , ,

Unity Challenge · November 30, 2011

It’s about time to learn something new. After publishing a few iOS projects using cocos2d as a programming framework, I’ve decided that I’m finally going to learn how to use Unity. I’ve always been on the cusp of using Unity since I first found out about it. At first, it was the $100 price tag for the “indie” version that kept me learning/using Actionscript with the free Flex compiler. After the base Unity package became free (and a Windows version was released), I toyed with the program: ran through a few tutorials before I had a Macintosh to start iPhone development. Once I got the Mac though, I dove straight into cocos2d instead.

cocos2d is great, but it has some limitations that I’ve been thinking about a lot lately. The main one is that your games run only on iOS devices. While it’s true that there is a cocos2d-mac port, it’s exactly that: a port. I did some investigation into making Mac versions of some of my games, and right now it’s actually a decent amount of work make that conversion. And let’s be honest: if a person owns a Macintosh, chances are they own an iOS device as well. As a part-time developer, one of my goals is (or at least should be) to create content in the shortest amount of time possible, and have it be playable on as many platforms as possible.

I think that Unity has reached a point where it is a viable option for aspiring game developers. The software is mature, it has a pretty sizable community, and there are a large number of helpful resources to get up and running. The added benefit of being able to publish to multiple platforms from the same project is what’s driving me to finally take the plunge.

Nothing is perfect, and I’m sure there will be things I dislike about Unity. Learning a new development platform is daunting, and it’s kind of depressing to start over with something new after investing a lot of time into cocos2d and Objective-C. However, the perceived benefits outweigh the costs in my mind right now, and I’m going to try to make the transition. If you’re interested in learning Unity along with me, keep coming back in the months ahead: I’ll be posting some introductory tutorials as I learn the basics (and you’ll be able to play the finished results in your browser with the Unity plugin!).

1 comment · Posted by in Meta · , , ,

Introducing BreakApp · November 14, 2011

Despite the relative silence of the blog recently, I’ve still been programming. After updating Nonogram Madness and Revolve Ball, I wanted to do something new, so decided to make a small productivity app. The result is BreakApp, a simple application for iPhone and iPod Touch which tries to remind you to take breaks from sitting at your desk. Most of my life is spent sitting, sadly, and there seems to be lots of research that says that prolonged sitting will take years off your life. However, if you can get up and move around regularly, it can help offset the negative effects of being a desk jockey.

Such “take a break” apps exist for the desktop already, but I wanted to make something for my phone. It’s all too easy for me to ignore warnings on my desktop, but when I get a notification on my phone, it breaks my flow/concentration more, because I have to spend more effort to look at the phone’s screen. Plus, I figured I’d be more likely to actually use the app if I was the one who wrote it.

The app is still written with cocos2d. I toyed with the idea of learning Interface Builder, but decided to prototype with something I already knew. By the time the functionality of the app was done, I had little interest in going back and re-writing the display code. The only real downside of using cocos2d instead of UIKit was the jankiness of the “slider” controls. I used some freely available code front the cocos2d-extensions project, and while it works, it’s not as good as what Apple provides.

I published the app as a way to make it more permanent, not necessarily to make any money. You can check it out on iTunes, and if it seems like the sort of thing you’d use, send me a note and I’ll give you a promo code.

4 comments · Posted by in Productivity · , ,

cocos2d + Game Center Achievements · November 1, 2011

If you’ve been following along on the blog, I posted a few months ago about how to easily integrate Game Center leaderboards into your cocos2d game. Game Center is pretty great, because Apple writes basically all of the code for you, and they also provide a web-based interface to create your content.

My previous tutorial was just about setting up leaderboards. Today I’m going to expand on that, and add in some methods to the Game Center singleton that will allow you to report achievements. Achievements are a bit different than leaderboards in that when you connect a player to Game Center, that player’s current achievement status is returned from Apple’s servers. Sending leaderboard scores are just fire and forget, but for achievements you have to figure out their completion status and increment that value, then send it back. Like I said, Apple writes all the GameKit classes that deal with interacting with Game Center, and they also provide example code which basically works right out of the box. In fact, I only had to write one method of my own when implementing achievements, and that was for my own convenience.

Bust out your GameCenterManager class and add some properties and methods to the header file:

// Store unsent Game Center data
NSMutableArray *unsentAchievements;

// Store saved Game Center achievement progress
NSMutableDictionary *achievementsDictionary;

// Achievement methods
- (GKAchievement *)getAchievementForIdentifier:(NSString *)identifier;
- (void)reportAchievementIdentifier:(NSString *)identifier percentComplete:(float)percent;
- (void)reportAchievementIdentifier:(NSString *)identifier incrementPercentComplete:(float)percent;
- (void)showAchievements;
- (void)achievementViewControllerDidFinish:(GKAchievementViewController *)viewController;

These properties and methods should look pretty self-explanitory if you’ve already read through the previous tutorial. The unsentAchievements array is used to store achievement reports that can’t be sent to Apple for some reason (e.g. network timeout). The next time the user is authenticated, the manager class tries to resend the data. achievementsDictionary stores a player’s existing achievements locally, so we can quickly check completion status without having to use a network connection each time. The first method is only used internally by the other methods as an easy way to query the achievementsDictionary. The next two methods are used to report achievement progress, while the last two deal with displaying the achievement progress.

The first thing we have to do is load a player’s existing achievement completion percentage from Game Center after they are successfully authenticated. In the - (void)authenticateLocalPlayer method, after the if (localPlayer.isAuthenticated) conditional, add the following code to load achievements into the achievementsDictionary object you added to the singleton.

// Load player achievements
[GKAchievement loadAchievementsWithCompletionHandler:^(NSArray *achievements, NSError *error) {
	if (error != nil)
	{
		// handle errors
	}
	if (achievements != nil)
	{
		// process array of achievements
		for (GKAchievement* achievement in achievements)
			[achievementsDictionary setObject:achievement forKey:achievement.identifier];
	}
}];

Next let’s look at the implementation of the methods we defined earlier. These are all taken from Apple’s example documentation, except for - (void)reportAchievementIdentifier:(NSString *)identifier incrementPercentComplete:(float)percent which is just a simple modification that I thought was convenient.

#pragma mark -
#pragma mark Achievement methods

/**
 * Get an achievement object in the locally stored dictionary
 */
- (GKAchievement *)getAchievementForIdentifier:(NSString *)identifier
{
	if (hasGameCenter)
	{
		GKAchievement *achievement = [achievementsDictionary objectForKey:identifier];
		if (achievement == nil)
		{
			achievement = [[[GKAchievement alloc] initWithIdentifier:identifier] autorelease];
			[achievementsDictionary setObject:achievement forKey:achievement.identifier];
		}
		return [[achievement retain] autorelease];
	}
	return nil;
}

/**
 * Send a completion % for a specific achievement to Game Center
 */
- (void)reportAchievementIdentifier:(NSString *)identifier percentComplete:(float)percent
{
	if (hasGameCenter)
	{
		// Instantiate GKAchievement object for an achievement (set up in iTunes Connect)
		GKAchievement *achievement = [self getAchievementForIdentifier:identifier];
		if (achievement)
		{
			achievement.percentComplete = percent;
			[achievement reportAchievementWithCompletionHandler:^(NSError *error)
			{
				if (error != nil)
				{
					// Retain the achievement object and try again later
					[unsentAchievements addObject:achievement];

					NSLog(@"Error sending achievement!");
				}
			}];
		}
	}
}

/**
 * Send a completion % for a specific achievement to Game Center - increments an existing achievement object
 */
- (void)reportAchievementIdentifier:(NSString *)identifier incrementPercentComplete:(float)percent
{
	if (hasGameCenter)
	{
		// Instantiate GKAchievement object for an achievement (set up in iTunes Connect)
		GKAchievement *achievement = [self getAchievementForIdentifier:identifier];
		if (achievement)
		{
			achievement.percentComplete += percent;
			[achievement reportAchievementWithCompletionHandler:^(NSError *error)
			 {
				 if (error != nil)
				 {
					 // Retain the achievement object and try again later
					 [unsentAchievements addObject:achievement];

					 NSLog(@"Error sending achievement!");
				 }
			 }];
		}
	}
}

You can see that these reporting methods are very similar to the reporting methods used for leaderboards. Each one tries to get an existing achievement object from your local cache of achievement data, set the percentage complete (or increment it), then send to Apple. If the report fails, the GKAchievement object gets temporarily stored locally, and will attempt to be sent again later. I added the - (void)reportAchievementIdentifier:(NSString *)identifier incrementPercentComplete:(float)percent method because it was easier to just have each successfully completed level in my game add a certain percentage towards completion status. For example, you have 20 levels, so each level just adds 5% to the total. That way you don’t have to find the previous completion percentage of the achievement object.

The next methods are straight from Apple’s example code; the only thing changed here is that we attach the UIViewController that shows a player’s achievements directly to cocos2d’s OpenGL view. This will show the default “green baize” style Game Center UI; if you want your own custom UI, that’s something you can do, but outside the scope of this tutorial.

/**
 * Create a GKAchievementViewController and display it on top of cocos2d's OpenGL view
 */
- (void)showAchievements
{
	if (hasGameCenter)
	{
		GKAchievementViewController *achievements = [[GKAchievementViewController alloc] init];
		if (achievements != nil)
		{
			achievements.achievementDelegate = self;

			// Create an additional UIViewController to attach the GKAchievementViewController to
			myViewController = [[UIViewController alloc] init];

			// Add the temporary UIViewController to the main OpenGL view
			[[[CCDirector sharedDirector] openGLView] addSubview:myViewController.view];

			[myViewController presentModalViewController:achievements animated:YES];
		}
		[achievements release];
	}
}

/**
 * Dismiss an active GKAchievementViewController
 */
- (void)achievementViewControllerDidFinish:(GKAchievementViewController *)viewController
{
	[myViewController dismissModalViewControllerAnimated:YES];
	[myViewController release];
}

The last thing you’ll have to do before you can actually use these reporting methods in your game is set up the achievements in iTunes Connect. Create a new app entry for your game and enable Game Center for it. Next, go into the “Configure Game Center” section and set up your achievements. The interface is really so simple that you should be able to figure it out easily. The most important part is to take note of each achievement ID string that you create, as these will be used in your code to reference each achievement. For example, in Nonogram Madness, when a player successfully completes an easy randomized level, I make a call with the GameCenterManager like this:

[[GameCenterManager sharedGameCenterManager] reportAchievementIdentifier:@"com.ganbarugames.nonogrammadness.random_easy" incrementPercentComplete:10.0];

And that’s all there is to it! Download the example source, and if you have any questions, feel free to leave a comment or get in touch on Twitter.

Add a comment · Posted by in Programming, Tutorial · , ,

Hmm, updates. · October 18, 2011

During periods of reduced productivity, the blog is inevitably the first thing to be neglected. The past two months have found me struggling to keep up active game development, mainly due to an inconsistent work schedule. And by “work,” I mean “sleeping baby.” I realize that’s no excuse, and simply need to shift my mindset to getting work done every day, regardless of the time.

While I haven’t released any new games since color + shape, I have done significant updates to Nonogram Madness and Revolve Ball. In addition to completely reworking the graphics and music for both games, I’ve created “lite” versions of the apps. I’m curious to see if there will be any noticeable difference in download volumes. Each lite app has a prominent “upgrade” button on the title screen, and includes the first few levels from each game. After completing all the demo levels, an upgrade scene is shown, describing the extra features of the full version of the game. Each “upgrade” button actually uses a LinkShare affiliate URL, in an attempt to track conversions.

EDIT: I’m actually pretty disappointed in the conversion rate for the “lite” apps. For a few days, it seemed like sales of Nonogram Madness were up by a decent margin, but they have since returned to normal levels. Even more disappointing was the Revolve Ball demo. It’s been out two days and had 1200 downloads, with 4 sales of the full version. I don’t regret spending the time to program these updates, because I feel like the games are more indicative of where I currently am as a game programmer. However, from a financial standpoint it was pretty much not worth it. The goal was to increase awareness and presence in the App Store, but the games just must not be compelling enough.

Add a comment · Posted by in Bizness, Games · , , , ,

color + shape postmortem · September 27, 2011

Uh, so I’m not sure how cool it is to slag on your own games, but I’m not really excited about color + shape. A number of things were frustrating about developing it, and I definitely learned a few lessons that I’ll carry on to future projects.

  1. The game isn’t interesting. I had the idea for this type of game back before I started doing serious iOS development. It was one of those “Oh, that might be fun.” type of ideas. Unfortunately, this sort of game has really been done to death. It’s not original, and doesn’t hold my interest for any prolonged amount of time. Why did I start and continue development? At first I started so that I could tell myself that I tried the idea. Then, as I sank more time into the project, I didn’t want to “give up,” as I viewed it. Two lessons here. The first is to only start projects that I can really be proud about and have fun playing. Life is too short to waste on making projects that you don’t care 100% about. color + shape might be something great to show a potential employer, but it means pretty much nothing as a marketable game. I’d love to submit it to some iOS gaming sites, but it’s really so unoriginal that I can’t imagine anyone taking an interest in it. The second is to kill projects that you’re not excited to finish and are not marketable. Now, it’s obviously important to finish some projects, but I spent four months on color + shape that would have been better spent elsewhere.
  2. Localization didn’t have any effect. In the first few days of downloads, I didn’t get any sales from Japan. At first, I thought there was something wrong with my localized App Store listing. Nope, nothing wrong, I guess the game doesn’t look appealing to Japanese people. Maybe the keywords I chose weren’t very good? Who knows? Now, it wasn’t a whole lot of extra work to localize the game, but it definitely wasn’t worth it. I might try to add a Japanese localization to another project, just as another attempt, but I’m pretty discouraged by my first effort. Maybe it’s just the fact that the game isn’t very interesting and I haven’t promoted it at all, but I would expect to see at least a few organic downloads.

There were a few positive things that came out of making the game, though.

  1. I learned a heck of a lot more about manipulating arrays for grid-based games. I have a decent collection of code that I can reuse if I ever decide to make another one.
  2. I was able to experiment more with cocos2d “actions,” which helped me a lot in my Nonogram Madness update.
  3. I finally updated to Xcode 4 and learned how to localize image resources.

In conclusion, I feel like the game is still a good thing to have in my portfolio, if only to remind me of the fact that execution is not enough; the idea and design of a game has to be solid in order for me to finish making it.

2 comments · Posted by in Games · , , , ,

color + shape is on the App Store! · September 8, 2011

Check-a check it! My new game just got published today. If you have a dollar burning a hole in your pocket, you should download it from iTunes.

There were a few design changes made from when I first announced the game on this blog back in June. For example, instead of having a countdown timer to limit each play session, there’s a “move” meter. Each time you move a row or column, the meter decreases. Making matches recharges it. I made this change after seeing my wife successfully play the game by swiping randomly over the iPad. Since the matches come so easily, there needed to be a way to limit the player’s moves. Partially because of this change, there’s no “Time Attack” mode in the game, since there’s no longer a timer. Although it’s something that could be added in an update.

In any case, it’s a fun little diversion, and I’d like to hear any feedback you might have. I’ll be writing a more detailed postmortem about the development process later, so stay tuned!

Add a comment · Posted by in Games

iOS internationalization and localization · August 25, 2011

Something I wanted to do for the release of color+shape was try to have a Japanese localization. I know a smattering of Japanese, and I figured it was a relatively small effort to double my App Store keywords. Actually, I think you can have multilingual app listings without doing any localization, but I also wanted to learn about internationalization (hereafter, “i18n”) in Xcode projects.

color+shape doesn’t have a lot of text in it; in fact, most of the text in the game is embedded in .png files. This actually means that localization is a lot more work, because I have to actually create two different versions of each image with text: one with English, the other with Japanese. However, that might have been my only option… I have no idea if cocos2d-iphone’s bitmap label classes support non-Latin characters. Perhaps I’ll try that experiment sometime in the future.

However, even though it’s lots of work to create multiple image files, it’s pretty easy to get them into Xcode (version 4, by the way). I’ll outline the steps here.

  1. Save out the image you want to display in multiple languages, and add it to Xcode in the normal way (right-click on the Project Navigator file hierarchy, click “Add Files to [your project name]“, then choose the image.
  2. Highlight the newly-added image, then click the button in the upper right that shows the “Utilities” toolbar (it’ll be the one that pops out from the right).
  3. There’ll be a “Localization” section in that toolbar for each resource file. By default, of course, there will be no localizations. Click the “+” button at the bottom of the blank list. It’ll deselect the image you selected, so re-select the image file.
  4. When you re-select the image, you’ll see that an “English” localization has been created. What that means is that behind the scenes, a new directory called “en.lproj” has been created in your Resources directory, and the image has been moved there. Click the “+” button again to create as many different localizations as you want. Each time you do so, a new directory will be created with a copy of the original file.
  5. To finish, simply create a translated version of the image, and save it into the appropriate localized directory, using the same filename (for example, if I wanted to have a localized title screen image, “title.png”, I’d follow the steps outlined above, then save my Japanese version in “Resources/ja.lproj/title.png”).
  6. To make sure everything is working, open up your iOS simulator (or device) and change the language setting under “General > International” in the Settings app. Build and run your app, and you should see the translated resource get used automatically — you don’t have to change anything in your code! It’s worth noting, however, that you want to make sure your translated images are the same dimensions, otherwise their positions might be incorrect.

I’ll also tell you how to localize the display name of your app. This actually took me a lot of trial and error to figure out, since most of the online documentation and tutorials I found left out a critical step (the necessity of semicolons at the end of each line).

  1. Add “Application has localized display name” key to Info.plist
  2. Add a new file to your project named “InfoPlist.strings” (under the “Resources” category in the New File dialog)
  3. Add localizations to that file, using the same process detailed above
  4. Add this line to each localization “CFBundleDisplayName” = “LocalizedName”;

If you get this error: “validation failed: The data couldn’t be read because it has been corrupted.” that means there needs to be a semicolon at the end of each line in your InfoPlist.strings file.

Hopefully this gives you a starting point for translating and building a localized version of your game or app. I’ll be sure to write again about whether or not this has an effect on my downloads in Japan.

5 comments · Posted by in Tutorial · , , , , ,