Cowboy Programming Game Development and General Hacking by the Old West

July 10, 2008

CheckWord – My iPhone Scrabble word checker app

Filed under: Game Development — Mick West @ 5:48 pm

I’ve been working on a iPhone game (NineSpeed) on and off for a while – although recently it has been mostly off.  So when I got an email from Apple last Wednesday, telling me to submit my game by Monday to get in the app store for launch, then this spurred me into some kind of action.

Of course I was not going to finish the game by Monday, as I still had a load of UI stuff to do, and it was getting annoying, as I’d done everything in OpenGL up to that point, and starting to bolt on the necessary iPhone OS stuff (flipping views, saving states, entering text) was a bit intimidating.

So it struck me I could kill two birds with one stone – I could write a simple app for launch that would include all the UI elements I was lacking in NineSpeed.   I needed something simple that I could do in three days, but also something useful, so it would actually get published (although that did not turn out to be as big an issue as I thought it might).   And doing this would also let me go through the submission process, which might raise some issues in advance of me doing it for an app I hoped people would buy.

So I decided to do a Scrabble word checker.  It would just input a word and then tell you if it was good or bad to play in Scrabble.  There would also be an options screen where the user could change dictionaries.  The finshed app, “CheckWord” is now on the store:

http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=284938074&mt=8

STARTING FROM SCRATCH

iPhone development is done using two applications on the Mac:  XCode and Interface Builder.   These two apps are closely linked.   XCode lets you create, edit, build and test code.  Interface Builder lets you build pretty screens with buttons and suchlike, and link it up with the code you made in XCode.

XCode will make a basic iPhone application for you.  Simple choose “New Project”, and you get to pick from a few basic templates.  I chose “Utility Application”, which gives you two “views”, and a button that flips between them.

A “view”, as it turns out, is nothing complicated.  It’s just a region of a window.  A window is just the entire iPhone screen – they are resizable on the Mac, but on the iPhone you can only rotate them.  It’s perhaps a little confusing.

First confusion is that there are actually three views:  Root, Main and Flipside.  There are also three “Root Controllers”, which are objects that control the views.  The template sets all these up so that it displays the main view with the root view overlaid on top of it, and you can press a button to flip to the flipside view.  So in theory all I had to do was add a text entry field and some text display fields to the main view, and hook them together with some code, and then add some options on the flipside screen.

FIDDLY

So that’s what I did.  It’s bit fiddly, and for reference I used the “Hello World” sample app that inputs some text and then displays it on screen.   So my app ended up being an amalgam of the two.  I started with “Utility Application”, and then pasted in bits of “Hello World”

That worked reasonably well for the code, but of the Interface Builder (IB) stuff, I had to go in and visually check each element to see how it was connected.    The connections between IB and the code are pretty simple.  There’s an IBOutlet, which is just a data field that refers to the button or label, or whatever. Then there’s an IBAction, which is a function you define that is called when some event occurs on an IB object.

To actually hook these up, you just define them in the code, then IB will detect them, and when you right click on the appropiate object you get a list of outlets and actions and can drag them to the required place.

It’s not quite that simple though, and for a first-timer like myself, it can be rather confusing.  You’ve got all your object, but you also have these other objects:  the “File’s owner”, the “First Responder” and sometimes the “App Delegate”.  The “File’s Owner” you have to hook up to the class of the correct object in your code.  If this object is an UIApplication, then there’s a ‘delegate’ outlet, which you set to the App Delegate object, which is set to the class of that object.   Then either the File’s Owner or its delegate will have the outlets, and the “First Reponder” will have the actions.

If that’s hard to understand, it’s because I don’t fully understand it, and so I can’t explain it very well.  I’m still at a relativly early stage of learning this particular model of programming, and it will take a while before I get the nuances.

ACTUAL CODE

So all that’s just setting up connections between IB and the code.  What about actual code for chcking words?  Well, it turns out that that’s the easiest code to write.  Not because it’s any simpler, but because I know EXACTLY what the code is doing, since it’s just some raw C++ whizzing though arrays of bytes and doing some comparisons, simple stuff like:

bool CWordList::IsValid(const char *p_word)
{
	if (strlen(p_word) <= 1)
		return false;
	for (int i=0;i < m_words;i++)
	{
		if (strcasecmp(p_word, mp_words[i]) == 0)
			return true;
	}
	return false;
}

Nothing complicated there, just some nice simple cowboy code :)

SUBMITTING

The process of submitting the app to the app store was actually fairly painless in comparison with some things I’ve had to do in the past.  There were lots of instructions, and while there were a few problems, if you simply follow the instructions, all will be well.  The one problem I had was that at some stage the distribution build had to actually be built before some signing thing could be changed, and then it had to be built again.

I packed it up, uploaded it with some screenshots, and a few hours later it was approved.  Nice.

Anyway, in closing, here’s a list of the various discreet things I learned how to do, mostly for my own reference.

LOAD A BINARY FILE

Add the binary file to your “Resources” in xcode so it goes into the “bundle”.  Then code to load “TWL06.txt” into some C++ style allocated memory is:

				NSString *filePath = [[NSBundle mainBundle] pathForResource:@"TWL06" ofType:@"txt"];
				NSData *fileContents = [NSData dataWithContentsOfFile:filePath];
				int len = fileContents.length;
				char *p_data = new char[len];
				[fileContents getBytes:p_data];

TEXT INPUT

Create a UITextField object in IB, and one one the view controller’s interface, which you have to also decorate with UITextFieldDelegate, like:

@interface MyViewController : UIViewController  {
	IBOutlet UITextField *textField;
...
@property (nonatomic, retain) UITextField *textField;

You then override textFieldShouldReturn to call resignFirstResponder and return YES if you want the keyboard to go away after text entry. In my case I wanted to it stay, and I also check the word as soon as the text is entered, so I have:

- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
	if (theTextField == textField) {
		//[textField resignFirstResponder];
		[self checkWord:nil];
	}
	return NO;
}

SAVING STATE

NSUserDefaults is what you want, it stores a dictionary of objects. In applicationDidFinishLaunching, you check for the existence of it, and create a default if needed:

NSString *kDictionaryIndexKey = @"dictionaryIndexKey";
NSString *kAcceptableSwitchKey = @"acceptableSwitchKey";
NSString *kNameKey = @"nameKey";
...
	NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kNameKey];
	if (testValue == nil)
	{
		printf("Dictionary Index key not found, creating default defaults\n");
		// since no default values have been set (i.e. no preferences file created), create it here
		NSString *name = @"CheckWord";
		NSDictionary *appDefaults =  [NSDictionary dictionaryWithObjectsAndKeys:
									  name,kNameKey,
									  [NSNumber numberWithInt:0], kAcceptableSwitchKey,
									  [NSNumber numberWithInt:0], kDictionaryIndexKey,
									  nil];

		[[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
		[[NSUserDefaults standardUserDefaults] synchronize];
	}

Then you read them like this:

	[acceptableSwitch setOn:[[NSUserDefaults standardUserDefaults] integerForKey:kAcceptableSwitchKey]];
	dictionary.selectedSegmentIndex = [[NSUserDefaults standardUserDefaults] integerForKey:kDictionaryIndexKey];

(That reading the options to set the switch the the multi-segment button used in the options screen)

And write them like this:

- (IBAction) changeDictionary:(id)sender
{
	dictionaryIndex = dictionary.selectedSegmentIndex;
    [[NSUserDefaults standardUserDefaults] setInteger:dictionaryIndex forKey:kDictionaryIndexKey];
}

That’s an Action that takes the dictionaryIndex from the multi-segment button, and stores it in the user defaults.

That’s it, the options will be saved, and persist between sessions, and power-downs.

FLIPPING THE SCREEN

Just use the “Utility” template code.

MAKING THE ‘i’ LESS FIDDLY

This was an annoying one. The ‘i’ button in the sample worked fine in the simulator, but on the actual iPhone, it was very fiddly, and often seemed not to work for some reason. To fix this, I made a custom button, and used a screen-grabbed image of the ‘i’ instead. I made this 44×44 pixels with a lot of transparency (although I think you can just re-size any custom button, regardless of the bitmap). This improved things a lot.

13 Comments »

  1. Checkword for iphone is great – do you have a version for Palm?
    Tks!

    Comment by Steve — August 30, 2008 @ 7:24 pm

  2. No sorry, I only do iPhone stuff.

    Comment by Mick West — August 30, 2008 @ 7:31 pm

  3. Must be very rewarding to know that you created and got an app approved by apple. I know that there are probably thousands out there. But still, nice accomplishment. BTW- I love scrabble, and my hubby and I often argue about words, so this app will come in handy! Sharon

    Comment by Sharon — January 11, 2009 @ 4:35 pm

  4. CheckWord rocks! Thank you! I’ve posted an entry in my blog endorsing it!

    Comment by Allan — January 13, 2009 @ 10:11 am

  5. FLIPPING THE SCREEN…
    :)))))

    Comment by Игры.. Детские игры — January 18, 2009 @ 9:43 am

  6. Mick West, this app is great. You do it excellent, so much that you got it approved by apple.

    Comment by tony g poker coupon code — July 21, 2009 @ 2:21 pm

  7. I played “greeking” this morning and it got challenged off the board because it wasn’t in Checkword :(

    But later I looked it up in Collin’s Tournament and Club Word List (which supplanted Chambers for UK Tournaments) and it’s allowed.

    Any chance of substituting/adding a new word list?

    Comment by Lee Rimar — August 16, 2009 @ 10:31 am

  8. GREEKING is in SOWPODS, which is the same as the collins word list. Just change to SOWPODS in the options if you are in the UK (it defaults to TWL, the American word list).

    Comment by Mick West — August 16, 2009 @ 10:38 am

  9. CheckWord solved a couple of word-arguing situations between me and my friend))
    It’s a pity that you only do iPhone stuff – I’d be great if we had a chance to get your app on Win Mobile…

    Comment by Mobile Application Development — September 8, 2009 @ 2:09 am

  10. Really small comment… But I think you can access the contents of the NSData directly with a copy using -[NSData bytes]…

    .n

    Comment by nielsbot — September 17, 2009 @ 10:25 am

  11. iPhone really gonna hit the market with their applications. Great info. Thanks

    Comment by Facebook Application Developers — October 23, 2009 @ 12:42 am

  12. […] showed me a useful Scrabble app for the iPhone called Check Word (you can get the app from the iTunes store here). The app is $0.99 but I can already see the value […]

    Pingback by Gotta strike while the iron is hot – A night at TSC (2010.03.24) « Scrabble Adventures — March 24, 2010 @ 9:32 pm

  13. Very simple app, great for travel Scrabble and other word games. New update was helpful so that we no need to carry around that huge dictionary when you want to look up a word for Scrabble.Thanks for making this free!

    Comment by Aaron Schmidt — February 2, 2011 @ 2:31 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

You must be logged in to post a comment.

Powered by WordPress