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

New Strategy · April 19, 2011

I’m wrapping up development on the first update of Revolve Ball, which means I’m also starting to look ahead to what I’m going to work on next. I’m also looking back, in order to gain some understanding about what problems I had with my previous project, and how to try to fix them.

The number one problem that I have right now is that I’m still treating game development as a hobby instead of as a (side) business. Now, there’s nothing wrong with that, but if I ever want to go full time, it will be much easier if I have good development practices in place. Practices such as design documents and scheduling/deadlines. Part of the reason that Revolve Ball took such a long time to make was that I never had a clear goal from the beginning, just a vague idea that I kept adding to. Because of that, I never really set deadlines or milestones to keep myself on track for a quicker release.

Another problem that I’ve seen in both Revolve Ball and Nonogram Madness is that creating game content is very time consuming. It’s possible to sit and tweak levels for hours, and since the “fun factor” of a level is kind of arbitrary, it’s hard to know when to stop. Since I only get maybe one hour of development time every day, such time consuming tasks would be best cut out, if at all possible.

So, because of these considerations, I’m going to try a new two-month development cycle for my next few projects. These games will be smaller in scope, and won’t require level creation. The basic timeline would look something like this:

  • Two weeks – design document, wireframes, screen comps, icons
  • Two weeks – music and sound effects
  • Four weeks – programming and quality assurance

Seems pretty aggressive. However, I’d rather set a narrower schedule due to Parkinson’s Law, which says that any task will take as long as the time limit you have to complete it. Since I’m still a novice game maker and am not anticipating any high sales for a particular game, my best strategy at this point is to focus on the $0.99 price point and ship, ship, ship. As always, I’ll keep this blog updated with the results of my game makin’.

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

Revolve Ball is Ready for Sale · April 13, 2011

Revolve Ball App IconCheck-a check it out! The game I’ve been working on for a while, Revolve Ball, has been approved by Apple and is available for general purchase on the App Store. I think that the game mechanic and controls are pretty fun, it’s got 40 levels, and is only $0.99! Basically there’s no reason not to buy it.

Check out the splash page I made for the game, or go directly to iTunes to start playing! Be sure to leave me a review…. I’ll be publishing another update shortly with Game Center leaderboards, and would love to incorporate your feedback.

Add a comment · Posted by in Games · , ,

Looping background MP3s with cocos2d · April 6, 2011

OK, so I had a minor crisis today as I realized that the music that I made with pxTone and encoded with Audacity was not looping correctly in cocos2d. Even though I carefully cropped my source .wav files, after converting them to .mp3 and loading them into my game, there would be about a half-second delay before the BGM would loop. Turns out that this is due to the way most MP3 encoders handle the format; they add extra padding to the beginning and end of the file.

I came across a forum post where the author of CocosDenshion linked to a post that explained the problem, but didn’t offer a solution. I tried to use the utility he referenced, but couldn’t get it to work. Then I tried to think why I hadn’t run into this problem before. I realized that for Nonogram Madness, I made all my music with GarageBand. On a whim, I loaded my exported .wav into a new GarageBand project, then exported to MP3. It worked perfectly! There are a number of great things about this solution. First, GarageBand is included free with Macintosh computers, and you can get new versions for $5 from the Mac App Store. Second, I don’t have to use Audacity, which I have not been a fan of so far.

Add a comment · Posted by in Tutorial

Review: Tiny Wings vs. Canabalt · March 24, 2011

Tiny Wings Title ScreenOh yeah, I’m going there: reviewing the #1 game on the App Store. Last Friday, during a company-wide meeting, one of my co-workers asked innocently, “So, has anyone played this ‘Tiny Wings’ game?” Only the entire internets, my friend. Only the entire internets. You’ve obviously played Tiny Wings, so this review is irrelevant as to whether or not you purchase the game. However, I figured I’d deconstruct it a little bit and try to explain (to myself, mostly) why it’s so much more fun than similar games such as Canabalt.

Canabalt inspired a number of other games, and has probably created its’ own “runner” genre. In Canabalt, you control a running man, and have to run as far as you can before you inevitably meet a grisly demise. The man runs forward constantly; the only way you can control him is by making him jump from platform to platform. As he runs farther, he also runs faster. The strategy behind a high score in the game is to run into debris that litters the platforms — they’ll cause the man to stumble and slow down, which means that you have more time to react to upcoming platforms.

Tiny Wings GameplayThe problem with Canabalt, though, is that it is very unforgiving. Make a mistake, and you have to start all over again from the beginning. Tiny Wings has you controlling a bird that flies between hills. To progress faster through the game, you tap the screen to cause the bird to fall. Move your finger away to allow him to jump off the hills, then tap again to drop into a valley and jump even higher. It’s a very satisfying movement mechanic — similar to the old-school Sonic series, in that the game character moves agonizingly slowly if he loses momentum. However, if you miss a jump, you don’t instantly lose… you get to climb to the next hill and keep moving. This means that you can still progress in the game without being “perfect,” and that a mistake early on won’t ruin the whole play session.

Canabalt is also notable for having entirely procedurally-generated content. While this means that you never play the same game twice, it also ensures that the game is very “twitchy;” you never know what’s coming ahead, and so fast reflexes are required for getting a high score. The levels in Tiny Wings aren’t random, so by playing through a few times you’ll be able to figure out the best way to fly faster or collect the most items. It also means that you won’t get randomly screwed by the level-generating algorithm.

More Tiny Wings GameplayTiny Wings has “achievements” — rewards for completing arbitrary goals in the game. Even if you aren’t skilled enough to reach the final level, the achievements provide mini-goals that are able to be completed even by beginners. These provide a reason to come back to the game even when the initial fun of the core mechanic has been exhausted. In Canabalt, once you tire of endless jumping, the game is effectively over for you.

My final observation might be somewhat silly, but I think it makes a difference in the overall appeal of the two games. Canabalt has a bleak outlook, enhanced by the monochromatic graphics. No matter how well you play, your character always dies in the end. The bird in Tiny Wings falls asleep if night catches up with him. In my mind, part of the appeal of video games is that you can forget about the real world for a while. I don’t need games reminding me about the futility of life and inevitability of death. +1 for Tiny Wings.

1 comment · Posted by in Games, Reviews · , , , ,

cocos2d Game Tutorial – Multitouch Asteroids (Part 3) · March 9, 2011

Hey, welcome back to yet another installment of the “multitouch asteroids” tutorial series. If you haven’t been following along, you can always go back and review part one or part two. This tutorial will focus on fleshing out the asteroids-style game that we created, including making both a title scene and “how to play” scene, as well as storing player high scores.

As it stands right now, starting our app takes the player directly into the action without any warning. In addition, there’s no explanation of the controls, which would definitely be confusing for the first-time player. An easy way to fix this problem would be to create an introductory title screen, that shows off the name of the game and has buttons that start the game, view instructions, or view the high scores.

We’re going to be a bit forward thinking and create three new layer classes all at the same time, then go back and fill in the implementation details later. Open up your project in Xcode, right-click the Classes group, then select Add > New File. Make the new file a subclass of CCLayer, and name it “TitleScene.m”. Now go ahead and do the same thing two more times, naming each new source file “SourceScene.m” and “ControlsScene.m”, respectively. In each of the three new header files, add a + (id)scene class method declaration, between the @interface and @end statements so the code looks like this:

// TitleScene.h
@interface TitleLayer : CCLayer { }
+ (id)scene;
@end

// ControlsScene.h
@interface ControlsLayer : CCLayer { }
+ (id)scene;
@end

// ScoresScene.h
@interface ScoresLayer : CCLayer { }
+ (id)scene;
@end

Next, go into each of the new .m files, and add the following code between @implementation and @end, which will create a generic CCScene, then add your layer to it.

+ (id)scene
{
	// 'scene' is an autorelease object.
	CCScene *scene = [CCScene node];
	
	// 'layer' is an autorelease object.
	// Be sure to specify the "ScoresLayer" class in "ScoresScene.m", etc.
	ControlsLayer *layer = [ControlsLayer node];
	
	// add layer as a child to scene
	[scene addChild:layer];
	
	// return the scene
	return scene;
}

- (id)init
{
	if ((self = [super init]))
	{
		// Code goez here
	}
	return self;
}

These will be your basic steps every time you want to add a new scene/layer to a cocos2d project. Now, let’s focus on the title scene. We’ll probably want to have a large bit of text that displays the name of the game, as well as the buttons necessary to navigate through the different scenes we create. This is the pattern that we’ll follow for the high scores scene as well as the game controls scene. Add the following in the init method of the title scene class, after the “code goez here” comment.

// Get window size
CGSize windowSize = [CCDirector sharedDirector].winSize;
		
// Create text label for title of game - "@stroids" - don't sue me Atari!
CCLabelTTF *title = [CCLabelTTF labelWithString:@"@stroids" fontName:@"Courier" fontSize:64.0];
		
// Position title at center of screen
[title setPosition:ccp(windowSize.width / 2, windowSize.height / 2)];
		
// Add to layer
[self addChild:title z:1];

This just puts a big TrueType text label smack in the center of the screen with the title of the game. Next we’ll want to create three buttons that link to the different areas of the game — the “how to play” scene, the high scores scene, and the actual game itself.

// Set the default CCMenuItemFont font
[CCMenuItemFont setFontName:@"Courier"];
		
// Create "play," "scores," and "controls" buttons - when tapped, they call methods we define: playButtonAction and scoresButtonAction
CCMenuItemFont *playButton = [CCMenuItemFont itemFromString:@"play" target:self selector:@selector(playButtonAction)];
CCMenuItemFont *scoresButton = [CCMenuItemFont itemFromString:@"scores" target:self selector:@selector(scoresButtonAction)];
CCMenuItemFont *controlsButton = [CCMenuItemFont itemFromString:@"controls" target:self selector:@selector(controlsButtonAction)];
		
// Create menu that contains our buttons
CCMenu *menu = [CCMenu menuWithItems:playButton, scoresButton, controlsButton, nil];
		
// Align buttons horizontally
[menu alignItemsHorizontallyWithPadding:20.0];
		
// Set position of menu to be below the title text
[menu setPosition:ccp(windowSize.width / 2, title.position.y - title.contentSize.height / 1.5)];
		
// Add menu to layer
[self addChild:menu z:2];

I’m being lazy here and just creating text-based buttons. An exercise for the reader might be to create some nifty-looking graphical buttons to use instead. You can see the first method I call is to set the font that will be used for subsequent CCMenuItemFont buttons. Next, the three buttons are instantiated, added to a menu, aligned horizontally, then added to the layer. You can see that each of these buttons calls a different method when it is tapped, so let’s create those methods now. After the init method in TitleScene.m, add the following:

- (void)playButtonAction
{
	NSLog(@"Switch to GameScene");
	[[CCDirector sharedDirector] replaceScene:[GameLayer scene]];
}

- (void)scoresButtonAction
{
	NSLog(@"Switch to ScoresScene");
	[[CCDirector sharedDirector] replaceScene:[ScoresLayer scene]];
}

- (void)controlsButtonAction
{
	NSLog(@"Switch to ControlsScene");
	[[CCDirector sharedDirector] replaceScene:[ControlsLayer scene]];
}

These are simple methods that just switch the active scene class running in the app. Make sure to #import the GameLayer.h, ScoresLayer.h and ControlsLayer.h headers at the top of the file, otherwise you’ll get errors because you tried to create an object the current scene knows nothing about.

The last thing we’re going to do in the TitleScene class is initialize the high scores data structure, which will be stored using NSUserDefaults. This is kind of a hacky way to store scores, but it’s easy and it works, so why not?

// Place the following at the end of the init method in TitleScene.m

// Get user defaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
		
// Register default high scores - this could be more easily done by loading a .plist instead of manually creating this nested object
NSDictionary *defaultDefaults = [NSDictionary dictionaryWithObject:[NSArray arrayWithObjects:[NSNumber numberWithInt:0], [NSNumber numberWithInt:0], [NSNumber numberWithInt:0], [NSNumber numberWithInt:0], [NSNumber numberWithInt:0], nil] forKey:@"scores"];

[defaults registerDefaults:defaultDefaults];
[defaults synchronize];

The NSUserDefaults object is like an NSDictionary, in which you can store various values associated with a “key.” Here, I’m storing an NSArray (filled with zeros) associated with the key “scores.” The thing to remember here is that this zero’d out array is only used the first time the app is launched, or if the NSUserDefaults are otherwise erased. As you may be able to tell by now, we’re going to store the top five high scores. Of course, the first time the game is played, the top scores will all be zero.

Next, let’s delve into the ControlsScene class. Not too much new here… we’ll just create a few labels that explain how to play the game, along with a button that takes the player back to the title screen.

// Goes in the init method of ControlsScene.m
		
// Get window size
CGSize windowSize = [CCDirector sharedDirector].winSize;
		
// Create title label
CCLabelTTF *title = [CCLabelTTF labelWithString:@"how to play" fontName:@"Courier" fontSize:32.0];
[title setPosition:ccp(windowSize.width / 2, windowSize.height - title.contentSize.height)];
[self addChild:title];
		
// Brief description ov how to control the game:
// Tap = Shoot
// Pinch = Rotate
// Swipe = Move

// Create label that will display the controls - manually set the dimensions due to multi-line content
CCLabelTTF *controlsLabel = [CCLabelTTF labelWithString:@"tap = shoot\npinch = rotate\nswipe = move" dimensions:CGSizeMake(windowSize.width, windowSize.height / 3) alignment:CCTextAlignmentCenter fontName:@"Courier" fontSize:16.0];
[controlsLabel setPosition:ccp(windowSize.width / 2, windowSize.height / 2)];
[self addChild:controlsLabel];
		
// Create button that will take us back to the title screen
CCMenuItemFont *backButton = [CCMenuItemFont itemFromString:@"back" target:self selector:@selector(backButtonAction)];
		
// Create menu that contains our buttons
CCMenu *menu = [CCMenu menuWithItems:backButton, nil];
		
// Set position of menu to be below the scores
[menu setPosition:ccp(windowSize.width / 2, controlsLabel.position.y - controlsLabel.contentSize.height)];
		
// Add menu to layer
[self addChild:menu z:2];

Also, make sure to create the backButtonAction method which will return the player back to the title screen. This method will go after init but before the @end of the class implementation.

- (void)backButtonAction
{
	NSLog(@"Switch to TitleScene");
	[[CCDirector sharedDirector] replaceScene:[TitleLayer scene]];
}

The ScoresScene class will be almost exactly the same as ControlsScene, with the notable exception of displaying the stored high scores instead of a static string of instructions.

// Put the following in the init method of ScoresLayer

// Get window size
CGSize windowSize = [CCDirector sharedDirector].winSize;
		
// Get scores array stored in user defaults
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
		
// Get high scores array from "defaults" object
NSArray *highScores = [defaults arrayForKey:@"scores"];
		
// Create title label
CCLabelTTF *title = [CCLabelTTF labelWithString:@"high scores" fontName:@"Courier" fontSize:32.0];
[title setPosition:ccp(windowSize.width / 2, windowSize.height - title.contentSize.height)];
[self addChild:title];
		
// Create a mutable string which will be used to store the score list
NSMutableString *scoresString = [NSMutableString stringWithString:@""];
		
// Iterate through array and print out high scores
for (int i = 0; i < [highScores count]; i++)
{
	[scoresString appendFormat:@"%i. %i\n", i + 1, [[highScores objectAtIndex:i] intValue]];
}
		
// Create label that will display the scores - manually set the dimensions due to multi-line content
CCLabelTTF *scoresLabel = [CCLabelTTF labelWithString:scoresString dimensions:CGSizeMake(windowSize.width, windowSize.height / 3) alignment:CCTextAlignmentCenter fontName:@"Courier" fontSize:16.0];
[scoresLabel setPosition:ccp(windowSize.width / 2, windowSize.height / 2)];
[self addChild:scoresLabel];
		
// Create button that will take us back to the title screen
CCMenuItemFont *backButton = [CCMenuItemFont itemFromString:@"back" target:self selector:@selector(backButtonAction)];
		
// Create menu that contains our buttons
CCMenu *menu = [CCMenu menuWithItems:backButton, nil];
		
// Set position of menu to be below the scores
[menu setPosition:ccp(windowSize.width / 2, scoresLabel.position.y - scoresLabel.contentSize.height)];
		
// Add menu to layer
[self addChild:menu z:2];

The real wonky line in this code is [scoresString appendFormat:@"%i. %i\n", i + 1, [[highScores objectAtIndex:i] intValue]];. This appends additional text to the end of the mutable string that is used to display the high scores. highScores is the NSArray stored in the NSUserDefaults that stores the scores. An NSArray can only hold objects derived from NSObject, so that's why we wrap each number with NSNumber before putting it in the array. To get a regular integer from an NSNumber, you use the intValue method; e.g. int myNumber = [myNSNumber intValue];. Finally, don't forget to add the backButtonAction method to the ScoresLayer class after the init method.

- (void)backButtonAction
{
	NSLog(@"Switch to TitleScene");
	[[CCDirector sharedDirector] replaceScene:[TitleLayer scene]];
}

OK, so we're getting close to finishing the improvements that make this project seem more like "finished" game. When we left off programming the actual game class, the player could play indefinitely. We'll make a modification to the GameScene class so that a "game over" message is displayed when the player's ship is destroyed, and their score will be saved if its' high enough. Open up GameScene.h and add - (void)gameOver; at the bottom of the class method declaration list. Then open GameScene.m and add the implementation:

- (void)gameOver
{
	// Reset the ship's position, which also removes all bullets
	[self resetShip];
	
	// Hide ship
	ship.visible = NO;
	
	// Get window size
	CGSize windowSize = [CCDirector sharedDirector].winSize;
	
	// Show "game over" text
	CCLabelTTF *title = [CCLabelTTF labelWithString:@"game over" fontName:@"Courier" fontSize:64.0];
	
	// Position title at center of screen
	[title setPosition:ccp(windowSize.width / 2, windowSize.height / 2)];
	
	// Add to layer
	[self addChild:title z:1];
	
	// Create button that will take us back to the title screen
	CCMenuItemFont *backButton = [CCMenuItemFont itemFromString:@"back to title" target:self selector:@selector(backButtonAction)];
	
	// Create menu that contains our button
	CCMenu *menu = [CCMenu menuWithItems:backButton, nil];
	
	// Set position of menu to be below the "game over" text
	[menu setPosition:ccp(windowSize.width / 2, title.position.y - title.contentSize.height)];
	
	// Add menu to layer
	[self addChild:menu z:2];
	
	// Get scores array stored in user defaults
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	
	// Get high scores array from "defaults" object
	NSMutableArray *highScores = [NSMutableArray arrayWithArray:[defaults arrayForKey:@"scores"]];
	
	// Iterate thru high scores; see if current point value is higher than any of the stored values
	for (int i = 0; i < [highScores count]; i++)
	{
		if (points >= [[highScores objectAtIndex:i] intValue])
		{
			// Insert new high score, which pushes all others down
			[highScores insertObject:[NSNumber numberWithInt:points] atIndex:i];
			
			// Remove last score, so as to ensure only 5 entries in the high score array
			[highScores removeLastObject];
			
			// Re-save scores array to user defaults
			[defaults setObject:highScores forKey:@"scores"];
			
			[defaults synchronize];
			
			NSLog(@"Saved new high score of %i", points);
			
			// Bust out of the loop 
			break;
		}
	}
}

This method will get called when an asteroid runs into the ship, so in the update method in the big loop that cycles through all the asteroid objects, the first if conditional will be changed to look like this:

// Check for collisions vs. asteroids
for (int i = 0; i < [asteroids count]; i++)
{
	Asteroid *a = [asteroids objectAtIndex:i];
        
	// Check if asteroid hits ship
	if ([a collidesWith:ship])
	{
		// Game over, man!
		[self gameOver];
	}
// ... rest of loop here
}

The last thing you'll have to do is change the AppDelegate so that the app gets launched with the TitleScene class instead of the GameScene class. Add #import "TitleScene.h" to the top of the AppDelegate file, and then change the last line in the applicationDidFinishLaunching method.

- (void) applicationDidFinishLaunching:(UIApplication*)application
{
	// ... other cocos2d init stuff here

	[[CCDirector sharedDirector] runWithScene: [TitleLayer scene]];
}

Try building and running the app to see these changes in effect. The game could still be polished further, but it's looking a heck of a lot better than where we left it at the end of the previous tutorial. At this point you could theoretically put it out on the App Store (albeit for free, since it's pretty bare bones). Feel free to experiment with the code that you have... add your own graphics, or maybe an alien ship or powerups. You can download the Xcode project for reference. And make sure to tune in to the final part of the tutorial, where we'll add some particle systems and sound effects to make the game even more interesting.

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

Finding Time to Make Games · March 4, 2011

Everyone seems to have their own tips and tricks regarding how to make and finish a game. Derek Yu has a totally awesome list on his Make Games blog, which is required reading for anyone now reading this. Seriously, go read it now, then come back if you want to. Cliff Harris also had a short list entitled “Why Your Indie Game Isn’t Done.” These lists are great to read and keep in mind to help keep you motivated and on track. However, they don’t give much advice on the topic of finding time to make games.

It can be pretty difficult to carve out a chunk of time for game making, especially when most of us have lots of other responsibilities. Myself, I have a wife and 6 month-old daughter that I like to spend time with, plus a full-time job. I’m involved in a small group Bible study each week, and I also spend time with my friends now and again. On top of all this, I actually like to play games as well. Where do I find time to make ‘em?

Well, here’s my secret: I only sleep for 6 hours a night. Doesn’t seem like rocket science, but it works for me. My wife and daughter both love to sleep (well, the daughter not quite as much yet), so I wake up at 5AM and get some work done while the house is quiet. It’s hard for me to do game making after work or late at night, since I’ve been in front of the computer screen for 8+ hours at that point. Working in the morning means that I’m still motivated to develop.

Of course, waking up early is difficult. I like to sleep as much as the next person, but here are some tips that help me get out of bed each day.

  1. Prepare the night before. When you get up at an ungodly hour, your mind is mush. Anything you can do to streamline the process of getting out of bed and into gear is something you should do. What’s really helpful is to prepare before you go to sleep. For example, lay out your clothes so you don’t have to fumble around in the dark for what you’re going to wear. Fill up the kettle with water and put out a cup with the bag of tea already in it, or grind your coffee and put it in the French press. These simple tasks will help you get up and get moving more quickly in the morning. This article from Wired inspired me with “night before” prep.
  2. Keep a to-do list. Again, this tip attempts to help your mushy morning mind. When a bit bleary, it’s hard to be super cognitive and get back into your workflow immediately. You’ll think, “What am I supposed to be doing again?” and waste quite a bit of time figuring out where you left off the day before. A to-do list can really help you jump in and start being productive, especially if you remember to make the first few tasks for the day no-brainers — you can cross off some items on your list, and get into “work mode” more quickly.
  3. Turn off the internet. It’s easy to fire up the browser and follow rabbit trails around the internet, especially when a bit tired. The problem with this is that before you know it, you’ve wasted half an hour of your precious game dev time, with absolutely nothing to show for it. If you work on computers during the day, it’s easy to defer checking your RSS reader until some downtime later in the day; it’s much harder to program your game when you’re supposed to be working.
  4. Do it every day. Working on games part-time means that your projects will take a lot longer to be finished. It’s tough to stay motivated when you seem to be making so little progress each day. However, that time each day adds up before you know it. Plus, doing work each day means that you’ll form that as a habit, which in turn makes the decision to do work easier. Apparently Jerry Seinfeld had a trick to help him work every day… maybe it would be helpful for you?
  5. Really want to. I guess this goes without saying. You have to decide what you love more, and cut out other things that can be cut. For me, time with my family and other social obligations aren’t options to give up, so I cut out a little bit of physical comfort. In return, I get to pursue an activity that’s more rewarding than the mindless development I do during the day. What’s important to you?

1 comment · Posted by in Productivity · , ,

How To Make Low Rez Pixel Buttons · February 23, 2011

Zomg, it’s an “art” tutorial! Faced with the need for buttons for a game UI, I wanted to create something low rez and pixel-y. Doing a search for “pixel buttons” didn’t really turn up a whole lot, so I kinda mucked around and came up with something I liked, which was an amalgamation of various sources of inspiration. Now I’m regurgitating this process back onto the ‘net, so hopefully it’ll be useful to you as well.

  1. Determine size you need, then halve that. Create a new image with the halved size, but add an extra pixel to both width and height. So, say I want a 200×40 button, I’ll create a 101×21 new image.
  2. Draw a border along the edge of the image, but leave a pixel’s width of spacing on the bottom and right of the image. We’ll use that spacing for a drop shadow.
  3. Determine how rounded you want the button to be. See some examples, and modify the corners of your button appropriately.
  4. Select the color you want for the button, then fill the whole center with that.
  5. Lighten your color slightly and outline the top and left sides.
  6. Darken your color slightly and outline the bottom and right sides.
  7. Create a new layer, then add a black border in the extra space on the bottom and right sides. Lower the opacity of the layer to 25%, then merge it with the main button layer.
  8. Scale the button by 2x, using the “nearest neighbor” scaling algorithm.
  9. Add your text with whatever text decoration you like.
  10. Done!

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

How to Save Data with NSUserDefaults · February 13, 2011

A common requirement for any sort of computer program is saving data. In iOS, probably the simplest way of saving information about your app is using NSUserDefaults. In a nutshell, NSUserDefaults is a dictionary that will automatically save and load its’ state when your app opens and closes. I’ve used the NSUserDefaults class to save preferences (such as music on or off), as well as store info about the player’s progress through my game (whether a level is completed, best completion time, etc).

The best thing about NSUserDefaults is that it’s super easy to use. To set a default value:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:TRUE forKey:@"shouldPlayMusic"];
[defaults synchronize];

To get that same value back:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
Boolean shouldPlayMusic = [defaults boolForKey:@"shouldPlayMusic"];

And of course, the best part is that’s all you have to do — you don’t have to worry about serialization or saving to disk or whatever.

Another tip is that you can initialize your NSUserDefaults with a pre-defined NSDictionary object. So for example you could set a default value to be “false” or “true” before the user ever had a chance to interact with your program. In my case, sometimes I create an array that represents all the levels in my game, and in each array value I store a boolean to check if a player has finished the level. To do this I create the data object and then register it with NSUserDefaults. If a previous value exists for the object, then nothing happens. Otherwise my blank object gets saved as the “default” defaults.

Even better, you can define your standard defaults by using a .plist:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults registerDefaults:[NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"UserDefaults" ofType:@"plist"]]];

In this example I’ve got a file named UserDefaults.plist in my project, which is a dictionary that has the default keys and objects I want my app to start with. For more examples, check out Apple’s reference page.

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