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 · , , , , ,

Thoughts on Square Enix’s iOS game pricing · August 5, 2011

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.

1. $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.

2. 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.

3. 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.

4. 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.

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

cocos2d + Game Center · July 13, 2011

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:

[[GameCenterManager sharedGameCenterManager] reportScore:bestTime forCategory:@"com.ganbarugames.revolveball.world_1"];

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 NSCoding tutorial 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!

8 comments · Posted by in Programming, Tutorial · , , , , ,

Preview: color + shape · June 24, 2011

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!

2 comments · Posted by in Games · , , ,

Review: Gears · June 16, 2011

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.

★★★☆☆ — Gears on the App Store

Add a comment · Posted by in Reviews · , , ,

NS(Mutable)Array tips · June 1, 2011

The game I’m currently working on is a color-matching game, where the puzzle tiles are arranged on a grid. Obviously, the data structure you’d use for such a game is an array. While you could use a regular C array, NSMutableArray has a few advantages. It’s true that NSArray/NSMutableArray are slower than regular C arrays, but in most (or all) cases, you won’t see any performance issues because of it.

First of all, there are lots of convenience methods in the NSArray/NSMutableArray classes that make it easy to be lazy. If you’re used to working with arrays in scripting languages, you probably don’t want to go back to using C-style arrays. NSArray allows you to easily search/sort your data. Second, NSArray can be easily serialized, which allows you to save/restore your data in order to support multitasking. Nonogram Madness uses an NSArray to store the player’s game when the app moves to the background.

Anyway, here are a few tips that I’ve found whilst mucking around with NSMutableArray… hopefully you can use them in your next puzzle game.

  1. The – removeObjectAtIndex: method will remove the specified object from your array, but then will also shift the indices of the elements beyond index down by one, filling the gap that was created. So, to perform logic that behaves like PHP’s array_shift, you could do something like this:
    id myObject = [myMutableArray objectAtIndex:0];
    [myMutableArray removeObjectAtIndex:0];
    
  2. You can easily use just one array to simulate a 2D array. This has an advantage when working with NSMutableArray, because the nested message passing syntax can get pretty hairy when querying an array inside an array. Just store the size of your grid as integers, and derive the x/y position of an object based on its’ index.
    // Size of grid - 10x10
    int rows = 10;
    int cols = 10;
    
    int index = 83;
    
    int x = index % cols;
    int y = floor(index / rows);
    // Results in x, y == 3, 8
    
  3. Since removing objects from an NSMutableArray actually shortens the array, what do you do when you want to remove objects but preserve the “empty space” they should leave? Use NSNull of course. NSNull is specifically used in arrays/collections that can’t store a nil value. Instead of removing the object from your array, do one of these numbers:
    [myMutableArray replaceObjectAtIndex:0 withObject:[NSNull null]];
    
    if ([myMutableArray objectAtIndex:0] == [NSNull null])
    {
        NSLog(@"That index is empty!");
    }
    

Have any other tricks or advice for using NSArray? Let me know in the comments!

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

iPhone 4 GET! · May 6, 2011

iPhone 4 Sorry for the recent blog silence… things have been pretty busy as of late, and of course the first thing to get cut is the blog. Don’t worry, I’ve still been game makin’. Revolve Ball just got updated with Game Center leaderboards and a few other tweaks, and I’ve started work on a new game. It’s not an original concept, but presents some interesting programming problems that I’ve been working through in the past week. Hopefully I’ll be able to show some progress in the coming weeks.

In other news, my crap Samsung Alias 2′s A/C adapter died and I decided to finally get another iPhone instead of pony up $30 to keep using a phone I totally hated. My original plan was to wait until iPhone 5, but my resolve was weakened after learning that it wouldn’t be released in June. So I nabbed a white Verizon iPhone 4. C’mon, I had to get the white! It’s like the Loch Ness Monster or something… a mythical, unseen legend. I’m very pleased with it so far (of course).

2 comments · Posted by in Meta · ,